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 */