Vulkan: Use pool of semaphores instead of per-image

Some drivers apparently don't iterate images in the order you expect.
This commit is contained in:
Connor McLaughlin 2023-01-12 19:15:11 +10:00 committed by lightningterror
parent d586582489
commit 95fa15f902
2 changed files with 46 additions and 40 deletions

View File

@ -637,7 +637,7 @@ namespace Vulkan
} }
m_images.reserve(image_count); m_images.reserve(image_count);
m_current_image = (image_count - 1); m_current_image = 0;
for (u32 i = 0; i < image_count; i++) for (u32 i = 0; i < image_count; i++)
{ {
SwapChainImage image; SwapChainImage image;
@ -650,31 +650,36 @@ namespace Vulkan
return false; 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); image.framebuffer = image.texture.CreateFramebuffer(m_load_render_pass);
if (image.framebuffer == VK_NULL_HANDLE) 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); LOG_VULKAN_ERROR(res, "vkCreateSemaphore failed: ");
vkDestroySemaphore(g_vulkan_context->GetDevice(), image.available_semaphore, nullptr);
return false; 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; return true;
@ -685,11 +690,16 @@ namespace Vulkan
for (auto& it : m_images) for (auto& it : m_images)
{ {
// Images themselves are cleaned up by the swap chain object // 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); vkDestroyFramebuffer(g_vulkan_context->GetDevice(), it.framebuffer, nullptr);
} }
m_images.clear(); 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(); m_image_acquire_result.reset();
} }
@ -712,21 +722,11 @@ namespace Vulkan
if (!m_swap_chain) if (!m_swap_chain)
return VK_ERROR_SURFACE_LOST_KHR; return VK_ERROR_SURFACE_LOST_KHR;
// Unfortunately we can't query the image before providing the semaphore. // Use a different semaphore for each image.
// So, let's hope we get it correct. m_current_semaphore = (m_current_semaphore + 1) % static_cast<u32>(m_semaphores.size());
const u32 expected_image = (m_current_image + 1) % static_cast<u32>(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);
}
}
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; m_image_acquire_result = res;
return res; return res;
} }

View File

@ -70,10 +70,10 @@ namespace Vulkan
__fi VkFramebuffer GetCurrentFramebuffer() const { return m_images[m_current_image].framebuffer; } __fi VkFramebuffer GetCurrentFramebuffer() const { return m_images[m_current_image].framebuffer; }
__fi VkRenderPass GetLoadRenderPass() const { return m_load_render_pass; } __fi VkRenderPass GetLoadRenderPass() const { return m_load_render_pass; }
__fi VkRenderPass GetClearRenderPass() const { return m_clear_render_pass; } __fi VkRenderPass GetClearRenderPass() const { return m_clear_render_pass; }
__fi VkSemaphore GetImageAvailableSemaphore() const { return m_images[m_current_image].available_semaphore; } __fi VkSemaphore GetImageAvailableSemaphore() const { return m_semaphores[m_current_semaphore].available_semaphore; }
__fi const VkSemaphore* GetImageAvailableSemaphorePtr() const { return &m_images[m_current_image].available_semaphore; } __fi const VkSemaphore* GetImageAvailableSemaphorePtr() const { return &m_semaphores[m_current_semaphore].available_semaphore; }
__fi VkSemaphore GetRenderingFinishedSemaphore() const { return m_images[m_current_image].rendering_finished_semaphore; } __fi VkSemaphore GetRenderingFinishedSemaphore() const { return m_semaphores[m_current_semaphore].rendering_finished_semaphore; }
__fi const VkSemaphore* GetRenderingFinishedSemaphorePtr() const { return &m_images[m_current_image].rendering_finished_semaphore; } __fi const VkSemaphore* GetRenderingFinishedSemaphorePtr() const { return &m_semaphores[m_current_semaphore].rendering_finished_semaphore; }
VkResult AcquireNextImage(); VkResult AcquireNextImage();
void ReleaseCurrentImage(); void ReleaseCurrentImage();
@ -107,6 +107,10 @@ namespace Vulkan
VkImage image; VkImage image;
Texture texture; Texture texture;
VkFramebuffer framebuffer; VkFramebuffer framebuffer;
};
struct ImageSemaphores
{
VkSemaphore available_semaphore; VkSemaphore available_semaphore;
VkSemaphore rendering_finished_semaphore; VkSemaphore rendering_finished_semaphore;
}; };
@ -123,7 +127,9 @@ namespace Vulkan
VkSwapchainKHR m_swap_chain = VK_NULL_HANDLE; VkSwapchainKHR m_swap_chain = VK_NULL_HANDLE;
std::vector<SwapChainImage> m_images; std::vector<SwapChainImage> m_images;
std::vector<ImageSemaphores> m_semaphores;
u32 m_current_image = 0; u32 m_current_image = 0;
u32 m_current_semaphore = 0;
std::optional<VkResult> m_image_acquire_result; std::optional<VkResult> m_image_acquire_result;
}; };
} // namespace Vulkan } // namespace Vulkan