Browse Source

Backends: Vulkan: reworked swap-chain resize handling for secondary viewports to work with typical Linux setups. (#2626, #3390, #3758, #7508, #7513)

Rory O'Connell 1 year ago
parent
commit
8b2c6dd42f
2 changed files with 29 additions and 9 deletions
  1. 27 9
      backends/imgui_impl_vulkan.cpp
  2. 2 0
      docs/CHANGELOG.txt

+ 27 - 9
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.
 // Helper structure we store in the void* RendererUserData field of each ImGuiViewport to easily retrieve our backend data.
 struct ImGui_ImplVulkan_ViewportData
 struct ImGui_ImplVulkan_ViewportData
 {
 {
+    ImGui_ImplVulkanH_Window                Window;                 // Used by secondary viewports only
+    ImGui_ImplVulkan_WindowRenderBuffers    RenderBuffers;          // Used by all viewports
     bool                                    WindowOwned;
     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()        { }
     ~ImGui_ImplVulkan_ViewportData()        { }
 };
 };
 
 
@@ -1731,13 +1732,25 @@ static void ImGui_ImplVulkan_RenderWindow(ImGuiViewport* viewport, void*)
     ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
     ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
     VkResult err;
     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_Frame* fd = &wd->Frames[wd->FrameIndex];
     ImGui_ImplVulkanH_FrameSemaphores* fsd = &wd->FrameSemaphores[wd->SemaphoreIndex];
     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 (;;)
         for (;;)
         {
         {
@@ -1863,6 +1876,9 @@ static void ImGui_ImplVulkan_SwapBuffers(ImGuiViewport* viewport, void*)
     ImGui_ImplVulkanH_Window* wd = &vd->Window;
     ImGui_ImplVulkanH_Window* wd = &vd->Window;
     ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
     ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
 
 
+    if (vd->SwapChainNeedRebuild) // Frame data became invalid in the middle of rendering
+        return;
+
     VkResult err;
     VkResult err;
     uint32_t present_index = wd->FrameIndex;
     uint32_t present_index = wd->FrameIndex;
 
 
@@ -1876,9 +1892,11 @@ static void ImGui_ImplVulkan_SwapBuffers(ImGuiViewport* viewport, void*)
     info.pImageIndices = &present_index;
     info.pImageIndices = &present_index;
     err = vkQueuePresentKHR(v->Queue, &info);
     err = vkQueuePresentKHR(v->Queue, &info);
     if (err == VK_ERROR_OUT_OF_DATE_KHR || err == VK_SUBOPTIMAL_KHR)
     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->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
     wd->SemaphoreIndex = (wd->SemaphoreIndex + 1) % wd->SemaphoreCount; // Now we can use the next set of semaphores

+ 2 - 0
docs/CHANGELOG.txt

@@ -95,6 +95,8 @@ Docking+Viewports Branch:
   reading SetNextWindowXXX() data. (#6709, #4643, #7491) [@ocornut, @cfillion]
   reading SetNextWindowXXX() data. (#6709, #4643, #7491) [@ocornut, @cfillion]
 - Viewports: fixed outer-right edge of MenuBar clipping rectangle off by one when window
 - 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]
   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
 - Backends: Vulkan: create a custom pipeline for secondary viewports. Fixes issues
   when user created main viewport uses a different renderpass. (#6325, #6305, #7398,
   when user created main viewport uses a different renderpass. (#6325, #6305, #7398,
   #3459, #3253, #3522) [@skaman, @FunMiles]
   #3459, #3253, #3522) [@skaman, @FunMiles]