From 7131dd30e7b562179105e5c42560684de3c88db3 Mon Sep 17 00:00:00 2001 From: SoftFever <103989404+SoftFever@users.noreply.github.com> Date: Wed, 14 Oct 2026 00:37:47 +0800 Subject: [PATCH] Lower peak memory when the G-code preview loads (#16440) --- src/slic3r/GUI/LibVGCode/LibVGCodeWrapper.cpp | 70 ++++++++++++------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/src/slic3r/GUI/LibVGCode/LibVGCodeWrapper.cpp b/src/slic3r/GUI/LibVGCode/LibVGCodeWrapper.cpp index ea010a41b5..8c6e475ad7 100644 --- a/src/slic3r/GUI/LibVGCode/LibVGCodeWrapper.cpp +++ b/src/slic3r/GUI/LibVGCode/LibVGCodeWrapper.cpp @@ -200,6 +200,22 @@ Slic3r::PrintEstimatedStatistics::ETimeMode convert(const ETimeMode& mode) } } +// libvgcode finds where a path starts from a phantom vertex placed at the previous move's +// position. Every move that is not an option marker (extrusions, travels, wipes, and Noop or +// unmapped moves) starts a path when it is the first move, or when it differs from the previous +// move in type, role or a value the preview colors by. convert() sizes its vertex array by +// counting these, so the count and the fill must both use this test. +static bool starts_path(const Slic3r::GCodeProcessorResult::MoveVertex& prev, + const Slic3r::GCodeProcessorResult::MoveVertex& curr, bool first_move) +{ + const EOptionType option_type = move_type_to_option(convert(curr.type)); + if (option_type != EOptionType::COUNT && option_type != EOptionType::Travels && option_type != EOptionType::Wipes) + return false; + return first_move || prev.type != curr.type || prev.extrusion_role != curr.extrusion_role + // ORCA: Split the path when a preview value changes. + || prev.mm3_per_mm != curr.mm3_per_mm || prev.acceleration != curr.acceleration || prev.jerk != curr.jerk; +} + GCodeInputData convert(const Slic3r::GCodeProcessorResult& result, const std::vector& str_tool_colors, const std::vector& str_color_print_colors, const Viewer& viewer, const Slic3r::Transform3d* belt_xform) @@ -231,7 +247,14 @@ GCodeInputData convert(const Slic3r::GCodeProcessorResult& result, const std::ve } const std::vector& moves = result.moves; - ret.vertices.reserve(2 * moves.size()); + // One vertex per move after the first, plus a phantom in front of every path start. Reserving + // the exact count leaves nothing to shrink afterwards, and shrinking would copy the whole array + // while both copies are alive. + size_t vertices_count = moves.empty() ? 0 : moves.size() - 1; + for (size_t i = 1; i < moves.size(); ++i) + if (starts_path(moves[i - 1], moves[i], i == 1)) + ++vertices_count; + ret.vertices.reserve(vertices_count); // libvgcode numbers its layers from the vertices it is given and expects them to // arrive one layer after the other with consecutive ids: a layer without any move // (a belt file can carry layer changes that print nothing) would leave a gap, and @@ -248,33 +271,28 @@ GCodeInputData convert(const Slic3r::GCodeProcessorResult& result, const std::ve ++ layer_id; src_layer_id = curr.layer_id; } - const EOptionType option_type = move_type_to_option(curr_type); - if (option_type == EOptionType::COUNT || option_type == EOptionType::Travels || option_type == EOptionType::Wipes) { - if (ret.vertices.empty() || prev.type != curr.type || prev.extrusion_role != curr.extrusion_role - // ORCA: Split the path when a preview value changes. - || prev.mm3_per_mm != curr.mm3_per_mm || prev.acceleration != curr.acceleration || prev.jerk != curr.jerk) { - // to allow libvgcode to properly detect the start/end of a path we need to add a 'phantom' vertex - // equal to the current one with the exception of the position, which should match the previous move position, - // and the times, which are set to zero + if (starts_path(prev, curr, i == 1)) { + // to allow libvgcode to properly detect the start/end of a path we need to add a 'phantom' vertex + // equal to the current one with the exception of the position, which should match the previous move position, + // and the times, which are set to zero #if VGCODE_ENABLE_COG_AND_TOOL_MARKERS - const libvgcode::PathVertex vertex = { xform_pos(prev.position), curr.height, curr.width, curr.feedrate, prev.actual_feedrate, - curr.mm3_per_mm, curr.fan_speed, curr.temperature, 0.0f, convert(curr.extrusion_role), curr_type, - static_cast(curr.gcode_id), layer_id, - static_cast(curr.extruder_id), static_cast(curr.cp_color_id), { 0.0f, 0.0f }, - /* ORCA: Add Pressure Advance visualization support */ 0.0f, curr.pressure_advance, - /* ORCA: Add Acceleration visualization support */ curr.acceleration, - /* ORCA: Add Jerk visualization support */ curr.jerk }; + const libvgcode::PathVertex vertex = { xform_pos(prev.position), curr.height, curr.width, curr.feedrate, prev.actual_feedrate, + curr.mm3_per_mm, curr.fan_speed, curr.temperature, 0.0f, convert(curr.extrusion_role), curr_type, + static_cast(curr.gcode_id), layer_id, + static_cast(curr.extruder_id), static_cast(curr.cp_color_id), { 0.0f, 0.0f }, + /* ORCA: Add Pressure Advance visualization support */ 0.0f, curr.pressure_advance, + /* ORCA: Add Acceleration visualization support */ curr.acceleration, + /* ORCA: Add Jerk visualization support */ curr.jerk }; #else - const libvgcode::PathVertex vertex = { xform_pos(prev.position), curr.height, curr.width, curr.feedrate, prev.actual_feedrate, - curr.mm3_per_mm, curr.fan_speed, curr.temperature, convert(curr.extrusion_role), curr_type, - static_cast(curr.gcode_id), layer_id, - static_cast(curr.extruder_id), static_cast(curr.cp_color_id), { 0.0f, 0.0f }, - /* ORCA: Add Pressure Advance visualization support */ 0.0f, curr.pressure_advance, - /* ORCA: Add Acceleration visualization support */ curr.acceleration, - /* ORCA: Add Jerk visualization support */ curr.jerk }; + const libvgcode::PathVertex vertex = { xform_pos(prev.position), curr.height, curr.width, curr.feedrate, prev.actual_feedrate, + curr.mm3_per_mm, curr.fan_speed, curr.temperature, convert(curr.extrusion_role), curr_type, + static_cast(curr.gcode_id), layer_id, + static_cast(curr.extruder_id), static_cast(curr.cp_color_id), { 0.0f, 0.0f }, + /* ORCA: Add Pressure Advance visualization support */ 0.0f, curr.pressure_advance, + /* ORCA: Add Acceleration visualization support */ curr.acceleration, + /* ORCA: Add Jerk visualization support */ curr.jerk }; #endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS - ret.vertices.emplace_back(vertex); - } + ret.vertices.emplace_back(vertex); } #if VGCODE_ENABLE_COG_AND_TOOL_MARKERS @@ -297,6 +315,8 @@ GCodeInputData convert(const Slic3r::GCodeProcessorResult& result, const std::ve #endif // VGCODE_ENABLE_COG_AND_TOOL_MARKERS ret.vertices.emplace_back(vertex); } + assert(ret.vertices.size() == vertices_count); + // A no-op when the count above is exact; restores the exact fit if the count ever drifts. ret.vertices.shrink_to_fit(); // Note: the belt designed-view anchoring (recovering the per-object placement/