From f0afea0e99a22be4ac4683899874d631b3cffbf5 Mon Sep 17 00:00:00 2001 From: Hanif Koh Date: Wed, 23 Sep 2026 00:47:57 +0800 Subject: [PATCH] Release the Reduced Set When Unused and Share the Drag Check With the Scene Cache The reduced index buffers were only re-uploaded while the preference was on, so the last set stayed allocated until the next load once it was switched off, and their size was missing from get_used_gpu_memory(). They are now uploaded on every rebuild, empty when nothing was built, and counted. The scene cache and the solid model both asked whether the user was dragging, with different lists: the cache knew about gizmos and the rectangle selection, the solid model about the navigator and the sliders. One is_user_interacting() now answers both. The tooltip says that negative volumes are not cut out of the solid model, since load_shells() drops every non-model-part volume, and the preferences handler keeps the dimming comment with the branch it documents. --- src/libvgcode/src/ViewerImpl.cpp | 26 ++++++++++++++++---------- src/libvgcode/src/ViewerImpl.hpp | 2 ++ src/slic3r/GUI/GCodeViewer.hpp | 2 ++ src/slic3r/GUI/GLCanvas3D.cpp | 19 ++++++++++++------- src/slic3r/GUI/GLCanvas3D.hpp | 2 ++ src/slic3r/GUI/Preferences.cpp | 24 ++++++++++++------------ 6 files changed, 46 insertions(+), 29 deletions(-) diff --git a/src/libvgcode/src/ViewerImpl.cpp b/src/libvgcode/src/ViewerImpl.cpp index 41ef90531b..d4c535f028 100644 --- a/src/libvgcode/src/ViewerImpl.cpp +++ b/src/libvgcode/src/ViewerImpl.cpp @@ -893,6 +893,8 @@ void ViewerImpl::reset() m_enabled_options_count = 0; m_enabled_segments_reduced_count = 0; m_enabled_options_reduced_count = 0; + m_enabled_segments_reduced_tex_size = 0; + m_enabled_options_reduced_tex_size = 0; m_settings_used_for_ranges = std::nullopt; @@ -1278,18 +1280,20 @@ void ViewerImpl::update_enabled_entities() m_enabled_segments_reduced_count = enabled_segments_reduced.size(); m_enabled_options_reduced_count = enabled_options_reduced.size(); + m_enabled_segments_reduced_tex_size = enabled_segments_reduced.size() * sizeof(uint32_t); + m_enabled_options_reduced_tex_size = enabled_options_reduced.size() * sizeof(uint32_t); - if (build_reduced) { - assert(m_enabled_segments_reduced_buf_id > 0); - glsafe(glBindBuffer(GL_TEXTURE_BUFFER, m_enabled_segments_reduced_buf_id)); - glsafe(glBufferData(GL_TEXTURE_BUFFER, enabled_segments_reduced.size() * sizeof(uint32_t), - enabled_segments_reduced.empty() ? nullptr : enabled_segments_reduced.data(), GL_STATIC_DRAW)); + // uploaded even when nothing was built, so that the last reduced set is released as soon as + // the preference is switched off + assert(m_enabled_segments_reduced_buf_id > 0); + glsafe(glBindBuffer(GL_TEXTURE_BUFFER, m_enabled_segments_reduced_buf_id)); + glsafe(glBufferData(GL_TEXTURE_BUFFER, m_enabled_segments_reduced_tex_size, + enabled_segments_reduced.empty() ? nullptr : enabled_segments_reduced.data(), GL_STATIC_DRAW)); - assert(m_enabled_options_reduced_buf_id > 0); - glsafe(glBindBuffer(GL_TEXTURE_BUFFER, m_enabled_options_reduced_buf_id)); - glsafe(glBufferData(GL_TEXTURE_BUFFER, enabled_options_reduced.size() * sizeof(uint32_t), - enabled_options_reduced.empty() ? nullptr : enabled_options_reduced.data(), GL_STATIC_DRAW)); - } + assert(m_enabled_options_reduced_buf_id > 0); + glsafe(glBindBuffer(GL_TEXTURE_BUFFER, m_enabled_options_reduced_buf_id)); + glsafe(glBufferData(GL_TEXTURE_BUFFER, m_enabled_options_reduced_tex_size, + enabled_options_reduced.empty() ? nullptr : enabled_options_reduced.data(), GL_STATIC_DRAW)); glsafe(glBindBuffer(GL_TEXTURE_BUFFER, 0)); #endif // ENABLE_OPENGL_ES @@ -1870,6 +1874,8 @@ size_t ViewerImpl::get_used_gpu_memory() const ret += m_colors_tex_size; ret += m_enabled_segments_tex_size; ret += m_enabled_options_tex_size; + ret += m_enabled_segments_reduced_tex_size; + ret += m_enabled_options_reduced_tex_size; #endif // ENABLE_OPENGL_ES return ret; } diff --git a/src/libvgcode/src/ViewerImpl.hpp b/src/libvgcode/src/ViewerImpl.hpp index cfc86e255a..6e8ac104fc 100644 --- a/src/libvgcode/src/ViewerImpl.hpp +++ b/src/libvgcode/src/ViewerImpl.hpp @@ -503,6 +503,8 @@ private: size_t m_colors_tex_size{ 0 }; size_t m_enabled_segments_tex_size{ 0 }; size_t m_enabled_options_tex_size{ 0 }; + size_t m_enabled_segments_reduced_tex_size{ 0 }; + size_t m_enabled_options_reduced_tex_size{ 0 }; // The set the next draw reads from: the reduced one while dragging, if one is built. bool use_reduced_set() const { return m_settings.reduced_detail && m_settings.reduced_detail_enabled; } diff --git a/src/slic3r/GUI/GCodeViewer.hpp b/src/slic3r/GUI/GCodeViewer.hpp index efc956ff1a..2ead79da0f 100644 --- a/src/slic3r/GUI/GCodeViewer.hpp +++ b/src/slic3r/GUI/GCodeViewer.hpp @@ -354,6 +354,8 @@ public: void set_dim_previous_layers_brightness(float value) { m_viewer.set_dim_previous_layers_brightness(value); } float get_dim_previous_layers_brightness() const { return m_viewer.get_dim_previous_layers_brightness(); } + // whether the mouse is holding either slider's handle + bool is_slider_dragging() const { return m_layers_slider->is_dragging() || m_moves_slider->is_dragging(); } // while the user drags the camera or a slider, draw the solid model, if the preference asks for it void set_interacting(bool interacting); bool is_reduced_detail() const { return m_viewer.is_reduced_detail(); } diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index b80120991a..0648e3359c 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -7726,13 +7726,20 @@ bool GLCanvas3D::_is_scene_cacheable() const return false; #endif - // The scene follows the cursor during a drag, under a gizmo that draws at the cursor, and while - // the cursor is on the layer height bar, where the object shader draws a band at its height. + // The scene follows the cursor while the user drags, under a gizmo that draws at the cursor, and + // while the cursor is on the layer height bar, where the object shader draws a band at its height. const GLGizmoBase* gizmo = m_gizmos.get_current(); const bool cursor_on_layers_bar = is_layers_editing_enabled() && m_layers_editing.bar_rect_contains(*this, (float)m_mouse.position.x(), (float)m_mouse.position.y()); - return !m_mouse.dragging && !m_gizmos.is_dragging() && !m_rectangle_selection.is_dragging() && - (gizmo == nullptr || !gizmo->render_follows_cursor()) && !cursor_on_layers_bar; + return !is_user_interacting() && (gizmo == nullptr || !gizmo->render_follows_cursor()) && !cursor_on_layers_bar; +} + +// Whether the user is holding something that moves the scene: the camera, the navigator, a gizmo, +// the rectangle selection or a preview slider. +bool GLCanvas3D::is_user_interacting() const +{ + return m_mouse.dragging || m_navigator_dragging || m_gizmos.is_dragging() || m_rectangle_selection.is_dragging() || + m_gcode_viewer.is_slider_dragging(); } bool GLCanvas3D::_is_frame_skipping_enabled() const @@ -8779,11 +8786,9 @@ void GLCanvas3D::_render_wireframe_overlay() // pass draws changed, since a frame that reuses the cached scene would hide the change. bool GLCanvas3D::_update_preview_interaction() { - IMSlider* layers_slider = m_gcode_viewer.get_layers_slider(); - IMSlider* moves_slider = m_gcode_viewer.get_moves_slider(); const auto now = std::chrono::steady_clock::now(); const bool settling = now < m_preview_interaction_until; - const bool dragging = m_mouse.dragging || m_navigator_dragging || layers_slider->is_dragging() || moves_slider->is_dragging(); + const bool dragging = is_user_interacting(); const bool was_reduced = m_gcode_viewer.is_reduced_detail(); m_gcode_viewer.set_interacting(dragging || settling); if (settling && !dragging && m_gcode_viewer.is_reduced_detail()) { diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 8f999cc11e..ba45543063 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -1219,6 +1219,8 @@ public: void msw_rescale() { m_gcode_viewer.invalidate_legend(); } void request_extra_frame() { m_extra_frame_requested = true; } + // whether the user is holding the camera, the navigator, a gizmo, the rectangle selection or a preview slider + bool is_user_interacting() const; // a wheel step is over before the next frame, so it holds the preview's solid model for a settle time void note_preview_interaction(); diff --git a/src/slic3r/GUI/Preferences.cpp b/src/slic3r/GUI/Preferences.cpp index 6b67a718c6..2206abd452 100644 --- a/src/slic3r/GUI/Preferences.cpp +++ b/src/slic3r/GUI/Preferences.cpp @@ -1049,16 +1049,6 @@ wxBoxSizer *PreferencesDialog::create_item_checkbox(wxString title, wxString too } } // ORCA: apply the preview dimming change immediately to the currently loaded preview - // apply the solid model preference immediately to the currently loaded preview - else if (param == "preview_solid_model_while_dragging") { - if (Plater* plater = wxGetApp().plater()) { - if (GLCanvas3D* canvas = plater->get_preview_canvas3D()) { - canvas->get_gcode_viewer().set_solid_model_while_dragging(app_config->get_bool(param)); - canvas->set_as_dirty(); - canvas->request_extra_frame(); - } - } - } else if (param == "preview_dim_previous_layers") { if (m_dim_previous_layers_brightness_input) m_dim_previous_layers_brightness_input->Enable(app_config->get_bool(param)); @@ -1070,6 +1060,16 @@ wxBoxSizer *PreferencesDialog::create_item_checkbox(wxString title, wxString too } } } + // apply the solid model preference immediately to the currently loaded preview + else if (param == "preview_solid_model_while_dragging") { + if (Plater* plater = wxGetApp().plater()) { + if (GLCanvas3D* canvas = plater->get_preview_canvas3D()) { + canvas->get_gcode_viewer().set_solid_model_while_dragging(app_config->get_bool(param)); + canvas->set_as_dirty(); + canvas->request_extra_frame(); + } + } + } #ifdef __WXMSW__ if (param == "associate_3mf") { @@ -2032,8 +2032,8 @@ void PreferencesDialog::create_items() auto item_solid_model_while_dragging = create_item_checkbox( _L("Only render solid model when dragging"), _L("While dragging the camera or a preview slider, or zooming with the mouse wheel, draw the sliced objects and the prime tower as solid shapes " - "in their filament colours instead of toolpaths, so that large prints stay responsive. They are cut to the visible layer range, with its bottom " - "and top layers drawn as toolpaths. Supports are not shown. The toolpaths are restored as soon as you let go."), + "in their filament colors instead of toolpaths, so that large prints stay responsive. They are cut to the visible layer range, with its bottom " + "and top layers drawn as toolpaths. Supports are not shown, and negative volumes are not cut out. The toolpaths are restored as soon as you let go."), "preview_solid_model_while_dragging" ); g_sizer->Add(item_solid_model_while_dragging);