Skip to content

AddRectFilled breaks after AddImage with custom texture #8694

@crazydef

Description

@crazydef

Version/Branch of Dear ImGui:

v1.91.9b

Back-ends:

Custom

Compiler, OS:

Windows 10, VS2022

Full config/build information:

No response

Details:

Our application uses multiple ImGui contexts. One for the main application UI and another context for the debug information system in the render engine itself. (And additional application contexts for each window the application opens - but they're not applicable here.)

Friday afternoon I started upgrading ImGui from v1.89.4 to v1.91.9b. After fixing a ton of compiler errors, I've spent the last six hours debugging this problem. I think I finally understand what's going on.

First, the problem:

Calling ImDrawList::AddRectFilled renders nothing after ImDrawList::AddImage has been called with a custom texture. As seen in the following image:

Image

After the drop shadow has been rendered, the window should be filled with a rounded rect to fill in the background. (Nearly all rendering in the application UI is custom ImDrawList calls.)

So, what I think is happening is this:

When I create the window with a call to ImGui::Begin, the ImDrawList is initialised with the default font and that font's atlas is pushed into the _TextureIdStack - which now contains just that texture ID.

After ImGui::Begin returns, I call ImGui::PushFont to set up default text rendering for the window. That call updates the current font and changes _CmdHeader.TextureId to that of the texture atlas for the specified font. However, it does not modify _TextureIdStack.

// This is used by ImGui::PushFont()/PopFont(). It works because we never use _TextureIdStack[] elsewhere than in PushTextureID()/PopTextureID().
void ImDrawList::_SetTextureID(ImTextureID texture_id)
{
    if (_CmdHeader.TextureId == texture_id)
        return;
    _CmdHeader.TextureId = texture_id;
    _OnChangedTextureID();
}

(Note the misleading comment about this working.) ;)

Next I draw the drop shadow around the window. This is done with a series of calls to ImDrawList::AddImage. Adding an image to the draw list will push the texture into _TextureIdStack and update _CmdHeader.TextureId. Once the image has been drawn, ImDrawList::AddImage will then pop the previously pushed texture from _TextureIdStack and update _CmdHeader.TextureId with the texture from the top of the stack. (The texture initially pushed during ImGui::Begin.)

So after calling ImDrawList::AddImage what you end up with is a font texture in use that has a different white pixel to the currently selected font and then nothing which relies on that white pixel draws correctly.

Changing ImGui::PushFont to call g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID); instead of g.CurrentWindow->DrawList->_SetTextureID(font->ContainerAtlas->TexID); and ImGui::PopFont to call g.CurrentWindow->DrawList->PopTextureID(); seems to fix the issue.

Screenshots/Video:

No response

Minimal, Complete and Verifiable Example code:

No response

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions