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,