Merge branch 'master' into docking

# Conflicts:
#	backends/imgui_impl_vulkan.cpp
This commit is contained in:
ocornut
2025-09-04 18:06:35 +02:00
8 changed files with 111 additions and 44 deletions

View File

@@ -29,6 +29,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2025-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
// 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)
@@ -279,6 +280,7 @@ struct ImGui_ImplVulkan_Data
VkShaderModule ShaderModuleVert;
VkShaderModule ShaderModuleFrag;
VkDescriptorPool DescriptorPool;
ImVector<VkFormat> PipelineRenderingCreateInfoColorAttachmentFormats; // Deep copy of format array
// Texture management
VkSampler TexSampler;
@@ -935,7 +937,11 @@ 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)
#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);
@@ -1039,15 +1045,19 @@ static void ImGui_ImplVulkan_CreatePipeline(VkDevice device, const VkAllocationC
#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(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
VkResult err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &info, allocator, pipeline);
VkPipeline pipeline;
VkResult err = vkCreateGraphicsPipelines(device, pipelineCache, 1, &info, allocator, &pipeline);
check_vk_result(err);
return pipeline;
}
bool ImGui_ImplVulkan_CreateDeviceObjects()
@@ -1121,7 +1131,22 @@ 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);
// Create pipeline
if (v->RenderPass
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
|| (v->UseDynamicRendering && v->PipelineRenderingCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR)
#endif
)
{
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.PipelineRenderingCreateInfo = v->PipelineRenderingCreateInfo;
#endif
ImGui_ImplVulkan_CreateMainPipeline(mp_info);
}
// Create command pool/buffer for texture upload
if (!bd->TexCommandPool)
@@ -1146,6 +1171,37 @@ bool ImGui_ImplVulkan_CreateDeviceObjects()
return true;
}
void ImGui_ImplVulkan_CreateMainPipeline(const ImGui_ImplVulkan_MainPipelineCreateInfo& 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;
const VkPipelineRenderingCreateInfoKHR* pipeline_rendering_create_info = nullptr;
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
if (v->UseDynamicRendering)
{
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);
}
void ImGui_ImplVulkan_DestroyDeviceObjects()
{
ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData();
@@ -1270,8 +1326,6 @@ 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;
@@ -1279,17 +1333,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.
@@ -1310,9 +1353,6 @@ void ImGui_ImplVulkan_Shutdown()
// First destroy objects in all viewports
ImGui_ImplVulkan_DestroyDeviceObjects();
#ifdef IMGUI_IMPL_VULKAN_HAS_DYNAMIC_RENDERING
IM_FREE((void*)const_cast<VkFormat*>(bd->VulkanInitInfo.PipelineRenderingCreateInfo.pColorAttachmentFormats));
#endif
// Manually delete main viewport render data in-case we haven't initialized for viewports
ImGuiViewport* main_viewport = ImGui::GetMainViewport();

View File

@@ -83,29 +83,27 @@ 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;
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!
@@ -115,6 +113,20 @@ 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
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))
// (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);

View File

@@ -47,10 +47,21 @@ 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)
- 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, 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: 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
@@ -70,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]
-----------------------------------------------------------------------

View File

@@ -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) |

View File

@@ -14966,7 +14966,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

View File

@@ -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
#define IMGUI_HAS_VIEWPORT // In 'docking' WIP branch.
@@ -102,8 +102,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 <sal.h> + 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 <sal.h> + 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)))

View File

@@ -3032,7 +3032,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

View File

@@ -4972,7 +4972,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;
}
@@ -5064,14 +5064,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(state->TextA.Data[0] != 0);
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;