thedmd / imgui-node-editor

Node Editor built using Dear ImGui
MIT License
3.48k stars 527 forks source link

Suspend & Resume may lead to corrupted ImDrawCmd in some cases #282

Open pthom opened 4 months ago

pthom commented 4 months ago

Hello Michał,

I encountered another issue with Suspend and Resume: in some cases, the ImDrawData CmdBuffer might be corrupted.

I put together a small repro, which you can find on the suspend_resume_issue2 branch of the same repro repository I used before (please use the suspend_resume_issue2 branch)

Here is a quick summary of what happens:

I use the node editor in a simple way, and I use suspend and resume to create popups:

        static ed::NodeId node_id = 1;

        BeginMainWindow();        // See explanations below

        ed::Begin("Graph");

        ed::BeginNode(node_id);

        if (ImGui::Button("O"))
        {
            ed::Suspend();
            ImGui::OpenPopup("expandable_str_popup");
            ed::Resume();
        }

        ed::Suspend();
        if (ImGui::BeginPopup("expandable_str_popup"))
        {
            ImGui::Text("AAAA");
            ImGui::EndPopup();
        }
        ed::Resume();

        ed::EndNode();

        ed::End();

        EndMainWindow();

And I encounter a bug inside ImGui_ImplOpenGL3_RenderDrawData

An issue is triggered at startup inside void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)


void    ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data)
{

   ...

    for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
    {
        const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
        if (pcmd->UserCallback != nullptr)
        {
            // User callback, registered via ImDrawList::AddCallback()
            // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
            if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
                ImGui_ImplOpenGL3_SetupRenderState(draw_data, fb_width, fb_height, vertex_array_object);
            else
                pcmd->UserCallback(cmd_list, pcmd);     // <== the bug is triggered here
        }

When the bug occurs, here is the content of pcmd

pcmd = {const ImDrawCmd *} 0x15a63c860 
 ClipRect = {ImVec4} 
 TextureId = {ImTextureID} 0x1 
 VtxOffset = {unsigned int} 0
 IdxOffset = {unsigned int} 930
 ElemCount = {unsigned int} 0
 UserCallback = {ImDrawCallback} 0xfffffffffffffffe        // This is a bad pointer 
 UserCallbackData = {void *} NULL

In order to trigger the bug, I had to create the main background window with several flags:

    void BeginMainWindow()
    {
        // the following code will create a background window that will cover the entire viewport
        // The bug is quite subtle and needs all the flags below to be set

        ImGuiViewport* viewport = ImGui::GetMainViewport();

        ImGui::SetNextWindowPos(viewport->Pos);
        ImVec2 viewportSize = viewport->Size;
        ImGui::SetNextWindowSize(viewportSize);
        ImGui::SetNextWindowViewport(viewport->ID);
        ImGui::SetNextWindowBgAlpha(0.0f);

        ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
        ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
        ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
        static bool p_open = true;

        ImGuiWindowFlags window_flags = 0;
        window_flags = window_flags
            | ImGuiWindowFlags_NoDocking
            | ImGuiWindowFlags_NoTitleBar
            | ImGuiWindowFlags_NoCollapse
            | ImGuiWindowFlags_NoResize
            | ImGuiWindowFlags_NoMove
            | ImGuiWindowFlags_NoScrollbar
            | ImGuiWindowFlags_NoSavedSettings
            | ImGuiWindowFlags_NoBringToFrontOnFocus
            | ImGuiWindowFlags_NoNavFocus
            ;

        ImGui::Begin("Main window", & p_open, window_flags);
        ImGui::PopStyleVar(3);

    }

In a sense, this might be related to of 205, since there were some discussions there about ImDrawCmd handling, and I think we are experiencing an issue around this here also.

Cheers!