From d4f722d5b289d4d75b775acfb0a4b41e7df472a7 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 18 Sep 2025 16:22:24 +0200 Subject: [PATCH 01/14] IO: added ImGuiPlatformIO::ClearPlatformHandlers(), ClearRendererHandlers(). Backends: call those on Shutdown(). (#8945, #2769) --- backends/imgui_impl_allegro5.cpp | 4 ++++ backends/imgui_impl_dx10.cpp | 4 ++++ backends/imgui_impl_dx11.cpp | 4 ++++ backends/imgui_impl_dx12.cpp | 4 +++- backends/imgui_impl_dx9.cpp | 4 ++++ backends/imgui_impl_glfw.cpp | 4 ++++ backends/imgui_impl_metal.mm | 6 +++++- backends/imgui_impl_opengl2.cpp | 4 ++++ backends/imgui_impl_opengl3.cpp | 4 ++++ backends/imgui_impl_osx.mm | 4 ++++ backends/imgui_impl_sdl2.cpp | 3 +++ backends/imgui_impl_sdl3.cpp | 3 +++ backends/imgui_impl_sdlgpu3.cpp | 4 ++++ backends/imgui_impl_sdlrenderer2.cpp | 3 +++ backends/imgui_impl_sdlrenderer3.cpp | 3 +++ backends/imgui_impl_vulkan.cpp | 3 +++ backends/imgui_impl_wgpu.cpp | 3 +++ backends/imgui_impl_win32.cpp | 3 +++ docs/CHANGELOG.txt | 6 ++++++ imgui.cpp | 17 +++++++++++++++++ imgui.h | 7 +++++++ 21 files changed, 95 insertions(+), 2 deletions(-) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index 6c5df4b1f..bb6660d88 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-09-18: Call platform_io.ClearRendererHandlers() and platform_io.ClearPlatformHandlers() on shutdown. // 2025-08-12: Inputs: fixed missing support for ImGuiKey_PrintScreen under Windows, as raw Allegro 5 does not receive it. // 2025-08-12: Added ImGui_ImplAllegro5_SetDisplay() function to change current ALLEGRO_DISPLAY, as Allegro applications often need to do that. // 2025-07-07: Fixed texture update broken on some platforms where ALLEGRO_LOCK_WRITEONLY needed all texels to be rewritten. @@ -499,6 +500,7 @@ void ImGui_ImplAllegro5_Shutdown() ImGui_ImplAllegro5_Data* bd = ImGui_ImplAllegro5_GetBackendData(); IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGui_ImplAllegro5_InvalidateDeviceObjects(); if (bd->VertexDecl) @@ -509,6 +511,8 @@ void ImGui_ImplAllegro5_Shutdown() io.BackendPlatformName = io.BackendRendererName = nullptr; io.BackendPlatformUserData = nullptr; io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_RendererHasTextures); + platform_io.ClearRendererHandlers(); + platform_io.ClearPlatformHandlers(); IM_DELETE(bd); } diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index 5515f780c..ae6510db2 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -16,6 +16,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-06-11: DirectX10: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. // 2025-05-07: DirectX10: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows). // 2025-01-06: DirectX10: Expose selected render state in ImGui_ImplDX10_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. @@ -630,13 +631,16 @@ void ImGui_ImplDX10_Shutdown() ImGui_ImplDX10_Data* bd = ImGui_ImplDX10_GetBackendData(); IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGui_ImplDX10_InvalidateDeviceObjects(); if (bd->pFactory) { bd->pFactory->Release(); } if (bd->pd3dDevice) { bd->pd3dDevice->Release(); } + io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); + platform_io.ClearRendererHandlers(); IM_DELETE(bd); } diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index c71e44d06..1b3423654 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -17,6 +17,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-06-11: DirectX11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. // 2025-05-07: DirectX11: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows). // 2025-01-06: DirectX11: Expose VertexConstantBuffer in ImGui_ImplDX11_RenderState. Reset projection matrix in ImDrawCallback_ResetRenderState handler. @@ -649,14 +650,17 @@ void ImGui_ImplDX11_Shutdown() ImGui_ImplDX11_Data* bd = ImGui_ImplDX11_GetBackendData(); IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGui_ImplDX11_InvalidateDeviceObjects(); if (bd->pFactory) { bd->pFactory->Release(); } if (bd->pd3dDevice) { bd->pd3dDevice->Release(); } if (bd->pd3dDeviceContext) { bd->pd3dDeviceContext->Release(); } + io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); + platform_io.ClearRendererHandlers(); IM_DELETE(bd); } diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index c84c21971..86f1180ab 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-06-19: Fixed build on MinGW. (#8702, #4594) // 2025-06-11: DirectX12: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. // 2025-05-07: DirectX12: Honor draw_data->FramebufferScale to allow for custom backends and experiment using it (consistently with other renderer backends, even though in normal condition it is not set under Windows). @@ -905,14 +906,15 @@ void ImGui_ImplDX12_Shutdown() ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - // Clean up windows and device objects ImGui_ImplDX12_InvalidateDeviceObjects(); delete[] bd->pFrameResources; io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); + platform_io.ClearRendererHandlers(); IM_DELETE(bd); } diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index 94411fabe..4a8899a62 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -17,6 +17,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-06-11: DirectX9: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. // 2024-10-07: DirectX9: Changed default texture sampler to Clamp instead of Repeat/Wrap. // 2024-02-12: DirectX9: Using RGBA format when supported by the driver to avoid CPU side conversion. (#6575) @@ -351,12 +352,15 @@ void ImGui_ImplDX9_Shutdown() ImGui_ImplDX9_Data* bd = ImGui_ImplDX9_GetBackendData(); IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGui_ImplDX9_InvalidateDeviceObjects(); if (bd->pd3dDevice) { bd->pd3dDevice->Release(); } + io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); + platform_io.ClearRendererHandlers(); IM_DELETE(bd); } diff --git a/backends/imgui_impl_glfw.cpp b/backends/imgui_impl_glfw.cpp index 8a646b5dd..cfe5dc6d3 100644 --- a/backends/imgui_impl_glfw.cpp +++ b/backends/imgui_impl_glfw.cpp @@ -29,6 +29,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown. // 2025-09-15: Content Scales are always reported as 1.0 on Wayland. FramebufferScale are always reported as 1.0 on X11. (#8920, #8921) // 2025-07-08: Made ImGui_ImplGlfw_GetContentScaleForWindow(), ImGui_ImplGlfw_GetContentScaleForMonitor() helpers return 1.0f on Emscripten and Android platforms, matching macOS logic. (#8742, #8733) // 2025-06-18: Added support for multiple Dear ImGui contexts. (#8676, #8239, #8069) @@ -767,7 +768,9 @@ void ImGui_ImplGlfw_Shutdown() { ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?"); + ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); if (bd->InstalledCallbacks) ImGui_ImplGlfw_RestoreCallbacks(bd->Window); @@ -790,6 +793,7 @@ void ImGui_ImplGlfw_Shutdown() io.BackendPlatformName = nullptr; io.BackendPlatformUserData = nullptr; io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad); + platform_io.ClearPlatformHandlers(); ImGui_ImplGlfw_ContextMap_Remove(bd->Window); IM_DELETE(bd); } diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index a1adc6c9a..81e8be6c4 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -16,6 +16,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplMetal_CreateFontsTexture() and ImGui_ImplMetal_DestroyFontsTexture(). // 2025-02-03: Metal: Crash fix. (#8367) // 2024-01-08: Metal: Fixed memory leaks when using metal-cpp (#8276, #8166) or when using multiple contexts (#7419). @@ -148,13 +149,16 @@ void ImGui_ImplMetal_Shutdown() ImGui_ImplMetal_Data* bd = ImGui_ImplMetal_GetBackendData(); IM_UNUSED(bd); IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); + ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + ImGui_ImplMetal_DestroyDeviceObjects(); ImGui_ImplMetal_DestroyBackendData(); - ImGuiIO& io = ImGui::GetIO(); io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); + platform_io.ClearRendererHandlers(); } void ImGui_ImplMetal_NewFrame(MTLRenderPassDescriptor* renderPassDescriptor) diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index 477e3a043..af5618fb6 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -25,6 +25,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-07-15: OpenGL: Set GL_UNPACK_ALIGNMENT to 1 before updating textures. (#8802) // 2025-06-11: OpenGL: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplOpenGL2_CreateFontsTexture() and ImGui_ImplOpenGL2_DestroyFontsTexture(). // 2024-10-07: OpenGL: Changed default texture sampler to Clamp instead of Repeat/Wrap. @@ -115,11 +116,14 @@ void ImGui_ImplOpenGL2_Shutdown() ImGui_ImplOpenGL2_Data* bd = ImGui_ImplOpenGL2_GetBackendData(); IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGui_ImplOpenGL2_DestroyDeviceObjects(); + io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasTextures); + platform_io.ClearRendererHandlers(); IM_DELETE(bd); } diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index 5ab43a406..3e0e265b1 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -23,6 +23,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-07-22: OpenGL: Add and call embedded loader shutdown during ImGui_ImplOpenGL3_Shutdown() to facilitate multiple init/shutdown cycles in same process. (#8792) // 2025-07-15: OpenGL: Set GL_UNPACK_ALIGNMENT to 1 before updating textures (#8802) + restore non-WebGL/ES update path that doesn't require a CPU-side copy. // 2025-06-11: OpenGL: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplOpenGL3_CreateFontsTexture() and ImGui_ImplOpenGL3_DestroyFontsTexture(). @@ -421,11 +422,14 @@ void ImGui_ImplOpenGL3_Shutdown() ImGui_ImplOpenGL3_Data* bd = ImGui_ImplOpenGL3_GetBackendData(); IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGui_ImplOpenGL3_DestroyDeviceObjects(); + io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); + platform_io.ClearRendererHandlers(); IM_DELETE(bd); #ifdef IMGUI_IMPL_OPENGL_LOADER_IMGL3W diff --git a/backends/imgui_impl_osx.mm b/backends/imgui_impl_osx.mm index 06a6aff8b..189dd53e6 100644 --- a/backends/imgui_impl_osx.mm +++ b/backends/imgui_impl_osx.mm @@ -29,6 +29,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown. // 2025-06-27: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. // 2025-06-12: ImGui_ImplOSX_HandleEvent() only process event for window containing our view. (#8644) // 2025-03-21: Fill gamepad inputs and set ImGuiBackendFlags_HasGamepad regardless of ImGuiConfigFlags_NavEnableGamepad being set. @@ -514,9 +515,12 @@ void ImGui_ImplOSX_Shutdown() ImGui_ImplOSX_DestroyBackendData(); ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + io.BackendPlatformName = nullptr; io.BackendPlatformUserData = nullptr; io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasGamepad); + platform_io.ClearPlatformHandlers(); } static void ImGui_ImplOSX_UpdateMouseCursor() diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index 08e7988e2..acd98f641 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown. // 2025-09-15: Content Scales are always reported as 1.0 on Wayland. (#8921) // 2025-07-08: Made ImGui_ImplSDL2_GetContentScaleForWindow(), ImGui_ImplSDL2_GetContentScaleForDisplay() helpers return 1.0f on Emscripten and Android platforms, matching macOS logic. (#8742, #8733) // 2025-06-11: Added ImGui_ImplSDL2_GetContentScaleForWindow(SDL_Window* window) and ImGui_ImplSDL2_GetContentScaleForDisplay(int display_index) helper to facilitate making DPI-aware apps. @@ -629,6 +630,7 @@ void ImGui_ImplSDL2_Shutdown() ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); if (bd->ClipboardTextData) SDL_free(bd->ClipboardTextData); @@ -639,6 +641,7 @@ void ImGui_ImplSDL2_Shutdown() io.BackendPlatformName = nullptr; io.BackendPlatformUserData = nullptr; io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad); + platform_io.ClearPlatformHandlers(); IM_DELETE(bd); } diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 17613d30a..83dc93282 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown. // 2025-09-15: Use SDL_GetWindowDisplayScale() on Mac to output DisplayFrameBufferScale. The function is more reliable during resolution changes e.g. going fullscreen. (#8703, #4414) // 2025-06-27: IME: avoid calling SDL_StartTextInput() again if already active. (#8727) // 2025-04-22: IME: honor ImGuiPlatformImeData->WantTextInput as an alternative way to call SDL_StartTextInput(), without IME being necessarily visible. @@ -590,6 +591,7 @@ void ImGui_ImplSDL3_Shutdown() ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); if (bd->ClipboardTextData) SDL_free(bd->ClipboardTextData); @@ -600,6 +602,7 @@ void ImGui_ImplSDL3_Shutdown() io.BackendPlatformName = nullptr; io.BackendPlatformUserData = nullptr; io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad); + platform_io.ClearPlatformHandlers(); IM_DELETE(bd); } diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index 0f8d5fa1a..3afbf3db6 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -22,6 +22,7 @@ // Calling the function is MANDATORY, otherwise the ImGui will not upload neither the vertex nor the index buffer for the GPU. See imgui_impl_sdlgpu3.cpp for more info. // CHANGELOG +// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-08-20: Added ImGui_ImplSDLGPU3_InitInfo::SwapchainComposition and ImGui_ImplSDLGPU3_InitInfo::PresentMode to configure how secondary viewports are created. // 2025-08-08: *BREAKING* Changed ImTextureID type from SDL_GPUTextureSamplerBinding* to SDL_GPUTexture*, which is more natural and easier for user to manage. If you need to change the current sampler, you can access the ImGui_ImplSDLGPU3_RenderState struct. (#8866, #8163, #7998, #7988) // 2025-08-08: Expose SamplerDefault and SamplerCurrent in ImGui_ImplSDLGPU3_RenderState. Allow callback to change sampler. @@ -641,11 +642,14 @@ void ImGui_ImplSDLGPU3_Shutdown() ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGui_ImplSDLGPU3_DestroyDeviceObjects(); + io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); + platform_io.ClearRendererHandlers(); IM_DELETE(bd); } diff --git a/backends/imgui_impl_sdlrenderer2.cpp b/backends/imgui_impl_sdlrenderer2.cpp index 3a47f80bf..fa1e802b1 100644 --- a/backends/imgui_impl_sdlrenderer2.cpp +++ b/backends/imgui_impl_sdlrenderer2.cpp @@ -24,6 +24,7 @@ // - Introduction, links and more at the top of imgui.cpp // CHANGELOG +// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplSDLRenderer2_CreateFontsTexture() and ImGui_ImplSDLRenderer2_DestroyFontsTexture(). // 2025-01-18: Use endian-dependent RGBA32 texture format, to match SDL_Color. // 2024-10-09: Expose selected render state in ImGui_ImplSDLRenderer2_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. @@ -94,12 +95,14 @@ void ImGui_ImplSDLRenderer2_Shutdown() ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData(); IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGui_ImplSDLRenderer2_DestroyDeviceObjects(); io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); + platform_io.ClearRendererHandlers(); IM_DELETE(bd); } diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index 42c173888..abf636b8d 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -24,6 +24,7 @@ // - Introduction, links and more at the top of imgui.cpp // CHANGELOG +// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplSDLRenderer3_CreateFontsTexture() and ImGui_ImplSDLRenderer3_DestroyFontsTexture(). // 2025-01-18: Use endian-dependent RGBA32 texture format, to match SDL_Color. // 2024-10-09: Expose selected render state in ImGui_ImplSDLRenderer3_RenderState, which you can access in 'void* platform_io.Renderer_RenderState' during draw callbacks. @@ -92,12 +93,14 @@ void ImGui_ImplSDLRenderer3_Shutdown() ImGui_ImplSDLRenderer3_Data* bd = ImGui_ImplSDLRenderer3_GetBackendData(); IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGui_ImplSDLRenderer3_DestroyDeviceObjects(); io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); + platform_io.ClearRendererHandlers(); IM_DELETE(bd); } diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index e56902254..4a0a5a947 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-18: Call platform_io.ClearRendererHandlers() on shutdown. // 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) @@ -1315,12 +1316,14 @@ void ImGui_ImplVulkan_Shutdown() ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGui_ImplVulkan_DestroyDeviceObjects(); io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); + platform_io.ClearRendererHandlers(); IM_DELETE(bd); } diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index d20028d55..1f997a10a 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -18,6 +18,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-06-12: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. (#8465) // 2025-02-26: Recreate image bind groups during render. (#8426, #8046, #7765, #8027) + Update for latest webgpu-native changes. // 2024-10-14: Update Dawn support for change of string usages. (#8082, #8083) @@ -880,6 +881,7 @@ void ImGui_ImplWGPU_Shutdown() ImGui_ImplWGPU_Data* bd = ImGui_ImplWGPU_GetBackendData(); IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); ImGui_ImplWGPU_InvalidateDeviceObjects(); delete[] bd->pFrameResources; @@ -892,6 +894,7 @@ void ImGui_ImplWGPU_Shutdown() io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures); + platform_io.ClearRendererHandlers(); IM_DELETE(bd); } diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index d7206b970..20dce139e 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown. // 2025-04-30: Inputs: Fixed an issue where externally losing mouse capture (due to e.g. focus loss) would fail to claim it again the next subsequent click. (#8594) // 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) // 2025-02-18: Added ImGuiMouseCursor_Wait and ImGuiMouseCursor_Progress mouse cursor support. @@ -222,6 +223,7 @@ void ImGui_ImplWin32_Shutdown() ImGui_ImplWin32_Data* bd = ImGui_ImplWin32_GetBackendData(); IM_ASSERT(bd != nullptr && "No platform backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); // Unload XInput library #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD @@ -232,6 +234,7 @@ void ImGui_ImplWin32_Shutdown() io.BackendPlatformName = nullptr; io.BackendPlatformUserData = nullptr; io.BackendFlags &= ~(ImGuiBackendFlags_HasMouseCursors | ImGuiBackendFlags_HasSetMousePos | ImGuiBackendFlags_HasGamepad); + platform_io.ClearPlatformHandlers(); IM_DELETE(bd); } diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f7ae7c991..ebb60f9a9 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,12 @@ Breaking Changes: Other Changes: +- IO: added ImGuiPlatformIO::ClearPlatformHandlers(), ClearRendererHandlers() + helpers to null all handlers. (#8945, #2769) +- Backends: all backends call ImGuiPlatformIO::ClearPlatformHandlers() and + ClearRendererHandlers() on shutdown, so as not to leave function pointers + which may be dangling when using backend in e.g. DLL. (#8945, #2769) + ----------------------------------------------------------------------- VERSION 1.92.3 (Released 2025-09-17) diff --git a/imgui.cpp b/imgui.cpp index 29774fe37..0c61f9ee1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -15453,6 +15453,23 @@ void ImGui::LocalizeRegisterEntries(const ImGuiLocEntry* entries, int count) // (this section is more complete in the 'docking' branch) //----------------------------------------------------------------------------- +void ImGuiPlatformIO::ClearPlatformHandlers() +{ + Platform_GetClipboardTextFn = NULL; + Platform_SetClipboardTextFn = NULL; + Platform_ClipboardUserData = NULL; + Platform_OpenInShellFn = NULL; + Platform_OpenInShellUserData = NULL; + Platform_SetImeDataFn = NULL; + Platform_ImeUserData = NULL; +} + +void ImGuiPlatformIO::ClearRendererHandlers() +{ + Renderer_TextureMaxWidth = Renderer_TextureMaxHeight = 0; + Renderer_RenderState = NULL; +} + ImGuiViewport* ImGui::GetMainViewport() { ImGuiContext& g = *GImGui; diff --git a/imgui.h b/imgui.h index d79a912bf..682364004 100644 --- a/imgui.h +++ b/imgui.h @@ -3970,6 +3970,13 @@ struct ImGuiPlatformIO // Textures list (the list is updated by calling ImGui::EndFrame or ImGui::Render) // The ImGui_ImplXXXX_RenderDrawData() function of each backend generally access this via ImDrawData::Textures which points to this. The array is available here mostly because backends will want to destroy textures on shutdown. ImVector Textures; // List of textures used by Dear ImGui (most often 1) + contents of external texture list is automatically appended into this. + + //------------------------------------------------------------------ + // Functions + //------------------------------------------------------------------ + + void ClearPlatformHandlers(); // Clear all Platform_XXX fields. Typically called on Platform Backend shutdown. + void ClearRendererHandlers(); // Clear all Renderer_XXX fields. Typically called on Renderer Backend shutdown. }; // (Optional) Support for IME (Input Method Editor) via the platform_io.Platform_SetImeDataFn() function. Handler is called during EndFrame(). From 087fbf08f600d061de7531a14c496145262e7319 Mon Sep 17 00:00:00 2001 From: David Mentler Date: Mon, 22 Sep 2025 12:20:15 +0200 Subject: [PATCH 02/14] Added type formatters for the LLDB debuggers (e.g. Xcode) (#8950) --- misc/debuggers/README.txt | 4 + misc/debuggers/imgui_lldb.py | 187 +++++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) create mode 100644 misc/debuggers/imgui_lldb.py diff --git a/misc/debuggers/README.txt b/misc/debuggers/README.txt index 3f4ba83e3..77a78b9e5 100644 --- a/misc/debuggers/README.txt +++ b/misc/debuggers/README.txt @@ -14,3 +14,7 @@ imgui.natvis With this, types like ImVector<> will be displayed nicely in the debugger. (read comments inside file for details) +imgui_lldb.py + LLDB: synthetic children provider and summaries for Dear ImGui types. + With this, types like ImVector<> will be displayed nicely in the debugger. + (read comments inside file for details) diff --git a/misc/debuggers/imgui_lldb.py b/misc/debuggers/imgui_lldb.py new file mode 100644 index 000000000..336d3f513 --- /dev/null +++ b/misc/debuggers/imgui_lldb.py @@ -0,0 +1,187 @@ +# This file implements synthetic children providers and summaries for various ImGui types for LLDB. +# +# Useful links/documentation related to the feature: +# - https://lldb.llvm.org/use/variable.html#summary-strings +# - https://lldb.llvm.org/use/variable.html#synthetic-children +# - https://lldb.llvm.org/python_reference/lldb-module.html +# +# To use it in a debug session: +# > (lldb) command script import +# +# Alternatively you may include the above command in your ~/.lldbinit file to have the formatters +# available in all future sessions + +import lldb + +class ArraySynthBase(object): + """ + Helper baseclass aimed to reduce the boilerplate needed for "array-like" containers + """ + + def __init__(self, valobj, internal_dict): + self.valobj = valobj + + def bind_to(self, pointer, size): + array_p = pointer.GetType().GetPointeeType().GetArrayType(size).GetPointerType() + self.array = pointer.Cast(array_p).Dereference() + + def update(self): + self.array = self.valobj + + def num_children(self, max_children): + return self.array.GetNumChildren(max_children) + + def get_child_index(self, name): + return self.array.GetIndexOfChildWithName(name) + + def get_child_at_index(self, index): + return self.array.GetChildAtIndex(index) + + def has_children(self): + return self.array.MightHaveChildren() + + def get_value(self): + return self.array + +class ImVectorSynth(ArraySynthBase): + def update(self): + self.size = self.valobj.GetChildMemberWithName("Size").GetValueAsUnsigned() + self.capacity = self.valobj.GetChildMemberWithName("Capacity").GetValueAsUnsigned() + + data = self.valobj.GetChildMemberWithName("Data") + + self.bind_to(data, self.size) + + def get_summary(self): + return f"Size={self.size} Capacity={self.capacity}" + +class ImSpanSynth(ArraySynthBase): + def update(self): + data = self.valobj.GetChildMemberWithName("Data") + end = self.valobj.GetChildMemberWithName("DataEnd") + + element_size = data.GetType().GetPointeeType().GetByteSize() + array_size = end.GetValueAsUnsigned() - data.GetValueAsUnsigned() + + self.size = int(array_size / element_size) + + self.bind_to(data, self.size) + + def get_summary(self): + return f"Size={self.size}" + +class ImRectSummary(object): + def __init__(self, valobj, internal_dict): + self.valobj = valobj + + def update(self): + pass + + def get_summary(self): + min = self.valobj.GetChildMemberWithName("Min") + max = self.valobj.GetChildMemberWithName("Max") + + minX = float(min.GetChildMemberWithName("x").GetValue()) + minY = float(min.GetChildMemberWithName("y").GetValue()) + + maxX = float(max.GetChildMemberWithName("x").GetValue()) + maxY = float(max.GetChildMemberWithName("y").GetValue()) + + return f"Min=({minX}, {minY}) Max=({maxX}, {maxY}) Size=({maxX - minX}, {maxY - minY})" + +def get_active_enum_flags(valobj): + flag_set = set() + + enum_name = valobj.GetType().GetName() + "_" + enum_type = valobj.GetTarget().FindFirstType(enum_name) + + if not enum_type.IsValid(): + return flag_set + + enum_members = enum_type.GetEnumMembers() + value = valobj.GetValueAsUnsigned() + + for i in range(0, enum_members.GetSize()): + member = enum_members.GetTypeEnumMemberAtIndex(i) + + if value & member.GetValueAsUnsigned(): + flag_set.add(member.GetName().removeprefix(enum_name)) + + return flag_set + +class ImGuiWindowSummary(object): + def __init__(self, valobj, internal_dict): + self.valobj = valobj + + def update(self): + pass + + def get_summary(self): + name = self.valobj.GetChildMemberWithName("Name").GetSummary() + + active = self.valobj.GetChildMemberWithName("Active").GetValueAsUnsigned() != 0 + was_active = self.valobj.GetChildMemberWithName("WasActive").GetValueAsUnsigned() != 0 + hidden = self.valobj.GetChildMemberWithName("Hidden") != 0 + + flags = get_active_enum_flags(self.valobj.GetChildMemberWithName("Flags")) + + active = 1 if active or was_active else 0 + child = 1 if "ChildWindow" in flags else 0 + popup = 1 if "Popup" in flags else 0 + hidden = 1 if hidden else 0 + + return f"Name {name} Active {active} Child {child} Popup {popup} Hidden {hidden}" + + +def __lldb_init_module(debugger, internal_dict): + """ + This function will be automatically called by LLDB when the module is loaded, here + we register the various synthetics/summaries we have build before + """ + + category_name = "imgui" + category = debugger.GetCategory(category_name) + + # Make sure we don't accidentally keep accumulating languages or override the user's + # category enablement in Xcode, where lldb-rpc-server loads this file once for eac + # debugging session + if not category.IsValid(): + category = debugger.CreateCategory(category_name) + category.AddLanguage(lldb.eLanguageTypeC_plus_plus) + category.SetEnabled(True) + + def add_summary(typename, impl): + summary = None + + if isinstance(impl, str): + summary = lldb.SBTypeSummary.CreateWithSummaryString(impl) + summary.SetOptions(lldb.eTypeOptionCascade) + else: + # Unfortunately programmatic summary string generation is an entirely different codepath + # in LLDB. Register a convenient trampoline function which makes it look like it's part + # of the SyntheticChildrenProvider contract + summary = lldb.SBTypeSummary.CreateWithScriptCode(f''' + synth = {impl.__module__}.{impl.__qualname__}(valobj.GetNonSyntheticValue(), internal_dict) + synth.update() + + return synth.get_summary() + ''') + summary.SetOptions(lldb.eTypeOptionCascade | lldb.eTypeOptionFrontEndWantsDereference) + + category.AddTypeSummary(lldb.SBTypeNameSpecifier(typename, True), summary) + + def add_synthetic(typename, impl): + add_summary(typename, impl) + + synthetic = lldb.SBTypeSynthetic.CreateWithClassName(f"{impl.__module__}.{impl.__qualname__}") + synthetic.SetOptions(lldb.eTypeOptionCascade | lldb.eTypeOptionFrontEndWantsDereference) + + category.AddTypeSynthetic(lldb.SBTypeNameSpecifier(typename, True), synthetic) + + add_synthetic("^ImVector<.+>$", ImVectorSynth) + add_synthetic("^ImSpan<.+>$", ImSpanSynth) + + add_summary("^ImVec2$", "x=${var.x} y=${var.y}") + add_summary("^ImVec4$", "x=${var.x} y=${var.y} z=${var.z} w=${var.w}") + add_summary("^ImRect$", ImRectSummary) + add_summary("^ImGuiWindow$", ImGuiWindowSummary) From 46e6382b69e30fe85b8e77bac6c4e5604b6195d1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 22 Sep 2025 12:26:53 +0200 Subject: [PATCH 03/14] Added type formatters for the LLDB debuggers (e.g. Xcode, Android Studio) (#8950) --- docs/CHANGELOG.txt | 3 +++ misc/README.txt | 4 ++-- misc/debuggers/README.txt | 3 ++- misc/debuggers/imgui_lldb.py | 4 +++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ebb60f9a9..344d5e228 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -45,6 +45,9 @@ Other Changes: - IO: added ImGuiPlatformIO::ClearPlatformHandlers(), ClearRendererHandlers() helpers to null all handlers. (#8945, #2769) +- Misc: Debuggers: added type formatters for the LLDB debuggers (e.g. Xcode, + Android Studio & more) to provide nicer display for ImVec2, ImVec4, ImVector etc. + See misc/debuggers/ for details. (#8950) [@mentlerd] - Backends: all backends call ImGuiPlatformIO::ClearPlatformHandlers() and ClearRendererHandlers() on shutdown, so as not to leave function pointers which may be dangling when using backend in e.g. DLL. (#8945, #2769) diff --git a/misc/README.txt b/misc/README.txt index b4ce89f03..58c00ee8c 100644 --- a/misc/README.txt +++ b/misc/README.txt @@ -4,8 +4,8 @@ misc/cpp/ This is also an example of how you may wrap your own similar types. misc/debuggers/ - Helper files for popular debuggers. - With the .natvis file, types like ImVector<> will be displayed nicely in Visual Studio debugger. + Helper files for popular debuggers (Visual Studio, GDB, LLDB). + e.g. With the .natvis file, types like ImVector<> will be displayed nicely in Visual Studio debugger. misc/fonts/ Fonts loading/merging instructions (e.g. How to handle glyph ranges, how to merge icons fonts). diff --git a/misc/debuggers/README.txt b/misc/debuggers/README.txt index 77a78b9e5..ad6f491fe 100644 --- a/misc/debuggers/README.txt +++ b/misc/debuggers/README.txt @@ -15,6 +15,7 @@ imgui.natvis (read comments inside file for details) imgui_lldb.py - LLDB: synthetic children provider and summaries for Dear ImGui types. + LLDB-based debuggers (*): synthetic children provider and summaries for Dear ImGui types. With this, types like ImVector<> will be displayed nicely in the debugger. (read comments inside file for details) + (*) Xcode, Android Studio, may be used from VS Code, C++Builder, CLion, Eclipse etc. diff --git a/misc/debuggers/imgui_lldb.py b/misc/debuggers/imgui_lldb.py index 336d3f513..7d3c6bfcb 100644 --- a/misc/debuggers/imgui_lldb.py +++ b/misc/debuggers/imgui_lldb.py @@ -1,4 +1,6 @@ -# This file implements synthetic children providers and summaries for various ImGui types for LLDB. +# This file implements synthetic children providers and summaries for various Dear ImGui types for LLDB. +# LLDB is used by Xcode, Android Studio, and may be used from VS Code, C++Builder, CLion, Eclipse etc. + # # Useful links/documentation related to the feature: # - https://lldb.llvm.org/use/variable.html#summary-strings From ef6fe2ecee61c4da1c57f31a585a8cc27909ee76 Mon Sep 17 00:00:00 2001 From: yaz0r <363511+yaz0r@users.noreply.github.com> Date: Sat, 20 Sep 2025 10:48:54 -0700 Subject: [PATCH 04/14] CI: update Windows Vulkan scripts. (#8925) --- .github/workflows/build.yml | 17 ++-------- .../workflows/build_windows_vulkan_libs.ps1 | 33 +++++++++++++++++++ .../workflows/build_windows_vulkan_libs.yml | 22 +++++++++++++ 3 files changed, 58 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/build_windows_vulkan_libs.ps1 create mode 100644 .github/workflows/build_windows_vulkan_libs.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 783615aec..1c578b76b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,20 +35,9 @@ jobs: Expand-Archive -Path SDL3-devel-3.2.18-VC.zip echo "SDL3_DIR=$(pwd)\SDL3-devel-3.2.18-VC\SDL3-3.2.18\" >>${env:GITHUB_ENV} - # VulkanSDK (retrieve minimal bits of the SDK from git) - $vulkanVersion = "1.4.326" - # 1. Get the vulkan headers, we will treat that folder as the sdk folder to avoid having to copy headers around - Invoke-WebRequest -Uri "https://github.com/KhronosGroup/Vulkan-Headers/archive/refs/tags/v$($vulkanVersion).zip" -OutFile Vulkan-Headers-$($vulkanVersion).zip - Expand-Archive -Path Vulkan-Headers-$($vulkanVersion).zip - echo "VULKAN_SDK=$(pwd)\Vulkan-Headers-$($vulkanVersion)\Vulkan-Headers-$($vulkanVersion)" >>${env:GITHUB_ENV} - # 2. Get and build the vulkan loader source code (UPDATE_DEPS=On will make it automatically fetch its dependencies) - Invoke-WebRequest -Uri "https://github.com/KhronosGroup/Vulkan-Loader/archive/refs/tags/v$($vulkanVersion).zip" -OutFile Vulkan-Loader-$($vulkanVersion).zip - Expand-Archive -Path Vulkan-Loader-$($vulkanVersion).zip - cmake -S Vulkan-Loader-$($vulkanVersion)\Vulkan-Loader-$($vulkanVersion) -B VulkanLoader-build -D UPDATE_DEPS=On - cmake --build VulkanLoader-build - # 3. Copy the built lib/dll to the expected place - mkdir Vulkan-Headers-$($vulkanVersion)\Vulkan-Headers-$($vulkanVersion)\Lib - copy VulkanLoader-build\loader\Debug\vulkan-1.* Vulkan-Headers-$($vulkanVersion)\Vulkan-Headers-$($vulkanVersion)\Lib\ + Invoke-WebRequest -Uri "https://github.com/ocornut/imgui/files/3789205/vulkan-sdk-1.1.121.2.zip" -OutFile vulkan-sdk-1.1.121.2.zip + Expand-Archive -Path vulkan-sdk-1.1.121.2.zip + echo "VULKAN_SDK=$(pwd)\vulkan-sdk-1.1.121.2\" >>${env:GITHUB_ENV} - name: Fix Projects shell: powershell diff --git a/.github/workflows/build_windows_vulkan_libs.ps1 b/.github/workflows/build_windows_vulkan_libs.ps1 new file mode 100644 index 000000000..57e542372 --- /dev/null +++ b/.github/workflows/build_windows_vulkan_libs.ps1 @@ -0,0 +1,33 @@ +# Set default vulkan version if none provided +if (-not $env:VULKAN_TAG) { $env:VULKAN_TAG = "1.4.326" } + +# Create output folder +mkdir vulkanArtifact + +# Download Vulkan Headers + +Invoke-WebRequest -Uri "https://github.com/KhronosGroup/Vulkan-Headers/archive/refs/tags/v$($env:VULKAN_TAG).zip" -OutFile Vulkan-Headers-$($env:VULKAN_TAG).zip +Expand-Archive -Path Vulkan-Headers-$($env:VULKAN_TAG).zip + +# Copy Vulkan Headers to artifact folder + +cp -R Vulkan-Headers-$($env:VULKAN_TAG)\Vulkan-Headers-$($env:VULKAN_TAG)\include vulkanArtifact\Include + +# Download Vulkan Loader + +Invoke-WebRequest -Uri "https://github.com/KhronosGroup/Vulkan-Loader/archive/refs/tags/v$($env:VULKAN_TAG).zip" -OutFile Vulkan-Loader-$($env:VULKAN_TAG).zip +Expand-Archive -Path Vulkan-Loader-$($env:VULKAN_TAG).zip + +# Build Vulkan Loader x64 + +cmake -S Vulkan-Loader-$($env:VULKAN_TAG)\Vulkan-Loader-$($env:VULKAN_TAG) -B VulkanLoader-build64 -D UPDATE_DEPS=On -A x64 +cmake --build VulkanLoader-build64 +mkdir vulkanArtifact\Lib +copy VulkanLoader-build64\loader\Debug\vulkan-1.lib vulkanArtifact\Lib + +# Build Vulkan Loader win32 + +cmake -S Vulkan-Loader-$($env:VULKAN_TAG)\Vulkan-Loader-$($env:VULKAN_TAG) -B VulkanLoader-build32 -D UPDATE_DEPS=On -A Win32 +cmake --build VulkanLoader-build32 +mkdir vulkanArtifact\Lib32 +copy VulkanLoader-build32\loader\Debug\vulkan-1.lib vulkanArtifact\Lib32 diff --git a/.github/workflows/build_windows_vulkan_libs.yml b/.github/workflows/build_windows_vulkan_libs.yml new file mode 100644 index 000000000..beaa2ff0a --- /dev/null +++ b/.github/workflows/build_windows_vulkan_libs.yml @@ -0,0 +1,22 @@ +name: build-windows-vulkan-libs + +on: workflow_dispatch + +jobs: + Windows: + runs-on: windows-2025 + env: + VULKAN_TAG: 1.4.326 + steps: + - uses: actions/checkout@v4 + + - name: Build Vulkan libs + shell: powershell + run: .github/workflows/build_windows_vulkan_libs.ps1 + + - uses: actions/upload-artifact@v4 + with: + name: vulkan_windows_libs_${{ env.VULKAN_TAG }} + path: vulkanArtifact + overwrite: 'true' + From dc0198a7e475fb2c1d6a8aac386aa8b0d73794f4 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 22 Sep 2025 12:44:49 +0200 Subject: [PATCH 05/14] CI: update Windows Vulkan scripts. Amends. (#8925) --- .github/workflows/build.yml | 8 ++++--- .../workflows/build_windows_vulkan_libs.ps1 | 5 +++++ .../workflows/build_windows_vulkan_libs.yml | 22 ------------------- docs/CHANGELOG.txt | 1 + 4 files changed, 11 insertions(+), 25 deletions(-) delete mode 100644 .github/workflows/build_windows_vulkan_libs.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1c578b76b..92d41dac1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,6 +24,8 @@ jobs: steps: - uses: actions/checkout@v4 + # The VulkanSDK libs for Windows is manually generated using build_windows_vulkan_libs.ps1 + attached to issue #8925. + # (we have a .yml workflow in commit history if it becomes ever useful to create this on CI too) - name: Install Dependencies shell: powershell run: | @@ -35,9 +37,9 @@ jobs: Expand-Archive -Path SDL3-devel-3.2.18-VC.zip echo "SDL3_DIR=$(pwd)\SDL3-devel-3.2.18-VC\SDL3-3.2.18\" >>${env:GITHUB_ENV} - Invoke-WebRequest -Uri "https://github.com/ocornut/imgui/files/3789205/vulkan-sdk-1.1.121.2.zip" -OutFile vulkan-sdk-1.1.121.2.zip - Expand-Archive -Path vulkan-sdk-1.1.121.2.zip - echo "VULKAN_SDK=$(pwd)\vulkan-sdk-1.1.121.2\" >>${env:GITHUB_ENV} + Invoke-WebRequest -Uri "https://github.com/user-attachments/files/22464296/vulkan_windows_libs_1.4.326.zip" -OutFile vulkan_windows_libs_1.4.326.zip + Expand-Archive -Path vulkan_windows_libs_1.4.326.zip + echo "VULKAN_SDK=$(pwd)\vulkan_windows_libs_1.4.326\" >>${env:GITHUB_ENV} - name: Fix Projects shell: powershell diff --git a/.github/workflows/build_windows_vulkan_libs.ps1 b/.github/workflows/build_windows_vulkan_libs.ps1 index 57e542372..6658f5b5b 100644 --- a/.github/workflows/build_windows_vulkan_libs.ps1 +++ b/.github/workflows/build_windows_vulkan_libs.ps1 @@ -1,3 +1,8 @@ +# This is current meant to be run manually, occasionally: +# - Run then zip the contents of vulkanArtifact/ into e.g. vulkan_windows_libs_1.4.326 +# - Upload as an attachment to https://github.com/ocornut/imgui/pull/8925 then change filename in build.yml +# - There is a build_windows_vulkan_libs.yml in commit history that we removed thinking this is run so rarely we don't need to pollute CI UI with it. + # Set default vulkan version if none provided if (-not $env:VULKAN_TAG) { $env:VULKAN_TAG = "1.4.326" } diff --git a/.github/workflows/build_windows_vulkan_libs.yml b/.github/workflows/build_windows_vulkan_libs.yml deleted file mode 100644 index beaa2ff0a..000000000 --- a/.github/workflows/build_windows_vulkan_libs.yml +++ /dev/null @@ -1,22 +0,0 @@ -name: build-windows-vulkan-libs - -on: workflow_dispatch - -jobs: - Windows: - runs-on: windows-2025 - env: - VULKAN_TAG: 1.4.326 - steps: - - uses: actions/checkout@v4 - - - name: Build Vulkan libs - shell: powershell - run: .github/workflows/build_windows_vulkan_libs.ps1 - - - uses: actions/upload-artifact@v4 - with: - name: vulkan_windows_libs_${{ env.VULKAN_TAG }} - path: vulkanArtifact - overwrite: 'true' - diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 344d5e228..636110ba2 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -48,6 +48,7 @@ Other Changes: - Misc: Debuggers: added type formatters for the LLDB debuggers (e.g. Xcode, Android Studio & more) to provide nicer display for ImVec2, ImVec4, ImVector etc. See misc/debuggers/ for details. (#8950) [@mentlerd] +- CI: Updates Windows CI scripts to generate/use VulkanSDK. (#8925, #8778) [@yaz0r] - Backends: all backends call ImGuiPlatformIO::ClearPlatformHandlers() and ClearRendererHandlers() on shutdown, so as not to leave function pointers which may be dangling when using backend in e.g. DLL. (#8945, #2769) From 301e652376b6bb20cfc8aedaa1e6d0ca8afe7bd9 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 22 Sep 2025 16:04:59 +0200 Subject: [PATCH 06/14] Backends: OpenGL3: fixed GL loader to work on Haiku OS which does not support. (#8952) --- backends/imgui_impl_opengl3_loader.h | 4 ++++ docs/CHANGELOG.txt | 2 ++ 2 files changed, 6 insertions(+) diff --git a/backends/imgui_impl_opengl3_loader.h b/backends/imgui_impl_opengl3_loader.h index a69ac89d7..2c80cc598 100644 --- a/backends/imgui_impl_opengl3_loader.h +++ b/backends/imgui_impl_opengl3_loader.h @@ -714,7 +714,11 @@ static void close_libgl(void) static int is_library_loaded(const char* name, void** lib) { +#if defined(__HAIKU__) + *lib = NULL; // no support for RTLD_NOLOAD on Haiku. +#else *lib = dlopen(name, RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); +#endif return *lib != NULL; } diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 636110ba2..c6b65dd2f 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -52,6 +52,8 @@ Other Changes: - Backends: all backends call ImGuiPlatformIO::ClearPlatformHandlers() and ClearRendererHandlers() on shutdown, so as not to leave function pointers which may be dangling when using backend in e.g. DLL. (#8945, #2769) +- Backends: OpenGL3: fixed GL loader to work on Haiku OS which does not support + `RTLD_NOLOAD`. (#8952) [@Xottab-DUTY] ----------------------------------------------------------------------- From 8868ad67e4fa45c21c9db2e7b9abd6e5a1849b7e Mon Sep 17 00:00:00 2001 From: Brenton Bostick Date: Mon, 22 Sep 2025 10:09:44 -0400 Subject: [PATCH 07/14] Fixed typos. (#8955) --- imgui.cpp | 2 +- imgui_draw.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 0c61f9ee1..93a77ec25 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3814,7 +3814,7 @@ void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, cons // Another overly complex function until we reorganize everything into a nice all-in-one helper. // This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) from 'ellipsis_max_x' which may be beyond it. // This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move. -// (BREAKING) On 2025/04/16 we removed the 'float clip_max_x' parameters which was preceeding 'float ellipsis_max' and was the same value for 99% of users. +// (BREAKING) On 2025/04/16 we removed the 'float clip_max_x' parameters which was preceding 'float ellipsis_max' and was the same value for 99% of users. void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known) { ImGuiContext& g = *GImGui; diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 3beb3aa80..0946d7a46 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -5598,7 +5598,7 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, const ImVec2& pos, Im } // Note: as with every ImDrawList drawing function, this expects that the font atlas texture is bound. -// DO NOT CALL DIRECTLY THIS WILL CHANGE WIDLY IN 2025-2025. Use ImDrawList::AddText(). +// DO NOT CALL DIRECTLY THIS WILL CHANGE WILDLY IN 2025-2025. Use ImDrawList::AddText(). void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, ImDrawTextFlags flags) { // Align to be pixel perfect From a00e517a8109030e13fc911abc9ebeb026c3ef2c Mon Sep 17 00:00:00 2001 From: Tomas Jakobsson Date: Mon, 22 Sep 2025 18:55:35 +0200 Subject: [PATCH 08/14] Examples: added SDL3+DirectX11 example. (#8956, #8957) --- .../example_sdl3_directx11/build_win32.bat | 8 + .../example_sdl3_directx11.vcxproj | 187 +++++++++++++ .../example_sdl3_directx11.vcxproj.filters | 63 +++++ examples/example_sdl3_directx11/main.cpp | 253 ++++++++++++++++++ examples/imgui_examples.sln | 10 + 5 files changed, 521 insertions(+) create mode 100644 examples/example_sdl3_directx11/build_win32.bat create mode 100644 examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj create mode 100644 examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj.filters create mode 100644 examples/example_sdl3_directx11/main.cpp diff --git a/examples/example_sdl3_directx11/build_win32.bat b/examples/example_sdl3_directx11/build_win32.bat new file mode 100644 index 000000000..b84b01f1a --- /dev/null +++ b/examples/example_sdl3_directx11/build_win32.bat @@ -0,0 +1,8 @@ +@REM Build for Visual Studio compiler. Run your copy of vcvars32.bat or vcvarsall.bat to setup command-line compiler. +@set OUT_DIR=Debug +@set OUT_EXE=example_sdl3_directx11 +@set INCLUDES=/I..\.. /I..\..\backends /I%SDL3_DIR%\include /I "%WindowsSdkDir%Include\um" /I "%WindowsSdkDir%Include\shared" /I "%DXSDK_DIR%Include" +@set SOURCES=main.cpp ..\..\backends\imgui_impl_sdl3.cpp ..\..\backends\imgui_impl_dx11.cpp ..\..\imgui*.cpp +@set LIBS=/LIBPATH:%SDL3_DIR%\lib\x86 SDL3.lib /LIBPATH:"%DXSDK_DIR%/Lib/x86" d3d11.lib d3dcompiler.lib shell32.lib +mkdir %OUT_DIR% +cl /nologo /Zi /MD /utf-8 %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console diff --git a/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj b/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj new file mode 100644 index 000000000..340901c3d --- /dev/null +++ b/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj @@ -0,0 +1,187 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {009DAC16-1A9C-47BE-9770-A30A046E8090} + example_sdl3_directx11 + 8.1 + example_sdl3_directx11 + + + + Application + true + MultiByte + v140 + + + Application + true + MultiByte + v140 + + + Application + false + true + MultiByte + v140 + + + Application + false + true + MultiByte + v140 + + + + + + + + + + + + + + + + + + + $(ProjectDir)$(Configuration)\ + $(ProjectDir)$(Configuration)\ + $(IncludePath) + + + $(ProjectDir)$(Configuration)\ + $(ProjectDir)$(Configuration)\ + $(IncludePath) + + + $(ProjectDir)$(Configuration)\ + $(ProjectDir)$(Configuration)\ + $(IncludePath) + + + $(ProjectDir)$(Configuration)\ + $(ProjectDir)$(Configuration)\ + $(IncludePath) + + + + Level4 + Disabled + ..\..;..\..\backends;%SDL3_DIR%\include;$(VcpkgCurrentInstalledDir)include;%(AdditionalIncludeDirectories) + /utf-8 %(AdditionalOptions) + + + true + %SDL3_DIR%\lib\x86;$(DXSDK_DIR)/Lib/x86;%(AdditionalLibraryDirectories) + SDL3.lib;d3d11.lib;d3dcompiler.lib;dxgi.lib;%(AdditionalDependencies) + Console + msvcrt.lib + + + + + Level4 + Disabled + ..\..;..\..\backends;%SDL3_DIR%\include;$(VcpkgCurrentInstalledDir)include;%(AdditionalIncludeDirectories) + /utf-8 %(AdditionalOptions) + + + true + %SDL3_DIR%\lib\x64;$(DXSDK_DIR)/Lib/x64;%(AdditionalLibraryDirectories) + SDL3.lib;d3d11.lib;d3dcompiler.lib;dxgi.lib;%(AdditionalDependencies) + Console + msvcrt.lib + + + + + Level4 + MaxSpeed + true + true + ..\..;..\..\backends;%SDL3_DIR%\include;$(VcpkgCurrentInstalledDir)include;%(AdditionalIncludeDirectories) + false + /utf-8 %(AdditionalOptions) + + + true + true + true + %SDL3_DIR%\lib\x86;$(DXSDK_DIR)/Lib/x86;%(AdditionalLibraryDirectories) + SDL3.lib;d3d11.lib;d3dcompiler.lib;dxgi.lib;%(AdditionalDependencies) + Console + + + + + + + Level4 + MaxSpeed + true + true + ..\..;..\..\backends;%SDL3_DIR%\include;$(VcpkgCurrentInstalledDir)include;%(AdditionalIncludeDirectories) + false + /utf-8 %(AdditionalOptions) + + + true + true + true + %SDL3_DIR%\lib\x64;$(DXSDK_DIR)/Lib/x64;%(AdditionalLibraryDirectories) + SDL3.lib;d3d11.lib;d3dcompiler.lib;dxgi.lib;%(AdditionalDependencies) + Console + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj.filters b/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj.filters new file mode 100644 index 000000000..0579b7a64 --- /dev/null +++ b/examples/example_sdl3_directx11/example_sdl3_directx11.vcxproj.filters @@ -0,0 +1,63 @@ + + + + + {0587d7a3-f2ce-4d56-b84f-a0005d3bfce6} + + + {08e36723-ce4f-4cff-9662-c40801cf1acf} + + + + + imgui + + + imgui + + + imgui + + + sources + + + sources + + + + + imgui + + + sources + + + imgui + + + imgui + + + imgui + + + imgui + + + sources + + + sources + + + + + + imgui + + + imgui + + + \ No newline at end of file diff --git a/examples/example_sdl3_directx11/main.cpp b/examples/example_sdl3_directx11/main.cpp new file mode 100644 index 000000000..a604e3076 --- /dev/null +++ b/examples/example_sdl3_directx11/main.cpp @@ -0,0 +1,253 @@ +// Dear ImGui: standalone example application for SDL3 + DirectX 11 +// (SDL is a cross-platform general purpose library for handling windows, inputs, OpenGL/Vulkan/Metal graphics context creation, etc.) + +// Learn about Dear ImGui: +// - FAQ https://dearimgui.com/faq +// - Getting Started https://dearimgui.com/getting-started +// - Documentation https://dearimgui.com/docs (same as your local docs/ folder). +// - Introduction, links and more at the top of imgui.cpp + +#include "imgui.h" +#include "imgui_impl_sdl3.h" +#include "imgui_impl_dx11.h" +#include +#include +#include + +// Data +static ID3D11Device* g_pd3dDevice = nullptr; +static ID3D11DeviceContext* g_pd3dDeviceContext = nullptr; +static IDXGISwapChain* g_pSwapChain = nullptr; +static ID3D11RenderTargetView* g_mainRenderTargetView = nullptr; + +// Forward declarations of helper functions +bool CreateDeviceD3D(HWND hWnd); +void CleanupDeviceD3D(); +void CreateRenderTarget(); +void CleanupRenderTarget(); + +// Main code +int main(int, char**) +{ + // Setup SDL + // [If using SDL_MAIN_USE_CALLBACKS: all code below until the main loop starts would likely be your SDL_AppInit() function] + if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD)) + { + printf("Error: SDL_Init(): %s\n", SDL_GetError()); + return -1; + } + + // Setup window + float main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()); + SDL_WindowFlags window_flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY; + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+DirectX11 example", (int)(1280 * main_scale), (int)(720 * main_scale), window_flags); + if (window == nullptr) + { + printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); + return -1; + } + + SDL_PropertiesID props = SDL_GetWindowProperties(window); + HWND hwnd = (HWND)SDL_GetPointerProperty(props, SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL); + + // Initialize Direct3D + if (!CreateDeviceD3D(hwnd)) + { + CleanupDeviceD3D(); + return 1; + } + + SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); + SDL_ShowWindow(window); + + // Setup Dear ImGui context + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); (void)io; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls + + // Setup Dear ImGui style + ImGui::StyleColorsDark(); + //ImGui::StyleColorsLight(); + + // Setup scaling + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again) + style.FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose) + + // Setup Platform/Renderer backends + ImGui_ImplSDL3_InitForD3D(window); + ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); + + // Load Fonts + // - If no fonts are loaded, dear imgui will use the default font. You can also load multiple fonts and use ImGui::PushFont()/PopFont() to select them. + // - AddFontFromFileTTF() will return the ImFont* so you can store it if you need to select the font among multiple. + // - If the file cannot be loaded, the function will return a nullptr. Please handle those errors in your application (e.g. use an assertion, or display an error and quit). + // - Use '#define IMGUI_ENABLE_FREETYPE' in your imconfig file to use Freetype for higher quality font rendering. + // - Read 'docs/FONTS.md' for more instructions and details. If you like the default font but want it to scale better, consider using the 'ProggyVector' from the same author! + // - Remember that in C/C++ if you want to include a backslash \ in a string literal you need to write a double backslash \\ ! + //style.FontSizeBase = 20.0f; + //io.Fonts->AddFontDefault(); + //io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\segoeui.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/DroidSans.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Roboto-Medium.ttf"); + //io.Fonts->AddFontFromFileTTF("../../misc/fonts/Cousine-Regular.ttf"); + //ImFont* font = io.Fonts->AddFontFromFileTTF("c:\\Windows\\Fonts\\ArialUni.ttf"); + //IM_ASSERT(font != nullptr); + + // Our state + bool show_demo_window = true; + bool show_another_window = false; + ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); + + // Main loop + bool done = false; + while (!done) + { + // Poll and handle events (inputs, window resize, etc.) + // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. + // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. + // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. + // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. + // [If using SDL_MAIN_USE_CALLBACKS: call ImGui_ImplSDL3_ProcessEvent() from your SDL_AppEvent() function] + SDL_Event event; + while (SDL_PollEvent(&event)) + { + ImGui_ImplSDL3_ProcessEvent(&event); + if (event.type == SDL_EVENT_QUIT) + done = true; + if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window)) + done = true; + if (event.type == SDL_EVENT_WINDOW_RESIZED && event.window.windowID == SDL_GetWindowID(window)) + { + // Release all outstanding references to the swap chain's buffers before resizing. + CleanupRenderTarget(); + g_pSwapChain->ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0); + CreateRenderTarget(); + } + } + + // [If using SDL_MAIN_USE_CALLBACKS: all code below would likely be your SDL_AppIterate() function] + if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) + { + SDL_Delay(10); + continue; + } + + // Start the Dear ImGui frame + ImGui_ImplDX11_NewFrame(); + ImGui_ImplSDL3_NewFrame(); + ImGui::NewFrame(); + + // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). + if (show_demo_window) + ImGui::ShowDemoWindow(&show_demo_window); + + // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window. + { + static float f = 0.0f; + static int counter = 0; + + ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. + + ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) + ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state + ImGui::Checkbox("Another Window", &show_another_window); + + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f + ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color + + if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) + counter++; + ImGui::SameLine(); + ImGui::Text("counter = %d", counter); + + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); + ImGui::End(); + } + + // 3. Show another simple window. + if (show_another_window) + { + ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) + ImGui::Text("Hello from another window!"); + if (ImGui::Button("Close Me")) + show_another_window = false; + ImGui::End(); + } + + // Rendering + ImGui::Render(); + const float clear_color_with_alpha[4] = { clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w }; + g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, nullptr); + g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha); + ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); + + g_pSwapChain->Present(1, 0); // Present with vsync + //g_pSwapChain->Present(0, 0); // Present without vsync + } + + // Cleanup + ImGui_ImplDX11_Shutdown(); + ImGui_ImplSDL3_Shutdown(); + ImGui::DestroyContext(); + + CleanupDeviceD3D(); + SDL_DestroyWindow(window); + SDL_Quit(); + + return 0; +} + +// Helper functions to use DirectX11 +bool CreateDeviceD3D(HWND hWnd) +{ + // Setup swap chain + DXGI_SWAP_CHAIN_DESC sd; + ZeroMemory(&sd, sizeof(sd)); + sd.BufferCount = 2; + sd.BufferDesc.Width = 0; + sd.BufferDesc.Height = 0; + sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + sd.BufferDesc.RefreshRate.Numerator = 60; + sd.BufferDesc.RefreshRate.Denominator = 1; + sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; + sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + sd.OutputWindow = hWnd; + sd.SampleDesc.Count = 1; + sd.SampleDesc.Quality = 0; + sd.Windowed = TRUE; + sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; + + UINT createDeviceFlags = 0; + //createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; + D3D_FEATURE_LEVEL featureLevel; + const D3D_FEATURE_LEVEL featureLevelArray[2] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0, }; + if (D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext) != S_OK) + return false; + + CreateRenderTarget(); + return true; +} + +void CleanupDeviceD3D() +{ + CleanupRenderTarget(); + if (g_pSwapChain) { g_pSwapChain->Release(); g_pSwapChain = nullptr; } + if (g_pd3dDeviceContext) { g_pd3dDeviceContext->Release(); g_pd3dDeviceContext = nullptr; } + if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = nullptr; } +} + +void CreateRenderTarget() +{ + ID3D11Texture2D* pBackBuffer; + g_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); + g_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &g_mainRenderTargetView); + pBackBuffer->Release(); +} + +void CleanupRenderTarget() +{ + if (g_mainRenderTargetView) { g_mainRenderTargetView->Release(); g_mainRenderTargetView = nullptr; } +} diff --git a/examples/imgui_examples.sln b/examples/imgui_examples.sln index cf1c5ad50..8ad1a2566 100644 --- a/examples/imgui_examples.sln +++ b/examples/imgui_examples.sln @@ -39,6 +39,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_win32_vulkan", "exa EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_sdlgpu3", "example_sdl3_sdlgpu3\example_sdl3_sdlgpu3.vcxproj", "{C22CB6F8-39A5-4DDA-90ED-4ACA4E81E1E5}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_directx11", "example_sdl3_directx11\example_sdl3_directx11.vcxproj", "{009DAC16-1A9C-47BE-9770-A30A046E8090}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -191,6 +193,14 @@ Global {C22CB6F8-39A5-4DDA-90ED-4ACA4E81E1E5}.Release|Win32.Build.0 = Release|Win32 {C22CB6F8-39A5-4DDA-90ED-4ACA4E81E1E5}.Release|x64.ActiveCfg = Release|x64 {C22CB6F8-39A5-4DDA-90ED-4ACA4E81E1E5}.Release|x64.Build.0 = Release|x64 + {009DAC16-1A9C-47BE-9770-A30A046E8090}.Debug|Win32.ActiveCfg = Debug|Win32 + {009DAC16-1A9C-47BE-9770-A30A046E8090}.Debug|Win32.Build.0 = Debug|Win32 + {009DAC16-1A9C-47BE-9770-A30A046E8090}.Debug|x64.ActiveCfg = Debug|x64 + {009DAC16-1A9C-47BE-9770-A30A046E8090}.Debug|x64.Build.0 = Debug|x64 + {009DAC16-1A9C-47BE-9770-A30A046E8090}.Release|Win32.ActiveCfg = Release|Win32 + {009DAC16-1A9C-47BE-9770-A30A046E8090}.Release|Win32.Build.0 = Release|Win32 + {009DAC16-1A9C-47BE-9770-A30A046E8090}.Release|x64.ActiveCfg = Release|x64 + {009DAC16-1A9C-47BE-9770-A30A046E8090}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From d701ffb4780467ca3a40e63ee7774346b9b61758 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 22 Sep 2025 21:37:41 +0200 Subject: [PATCH 09/14] Examples: added SDL3+DirectX11 example. Minor amends + fix both SDL2/SDL3+DirectX11 to allow WARP driver. (#8956, #8957) --- docs/CHANGELOG.txt | 5 ++++- docs/EXAMPLES.md | 6 +++++- examples/example_sdl2_directx11/main.cpp | 5 ++++- examples/example_sdl3_directx11/main.cpp | 12 ++++++++---- examples/example_win32_directx10/main.cpp | 2 +- examples/example_win32_directx11/main.cpp | 2 +- examples/example_win32_directx12/main.cpp | 2 +- examples/example_win32_directx9/main.cpp | 2 +- examples/example_win32_opengl3/main.cpp | 2 +- examples/example_win32_vulkan/main.cpp | 2 +- 10 files changed, 27 insertions(+), 13 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c6b65dd2f..87cf826c1 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -53,7 +53,10 @@ Other Changes: ClearRendererHandlers() on shutdown, so as not to leave function pointers which may be dangling when using backend in e.g. DLL. (#8945, #2769) - Backends: OpenGL3: fixed GL loader to work on Haiku OS which does not support - `RTLD_NOLOAD`. (#8952) [@Xottab-DUTY] + `RTLD_NOLOAD`. (#8952) [@Xottab-DUTY, @threedeyes] +- Examples: SDL2+DirectX11: Try WARP software driver if hardware driver is + not available. (#5924, #5562) +- Examples: SDL3+DirectX11: Added SDL3+DirectX11 example. (#8956, #8957) [@tomaz82] ----------------------------------------------------------------------- diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md index 038bd5858..f61297fd1 100644 --- a/docs/EXAMPLES.md +++ b/docs/EXAMPLES.md @@ -149,8 +149,12 @@ SDL2 (Win32, Mac, Linux, etc.) + Vulkan example.
This is quite long and tedious, because: Vulkan.
For this example, the main.cpp file exceptionally use helpers function from imgui_impl_vulkan.h/cpp. +[example_sdl3_directx11/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl3_directx11/)
+SDL3 + DirectX11 examples, Windows only.
+= main.cpp + imgui_impl_sdl3.cpp + imgui_impl_dx11.cpp
+ [example_sdl3_metal/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl3_metal/)
-SDL3 + Metal example (Mac).
+SDL3 + Metal example, Mac only.
= main.cpp + imgui_impl_sdl3.cpp + imgui_impl_metal.mm
[example_sdl3_opengl3/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl3_opengl3/)
diff --git a/examples/example_sdl2_directx11/main.cpp b/examples/example_sdl2_directx11/main.cpp index a2b39f362..ec6602f83 100644 --- a/examples/example_sdl2_directx11/main.cpp +++ b/examples/example_sdl2_directx11/main.cpp @@ -230,7 +230,10 @@ bool CreateDeviceD3D(HWND hWnd) //createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; D3D_FEATURE_LEVEL featureLevel; const D3D_FEATURE_LEVEL featureLevelArray[2] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0, }; - if (D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext) != S_OK) + HRESULT res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext); + if (res == DXGI_ERROR_UNSUPPORTED) // Try high-performance WARP software driver if hardware is not available. + res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_WARP, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext); + if (res != S_OK) return false; CreateRenderTarget(); diff --git a/examples/example_sdl3_directx11/main.cpp b/examples/example_sdl3_directx11/main.cpp index a604e3076..bc8889b8c 100644 --- a/examples/example_sdl3_directx11/main.cpp +++ b/examples/example_sdl3_directx11/main.cpp @@ -11,7 +11,7 @@ #include "imgui_impl_sdl3.h" #include "imgui_impl_dx11.h" #include -#include +#include // printf #include // Data @@ -40,7 +40,7 @@ int main(int, char**) // Setup window float main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()); SDL_WindowFlags window_flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY; - SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+DirectX11 example", (int)(1280 * main_scale), (int)(720 * main_scale), window_flags); + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+DirectX11 example", (int)(1280 * main_scale), (int)(800 * main_scale), window_flags); if (window == nullptr) { printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); @@ -54,7 +54,7 @@ int main(int, char**) if (!CreateDeviceD3D(hwnd)) { CleanupDeviceD3D(); - return 1; + return -1; } SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); @@ -189,6 +189,7 @@ int main(int, char**) } // Cleanup + // [If using SDL_MAIN_USE_CALLBACKS: all code below would likely be your SDL_AppQuit() function] ImGui_ImplDX11_Shutdown(); ImGui_ImplSDL3_Shutdown(); ImGui::DestroyContext(); @@ -224,7 +225,10 @@ bool CreateDeviceD3D(HWND hWnd) //createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; D3D_FEATURE_LEVEL featureLevel; const D3D_FEATURE_LEVEL featureLevelArray[2] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0, }; - if (D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext) != S_OK) + HRESULT res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext); + if (res == DXGI_ERROR_UNSUPPORTED) // Try high-performance WARP software driver if hardware is not available. + res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_WARP, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext); + if (res != S_OK) return false; CreateRenderTarget(); diff --git a/examples/example_win32_directx10/main.cpp b/examples/example_win32_directx10/main.cpp index 12f10ab4d..6fd10f83d 100644 --- a/examples/example_win32_directx10/main.cpp +++ b/examples/example_win32_directx10/main.cpp @@ -1,4 +1,4 @@ -// Dear ImGui: standalone example application for DirectX 10 +// Dear ImGui: standalone example application for Windows API + DirectX 10 // Learn about Dear ImGui: // - FAQ https://dearimgui.com/faq diff --git a/examples/example_win32_directx11/main.cpp b/examples/example_win32_directx11/main.cpp index 2b85895f7..5b88007a9 100644 --- a/examples/example_win32_directx11/main.cpp +++ b/examples/example_win32_directx11/main.cpp @@ -1,4 +1,4 @@ -// Dear ImGui: standalone example application for DirectX 11 +// Dear ImGui: standalone example application for Windows API + DirectX 11 // Learn about Dear ImGui: // - FAQ https://dearimgui.com/faq diff --git a/examples/example_win32_directx12/main.cpp b/examples/example_win32_directx12/main.cpp index 4ff7c54e5..a5396d31b 100644 --- a/examples/example_win32_directx12/main.cpp +++ b/examples/example_win32_directx12/main.cpp @@ -1,4 +1,4 @@ -// Dear ImGui: standalone example application for DirectX 12 +// Dear ImGui: standalone example application for Windows API + DirectX 12 // Learn about Dear ImGui: // - FAQ https://dearimgui.com/faq diff --git a/examples/example_win32_directx9/main.cpp b/examples/example_win32_directx9/main.cpp index 66369d242..b330efdeb 100644 --- a/examples/example_win32_directx9/main.cpp +++ b/examples/example_win32_directx9/main.cpp @@ -1,4 +1,4 @@ -// Dear ImGui: standalone example application for DirectX 9 +// Dear ImGui: standalone example application for Windows API + DirectX 9 // Learn about Dear ImGui: // - FAQ https://dearimgui.com/faq diff --git a/examples/example_win32_opengl3/main.cpp b/examples/example_win32_opengl3/main.cpp index 648d0d969..9ad74d61f 100644 --- a/examples/example_win32_opengl3/main.cpp +++ b/examples/example_win32_opengl3/main.cpp @@ -1,4 +1,4 @@ -// Dear ImGui: standalone example application for Win32 + OpenGL 3 +// Dear ImGui: standalone example application for Windows API + OpenGL // Learn about Dear ImGui: // - FAQ https://dearimgui.com/faq diff --git a/examples/example_win32_vulkan/main.cpp b/examples/example_win32_vulkan/main.cpp index b4b3a0860..6063437d8 100644 --- a/examples/example_win32_vulkan/main.cpp +++ b/examples/example_win32_vulkan/main.cpp @@ -1,4 +1,4 @@ -// Dear ImGui: standalone example application for Win32 + Vulkan +// Dear ImGui: standalone example application for Windows API + Vulkan // Learn about Dear ImGui: // - FAQ https://dearimgui.com/faq From 5f6eaa5278aa56075f6b001105e2e7dde9cc82ce Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 23 Sep 2025 16:29:30 +0200 Subject: [PATCH 10/14] Backends: Win32: minor optimization not submitting gamepad input if packet number has not changed. (#8556) To be honest I don't believe this is valuable as an optimization, but it makes debug stepping a little nicer. --- backends/imgui_impl_win32.cpp | 5 +++++ docs/CHANGELOG.txt | 2 ++ 2 files changed, 7 insertions(+) diff --git a/backends/imgui_impl_win32.cpp b/backends/imgui_impl_win32.cpp index 20dce139e..a8b9ff8ee 100644 --- a/backends/imgui_impl_win32.cpp +++ b/backends/imgui_impl_win32.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-09-23: Inputs: Minor optimization not submitting gamepad input if packet number has not changed. // 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown. // 2025-04-30: Inputs: Fixed an issue where externally losing mouse capture (due to e.g. focus loss) would fail to claim it again the next subsequent click. (#8594) // 2025-03-10: When dealing with OEM keys, use scancodes instead of translated keycodes to choose ImGuiKey values. (#7136, #7201, #7206, #7306, #7670, #7672, #8468) @@ -124,6 +125,7 @@ struct ImGui_ImplWin32_Data HMODULE XInputDLL; PFN_XInputGetCapabilities XInputGetCapabilities; PFN_XInputGetState XInputGetState; + DWORD XInputPacketNumber; #endif ImGui_ImplWin32_Data() { memset((void*)this, 0, sizeof(*this)); } @@ -355,6 +357,9 @@ static void ImGui_ImplWin32_UpdateGamepads(ImGuiIO& io) if (!bd->HasGamepad || bd->XInputGetState == nullptr || bd->XInputGetState(0, &xinput_state) != ERROR_SUCCESS) return; io.BackendFlags |= ImGuiBackendFlags_HasGamepad; + if (bd->XInputPacketNumber != 0 && bd->XInputPacketNumber == xinput_state.dwPacketNumber) + return; + bd->XInputPacketNumber = xinput_state.dwPacketNumber; #define IM_SATURATE(V) (V < 0.0f ? 0.0f : V > 1.0f ? 1.0f : V) #define MAP_BUTTON(KEY_NO, BUTTON_ENUM) { io.AddKeyEvent(KEY_NO, (gamepad.wButtons & BUTTON_ENUM) != 0); } diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 87cf826c1..8f2aaac11 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -54,6 +54,8 @@ Other Changes: which may be dangling when using backend in e.g. DLL. (#8945, #2769) - Backends: OpenGL3: fixed GL loader to work on Haiku OS which does not support `RTLD_NOLOAD`. (#8952) [@Xottab-DUTY, @threedeyes] +- Backends: Win32: minor optimization not submitting gamepad io again if + XInput's dwPacketNumber has not changed. (#8556) [@MidTerm-CN] - Examples: SDL2+DirectX11: Try WARP software driver if hardware driver is not available. (#5924, #5562) - Examples: SDL3+DirectX11: Added SDL3+DirectX11 example. (#8956, #8957) [@tomaz82] From 82e9a5e47dfbb1954e4c3293302506a0a9f7b29d Mon Sep 17 00:00:00 2001 From: Aleksi Juvani Date: Wed, 19 Mar 2025 14:11:01 +0100 Subject: [PATCH 11/14] Windows: add resize grips for child windows with both ResizeX+ResizeY. (#8501) --- imgui.cpp | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/imgui.cpp b/imgui.cpp index 93a77ec25..c3977a21e 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6647,8 +6647,19 @@ static ImGuiCol GetWindowBgColorIdx(ImGuiWindow* window) return ImGuiCol_WindowBg; } -static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& corner_target, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size) +static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, ImVec2 corner_target, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size) { + if (window->Flags & ImGuiWindowFlags_ChildWindow) // Clamp resizing of childs within parent + { + ImGuiWindow* parent_window = window->ParentWindow; + ImGuiWindowFlags parent_flags = parent_window->Flags; + ImRect corner_limit_rect = parent_window->InnerRect; + corner_limit_rect.Expand(ImVec2(-ImMax(parent_window->WindowPadding.x, parent_window->WindowBorderSize), -ImMax(parent_window->WindowPadding.y, parent_window->WindowBorderSize))); + if ((parent_flags & (ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar)) == 0 || (parent_flags & ImGuiWindowFlags_NoScrollbar)) + corner_target.x = ImClamp(corner_target.x, corner_limit_rect.Min.x, corner_limit_rect.Max.x); + if (parent_flags & ImGuiWindowFlags_NoScrollbar) + corner_target.y = ImClamp(corner_target.y, corner_limit_rect.Min.y, corner_limit_rect.Max.y); + } ImVec2 pos_min = ImLerp(corner_target, window->Pos, corner_norm); // Expected window upper-left ImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm); // Expected window lower-right ImVec2 size_expected = pos_max - pos_min; @@ -6868,17 +6879,6 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si ImVec2 clamp_min(border_n == ImGuiDir_Right ? clamp_rect.Min.x : -FLT_MAX, border_n == ImGuiDir_Down || (border_n == ImGuiDir_Up && window_move_from_title_bar) ? clamp_rect.Min.y : -FLT_MAX); ImVec2 clamp_max(border_n == ImGuiDir_Left ? clamp_rect.Max.x : +FLT_MAX, border_n == ImGuiDir_Up ? clamp_rect.Max.y : +FLT_MAX); border_target = ImClamp(border_target, clamp_min, clamp_max); - if (flags & ImGuiWindowFlags_ChildWindow) // Clamp resizing of childs within parent - { - ImGuiWindow* parent_window = window->ParentWindow; - ImGuiWindowFlags parent_flags = parent_window->Flags; - ImRect border_limit_rect = parent_window->InnerRect; - border_limit_rect.Expand(ImVec2(-ImMax(parent_window->WindowPadding.x, parent_window->WindowBorderSize), -ImMax(parent_window->WindowPadding.y, parent_window->WindowBorderSize))); - if ((axis == ImGuiAxis_X) && ((parent_flags & (ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar)) == 0 || (parent_flags & ImGuiWindowFlags_NoScrollbar))) - border_target.x = ImClamp(border_target.x, border_limit_rect.Min.x, border_limit_rect.Max.x); - if ((axis == ImGuiAxis_Y) && (parent_flags & ImGuiWindowFlags_NoScrollbar)) - border_target.y = ImClamp(border_target.y, border_limit_rect.Min.y, border_limit_rect.Max.y); - } if (!ignore_resize) CalcResizePosSizeFromAnyCorner(window, border_target, ImMin(def.SegmentN1, def.SegmentN2), &pos_target, &size_target); } @@ -7657,7 +7657,19 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) // Handle manual resize: Resize Grips, Borders, Gamepad int border_hovered = -1, border_held = -1; ImU32 resize_grip_col[4] = {}; - const int resize_grip_count = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup)) ? 0 : g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it. + int resize_grip_count; + if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup)) { + // Child windows can only be resized when they have the flags set. The resize grip allows resizing in both directions, so it should appear only if both flags are set. + if ((window->ChildFlags & ImGuiChildFlags_ResizeX) && (window->ChildFlags & ImGuiChildFlags_ResizeY)) { + resize_grip_count = 1; // Child windows can only be resized in the layout direction, that is rightwards and downwards. + } + else { + resize_grip_count = 0; + } + } + else { + resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it. + } const float resize_grip_draw_size = IM_TRUNC(ImMax(g.FontSize * 1.10f, window->WindowRounding + 1.0f + g.FontSize * 0.2f)); if (handle_borders_and_resize_grips && !window->Collapsed) if (int auto_fit_mask = UpdateWindowManualResize(window, size_auto_fit, &border_hovered, &border_held, resize_grip_count, &resize_grip_col[0], visibility_rect)) From e1aea42e45165350029d54683c363b623efd7469 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 23 Sep 2025 16:54:59 +0200 Subject: [PATCH 12/14] Windows: add resize grips for child windows with both ResizeX+ResizeY. Amends. (#8501) --- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 32 ++++++++++++++------------------ 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 8f2aaac11..f1a9ff6da 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -43,6 +43,9 @@ Breaking Changes: Other Changes: +- Windows: added lower-right resize grip on child windows using both + ImGuiChildFlags_ResizeX and ImGuiChildFlags_ResizeY flags. (#8501) [@aleksijuvani] + The grip is not visible before hovering to reduce clutter. - IO: added ImGuiPlatformIO::ClearPlatformHandlers(), ClearRendererHandlers() helpers to null all handlers. (#8945, #2769) - Misc: Debuggers: added type formatters for the LLDB debuggers (e.g. Xcode, diff --git a/imgui.cpp b/imgui.cpp index c3977a21e..417747bca 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6647,18 +6647,19 @@ static ImGuiCol GetWindowBgColorIdx(ImGuiWindow* window) return ImGuiCol_WindowBg; } -static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, ImVec2 corner_target, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size) +static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& corner_target_arg, const ImVec2& corner_norm, ImVec2* out_pos, ImVec2* out_size) { + ImVec2 corner_target = corner_target_arg; if (window->Flags & ImGuiWindowFlags_ChildWindow) // Clamp resizing of childs within parent { ImGuiWindow* parent_window = window->ParentWindow; ImGuiWindowFlags parent_flags = parent_window->Flags; - ImRect corner_limit_rect = parent_window->InnerRect; - corner_limit_rect.Expand(ImVec2(-ImMax(parent_window->WindowPadding.x, parent_window->WindowBorderSize), -ImMax(parent_window->WindowPadding.y, parent_window->WindowBorderSize))); + ImRect limit_rect = parent_window->InnerRect; + limit_rect.Expand(ImVec2(-ImMax(parent_window->WindowPadding.x, parent_window->WindowBorderSize), -ImMax(parent_window->WindowPadding.y, parent_window->WindowBorderSize))); if ((parent_flags & (ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar)) == 0 || (parent_flags & ImGuiWindowFlags_NoScrollbar)) - corner_target.x = ImClamp(corner_target.x, corner_limit_rect.Min.x, corner_limit_rect.Max.x); + corner_target.x = ImClamp(corner_target.x, limit_rect.Min.x, limit_rect.Max.x); if (parent_flags & ImGuiWindowFlags_NoScrollbar) - corner_target.y = ImClamp(corner_target.y, corner_limit_rect.Min.y, corner_limit_rect.Max.y); + corner_target.y = ImClamp(corner_target.y, limit_rect.Min.y, limit_rect.Max.y); } ImVec2 pos_min = ImLerp(corner_target, window->Pos, corner_norm); // Expected window upper-left ImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm); // Expected window lower-right @@ -6804,7 +6805,8 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si } // Only lower-left grip is visible before hovering/activating - if (resize_grip_n == 0 || held || hovered) + const bool resize_grip_visible = held || hovered || (resize_grip_n == 0 && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0); + if (resize_grip_visible) resize_grip_col[resize_grip_n] = GetColorU32(held ? ImGuiCol_ResizeGripActive : hovered ? ImGuiCol_ResizeGripHovered : ImGuiCol_ResizeGrip); } @@ -7655,21 +7657,15 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags) handle_borders_and_resize_grips = false; // Handle manual resize: Resize Grips, Borders, Gamepad + // Child windows can only be resized when they have the flags set. The resize grip allows resizing in both directions, so it should appear only if both flags are set. int border_hovered = -1, border_held = -1; ImU32 resize_grip_col[4] = {}; int resize_grip_count; - if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup)) { - // Child windows can only be resized when they have the flags set. The resize grip allows resizing in both directions, so it should appear only if both flags are set. - if ((window->ChildFlags & ImGuiChildFlags_ResizeX) && (window->ChildFlags & ImGuiChildFlags_ResizeY)) { - resize_grip_count = 1; // Child windows can only be resized in the layout direction, that is rightwards and downwards. - } - else { - resize_grip_count = 0; - } - } - else { - resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it. - } + if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup)) + resize_grip_count = ((window->ChildFlags & ImGuiChildFlags_ResizeX) && (window->ChildFlags & ImGuiChildFlags_ResizeY)) ? 1 : 0; + else + resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it. + const float resize_grip_draw_size = IM_TRUNC(ImMax(g.FontSize * 1.10f, window->WindowRounding + 1.0f + g.FontSize * 0.2f)); if (handle_borders_and_resize_grips && !window->Collapsed) if (int auto_fit_mask = UpdateWindowManualResize(window, size_auto_fit, &border_hovered, &border_held, resize_grip_count, &resize_grip_col[0], visibility_rect)) From e06b5dfe129ccfc3ab6f28e68bee34cb64a72345 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 24 Sep 2025 14:17:24 +0200 Subject: [PATCH 13/14] Backends: SDL2,SDL3: Shallow tweaks. Toward fallback focused mouse handler to be a closer match docking version. --- backends/imgui_impl_sdl2.cpp | 13 ++++++++----- backends/imgui_impl_sdl3.cpp | 10 ++++++---- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index acd98f641..a116063ad 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -674,15 +674,18 @@ static void ImGui_ImplSDL2_UpdateMouseData() if (io.WantSetMousePos) SDL_WarpMouseInWindow(bd->Window, (int)io.MousePos.x, (int)io.MousePos.y); - // (Optional) Fallback to provide mouse position when focused (SDL_MOUSEMOTION already provides this when hovered or captured) + // (Optional) Fallback to provide unclamped mouse position when focused (SDL_MOUSEMOTION already provides this when hovered or captured) const bool is_relative_mouse_mode = SDL_GetRelativeMouseMode() != 0; if (bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode) { // Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) - int window_x, window_y, mouse_x_global, mouse_y_global; - SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global); - SDL_GetWindowPosition(bd->Window, &window_x, &window_y); - io.AddMousePosEvent((float)(mouse_x_global - window_x), (float)(mouse_y_global - window_y)); + int mouse_x, mouse_y; + int window_x, window_y; + SDL_GetGlobalMouseState(&mouse_x, &mouse_y); + SDL_GetWindowPosition(focused_window, &window_x, &window_y); + mouse_x -= window_x; + mouse_y -= window_y; + io.AddMousePosEvent((float)mouse_x, (float)mouse_y); } } } diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 83dc93282..871e7aba4 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -636,16 +636,18 @@ static void ImGui_ImplSDL3_UpdateMouseData() if (io.WantSetMousePos) SDL_WarpMouseInWindow(bd->Window, io.MousePos.x, io.MousePos.y); - // (Optional) Fallback to provide mouse position when focused (SDL_EVENT_MOUSE_MOTION already provides this when hovered or captured) + // (Optional) Fallback to provide unclamped mouse position when focused (SDL_EVENT_MOUSE_MOTION already provides this when hovered or captured) const bool is_relative_mouse_mode = SDL_GetWindowRelativeMouseMode(bd->Window); if (bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode) { // Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) - float mouse_x_global, mouse_y_global; + float mouse_x, mouse_y; int window_x, window_y; - SDL_GetGlobalMouseState(&mouse_x_global, &mouse_y_global); + SDL_GetGlobalMouseState(&mouse_x, &mouse_y); SDL_GetWindowPosition(focused_window, &window_x, &window_y); - io.AddMousePosEvent(mouse_x_global - window_x, mouse_y_global - window_y); + mouse_x -= window_x; + mouse_y -= window_y; + io.AddMousePosEvent(mouse_x, mouse_y); } } } From f61a7ef222747779a81dfa6cc44c648eb944fa6a Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 24 Sep 2025 14:48:33 +0200 Subject: [PATCH 14/14] Backends: SDL2,SDL3: avoid using the SDL_GetGlobalMouseState() path when one of our window is hovered. Fix mouse coordinate issue in fullscreen apps with macOS notch + better X11 perfs. (#7919, #7786) --- backends/imgui_impl_sdl2.cpp | 6 ++++-- backends/imgui_impl_sdl3.cpp | 6 ++++-- docs/CHANGELOG.txt | 4 ++++ imgui.h | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/backends/imgui_impl_sdl2.cpp b/backends/imgui_impl_sdl2.cpp index a116063ad..53336995e 100644 --- a/backends/imgui_impl_sdl2.cpp +++ b/backends/imgui_impl_sdl2.cpp @@ -21,6 +21,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-09-24: Skip using the SDL_GetGlobalMouseState() state when one of our window is hovered, as the SDL_MOUSEMOTION data is reliable. Fix macOS notch mouse coordinates issue in fullscreen mode + better perf on X11. (#7919, #7786) // 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown. // 2025-09-15: Content Scales are always reported as 1.0 on Wayland. (#8921) // 2025-07-08: Made ImGui_ImplSDL2_GetContentScaleForWindow(), ImGui_ImplSDL2_GetContentScaleForDisplay() helpers return 1.0f on Emscripten and Android platforms, matching macOS logic. (#8742, #8733) @@ -674,9 +675,10 @@ static void ImGui_ImplSDL2_UpdateMouseData() if (io.WantSetMousePos) SDL_WarpMouseInWindow(bd->Window, (int)io.MousePos.x, (int)io.MousePos.y); - // (Optional) Fallback to provide unclamped mouse position when focused (SDL_MOUSEMOTION already provides this when hovered or captured) + // (Optional) Fallback to provide unclamped mouse position when focused but not hovered (SDL_MOUSEMOTION already provides this when hovered or captured) + SDL_Window* hovered_window = SDL_GetMouseFocus(); const bool is_relative_mouse_mode = SDL_GetRelativeMouseMode() != 0; - if (bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode) + if (hovered_window == NULL && bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode) { // Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) int mouse_x, mouse_y; diff --git a/backends/imgui_impl_sdl3.cpp b/backends/imgui_impl_sdl3.cpp index 871e7aba4..77e5b94a8 100644 --- a/backends/imgui_impl_sdl3.cpp +++ b/backends/imgui_impl_sdl3.cpp @@ -20,6 +20,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2025-09-24: Skip using the SDL_GetGlobalMouseState() state when one of our window is hovered, as the SDL_EVENT_MOUSE_MOTION data is reliable. Fix macOS notch mouse coordinates issue in fullscreen mode + better perf on X11. (#7919, #7786) // 2025-09-18: Call platform_io.ClearPlatformHandlers() on shutdown. // 2025-09-15: Use SDL_GetWindowDisplayScale() on Mac to output DisplayFrameBufferScale. The function is more reliable during resolution changes e.g. going fullscreen. (#8703, #4414) // 2025-06-27: IME: avoid calling SDL_StartTextInput() again if already active. (#8727) @@ -636,9 +637,10 @@ static void ImGui_ImplSDL3_UpdateMouseData() if (io.WantSetMousePos) SDL_WarpMouseInWindow(bd->Window, io.MousePos.x, io.MousePos.y); - // (Optional) Fallback to provide unclamped mouse position when focused (SDL_EVENT_MOUSE_MOTION already provides this when hovered or captured) + // (Optional) Fallback to provide unclamped mouse position when focused but not hovered (SDL_EVENT_MOUSE_MOTION already provides this when hovered or captured) + SDL_Window* hovered_window = SDL_GetMouseFocus(); const bool is_relative_mouse_mode = SDL_GetWindowRelativeMouseMode(bd->Window); - if (bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode) + if (hovered_window == NULL && bd->MouseCanUseGlobalState && bd->MouseButtonsDown == 0 && !is_relative_mouse_mode) { // Single-viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window) float mouse_x, mouse_y; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index f1a9ff6da..9906174a5 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -57,6 +57,10 @@ Other Changes: which may be dangling when using backend in e.g. DLL. (#8945, #2769) - Backends: OpenGL3: fixed GL loader to work on Haiku OS which does not support `RTLD_NOLOAD`. (#8952) [@Xottab-DUTY, @threedeyes] +- Backends: SDL2,SDL3: avoid using the SDL_GetGlobalMouseState() path when one of our + window is hovered, as the event data is reliable and enough in this case. + - Fix mouse coordinates issue in fullscreen apps with macOS notch. (#7919, #7786) + - Better perf on X11 as querying global position requires a round trip to X11 server. - Backends: Win32: minor optimization not submitting gamepad io again if XInput's dwPacketNumber has not changed. (#8556) [@MidTerm-CN] - Examples: SDL2+DirectX11: Try WARP software driver if hardware driver is diff --git a/imgui.h b/imgui.h index 682364004..f04e8c0e4 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.4 WIP" -#define IMGUI_VERSION_NUM 19231 +#define IMGUI_VERSION_NUM 19232 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198