From 3c7e973d40282c3560df267ce1aba03115685391 Mon Sep 17 00:00:00 2001 From: Faith Ekstrand Date: Fri, 15 Aug 2025 13:57:44 -0400 Subject: [PATCH] vulkan: Add a vk_sync_wait_unwrap() helper Reviewed-by: Lars-Ivar Hesselberg Simonsen Reviewed-by: Adam Jackson Reviewed-by: Lionel Landwerlin Part-of: --- src/vulkan/runtime/vk_queue.c | 55 ++++++-------------------- src/vulkan/runtime/vk_sync.c | 72 +++++++++++++++++++++++++++++++++++ src/vulkan/runtime/vk_sync.h | 6 +++ 3 files changed, 90 insertions(+), 43 deletions(-) diff --git a/src/vulkan/runtime/vk_queue.c b/src/vulkan/runtime/vk_queue.c index 13ba695aa6e..20018e33380 100644 --- a/src/vulkan/runtime/vk_queue.c +++ b/src/vulkan/runtime/vk_queue.c @@ -604,55 +604,24 @@ vk_queue_submit_final(struct vk_queue *queue, */ uint32_t wait_count = 0; for (uint32_t i = 0; i < submit->wait_count; i++) { - /* A timeline wait on 0 is always a no-op */ - if ((submit->waits[i].sync->flags & VK_SYNC_IS_TIMELINE) && - submit->waits[i].wait_value == 0) - continue; + struct vk_sync_timeline_point *wait_point; + result = vk_sync_wait_unwrap(queue->base.device, + &submit->waits[i], &wait_point); + if (wait_point != NULL) + submit->_wait_points[i] = wait_point; + if (unlikely(result != VK_SUCCESS)) + result = vk_queue_set_lost(queue, "Failed to unwrap sync wait"); - /* Waits on dummy vk_syncs are no-ops */ - if (vk_sync_type_is_dummy(submit->waits[i].sync->type)) { + if (submit->waits[i].sync == NULL) { /* We are about to lose track of this wait, if it has a temporary - * we need to destroy it now, as vk_queue_submit_cleanup will not - * know about it */ - if (submit->_wait_temps[i] != NULL) { + * or a wait point, we need to destroy it now, as + * vk_queue_submit_cleanup will not know about it + */ + if (submit->_wait_temps[i] != NULL) vk_sync_destroy(queue->base.device, submit->_wait_temps[i]); - submit->waits[i].sync = NULL; - } continue; } - /* For emulated timelines, we have a binary vk_sync associated with - * each time point and pass the binary vk_sync to the driver. - */ - struct vk_sync_timeline *timeline = - vk_sync_as_timeline(submit->waits[i].sync); - if (timeline) { - assert(queue->base.device->timeline_mode == - VK_DEVICE_TIMELINE_MODE_EMULATED); - result = vk_sync_timeline_get_point(queue->base.device, timeline, - submit->waits[i].wait_value, - &submit->_wait_points[i]); - if (unlikely(result != VK_SUCCESS)) { - result = vk_queue_set_lost(queue, - "Time point >= %"PRIu64" not found", - submit->waits[i].wait_value); - } - - /* This can happen if the point is long past */ - if (submit->_wait_points[i] == NULL) - continue; - - submit->waits[i].sync = &submit->_wait_points[i]->sync; - submit->waits[i].wait_value = 0; - } - - struct vk_sync_binary *binary = - vk_sync_as_binary(submit->waits[i].sync); - if (binary) { - submit->waits[i].sync = &binary->timeline; - submit->waits[i].wait_value = binary->next_point; - } - assert((submit->waits[i].sync->flags & VK_SYNC_IS_TIMELINE) || submit->waits[i].wait_value == 0); diff --git a/src/vulkan/runtime/vk_sync.c b/src/vulkan/runtime/vk_sync.c index ff8d54bba36..043c0a46673 100644 --- a/src/vulkan/runtime/vk_sync.c +++ b/src/vulkan/runtime/vk_sync.c @@ -34,6 +34,9 @@ #include "vk_device.h" #include "vk_log.h" #include "vk_physical_device.h" +#include "vk_sync_binary.h" +#include "vk_sync_dummy.h" +#include "vk_sync_timeline.h" static void vk_sync_type_validate(const struct vk_sync_type *type) @@ -554,3 +557,72 @@ vk_sync_set_win32_export_params(struct vk_device *device, return sync->type->set_win32_export_params(device, sync, security_attributes, access, name); } + +/** + * Unwraps a vk_sync_wait, removing any vk_sync_timeline or vk_sync_binary + * and replacing the sync with the actual driver primitive. + * + * After this is returns, wait->sync may be NULL, indicating no actual wait + * is needed and this wait can be discarded. + * + * If the sync is a timeline, the point will be returned in point_out. + * Otherwise point_out will be set to NULL. + */ +VkResult +vk_sync_wait_unwrap(struct vk_device *device, + struct vk_sync_wait *wait, + struct vk_sync_timeline_point **point_out) +{ + *point_out = NULL; + + if (wait->sync->flags & VK_SYNC_IS_TIMELINE) { + if (wait->wait_value == 0) { + *wait = (struct vk_sync_wait) { .sync = NULL }; + return VK_SUCCESS; + } + } else { + assert(wait->wait_value == 0); + } + + struct vk_sync_timeline *timeline = vk_sync_as_timeline(wait->sync); + if (timeline) { + assert(device->timeline_mode == VK_DEVICE_TIMELINE_MODE_EMULATED); + VkResult result = vk_sync_timeline_get_point(device, timeline, + wait->wait_value, + point_out); + if (unlikely(result != VK_SUCCESS)) { + /* vk_sync_timeline_get_point() returns VK_NOT_READY if no time + * point can be found. Turn that into an actual error. + */ + return vk_errorf(device, VK_ERROR_UNKNOWN, + "Time point >= %"PRIu64" not found", + wait->wait_value); + } + + /* This can happen if the point is long past */ + if (*point_out == NULL) { + *wait = (struct vk_sync_wait) { .sync = NULL }; + return VK_SUCCESS; + } + + wait->sync = &(*point_out)->sync; + wait->wait_value = 0; + } + + struct vk_sync_binary *binary = vk_sync_as_binary(wait->sync); + if (binary) { + wait->sync = &binary->timeline; + wait->wait_value = binary->next_point; + } + + if (vk_sync_type_is_dummy(wait->sync->type)) { + if (*point_out != NULL) { + vk_sync_timeline_point_unref(device, *point_out); + *point_out = NULL; + } + *wait = (struct vk_sync_wait) { .sync = NULL }; + return VK_SUCCESS; + } + + return VK_SUCCESS; +} diff --git a/src/vulkan/runtime/vk_sync.h b/src/vulkan/runtime/vk_sync.h index f4a1f1e38e3..cfa06fb153c 100644 --- a/src/vulkan/runtime/vk_sync.h +++ b/src/vulkan/runtime/vk_sync.h @@ -425,6 +425,12 @@ VkResult MUST_CHECK vk_sync_move(struct vk_device *device, struct vk_sync *dst, struct vk_sync *src); +struct vk_sync_timeline_point; + +VkResult MUST_CHECK vk_sync_wait_unwrap(struct vk_device *device, + struct vk_sync_wait *wait, + struct vk_sync_timeline_point **point_out); + #ifdef __cplusplus } #endif