From 942ec179f3d9c74fcd14a58a623c039c494d9a7a Mon Sep 17 00:00:00 2001 From: Yiwei Zhang Date: Tue, 24 May 2022 16:31:20 +0000 Subject: venus: add event feedback - add perf option VN_PERF_NO_EVENT_FEEDBACK - intercept to record feedback cmds for: - vkCmdSetEvent - vkCmdResetEvent - add feedback code path for - vkGetEventStatus - vkSetEvent - vkResetEvent Test: dEQP-VK.synchronization.basic.event.* Test: dEQP-VK.api.command_buffers.record_simul* Signed-off-by: Yiwei Zhang Reviewed-by: Ryan Neph Reviewed-by: Chad Versace Part-of: --- src/virtio/vulkan/vn_command_buffer.c | 6 +++ src/virtio/vulkan/vn_common.c | 1 + src/virtio/vulkan/vn_common.h | 1 + src/virtio/vulkan/vn_device.c | 36 +++++++++++++++++- src/virtio/vulkan/vn_device.h | 3 ++ src/virtio/vulkan/vn_feedback.c | 59 +++++++++++++++++++++++++++++ src/virtio/vulkan/vn_feedback.h | 6 +++ src/virtio/vulkan/vn_queue.c | 70 +++++++++++++++++++++++++++++++---- src/virtio/vulkan/vn_queue.h | 8 ++++ 9 files changed, 181 insertions(+), 9 deletions(-) diff --git a/src/virtio/vulkan/vn_command_buffer.c b/src/virtio/vulkan/vn_command_buffer.c index b293288e69c..804e435ba9f 100644 --- a/src/virtio/vulkan/vn_command_buffer.c +++ b/src/virtio/vulkan/vn_command_buffer.c @@ -1141,6 +1141,9 @@ vn_CmdSetEvent(VkCommandBuffer commandBuffer, VkPipelineStageFlags stageMask) { VN_CMD_ENQUEUE(vkCmdSetEvent, commandBuffer, event, stageMask); + + vn_feedback_event_cmd_record(commandBuffer, event, stageMask, + VK_EVENT_SET); } void @@ -1149,6 +1152,9 @@ vn_CmdResetEvent(VkCommandBuffer commandBuffer, VkPipelineStageFlags stageMask) { VN_CMD_ENQUEUE(vkCmdResetEvent, commandBuffer, event, stageMask); + + vn_feedback_event_cmd_record(commandBuffer, event, stageMask, + VK_EVENT_RESET); } void diff --git a/src/virtio/vulkan/vn_common.c b/src/virtio/vulkan/vn_common.c index 743e3251517..ec48f72a2a0 100644 --- a/src/virtio/vulkan/vn_common.c +++ b/src/virtio/vulkan/vn_common.c @@ -34,6 +34,7 @@ static const struct debug_control vn_perf_options[] = { { "no_async_set_alloc", VN_PERF_NO_ASYNC_SET_ALLOC }, { "no_async_buffer_create", VN_PERF_NO_ASYNC_BUFFER_CREATE }, { "no_async_queue_submit", VN_PERF_NO_ASYNC_QUEUE_SUBMIT }, + { "no_event_feedback", VN_PERF_NO_EVENT_FEEDBACK }, { NULL, 0 }, }; diff --git a/src/virtio/vulkan/vn_common.h b/src/virtio/vulkan/vn_common.h index b8079949bcd..47505e7e805 100644 --- a/src/virtio/vulkan/vn_common.h +++ b/src/virtio/vulkan/vn_common.h @@ -146,6 +146,7 @@ enum vn_perf { VN_PERF_NO_ASYNC_SET_ALLOC = 1ull << 0, VN_PERF_NO_ASYNC_BUFFER_CREATE = 1ull << 1, VN_PERF_NO_ASYNC_QUEUE_SUBMIT = 1ull << 2, + VN_PERF_NO_EVENT_FEEDBACK = 1ull << 3, }; typedef uint64_t vn_object_id; diff --git a/src/virtio/vulkan/vn_device.c b/src/virtio/vulkan/vn_device.c index 28b64bb1ce5..2c8c90cc6f5 100644 --- a/src/virtio/vulkan/vn_device.c +++ b/src/virtio/vulkan/vn_device.c @@ -300,6 +300,31 @@ vn_device_fix_create_info(const struct vn_device *dev, return local_info; } +static inline VkResult +vn_device_feedback_pool_init(struct vn_device *dev) +{ + /* The feedback pool defaults to suballocate slots of 8 bytes each. Initial + * pool size of 4096 corresponds to a total of 512 fences, semaphores and + * events, which well covers the common scenarios. Pool can grow anyway. + */ + static const uint32_t pool_size = 4096; + const VkAllocationCallbacks *alloc = &dev->base.base.alloc; + + if (VN_PERF(NO_EVENT_FEEDBACK)) + return VK_SUCCESS; + + return vn_feedback_pool_init(dev, &dev->feedback_pool, pool_size, alloc); +} + +static inline void +vn_device_feedback_pool_fini(struct vn_device *dev) +{ + if (VN_PERF(NO_EVENT_FEEDBACK)) + return; + + vn_feedback_pool_fini(&dev->feedback_pool); +} + static VkResult vn_device_init(struct vn_device *dev, struct vn_physical_device *physical_dev, @@ -346,12 +371,19 @@ vn_device_init(struct vn_device *dev, if (result != VK_SUCCESS) goto out_memory_pool_fini; - result = vn_device_init_queues(dev, create_info); + result = vn_device_feedback_pool_init(dev); if (result != VK_SUCCESS) goto out_buffer_cache_fini; + result = vn_device_init_queues(dev, create_info); + if (result != VK_SUCCESS) + goto out_feedback_pool_fini; + return VK_SUCCESS; +out_feedback_pool_fini: + vn_device_feedback_pool_fini(dev); + out_buffer_cache_fini: vn_buffer_cache_fini(dev); @@ -423,6 +455,8 @@ vn_DestroyDevice(VkDevice device, const VkAllocationCallbacks *pAllocator) for (uint32_t i = 0; i < dev->queue_count; i++) vn_queue_fini(&dev->queues[i]); + vn_device_feedback_pool_fini(dev); + vn_buffer_cache_fini(dev); for (uint32_t i = 0; i < ARRAY_SIZE(dev->memory_pools); i++) diff --git a/src/virtio/vulkan/vn_device.h b/src/virtio/vulkan/vn_device.h index d85cf088b92..123a39e0352 100644 --- a/src/virtio/vulkan/vn_device.h +++ b/src/virtio/vulkan/vn_device.h @@ -15,6 +15,7 @@ #include "vn_buffer.h" #include "vn_device_memory.h" +#include "vn_feedback.h" struct vn_device { struct vn_device_base base; @@ -31,6 +32,8 @@ struct vn_device { struct vn_buffer_cache buffer_cache; + struct vn_feedback_pool feedback_pool; + struct vn_queue *queues; uint32_t queue_count; }; diff --git a/src/virtio/vulkan/vn_feedback.c b/src/virtio/vulkan/vn_feedback.c index cdfdca9db3b..24041229f0c 100644 --- a/src/virtio/vulkan/vn_feedback.c +++ b/src/virtio/vulkan/vn_feedback.c @@ -7,6 +7,7 @@ #include "vn_device.h" #include "vn_physical_device.h" +#include "vn_queue.h" /* coherent buffer with bound and mapped memory */ struct vn_feedback_buffer { @@ -263,3 +264,61 @@ vn_feedback_pool_free(struct vn_feedback_pool *pool, list_add(&slot->head, &pool->free_slots); simple_mtx_unlock(&pool->mutex); } + +void +vn_feedback_event_cmd_record(VkCommandBuffer cmd_handle, + VkEvent ev_handle, + VkPipelineStageFlags stage_mask, + VkResult status) +{ + /* For vkCmdSetEvent and vkCmdResetEvent feedback interception. + * + * The injection point is after the event call to avoid introducing + * unexpected src stage waiting for VK_PIPELINE_STAGE_HOST_BIT and + * VK_PIPELINE_STAGE_TRANSFER_BIT if they are not already being waited by + * vkCmdSetEvent or vkCmdResetEvent. On the other hand, the delay in the + * feedback signal is acceptable for the nature of VkEvent, and the event + * feedback cmds lifecycle is guarded by the intercepted command buffer. + */ + struct vn_event *ev = vn_event_from_handle(ev_handle); + struct vn_feedback_slot *slot = ev->feedback_slot; + + if (!slot) + return; + + STATIC_ASSERT(sizeof(*slot->status) == 4); + + const VkBufferMemoryBarrier buf_barrier_before = { + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + .pNext = NULL, + .srcAccessMask = + VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = slot->buffer, + .offset = slot->offset, + .size = 4, + }; + vn_CmdPipelineBarrier(cmd_handle, + stage_mask | VK_PIPELINE_STAGE_HOST_BIT | + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 1, + &buf_barrier_before, 0, NULL); + vn_CmdFillBuffer(cmd_handle, slot->buffer, slot->offset, 4, status); + + const VkBufferMemoryBarrier buf_barrier_after = { + .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, + .pNext = NULL, + .srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT, + .dstAccessMask = VK_ACCESS_HOST_READ_BIT | VK_ACCESS_HOST_WRITE_BIT, + .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED, + .buffer = slot->buffer, + .offset = slot->offset, + .size = 4, + }; + vn_CmdPipelineBarrier(cmd_handle, VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_HOST_BIT, 0, 0, NULL, 1, + &buf_barrier_after, 0, NULL); +} diff --git a/src/virtio/vulkan/vn_feedback.h b/src/virtio/vulkan/vn_feedback.h index ea5b47e2f8a..f5b008d264e 100644 --- a/src/virtio/vulkan/vn_feedback.h +++ b/src/virtio/vulkan/vn_feedback.h @@ -101,4 +101,10 @@ vn_feedback_set_counter(struct vn_feedback_slot *slot, uint64_t counter) *slot->counter = counter; } +void +vn_feedback_event_cmd_record(VkCommandBuffer cmd_handle, + VkEvent ev_handle, + VkPipelineStageFlags stage_mask, + VkResult status); + #endif /* VN_FEEDBACK_H */ diff --git a/src/virtio/vulkan/vn_queue.c b/src/virtio/vulkan/vn_queue.c index 006ccc3e6a0..37f8ebe1f71 100644 --- a/src/virtio/vulkan/vn_queue.c +++ b/src/virtio/vulkan/vn_queue.c @@ -1030,6 +1030,33 @@ vn_GetSemaphoreFdKHR(VkDevice device, /* event commands */ +static VkResult +vn_event_feedback_init(struct vn_device *dev, struct vn_event *ev) +{ + struct vn_feedback_slot *slot; + + if (VN_PERF(NO_EVENT_FEEDBACK)) + return VK_SUCCESS; + + slot = vn_feedback_pool_alloc(&dev->feedback_pool, VN_FEEDBACK_TYPE_EVENT); + if (!slot) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + /* newly created event object is in the unsignaled state */ + vn_feedback_set_status(slot, VK_EVENT_RESET); + + ev->feedback_slot = slot; + + return VK_SUCCESS; +} + +static inline void +vn_event_feedback_fini(struct vn_device *dev, struct vn_event *ev) +{ + if (ev->feedback_slot) + vn_feedback_pool_free(&dev->feedback_pool, ev->feedback_slot); +} + VkResult vn_CreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo, @@ -1047,6 +1074,13 @@ vn_CreateEvent(VkDevice device, vn_object_base_init(&ev->base, VK_OBJECT_TYPE_EVENT, &dev->base); + /* feedback is only needed to speed up host operations */ + if (!(pCreateInfo->flags & VK_EVENT_CREATE_DEVICE_ONLY_BIT)) { + VkResult result = vn_event_feedback_init(dev, ev); + if (result != VK_SUCCESS) + return vn_error(dev->instance, result); + } + VkEvent ev_handle = vn_event_to_handle(ev); vn_async_vkCreateEvent(dev->instance, device, pCreateInfo, NULL, &ev_handle); @@ -1071,6 +1105,8 @@ vn_DestroyEvent(VkDevice device, vn_async_vkDestroyEvent(dev->instance, device, event, NULL); + vn_event_feedback_fini(dev, ev); + vn_object_base_fini(&ev->base); vk_free(alloc, ev); } @@ -1079,11 +1115,13 @@ VkResult vn_GetEventStatus(VkDevice device, VkEvent event) { struct vn_device *dev = vn_device_from_handle(device); + struct vn_event *ev = vn_event_from_handle(event); + VkResult result; - /* TODO When the renderer supports it (requires a new vk extension), there - * should be a coherent memory backing the event. - */ - VkResult result = vn_call_vkGetEventStatus(dev->instance, device, event); + if (ev->feedback_slot) + result = vn_feedback_get_status(ev->feedback_slot); + else + result = vn_call_vkGetEventStatus(dev->instance, device, event); return vn_result(dev->instance, result); } @@ -1092,18 +1130,34 @@ VkResult vn_SetEvent(VkDevice device, VkEvent event) { struct vn_device *dev = vn_device_from_handle(device); + struct vn_event *ev = vn_event_from_handle(event); - VkResult result = vn_call_vkSetEvent(dev->instance, device, event); + if (ev->feedback_slot) { + vn_feedback_set_status(ev->feedback_slot, VK_EVENT_SET); + vn_async_vkSetEvent(dev->instance, device, event); + } else { + VkResult result = vn_call_vkSetEvent(dev->instance, device, event); + if (result != VK_SUCCESS) + return vn_error(dev->instance, result); + } - return vn_result(dev->instance, result); + return VK_SUCCESS; } VkResult vn_ResetEvent(VkDevice device, VkEvent event) { struct vn_device *dev = vn_device_from_handle(device); + struct vn_event *ev = vn_event_from_handle(event); - VkResult result = vn_call_vkResetEvent(dev->instance, device, event); + if (ev->feedback_slot) { + vn_feedback_reset_status(ev->feedback_slot); + vn_async_vkResetEvent(dev->instance, device, event); + } else { + VkResult result = vn_call_vkResetEvent(dev->instance, device, event); + if (result != VK_SUCCESS) + return vn_error(dev->instance, result); + } - return vn_result(dev->instance, result); + return VK_SUCCESS; } diff --git a/src/virtio/vulkan/vn_queue.h b/src/virtio/vulkan/vn_queue.h index c692a434ea0..a66697b4f9c 100644 --- a/src/virtio/vulkan/vn_queue.h +++ b/src/virtio/vulkan/vn_queue.h @@ -13,6 +13,8 @@ #include "vn_common.h" +#include "vn_feedback.h" + struct vn_queue { struct vn_object_base base; @@ -72,6 +74,12 @@ VK_DEFINE_NONDISP_HANDLE_CASTS(vn_semaphore, struct vn_event { struct vn_object_base base; + + /* non-NULL if below are satisfied: + * - event is created without VK_EVENT_CREATE_DEVICE_ONLY_BIT + * - VN_PERF_NO_EVENT_FEEDBACK is disabled + */ + struct vn_feedback_slot *feedback_slot; }; VK_DEFINE_NONDISP_HANDLE_CASTS(vn_event, base.base, -- cgit v1.2.3