Comments (4)
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.
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.
“ 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)
- Combo jitters inside Table when _SizingStretchProp is set HOT 4
- How to assign different window paddings in one window? HOT 1
- OpenGL Polygon Mode warning in Windows Opengl ES 3.0 HOT 5
- Image buttons - loop - no response - always false HOT 2
- Work around for peristent Centos/RHEL GLFW mouse offset issue? HOT 1
- ProgressBar with fraction == NaN leads to gigantic allocation HOT 1
- Resizing Widgets with SDL and Ogre HOT 1
- ImGui resizes itself to git content when setting size to 0. HOT 3
- How to set the clipboard functions to default ImGui implementation? HOT 5
- More than one BeginTabItem()s crashes program HOT 1
- Tracing back to the original pushed element ID HOT 5
- Font descriptor set of the backend is always null
- ImGui Windows being weird HOT 1
- Displaying Directory/Path Tree HOT 2
- main.exe is not compatible with mi pc HOT 1
- Window Freeze using Multi Viewport and hidding main window
- Difference between backends? HOT 2
- Text rendering character advancing adds visual space for Unicode VARIATION_SELECTOR-16 codepoint HOT 2
- Creating checkboxes from a list of values HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from imgui.