Coder Social home page Coder Social logo

Comments (4)

ocornut avatar ocornut commented on May 30, 2024

We don't allocate vertex data in the SDLRenderer backend, as we only call SDL_RenderGeometryRaw() and let SDL do its thing. While it is possible that SDL would maintain internal buffers, calling ImGui_ImplSDLRenderer3_Shutdown() doesn't involve any meaningful call to SDL/SDLRenderer that would be tied to the growth of data, it only destroy the textures which is of fixed size.

Therefore something in your statement is incorrect and I think you may need to do further research.

High usage of ImDrawList in a given window will create a large buffer, which will be GC-ed when the window is unused for a certain time. io.ConfigMemoryCompactTimer defaults to 60 = 60 seconds. You may want to adjust this value to see if it makes a difference, but it is 100% unrelated to SDL renderer. Also it won't compact if the window is in use. We might consider introducing another form of vector compaction for extreme cases where a large vector growth happens temporarily, but given your statements I'm not sure it would affect you.

from imgui.

spikeyamk avatar spikeyamk commented on May 30, 2024

I'm sorry, I probably didn't express my thought clear enough so I build this. It skips one frame after SDL_DestroyRenderer(renderer) call so that the screen won't blink. I know it's a hack but I can't come up with anything better than this:

#include <algorithm>
#include <chrono>
#include <stdio.h>
#include <thread>
#include <vector>
#include <cmath>

#include <SDL3/SDL.h>
#include <backends/imgui_impl_sdl3.h>
#include <backends/imgui_impl_sdlrenderer3.h>
#include <imgui.h>
#include <implot.h>
#if defined(IMGUI_IMPL_OPENGL_ES2)
#include <SDL3/SDL_opengles2.h>
#else
#include <SDL3/SDL_opengl.h>
#endif

int run() {
    // Setup SDL
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMEPAD) != 0)
    {
        printf("Error: SDL_Init(): %s\n", SDL_GetError());
        return -1;
    }

    // Create window with SDL_Renderer graphics context
    Uint32 window_flags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN;
    SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+SDL_Renderer example", 1920, 1080, window_flags);
    if (window == nullptr)
    {
        printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError());
        return -1;
    }
    SDL_Renderer* renderer = SDL_CreateRenderer(window, nullptr, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
    if (renderer == nullptr)
    {
        SDL_Log("Error: SDL_CreateRenderer(): %s\n", SDL_GetError());
        return -1;
    }
    SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED);
    SDL_ShowWindow(window);

    // Setup Dear ImGui context
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImPlot::CreateContext();
    ImGuiIO& io = ImGui::GetIO();
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;     // Enable Keyboard Controls
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;      // Enable Gamepad Controls

    // Setup Dear ImGui style
    ImGui::StyleColorsDark();

    // Setup Platform/Renderer backends
    ImGui_ImplSDL3_InitForSDLRenderer(window, renderer);
    ImGui_ImplSDLRenderer3_Init(renderer);

    // Our state
    bool show_demo_window { false };
    bool show_implot_window { false };
    bool show_another_window { true };
    bool reload { false };
    bool skip { false };
    const size_t xs_ys_count { 2 << 17 };
    std::vector<float> xs {
        [&]() {
            std::vector<float> ret;
            ret.resize(xs_ys_count);
            std::generate(ret.begin(), ret.end(), [index = 0.0f]() mutable {
                return index++;
            });
            return ret;
        }()
    };
    std::vector<float> ys {
        [&]() {
            std::vector<float> ret;
            ret.resize(xs_ys_count);
            std::generate(ret.begin(), ret.end(), [index = 0.0f]() mutable {
                return std::sin(index++);
            });
            return ret;
        }()
    };
    const ImVec4 clear_color { 0.45f, 0.55f, 0.60f, 1.00f };

    // Main loop
    bool done = false;
    while (!done)
    {
        SDL_Event event;
        while (SDL_PollEvent(&event))
        {
            ImGui_ImplSDL3_ProcessEvent(&event);
            if (event.type == SDL_EVENT_QUIT)
                done = true;
            if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window))
                done = true;
        }

        // Start the Dear ImGui frame
        ImGui_ImplSDLRenderer3_NewFrame();
        ImGui_ImplSDL3_NewFrame();
        ImGui::NewFrame();

        // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
        if (show_demo_window)
            ImGui::ShowDemoWindow(&show_demo_window);

        // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window.
        {
            static float f = 0.0f;
            static int counter = 0;

            ImGui::Begin("Hello, world!");                          // Create a window called "Hello, world!" and append into it.

            ImGui::Text("This is some useful text.");               // Display some text (you can use a format strings too)
            ImGui::Checkbox("Demo Window", &show_demo_window);      // Edit bools storing our window open/close state
            ImGui::Checkbox("Another Window", &show_another_window);
            ImGui::Checkbox("ImPlot Window", &show_implot_window);

            ImGui::SliderFloat("float", &f, 0.0f, 1.0f);            // Edit 1 float using a slider from 0.0f to 1.0f
            ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color

            if (ImGui::Button("Button"))                            // Buttons return true when clicked (most widgets return true when edited/activated)
                counter++;
            ImGui::SameLine();
            ImGui::Text("counter = %d", counter);

            ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
            ImGui::End();
        }

        // 3. Show another simple window.
        if (show_another_window)
        {
            ImGui::Begin("Another Window", &show_another_window);   // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked)
            ImGui::Text("Hello from another window!");
            if (ImGui::Button("Close Me"))
                show_another_window = false;

            if (ImGui::Button("Reload")) {
                reload = true;
           }

            ImGui::End();
        }

        if (show_implot_window) {
            ImGui::Begin("ImPlot", &show_implot_window);
            ImPlot::SetNextAxesToFit();
            if (ImPlot::BeginPlot("ImPlot")) {
                ImPlot::PlotLine("ImPlot", xs.data(), ys.data(), std::min(xs.size(), ys.size()));
                ImPlot::EndPlot();
            }
            ImGui::End();
        }

        // Rendering
        ImGui::Render();
        //SDL_RenderSetScale(renderer, io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
        SDL_SetRenderDrawColor(renderer, (Uint8)(clear_color.x * 255), (Uint8)(clear_color.y * 255), (Uint8)(clear_color.z * 255), (Uint8)(clear_color.w * 255));
        SDL_RenderClear(renderer);
        ImGui_ImplSDLRenderer3_RenderDrawData(ImGui::GetDrawData());
        if(skip) {
            skip = false;
        } else {
            SDL_RenderPresent(renderer);
        }

        if(reload) {
            reload = false;
            skip = true;
            // Cleanup
            SDL_RenderClear(renderer);
            ImGui_ImplSDLRenderer3_Shutdown();
            ImGui_ImplSDL3_Shutdown();
            ImPlot::DestroyContext();
            ImGui::DestroyContext();
            SDL_DestroyRenderer(renderer);

            renderer = SDL_CreateRenderer(window, nullptr, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
            if (renderer == nullptr)
            {
                SDL_Log("Error: SDL_CreateRenderer(): %s\n", SDL_GetError());
                return -1;
            }
            ImGui::CreateContext();
            ImPlot::CreateContext();

            // Setup Dear ImGui style
            ImGui::StyleColorsDark();

            // Setup Platform/Renderer backends
            ImGui_ImplSDL3_InitForSDLRenderer(window, renderer);
            ImGui_ImplSDLRenderer3_Init(renderer);
        }
    }

    // Cleanup
    ImGui_ImplSDLRenderer3_Shutdown();
    ImGui_ImplSDL3_Shutdown();
    ImPlot::DestroyContext();
    ImGui::DestroyContext();

    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();

    return 0;

}

// Main code
int main(int, char**)
{
    while(1) {
        run();
    }
}

After I close the ImGui window with one ImPlot Plot widget the memory usage is around 550 MB and stays there. ImGui::DestroyContext() or ImPlot::DestroyContext() don't free up any meaningful amount of memory ImGui_ImplSDLRenderer3_Shutdown() and ImGui_ImplSDL3_Shutdown() don't free up much more either. It's only after I call SDL_DestroyRenderer(renderer) the memory usage goes down back to 17 MB so I was looking for some other way to free the memory from the SDL_Renderer, but I guess there's no way to do that unless I do serious modifications to the backend or write something else myself?

The code above to me looks like the only thing that could be used to free up unused memory.

Also I'm not really looking into reducing the memory usage just looking into freeing unused allocated memory, so this io.ConfigMemoryCompactTimer wouldn't really help

from imgui.

ocornut avatar ocornut commented on May 30, 2024

“ The only way to free them is to call ImGui_ImplSDLRenderer3_Shutdown() and then ImGui_ImplSDLRenderer3_Init() again, ”
[…]
“It's only after I call SDL_DestroyRenderer(renderer)”

So that’s a different thing, and the answer is not really within the realm of dear imgui but entirely internal to SDL. I presume it is using a large buffer to temporarily convert/store some data.

Making a ImPlot call with 200k points is pretty unusual already. Before asking for a solution you may ask yourself why you really need to clear that temporary scratch buffer. After all you’ll need it again if you render a large plot again.

I presume SDLRenderer could decide to split very large draw calls into severals, if it knows it needs a temporary buffer, in order to cap the temporary buffer size. Our own backend for SDL renderer could easily do that arbitrary split, but it seems reasonable for SDL to be doing it to benefit the largest number of users.

So you ought to ask SDL3 team if the call to SDL_RenderGeometryRaw() for large numbers of vertices could perhaps perform multiple calls in order to avoid excessively large scratch buffer. Perhaps it is backend dependent for them.

from imgui.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.