From e57cf175e23937f4acef6e4a1c5b9ed7f8e3cc8b Mon Sep 17 00:00:00 2001 From: Juston Li Date: Mon, 26 Feb 2024 16:43:27 -0800 Subject: [PATCH] venus: move feedback on empty last batch to prior batch For submissions with an empty last batch containing no cmd buffers but with semaphores as zink does, adding feedback to that batch would make it no longer empty and increase submission overhead on some drivers. Since feedback order is enforced by barriers, the feedback cmds can instead be appended to the previous batch (if it exists) so that the last batch remains empty. Signed-off-by: Juston Li Part-of: --- src/virtio/vulkan/vn_instance.c | 5 +++ src/virtio/vulkan/vn_instance.h | 2 + src/virtio/vulkan/vn_queue.c | 80 ++++++++++++++++++++++++++++++++- 3 files changed, 85 insertions(+), 2 deletions(-) diff --git a/src/virtio/vulkan/vn_instance.c b/src/virtio/vulkan/vn_instance.c index a53afd9cb58..ae826f7ab40 100644 --- a/src/virtio/vulkan/vn_instance.c +++ b/src/virtio/vulkan/vn_instance.c @@ -395,6 +395,11 @@ vn_CreateInstance(const VkInstanceCreateInfo *pCreateInfo, instance->enable_wsi_multi_plane_modifiers ? "yes" : "no"); } + const char *engine_name = instance->base.base.app_info.engine_name; + if (engine_name) { + instance->engine_is_zink = strcmp(engine_name, "mesa zink") == 0; + } + *pInstance = instance_handle; return VK_SUCCESS; diff --git a/src/virtio/vulkan/vn_instance.h b/src/virtio/vulkan/vn_instance.h index 9b611d20e43..bcc42b6f4af 100644 --- a/src/virtio/vulkan/vn_instance.h +++ b/src/virtio/vulkan/vn_instance.h @@ -69,6 +69,8 @@ struct vn_instance { uint32_t renderer_api_version; uint32_t renderer_version; + bool engine_is_zink; + struct { mtx_t mutex; bool initialized; diff --git a/src/virtio/vulkan/vn_queue.c b/src/virtio/vulkan/vn_queue.c index 0a4fd274a67..0ff1cd01a66 100644 --- a/src/virtio/vulkan/vn_queue.c +++ b/src/virtio/vulkan/vn_queue.c @@ -21,6 +21,7 @@ #include "vn_device.h" #include "vn_device_memory.h" #include "vn_feedback.h" +#include "vn_instance.h" #include "vn_physical_device.h" #include "vn_query_pool.h" #include "vn_renderer.h" @@ -42,6 +43,7 @@ struct vn_queue_submission { uint32_t cmd_count; uint32_t feedback_types; + bool has_zink_sync_batch; const struct vn_device_memory *wsi_mem; struct vn_sync_payload_external external_payload; @@ -256,6 +258,62 @@ vn_get_signal_semaphore_counter(struct vn_queue_submission *submit, } } +static bool +vn_has_zink_sync_batch(struct vn_queue_submission *submit) +{ + struct vn_queue *queue = vn_queue_from_handle(submit->queue_handle); + struct vn_device *dev = (void *)queue->base.base.base.device; + struct vn_instance *instance = dev->instance; + const uint32_t last_batch_index = submit->batch_count - 1; + + if (!instance->engine_is_zink) + return false; + + if (!submit->batch_count || !last_batch_index || + vn_get_cmd_count(submit, last_batch_index)) + return false; + + if (vn_get_wait_semaphore_count(submit, last_batch_index)) + return false; + + const uint32_t signal_count = + vn_get_signal_semaphore_count(submit, last_batch_index); + for (uint32_t i = 0; i < signal_count; i++) { + struct vn_semaphore *sem = vn_semaphore_from_handle( + vn_get_signal_semaphore(submit, last_batch_index, i)); + if (sem->feedback.slot) { + return true; + } + } + return false; +} + +static bool +vn_fix_batch_cmd_count_for_zink_sync(struct vn_queue_submission *submit, + uint32_t batch_index, + uint32_t new_cmd_count) +{ + /* If the last batch is a zink sync batch which is empty but contains + * feedback, append the feedback to the previous batch instead so that + * the last batch remains empty for perf. + */ + if (batch_index == submit->batch_count - 1 && + submit->has_zink_sync_batch) { + if (submit->batch_type == VK_STRUCTURE_TYPE_SUBMIT_INFO_2) { + VkSubmitInfo2 *batch = + &submit->temp.submit2_batches[batch_index - 1]; + assert(batch->pCommandBufferInfos); + batch->commandBufferInfoCount += new_cmd_count; + } else { + VkSubmitInfo *batch = &submit->temp.submit_batches[batch_index - 1]; + assert(batch->pCommandBuffers); + batch->commandBufferCount += new_cmd_count; + } + return true; + } + return false; +} + static bool vn_semaphore_wait_external(struct vn_device *dev, struct vn_semaphore *sem); @@ -340,8 +398,16 @@ vn_queue_submission_count_batch_feedback(struct vn_queue_submission *submit, submit->cmd_count++; } - if (feedback_types) + /* Space to copy the original cmds to append feedback to it. + * If the last batch is a zink sync batch which is an empty batch with + * sem feedback, feedback will be appended to the second to last batch + * so also need to copy the second to last batch's original cmds even + * if it doesn't have feedback itself. + */ + if (feedback_types || (batch_index == submit->batch_count - 2 && + submit->has_zink_sync_batch)) { submit->cmd_count += cmd_count; + } } submit->feedback_types |= feedback_types; @@ -357,6 +423,9 @@ vn_queue_submission_prepare(struct vn_queue_submission *submit) if (fence && fence->feedback.slot) submit->feedback_types |= VN_FEEDBACK_TYPE_FENCE; + if (submit->batch_type != VK_STRUCTURE_TYPE_BIND_SPARSE_INFO) + submit->has_zink_sync_batch = vn_has_zink_sync_batch(submit); + submit->external_payload.ring_idx = queue->ring_idx; submit->wsi_mem = NULL; @@ -640,6 +709,9 @@ vn_queue_submission_add_feedback_cmds(struct vn_queue_submission *submit, if (result != VK_SUCCESS) return result; } + if (vn_fix_batch_cmd_count_for_zink_sync(submit, batch_index, + new_cmd_count)) + return VK_SUCCESS; } if (feedback_types & VN_FEEDBACK_TYPE_FENCE) { @@ -696,8 +768,12 @@ vn_queue_submission_setup_batch(struct vn_queue_submission *submit, /* If the batch has qfb, sfb or ffb, copy the original commands and append * feedback cmds. + * If this is the second to last batch and the last batch a zink sync batch + * which is empty but has feedback, also copy the original commands for + * this batch so that the last batch's feedback can be appended to it. */ - if (extra_cmd_count) { + if (extra_cmd_count || (batch_index == submit->batch_count - 2 && + submit->has_zink_sync_batch)) { const size_t cmd_size = vn_get_cmd_size(submit); const size_t total_cmd_size = cmd_count * cmd_size; /* copy only needed for non-empty batches */