From 38b1c39b59527c2afadb66c7c14664c7641660cb Mon Sep 17 00:00:00 2001 From: Juston Li Date: Fri, 30 Jun 2023 08:37:30 -0700 Subject: [PATCH] venus: batch query feedback and defer until after render pass vkCmdCopyQueryPoolResults cannot be called within a render pass so batch and defer the query feedback copies until after the render pass. Secondary command buffers inside render passes also have their query feedback copies batched when recorded. When the secondary command buffer is recorded via vkCmdExecuteCommands, it's batch is merged into the primary command buffer's batch and is defered until the render pass ends. If multiview is enabled, vkCmdCopyQueryPoolResults needs to copy additional queries matching the number of bits set in viewMask. Signed-off-by: Juston Li Part-of: --- src/virtio/vulkan/vn_command_buffer.c | 132 ++++++++++++++++++++++++++ src/virtio/vulkan/vn_command_buffer.h | 1 + 2 files changed, 133 insertions(+) diff --git a/src/virtio/vulkan/vn_command_buffer.c b/src/virtio/vulkan/vn_command_buffer.c index ae6e3dea33b..762baecfd27 100644 --- a/src/virtio/vulkan/vn_command_buffer.c +++ b/src/virtio/vulkan/vn_command_buffer.c @@ -16,8 +16,18 @@ #include "vn_descriptor_set.h" #include "vn_device.h" #include "vn_image.h" +#include "vn_query_pool.h" #include "vn_render_pass.h" +/* query feedback batch for deferred recording */ +struct vn_command_buffer_query_batch { + struct vn_query_pool *query_pool; + uint32_t query; + uint32_t query_count; + + struct list_head head; +}; + static void vn_cmd_submit(struct vn_command_buffer *cmd); @@ -504,6 +514,45 @@ vn_cmd_transfer_present_src_images( count, img_barriers); } +static void +vn_cmd_record_batched_query_feedback(struct vn_command_buffer *cmd) +{ + list_for_each_entry_safe(struct vn_command_buffer_query_batch, batch, + &cmd->query_batches, head) { + vn_feedback_query_copy_cmd_record( + vn_command_buffer_to_handle(cmd), + vn_query_pool_to_handle(batch->query_pool), batch->query, + batch->query_count); + + list_del(&batch->head); + vk_free(&cmd->allocator, batch); + } +} + +static void +vn_cmd_merge_batched_query_feedback(struct vn_command_buffer *primary_cmd, + struct vn_command_buffer *secondary_cmd) +{ + list_for_each_entry_safe(struct vn_command_buffer_query_batch, + secondary_batch, &secondary_cmd->query_batches, + head) { + /* TODO: add a cache for batch allocs inside cmd pool */ + struct vn_command_buffer_query_batch *primary_batch = + vk_zalloc(&primary_cmd->allocator, sizeof(*primary_batch), + VN_DEFAULT_ALIGN, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!primary_batch) { + primary_cmd->state = VN_COMMAND_BUFFER_STATE_INVALID; + return; + } + + primary_batch->query_pool = secondary_batch->query_pool; + primary_batch->query = secondary_batch->query; + primary_batch->query_count = secondary_batch->query_count; + + list_add(&primary_batch->head, &primary_cmd->query_batches); + } +} + static void vn_cmd_begin_render_pass(struct vn_command_buffer *cmd, const struct vn_render_pass *pass, @@ -570,6 +619,7 @@ vn_cmd_end_render_pass(struct vn_command_buffer *cmd) cmd->builder.render_pass = NULL; cmd->builder.framebuffer = NULL; + vn_cmd_record_batched_query_feedback(cmd); cmd->in_render_pass = false; cmd->render_pass = NULL; cmd->subpass_index = 0; @@ -650,6 +700,13 @@ vn_DestroyCommandPool(VkDevice device, &pool->command_buffers, head) { vn_cs_encoder_fini(&cmd->cs); vn_object_base_fini(&cmd->base); + + list_for_each_entry_safe(struct vn_command_buffer_query_batch, batch, + &cmd->query_batches, head) { + list_del(&batch->head); + vk_free(&cmd->allocator, batch); + } + vk_free(alloc, cmd); } @@ -669,6 +726,11 @@ vn_cmd_reset(struct vn_command_buffer *cmd) cmd->render_pass = NULL; cmd->subpass_index = 0; cmd->view_mask = 0; + list_for_each_entry_safe(struct vn_command_buffer_query_batch, batch, + &cmd->query_batches, head) { + list_del(&batch->head); + vk_free(&cmd->allocator, batch); + } } VkResult @@ -744,6 +806,8 @@ vn_AllocateCommandBuffers(VkDevice device, vn_cs_encoder_init(&cmd->cs, dev->instance, VN_CS_ENCODER_STORAGE_SHMEM_POOL, 16 * 1024); + list_inithead(&cmd->query_batches); + VkCommandBuffer cmd_handle = vn_command_buffer_to_handle(cmd); pCommandBuffers[i] = cmd_handle; } @@ -781,6 +845,12 @@ vn_FreeCommandBuffers(VkDevice device, vn_cs_encoder_fini(&cmd->cs); list_del(&cmd->head); + list_for_each_entry_safe(struct vn_command_buffer_query_batch, batch, + &cmd->query_batches, head) { + list_del(&batch->head); + vk_free(&cmd->allocator, batch); + } + vn_object_base_fini(&cmd->base); vk_free(alloc, cmd); } @@ -1183,6 +1253,7 @@ vn_CmdEndRendering(VkCommandBuffer commandBuffer) * so defer until it actually ends. */ if (!cmd->suspends) { + vn_cmd_record_batched_query_feedback(cmd); cmd->in_render_pass = false; cmd->view_mask = 0; } @@ -1677,6 +1748,56 @@ vn_CmdBeginQuery(VkCommandBuffer commandBuffer, VN_CMD_ENQUEUE(vkCmdBeginQuery, commandBuffer, queryPool, query, flags); } +static void +vn_cmd_add_query_feedback(VkCommandBuffer commandBuffer, + VkQueryPool queryPool, + uint32_t query, + uint32_t queryCount) +{ + struct vn_command_buffer *cmd = + vn_command_buffer_from_handle(commandBuffer); + struct vn_query_pool *pool = vn_query_pool_from_handle(queryPool); + + if (!pool->feedback) + return; + + /* vkCmdCopyQueryPoolResults cannot be called within a render pass so batch + * and defer the query feedback copies until after the render pass + */ + if (cmd->in_render_pass) { + /* Per 1.3.255 spec "If queries are used while executing a render pass + * instance that has multiview enabled, the query uses N consecutive + * query indices in the query pool (starting at query) where N is the + * number of bits set in the view mask in the subpass the query is used + * in." + * + * viewMask is passed in for `vkCmdBeginRendering` but for + * `vkCmdBeginRenderPass/2` they are set by `vkCreateRenderPass` per + * subpass + */ + uint32_t num_queries = + cmd->view_mask ? util_bitcount(cmd->view_mask) : 1; + + /* TODO: add a cache for batch allocs inside cmd pool */ + struct vn_command_buffer_query_batch *batch = + vk_zalloc(&cmd->allocator, sizeof(*batch), VN_DEFAULT_ALIGN, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!batch) { + cmd->state = VN_COMMAND_BUFFER_STATE_INVALID; + return; + } + + batch->query_pool = vn_query_pool_from_handle(queryPool); + batch->query = query; + batch->query_count = num_queries; + + list_add(&batch->head, &cmd->query_batches); + } else { + vn_feedback_query_copy_cmd_record(commandBuffer, queryPool, query, + queryCount); + } +} + void vn_CmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, @@ -1829,8 +1950,19 @@ vn_CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer *pCommandBuffers) { + struct vn_command_buffer *primary_cmd = + vn_command_buffer_from_handle(commandBuffer); VN_CMD_ENQUEUE(vkCmdExecuteCommands, commandBuffer, commandBufferCount, pCommandBuffers); + + if (primary_cmd->in_render_pass) { + for (uint32_t i = 0; i < commandBufferCount; i++) { + struct vn_command_buffer *secondary_cmd = + vn_command_buffer_from_handle(pCommandBuffers[i]); + if (secondary_cmd->in_render_pass) + vn_cmd_merge_batched_query_feedback(primary_cmd, secondary_cmd); + } + } } void diff --git a/src/virtio/vulkan/vn_command_buffer.h b/src/virtio/vulkan/vn_command_buffer.h index 93d62ce2fcf..3bde05b2ec8 100644 --- a/src/virtio/vulkan/vn_command_buffer.h +++ b/src/virtio/vulkan/vn_command_buffer.h @@ -80,6 +80,7 @@ struct vn_command_buffer { * the above variables. */ uint32_t view_mask; + struct list_head query_batches; }; VK_DEFINE_HANDLE_CASTS(vn_command_buffer, base.base,