Imgui: Why ImDrawData* draw_data is empty?

Created on 15 May 2018  路  24Comments  路  Source: ocornut/imgui


Version/Branch of Dear ImGui: 1.62
Back-end/Renderer/OS: Vulkan + Windows

Hello, I try to use ImGui in my Vulkan project but after few days I can't find reason why ImDrawData* return empty members. I am making code with help imgui vulkan example from imgui repository and Sascha Willems examples.

bug

All 24 comments

Hello,

It's hard to guess what may be wrong here without more code.
What's the value of draw_data->Valid ?
GetDrawData() needs to be called after ImGui::Render().

Valid is true and GetDrawData() is after ImGui::Render().

What's the exact contents of the draw data instance?
Are you actually calling imgui functions?

I'm not aware of a bug related to that so I would guess something changed in your code there..

console->NewFrame();
console->UpdateBuffers();

Inside NewFrame() I was trying different options but they didn't change anything;

void ImGuiMenu::NewFrame()
{
    ImGui::NewFrame();

    ImGui::SetWindowSize(ImVec2(200, 150), ImGuiSetCond_FirstUseEver);
    ImGui::SetWindowPos(ImVec2(0, 250));
    static float f = 0.0f;
    ImGui::Text("Debug information");
    ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
    ImGui::Checkbox("Render models", &uiSettings.display_models);

    ImGui::Render();

}
void ImGuiMenu::UpdateBuffers() {


        ImDrawData* draw_data = ImGui::GetDrawData();

        // Note: Alignment is done inside buffer creation
        VkDeviceSize vertexBufferSize = draw_data->TotalVtxCount * sizeof(ImDrawVert);
        VkDeviceSize indexBufferSize = draw_data->TotalIdxCount * sizeof(ImDrawIdx);

        // Update buffers only if vertex or index count has been changed compared to current buffer size

        // Vertex buffer
        if ((vertex_buffer.buffer == VK_NULL_HANDLE) || (vertex_count != draw_data->TotalVtxCount)) {
            vertex_buffer.Unmap();
            vertex_buffer.Destroy();

            logical_device->CreateBuffer(vertexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, vertex_buffer.buffer, vertex_buffer.memory);
            vertex_buffer.device = logical_device->device;
            vertex_count = draw_data->TotalVtxCount;
            vertex_buffer.Unmap();
            vertex_buffer.Map();
        }

        // Index buffer
        VkDeviceSize indexSize = draw_data->TotalIdxCount * sizeof(ImDrawIdx);
        if ((index_buffer.buffer == VK_NULL_HANDLE) || (index_count < draw_data->TotalIdxCount)) {
            index_buffer.Unmap();
            index_buffer.Destroy();

            logical_device->CreateBuffer(indexBufferSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, index_buffer.buffer, index_buffer.memory);

            index_count = draw_data->TotalIdxCount;
            index_buffer.Map();
        }

        // Upload data
        ImDrawVert* vtxDst = (ImDrawVert*)vertex_buffer.mapped;
        ImDrawIdx* idxDst = (ImDrawIdx*)index_buffer.mapped;

        for (int n = 0; n < draw_data->CmdListsCount; n++) {
            const ImDrawList* cmd_list = draw_data->CmdLists[n];
            memcpy(vtxDst, cmd_list->VtxBuffer.Data, cmd_list->VtxBuffer.Size * sizeof(ImDrawVert));
            memcpy(idxDst, cmd_list->IdxBuffer.Data, cmd_list->IdxBuffer.Size * sizeof(ImDrawIdx));
            vtxDst += cmd_list->VtxBuffer.Size;
            idxDst += cmd_list->IdxBuffer.Size;
        }

        // Flush to make writes visible to GPU
        vertex_buffer.Flush();
        index_buffer.Flush();
}



md5-01c5c1923aec822ababaa7c9c21551c3




void PearOrchard::InitWindow() {

    glfwInit();

    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); 
    glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);

    window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", VK_NULL_HANDLE, VK_NULL_HANDLE);

    ImGui::CreateContext();
    ImGuiIO& io = ImGui::GetIO(); (void)io;
    io.ClipboardUserData = window;
    ImGui::StyleColorsDark();

    glfwSetKeyCallback(window, PearOrchard::KeyCallback);
    glfwSetMouseButtonCallback(window, PearOrchard::MouseButtonCallback);
    glfwSetCharCallback(window, PearOrchard::CharacterCallback);
    glfwSetCursorPosCallback(window, PearOrchard::CursorPositionCallback);
    glfwSetWindowUserPointer(window, this);
    glfwSetWindowSizeCallback(window, PearOrchard::onWindowResized);
    glfwSetInputMode(window, GLFW_STICKY_KEYS, GLFW_FALSE);
    glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
    glfwSetCursorPos(window, WIDTH / 2, HEIGHT / 2);
    glfwSetCursorEnterCallback(window, PearOrchard::CursorEnterCallback);
    glfwSetScrollCallback(window, PearOrchard::ScrollCallback);

    if (!window)
    {
        glfwTerminate();
        exit(EXIT_FAILURE);
    }
}

void PearOrchard::CharacterCallback(GLFWwindow* window, unsigned int codepoint)
{
    ImGuiIO& io = ImGui::GetIO();
    if (codepoint > 0 && codepoint < 0x10000)
        io.AddInputCharacter((unsigned short)codepoint);
}

void PearOrchard::CursorPositionCallback(GLFWwindow* window, double xpos, double ypos)
{
    PearOrchard* app = reinterpret_cast<PearOrchard*>(glfwGetWindowUserPointer(window));
    app->scene_1->camera->MouseMove(xpos, ypos, WIDTH, HEIGHT, 0.005f);

    ImGuiIO& io = ImGui::GetIO();
    io.MousePos = ImVec2((float)xpos, (float)ypos);
}

void PearOrchard::KeyCallback(GLFWwindow* window, int key, int scancode, int event, int mods)
{
    PearOrchard* app = reinterpret_cast<PearOrchard*>(glfwGetWindowUserPointer(window));
    app->scene_1->PressKey(key);

    ImGuiIO& io = ImGui::GetIO();
    if (event == GLFW_PRESS)
        io.KeysDown[key] = true;
    if (event == GLFW_RELEASE)
        io.KeysDown[key] = false;

    (void)mods; // Modifiers are not reliable across systems
    io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
    io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
    io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
    io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];
}

void PearOrchard::MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
{
#if BUILD_ENABLE_VULKAN_DEBUG
    if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS)
        std::cout << "You clicked right mouse button" << std::endl;
    if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
        std::cout << "You clicked left mouse button" << std::endl;
    if (button == GLFW_MOUSE_BUTTON_MIDDLE && action == GLFW_PRESS)
        std::cout << "You clicked middle mouse button" << std::endl;
#endif

    ImGuiIO& io = ImGui::GetIO();
    if (action == GLFW_PRESS && button >= 0 && button < 3)
        io.MouseDown[button] = true;

}

I didn't change anything inside ImGui files. I just copied them to project.

I'm not sure what may be causing this, maybe if you io.DisplaySize was always zero

It's 800 by 600. Even when debbuger is inside UpdateBuffers().

Then you want to use a debugger and trace into Render() to see what is happening there.

g.Initialized - true
window_to_render_front_most - unable to read memory
NavWindowingTarget - Null
g.DrawDataBuilder - zeros

Hi,
I had similar issue when I migrate from ImGUI 1.52 to 1.61 (and similar background -> I use example of Sascha Willem in my project).
When I adapt code, I copy the following line:
ImGui::SetNextWindowSize(ImVec2(0, 0), ImGuiSetCond_FirstUseEver);

Now, I set the real window size and all working fine.
Maybe, you have a similar issue ?

FYI: Currently this line exists in sascha code: see vulkanexamplebase.cpp -> void VulkanExampleBase::updateOverlay().

Thanks, I probably found problem. It's somewhere in ImGui::SetNextWindowPos(ImVec2(0, 0));

I added line you suggested after ImGui::NewFrame();
First time compiled - I changed values to 10, 10 and still wasn't working.
Second time compiled - I changed values to 650, 20 - and now ImGui::GetDrawData() is working.
(I suppose ImGui window was outside GLFW window)

Third time compiled - Without changing anything -ImGui::GetDrawData() is not working.

@Tshayka Could you clarify?
Because none of your code above had a call to ImGui::SetNextWindowPos(ImVec2(0, 0)); and honestly I don't think this would have an affect. Nor ImGui::SetNextWindowSize(ImVec2(0, 0), ImGuiSetCond_FirstUseEver); would have an effect of that sort (I just tried), at least as long as ImGuiCond_FirstUseEver is used..).

Now it's look like:

void ImGuiMenu::NewFrame()
{
    ImGui::NewFrame();

    ImGui::SetNextWindowSize(ImVec2(200, 200), ImGuiSetCond_FirstUseEver);
    ImGui::SetNextWindowPos(ImVec2(650, 20));

    ImGui::Begin("Vulkan Example", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove);

    ImGui::SetWindowSize(ImVec2(200, 150), ImGuiSetCond_FirstUseEver);
    ImGui::SetWindowPos(ImVec2(650, 250));
    static float f = 0.0f;
    ImGui::Text("Debug information");
    ImGui::SliderFloat("float", &f, 0.0f, 1.0f);
    ImGui::Checkbox("Render models", &uiSettings.display_models);

    ImGui::End();

    ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiSetCond_FirstUseEver);
    ImGui::ShowTestWindow();
    ImGui::Render();
}

It's working always when I remove everything from imgui.ini, but no mater how I change code above and leave imgui.ini untouched ImGui::GetDrawData() members are empty. Now I am guessing.

Could you post the .ini file associated to that code? Thanks!

[Window][Debug##Default]
Pos=60,60
Size=400,400
Collapsed=0

[Window][Vulkan Example]
Pos=650,250
Size=200,200
Collapsed=0

[Window][ImGui Demo]
Pos=650,20
Size=550,680
Collapsed=0

Which version are you using? I can't understand how this would have an effect.

So you confirm that with the block of code you posted above (and nothing else) + this imgui.ini file you get an empty GetDrawData() structure?

// dear imgui, v1.62 WIP
// (headers)
  1. I empty file .ini
  2. Code compiles successfully, program is running.
  3. Close program, .ini is filled.
  4. Compile again, I don't touch anything. structure is empty.

Here is everything. It may be useful. https://github.com/Tshayka/Vulkan-get-started/tree/master/Vulcan%20get%20stared/VulcanGetStared. Code is for studying purpose so it's not perfect, but at least should handle ImGui.
Inside Ui.cpp is this method.

Thanks.
I can't reproduce the issue nor understand how this could happen.

Note that this code is a little strange because it tries to set the size from 3 different spot:

ImGui::SetNextWindowSize(ImVec2(200, 200), ImGuiSetCond_FirstUseEver);
ImGui::Begin("Vulkan Example", nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove);
ImGui::SetWindowSize(ImVec2(200, 150), ImGuiSetCond_FirstUseEver);

All those settings are conflicting with each others. In addition, there's currently a bug if you use SetWindowPos (which should almost never be used) and tries to move the window manually the window will move super strange. But none of that should result in the issue you have here..

Right, but even I leave only:

ImGui::NewFrame();
ImGui::SetNextWindowPos(ImVec2(650, 20), ImGuiSetCond_FirstUseEver);
ImGui::ShowTestWindow();
ImGui::Render();

.ini is

[Window][Debug##Default]
Pos=60,60
Size=400,400
Collapsed=0

[Window][ImGui Demo]
Pos=650,20
Size=550,680
Collapsed=0

And still there is a problem.

I looked into this with Damian and upon some inspection and discussion decided to drop this as probably being a user error. Although I didn't find the error per-se, Damian said the debugger doesn't land on the code there... Other issues in the project suggest it's all a little too brittle right now.

Note that something something like SetNextWindowSize(ImVec2(0,0)) aka SetNextWindowSize(ImVec2(0,0), ImGuiCond_Always) _will_ keep the window hidden, but none of the example reported above are doing this.

@Rominitch if you have more details feel free to share. There are probably certain usage patterns that are error-prone and if we can improve that it'd be good.

I had a similar issue. I dug somewhat deeper into ImGui::Render() and found that window->Hidden were set true. Removing the *.ini fixed the issues for me.

@sayan1an Please provide details, repro, debugger infos etc.

@ocornut Turns out the in the first iteration of render-loop ImDrawData* draw_data is NULL. Subsequent iterations are good. Putting the following sequence in or out of the render loop makes the difference:

ImGui::NewFrame()
//Do stuff
ImGui::Render()
buildBuffers(); // here ImDrawData* draw_data is NULL in the first iteration, so no vertex or index buffers are built.

in the first iteration of render-loop ImDrawData* draw_data is NULL.

I don't think this assumption is true.
None of the examples application in examples/ are checking for a NULL draw_data and they are all dereferencing the pointer.

Can you try making actual repro (which I can confirm) based on one of the examples/ app ?
There must be another factor you are omitting from the description, and nailing this repro would help us find this factor.

Was this page helpful?
0 / 5 - 0 ratings