mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-10 01:01:57 +00:00
Release GL textures, menus and handlers the GUI was leaking
The filament legend held its texture id in a function local static while the loader it calls generates a new texture every time, and BitmapCache deletes none, so a dual nozzle printer leaked one texture per filament per frame while the preview was open, along with an SVG read and a rasterize per frame. The same pattern sat in menu_item_with_icon. Textures are now cached on what actually varies and released with the rest of the ImGui resources. The canvas reuses frames by hashing the draw commands, which include the texture id, so a fresh id every frame also kept frame skipping from ever triggering. TriangleSelectorPatch did not release its VAO and buffers in the destructor, so every gizmo close leaked them. The base class already issues GL deletes on that same path, so this adds no new context requirement. bind_event_handlers() installed three lambdas that unbind_event_handlers() could not remove, because wx matches handlers by functor address. They are member functions now, so bind and unbind are symmetric, and the view switch stops stacking handlers. The five selection dependent menus were allocated with new on every popup and never owned. PopupMenu is synchronous and none of them is used as a submenu, so a single owner is enough. remove_notification_of_type stopped at the first match, so clear_all() left the later instances of multi-instance types alive with object ids from a project that is gone. The measure gizmo cleared its raycaster map but not the map holding one full mesh decomposition per volume.
This commit is contained in:
@@ -361,6 +361,7 @@ ImGuiWrapper::~ImGuiWrapper()
|
||||
{
|
||||
//destroy_fonts_texture();
|
||||
destroy_font();
|
||||
destroy_svg_textures();
|
||||
ImGui::DestroyContext();
|
||||
}
|
||||
|
||||
@@ -542,6 +543,12 @@ bool ImGuiWrapper::update_key_data(wxKeyEvent &evt)
|
||||
return ret;
|
||||
}
|
||||
|
||||
// SVG icons rasterized into GL textures, keyed on file name, size and recolor. Cleared as a whole
|
||||
// from new_frame() once it grows past MAX_SVG_TEXTURES, which is safe there: the previous frame has
|
||||
// been rendered and the frame about to be recorded asks for every icon it draws again.
|
||||
static std::map<std::string, ImTextureID> s_svg_textures;
|
||||
static const size_t MAX_SVG_TEXTURES = 256;
|
||||
|
||||
void ImGuiWrapper::new_frame()
|
||||
{
|
||||
if (m_new_frame_open) {
|
||||
@@ -552,6 +559,11 @@ void ImGuiWrapper::new_frame()
|
||||
init_font(true);
|
||||
}
|
||||
|
||||
// Recolored icons accumulate one texture per color the session has shown; drop them before
|
||||
// anything references them again. This frame recreates the handful it actually draws.
|
||||
if (s_svg_textures.size() > MAX_SVG_TEXTURES)
|
||||
destroy_svg_textures();
|
||||
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
|
||||
ImGui::NewFrame();
|
||||
@@ -1804,8 +1816,7 @@ bool menu_item_with_icon(const char *label, const char *shortcut, ImVec2 icon_si
|
||||
if (icon_color != 0)
|
||||
ImGui::RenderFrame(icon_pos, icon_pos + icon_size, icon_color);
|
||||
else {
|
||||
static ImTextureID transparent;
|
||||
IMTexture::load_from_svg_file(Slic3r::resources_dir() + "/images/transparent.svg", icon_size.x, icon_size.y, transparent);
|
||||
ImTextureID transparent = ImGuiWrapper::svg_texture(Slic3r::resources_dir() + "/images/transparent.svg", icon_size.x, icon_size.y);
|
||||
window->DrawList->AddImage(transparent, icon_pos, icon_pos + icon_size, { 0,0 }, { 1,1 }, ImGui::GetColorU32(ImVec4(1.f, 1.f, 1.f, 1.f)));
|
||||
}
|
||||
}
|
||||
@@ -2631,11 +2642,7 @@ void ImGuiWrapper::push_toolbar_style(const float scale)
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, ImVec4(238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 1.00f)); // 10
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(238 / 255.0f, 238 / 255.0f, 238 / 255.0f, 0.00f)); // 11
|
||||
ImGui::PushStyleColor(ImGuiCol_TextSelectedBg, COL_GREEN_LIGHT); // 12
|
||||
// The checkbox/radio frame behind this is drawn fully transparent (see FrameBg above,
|
||||
// alpha 0), showing the light window background through it - a white check mark there is
|
||||
// invisible. Dark mode doesn't have this problem (its window background is dark), so only
|
||||
// this branch needs a check mark color with real contrast against a light background.
|
||||
ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(0.f, 156 / 255.f, 136 / 255.f, 1.00f));//13
|
||||
ImGui::PushStyleColor(ImGuiCol_CheckMark, ImVec4(1.00f, 1.00f, 1.00f, 1.00f));//13
|
||||
ImGui::PushStyleColor(ImGuiCol_ScrollbarGrab, ImVec4(0.42f, 0.42f, 0.42f, 1.00f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabHovered, ImVec4(0.93f, 0.93f, 0.93f, 1.00f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ScrollbarGrabActive, ImVec4(0.93f, 0.93f, 0.93f, 1.00f));
|
||||
@@ -3389,6 +3396,36 @@ bool ImGuiWrapper::display_initialized() const
|
||||
return io.DisplaySize.x >= 0.0f && io.DisplaySize.y >= 0.0f;
|
||||
}
|
||||
|
||||
ImTextureID ImGuiWrapper::svg_texture(const std::string& filename, unsigned width, unsigned height, const char* hex_color)
|
||||
{
|
||||
std::string key = filename + "|" + std::to_string(width) + "x" + std::to_string(height);
|
||||
if (hex_color != nullptr)
|
||||
key += std::string("|") + hex_color;
|
||||
|
||||
const auto it = s_svg_textures.find(key);
|
||||
if (it != s_svg_textures.end())
|
||||
return it->second;
|
||||
|
||||
ImTextureID texture_id = nullptr;
|
||||
const bool loaded = (hex_color != nullptr) ?
|
||||
BitmapCache::load_from_svg_file_change_color(filename, width, height, texture_id, hex_color) :
|
||||
IMTexture::load_from_svg_file(filename, width, height, texture_id);
|
||||
if (!loaded)
|
||||
return nullptr;
|
||||
|
||||
s_svg_textures.emplace(std::move(key), texture_id);
|
||||
return texture_id;
|
||||
}
|
||||
|
||||
void ImGuiWrapper::destroy_svg_textures()
|
||||
{
|
||||
for (const auto& texture : s_svg_textures) {
|
||||
GLuint texture_id = (GLuint)(intptr_t)texture.second;
|
||||
glsafe(::glDeleteTextures(1, &texture_id));
|
||||
}
|
||||
s_svg_textures.clear();
|
||||
}
|
||||
|
||||
void ImGuiWrapper::destroy_font()
|
||||
{
|
||||
if (m_font_texture != 0) {
|
||||
@@ -3468,7 +3505,6 @@ void ImGuiWrapper::filament_group(const std::string& filament_type, const char*
|
||||
//ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
|
||||
std::string id = std::to_string(static_cast<unsigned int> (filament_id + 1));
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
static ImTextureID transparent;
|
||||
ImVec2 text_size = ImGui::CalcTextSize(filament_type.c_str());
|
||||
// BBS image sizing based on text width (DPI scaling)
|
||||
float img_width = ImGui::CalcTextSize("ABC").x;
|
||||
@@ -3481,7 +3517,7 @@ void ImGuiWrapper::filament_group(const std::string& filament_type, const char*
|
||||
if (rgba[3] == 0x00) {
|
||||
svg_path = "/images/outlined_rect_transparent.svg";
|
||||
}
|
||||
BitmapCache::load_from_svg_file_change_color(Slic3r::resources_dir() + svg_path, img_size.x, img_size.y, transparent, hex_color);
|
||||
ImTextureID transparent = svg_texture(Slic3r::resources_dir() + svg_path, img_size.x, img_size.y, hex_color);
|
||||
ImGui::BeginGroup();
|
||||
{
|
||||
ImVec2 cursor_pos = ImGui::GetCursorScreenPos();
|
||||
|
||||
Reference in New Issue
Block a user