From 0dd3c845ebf4e4a08b88f40d34efc9b3605ae80b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AF=D0=BD=20=D0=9B=D0=B8?= <184278878+vxbo@users.noreply.github.com> Date: Wed, 3 Sep 2025 10:17:23 +0300 Subject: [PATCH 01/12] Docs: add missing anchor in FAQ.md (#8913) --- docs/FAQ.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/FAQ.md b/docs/FAQ.md index fb693c7e3..519a0e8a9 100644 --- a/docs/FAQ.md +++ b/docs/FAQ.md @@ -19,7 +19,7 @@ or view this file with any Markdown viewer. | **[How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?](#q-how-can-i-tell-whether-to-dispatch-mousekeyboard-to-dear-imgui-or-my-application)** | | [How can I enable keyboard or gamepad controls?](#q-how-can-i-enable-keyboard-or-gamepad-controls) | | [How can I use this on a machine without mouse, keyboard or screen? (input share, remote display)](#q-how-can-i-use-this-on-a-machine-without-mouse-keyboard-or-screen-input-share-remote-display) | -| [How can I create my own backend?](q-how-can-i-create-my-own-backend) +| [How can I create my own backend?](#q-how-can-i-create-my-own-backend) | [I integrated Dear ImGui in my engine and little squares are showing instead of text...](#q-i-integrated-dear-imgui-in-my-engine-and-little-squares-are-showing-instead-of-text) | | [I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around...](#q-i-integrated-dear-imgui-in-my-engine-and-some-elements-are-clipping-or-disappearing-when-i-move-windows-around) | | [I integrated Dear ImGui in my engine and some elements are displaying outside their expected windows boundaries...](#q-i-integrated-dear-imgui-in-my-engine-and-some-elements-are-displaying-outside-their-expected-windows-boundaries) | From 3766d40394a9f4b66a919085ae25db89cb16d7b1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 3 Sep 2025 17:50:10 +0200 Subject: [PATCH 02/12] Nav: fixed Ctrl+Tab window appearing as empty when the sole active and focused window has the ImGuiWindowFlags_NoNavFocus flag. (#8914) --- docs/CHANGELOG.txt | 4 +++- imgui.cpp | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 9d1710a6d..4a28876bc 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -50,7 +50,9 @@ Other Changes: - Clipper, Tables: added ImGuiListClipperFlags_NoSetTableRowCounters as a way to disable the assumption that 1 clipper item == 1 table row, which breaks when e.g. using clipper with ItemsHeight=1 in order to clip in pixel units. (#8886) -- Fixed Bullet() fixed tesselation amount which looked out of place in very large sizes. +- Nav: fixed Ctrl+Tab window appearing as empty when the sole active and focused + window has the ImGuiWindowFlags_NoNavFocus flag. (#8914) +- Bullet: fixed tesselation amount which looked out of place in very large sizes. - InputText: allow passing an empty string with buf_size==0. (#8907) In theory the buffer size should always account for a zero-terminator, but idioms such as using InputTextMultiline() with ImGuiInputTextFlags_ReadOnly to display diff --git a/imgui.cpp b/imgui.cpp index 07537df87..a4128f2dc 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -14253,7 +14253,7 @@ static void ImGui::NavUpdateWindowing() g.NavWindowingInputSource = g.NavInputSource = ImGuiInputSource_Gamepad; } if (start_windowing_with_gamepad || start_windowing_with_keyboard) - if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1)) + if (ImGuiWindow* window = (g.NavWindow && IsWindowNavFocusable(g.NavWindow)) ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1)) { if (start_windowing_with_keyboard || g.ConfigNavWindowingWithGamepad) g.NavWindowingTarget = g.NavWindowingTargetAnim = window->RootWindow; // Current location From 20160ff1d5ec8c2fc4f3e18a50f4e4dc902418b8 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 3 Sep 2025 19:36:02 +0200 Subject: [PATCH 03/12] Fonts: fixed merging a font and specifying a font target in DstFont that's not the last added font (regression in 1.92). (#8912) --- docs/CHANGELOG.txt | 2 ++ imgui_draw.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 4a28876bc..479115613 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -47,6 +47,8 @@ Other Changes: ImGuiStyleVar_ScrollbarPadding enum, instead of hardcoded computed default. (#8895) - Fonts: fixed an assertion failure when a rectangle entry has been reused 1024 times (e.g. due to constant change of font types). (#8906) [@cfillion] +- Fonts: fixed merging a font and specifying a font target in DstFont + that's not the last added font (regression in 1.92). (#8912) - Clipper, Tables: added ImGuiListClipperFlags_NoSetTableRowCounters as a way to disable the assumption that 1 clipper item == 1 table row, which breaks when e.g. using clipper with ItemsHeight=1 in order to clip in pixel units. (#8886) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index e0d56612a..ee7f55efa 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3026,7 +3026,7 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg_in) else { IM_ASSERT(Fonts.Size > 0 && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font. - font = Fonts.back(); + font = font_cfg_in->DstFont ? font_cfg_in->DstFont : Fonts.back(); } // Add to list From b7cb3d93a419ffa9c37c2150eda695f3f43c221f Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 3 Sep 2025 19:39:55 +0200 Subject: [PATCH 04/12] Comments about using MSVC SAL for printf annotation. (#8871) --- imgui.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/imgui.h b/imgui.h index 12f01f43f..859cb0318 100644 --- a/imgui.h +++ b/imgui.h @@ -100,8 +100,10 @@ Index of this file: #define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx)) // Helper Macros - IM_FMTARGS, IM_FMTLIST: Apply printf-style warnings to our formatting functions. -// (MSVC provides an equivalent mechanism via SAL Annotations but it would require the macros in a different -// location. e.g. #include + void myprintf(_Printf_format_string_ const char* format, ...)) +// (MSVC provides an equivalent mechanism via SAL Annotations but it requires the macros in a different +// location. e.g. #include + void myprintf(_Printf_format_string_ const char* format, ...), +// and only works when using Code Analysis, rather than just normal compiling). +// (see https://github.com/ocornut/imgui/issues/8871 for a patch to enable this for MSVC's Code Analysis) #if !defined(IMGUI_USE_STB_SPRINTF) && defined(__MINGW32__) && !defined(__clang__) #define IM_FMTARGS(FMT) __attribute__((format(gnu_printf, FMT, FMT+1))) #define IM_FMTLIST(FMT) __attribute__((format(gnu_printf, FMT, 0))) From 605a751571530693cc2d36bd41e4a3c11109678c Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 4 Sep 2025 13:13:58 +0200 Subject: [PATCH 05/12] InputText, InputInt, InputFloat: fixed an issue where using Escape to revert would not write back the reverted value. (#8915, #8273) Revealed by 00f12b9a0 Regression test: "widgets_inputtext_temp_buffer_2" --- docs/CHANGELOG.txt | 4 ++++ imgui.h | 2 +- imgui_widgets.cpp | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 479115613..172e2f5cc 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -55,6 +55,10 @@ Other Changes: - Nav: fixed Ctrl+Tab window appearing as empty when the sole active and focused window has the ImGuiWindowFlags_NoNavFocus flag. (#8914) - Bullet: fixed tesselation amount which looked out of place in very large sizes. +- InputText, InputInt, InputFloat: fixed an issue where using Escape to revert + would not write back the reverted value during the IsItemDeactivatedAfterEdit() + frame if the provided input buffer doesn't store temporary edits. + (regression in 1.91.7) (#8915, #8273) - InputText: allow passing an empty string with buf_size==0. (#8907) In theory the buffer size should always account for a zero-terminator, but idioms such as using InputTextMultiline() with ImGuiInputTextFlags_ReadOnly to display diff --git a/imgui.h b/imgui.h index 859cb0318..cee72416c 100644 --- a/imgui.h +++ b/imgui.h @@ -29,7 +29,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.92.3 WIP" -#define IMGUI_VERSION_NUM 19224 +#define IMGUI_VERSION_NUM 19225 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 3012404e0..1d6fc9a83 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5058,14 +5058,14 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (flags & ImGuiInputTextFlags_EscapeClearsAll) { // Clear input - IM_ASSERT(buf[0] != 0); + IM_ASSERT(buf[0] != 0); // FIXME: use TextA here? apply_new_text = ""; apply_new_text_length = 0; value_changed = true; IMSTB_TEXTEDIT_CHARTYPE empty_string; stb_textedit_replace(state, state->Stb, &empty_string, 0); } - else if (strcmp(buf, state->TextToRevertTo.Data) != 0) + else if (strcmp(state->TextA.Data, state->TextToRevertTo.Data) != 0) { apply_new_text = state->TextToRevertTo.Data; apply_new_text_length = state->TextToRevertTo.Size - 1; From 7d33524042fe6781dad8bbf9de66cc726a10b1cf Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 4 Sep 2025 13:15:18 +0200 Subject: [PATCH 06/12] InputText: fixed an issue where using Escape with ImGuiInputTextFlags_EscapeClearsAll. (#8915, #8273) Regression test: "widgets_inputtext_temp_buffer_2" --- docs/CHANGELOG.txt | 3 +++ imgui_widgets.cpp | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 172e2f5cc..da1fd9b0d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -59,6 +59,9 @@ Other Changes: would not write back the reverted value during the IsItemDeactivatedAfterEdit() frame if the provided input buffer doesn't store temporary edits. (regression in 1.91.7) (#8915, #8273) +- InputText: fixed an issue where using Escape with ImGuiInputTextFlags_EscapeClearsAll + would not write back the cleared value during the IsItemDeactivatedAfterEdit() + frame if the provided input buffer doesn't store temporary edits. (#8915, #8273) - InputText: allow passing an empty string with buf_size==0. (#8907) In theory the buffer size should always account for a zero-terminator, but idioms such as using InputTextMultiline() with ImGuiInputTextFlags_ReadOnly to display diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 1d6fc9a83..f66baf767 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -4966,7 +4966,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ { if (flags & ImGuiInputTextFlags_EscapeClearsAll) { - if (buf[0] != 0) + if (state->TextA.Data[0] != 0) { revert_edit = true; } @@ -5058,7 +5058,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (flags & ImGuiInputTextFlags_EscapeClearsAll) { // Clear input - IM_ASSERT(buf[0] != 0); // FIXME: use TextA here? + IM_ASSERT(state->TextA.Data[0] != 0); apply_new_text = ""; apply_new_text_length = 0; value_changed = true; From e51d93e2f523b3209065bc556becc0269506113b Mon Sep 17 00:00:00 2001 From: Ronan Cailleau Date: Tue, 29 Oct 2024 13:58:08 +0100 Subject: [PATCH 07/12] Backends: Vulkan: added ImGui_ImplVulkan_CreateMainPipeline(). (#8110, #8111, #8053) - Added ImGui_ImplVulkan_CreateMainPipeline(...) to explicitly re-create the main window pipeline (when some of its properties are changed). - 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). --- backends/imgui_impl_vulkan.cpp | 102 ++++++++++++++++++++++++++++----- backends/imgui_impl_vulkan.h | 19 +++++- 2 files changed, 105 insertions(+), 16 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 263c2c73b..e011f6ff1 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -906,10 +906,21 @@ static void ImGui_ImplVulkan_CreateShaderModules(VkDevice device, const VkAlloca } } -static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationCallbacks* allocator, VkPipelineCache pipelineCache, VkRenderPass renderPass, VkSampleCountFlagBits MSAASamples, VkPipeline* pipeline, uint32_t subpass) +struct ImGui_ImplVulkan_PipelineCreateInfo +{ + VkDevice Device = VK_NULL_HANDLE; + const VkAllocationCallbacks* Allocator = nullptr; + VkPipelineCache PipelineCache = VK_NULL_HANDLE; + VkRenderPass RenderPass = VK_NULL_HANDLE; + uint32_t Subpass = 0; + VkSampleCountFlagBits MSAASamples = {}; + const ImGui_ImplVulkan_PipelineRenderingCreateInfo* pRenderingInfo = nullptr; +}; + +static VkPipeline ImGui_ImplVulkan_CreatePipeline(ImGui_ImplVulkan_PipelineCreateInfo const& pci) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_CreateShaderModules(device, allocator); + ImGui_ImplVulkan_CreateShaderModules(pci.Device, pci.Allocator); VkPipelineShaderStageCreateInfo stage[2] = {}; stage[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -964,7 +975,7 @@ static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationC VkPipelineMultisampleStateCreateInfo ms_info = {}; ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - ms_info.rasterizationSamples = (MSAASamples != 0) ? MSAASamples : VK_SAMPLE_COUNT_1_BIT; + ms_info.rasterizationSamples = (pci.MSAASamples != 0) ? pci.MSAASamples : VK_SAMPLE_COUNT_1_BIT; VkPipelineColorBlendAttachmentState color_attachment[1] = {}; color_attachment[0].blendEnable = VK_TRUE; @@ -1004,21 +1015,23 @@ static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationC info.pColorBlendState = &blend_info; info.pDynamicState = &dynamic_state; info.layout = bd->PipelineLayout; - info.renderPass = renderPass; - info.subpass = subpass; + info.renderPass = pci.RenderPass; + info.subpass = pci.Subpass; #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING if (bd->VulkanInitInfo.UseDynamicRendering) { - 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"); - IM_ASSERT(bd->VulkanInitInfo.PipelineRenderingCreateInfo.pNext == nullptr && "PipelineRenderingCreateInfo pNext must be nullptr"); - info.pNext = &bd->VulkanInitInfo.PipelineRenderingCreateInfo; + IM_ASSERT(pci.pRenderingInfo && "PipelineRenderingCreateInfo must not be nullptr when using dynamic rendering"); + 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"); + IM_ASSERT(pci.pRenderingInfo->pNext == nullptr && "PipelineRenderingCreateInfo::pNext must be nullptr"); + info.pNext = pci.pRenderingInfo; info.renderPass = VK_NULL_HANDLE; // Just make sure it's actually nullptr. } #endif - - VkResult err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &info, allocator, pipeline); + VkPipeline res; + VkResult err = vkCreateGraphicsPipelines(pci.Device, pci.PipelineCache, 1, &info, pci.Allocator, &res); check_vk_result(err); + return res; } bool ImGui_ImplVulkan_CreateDeviceObjects() @@ -1092,7 +1105,34 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() check_vk_result(err); } - ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, v->PipelineCache, v->RenderPass, v->MSAASamples, &bd->Pipeline, v->Subpass); + { + bool create_pipeline = false; + const ImGui_ImplVulkan_PipelineRenderingCreateInfo* p_dynamic_rendering = nullptr; + if (v->RenderPass) + { + create_pipeline = true; + } + else + { +#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING + if (v->UseDynamicRendering && v->PipelineRenderingCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR) + { + p_dynamic_rendering = &v->PipelineRenderingCreateInfo; + create_pipeline = true; + } +#endif + } + if (create_pipeline) + { + ImGui_ImplVulkan_MainPipelineCreateInfo mp_info = {}; + mp_info.RenderPass = v->RenderPass; + mp_info.Subpass = v->Subpass; + mp_info.MSAASamples = v->MSAASamples; + mp_info.pDynamicRendering = p_dynamic_rendering; + + ImGui_ImplVulkan_ReCreateMainPipeline(mp_info); + } + } // Create command pool/buffer for texture upload if (!bd->TexCommandPool) @@ -1117,6 +1157,40 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() return true; } +void ImGui_ImplVulkan_ReCreateMainPipeline(ImGui_ImplVulkan_MainPipelineCreateInfo const& info) +{ + ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); + ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; + if (bd->Pipeline) + { + vkDestroyPipeline(v->Device, bd->Pipeline, v->Allocator); + bd->Pipeline = VK_NULL_HANDLE; + } + v->RenderPass = info.RenderPass; + v->MSAASamples = info.MSAASamples; + v->Subpass = info.Subpass; + +#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING + if (info.pDynamicRendering) + { + v->PipelineRenderingCreateInfo = *info.pDynamicRendering; + } +#else + IM_ASSERT(info.pDynamicRendering == nullptr); +#endif + + ImGui_ImplVulkan_PipelineCreateInfo pci; + pci.Device = v->Device; + pci.Allocator = v->Allocator; + pci.PipelineCache = v->PipelineCache; + pci.RenderPass = v->RenderPass; + pci.Subpass = v->Subpass; + pci.MSAASamples = v->MSAASamples; + pci.pRenderingInfo = info.pDynamicRendering; + + bd->Pipeline = ImGui_ImplVulkan_CreatePipeline(pci); +} + void ImGui_ImplVulkan_DestroyDeviceObjects() { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); @@ -1239,17 +1313,15 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) IM_ASSERT(info->DescriptorPoolSize > 0); IM_ASSERT(info->MinImageCount >= 2); IM_ASSERT(info->ImageCount >= info->MinImageCount); - if (info->UseDynamicRendering == false) - IM_ASSERT(info->RenderPass != VK_NULL_HANDLE); - bd->VulkanInitInfo = *info; + ImGui_ImplVulkan_InitInfo * v = &bd->VulkanInitInfo; + *v = *info; VkPhysicalDeviceProperties properties; vkGetPhysicalDeviceProperties(info->PhysicalDevice, &properties); bd->NonCoherentAtomSize = properties.limits.nonCoherentAtomSize; #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; if (v->PipelineRenderingCreateInfo.pColorAttachmentFormats != NULL) { // Deep copy buffer to reduce error-rate for end user (#8282) diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index 4baa98335..d4f897961 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -65,6 +65,12 @@ // Backend uses a small number of descriptors per font atlas + as many as additional calls done to ImGui_ImplVulkan_AddTexture(). #define IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE (8) // Minimum per atlas +#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING +typedef VkPipelineRenderingCreateInfoKHR ImGui_ImplVulkan_PipelineRenderingCreateInfo; +#else +typedef void ImGui_ImplVulkan_PipelineRenderingCreateInfo; +#endif + // Initialization data, for ImGui_ImplVulkan_Init() // [Please zero-clear before use!] // - About descriptor pool: @@ -98,6 +104,7 @@ struct ImGui_ImplVulkan_InitInfo // Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3. bool UseDynamicRendering; #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING + // (Optional, valid iif .sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR) VkPipelineRenderingCreateInfoKHR PipelineRenderingCreateInfo; #endif @@ -108,12 +115,22 @@ struct ImGui_ImplVulkan_InitInfo }; // Follow "Getting Started" link and check examples/ folder to learn about using backends! -IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info); +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)) +#define IMGUI_IMPL_VULKAN_HAS_MAIN_PIPELINE_RE_CREATION 1 +struct ImGui_ImplVulkan_MainPipelineCreateInfo +{ + VkRenderPass RenderPass = VK_NULL_HANDLE; + uint32_t Subpass = 0; + VkSampleCountFlagBits MSAASamples = {}; + const ImGui_ImplVulkan_PipelineRenderingCreateInfo* pDynamicRendering = nullptr; +}; +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)) IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown(); IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame(); IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE); IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated) + // (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. IMGUI_IMPL_API void ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex); From ee03cef14fbc2e49c8236423a2d6b53f031e2093 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 4 Sep 2025 14:37:14 +0200 Subject: [PATCH 08/12] Backends: Vulkan: revert using a struct for ImGui_ImplVulkan_CreatePipeline() for now. (#8110, #8111, #8053) --- backends/imgui_impl_vulkan.cpp | 51 ++++++++++++---------------------- 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index e011f6ff1..69e3430e0 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -906,21 +906,10 @@ static void ImGui_ImplVulkan_CreateShaderModules(VkDevice device, const VkAlloca } } -struct ImGui_ImplVulkan_PipelineCreateInfo -{ - VkDevice Device = VK_NULL_HANDLE; - const VkAllocationCallbacks* Allocator = nullptr; - VkPipelineCache PipelineCache = VK_NULL_HANDLE; - VkRenderPass RenderPass = VK_NULL_HANDLE; - uint32_t Subpass = 0; - VkSampleCountFlagBits MSAASamples = {}; - const ImGui_ImplVulkan_PipelineRenderingCreateInfo* pRenderingInfo = nullptr; -}; - -static VkPipeline ImGui_ImplVulkan_CreatePipeline(ImGui_ImplVulkan_PipelineCreateInfo const& pci) +static VkPipeline ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationCallbacks* allocator, VkPipelineCache pipelineCache, VkRenderPass renderPass, VkSampleCountFlagBits MSAASamples, uint32_t subpass, const ImGui_ImplVulkan_PipelineRenderingCreateInfo* pipeline_rendering_create_info) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_CreateShaderModules(pci.Device, pci.Allocator); + ImGui_ImplVulkan_CreateShaderModules(device, allocator); VkPipelineShaderStageCreateInfo stage[2] = {}; stage[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -975,7 +964,7 @@ static VkPipeline ImGui_ImplVulkan_CreatePipeline(ImGui_ImplVulkan_PipelineCreat VkPipelineMultisampleStateCreateInfo ms_info = {}; ms_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - ms_info.rasterizationSamples = (pci.MSAASamples != 0) ? pci.MSAASamples : VK_SAMPLE_COUNT_1_BIT; + ms_info.rasterizationSamples = (MSAASamples != 0) ? MSAASamples : VK_SAMPLE_COUNT_1_BIT; VkPipelineColorBlendAttachmentState color_attachment[1] = {}; color_attachment[0].blendEnable = VK_TRUE; @@ -1015,23 +1004,25 @@ static VkPipeline ImGui_ImplVulkan_CreatePipeline(ImGui_ImplVulkan_PipelineCreat info.pColorBlendState = &blend_info; info.pDynamicState = &dynamic_state; info.layout = bd->PipelineLayout; - info.renderPass = pci.RenderPass; - info.subpass = pci.Subpass; + info.renderPass = renderPass; + info.subpass = subpass; #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING if (bd->VulkanInitInfo.UseDynamicRendering) { - IM_ASSERT(pci.pRenderingInfo && "PipelineRenderingCreateInfo must not be nullptr when using dynamic rendering"); - 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"); - IM_ASSERT(pci.pRenderingInfo->pNext == nullptr && "PipelineRenderingCreateInfo::pNext must be nullptr"); - info.pNext = pci.pRenderingInfo; + IM_ASSERT(pipeline_rendering_create_info && "PipelineRenderingCreateInfo must not be nullptr when using dynamic rendering"); + IM_ASSERT(pipeline_rendering_create_info->sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR && "PipelineRenderingCreateInfo::sType must be VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR"); + IM_ASSERT(pipeline_rendering_create_info->pNext == nullptr && "PipelineRenderingCreateInfo::pNext must be nullptr"); + info.pNext = pipeline_rendering_create_info; info.renderPass = VK_NULL_HANDLE; // Just make sure it's actually nullptr. } +#else + IM_ASSERT(pipeline_rendering_create_info == nullptr); #endif - VkPipeline res; - VkResult err = vkCreateGraphicsPipelines(pci.Device, pci.PipelineCache, 1, &info, pci.Allocator, &res); + VkPipeline pipeline; + VkResult err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &info, allocator, &pipeline); check_vk_result(err); - return res; + return pipeline; } bool ImGui_ImplVulkan_CreateDeviceObjects() @@ -1170,25 +1161,17 @@ void ImGui_ImplVulkan_ReCreateMainPipeline(ImGui_ImplVulkan_MainPipelineCreateIn v->MSAASamples = info.MSAASamples; v->Subpass = info.Subpass; + ImGui_ImplVulkan_PipelineRenderingCreateInfo * pipeline_rendering_create_info = nullptr; #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING if (info.pDynamicRendering) { v->PipelineRenderingCreateInfo = *info.pDynamicRendering; + pipeline_rendering_create_info = &v->PipelineRenderingCreateInfo; } #else IM_ASSERT(info.pDynamicRendering == nullptr); #endif - - ImGui_ImplVulkan_PipelineCreateInfo pci; - pci.Device = v->Device; - pci.Allocator = v->Allocator; - pci.PipelineCache = v->PipelineCache; - pci.RenderPass = v->RenderPass; - pci.Subpass = v->Subpass; - pci.MSAASamples = v->MSAASamples; - pci.pRenderingInfo = info.pDynamicRendering; - - bd->Pipeline = ImGui_ImplVulkan_CreatePipeline(pci); + bd->Pipeline = ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, v->PipelineCache, v->RenderPass, v->MSAASamples, v->Subpass, pipeline_rendering_create_info); } void ImGui_ImplVulkan_DestroyDeviceObjects() From 1ecc34a0b1096e61b5585025525392886bfebc34 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 4 Sep 2025 14:24:06 +0200 Subject: [PATCH 09/12] Backends: Vulkan: misc amends (e.g. changelog, coding style). (8110, 8111, 8053) # Conflicts: # backends/imgui_impl_vulkan.cpp --- backends/imgui_impl_vulkan.cpp | 56 +++++++++++++++------------------- backends/imgui_impl_vulkan.h | 33 +++++++++----------- docs/CHANGELOG.txt | 2 ++ 3 files changed, 41 insertions(+), 50 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 69e3430e0..23bf7b8ce 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -27,6 +27,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-09-04: Vulkan: Added ImGui_ImplVulkan_CreateMainPipeline(). (#8110, #8111) // 2025-07-27: Vulkan: Fixed texture update corruption introduced on 2025-06-11. (#8801, #8755, #8840) // 2025-07-07: Vulkan: Fixed texture synchronization issue introduced on 2025-06-11. (#8772) // 2025-06-27: Vulkan: Fixed validation errors during texture upload/update by aligning upload size to 'nonCoherentAtomSize'. (#8743, #8744) @@ -906,7 +907,11 @@ static void ImGui_ImplVulkan_CreateShaderModules(VkDevice device, const VkAlloca } } -static VkPipeline ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationCallbacks* allocator, VkPipelineCache pipelineCache, VkRenderPass renderPass, VkSampleCountFlagBits MSAASamples, uint32_t subpass, const ImGui_ImplVulkan_PipelineRenderingCreateInfo* pipeline_rendering_create_info) +#if !defined(IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING) && !(defined(VK_VERSION_1_3) || defined(VK_KHR_dynamic_rendering)) +typedef void VkPipelineRenderingCreateInfoKHR; +#endif + +static VkPipeline ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationCallbacks* allocator, VkPipelineCache pipelineCache, VkRenderPass renderPass, VkSampleCountFlagBits MSAASamples, uint32_t subpass, const VkPipelineRenderingCreateInfoKHR* pipeline_rendering_create_info) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); ImGui_ImplVulkan_CreateShaderModules(device, allocator); @@ -1096,33 +1101,22 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() check_vk_result(err); } - { - bool create_pipeline = false; - const ImGui_ImplVulkan_PipelineRenderingCreateInfo* p_dynamic_rendering = nullptr; - if (v->RenderPass) - { - create_pipeline = true; - } - else - { + // Create pipeline + const VkPipelineRenderingCreateInfoKHR* p_dynamic_rendering_create_info = nullptr; #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - if (v->UseDynamicRendering && v->PipelineRenderingCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR) - { - p_dynamic_rendering = &v->PipelineRenderingCreateInfo; - create_pipeline = true; - } + if (v->UseDynamicRendering && v->PipelineRenderingCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR) + p_dynamic_rendering_create_info = &v->PipelineRenderingCreateInfo; #endif - } - if (create_pipeline) - { - ImGui_ImplVulkan_MainPipelineCreateInfo mp_info = {}; - mp_info.RenderPass = v->RenderPass; - mp_info.Subpass = v->Subpass; - mp_info.MSAASamples = v->MSAASamples; - mp_info.pDynamicRendering = p_dynamic_rendering; - - ImGui_ImplVulkan_ReCreateMainPipeline(mp_info); - } + if (v->RenderPass || p_dynamic_rendering_create_info != nullptr) + { + ImGui_ImplVulkan_MainPipelineCreateInfo mp_info = {}; + mp_info.RenderPass = v->RenderPass; + mp_info.Subpass = v->Subpass; + mp_info.MSAASamples = v->MSAASamples; +#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING + mp_info.pDynamicRendering = p_dynamic_rendering_create_info; +#endif + ImGui_ImplVulkan_CreateMainPipeline(mp_info); } // Create command pool/buffer for texture upload @@ -1148,7 +1142,7 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() return true; } -void ImGui_ImplVulkan_ReCreateMainPipeline(ImGui_ImplVulkan_MainPipelineCreateInfo const& info) +void ImGui_ImplVulkan_CreateMainPipeline(const ImGui_ImplVulkan_MainPipelineCreateInfo& info) { ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; @@ -1161,15 +1155,13 @@ void ImGui_ImplVulkan_ReCreateMainPipeline(ImGui_ImplVulkan_MainPipelineCreateIn v->MSAASamples = info.MSAASamples; v->Subpass = info.Subpass; - ImGui_ImplVulkan_PipelineRenderingCreateInfo * pipeline_rendering_create_info = nullptr; + VkPipelineRenderingCreateInfoKHR* pipeline_rendering_create_info = nullptr; #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING if (info.pDynamicRendering) { v->PipelineRenderingCreateInfo = *info.pDynamicRendering; pipeline_rendering_create_info = &v->PipelineRenderingCreateInfo; } -#else - IM_ASSERT(info.pDynamicRendering == nullptr); #endif bd->Pipeline = ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, v->PipelineCache, v->RenderPass, v->MSAASamples, v->Subpass, pipeline_rendering_create_info); } @@ -1297,14 +1289,14 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) IM_ASSERT(info->MinImageCount >= 2); IM_ASSERT(info->ImageCount >= info->MinImageCount); - ImGui_ImplVulkan_InitInfo * v = &bd->VulkanInitInfo; - *v = *info; + bd->VulkanInitInfo = *info; VkPhysicalDeviceProperties properties; vkGetPhysicalDeviceProperties(info->PhysicalDevice, &properties); bd->NonCoherentAtomSize = properties.limits.nonCoherentAtomSize; #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING + ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; if (v->PipelineRenderingCreateInfo.pColorAttachmentFormats != NULL) { // Deep copy buffer to reduce error-rate for end user (#8282) diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index d4f897961..e4503261e 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -65,12 +65,6 @@ // Backend uses a small number of descriptors per font atlas + as many as additional calls done to ImGui_ImplVulkan_AddTexture(). #define IMGUI_IMPL_VULKAN_MINIMUM_IMAGE_SAMPLER_POOL_SIZE (8) // Minimum per atlas -#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING -typedef VkPipelineRenderingCreateInfoKHR ImGui_ImplVulkan_PipelineRenderingCreateInfo; -#else -typedef void ImGui_ImplVulkan_PipelineRenderingCreateInfo; -#endif - // Initialization data, for ImGui_ImplVulkan_Init() // [Please zero-clear before use!] // - About descriptor pool: @@ -104,8 +98,7 @@ struct ImGui_ImplVulkan_InitInfo // Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3. bool UseDynamicRendering; #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - // (Optional, valid iif .sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR) - VkPipelineRenderingCreateInfoKHR PipelineRenderingCreateInfo; + VkPipelineRenderingCreateInfoKHR PipelineRenderingCreateInfo; // Optional, valid if .sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR #endif // (Optional) Allocation, Debugging @@ -115,21 +108,25 @@ struct ImGui_ImplVulkan_InitInfo }; // Follow "Getting Started" link and check examples/ folder to learn about using backends! -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)) -#define IMGUI_IMPL_VULKAN_HAS_MAIN_PIPELINE_RE_CREATION 1 -struct ImGui_ImplVulkan_MainPipelineCreateInfo -{ - VkRenderPass RenderPass = VK_NULL_HANDLE; - uint32_t Subpass = 0; - VkSampleCountFlagBits MSAASamples = {}; - const ImGui_ImplVulkan_PipelineRenderingCreateInfo* pDynamicRendering = nullptr; -}; -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)) +IMGUI_IMPL_API bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info); IMGUI_IMPL_API void ImGui_ImplVulkan_Shutdown(); IMGUI_IMPL_API void ImGui_ImplVulkan_NewFrame(); IMGUI_IMPL_API void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer command_buffer, VkPipeline pipeline = VK_NULL_HANDLE); IMGUI_IMPL_API void ImGui_ImplVulkan_SetMinImageCount(uint32_t min_image_count); // To override MinImageCount after initialization (e.g. if swap chain is recreated) +// (Advanced) Use e.g. if you need to recreate pipeline without reinitializing the backend (see #8110, #8111) +// The main window pipeline will be created by ImGui_ImplVulkan_Init() if possible (== RenderPass xor (UseDynamicRendering && PipelineRenderingCreateInfo->sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR)) +// Else, the pipeline can be created, or re-created, using ImGui_ImplVulkan_CreateMainPipeline() before rendering. +struct ImGui_ImplVulkan_MainPipelineCreateInfo +{ + VkRenderPass RenderPass = VK_NULL_HANDLE; + uint32_t Subpass = 0; + VkSampleCountFlagBits MSAASamples = {}; +#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING + const VkPipelineRenderingCreateInfoKHR* pDynamicRendering = nullptr; +#endif +}; +IMGUI_IMPL_API void ImGui_ImplVulkan_CreateMainPipeline(const ImGui_ImplVulkan_MainPipelineCreateInfo& info); // (render_pass xor (p_dynamic_rendering && p_dynamic_rendering is correct (sType and pNext)) // (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. IMGUI_IMPL_API void ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index da1fd9b0d..afdcbfc6c 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -81,6 +81,8 @@ Other Changes: - Backends: SDL_GPU: Added ImGui_ImplSDLGPU3_InitInfo::SwapchainComposition and PresentMode to configure how secondary viewports are created. Currently only used multi-viewport mode. (#8892) [@PTSVU] +- Backends: Vulkan: added ImGui_ImplVulkan_CreateMainPipeline() to recreate pipeline + without reinitializing backend. (#8110, #8111) [@SuperRonan] ----------------------------------------------------------------------- From 26aa81a8b1546ab5805602dde49a29c06699c6d5 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 4 Sep 2025 16:39:16 +0200 Subject: [PATCH 10/12] Backends: Vulkan: misc amends (makes ImGui_ImplVulkan_MainPipelineCreateInfo::PipelineRenderingCreateInfo consistent with InitInfo). (#8110, #8111, #8053) --- backends/imgui_impl_vulkan.cpp | 15 +++++++-------- backends/imgui_impl_vulkan.h | 6 +++--- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 23bf7b8ce..db23aad49 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -1102,19 +1102,18 @@ bool ImGui_ImplVulkan_CreateDeviceObjects() } // Create pipeline - const VkPipelineRenderingCreateInfoKHR* p_dynamic_rendering_create_info = nullptr; + if (v->RenderPass #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - if (v->UseDynamicRendering && v->PipelineRenderingCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR) - p_dynamic_rendering_create_info = &v->PipelineRenderingCreateInfo; + || (v->UseDynamicRendering && v->PipelineRenderingCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR) #endif - if (v->RenderPass || p_dynamic_rendering_create_info != nullptr) + ) { ImGui_ImplVulkan_MainPipelineCreateInfo mp_info = {}; mp_info.RenderPass = v->RenderPass; mp_info.Subpass = v->Subpass; mp_info.MSAASamples = v->MSAASamples; #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - mp_info.pDynamicRendering = p_dynamic_rendering_create_info; + mp_info.PipelineRenderingCreateInfo = v->PipelineRenderingCreateInfo; #endif ImGui_ImplVulkan_CreateMainPipeline(mp_info); } @@ -1155,11 +1154,11 @@ void ImGui_ImplVulkan_CreateMainPipeline(const ImGui_ImplVulkan_MainPipelineCrea v->MSAASamples = info.MSAASamples; v->Subpass = info.Subpass; - VkPipelineRenderingCreateInfoKHR* pipeline_rendering_create_info = nullptr; + const VkPipelineRenderingCreateInfoKHR* pipeline_rendering_create_info = nullptr; #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - if (info.pDynamicRendering) + if (v->UseDynamicRendering) { - v->PipelineRenderingCreateInfo = *info.pDynamicRendering; + v->PipelineRenderingCreateInfo = info.PipelineRenderingCreateInfo; pipeline_rendering_create_info = &v->PipelineRenderingCreateInfo; } #endif diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index e4503261e..fbbd9e2bd 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -98,13 +98,13 @@ struct ImGui_ImplVulkan_InitInfo // Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3. bool UseDynamicRendering; #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - VkPipelineRenderingCreateInfoKHR PipelineRenderingCreateInfo; // Optional, valid if .sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR + VkPipelineRenderingCreateInfoKHR PipelineRenderingCreateInfo; // Optional, valid if .sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR #endif // (Optional) Allocation, Debugging const VkAllocationCallbacks* Allocator; void (*CheckVkResultFn)(VkResult err); - VkDeviceSize MinAllocationSize; // Minimum allocation size. Set to 1024*1024 to satisfy zealous best practices validation layer and waste a little memory. + VkDeviceSize MinAllocationSize; // Minimum allocation size. Set to 1024*1024 to satisfy zealous best practices validation layer and waste a little memory. }; // Follow "Getting Started" link and check examples/ folder to learn about using backends! @@ -123,7 +123,7 @@ struct ImGui_ImplVulkan_MainPipelineCreateInfo uint32_t Subpass = 0; VkSampleCountFlagBits MSAASamples = {}; #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - const VkPipelineRenderingCreateInfoKHR* pDynamicRendering = nullptr; + VkPipelineRenderingCreateInfoKHR PipelineRenderingCreateInfo; // Optional, valid if .sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR #endif }; IMGUI_IMPL_API void ImGui_ImplVulkan_CreateMainPipeline(const ImGui_ImplVulkan_MainPipelineCreateInfo& info); // (render_pass xor (p_dynamic_rendering && p_dynamic_rendering is correct (sType and pNext)) From c63714822f3e7cad9c6f6cebfcbe91e74c93b5ee Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 4 Sep 2025 16:41:20 +0200 Subject: [PATCH 11/12] Backends: Vulkan: reorder InitInfo fields. --- backends/imgui_impl_vulkan.h | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/backends/imgui_impl_vulkan.h b/backends/imgui_impl_vulkan.h index fbbd9e2bd..c7f3007dc 100644 --- a/backends/imgui_impl_vulkan.h +++ b/backends/imgui_impl_vulkan.h @@ -82,20 +82,18 @@ struct ImGui_ImplVulkan_InitInfo uint32_t QueueFamily; VkQueue Queue; VkDescriptorPool DescriptorPool; // See requirements in note above; ignored if using DescriptorPoolSize > 0 - VkRenderPass RenderPass; // Ignored if using dynamic rendering + uint32_t DescriptorPoolSize; // Optional: set to create internal descriptor pool automatically instead of using DescriptorPool. uint32_t MinImageCount; // >= 2 uint32_t ImageCount; // >= MinImageCount + VkPipelineCache PipelineCache; // Optional + + // Pipeline + VkRenderPass RenderPass; // Ignored if using dynamic rendering + uint32_t Subpass; VkSampleCountFlagBits MSAASamples; // 0 defaults to VK_SAMPLE_COUNT_1_BIT - // (Optional) - VkPipelineCache PipelineCache; - uint32_t Subpass; - - // (Optional) Set to create internal descriptor pool instead of using DescriptorPool - uint32_t DescriptorPoolSize; - // (Optional) Dynamic Rendering - // Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3. + // Need to explicitly enable VK_KHR_dynamic_rendering extension to use this, even for Vulkan 1.3 + setup PipelineRenderingCreateInfo. bool UseDynamicRendering; #ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING VkPipelineRenderingCreateInfoKHR PipelineRenderingCreateInfo; // Optional, valid if .sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR From 026d47cd35ca2b2088266950127b5074a0cf852a Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 4 Sep 2025 17:47:36 +0200 Subject: [PATCH 12/12] Backends: Vulkan: store pColorAttachmentFormats deep-copy into an ImVector. (#8282, #8110) --- backends/imgui_impl_vulkan.cpp | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index db23aad49..65fecb41e 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -257,6 +257,7 @@ struct ImGui_ImplVulkan_Data VkShaderModule ShaderModuleVert; VkShaderModule ShaderModuleFrag; VkDescriptorPool DescriptorPool; + ImVector PipelineRenderingCreateInfoColorAttachmentFormats; // Deep copy of format array // Texture management VkSampler TexSampler; @@ -1160,6 +1161,13 @@ void ImGui_ImplVulkan_CreateMainPipeline(const ImGui_ImplVulkan_MainPipelineCrea { v->PipelineRenderingCreateInfo = info.PipelineRenderingCreateInfo; pipeline_rendering_create_info = &v->PipelineRenderingCreateInfo; + if (v->PipelineRenderingCreateInfo.pColorAttachmentFormats != NULL) + { + // Deep copy buffer to reduce error-rate for end user (#8282) + bd->PipelineRenderingCreateInfoColorAttachmentFormats.resize((int)v->PipelineRenderingCreateInfo.colorAttachmentCount); + memcpy(bd->PipelineRenderingCreateInfoColorAttachmentFormats.Data, v->PipelineRenderingCreateInfo.pColorAttachmentFormats, (size_t)bd->PipelineRenderingCreateInfoColorAttachmentFormats.size_in_bytes()); + v->PipelineRenderingCreateInfo.pColorAttachmentFormats = bd->PipelineRenderingCreateInfoColorAttachmentFormats.Data; + } } #endif bd->Pipeline = ImGui_ImplVulkan_CreatePipeline(v->Device, v->Allocator, v->PipelineCache, v->RenderPass, v->MSAASamples, v->Subpass, pipeline_rendering_create_info); @@ -1294,17 +1302,6 @@ bool ImGui_ImplVulkan_Init(ImGui_ImplVulkan_InitInfo* info) vkGetPhysicalDeviceProperties(info->PhysicalDevice, &properties); bd->NonCoherentAtomSize = properties.limits.nonCoherentAtomSize; -#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - if (v->PipelineRenderingCreateInfo.pColorAttachmentFormats != NULL) - { - // Deep copy buffer to reduce error-rate for end user (#8282) - VkFormat* formats_copy = (VkFormat*)IM_ALLOC(sizeof(VkFormat) * v->PipelineRenderingCreateInfo.colorAttachmentCount); - memcpy(formats_copy, v->PipelineRenderingCreateInfo.pColorAttachmentFormats, sizeof(VkFormat) * v->PipelineRenderingCreateInfo.colorAttachmentCount); - v->PipelineRenderingCreateInfo.pColorAttachmentFormats = formats_copy; - } -#endif - if (!ImGui_ImplVulkan_CreateDeviceObjects()) IM_ASSERT(0 && "ImGui_ImplVulkan_CreateDeviceObjects() failed!"); // <- Can't be hit yet. @@ -1318,9 +1315,6 @@ void ImGui_ImplVulkan_Shutdown() ImGuiIO& io = ImGui::GetIO(); ImGui_ImplVulkan_DestroyDeviceObjects(); -#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING - IM_FREE((void*)const_cast(bd->VulkanInitInfo.PipelineRenderingCreateInfo.pColorAttachmentFormats)); -#endif io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr;