From 95fa15f902e2da440eee9265bf71d06452e75379 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Thu, 12 Jan 2023 19:15:11 +1000 Subject: [PATCH] Vulkan: Use pool of semaphores instead of per-image Some drivers apparently don't iterate images in the order you expect. --- common/Vulkan/SwapChain.cpp | 72 ++++++++++++++++++------------------- common/Vulkan/SwapChain.h | 14 +++++--- 2 files changed, 46 insertions(+), 40 deletions(-) diff --git a/common/Vulkan/SwapChain.cpp b/common/Vulkan/SwapChain.cpp index 8e1bac2890..6754dfdaad 100644 --- a/common/Vulkan/SwapChain.cpp +++ b/common/Vulkan/SwapChain.cpp @@ -637,7 +637,7 @@ namespace Vulkan } m_images.reserve(image_count); - m_current_image = (image_count - 1); + m_current_image = 0; for (u32 i = 0; i < image_count; i++) { SwapChainImage image; @@ -650,31 +650,36 @@ namespace Vulkan return false; } - const VkSemaphoreCreateInfo semaphore_info = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0}; - res = vkCreateSemaphore(g_vulkan_context->GetDevice(), &semaphore_info, nullptr, &image.available_semaphore); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateSemaphore failed: "); - return false; - } - - res = vkCreateSemaphore(g_vulkan_context->GetDevice(), &semaphore_info, nullptr, &image.rendering_finished_semaphore); - if (res != VK_SUCCESS) - { - LOG_VULKAN_ERROR(res, "vkCreateSemaphore failed: "); - vkDestroySemaphore(g_vulkan_context->GetDevice(), image.available_semaphore, nullptr); - return false; - } - image.framebuffer = image.texture.CreateFramebuffer(m_load_render_pass); if (image.framebuffer == VK_NULL_HANDLE) + return false; + + m_images.emplace_back(std::move(image)); + } + + m_semaphores.reserve(image_count); + m_current_semaphore = (image_count - 1); + for (u32 i = 0; i < image_count; i++) + { + ImageSemaphores sema; + + const VkSemaphoreCreateInfo semaphore_info = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, nullptr, 0}; + res = vkCreateSemaphore(g_vulkan_context->GetDevice(), &semaphore_info, nullptr, &sema.available_semaphore); + if (res != VK_SUCCESS) { - vkDestroySemaphore(g_vulkan_context->GetDevice(), image.rendering_finished_semaphore, nullptr); - vkDestroySemaphore(g_vulkan_context->GetDevice(), image.available_semaphore, nullptr); + LOG_VULKAN_ERROR(res, "vkCreateSemaphore failed: "); return false; } - m_images.emplace_back(std::move(image)); + res = vkCreateSemaphore(g_vulkan_context->GetDevice(), &semaphore_info, nullptr, &sema.rendering_finished_semaphore); + if (res != VK_SUCCESS) + { + LOG_VULKAN_ERROR(res, "vkCreateSemaphore failed: "); + vkDestroySemaphore(g_vulkan_context->GetDevice(), sema.available_semaphore, nullptr); + return false; + } + + m_semaphores.push_back(sema); } return true; @@ -685,11 +690,16 @@ namespace Vulkan for (auto& it : m_images) { // Images themselves are cleaned up by the swap chain object - vkDestroySemaphore(g_vulkan_context->GetDevice(), it.rendering_finished_semaphore, nullptr); - vkDestroySemaphore(g_vulkan_context->GetDevice(), it.available_semaphore, nullptr); vkDestroyFramebuffer(g_vulkan_context->GetDevice(), it.framebuffer, nullptr); } m_images.clear(); + for (auto& it : m_semaphores) + { + vkDestroySemaphore(g_vulkan_context->GetDevice(), it.rendering_finished_semaphore, nullptr); + vkDestroySemaphore(g_vulkan_context->GetDevice(), it.available_semaphore, nullptr); + } + m_semaphores.clear(); + m_image_acquire_result.reset(); } @@ -712,21 +722,11 @@ namespace Vulkan if (!m_swap_chain) return VK_ERROR_SURFACE_LOST_KHR; - // Unfortunately we can't query the image before providing the semaphore. - // So, let's hope we get it correct. - const u32 expected_image = (m_current_image + 1) % static_cast(m_images.size()); - const VkResult res = vkAcquireNextImageKHR(g_vulkan_context->GetDevice(), m_swap_chain, UINT64_MAX, - m_images[expected_image].available_semaphore, VK_NULL_HANDLE, &m_current_image); - if (res == VK_SUCCESS) - { - // Did we get the correct image? If not, we'll just swap the semaphore handles so it lines up. - if (m_current_image != expected_image) - { - std::swap(m_images[expected_image].available_semaphore, m_images[m_current_image].available_semaphore); - DevCon.WriteLn("Predicted wrong image (expected %u, got %u), swapped semaphores", expected_image, m_current_image); - } - } + // Use a different semaphore for each image. + m_current_semaphore = (m_current_semaphore + 1) % static_cast(m_semaphores.size()); + const VkResult res = vkAcquireNextImageKHR(g_vulkan_context->GetDevice(), m_swap_chain, UINT64_MAX, + m_semaphores[m_current_semaphore].available_semaphore, VK_NULL_HANDLE, &m_current_image); m_image_acquire_result = res; return res; } diff --git a/common/Vulkan/SwapChain.h b/common/Vulkan/SwapChain.h index 9172eb2a0f..eeca0140eb 100644 --- a/common/Vulkan/SwapChain.h +++ b/common/Vulkan/SwapChain.h @@ -70,10 +70,10 @@ namespace Vulkan __fi VkFramebuffer GetCurrentFramebuffer() const { return m_images[m_current_image].framebuffer; } __fi VkRenderPass GetLoadRenderPass() const { return m_load_render_pass; } __fi VkRenderPass GetClearRenderPass() const { return m_clear_render_pass; } - __fi VkSemaphore GetImageAvailableSemaphore() const { return m_images[m_current_image].available_semaphore; } - __fi const VkSemaphore* GetImageAvailableSemaphorePtr() const { return &m_images[m_current_image].available_semaphore; } - __fi VkSemaphore GetRenderingFinishedSemaphore() const { return m_images[m_current_image].rendering_finished_semaphore; } - __fi const VkSemaphore* GetRenderingFinishedSemaphorePtr() const { return &m_images[m_current_image].rendering_finished_semaphore; } + __fi VkSemaphore GetImageAvailableSemaphore() const { return m_semaphores[m_current_semaphore].available_semaphore; } + __fi const VkSemaphore* GetImageAvailableSemaphorePtr() const { return &m_semaphores[m_current_semaphore].available_semaphore; } + __fi VkSemaphore GetRenderingFinishedSemaphore() const { return m_semaphores[m_current_semaphore].rendering_finished_semaphore; } + __fi const VkSemaphore* GetRenderingFinishedSemaphorePtr() const { return &m_semaphores[m_current_semaphore].rendering_finished_semaphore; } VkResult AcquireNextImage(); void ReleaseCurrentImage(); @@ -107,6 +107,10 @@ namespace Vulkan VkImage image; Texture texture; VkFramebuffer framebuffer; + }; + + struct ImageSemaphores + { VkSemaphore available_semaphore; VkSemaphore rendering_finished_semaphore; }; @@ -123,7 +127,9 @@ namespace Vulkan VkSwapchainKHR m_swap_chain = VK_NULL_HANDLE; std::vector m_images; + std::vector m_semaphores; u32 m_current_image = 0; + u32 m_current_semaphore = 0; std::optional m_image_acquire_result; }; } // namespace Vulkan