Skip to content

In DX9 backend InvalidateDeviceObjects can release already released texture #8977

@karol57

Description

@karol57

Version/Branch of Dear ImGui:

Version 1.92.3, Branch: 3 week old docking with features/string_view applied, but I reproduced it on current master

Back-ends:

imgui_impl_dx9.cpp

Compiler, OS:

Windows 11, Visual Studio Build Tools 2022

Full config/build information:

No response

Details:

My Issue/Question:

For sake of simplicity I decided to call

ImGui_ImplDX9_InvalidateDeviceObjects();
direct3DDevice->Reset(&direct3DParams);
ImGui_ImplDX9_CreateDeviceObjects();

after arrival of WM_SIZE with wParam != SIZE_MINIMIZED.
This change lead to missing font glyphs or crashes after window resize.
After some investigation I noticed that the problem arises when aforementioned block of code is called multiple times in a row.

The problem is that in function ImGui_ImplDX9_InvalidateDeviceObjects following loop:

for (ImTextureData* tex : ImGui::GetPlatformIO().Textures)
    if (tex->RefCount == 1)
    {
        tex->SetStatus(ImTextureStatus_WantDestroy);
        ImGui_ImplDX9_UpdateTexture(tex);
    }

can release already destroyed textures as in ImGui_ImplDX9_UpdateTexture:

LPDIRECT3DTEXTURE9 backend_tex = (LPDIRECT3DTEXTURE9)tex->TexID;
if (backend_tex == nullptr)
    return;
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);
tex->SetStatus(ImTextureStatus_Destroyed);

backend_tex is not set to nullptr.

Locally I changed if statement to if (tex->RefCount == 1 && tex->Status != ImTextureStatus_Destroyed) and it works, but I'm not sure if this is desired solution.

Screenshots/Video:

No response

Minimal, Complete and Verifiable Example code:

In examples\example_win32_directx9\main.cpp change WM_SIZE handling to:

case WM_SIZE:
    if (wParam == SIZE_MINIMIZED)
        return 0;
    g_d3dpp.BackBufferWidth = (UINT)LOWORD(lParam);
    g_d3dpp.BackBufferHeight = (UINT)HIWORD(lParam);
    ResetDevice();
    return 0;

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions