From 5cd83e689ed887778f9662f94060ee3345abd4aa Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 29 Sep 2025 16:34:27 +0200 Subject: [PATCH 1/8] Backends: DirectX12: amend changelog to clarify fixes. (#3463, #5018) --- docs/CHANGELOG.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b1579715e..56b18de83 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -76,6 +76,7 @@ Other Changes: - Backends: DirectX12: reuse a command list and allocator for texture uploads instead of recreating them each time. (#8963, #8465) [@RT2Code] - Backends: DirectX12: Rework synchronization logic. (#8961) [@RT2Code] + (presumably fixes old hard-to-repro crash issues such as #3463, #5018) - Backends: OpenGL3: fixed GL loader to work on Haiku OS which does not support `RTLD_NOLOAD`. (#8952) [@Xottab-DUTY, @threedeyes] - Backends: GLFW: fixed build on platform that are neither Windows, macOS or From 3dafd9e898290ca890c29a379188be9e53b88537 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 29 Sep 2025 18:30:31 +0200 Subject: [PATCH 2/8] Backends: DirectX12: enable swapchain tearing if available. (#8965) --- backends/imgui_impl_dx12.cpp | 21 ++++++++++++++++----- docs/CHANGELOG.txt | 1 + examples/example_win32_directx12/main.cpp | 21 +++++++++++++++++---- 3 files changed, 34 insertions(+), 9 deletions(-) diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index a27d34ba2..9462ca1fa 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -21,7 +21,8 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) // 2025-09-29: DirectX12: Rework synchronization logic. (#8961) -// 2025-09-29: DirectX12: Reuse a command list and allocator for texture uploads instead of recreating them each time. +// 2025-09-29: DirectX12: Enable swapchain tearing to eliminate viewports framerate throttling. (#8965) +// 2025-09-29: DirectX12: Reuse a command list and allocator for texture uploads instead of recreating them each time. (#8963) // 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. @@ -59,7 +60,7 @@ // DirectX #include -#include +#include #include #ifdef _MSC_VER #pragma comment(lib, "d3dcompiler") // Automatically link with d3dcompiler.lib as we are using D3DCompile() below. @@ -89,6 +90,7 @@ struct ImGui_ImplDX12_Texture struct ImGui_ImplDX12_Data { ImGui_ImplDX12_InitInfo InitInfo; + IDXGIFactory5* pdxgiFactory; ID3D12Device* pd3dDevice; ID3D12RootSignature* pRootSignature; ID3D12PipelineState* pPipelineState; @@ -101,6 +103,8 @@ struct ImGui_ImplDX12_Data UINT64 FenceLastSignaledValue; HANDLE FenceEvent; UINT numFramesInFlight; + bool tearingSupport; + bool LegacySingleDescriptorUsed; ID3D12CommandAllocator* pTexCmdAllocator; ID3D12GraphicsCommandList* pTexCmdList; @@ -108,8 +112,6 @@ struct ImGui_ImplDX12_Data ImGui_ImplDX12_RenderBuffers* pFrameResources; UINT frameIndex; - bool LegacySingleDescriptorUsed; - ImGui_ImplDX12_Data() { memset((void*)this, 0, sizeof(*this)); } }; @@ -545,6 +547,13 @@ bool ImGui_ImplDX12_CreateDeviceObjects() if (bd->pPipelineState) ImGui_ImplDX12_InvalidateDeviceObjects(); + HRESULT hr = ::CreateDXGIFactory1(IID_PPV_ARGS(&bd->pdxgiFactory)); + IM_ASSERT(hr == S_OK); + + BOOL allow_tearing = FALSE; + bd->pdxgiFactory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing, sizeof(allow_tearing)); + bd->tearingSupport = (allow_tearing == TRUE); + // Create the root signature { D3D12_DESCRIPTOR_RANGE descRange = {}; @@ -767,7 +776,7 @@ bool ImGui_ImplDX12_CreateDeviceObjects() return false; // Create command allocator and command list for ImGui_ImplDX12_UpdateTexture() - HRESULT hr = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&bd->pTexCmdAllocator)); + hr = bd->pd3dDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&bd->pTexCmdAllocator)); IM_ASSERT(SUCCEEDED(hr)); hr = bd->pd3dDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, bd->pTexCmdAllocator, nullptr, IID_PPV_ARGS(&bd->pTexCmdList)); IM_ASSERT(SUCCEEDED(hr)); @@ -789,6 +798,7 @@ void ImGui_ImplDX12_InvalidateDeviceObjects() if (!bd || !bd->pd3dDevice) return; + SafeRelease(bd->pdxgiFactory); if (bd->commandQueueOwned) SafeRelease(bd->pCommandQueue); bd->commandQueueOwned = false; @@ -853,6 +863,7 @@ bool ImGui_ImplDX12_Init(ImGui_ImplDX12_InitInfo* init_info) bd->DSVFormat = init_info->DSVFormat; bd->numFramesInFlight = init_info->NumFramesInFlight; bd->pd3dSrvDescHeap = init_info->SrvDescriptorHeap; + bd->tearingSupport = false; io.BackendRendererUserData = (void*)bd; io.BackendRendererName = "imgui_impl_dx12"; diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 56b18de83..cc389c907 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -77,6 +77,7 @@ Other Changes: of recreating them each time. (#8963, #8465) [@RT2Code] - Backends: DirectX12: Rework synchronization logic. (#8961) [@RT2Code] (presumably fixes old hard-to-repro crash issues such as #3463, #5018) +- Backends: DirectX12: Enable swapchain tearing if available. (#8965) [@RT2Code] - Backends: OpenGL3: fixed GL loader to work on Haiku OS which does not support `RTLD_NOLOAD`. (#8952) [@Xottab-DUTY, @threedeyes] - Backends: GLFW: fixed build on platform that are neither Windows, macOS or diff --git a/examples/example_win32_directx12/main.cpp b/examples/example_win32_directx12/main.cpp index 665693462..c8578b54c 100644 --- a/examples/example_win32_directx12/main.cpp +++ b/examples/example_win32_directx12/main.cpp @@ -10,7 +10,7 @@ #include "imgui_impl_win32.h" #include "imgui_impl_dx12.h" #include -#include +#include #include #ifdef _DEBUG @@ -92,6 +92,7 @@ static ID3D12Fence* g_fence = nullptr; static HANDLE g_fenceEvent = nullptr; static UINT64 g_fenceLastSignaledValue = 0; static IDXGISwapChain3* g_pSwapChain = nullptr; +static bool g_SwapChainTearingSupport = false; static bool g_SwapChainOccluded = false; static HANDLE g_hSwapChainWaitableObject = nullptr; static ID3D12Resource* g_mainRenderTargetResource[APP_NUM_BACK_BUFFERS] = {}; @@ -287,7 +288,7 @@ int main(int, char**) // Present HRESULT hr = g_pSwapChain->Present(1, 0); // Present with vsync - //HRESULT hr = g_pSwapChain->Present(0, 0); // Present without vsync + //HRESULT hr = g_pSwapChain->Present(0, g_SwapChainTearingSupport ? DXGI_PRESENT_ALLOW_TEARING : 0); // Present without vsync g_SwapChainOccluded = (hr == DXGI_STATUS_OCCLUDED); g_frameIndex++; } @@ -407,14 +408,24 @@ bool CreateDeviceD3D(HWND hWnd) return false; { - IDXGIFactory4* dxgiFactory = nullptr; + IDXGIFactory5* dxgiFactory = nullptr; IDXGISwapChain1* swapChain1 = nullptr; if (CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)) != S_OK) return false; + + BOOL allow_tearing = FALSE; + dxgiFactory->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allow_tearing, sizeof(allow_tearing)); + g_SwapChainTearingSupport = (allow_tearing == TRUE); + if (g_SwapChainTearingSupport) + sd.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; + if (dxgiFactory->CreateSwapChainForHwnd(g_pd3dCommandQueue, hWnd, &sd, nullptr, nullptr, &swapChain1) != S_OK) return false; if (swapChain1->QueryInterface(IID_PPV_ARGS(&g_pSwapChain)) != S_OK) return false; + if (g_SwapChainTearingSupport) + dxgiFactory->MakeWindowAssociation(hWnd, DXGI_MWA_NO_ALT_ENTER); + swapChain1->Release(); dxgiFactory->Release(); g_pSwapChain->SetMaximumFrameLatency(APP_NUM_BACK_BUFFERS); @@ -511,7 +522,9 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) if (g_pd3dDevice != nullptr && wParam != SIZE_MINIMIZED) { CleanupRenderTarget(); - HRESULT result = g_pSwapChain->ResizeBuffers(0, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam), DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_FRAME_LATENCY_WAITABLE_OBJECT); + DXGI_SWAP_CHAIN_DESC1 desc = {}; + g_pSwapChain->GetDesc1(&desc); + HRESULT result = g_pSwapChain->ResizeBuffers(0, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam), desc.Format, desc.Flags); assert(SUCCEEDED(result) && "Failed to resize swapchain."); CreateRenderTarget(); } From a3d6e82dbd0b947401c118519894abf4420b26cb Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 30 Sep 2025 16:26:27 +0200 Subject: [PATCH 3/8] Update README.md --- docs/README.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/README.md b/docs/README.md index 90a66119d..45977e74f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -107,22 +107,26 @@ Reading the changelogs is a good way to keep up to date with the things Dear ImG ### Demo -Calling the `ImGui::ShowDemoWindow()` function will create a demo window showcasing a variety of features and examples. The code is always available for reference in `imgui_demo.cpp`. [Here's how the demo looks](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v167/v167-misc.png). +Calling the `ImGui::ShowDemoWindow()` function will create a demo window showcasing a variety of features and examples. The code is always available for reference in `imgui_demo.cpp`. +- [Web version of the demo](https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html) courtesy of [@pthom](https://github.com/pthom). +- [Screenshot of the demo](https://raw.githubusercontent.com/wiki/ocornut/imgui/web/v167/v167-misc.png). You should be able to build the examples from sources. If you don't, let us know! If you want to have a quick look at some Dear ImGui features, you can download Windows binaries of the demo app here: - [imgui-demo-binaries-20250625.zip](https://www.dearimgui.com/binaries/imgui-demo-binaries-20250625.zip) (Windows, 1.92.0, built 2025/06/25, master) or [older binaries](https://www.dearimgui.com/binaries). -The demo applications are not DPI aware so expect some blurriness on a 4K screen. For DPI awareness in your application, you can load/reload your font at a different scale and scale your style with `style.ScaleAllSizes()` (see [FAQ](https://www.dearimgui.com/faq)). - ### Getting Started & Integration See the [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) guide for details. On most platforms and when using C++, **you should be able to use a combination of the [imgui_impl_xxxx](https://github.com/ocornut/imgui/tree/master/backends) backends without modification** (e.g. `imgui_impl_win32.cpp` + `imgui_impl_dx11.cpp`). If your engine supports multiple platforms, consider using more imgui_impl_xxxx files instead of rewriting them: this will be less work for you, and you can get Dear ImGui running immediately. You can _later_ decide to rewrite a custom backend using your custom engine functions if you wish so. -Integrating Dear ImGui within your custom engine is a matter of 1) wiring mouse/keyboard/gamepad inputs 2) uploading a texture to your GPU/render engine 3) providing a render function that can bind textures and render textured triangles, which is essentially what Backends are doing. The [examples/](https://github.com/ocornut/imgui/tree/master/examples) folder is populated with applications doing just that: setting up a window and using backends. If you follow the [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) guide it should in theory take you less than an hour to integrate Dear ImGui. **Make sure to spend time reading the [FAQ](https://www.dearimgui.com/faq), comments, and the examples applications!** +Integrating Dear ImGui within your custom engine is a matter of mainly 1) wiring mouse/keyboard/gamepad inputs 2) uploading a texture to your GPU/render engine 3) providing a render function that can create/update textures and render textured triangles. This is exactly what backends are doing. +- The [examples/](https://github.com/ocornut/imgui/tree/master/examples) folder is populated with applications setting up a window and using standard backends. +- The [Getting Started](https://github.com/ocornut/imgui/wiki/Getting-Started) guide has instructions to integrate imgui into an existing application using standard backends. It should in theory take you less than an hour to integrate Dear ImGui into your existing codebase where support libraries are linked. Less if you read carefully. +- The [Backends](https://github.com/ocornut/imgui/blob/master/docs/BACKENDS.md) guide explains what backends are doing, and has instructions to implement a custom backend. You can also refer to the source code of our ~20 backends to understand how they work. +- Generally, **make sure to spend time reading the [FAQ](https://www.dearimgui.com/faq), comments, and the examples applications!** -Officially maintained backends/bindings (in repository): +Officially maintained backends (in repository): - Renderers: DirectX9, DirectX10, DirectX11, DirectX12, Metal, OpenGL/ES/ES2, SDL_GPU, SDL_Renderer2/3, Vulkan, WebGPU. - Platforms: GLFW, SDL2/SDL3, Win32, Glut, OSX, Android. - Frameworks: Allegro5, Emscripten. @@ -130,7 +134,7 @@ Officially maintained backends/bindings (in repository): [Third-party backends/bindings](https://github.com/ocornut/imgui/wiki/Bindings) wiki page: - Languages: C, C# and: Beef, ChaiScript, CovScript, Crystal, D, Go, Haskell, Haxe/hxcpp, Java, JavaScript, Julia, Kotlin, Lobster, Lua, Nim, Odin, Pascal, PureBasic, Python, ReaScript, Ruby, Rust, Swift, Zig... - Frameworks: AGS/Adventure Game Studio, Amethyst, Blender, bsf, Cinder, Cocos2d-x, Defold, Diligent Engine, Ebiten, Flexium, GML/Game Maker Studio, GLEQ, Godot, GTK3, Irrlicht Engine, JUCE, LÖVE+LUA, Mach Engine, Magnum, Marmalade, Monogame, NanoRT, nCine, Nim Game Lib, Nintendo 3DS/Switch/WiiU (homebrew), Ogre, openFrameworks, OSG/OpenSceneGraph, Orx, Photoshop, px_render, Qt/QtDirect3D, raylib, SFML, Sokol, Unity, Unreal Engine 4/5, UWP, vtk, VulkanHpp, VulkanSceneGraph, Win32 GDI, WxWidgets. -- Many bindings are auto-generated (by good old [cimgui](https://github.com/cimgui/cimgui) or newer/experimental [dear_bindings](https://github.com/dearimgui/dear_bindings)), you can use their metadata output to generate bindings for other languages. +- Many bindings are auto-generated (by good old [cimgui](https://github.com/cimgui/cimgui) or our newer [dear_bindings](https://github.com/dearimgui/dear_bindings)), you can use their metadata output to generate bindings for other languages. [Useful Extensions/Widgets](https://github.com/ocornut/imgui/wiki/Useful-Extensions) wiki page: - Automation/testing, Text editors, node editors, timeline editors, plotting, software renderers, remote network access, memory editors, gizmos, etc. Notable and well supported extensions include [ImPlot](https://github.com/epezent/implot) and [Dear ImGui Test Engine](https://github.com/ocornut/imgui_test_engine). From b987970870ec3ee3a71b125b76d1cf7aa7657a74 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 1 Oct 2025 14:58:30 +0200 Subject: [PATCH 4/8] Textures: fixed an issue preventing multi-contexts sharing a ImFontAtlas from being possible to destroy in any order. --- docs/CHANGELOG.txt | 2 ++ imgui.cpp | 2 +- imgui.h | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index cc389c907..2a937a6cf 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -69,6 +69,8 @@ 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] +- Textures: fixed an issue preventing multi-contexts sharing a ImFontAtlas from + being possible to destroy in any order. - 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 diff --git a/imgui.cpp b/imgui.cpp index 417747bca..814ed73d1 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4326,7 +4326,7 @@ void ImGui::Shutdown() for (ImFontAtlas* atlas : g.FontAtlases) { UnregisterFontAtlas(atlas); - if (atlas->OwnerContext == &g) + if (atlas->RefCount == 0) { atlas->Locked = false; IM_DELETE(atlas); diff --git a/imgui.h b/imgui.h index 7d71480b8..9ec6bf20b 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 19233 +#define IMGUI_VERSION_NUM 19234 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 From 9809b0b0617c4e6500fce94451fdde7e32c7047c Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 1 Oct 2025 14:55:16 +0200 Subject: [PATCH 5/8] Textures: Fixed not updating ImTextureData's RefCount when destroying a context using a shared ImFontAtlas. (#8975) --- backends/imgui_impl_dx11.cpp | 2 +- docs/CHANGELOG.txt | 3 +++ imgui.cpp | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index 1b3423654..144850faa 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -596,7 +596,7 @@ void ImGui_ImplDX11_InvalidateDeviceObjects() if (tex->RefCount == 1) ImGui_ImplDX11_DestroyTexture(tex); - if (bd->pTexSamplerLinear) { bd->pTexSamplerLinear->Release(); bd->pTexSamplerLinear = nullptr; } + if (bd->pTexSamplerLinear) { bd->pTexSamplerLinear->Release(); bd->pTexSamplerLinear = nullptr; } if (bd->pIB) { bd->pIB->Release(); bd->pIB = nullptr; } if (bd->pVB) { bd->pVB->Release(); bd->pVB = nullptr; } if (bd->pBlendState) { bd->pBlendState->Release(); bd->pBlendState = nullptr; } diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 2a937a6cf..43658071b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -71,6 +71,9 @@ Other Changes: See misc/debuggers/ for details. (#8950) [@mentlerd] - Textures: fixed an issue preventing multi-contexts sharing a ImFontAtlas from being possible to destroy in any order. +- Textures: fixed not updating ImTextureData's RefCount when destroying a context + using a shared ImFontAtlas, leading standard backends to not properly free + texture resources. (#8975) [@icrashstuff] - 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 diff --git a/imgui.cpp b/imgui.cpp index 814ed73d1..1e881ca63 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -8841,6 +8841,8 @@ void ImGui::RegisterFontAtlas(ImFontAtlas* atlas) atlas->RefCount++; g.FontAtlases.push_back(atlas); ImFontAtlasAddDrawListSharedData(atlas, &g.DrawListSharedData); + for (ImTextureData* tex : atlas->TexList) + tex->RefCount = (unsigned short)atlas->RefCount; } void ImGui::UnregisterFontAtlas(ImFontAtlas* atlas) @@ -8850,6 +8852,8 @@ void ImGui::UnregisterFontAtlas(ImFontAtlas* atlas) ImFontAtlasRemoveDrawListSharedData(atlas, &g.DrawListSharedData); g.FontAtlases.find_erase(atlas); atlas->RefCount--; + for (ImTextureData* tex : atlas->TexList) + tex->RefCount = (unsigned short)atlas->RefCount; } // Use ImDrawList::_SetTexture(), making our shared g.FontStack[] authoritative against window-local ImDrawList. From ea564a6a5e9ef9d1f37c59535f3b361484aa5b8b Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 1 Oct 2025 17:40:20 +0200 Subject: [PATCH 6/8] Textures: fixed a crash if a texture marked as _WantDestroy by a backend after it had already been destroyed. (#8977, #8811) --- docs/CHANGELOG.txt | 3 +++ imgui_draw.cpp | 31 ++++++++++++++++++------------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 43658071b..628b909aa 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -69,6 +69,9 @@ 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] +- Textures: fixed a crash if a texture marked as _WantDestroy by a backend after + it had already been destroyed. This would typically happen when calling backend's + ImGui_ImplXXXX_InvalidateDeviceObjects() helpers twice in a row. (#8977, #8811) - Textures: fixed an issue preventing multi-contexts sharing a ImFontAtlas from being possible to destroy in any order. - Textures: fixed not updating ImTextureData's RefCount when destroying a context diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 0946d7a46..082af59ac 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2790,21 +2790,29 @@ void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count, bool rendere if (tex->Status == ImTextureStatus_WantCreate && atlas->RendererHasTextures) IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL && "Backend set texture's TexID/BackendUserData but did not update Status to OK."); + // Request destroy + // - Keep bool to true in order to differentiate a planned destroy vs a destroy decided by the backend. + // - We don't destroy pixels right away, as backend may have an in-flight copy from RAM. + if (tex->WantDestroyNextFrame && tex->Status != ImTextureStatus_Destroyed && tex->Status != ImTextureStatus_WantDestroy) + { + IM_ASSERT(tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates); + tex->Status = ImTextureStatus_WantDestroy; + } + + // If a texture has never reached the backend, they don't need to know about it. + // (note: backends between 1.92.0 and 1.92.4 could set an already destroyed texture to ImTextureStatus_WantDestroy + // when invalidating graphics objects twice, which would previously remove it from the list and crash.) + if (tex->Status == ImTextureStatus_WantDestroy && tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL) + tex->Status = ImTextureStatus_Destroyed; + + // Process texture being destroyed if (tex->Status == ImTextureStatus_Destroyed) { IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL && "Backend set texture Status to Destroyed but did not clear TexID/BackendUserData!"); if (tex->WantDestroyNextFrame) remove_from_list = true; // Destroy was scheduled by us else - tex->Status = ImTextureStatus_WantCreate; // Destroy was done was backend (e.g. freed resources mid-run) - } - else if (tex->WantDestroyNextFrame && tex->Status != ImTextureStatus_WantDestroy) - { - // Request destroy. - // - Keep bool to true in order to differentiate a planned destroy vs a destroy decided by the backend. - // - We don't destroy pixels right away, as backend may have an in-flight copy from RAM. - IM_ASSERT(tex->Status == ImTextureStatus_OK || tex->Status == ImTextureStatus_WantCreate || tex->Status == ImTextureStatus_WantUpdates); - tex->Status = ImTextureStatus_WantDestroy; + tex->Status = ImTextureStatus_WantCreate; // Destroy was done was backend: recreate it (e.g. freed resources mid-run) } // The backend may need defer destroying by a few frames, to handle texture used by previous in-flight rendering. @@ -2812,13 +2820,10 @@ void ImFontAtlasUpdateNewFrame(ImFontAtlas* atlas, int frame_count, bool rendere if (tex->Status == ImTextureStatus_WantDestroy) tex->UnusedFrames++; - // If a texture has never reached the backend, they don't need to know about it. - if (tex->Status == ImTextureStatus_WantDestroy && tex->TexID == ImTextureID_Invalid && tex->BackendUserData == NULL) - remove_from_list = true; - // Destroy and remove if (remove_from_list) { + IM_ASSERT(atlas->TexData != tex); tex->DestroyPixels(); IM_DELETE(tex); atlas->TexList.erase(atlas->TexList.begin() + tex_n); From fc4105c8a8a99fccb2bd6a1488d131dd06df9177 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 1 Oct 2025 17:49:22 +0200 Subject: [PATCH 7/8] Backends: DX9,DX10,DX11,DX12,Metal,Vulkan,WGPU,SDLRenderer2,SDLRenderer3: ensure that a texture in _WantDestroy state always turn to _Destroyed. (#8977) Amend 9809b0b. Strictly speaking this is not necessary anymore but it seems generally sane to promote this. --- backends/imgui_impl_dx10.cpp | 20 ++++++++++---------- backends/imgui_impl_dx11.cpp | 20 ++++++++++---------- backends/imgui_impl_dx12.cpp | 26 +++++++++++++------------- backends/imgui_impl_dx9.cpp | 14 +++++++------- backends/imgui_impl_metal.mm | 16 ++++++++-------- backends/imgui_impl_sdlgpu3.cpp | 3 +-- backends/imgui_impl_sdlrenderer2.cpp | 6 ++---- backends/imgui_impl_sdlrenderer3.cpp | 6 ++---- backends/imgui_impl_vulkan.cpp | 28 ++++++++++++++-------------- backends/imgui_impl_wgpu.cpp | 21 ++++++++++----------- docs/CHANGELOG.txt | 3 +++ 11 files changed, 80 insertions(+), 83 deletions(-) diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index ae6510db2..5650a3c85 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -325,18 +325,18 @@ void ImGui_ImplDX10_RenderDrawData(ImDrawData* draw_data) static void ImGui_ImplDX10_DestroyTexture(ImTextureData* tex) { - ImGui_ImplDX10_Texture* backend_tex = (ImGui_ImplDX10_Texture*)tex->BackendUserData; - if (backend_tex == nullptr) - return; - IM_ASSERT(backend_tex->pTextureView == (ID3D10ShaderResourceView*)(intptr_t)tex->TexID); - backend_tex->pTexture->Release(); - backend_tex->pTextureView->Release(); - IM_DELETE(backend_tex); + if (ImGui_ImplDX10_Texture* backend_tex = (ImGui_ImplDX10_Texture*)tex->BackendUserData) + { + IM_ASSERT(backend_tex->pTextureView == (ID3D10ShaderResourceView*)(intptr_t)tex->TexID); + backend_tex->pTextureView->Release(); + backend_tex->pTexture->Release(); + IM_DELETE(backend_tex); - // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) - tex->SetTexID(ImTextureID_Invalid); + // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) + tex->SetTexID(ImTextureID_Invalid); + tex->BackendUserData = nullptr; + } tex->SetStatus(ImTextureStatus_Destroyed); - tex->BackendUserData = nullptr; } void ImGui_ImplDX10_UpdateTexture(ImTextureData* tex) diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index 144850faa..878930404 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -341,18 +341,18 @@ void ImGui_ImplDX11_RenderDrawData(ImDrawData* draw_data) static void ImGui_ImplDX11_DestroyTexture(ImTextureData* tex) { - ImGui_ImplDX11_Texture* backend_tex = (ImGui_ImplDX11_Texture*)tex->BackendUserData; - if (backend_tex == nullptr) - return; - IM_ASSERT(backend_tex->pTextureView == (ID3D11ShaderResourceView*)(intptr_t)tex->TexID); - backend_tex->pTextureView->Release(); - backend_tex->pTexture->Release(); - IM_DELETE(backend_tex); + if (ImGui_ImplDX11_Texture* backend_tex = (ImGui_ImplDX11_Texture*)tex->BackendUserData) + { + IM_ASSERT(backend_tex->pTextureView == (ID3D11ShaderResourceView*)(intptr_t)tex->TexID); + backend_tex->pTextureView->Release(); + backend_tex->pTexture->Release(); + IM_DELETE(backend_tex); - // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) - tex->SetTexID(ImTextureID_Invalid); + // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) + tex->SetTexID(ImTextureID_Invalid); + tex->BackendUserData = nullptr; + } tex->SetStatus(ImTextureStatus_Destroyed); - tex->BackendUserData = nullptr; } void ImGui_ImplDX11_UpdateTexture(ImTextureData* tex) diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 9462ca1fa..1e122a76e 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -345,21 +345,21 @@ void ImGui_ImplDX12_RenderDrawData(ImDrawData* draw_data, ID3D12GraphicsCommandL static void ImGui_ImplDX12_DestroyTexture(ImTextureData* tex) { - ImGui_ImplDX12_Texture* backend_tex = (ImGui_ImplDX12_Texture*)tex->BackendUserData; - if (backend_tex == nullptr) - return; - IM_ASSERT(backend_tex->hFontSrvGpuDescHandle.ptr == (UINT64)tex->TexID); - ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); - bd->InitInfo.SrvDescriptorFreeFn(&bd->InitInfo, backend_tex->hFontSrvCpuDescHandle, backend_tex->hFontSrvGpuDescHandle); - SafeRelease(backend_tex->pTextureResource); - backend_tex->hFontSrvCpuDescHandle.ptr = 0; - backend_tex->hFontSrvGpuDescHandle.ptr = 0; - IM_DELETE(backend_tex); + if (ImGui_ImplDX12_Texture* backend_tex = (ImGui_ImplDX12_Texture*)tex->BackendUserData) + { + IM_ASSERT(backend_tex->hFontSrvGpuDescHandle.ptr == (UINT64)tex->TexID); + ImGui_ImplDX12_Data* bd = ImGui_ImplDX12_GetBackendData(); + bd->InitInfo.SrvDescriptorFreeFn(&bd->InitInfo, backend_tex->hFontSrvCpuDescHandle, backend_tex->hFontSrvGpuDescHandle); + SafeRelease(backend_tex->pTextureResource); + backend_tex->hFontSrvCpuDescHandle.ptr = 0; + backend_tex->hFontSrvGpuDescHandle.ptr = 0; + IM_DELETE(backend_tex); - // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) - tex->SetTexID(ImTextureID_Invalid); + // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) + tex->SetTexID(ImTextureID_Invalid); + tex->BackendUserData = nullptr; + } tex->SetStatus(ImTextureStatus_Destroyed); - tex->BackendUserData = nullptr; } void ImGui_ImplDX12_UpdateTexture(ImTextureData* tex) diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index 4a8899a62..37b5815cc 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -431,14 +431,14 @@ void ImGui_ImplDX9_UpdateTexture(ImTextureData* tex) } else if (tex->Status == ImTextureStatus_WantDestroy) { - LPDIRECT3DTEXTURE9 backend_tex = (LPDIRECT3DTEXTURE9)tex->TexID; - if (backend_tex == nullptr) - return; - IM_ASSERT(tex->TexID == (ImTextureID)(intptr_t)backend_tex); - backend_tex->Release(); + if (LPDIRECT3DTEXTURE9 backend_tex = (LPDIRECT3DTEXTURE9)tex->TexID) + { + IM_ASSERT(tex->TexID == (ImTextureID)(intptr_t)backend_tex); + backend_tex->Release(); - // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) - tex->SetTexID(ImTextureID_Invalid); + // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) + tex->SetTexID(ImTextureID_Invalid); + } tex->SetStatus(ImTextureStatus_Destroyed); } } diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index 81e8be6c4..2746efa95 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -338,16 +338,16 @@ void ImGui_ImplMetal_RenderDrawData(ImDrawData* draw_data, id static void ImGui_ImplMetal_DestroyTexture(ImTextureData* tex) { - MetalTexture* backend_tex = (__bridge_transfer MetalTexture*)(tex->BackendUserData); - if (backend_tex == nullptr) - return; - IM_ASSERT(backend_tex.metalTexture == (__bridge id)(void*)(intptr_t)tex->TexID); - backend_tex.metalTexture = nil; + if (MetalTexture* backend_tex = (__bridge_transfer MetalTexture*)(tex->BackendUserData)) + { + IM_ASSERT(backend_tex.metalTexture == (__bridge id)(void*)(intptr_t)tex->TexID); + backend_tex.metalTexture = nil; - // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) - tex->SetTexID(ImTextureID_Invalid); + // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) + tex->SetTexID(ImTextureID_Invalid); + tex->BackendUserData = nullptr; + } tex->SetStatus(ImTextureStatus_Destroyed); - tex->BackendUserData = nullptr; } void ImGui_ImplMetal_UpdateTexture(ImTextureData* tex) diff --git a/backends/imgui_impl_sdlgpu3.cpp b/backends/imgui_impl_sdlgpu3.cpp index 3afbf3db6..8d8f0a4c4 100644 --- a/backends/imgui_impl_sdlgpu3.cpp +++ b/backends/imgui_impl_sdlgpu3.cpp @@ -307,8 +307,7 @@ void ImGui_ImplSDLGPU3_RenderDrawData(ImDrawData* draw_data, SDL_GPUCommandBuffe static void ImGui_ImplSDLGPU3_DestroyTexture(ImTextureData* tex) { ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData(); - SDL_GPUTexture* raw_tex = (SDL_GPUTexture*)(intptr_t)tex->GetTexID(); - if (raw_tex != nullptr) + if (SDL_GPUTexture* raw_tex = (SDL_GPUTexture*)(intptr_t)tex->GetTexID()) SDL_ReleaseGPUTexture(bd->InitInfo.Device, raw_tex); // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) diff --git a/backends/imgui_impl_sdlrenderer2.cpp b/backends/imgui_impl_sdlrenderer2.cpp index fa1e802b1..e03d13115 100644 --- a/backends/imgui_impl_sdlrenderer2.cpp +++ b/backends/imgui_impl_sdlrenderer2.cpp @@ -267,10 +267,8 @@ void ImGui_ImplSDLRenderer2_UpdateTexture(ImTextureData* tex) } else if (tex->Status == ImTextureStatus_WantDestroy) { - SDL_Texture* sdl_texture = (SDL_Texture*)(intptr_t)tex->TexID; - if (sdl_texture == nullptr) - return; - SDL_DestroyTexture(sdl_texture); + if (SDL_Texture* sdl_texture = (SDL_Texture*)(intptr_t)tex->TexID) + SDL_DestroyTexture(sdl_texture); // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) tex->SetTexID(ImTextureID_Invalid); diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index abf636b8d..38a4383c2 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -283,10 +283,8 @@ void ImGui_ImplSDLRenderer3_UpdateTexture(ImTextureData* tex) } else if (tex->Status == ImTextureStatus_WantDestroy) { - SDL_Texture* sdl_texture = (SDL_Texture*)(intptr_t)tex->TexID; - if (sdl_texture == nullptr) - return; - SDL_DestroyTexture(sdl_texture); + if (SDL_Texture* sdl_texture = (SDL_Texture*)(intptr_t)tex->TexID) + SDL_DestroyTexture(sdl_texture); // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) tex->SetTexID(ImTextureID_Invalid); diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index 60554368e..a8eb9a8c4 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -663,22 +663,22 @@ void ImGui_ImplVulkan_RenderDrawData(ImDrawData* draw_data, VkCommandBuffer comm static void ImGui_ImplVulkan_DestroyTexture(ImTextureData* tex) { - ImGui_ImplVulkan_Texture* backend_tex = (ImGui_ImplVulkan_Texture*)tex->BackendUserData; - if (backend_tex == nullptr) - return; - IM_ASSERT(backend_tex->DescriptorSet == (VkDescriptorSet)tex->TexID); - ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); - ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; - ImGui_ImplVulkan_RemoveTexture(backend_tex->DescriptorSet); - vkDestroyImageView(v->Device, backend_tex->ImageView, v->Allocator); - vkDestroyImage(v->Device, backend_tex->Image, v->Allocator); - vkFreeMemory(v->Device, backend_tex->Memory, v->Allocator); - IM_DELETE(backend_tex); + if (ImGui_ImplVulkan_Texture* backend_tex = (ImGui_ImplVulkan_Texture*)tex->BackendUserData) + { + IM_ASSERT(backend_tex->DescriptorSet == (VkDescriptorSet)tex->TexID); + ImGui_ImplVulkan_Data* bd = ImGui_ImplVulkan_GetBackendData(); + ImGui_ImplVulkan_InitInfo* v = &bd->VulkanInitInfo; + ImGui_ImplVulkan_RemoveTexture(backend_tex->DescriptorSet); + vkDestroyImageView(v->Device, backend_tex->ImageView, v->Allocator); + vkDestroyImage(v->Device, backend_tex->Image, v->Allocator); + vkFreeMemory(v->Device, backend_tex->Memory, v->Allocator); + IM_DELETE(backend_tex); - // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) - tex->SetTexID(ImTextureID_Invalid); + // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) + tex->SetTexID(ImTextureID_Invalid); + tex->BackendUserData = nullptr; + } tex->SetStatus(ImTextureStatus_Destroyed); - tex->BackendUserData = nullptr; } void ImGui_ImplVulkan_UpdateTexture(ImTextureData* tex) diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 1f997a10a..9f731c8f1 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -533,19 +533,18 @@ void ImGui_ImplWGPU_RenderDrawData(ImDrawData* draw_data, WGPURenderPassEncoder static void ImGui_ImplWGPU_DestroyTexture(ImTextureData* tex) { - ImGui_ImplWGPU_Texture* backend_tex = (ImGui_ImplWGPU_Texture*)tex->BackendUserData; - if (backend_tex == nullptr) - return; + if (ImGui_ImplWGPU_Texture* backend_tex = (ImGui_ImplWGPU_Texture*)tex->BackendUserData) + { + IM_ASSERT(backend_tex->TextureView == (WGPUTextureView)(intptr_t)tex->TexID); + wgpuTextureViewRelease(backend_tex->TextureView); + wgpuTextureRelease(backend_tex->Texture); + IM_DELETE(backend_tex); - IM_ASSERT(backend_tex->TextureView == (WGPUTextureView)(intptr_t)tex->TexID); - wgpuTextureViewRelease(backend_tex->TextureView); - wgpuTextureRelease(backend_tex->Texture); - IM_DELETE(backend_tex); - - // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) - tex->SetTexID(ImTextureID_Invalid); + // Clear identifiers and mark as destroyed (in order to allow e.g. calling InvalidateDeviceObjects while running) + tex->SetTexID(ImTextureID_Invalid); + tex->BackendUserData = nullptr; + } tex->SetStatus(ImTextureStatus_Destroyed); - tex->BackendUserData = nullptr; } void ImGui_ImplWGPU_UpdateTexture(ImTextureData* tex) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 628b909aa..14dc2c8c4 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -99,6 +99,9 @@ Other Changes: XInput's dwPacketNumber has not changed. (#8556) [@MidTerm-CN] - Backends: Vulkan: added a way to specify custom shaders by filling init fields CustomShaderVertCreateInfo and CustomShaderFragCreateInfo. (#8585, #8271) [@johan0A] +- Backends: DX9,DX10,DX11,DX12,Metal,Vulkan,WGPU,SDLRenderer2,SDLRenderer3: + ensure that a texture in _WantDestroy state always turn to _Destroyed even + if your underlying graphics data was already destroyed. - 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 8c22b8aef6f5a80f18fff0bbebb895a97013bcdb Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 1 Oct 2025 18:38:27 +0200 Subject: [PATCH 8/8] Textures: allowed backend to destroy texture while inside the NewFrame/EndFrame scope. (#8811) --- docs/CHANGELOG.txt | 8 ++++++-- imgui.h | 6 ++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 14dc2c8c4..ea29c0b8d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -69,9 +69,13 @@ 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] -- Textures: fixed a crash if a texture marked as _WantDestroy by a backend after +- Textures: fixed a crash if texture status is set to _WantDestroy by a backend after it had already been destroyed. This would typically happen when calling backend's ImGui_ImplXXXX_InvalidateDeviceObjects() helpers twice in a row. (#8977, #8811) +- Textures: allowed backend to destroy texture while inside the NewFrame/EndFrame + scope. Basically if a backend decide to destroy a texture that we didn't request + to destroy (for e.g. freeing resources) the texture is immediately set to + a _WantCreate status again. (#8811) - Textures: fixed an issue preventing multi-contexts sharing a ImFontAtlas from being possible to destroy in any order. - Textures: fixed not updating ImTextureData's RefCount when destroying a context @@ -101,7 +105,7 @@ Other Changes: CustomShaderVertCreateInfo and CustomShaderFragCreateInfo. (#8585, #8271) [@johan0A] - Backends: DX9,DX10,DX11,DX12,Metal,Vulkan,WGPU,SDLRenderer2,SDLRenderer3: ensure that a texture in _WantDestroy state always turn to _Destroyed even - if your underlying graphics data was already destroyed. + if your underlying graphics data was already destroyed. (#8977) - 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/imgui.h b/imgui.h index 9ec6bf20b..b006023a2 100644 --- a/imgui.h +++ b/imgui.h @@ -3491,8 +3491,10 @@ struct ImTextureData ImTextureID GetTexID() const { return TexID; } // Called by Renderer backend - void SetTexID(ImTextureID tex_id) { TexID = tex_id; } // Call after creating or destroying the texture. Never modify TexID directly! - void SetStatus(ImTextureStatus status) { Status = status; } // Call after honoring a request. Never modify Status directly! + // - Call SetTexID() and SetStatus() after honoring texture requests. Never modify TexID and Status directly! + // - A backend may decide to destroy a texture that we did not request to destroy, which is fine (e.g. freeing resources), but we immediately set the texture back in _WantCreate mode. + void SetTexID(ImTextureID tex_id) { TexID = tex_id; } + void SetStatus(ImTextureStatus status) { Status = status; if (status == ImTextureStatus_Destroyed && !WantDestroyNextFrame) Status = ImTextureStatus_WantCreate; } }; //-----------------------------------------------------------------------------