From 9bba5032c233ffe57cb1677f61cecfe79e6b53d5 Mon Sep 17 00:00:00 2001 From: Ryan Neph Date: Wed, 9 Nov 2022 14:37:10 -0800 Subject: [PATCH] venus: bind VkQueue to available ring_idx at creation Signed-off-by: Ryan Neph Part-of: --- src/virtio/vulkan/vn_device.c | 48 ++++++++++++++++++++++++++------- src/virtio/vulkan/vn_instance.c | 6 +++++ src/virtio/vulkan/vn_instance.h | 31 +++++++++++++++++++++ src/virtio/vulkan/vn_queue.h | 3 +++ src/virtio/vulkan/vn_renderer.h | 1 + 5 files changed, 80 insertions(+), 9 deletions(-) diff --git a/src/virtio/vulkan/vn_device.c b/src/virtio/vulkan/vn_device.c index 2cdc45e95e2..62cfc0895ca 100644 --- a/src/virtio/vulkan/vn_device.c +++ b/src/virtio/vulkan/vn_device.c @@ -41,16 +41,36 @@ vn_queue_init(struct vn_device *dev, { vn_object_base_init(&queue->base, VK_OBJECT_TYPE_QUEUE, &dev->base); + VkDeviceQueueTimelineInfoMESA timeline_info; + const struct vn_renderer_info *renderer_info = + &dev->instance->renderer->info; + if (renderer_info->supports_multiple_timelines) { + int ring_idx = vn_instance_acquire_ring_idx(dev->instance); + if (ring_idx < 0) { + vn_log(dev->instance, + "failed binding VkQueue to renderer sync queue"); + return VK_ERROR_INITIALIZATION_FAILED; + } + queue->ring_idx = (uint32_t)ring_idx; + + timeline_info = (VkDeviceQueueTimelineInfoMESA){ + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_TIMELINE_INFO_MESA, + .ringIdx = queue->ring_idx, + }; + } + + const VkDeviceQueueInfo2 device_queue_info = { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2, + .pNext = + renderer_info->supports_multiple_timelines ? &timeline_info : NULL, + .flags = queue_info->flags, + .queueFamilyIndex = queue_info->queueFamilyIndex, + .queueIndex = queue_index, + }; + VkQueue queue_handle = vn_queue_to_handle(queue); - vn_async_vkGetDeviceQueue2( - dev->instance, vn_device_to_handle(dev), - &(VkDeviceQueueInfo2){ - .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2, - .flags = queue_info->flags, - .queueFamilyIndex = queue_info->queueFamilyIndex, - .queueIndex = queue_index, - }, - &queue_handle); + vn_async_vkGetDeviceQueue2(dev->instance, vn_device_to_handle(dev), + &device_queue_info, &queue_handle); queue->device = dev; queue->family = queue_info->queueFamilyIndex; @@ -493,6 +513,16 @@ vn_DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) */ vn_async_vkDestroyDevice(dev->instance, device, NULL); + /* We must emit vn_call_vkDestroyDevice before releasing bound ring_idx. + * Otherwise, another thread might reuse their ring_idx while they + * are still bound to the queues in the renderer. + */ + if (dev->instance->renderer->info.supports_multiple_timelines) { + for (uint32_t i = 0; i < dev->queue_count; i++) { + vn_instance_release_ring_idx(dev->instance, dev->queues[i].ring_idx); + } + } + vk_free(alloc, dev->queues); vn_device_base_fini(&dev->base); diff --git a/src/virtio/vulkan/vn_instance.c b/src/virtio/vulkan/vn_instance.c index 952462968db..08d172bc7d9 100644 --- a/src/virtio/vulkan/vn_instance.c +++ b/src/virtio/vulkan/vn_instance.c @@ -720,8 +720,12 @@ vn_CreateInstance(const VkInstanceCreateInfo *pCreateInfo, return vn_error(NULL, result); } + /* ring_idx = 0 reserved for CPU timeline */ + instance->ring_idx_used_mask = 0x1; + mtx_init(&instance->physical_device.mutex, mtx_plain); mtx_init(&instance->cs_shmem.mutex, mtx_plain); + mtx_init(&instance->ring_idx_mutex, mtx_plain); if (!vn_icd_supports_api_version( instance->base.base.app_info.api_version)) { @@ -823,6 +827,7 @@ fail: vn_renderer_destroy(instance->renderer, alloc); mtx_destroy(&instance->physical_device.mutex); + mtx_destroy(&instance->ring_idx_mutex); mtx_destroy(&instance->cs_shmem.mutex); vn_instance_base_fini(&instance->base); @@ -850,6 +855,7 @@ vn_DestroyInstance(VkInstance _instance, vk_free(alloc, instance->physical_device.groups); } mtx_destroy(&instance->physical_device.mutex); + mtx_destroy(&instance->ring_idx_mutex); vn_call_vkDestroyInstance(instance, _instance, NULL); diff --git a/src/virtio/vulkan/vn_instance.h b/src/virtio/vulkan/vn_instance.h index ac74607b6c7..6aee3ed51a9 100644 --- a/src/virtio/vulkan/vn_instance.h +++ b/src/virtio/vulkan/vn_instance.h @@ -41,6 +41,9 @@ struct vn_instance { struct vn_renderer_shmem_pool reply_shmem_pool; + mtx_t ring_idx_mutex; + uint64_t ring_idx_used_mask; + /* XXX staged features to be merged to core venus protocol */ VkVenusExperimentalFeatures100000MESA experimental; @@ -172,4 +175,32 @@ vn_instance_cs_shmem_alloc(struct vn_instance *instance, return shmem; } +static inline int +vn_instance_acquire_ring_idx(struct vn_instance *instance) +{ + mtx_lock(&instance->ring_idx_mutex); + int ring_idx = ffsll(~instance->ring_idx_used_mask) - 1; + if (ring_idx >= instance->renderer->info.max_sync_queue_count) + ring_idx = -1; + if (ring_idx > 0) + instance->ring_idx_used_mask |= (1ULL << (uint32_t)ring_idx); + mtx_unlock(&instance->ring_idx_mutex); + + assert(ring_idx); /* never acquire the dedicated CPU ring */ + + /* returns -1 when no vacant rings */ + return ring_idx; +} + +static inline void +vn_instance_release_ring_idx(struct vn_instance *instance, uint32_t ring_idx) +{ + assert(ring_idx > 0); + + mtx_lock(&instance->ring_idx_mutex); + assert(instance->ring_idx_used_mask & (1ULL << ring_idx)); + instance->ring_idx_used_mask &= ~(1ULL << ring_idx); + mtx_unlock(&instance->ring_idx_mutex); +} + #endif /* VN_INSTANCE_H */ diff --git a/src/virtio/vulkan/vn_queue.h b/src/virtio/vulkan/vn_queue.h index d44b76a3eb5..b0c491cd68f 100644 --- a/src/virtio/vulkan/vn_queue.h +++ b/src/virtio/vulkan/vn_queue.h @@ -23,6 +23,9 @@ struct vn_queue { uint32_t index; uint32_t flags; + /* only used if renderer supports multiple timelines */ + uint32_t ring_idx; + /* wait fence used for vn_QueueWaitIdle */ VkFence wait_fence; diff --git a/src/virtio/vulkan/vn_renderer.h b/src/virtio/vulkan/vn_renderer.h index a8207c6b85b..6143c902de0 100644 --- a/src/virtio/vulkan/vn_renderer.h +++ b/src/virtio/vulkan/vn_renderer.h @@ -78,6 +78,7 @@ struct vn_renderer_info { /* combined mask for vk_extension_mask1, 2,..., N */ uint32_t vk_extension_mask[32]; uint32_t allow_vk_wait_syncs; + uint32_t supports_multiple_timelines; }; struct vn_renderer_submit_batch {