diff --git a/layer/private_data.hpp b/layer/private_data.hpp index 7514f06..6092500 100644 --- a/layer/private_data.hpp +++ b/layer/private_data.hpp @@ -120,6 +120,8 @@ struct instance_dispatch_table REQUIRED(FreeMemory) \ REQUIRED(CreateFence) \ REQUIRED(DestroyFence) \ + REQUIRED(CreateSemaphore) \ + REQUIRED(DestroySemaphore) \ REQUIRED(ResetFences) \ REQUIRED(WaitForFences) \ REQUIRED(DestroyDevice) \ diff --git a/layer/swapchain_api.cpp b/layer/swapchain_api.cpp index 8ee59a8..b043d2b 100644 --- a/layer/swapchain_api.cpp +++ b/layer/swapchain_api.cpp @@ -127,6 +127,54 @@ VKAPI_ATTR VkResult wsi_layer_vkAcquireNextImageKHR(VkDevice device, VkSwapchain return sc->acquire_next_image(timeout, semaphore, fence, pImageIndex); } +static VkResult submit_wait_request(VkQueue queue, const VkPresentInfoKHR &present_info, + layer::device_private_data &device_data) +{ + util::vector swapchain_semaphores{ util::allocator(device_data.get_allocator(), + VK_SYSTEM_ALLOCATION_SCOPE_COMMAND) }; + if (!swapchain_semaphores.try_resize(present_info.swapchainCount)) + { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + for (uint32_t i = 0; i < present_info.swapchainCount; ++i) + { + auto swapchain = reinterpret_cast(present_info.pSwapchains[i]); + swapchain_semaphores[i] = swapchain->get_image_present_semaphore(present_info.pImageIndices[i]); + } + + util::vector pipeline_stage_flags{ util::allocator::get_generic() }; + if (!pipeline_stage_flags.try_resize(present_info.waitSemaphoreCount)) + { + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + for (uint32_t i = 0; i < present_info.waitSemaphoreCount; ++i) + { + pipeline_stage_flags[i] = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT; + } + + VkSubmitInfo submit_info = { + VK_STRUCTURE_TYPE_SUBMIT_INFO, + NULL, + present_info.waitSemaphoreCount, + present_info.pWaitSemaphores, + pipeline_stage_flags.data(), + 0, + NULL, + static_cast(swapchain_semaphores.size()), + swapchain_semaphores.data(), + }; + + VkResult result = device_data.disp.QueueSubmit(queue, 1, &submit_info, VK_NULL_HANDLE); + if (result != VK_SUCCESS) + { + return result; + } + + return VK_SUCCESS; +} + VKAPI_ATTR VkResult wsi_layer_vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo) { assert(queue != VK_NULL_HANDLE); @@ -139,6 +187,20 @@ VKAPI_ATTR VkResult wsi_layer_vkQueuePresentKHR(VkQueue queue, const VkPresentIn return device_data.disp.QueuePresentKHR(queue, pPresentInfo); } + /* Avoid allocating on the heap when there is only one swapchain. */ + VkResult res = VK_SUCCESS; + const VkPresentInfoKHR *present_info = pPresentInfo; + if (pPresentInfo->swapchainCount > 1) + { + res = submit_wait_request(queue, *pPresentInfo, device_data); + if (res != VK_SUCCESS) + { + return res; + } + + present_info = nullptr; + } + VkResult ret = VK_SUCCESS; for (uint32_t i = 0; i < pPresentInfo->swapchainCount; ++i) { @@ -147,7 +209,7 @@ VKAPI_ATTR VkResult wsi_layer_vkQueuePresentKHR(VkQueue queue, const VkPresentIn wsi::swapchain_base *sc = reinterpret_cast(swapc); assert(sc != nullptr); - VkResult res = sc->queue_present(queue, pPresentInfo, pPresentInfo->pImageIndices[i]); + res = sc->queue_present(queue, present_info, pPresentInfo->pImageIndices[i]); if (pPresentInfo->pResults != nullptr) { diff --git a/wsi/swapchain_base.cpp b/wsi/swapchain_base.cpp index fdc0c29..e139820 100644 --- a/wsi/swapchain_base.cpp +++ b/wsi/swapchain_base.cpp @@ -199,7 +199,9 @@ VkResult swapchain_base::init(VkDevice device, const VkSwapchainCreateInfoKHR *s /* Init image to invalid values. */ if (!m_swapchain_images.try_resize(swapchain_create_info->minImageCount)) + { return VK_ERROR_OUT_OF_HOST_MEMORY; + } /* We have allocated images, we can call the platform init function if something needs to be done. */ bool use_presentation_thread = true; @@ -249,6 +251,15 @@ VkResult swapchain_base::init(VkDevice device, const VkSwapchainCreateInfoKHR *s { return result; } + + VkSemaphoreCreateInfo semaphore_info = {}; + semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + result = m_device_data.disp.CreateSemaphore(m_device, &semaphore_info, get_allocation_callbacks(), + &img.present_semaphore); + if (result != VK_SUCCESS) + { + return result; + } } m_device_data.disp.GetDeviceQueue(m_device, 0, 0, &m_queue); @@ -352,6 +363,8 @@ void swapchain_base::teardown() { /* Call implementation specific release */ destroy_image(img); + + m_device_data.disp.DestroySemaphore(m_device, img.present_semaphore, get_allocation_callbacks()); } } @@ -481,8 +494,15 @@ VkResult swapchain_base::notify_presentation_engine(uint32_t image_index) VkResult swapchain_base::queue_present(VkQueue queue, const VkPresentInfoKHR *present_info, const uint32_t image_index) { - VkResult result = image_set_present_payload(m_swapchain_images[image_index], queue, present_info->pWaitSemaphores, - present_info->waitSemaphoreCount); + const VkSemaphore *wait_semaphores = &m_swapchain_images[image_index].present_semaphore; + uint32_t sem_count = 1; + if (present_info != nullptr) + { + wait_semaphores = present_info->pWaitSemaphores; + sem_count = present_info->waitSemaphoreCount; + } + + VkResult result = image_set_present_payload(m_swapchain_images[image_index], queue, wait_semaphores, sem_count); if (result != VK_SUCCESS) { return result; diff --git a/wsi/swapchain_base.hpp b/wsi/swapchain_base.hpp index ae4668b..382ee11 100644 --- a/wsi/swapchain_base.hpp +++ b/wsi/swapchain_base.hpp @@ -60,6 +60,7 @@ struct swapchain_image VkImage image{VK_NULL_HANDLE}; status status{swapchain_image::INVALID}; + VkSemaphore present_semaphore{ VK_NULL_HANDLE }; }; /** @@ -124,7 +125,10 @@ public: * * @param queue The queue to which the submission will be made to. * - * @param pPresentInfo Information about the swapchain and image to be presented. + * @param present_info Information about the swapchain and image to be presented. + * If it is nullptr it means that the presentation request will wait on the + * image's \p present_semaphore and not the semaphores that come with + * \p present_info. * * @param imageIndex The index of the image to be presented. * @@ -169,6 +173,18 @@ public: virtual VkResult bind_swapchain_image(VkDevice &device, const VkBindImageMemoryInfo *bind_image_mem_info, const VkBindImageMemorySwapchainInfoKHR *bind_sc_info) = 0; + /** + * @brief Get image's present semaphore + * + * @param image_index Image's index + * + * @return the image's present_semaphore + */ + VkSemaphore get_image_present_semaphore(uint32_t image_index) + { + return m_swapchain_images[image_index].present_semaphore; + } + protected: layer::device_private_data &m_device_data;