Skip to content

Commit 34f0a33

Browse files
committed
Backends: Vulkan: Explicitly enforce that secondary viewports share the same surface format.
- Add `ImGui_ImplVulkan_PrepareViewportsRendering(VkSurfaceKHR)` for later re-usability
1 parent 764a775 commit 34f0a33

File tree

1 file changed

+59
-32
lines changed

1 file changed

+59
-32
lines changed

backends/imgui_impl_vulkan.cpp

Lines changed: 59 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ struct ImGui_ImplVulkan_Data
296296
ImGui_ImplVulkan_WindowRenderBuffers MainWindowRenderBuffers;
297297

298298
// Viewports common data
299+
VkSurfaceFormatKHR ViewportsFormat; // Common for all viewports, may differ from VulkanInitInfo.SecondaryViewportsInfo.DesiredFormat
299300
// Filled during ImGui_ImplVulkan_PrepareViewportsRendering() based on ViewportsFormat and VulkanInitInfo->SecondaryViewportsInfo
300301
ImGui_ImplVulkan_PipelineInfo PipelineInfoForViewports;
301302
VkPipeline PipelineForViewports; // pipeline for secondary viewports (created by backend)
@@ -1219,8 +1220,15 @@ void ImGui_ImplVulkan_DestroyDeviceObjects()
12191220
if (bd->DescriptorSetLayout) { vkDestroyDescriptorSetLayout(v->Device, bd->DescriptorSetLayout, v->Allocator); bd->DescriptorSetLayout = VK_NULL_HANDLE; }
12201221
if (bd->PipelineLayout) { vkDestroyPipelineLayout(v->Device, bd->PipelineLayout, v->Allocator); bd->PipelineLayout = VK_NULL_HANDLE; }
12211222
if (bd->Pipeline) { vkDestroyPipeline(v->Device, bd->Pipeline, v->Allocator); bd->Pipeline = VK_NULL_HANDLE; }
1222-
if (bd->PipelineForViewports) { vkDestroyPipeline(v->Device, bd->PipelineForViewports, v->Allocator); bd->PipelineForViewports = VK_NULL_HANDLE; }
12231223
if (bd->DescriptorPool) { vkDestroyDescriptorPool(v->Device, bd->DescriptorPool, v->Allocator); bd->DescriptorPool = VK_NULL_HANDLE; }
1224+
1225+
// Destroy viewports common objects
1226+
if (bd->PipelineForViewports) { vkDestroyPipeline(v->Device, bd->PipelineForViewports, v->Allocator); bd->PipelineForViewports = VK_NULL_HANDLE; }
1227+
if (bd->PipelineInfoForViewports.RenderPass)
1228+
{
1229+
vkDestroyRenderPass(v->Device, bd->PipelineInfoForViewports.RenderPass, v->Allocator);
1230+
bd->PipelineInfoForViewports.RenderPass = VK_NULL_HANDLE;
1231+
}
12241232
}
12251233

12261234
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
@@ -1980,28 +1988,15 @@ static void ImGui_ImplVulkan_SelectPresentMode(ImGuiViewport* viewport)
19801988
//printf("[vulkan] Secondary window selected PresentMode = %d\n", wd->PresentMode);
19811989
}
19821990

1983-
static void ImGui_ImplVulkan_CreateWindow(ImGuiViewport* viewport)
1991+
// Prepare common viewports rendering objects.
1992+
// Requires a sample surface (assuming any viewport surface behaves the same).
1993+
// - Select a surface format
1994+
// - Create the common RenderPass and Pipeline
1995+
static void ImGui_ImplVulkan_PrepareViewportsRendering(VkSurfaceKHR surface)
19841996
{
19851997
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
1986-
ImGui_ImplVulkan_ViewportData* vd = IM_NEW(ImGui_ImplVulkan_ViewportData)();
1987-
viewport->RendererUserData = vd;
1988-
ImGui_ImplVulkanH_Window* wd = &vd->Window;
19891998
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
19901999

1991-
// Create surface
1992-
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
1993-
VkResult err = (VkResult)platform_io.Platform_CreateVkSurface(viewport, (ImU64)v->Instance, (const void*)v->Allocator, (ImU64*)&wd->Surface);
1994-
check_vk_result(err);
1995-
1996-
// Check for WSI support
1997-
VkBool32 res;
1998-
vkGetPhysicalDeviceSurfaceSupportKHR(v->PhysicalDevice, v->QueueFamily, wd->Surface, &res);
1999-
if (res != VK_TRUE)
2000-
{
2001-
IM_ASSERT(0); // Error: no WSI support on physical device
2002-
return;
2003-
}
2004-
20052000
// Select Surface Format
20062001
ImGui_ImplVulkan_PipelineInfo* pipeline_info = &bd->PipelineInfoForViewports;
20072002
const VkFormat requestSurfaceImageFormats[] = { v->SecondaryViewportsInfo.DesiredFormat.format, VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_B8G8R8_UNORM, VK_FORMAT_R8G8B8_UNORM };
@@ -2014,36 +2009,68 @@ static void ImGui_ImplVulkan_CreateWindow(ImGuiViewport* viewport)
20142009
}
20152010

20162011
const VkColorSpaceKHR requestSurfaceColorSpace = v->SecondaryViewportsInfo.DesiredFormat.colorSpace;
2017-
wd->SurfaceFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(v->PhysicalDevice, wd->Surface, pRequestSurfaceImageFormats, requestSurfaceImageFormatsCount, requestSurfaceColorSpace);
2018-
2019-
// Select Present Mode
2020-
ImGui_ImplVulkan_SelectPresentMode(viewport);
2021-
2022-
// Create SwapChain, RenderPass, Framebuffer, etc.
2023-
wd->ClearEnable = (viewport->Flags & ImGuiViewportFlags_NoRendererClear) ? false : true;
2024-
wd->UseDynamicRendering = v->UseDynamicRendering;
2025-
ImGui_ImplVulkanH_CreateOrResizeWindow(v->Instance, v->PhysicalDevice, v->Device, wd, v->QueueFamily, v->Allocator, (int)viewport->Size.x, (int)viewport->Size.y, v->MinImageCount, v->SecondaryViewportsInfo.SwapChainImageUsage);
2026-
vd->WindowOwned = true;
2012+
bd->ViewportsFormat = ImGui_ImplVulkanH_SelectSurfaceFormat(v->PhysicalDevice, surface, pRequestSurfaceImageFormats, requestSurfaceImageFormatsCount, requestSurfaceColorSpace);
20272013

20282014
// Create pipeline (shared by all secondary viewports)
20292015
if (bd->PipelineForViewports == VK_NULL_HANDLE)
20302016
{
20312017
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
2032-
if (wd->UseDynamicRendering)
2018+
if (v->UseDynamicRendering)
20332019
{
20342020
pipeline_info->PipelineRenderingCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO;
20352021
pipeline_info->PipelineRenderingCreateInfo.colorAttachmentCount = 1;
2036-
pipeline_info->PipelineRenderingCreateInfo.pColorAttachmentFormats = &wd->SurfaceFormat.format;
2022+
pipeline_info->PipelineRenderingCreateInfo.pColorAttachmentFormats = &bd->ViewportsFormat.format;
20372023
}
20382024
else
20392025
{
2040-
pipeline_info->RenderPass = wd->RenderPass;
2026+
// Create a reference RenderPass (needed for the Pipeline creation)
2027+
// Viewports will create their own RenderPass, compatible with this one (same format, different clear option)
2028+
pipeline_info->RenderPass = ImGui_ImplVulkanH_CreateRenderPass(v->Device, v->Allocator, bd->ViewportsFormat.format, true);
2029+
pipeline_info->Subpass = 0;
20412030
}
20422031
#endif
20432032
bd->PipelineForViewports = ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, VK_NULL_HANDLE, pipeline_info);
20442033
}
20452034
}
20462035

2036+
static void ImGui_ImplVulkan_CreateWindow(ImGuiViewport* viewport)
2037+
{
2038+
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
2039+
ImGui_ImplVulkan_ViewportData* vd = IM_NEW(ImGui_ImplVulkan_ViewportData)();
2040+
viewport->RendererUserData = vd;
2041+
ImGui_ImplVulkanH_Window* wd = &vd->Window;
2042+
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
2043+
2044+
// Create surface
2045+
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
2046+
VkResult err = (VkResult)platform_io.Platform_CreateVkSurface(viewport, (ImU64)v->Instance, (const void*)v->Allocator, (ImU64*)&wd->Surface);
2047+
check_vk_result(err);
2048+
2049+
// Check for WSI support
2050+
VkBool32 res;
2051+
vkGetPhysicalDeviceSurfaceSupportKHR(v->PhysicalDevice, v->QueueFamily, wd->Surface, &res);
2052+
if (res != VK_TRUE)
2053+
{
2054+
IM_ASSERT(0); // Error: no WSI support on physical device
2055+
return;
2056+
}
2057+
2058+
// Select Present Mode
2059+
ImGui_ImplVulkan_SelectPresentMode(viewport);
2060+
2061+
if (bd->ViewportsFormat.format == VK_FORMAT_UNDEFINED)
2062+
{
2063+
ImGui_ImplVulkan_PrepareViewportsRendering(wd->Surface);
2064+
}
2065+
wd->SurfaceFormat = bd->ViewportsFormat;
2066+
2067+
// Create SwapChain, RenderPass, Framebuffer, etc.
2068+
wd->ClearEnable = (viewport->Flags & ImGuiViewportFlags_NoRendererClear) ? false : true;
2069+
wd->UseDynamicRendering = v->UseDynamicRendering;
2070+
ImGui_ImplVulkanH_CreateOrResizeWindow(v->Instance, v->PhysicalDevice, v->Device, wd, v->QueueFamily, v->Allocator, (int)viewport->Size.x, (int)viewport->Size.y, v->MinImageCount, v->SecondaryViewportsInfo.SwapChainImageUsage);
2071+
vd->WindowOwned = true;
2072+
}
2073+
20472074
static void ImGui_ImplVulkan_DestroyWindow(ImGuiViewport* viewport)
20482075
{
20492076
// The main viewport (owned by the application) will always have RendererUserData == 0 since we didn't create the data for it.

0 commit comments

Comments
 (0)