Skip to content

Commit 25a7b6c

Browse files
committed
Vulkan: Re-Create main window pipeline
- Added ImGui_ImplVulkan_ReCreateMainPipeline(...) to explicitly re-create the main window pipeline (when some of its properties are changed). - ImGui_ImplVulkan_ReCreateMainPipeline(...) does not implicitly use ImGui_ImplVulkan_InitInfo::PipelineRenderingCreateInfo, but a function parameter. - The main window pipeline is created only if possible during ImGui_ImplVulkan_Init(...) (if a render pass or rendering info are given), else it should be created with ImGui_ImplVulkan_ReCreateMainPipeline(...) - ImGui_ImplVulkan_CreatePipeline now takes a struct rather than (too) many parameters (and returns the created pipeline).
1 parent 0dd3c84 commit 25a7b6c

File tree

2 files changed

+105
-16
lines changed

2 files changed

+105
-16
lines changed

backends/imgui_impl_vulkan.cpp

Lines changed: 87 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -906,10 +906,21 @@ static void ImGui_ImplVulkan_CreateShaderModules(VkDevice device, const VkAlloca
906906
}
907907
}
908908

909-
static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationCallbacks* allocator, VkPipelineCache pipelineCache, VkRenderPass renderPass, VkSampleCountFlagBits MSAASamples, VkPipeline* pipeline, uint32_t subpass)
909+
struct ImGui_ImplVulkan_PipelineCreateInfo
910+
{
911+
VkDevice Device = VK_NULL_HANDLE;
912+
const VkAllocationCallbacks* Allocator = nullptr;
913+
VkPipelineCache PipelineCache = VK_NULL_HANDLE;
914+
VkRenderPass RenderPass = VK_NULL_HANDLE;
915+
uint32_t Subpass = 0;
916+
VkSampleCountFlagBits MSAASamples = {};
917+
const ImGui_ImplVulkan_PipelineRenderingCreateInfo* pRenderingInfo = nullptr;
918+
};
919+
920+
static VkPipeline ImGui_ImplVulkan_CreatePipeline(ImGui_ImplVulkan_PipelineCreateInfo const& pci)
910921
{
911922
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
912-
ImGui_ImplVulkan_CreateShaderModules(device, allocator);
923+
ImGui_ImplVulkan_CreateShaderModules(pci.Device, pci.Allocator);
913924

914925
VkPipelineShaderStageCreateInfo stage[2] = {};
915926
stage[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
@@ -964,7 +975,7 @@ static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationC
964975

965976
VkPipelineMultisampleStateCreateInfo ms_info = {};
966977
ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
967-
ms_info.rasterizationSamples = (MSAASamples != 0) ? MSAASamples : VK_SAMPLE_COUNT_1_BIT;
978+
ms_info.rasterizationSamples = (pci.MSAASamples != 0) ? pci.MSAASamples : VK_SAMPLE_COUNT_1_BIT;
968979

969980
VkPipelineColorBlendAttachmentState color_attachment[1] = {};
970981
color_attachment[0].blendEnable = VK_TRUE;
@@ -1004,21 +1015,23 @@ static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationC
10041015
info.pColorBlendState = &blend_info;
10051016
info.pDynamicState = &dynamic_state;
10061017
info.layout = bd->PipelineLayout;
1007-
info.renderPass = renderPass;
1008-
info.subpass = subpass;
1018+
info.renderPass = pci.RenderPass;
1019+
info.subpass = pci.Subpass;
10091020

10101021
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
10111022
if (bd->VulkanInitInfo.UseDynamicRendering)
10121023
{
1013-
IM_ASSERT(bd->VulkanInitInfo.PipelineRenderingCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR && "PipelineRenderingCreateInfo sType must be VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR");
1014-
IM_ASSERT(bd->VulkanInitInfo.PipelineRenderingCreateInfo.pNext == nullptr && "PipelineRenderingCreateInfo pNext must be nullptr");
1015-
info.pNext = &bd->VulkanInitInfo.PipelineRenderingCreateInfo;
1024+
IM_ASSERT(pci.pRenderingInfo && "PipelineRenderingCreateInfo must not be nullptr when using dynamic rendering");
1025+
IM_ASSERT(pci.pRenderingInfo->sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR && "PipelineRenderingCreateInfo::sType must be VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR");
1026+
IM_ASSERT(pci.pRenderingInfo->pNext == nullptr && "PipelineRenderingCreateInfo::pNext must be nullptr");
1027+
info.pNext = pci.pRenderingInfo;
10161028
info.renderPass = VK_NULL_HANDLE; // Just make sure it's actually nullptr.
10171029
}
10181030
#endif
1019-
1020-
VkResult err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &info, allocator, pipeline);
1031+
VkPipeline res;
1032+
VkResult err = vkCreateGraphicsPipelines(pci.Device, pci.PipelineCache, 1, &info, pci.Allocator, &res);
10211033
check_vk_result(err);
1034+
return res;
10221035
}
10231036

10241037
bool ImGui_ImplVulkan_CreateDeviceObjects()
@@ -1092,7 +1105,34 @@ bool ImGui_ImplVulkan_CreateDeviceObjects()
10921105
check_vk_result(err);
10931106
}
10941107

1095-
ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, v->PipelineCache, v->RenderPass, v->MSAASamples, &bd->Pipeline, v->Subpass);
1108+
{
1109+
bool create_pipeline = false;
1110+
const ImGui_ImplVulkan_PipelineRenderingCreateInfo* p_dynamic_rendering = nullptr;
1111+
if (v->RenderPass)
1112+
{
1113+
create_pipeline = true;
1114+
}
1115+
else
1116+
{
1117+
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
1118+
if (v->UseDynamicRendering && v->PipelineRenderingCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR)
1119+
{
1120+
p_dynamic_rendering = &v->PipelineRenderingCreateInfo;
1121+
create_pipeline = true;
1122+
}
1123+
#endif
1124+
}
1125+
if (create_pipeline)
1126+
{
1127+
ImGui_ImplVulkan_MainPipelineCreateInfo mp_info = {};
1128+
mp_info.RenderPass = v->RenderPass;
1129+
mp_info.Subpass = v->Subpass;
1130+
mp_info.MSAASamples = v->MSAASamples;
1131+
mp_info.pDynamicRendering = p_dynamic_rendering;
1132+
1133+
ImGui_ImplVulkan_ReCreateMainPipeline(mp_info);
1134+
}
1135+
}
10961136

10971137
// Create command pool/buffer for texture upload
10981138
if (!bd->TexCommandPool)
@@ -1117,6 +1157,40 @@ bool ImGui_ImplVulkan_CreateDeviceObjects()
11171157
return true;
11181158
}
11191159

1160+
void ImGui_ImplVulkan_ReCreateMainPipeline(ImGui_ImplVulkan_MainPipelineCreateInfo const& info)
1161+
{
1162+
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
1163+
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
1164+
if (bd->Pipeline)
1165+
{
1166+
vkDestroyPipeline(v->Device, bd->Pipeline, v->Allocator);
1167+
bd->Pipeline = VK_NULL_HANDLE;
1168+
}
1169+
v->RenderPass = info.RenderPass;
1170+
v->MSAASamples = info.MSAASamples;
1171+
v->Subpass = info.Subpass;
1172+
1173+
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
1174+
if (info.pDynamicRendering)
1175+
{
1176+
v->PipelineRenderingCreateInfo = *info.pDynamicRendering;
1177+
}
1178+
#else
1179+
IM_ASSERT(p_dynamic_rendering == nullptr);
1180+
#endif
1181+
1182+
ImGui_ImplVulkan_PipelineCreateInfo pci;
1183+
pci.Device = v->Device;
1184+
pci.Allocator = v->Allocator;
1185+
pci.PipelineCache = v->PipelineCache;
1186+
pci.RenderPass = v->RenderPass;
1187+
pci.Subpass = v->Subpass;
1188+
pci.MSAASamples = v->MSAASamples;
1189+
pci.pRenderingInfo = info.pDynamicRendering;
1190+
1191+
bd->Pipeline = ImGui_ImplVulkan_CreatePipeline(pci);
1192+
}
1193+
11201194
void ImGui_ImplVulkan_DestroyDeviceObjects()
11211195
{
11221196
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
@@ -1239,17 +1313,15 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info)
12391313
IM_ASSERT(info->DescriptorPoolSize > 0);
12401314
IM_ASSERT(info->MinImageCount >= 2);
12411315
IM_ASSERT(info->ImageCount >= info->MinImageCount);
1242-
if (info->UseDynamicRendering == false)
1243-
IM_ASSERT(info->RenderPass != VK_NULL_HANDLE);
12441316

1245-
bd->VulkanInitInfo = *info;
1317+
ImGui_ImplVulkan_InitInfo * v = &bd->VulkanInitInfo;
1318+
*v = *info;
12461319

12471320
VkPhysicalDeviceProperties properties;
12481321
vkGetPhysicalDeviceProperties(info->PhysicalDevice, &properties);
12491322
bd->NonCoherentAtomSize = properties.limits.nonCoherentAtomSize;
12501323

12511324
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
1252-
ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo;
12531325
if (v->PipelineRenderingCreateInfo.pColorAttachmentFormats != NULL)
12541326
{
12551327
// Deep copy buffer to reduce error-rate for end user (#8282)

backends/imgui_impl_vulkan.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@
6565
// Backend uses a small number of descriptors per font atlas + as many as additional calls done to ImGui_ImplVulkan_AddTexture().
6666
#define IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE (8) // Minimum per atlas
6767

68+
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
69+
typedef VkPipelineRenderingCreateInfoKHR ImGui_ImplVulkan_PipelineRenderingCreateInfo;
70+
#else
71+
typedef void ImGui_ImplVulkan_PipelineRenderingCreateInfo;
72+
#endif
73+
6874
// Initialization data, for ImGui_ImplVulkan_Init()
6975
// [Please zero-clear before use!]
7076
// - About descriptor pool:
@@ -98,6 +104,7 @@ struct ImGui_ImplVulkan_InitInfo
98104
// Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3.
99105
bool UseDynamicRendering;
100106
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
107+
// (Optional, valid iif .sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR)
101108
VkPipelineRenderingCreateInfoKHR PipelineRenderingCreateInfo;
102109
#endif
103110

@@ -108,12 +115,22 @@ struct ImGui_ImplVulkan_InitInfo
108115
};
109116

110117
// Follow "Getting Started" link and check examples/ folder to learn about using backends!
111-
IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info);
118+
IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info); // The main pipeline will be created if possible (RenderPass xor (UseDynamicRendering && PipelineRenderingCreateInfo->sType is correct))
119+
#define IMGUI_IMPL_VULKAN_HAS_MAIN_PIPELINE_RE_CREATION 1
120+
struct ImGui_ImplVulkan_MainPipelineCreateInfo
121+
{
122+
VkRenderPass RenderPass = VK_NULL_HANDLE;
123+
uint32_t Subpass = 0;
124+
VkSampleCountFlagBits MSAASamples = {};
125+
const ImGui_ImplVulkan_PipelineRenderingCreateInfo* pDynamicRendering = nullptr;
126+
};
127+
IMGUI_IMPL_API void ImGui_ImplVulkan_ReCreateMainPipeline(ImGui_ImplVulkan_MainPipelineCreateInfo const& info); // (render_pass xor (p_dynamic_rendering && p_dynamic_rendering is correct (sType and pNext))
112128
IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown();
113129
IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame();
114130
IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE);
115131
IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated)
116132

133+
117134
// (Advanced) Use e.g. if you need to precisely control the timing of texture updates (e.g. for staged rendering), by setting ImDrawData::Textures = NULL to handle this manually.
118135
IMGUI_IMPL_API void ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex);
119136

0 commit comments

Comments
 (0)