diff --git a/src/virtio/vulkan/vn_queue.c b/src/virtio/vulkan/vn_queue.c index ce3bca72c39..2120c0472d1 100644 --- a/src/virtio/vulkan/vn_queue.c +++ b/src/virtio/vulkan/vn_queue.c @@ -53,12 +53,23 @@ struct vn_queue_submission { union { const void *batches; const VkSubmitInfo *submit_batches; + const VkSubmitInfo2 *submit_batches2; }; VkFence fence; bool synchronous; bool has_feedback_fence; const struct vn_device_memory *wsi_mem; + + struct { + union { + void *batches; + VkSubmitInfo *submit_batches; + VkSubmitInfo2 *submit_batches2; + }; + + VkCommandBufferSubmitInfo fence_feedback_cmd_info; + } temp; }; static VkResult @@ -162,6 +173,109 @@ vn_queue_submission_prepare(struct vn_queue_submission *submit) return VK_SUCCESS; } +static const VkCommandBuffer * +vn_get_fence_feedback_cmd(struct vn_queue *queue, struct vn_fence *fence) +{ + assert(fence->feedback.slot); + + for (uint32_t i = 0; i < queue->device->queue_family_count; i++) { + if (queue->device->queue_families[i] == queue->family) + return &fence->feedback.commands[i]; + } + + unreachable("bad feedback fence"); +} + +static VkResult +vn_queue_submission_add_fence_feedback(struct vn_queue_submission *submit) +{ + struct vn_fence *fence = vn_fence_from_handle(submit->fence); + struct vn_queue *queue = vn_queue_from_handle(submit->queue); + const VkAllocationCallbacks *alloc = &queue->device->base.base.alloc; + size_t batch_size = 0; + + assert(fence->feedback.slot); + + switch (submit->batch_type) { + case VK_STRUCTURE_TYPE_SUBMIT_INFO: + batch_size = sizeof(VkSubmitInfo); + break; + case VK_STRUCTURE_TYPE_SUBMIT_INFO_2: + batch_size = sizeof(VkSubmitInfo2); + break; + default: + unreachable("unexpected batch type"); + break; + } + + size_t submit_batches_size = batch_size * submit->batch_count; + /* add space for an additional batch for fence feedback */ + size_t new_submit_batches_size = submit_batches_size + batch_size; + + submit->temp.batches = + vk_zalloc(alloc, new_submit_batches_size, VN_DEFAULT_ALIGN, + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND); + + if (!submit->temp.batches) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + /* copy only needed for non-empty submissions */ + if (submit_batches_size) + memcpy(submit->temp.batches, submit->batches, submit_batches_size); + + const VkCommandBuffer *cmd_handle = + vn_get_fence_feedback_cmd(queue, fence); + + switch (submit->batch_type) { + case VK_STRUCTURE_TYPE_SUBMIT_INFO: { + VkSubmitInfo *submit_info = + &submit->temp.submit_batches[submit->batch_count]; + + submit_info->sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info->commandBufferCount = 1; + submit_info->pCommandBuffers = cmd_handle; + + submit->submit_batches = submit->temp.submit_batches; + break; + } + case VK_STRUCTURE_TYPE_SUBMIT_INFO_2: { + VkSubmitInfo2 *submit_info2 = + &submit->temp.submit_batches2[submit->batch_count]; + + submit_info2->sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2; + submit_info2->commandBufferInfoCount = 1; + + submit->temp.fence_feedback_cmd_info.sType = + VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO; + submit->temp.fence_feedback_cmd_info.pNext = NULL; + submit->temp.fence_feedback_cmd_info.commandBuffer = *cmd_handle; + + submit_info2->pCommandBufferInfos = + &submit->temp.fence_feedback_cmd_info; + + submit->submit_batches2 = submit->temp.submit_batches2; + break; + } + default: + unreachable("unexpected batch type"); + break; + } + + submit->batch_count++; + + return VK_SUCCESS; +} + +static void +vn_queue_submission_cleanup(struct vn_queue_submission *submit) +{ + struct vn_queue *queue = vn_queue_from_handle(submit->queue); + const VkAllocationCallbacks *alloc = &queue->device->base.base.alloc; + + if (submit->has_feedback_fence) + vk_free(alloc, submit->temp.batches); +} + static VkResult vn_queue_submission_prepare_submit(struct vn_queue_submission *submit, VkQueue queue, @@ -179,20 +293,13 @@ vn_queue_submission_prepare_submit(struct vn_queue_submission *submit, if (result != VK_SUCCESS) return result; - return result; -} - -static const VkCommandBuffer -vn_get_fence_feedback_cmd(struct vn_queue *queue, struct vn_fence *fence) -{ - assert(fence->feedback.slot); - - for (uint32_t i = 0; i < queue->device->queue_family_count; i++) { - if (queue->device->queue_families[i] == queue->family) - return fence->feedback.commands[i]; + if (submit->has_feedback_fence) { + result = vn_queue_submission_add_fence_feedback(submit); + if (result != VK_SUCCESS) + return result; } - unreachable("bad feedback fence"); + return VK_SUCCESS; } static VkResult @@ -249,15 +356,11 @@ vn_QueueSubmit(VkQueue queue_h, if (result != VK_SUCCESS) return vn_error(dev->instance, VK_ERROR_OUT_OF_HOST_MEMORY); - /* if the original submission involves a feedback fence: - * - defer the feedback fence to another submit to avoid deep copy - * - defer the potential sync_submit to the feedback fence submission - */ - result = vn_queue_submit( - dev->instance, submit.queue, submit.batch_count, submit.submit_batches, - submit.has_feedback_fence ? VK_NULL_HANDLE : submit.fence, - !submit.has_feedback_fence && submit.synchronous); + result = vn_queue_submit(dev->instance, submit.queue, submit.batch_count, + submit.submit_batches, submit.fence, + submit.synchronous); if (result != VK_SUCCESS) { + vn_queue_submission_cleanup(&submit); return vn_error(dev->instance, result); } @@ -283,27 +386,6 @@ vn_QueueSubmit(VkQueue queue_h, } } - /* TODO intercept original submit batches to append the fence feedback cmd - * with a per-queue cached submission builder to avoid transient allocs. - * - * vn_queue_submission bits must be fixed for VkTimelineSemaphoreSubmitInfo - * before adding timeline semaphore feedback. - */ - if (submit.has_feedback_fence) { - const VkCommandBuffer cmd_handle = - vn_get_fence_feedback_cmd(queue, fence); - const VkSubmitInfo info = { - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, - .commandBufferCount = 1, - .pCommandBuffers = &cmd_handle, - }; - result = vn_queue_submit(dev->instance, submit.queue, 1, &info, - submit.fence, submit.synchronous); - if (result != VK_SUCCESS) { - return vn_error(dev->instance, result); - } - } - if (submit.wsi_mem) { /* XXX this is always false and kills the performance */ if (dev->instance->renderer->info.has_implicit_fencing) { @@ -322,6 +404,8 @@ vn_QueueSubmit(VkQueue queue_h, } } + vn_queue_submission_cleanup(&submit); + return VK_SUCCESS; } @@ -414,6 +498,9 @@ vn_queue_submit2_feedback_fence(struct vn_queue *queue, assert(fence->feedback.slot); + const VkCommandBuffer *cmd_handle = + vn_get_fence_feedback_cmd(queue, fence); + const VkSubmitInfo2 submit = { .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2, .commandBufferInfoCount = 1, @@ -421,7 +508,7 @@ vn_queue_submit2_feedback_fence(struct vn_queue *queue, (VkCommandBufferSubmitInfo[]){ { .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO, - .commandBuffer = vn_get_fence_feedback_cmd(queue, fence), + .commandBuffer = *cmd_handle, .deviceMask = 0, }, },