From 155170262a4af95a4544b72f618bdda92e90fb37 Mon Sep 17 00:00:00 2001 From: Turtle Dove Date: Fri, 17 Jul 2026 11:25:20 -0500 Subject: [PATCH] Backends: DX9, Allegro5, SDLRenderer2, SDLRenderer3: Defer texture destruction until UnusedFrames > 0 (#8597, #9475) These four backends were missing the UnusedFrames > 0 check in their UpdateTexture() WantDestroy branch, inconsistent with all other backends (OpenGL2, OpenGL3, DX10, DX11, DX12, Vulkan, WGPU, SDLGPU3) which already defer destruction until the texture is no longer in flight. This is a potential use-after-free in multi-threaded/staged rendering pipelines where the UI thread may destroy a texture while the render thread is still drawing with it. Per #8597 guidance: backends should defer destroying by the amount of in-flight frames in their rendering pipeline. The fix adds '&& tex->UnusedFrames > 0' to the WantDestroy condition, matching the exact pattern used by OpenGL3, DX10, DX11, WGPU, and SDLGPU3. Companion to #9475 (OpenGL2 fix, already merged). --- backends/imgui_impl_allegro5.cpp | 3 ++- backends/imgui_impl_dx9.cpp | 3 ++- backends/imgui_impl_sdlrenderer2.cpp | 3 ++- backends/imgui_impl_sdlrenderer3.cpp | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index 79b169da8..89620e359 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -22,6 +22,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-07-17: Allegro5: Fixed texture destruction not deferring until UnusedFrames > 0, inconsistent with all other backends. (#8597, #9475) // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState (others cannot be supported by Allegro5). (#9378) // 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. @@ -310,7 +311,7 @@ void ImGui_ImplAllegro5_UpdateTexture(ImTextureData* tex) al_unlock_bitmap(gpu_bitmap); tex->SetStatus(ImTextureStatus_OK); } - else if (tex->Status == ImTextureStatus_WantDestroy) + else if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames > 0) { ALLEGRO_BITMAP* backend_tex = (ALLEGRO_BITMAP*)(intptr_t)tex->TexID; if (backend_tex) diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index 360398f04..dc435bfbd 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) +// 2026-07-17: DirectX9: Fixed texture destruction not deferring until UnusedFrames > 0, inconsistent with all other backends. (#8597, #9475) // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) // 2026-03-19: Fixed issue in ImGui_ImplDX9_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310) // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. @@ -395,7 +396,7 @@ void ImGui_ImplDX9_UpdateTexture(ImTextureData* tex) backend_tex->UnlockRect(0); tex->SetStatus(ImTextureStatus_OK); } - else if (tex->Status == ImTextureStatus_WantDestroy) + else if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames > 0) { if (tex->TexID != ImTextureID_Invalid) if (LPDIRECT3DTEXTURE9 backend_tex = (LPDIRECT3DTEXTURE9)tex->TexID) diff --git a/backends/imgui_impl_sdlrenderer2.cpp b/backends/imgui_impl_sdlrenderer2.cpp index d9f329bd1..558c36956 100644 --- a/backends/imgui_impl_sdlrenderer2.cpp +++ b/backends/imgui_impl_sdlrenderer2.cpp @@ -27,6 +27,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-07-17: SDLRenderer2: Fixed texture destruction not deferring until UnusedFrames > 0, inconsistent with all other backends. (#8597, #9475) // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState (others cannot be supported). (#9378) // 2026-03-12: Fixed invalid assert in ImGui_ImplSDLRenderer2_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295) // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. @@ -237,7 +238,7 @@ void ImGui_ImplSDLRenderer2_UpdateTexture(ImTextureData* tex) } tex->SetStatus(ImTextureStatus_OK); } - else if (tex->Status == ImTextureStatus_WantDestroy) + else if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames > 0) { if (tex->TexID != ImTextureID_Invalid) if (SDL_Texture* sdl_texture = (SDL_Texture*)(intptr_t)tex->TexID) diff --git a/backends/imgui_impl_sdlrenderer3.cpp b/backends/imgui_impl_sdlrenderer3.cpp index d4c043cbc..8da9c4036 100644 --- a/backends/imgui_impl_sdlrenderer3.cpp +++ b/backends/imgui_impl_sdlrenderer3.cpp @@ -25,6 +25,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2026-07-17: SDLRenderer3: Fixed texture destruction not deferring until UnusedFrames > 0, inconsistent with all other backends. (#8597, #9475) // 2026-07-15: Fixed default sampler state to be linear (broken 2026-04-23). (#9470, #9378) // 2026-04-23: Added support for standard draw callbacks (in platform_io): DrawCallback_ResetRenderState, DrawCallback_SetSamplerLinear, DrawCallback_SetSamplerNearest. (#9378) // 2026-03-12: Fixed invalid assert in ImGui_ImplSDLRenderer3_UpdateTexture() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295) @@ -266,7 +267,7 @@ void ImGui_ImplSDLRenderer3_UpdateTexture(ImTextureData* tex) } tex->SetStatus(ImTextureStatus_OK); } - else if (tex->Status == ImTextureStatus_WantDestroy) + else if (tex->Status == ImTextureStatus_WantDestroy && tex->UnusedFrames > 0) { if (tex->TexID != ImTextureID_Invalid) if (SDL_Texture* sdl_texture = (SDL_Texture*)(intptr_t)tex->TexID)