From 8b2c6dd42fb02dc95a581bb8c7db0199064cfced Mon Sep 17 00:00:00 2001 From: Rory O'Connell <19547+RoryO@users.noreply.github.com> Date: Tue, 7 May 2024 16:11:54 +0200 Subject: [PATCH] Backends: Vulkan: reworked swap-chain resize handling for secondary viewports to work with typical Linux setups. (#2626, #3390, #3758, #7508, #7513) --- backends/imgui_impl_vulkan.cpp | 36 +++++++++++++++++++++++++--------- docs/CHANGELOG.txt | 2 ++ 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index f8bfc9d49..3cfe8be16 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -228,11 +228,12 @@ struct ImGui_ImplVulkan_WindowRenderBuffers // Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data. struct ImGui_ImplVulkan_ViewportData { + ImGui_ImplVulkanH_Window Window; // Used by secondary viewports only + ImGui_ImplVulkan_WindowRenderBuffers RenderBuffers; // Used by all viewports bool WindowOwned; - ImGui_ImplVulkanH_Window Window; // Used by secondary viewports only - ImGui_ImplVulkan_WindowRenderBuffers RenderBuffers; // Used by all viewports + bool SwapChainNeedRebuild; // Flag when viewport swapchain resized in the middle of processing a frame - ImGui_ImplVulkan_ViewportData() { WindowOwned = false; memset(&RenderBuffers, 0, sizeof(RenderBuffers)); } + ImGui_ImplVulkan_ViewportData() { WindowOwned = SwapChainNeedRebuild = false; memset(&RenderBuffers, 0, sizeof(RenderBuffers)); } ~ImGui_ImplVulkan_ViewportData() { } }; @@ -1731,13 +1732,25 @@ static void ImGui_ImplVulkan_RenderWindow(ImGuiViewport* viewport, void*) ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; VkResult err; + if (vd->SwapChainNeedRebuild) + { + ImGui_ImplVulkanH_CreateOrResizeWindow(v->Instance, v->PhysicalDevice, v->Device, wd, v->QueueFamily, v->Allocator, (int)viewport->Size.x, (int)viewport->Size.y, v->MinImageCount); + vd->SwapChainNeedRebuild = false; + } + ImGui_ImplVulkanH_Frame* fd = &wd->Frames[wd->FrameIndex]; ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[wd->SemaphoreIndex]; { { - err = vkAcquireNextImageKHR(v->Device, wd->Swapchain, UINT64_MAX, fsd->ImageAcquiredSemaphore, VK_NULL_HANDLE, &wd->FrameIndex); - check_vk_result(err); - fd = &wd->Frames[wd->FrameIndex]; + err = vkAcquireNextImageKHR(v->Device, wd->Swapchain, UINT64_MAX, fsd->ImageAcquiredSemaphore, VK_NULL_HANDLE, &wd->FrameIndex); + if (err == VK_ERROR_OUT_OF_DATE_KHR) + { + // Since we are not going to swap this frame anyway, it's ok that recreation happens on next frame. + vd->SwapChainNeedRebuild = true; + return; + } + check_vk_result(err); + fd = &wd->Frames[wd->FrameIndex]; } for (;;) { @@ -1863,6 +1876,9 @@ static void ImGui_ImplVulkan_SwapBuffers(ImGuiViewport* viewport, void*) ImGui_ImplVulkanH_Window* wd = &vd->Window; ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; + if (vd->SwapChainNeedRebuild) // Frame data became invalid in the middle of rendering + return; + VkResult err; uint32_t present_index = wd->FrameIndex; @@ -1876,9 +1892,11 @@ static void ImGui_ImplVulkan_SwapBuffers(ImGuiViewport* viewport, void*) info.pImageIndices = &present_index; err = vkQueuePresentKHR(v->Queue, &info); if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR) - ImGui_ImplVulkanH_CreateOrResizeWindow(v->Instance, v->PhysicalDevice, v->Device, &vd->Window, v->QueueFamily, v->Allocator, (int)viewport->Size.x, (int)viewport->Size.y, v->MinImageCount); - else - check_vk_result(err); + { + vd->SwapChainNeedRebuild = true; + return; + } + check_vk_result(err); wd->FrameIndex = (wd->FrameIndex + 1) % wd->ImageCount; // This is for the next vkWaitForFences() wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index db4e54f97..4bc78a94b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -95,6 +95,8 @@ Docking+Viewports Branch: reading SetNextWindowXXX() data. (#6709, #4643, #7491) [@ocornut, @cfillion] - Viewports: fixed outer-right edge of MenuBar clipping rectangle off by one when window is located on a monitor with negative coordinates. (#6861, #2884) [@cfillion] +- Backends: Vulkan: reworked swap-chain resize handling for secondary viewports, fix for + typical Linux setups. (#2626, #3390, #3758, #7508, #7513) [@RoryO, @InsideBSITheSecond] - Backends: Vulkan: create a custom pipeline for secondary viewports. Fixes issues when user created main viewport uses a different renderpass. (#6325, #6305, #7398, #3459, #3253, #3522) [@skaman, @FunMiles]