From c888da3d48a55ad7be4fedf783369fb12163b03e Mon Sep 17 00:00:00 2001 From: Hans-Kristian Arntzen Date: Mon, 24 Oct 2022 14:47:51 +0200 Subject: [PATCH] vulkan/wsi: Add mechanism to wait for WSI semaphore unsignal. When vkWaitForPresentKHR succeeds, we are guaranteed that any dependent semaphores have been unsignalled. In an explicit sync world, we are guaranteed this automatically by having a present complete, since that event must follow a semaphore wait completion. However, if the swapchain image is implicitly synchronized, the semaphore might technically not have been unsignaled before the present complete event triggers. Present IDs must be signalled in monotonic order, same as timeline semaphores. Signed-off-by: Hans-Kristian Arntzen Reviewed-by: Joshua Ashton Part-of: --- src/vulkan/wsi/wsi_common.c | 73 +++++++++++++++++++++++++++++ src/vulkan/wsi/wsi_common.h | 7 +++ src/vulkan/wsi/wsi_common_private.h | 5 ++ 3 files changed, 85 insertions(+) diff --git a/src/vulkan/wsi/wsi_common.c b/src/vulkan/wsi/wsi_common.c index ae89f5589c7..34512c9cb88 100644 --- a/src/vulkan/wsi/wsi_common.c +++ b/src/vulkan/wsi/wsi_common.c @@ -129,6 +129,12 @@ wsi_device_init(struct wsi_device *wsi, &vk_physical_device_from_handle(pdevice)->supported_extensions; wsi->has_import_memory_host = supported_extensions->EXT_external_memory_host; + wsi->khr_present_wait = + supported_extensions->KHR_present_id && + supported_extensions->KHR_present_wait; + + /* We cannot expose KHR_present_wait without timeline semaphores. */ + assert(!wsi->khr_present_wait || supported_extensions->KHR_timeline_semaphore); list_inithead(&wsi->hotplug_fences); @@ -169,6 +175,8 @@ wsi_device_init(struct wsi_device *wsi, WSI_GET_CB(WaitForFences); WSI_GET_CB(MapMemory); WSI_GET_CB(UnmapMemory); + if (wsi->khr_present_wait) + WSI_GET_CB(WaitSemaphoresKHR); #undef WSI_GET_CB #ifdef VK_USE_PLATFORM_XCB_KHR @@ -487,6 +495,8 @@ wsi_swapchain_finish(struct wsi_swapchain *chain) } chain->wsi->DestroySemaphore(chain->device, chain->dma_buf_semaphore, &chain->alloc); + chain->wsi->DestroySemaphore(chain->device, chain->present_id_timeline, + &chain->alloc); int cmd_pools_count = chain->buffer_blit_queue != VK_NULL_HANDLE ? 1 : chain->wsi->queue_family_count; @@ -879,12 +889,33 @@ wsi_CreateSwapchainKHR(VkDevice _device, return VK_ERROR_OUT_OF_HOST_MEMORY; } + if (wsi_device->khr_present_wait) { + const VkSemaphoreTypeCreateInfo type_info = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO, + .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE, + }; + + const VkSemaphoreCreateInfo sem_info = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + .pNext = &type_info, + .flags = 0, + }; + + /* We assume here that a driver exposing present_wait also exposes VK_KHR_timeline_semaphore. */ + result = wsi_device->CreateSemaphore(_device, &sem_info, alloc, &swapchain->present_id_timeline); + if (result != VK_SUCCESS) { + swapchain->destroy(swapchain, alloc); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + } + if (swapchain->buffer_blit_queue != VK_NULL_HANDLE) { swapchain->buffer_blit_semaphores = vk_zalloc(alloc, sizeof (*swapchain->buffer_blit_semaphores) * swapchain->image_count, sizeof (*swapchain->buffer_blit_semaphores), VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); if (!swapchain->buffer_blit_semaphores) { + wsi_device->DestroySemaphore(_device, swapchain->present_id_timeline, alloc); swapchain->destroy(swapchain, alloc); return VK_ERROR_OUT_OF_HOST_MEMORY; } @@ -1091,6 +1122,27 @@ wsi_AcquireNextImage2KHR(VkDevice _device, _device, pAcquireInfo, pImageIndex); } +static VkResult wsi_signal_present_id_timeline(struct wsi_swapchain *swapchain, + VkQueue queue, uint64_t present_id) +{ + assert(swapchain->present_id_timeline); + + const VkTimelineSemaphoreSubmitInfo timeline_info = { + .sType = VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO, + .pSignalSemaphoreValues = &present_id, + .signalSemaphoreValueCount = 1, + }; + + const VkSubmitInfo submit_info = { + .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, + .pNext = &timeline_info, + .signalSemaphoreCount = 1, + .pSignalSemaphores = &swapchain->present_id_timeline, + }; + + return swapchain->wsi->QueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); +} + VkResult wsi_common_queue_present(const struct wsi_device *wsi, VkDevice device, @@ -1260,6 +1312,12 @@ wsi_common_queue_present(const struct wsi_device *wsi, if (present_ids && present_ids->pPresentIds) present_id = present_ids->pPresentIds[i]; + if (present_id) { + result = wsi_signal_present_id_timeline(swapchain, queue, present_id); + if (result != VK_SUCCESS) + goto fail_present; + } + result = swapchain->queue_present(swapchain, image_index, present_id, region); if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) goto fail_present; @@ -1386,6 +1444,21 @@ wsi_common_bind_swapchain_image(const struct wsi_device *wsi, return wsi->BindImageMemory(chain->device, vk_image, image->memory, 0); } +VkResult +wsi_swapchain_wait_for_present_semaphore(const struct wsi_swapchain *chain, + uint64_t present_id, uint64_t timeout) +{ + assert(chain->present_id_timeline); + const VkSemaphoreWaitInfo wait_info = { + .sType = VK_STRUCTURE_TYPE_SEMAPHORE_WAIT_INFO, + .semaphoreCount = 1, + .pSemaphores = &chain->present_id_timeline, + .pValues = &present_id, + }; + + return chain->wsi->WaitSemaphoresKHR(chain->device, &wait_info, timeout); +} + uint32_t wsi_select_memory_type(const struct wsi_device *wsi, VkMemoryPropertyFlags req_props, diff --git a/src/vulkan/wsi/wsi_common.h b/src/vulkan/wsi/wsi_common.h index 886bac9f800..19b34ed6e18 100644 --- a/src/vulkan/wsi/wsi_common.h +++ b/src/vulkan/wsi/wsi_common.h @@ -166,6 +166,12 @@ struct wsi_device { */ bool signal_fence_with_memory; + /* Whether present_wait functionality is enabled on the device. + * In this case, we have to create an extra timeline semaphore + * to be able to synchronize with the WSI present semaphore being unsignalled. + * This requires VK_KHR_timeline_semaphore. */ + bool khr_present_wait; + /* * This sets the ownership for a WSI memory object: * @@ -229,6 +235,7 @@ struct wsi_device { WSI_CB(WaitForFences); WSI_CB(MapMemory); WSI_CB(UnmapMemory); + WSI_CB(WaitSemaphoresKHR); #undef WSI_CB struct wsi_interface * wsi[VK_ICD_WSI_PLATFORM_MAX]; diff --git a/src/vulkan/wsi/wsi_common_private.h b/src/vulkan/wsi/wsi_common_private.h index 1b1ed138465..92efcddf5e4 100644 --- a/src/vulkan/wsi/wsi_common_private.h +++ b/src/vulkan/wsi/wsi_common_private.h @@ -134,6 +134,7 @@ struct wsi_swapchain { VkFence* fences; VkSemaphore* buffer_blit_semaphores; VkPresentModeKHR present_mode; + VkSemaphore present_id_timeline; int signal_dma_buf_from_semaphore; VkSemaphore dma_buf_semaphore; @@ -256,6 +257,10 @@ void wsi_destroy_image(const struct wsi_swapchain *chain, struct wsi_image *image); +VkResult +wsi_swapchain_wait_for_present_semaphore(const struct wsi_swapchain *chain, + uint64_t present_id, uint64_t timeout); + #ifdef HAVE_LIBDRM VkResult wsi_prepare_signal_dma_buf_from_semaphore(struct wsi_swapchain *chain,