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,