Module: Mesa Branch: staging/23.3 Commit: 62ea10c0e05ab08dccf05f3218045297c2d2b074 URL: http://cgit.freedesktop.org/mesa/mesa/commit/?id=62ea10c0e05ab08dccf05f3218045297c2d2b074
Author: Juston Li <justo...@google.com> Date: Tue Sep 26 16:04:18 2023 -0700 venus: track/recycle appended query feedback cmds Link the query feedback cmd lifecycle to a cmd in the batch so that when that last cmd gets reset/freed, we assert its safe to reset the query feedback cmd. The cmd is then placed on the free list for reuse. Some edge cases if the the last cmd is simultaneous or gets resubmitted. Cc: 23.3 <mesa-stable> Signed-off-by: Juston Li <justo...@google.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/25413> (cherry picked from commit d2a626787e559dad9105243be9e5043c9230853c) --- .pick_status.json | 2 +- src/virtio/vulkan/vn_command_buffer.c | 22 ++++++++++ src/virtio/vulkan/vn_command_buffer.h | 7 +++ src/virtio/vulkan/vn_feedback.c | 18 ++++++-- src/virtio/vulkan/vn_queue.c | 83 +++++++++++++++++++++++++++++++++++ 5 files changed, 127 insertions(+), 5 deletions(-) diff --git a/.pick_status.json b/.pick_status.json index 9c8571849f8..9744f33d89f 100644 --- a/.pick_status.json +++ b/.pick_status.json @@ -254,7 +254,7 @@ "description": "venus: track/recycle appended query feedback cmds", "nominated": true, "nomination_type": 0, - "resolution": 0, + "resolution": 1, "main_sha": null, "because_sha": null, "notes": null diff --git a/src/virtio/vulkan/vn_command_buffer.c b/src/virtio/vulkan/vn_command_buffer.c index 35db167f125..3b225f0f855 100644 --- a/src/virtio/vulkan/vn_command_buffer.c +++ b/src/virtio/vulkan/vn_command_buffer.c @@ -716,6 +716,7 @@ vn_CreateCommandPool(VkDevice device, pool->queue_family_index = pCreateInfo->queueFamilyIndex; list_inithead(&pool->command_buffers); list_inithead(&pool->free_query_batches); + list_inithead(&pool->free_query_feedback_cmds); VkCommandPool pool_handle = vn_command_pool_to_handle(pool); vn_async_vkCreateCommandPool(dev->instance, device, pCreateInfo, NULL, @@ -726,6 +727,16 @@ vn_CreateCommandPool(VkDevice device, return VK_SUCCESS; } +static inline void +vn_recycle_query_feedback_cmd(struct vn_command_buffer *cmd) +{ + vn_ResetCommandBuffer( + vn_command_buffer_to_handle(cmd->linked_query_feedback_cmd), 0); + list_add(&cmd->linked_query_feedback_cmd->feedback_head, + &cmd->linked_query_feedback_cmd->pool->free_query_feedback_cmds); + cmd->linked_query_feedback_cmd = NULL; +} + void vn_DestroyCommandPool(VkDevice device, VkCommandPool commandPool, @@ -760,6 +771,9 @@ vn_DestroyCommandPool(VkDevice device, &cmd->builder.query_batches, head) vk_free(alloc, batch); + if (cmd->linked_query_feedback_cmd) + vn_recycle_query_feedback_cmd(cmd); + vk_free(alloc, cmd); } @@ -789,6 +803,9 @@ vn_cmd_reset(struct vn_command_buffer *cmd) &cmd->builder.query_batches, head) vn_cmd_query_batch_pop(cmd, batch); + if (cmd->linked_query_feedback_cmd) + vn_recycle_query_feedback_cmd(cmd); + memset(&cmd->builder, 0, sizeof(cmd->builder)); list_inithead(&cmd->builder.query_batches); @@ -906,6 +923,9 @@ vn_FreeCommandBuffers(VkDevice device, &cmd->builder.query_batches, head) vn_cmd_query_batch_pop(cmd, batch); + if (cmd->linked_query_feedback_cmd) + vn_recycle_query_feedback_cmd(cmd); + vn_object_base_fini(&cmd->base); vk_free(alloc, cmd); } @@ -1045,6 +1065,8 @@ vn_BeginCommandBuffer(VkCommandBuffer commandBuffer, cmd->state = VN_COMMAND_BUFFER_STATE_INVALID; return vn_error(instance, VK_ERROR_OUT_OF_HOST_MEMORY); } + cmd->builder.is_simultaneous = + pBeginInfo->flags & VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; vn_encode_vkBeginCommandBuffer(&cmd->cs, 0, commandBuffer, pBeginInfo); diff --git a/src/virtio/vulkan/vn_command_buffer.h b/src/virtio/vulkan/vn_command_buffer.h index 292b0babc8b..73fc91d92d5 100644 --- a/src/virtio/vulkan/vn_command_buffer.h +++ b/src/virtio/vulkan/vn_command_buffer.h @@ -25,6 +25,7 @@ struct vn_command_pool { struct list_head command_buffers; struct list_head free_query_batches; + struct list_head free_query_feedback_cmds; /* Temporary storage for scrubbing VK_IMAGE_LAYOUT_PRESENT_SRC_KHR. The * storage's lifetime is the command pool's lifetime. We increase the @@ -66,6 +67,8 @@ struct vn_command_buffer_builder { uint32_t subpass_index; /* track the active view mask inside a render pass instance */ uint32_t view_mask; + /* track if VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT was set */ + bool is_simultaneous; /* track the query feedbacks deferred outside the render pass instance */ struct list_head query_batches; }; @@ -82,7 +85,11 @@ struct vn_command_buffer { struct vn_command_buffer_builder builder; + struct vn_command_buffer *linked_query_feedback_cmd; + struct list_head head; + + struct list_head feedback_head; }; VK_DEFINE_HANDLE_CASTS(vn_command_buffer, base.base, diff --git a/src/virtio/vulkan/vn_feedback.c b/src/virtio/vulkan/vn_feedback.c index 5adb55e4d78..c17d947e958 100644 --- a/src/virtio/vulkan/vn_feedback.c +++ b/src/virtio/vulkan/vn_feedback.c @@ -620,15 +620,25 @@ vn_feedback_query_batch_record(VkDevice dev_handle, .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, .commandBufferCount = 1, }; + struct vn_command_pool *cmd_pool = + vn_command_pool_from_handle(feedback_pool->pool); VkCommandBuffer feedback_cmd_handle; VkResult result; simple_mtx_lock(&feedback_pool->mutex); - result = - vn_AllocateCommandBuffers(dev_handle, &info, &feedback_cmd_handle); - if (result != VK_SUCCESS) - goto out_unlock; + if (!list_is_empty(&cmd_pool->free_query_feedback_cmds)) { + struct vn_command_buffer *free_cmd = + list_first_entry(&cmd_pool->free_query_feedback_cmds, + struct vn_command_buffer, feedback_head); + feedback_cmd_handle = vn_command_buffer_to_handle(free_cmd); + list_del(&free_cmd->feedback_head); + } else { + result = + vn_AllocateCommandBuffers(dev_handle, &info, &feedback_cmd_handle); + if (result != VK_SUCCESS) + goto out_unlock; + } static const VkCommandBufferBeginInfo begin_info = { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, diff --git a/src/virtio/vulkan/vn_queue.c b/src/virtio/vulkan/vn_queue.c index 62d9980c011..a3169275a85 100644 --- a/src/virtio/vulkan/vn_queue.c +++ b/src/virtio/vulkan/vn_queue.c @@ -17,6 +17,7 @@ #include "venus-protocol/vn_protocol_driver_semaphore.h" #include "venus-protocol/vn_protocol_driver_transport.h" +#include "vn_command_buffer.h" #include "vn_device.h" #include "vn_device_memory.h" #include "vn_physical_device.h" @@ -45,6 +46,7 @@ struct vn_queue_submission { const struct vn_device_memory *wsi_mem; uint32_t feedback_cmd_buffer_count; struct vn_sync_payload_external external_payload; + struct vn_command_buffer *recycle_query_feedback_cmd; /* Temporary storage allocation for submission * A single alloc for storage is performed and the offsets inside @@ -489,6 +491,79 @@ vn_get_feedback_cmd_handle(struct vn_queue_submission *submit, : &feedback_cmds->cmd_buffer_infos[cmd_index].commandBuffer; } +static VkResult +vn_queue_submission_add_query_feedback(struct vn_queue_submission *submit, + uint32_t cmd_buffer_count, + struct vn_feedback_cmds *feedback_cmds) +{ + struct vk_queue *queue_vk = vk_queue_from_handle(submit->queue_handle); + VkDevice dev_handle = vk_device_to_handle(queue_vk->base.device); + struct vn_device *dev = vn_device_from_handle(dev_handle); + VkCommandBuffer *src_cmd_handles = + vn_get_feedback_cmd_handle(submit, feedback_cmds, 0); + VkCommandBuffer *feedback_cmd_handle = + vn_get_feedback_cmd_handle(submit, feedback_cmds, cmd_buffer_count); + uint32_t stride = (submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO) + ? sizeof(VkCommandBuffer *) + : sizeof(VkCommandBufferSubmitInfo); + VkResult result; + + uint32_t pool_index; + for (pool_index = 0; pool_index < dev->queue_family_count; pool_index++) { + if (dev->queue_families[pool_index] == queue_vk->queue_family_index) + break; + } + + result = vn_feedback_query_batch_record( + dev_handle, &dev->cmd_pools[pool_index], src_cmd_handles, + cmd_buffer_count, stride, feedback_cmd_handle); + if (result != VK_SUCCESS) + return result; + + /* link query feedback cmd lifecycle with a cmd in the original batch so + * that the feedback cmd can be reset and recycled when that cmd gets + * reset/freed. + * + * Avoid cmd buffers with VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT + * since we don't know if all its instances have completed execution. + * Should be rare enough to just log and leak the feedback cmd. + */ + struct vn_command_buffer *linked_cmd_buffer = NULL; + for (uint32_t i = cmd_buffer_count - 1; i >= 0; i--) { + VkCommandBuffer *cmd_handle = + vn_get_feedback_cmd_handle(submit, feedback_cmds, i); + struct vn_command_buffer *cmd_buffer = + vn_command_buffer_from_handle(*cmd_handle); + + if (!cmd_buffer->builder.is_simultaneous) { + linked_cmd_buffer = cmd_buffer; + break; + } + } + + if (!linked_cmd_buffer) { + vn_log(dev->instance, + "Could not find non simultaneous cmd to link query feedback\n"); + return VK_SUCCESS; + } + + /* If a cmd that was submitted previously and already has a feedback cmd + * linked, as long as VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT is not + * set we can assume it has completed execution and is no longer in the + * pending state so its safe to recycle the old feedback command before + * linking a new one. Defer the actual recycle operation to + * vn_queue_submission_cleanup. + */ + if (linked_cmd_buffer->linked_query_feedback_cmd) + submit->recycle_query_feedback_cmd = + linked_cmd_buffer->linked_query_feedback_cmd; + + linked_cmd_buffer->linked_query_feedback_cmd = + vn_command_buffer_from_handle(*feedback_cmd_handle); + + return VK_SUCCESS; +} + static VkResult vn_queue_submission_add_sem_feedback(struct vn_queue_submission *submit, uint32_t batch_index, @@ -789,6 +864,14 @@ vn_queue_submission_cleanup(struct vn_queue_submission *submit) struct vn_queue *queue = vn_queue_from_handle(submit->queue_handle); const VkAllocationCallbacks *alloc = &queue->base.base.base.device->alloc; + if (submit->recycle_query_feedback_cmd) { + vn_ResetCommandBuffer( + vn_command_buffer_to_handle(submit->recycle_query_feedback_cmd), 0); + list_add( + &submit->recycle_query_feedback_cmd->feedback_head, + &submit->recycle_query_feedback_cmd->pool->free_query_feedback_cmds); + } + /* TODO clean up pending src feedbacks on failure? */ if (submit->has_feedback_semaphore) vn_queue_recycle_src_feedback(submit);