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).
This commit is contained in:
Turtle Dove 2026-07-17 11:25:20 -05:00
parent baeea39c1a
commit 155170262a
4 changed files with 8 additions and 4 deletions

View File

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

View File

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

View File

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

View File

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