Skip to content

perf: parallelize profile JSON loading with TBB (no-exception style) - #599

Merged
LiuLikeQian merged 1 commit into
mainfrom
perf_profile_loading
Jul 21, 2026
Merged

perf: parallelize profile JSON loading with TBB (no-exception style)#599
LiuLikeQian merged 1 commit into
mainfrom
perf_profile_loading

Conversation

@LuckZAE

@LuckZAE LuckZAE commented Jul 21, 2026

Copy link
Copy Markdown

Description

GuideFrame::LoadProfileData() (setup wizard / "configure selectable filaments") and WebPresetDialog::LoadProfile() (constructed at every app startup for SSWCP; also the web UI's switch-model flow) read ~8000 profile JSON files strictly serially, stalling for seconds on first use.

Measured on a real run: 383 ms for 326 models / 796 machines / 2660 filaments / 2167 processes (previously a multi-second serial load).

GuideFrame::LoadProfileData() (setup wizard / "configure selectable
filaments") and WebPresetDialog::LoadProfile() (constructed at every
app startup for SSWCP; also the web UI's switch-model flow) read
~8000 profile JSON files strictly serially, stalling for seconds on
first use.

convention:

- the model/machine/filament/process per-file loops in both
  LoadProfileFamily copies run under tbb::parallel_for via a shared
  driver in src/slic3r/GUI/ProfileLoadUtil.hpp: parallel_load_items()
  fans work across workers (each writing only its own private result
  slot - no shared writes, no locks, no data races), and load_section()
  wraps it with an in-order serial merge that preserves the exact
  ordering and dedup ("first wins") semantics of the old serial code.
  Both dialogs now share one copy instead of two that had drifted.
- no exception control flow: json::parse(..., nullptr, false) +
  is_discarded(), type-checked field access before every conversion,
  json == "literal" comparisons, boost::filesystem error_code
  overloads. A malformed file or entry drops only itself instead of
  aborting the whole vendor family; anything unexpected still lands
  in the pre-existing family-level catch at the thread boundary
  (GetFilamentInfo retains its own internal try/catch, which never
  escapes the worker).
- workers touch shared nlohmann::json only through const references
  (non-const operator[] emplaces internally - a data race BBS's
  version has); GetFilamentInfo takes pFilaList by const reference.
  The whole-load m_ProfileJson_mutex hold that makes these unlocked
  reads safe is documented as a precondition at LoadProfileFamily.
- m_destroy is std::atomic<bool>, checked per work item and between
  vendor families (acquire/release) for fast cancel on dialog
  destruction.
- GuideFrame's load-completion callbacks are queued on the dialog's
  own wxEvtHandler::CallAfter instead of the app's: pending events on
  a handler are discarded when it is destroyed, closing a
  pre-existing use-after-free when the wizard is cancelled right as
  loading finishes (the post-EndModal ShowDownNetPluginDlg/login
  sites intentionally stay on the app queue - they must outlive the
  dialog and never dereference this).
- log hygiene: removed the full-json dumps and per-file content dumps;
  recoverable skips log at warning, per-item diagnostics at trace.

Measured on a real run: 383 ms for 326 models / 796 machines /
2660 filaments / 2167 processes (previously a multi-second serial load).
@LiuLikeQian
LiuLikeQian merged commit 2d10f4e into main Jul 21, 2026
1 check passed
zhangzhend0ng added a commit to zhangzhend0ng/OrcaSlicer that referenced this pull request Aug 20, 2026
The v3 upgrade commit missed three test files added later via upstream
merges (Snapmaker#599/Snapmaker#702) that still include the v2 header, and passed the
GNU-ld-only -Wl,--no-as-needed flag unconditionally, which Apple ld64
rejects. Test binaries also never configured libslic3r's runtime
environment, so resources_dir() stayed empty (bed-temperature suites
read an empty nozzle_info.json) and boost log lines polluted
catch_discover_tests' stdout-based test enumeration with bogus,
always-failing test entries.

- Migrate test_mixed_filament_color_golden / test_profile_load_util /
  test_bed_temperature to <catch2/catch_test_macros.hpp>
- Guard -Wl,--no-as-needed with if(UNIX AND NOT APPLE) in the five test
  CMakeLists (Linux behaviour unchanged; macOS skips, the
  test_nanosvg_impl OBJECT library still links unconditionally)
- Bootstrap the test runtime in tests/catch_main.hpp with two
  mechanisms of opposite timing requirements: a prioritised
  constructor(101) raises the log level before any static initialiser
  runs (writes only a constant-initialised enum + the boost::log
  singleton; MSVC has no prioritised ctors and falls back to a plain
  static object with unspecified ordering), and a Catch2
  testRunStarting listener sets resources_dir(TEST_RESOURCES_DIR)
  after all static init — assigning the non-trivial std::string any
  earlier gets wiped by its own constructor (verified in lldb)
- Drop fff_print's per-suite TestResources static initializer, which
  suffered exactly that static-init-order wipe
- Refresh the stale TestResources reference in sanitizer-tests.yml

Verified on macOS (GUI=OFF, BUILD_TESTS=ON, arm64): 356 tests register
cleanly (no log-line pollution), 353/356 pass. The 3 bed-temperature
failures are a pre-existing product bug, not a regression:
PrintConfigDef's constructor never calls init_filament_option_keys(),
so DynamicPrintConfig::set_num_filaments() is a silent no-op and
multi-extruder configs collapse to one extruder. Linux CI verification
still pending (workflows are manual-dispatch).

Co-authored-by: Claude <noreply@anthropic.com>
zhangzhend0ng added a commit to zhangzhend0ng/OrcaSlicer that referenced this pull request Aug 20, 2026
The v3 upgrade commit missed three test files added later via upstream
merges (Snapmaker#599/Snapmaker#702) that still include the v2 header, and passed the
GNU-ld-only -Wl,--no-as-needed flag unconditionally, which Apple ld64
rejects. Test binaries also never configured libslic3r's runtime
environment, so resources_dir() stayed empty (bed-temperature suites
read an empty nozzle_info.json) and boost log lines polluted
catch_discover_tests' stdout-based test enumeration with bogus,
always-failing test entries.

- Migrate test_mixed_filament_color_golden / test_profile_load_util /
  test_bed_temperature to <catch2/catch_test_macros.hpp>
- Guard -Wl,--no-as-needed with if(UNIX AND NOT APPLE) in the five test
  CMakeLists (Linux behaviour unchanged; macOS skips, the
  test_nanosvg_impl OBJECT library still links unconditionally)
- Bootstrap the test runtime in tests/catch_main.hpp with two
  mechanisms of opposite timing requirements: a prioritised
  constructor(101) raises the log level before any static initialiser
  runs (writes only a constant-initialised enum + the boost::log
  singleton; MSVC has no prioritised ctors and falls back to a plain
  static object with unspecified ordering), and a Catch2
  testRunStarting listener sets resources_dir(TEST_RESOURCES_DIR)
  after all static init — assigning the non-trivial std::string any
  earlier gets wiped by its own constructor (verified in lldb)
- Drop fff_print's per-suite TestResources static initializer, which
  suffered exactly that static-init-order wipe
- Refresh the stale TestResources reference in sanitizer-tests.yml

Verified on macOS (GUI=OFF, BUILD_TESTS=ON, arm64): 356 tests register
cleanly (no log-line pollution), 353/356 pass. The 3 bed-temperature
failures are a pre-existing product bug, not a regression:
PrintConfigDef's constructor never calls init_filament_option_keys(),
so DynamicPrintConfig::set_num_filaments() is a silent no-op and
multi-extruder configs collapse to one extruder. Linux CI verification
still pending (workflows are manual-dispatch).

Co-authored-by: Claude <noreply@anthropic.com>
zhangzhend0ng added a commit to zhangzhend0ng/OrcaSlicer that referenced this pull request Aug 20, 2026
The v3 upgrade commit missed three test files added later via upstream
merges (Snapmaker#599/Snapmaker#702) that still include the v2 header, and passed the
GNU-ld-only -Wl,--no-as-needed flag unconditionally, which Apple ld64
rejects. Test binaries also never configured libslic3r's runtime
environment, so resources_dir() stayed empty (bed-temperature suites
read an empty nozzle_info.json) and boost log lines polluted
catch_discover_tests' stdout-based test enumeration with bogus,
always-failing test entries.

- Migrate test_mixed_filament_color_golden / test_profile_load_util /
  test_bed_temperature to <catch2/catch_test_macros.hpp>
- Guard -Wl,--no-as-needed with if(UNIX AND NOT APPLE) in the five test
  CMakeLists (Linux behaviour unchanged; macOS skips, the
  test_nanosvg_impl OBJECT library still links unconditionally)
- Bootstrap the test runtime in tests/catch_main.hpp with two
  mechanisms of opposite timing requirements: a prioritised
  constructor(101) raises the log level before any static initialiser
  runs (writes only a constant-initialised enum + the boost::log
  singleton; MSVC has no prioritised ctors and falls back to a plain
  static object with unspecified ordering), and a Catch2
  testRunStarting listener sets resources_dir(TEST_RESOURCES_DIR)
  after all static init — assigning the non-trivial std::string any
  earlier gets wiped by its own constructor (verified in lldb)
- Drop fff_print's per-suite TestResources static initializer, which
  suffered exactly that static-init-order wipe
- Refresh the stale TestResources reference in sanitizer-tests.yml

Verified on macOS (GUI=OFF, BUILD_TESTS=ON, arm64): 356 tests register
cleanly (no log-line pollution), 353/356 pass. The 3 bed-temperature
failures are a pre-existing product bug, not a regression:
PrintConfigDef's constructor never calls init_filament_option_keys(),
so DynamicPrintConfig::set_num_filaments() is a silent no-op and
multi-extruder configs collapse to one extruder. Linux CI verification
still pending (workflows are manual-dispatch).

Co-authored-by: Claude <noreply@anthropic.com>
zhangzhend0ng added a commit to zhangzhend0ng/OrcaSlicer that referenced this pull request Aug 20, 2026
The v3 upgrade commit missed three test files added later via upstream
merges (Snapmaker#599/Snapmaker#702) that still include the v2 header, and passed the
GNU-ld-only -Wl,--no-as-needed flag unconditionally, which Apple ld64
rejects. Test binaries also never configured libslic3r's runtime
environment, so resources_dir() stayed empty (bed-temperature suites
read an empty nozzle_info.json) and boost log lines polluted
catch_discover_tests' stdout-based test enumeration with bogus,
always-failing test entries.

- Migrate test_mixed_filament_color_golden / test_profile_load_util /
  test_bed_temperature to <catch2/catch_test_macros.hpp>
- Guard -Wl,--no-as-needed with if(UNIX AND NOT APPLE) in the five test
  CMakeLists (Linux behaviour unchanged; macOS skips, the
  test_nanosvg_impl OBJECT library still links unconditionally)
- Bootstrap the test runtime in tests/catch_main.hpp with two
  mechanisms of opposite timing requirements: a prioritised
  constructor(101) raises the log level before any static initialiser
  runs (writes only a constant-initialised enum + the boost::log
  singleton; MSVC has no prioritised ctors and falls back to a plain
  static object with unspecified ordering), and a Catch2
  testRunStarting listener sets resources_dir(TEST_RESOURCES_DIR)
  after all static init — assigning the non-trivial std::string any
  earlier gets wiped by its own constructor (verified in lldb)
- Drop fff_print's per-suite TestResources static initializer, which
  suffered exactly that static-init-order wipe
- Refresh the stale TestResources reference in sanitizer-tests.yml

Verified on macOS (GUI=OFF, BUILD_TESTS=ON, arm64): 356 tests register
cleanly (no log-line pollution), 353/356 pass. The 3 bed-temperature
failures are a pre-existing product bug, not a regression:
PrintConfigDef's constructor never calls init_filament_option_keys(),
so DynamicPrintConfig::set_num_filaments() is a silent no-op and
multi-extruder configs collapse to one extruder. Linux CI verification
still pending (workflows are manual-dispatch).

Co-authored-by: Claude <noreply@anthropic.com>
zhangzhend0ng added a commit to zhangzhend0ng/OrcaSlicer that referenced this pull request Aug 21, 2026
The v3 upgrade commit missed three test files added later via upstream
merges (Snapmaker#599/Snapmaker#702) that still include the v2 header, and passed the
GNU-ld-only -Wl,--no-as-needed flag unconditionally, which Apple ld64
rejects. Test binaries also never configured libslic3r's runtime
environment, so resources_dir() stayed empty (bed-temperature suites
read an empty nozzle_info.json) and boost log lines polluted
catch_discover_tests' stdout-based test enumeration with bogus,
always-failing test entries.

- Migrate test_mixed_filament_color_golden / test_profile_load_util /
  test_bed_temperature to <catch2/catch_test_macros.hpp>
- Guard -Wl,--no-as-needed with if(UNIX AND NOT APPLE) in the five test
  CMakeLists (Linux behaviour unchanged; macOS skips, the
  test_nanosvg_impl OBJECT library still links unconditionally)
- Bootstrap the test runtime in tests/catch_main.hpp with two
  mechanisms of opposite timing requirements: a prioritised
  constructor(101) raises the log level before any static initialiser
  runs (writes only a constant-initialised enum + the boost::log
  singleton; MSVC has no prioritised ctors and falls back to a plain
  static object with unspecified ordering), and a Catch2
  testRunStarting listener sets resources_dir(TEST_RESOURCES_DIR)
  after all static init — assigning the non-trivial std::string any
  earlier gets wiped by its own constructor (verified in lldb)
- Drop fff_print's per-suite TestResources static initializer, which
  suffered exactly that static-init-order wipe
- Refresh the stale TestResources reference in sanitizer-tests.yml

Verified on macOS (GUI=OFF, BUILD_TESTS=ON, arm64): 356 tests register
cleanly (no log-line pollution), 353/356 pass. The 3 bed-temperature
failures are a pre-existing product bug, not a regression:
PrintConfigDef's constructor never calls init_filament_option_keys(),
so DynamicPrintConfig::set_num_filaments() is a silent no-op and
multi-extruder configs collapse to one extruder. Linux CI verification
still pending (workflows are manual-dispatch).
LiuLikeQian pushed a commit that referenced this pull request Aug 21, 2026
* test: upgrade test framework to Catch2 v3 and add CI pipelines

- Migrate from vendored Catch2 v2 (tests/catch2/catch.hpp) to FetchContent
  Catch2 v3 via cmake/catch2.cmake; update 43 test files to v3 headers
- Unify test CMake: TEST_LINK_LIBS, force-include catch_main.hpp, enable
  sla_print tests, fix headless linking with nanosvg_impl OBJECT library
- Add test-linux / sanitizer (ASan+UBSan) / coverage workflows, all manual
  trigger for now so they don't gate main or release branches
- Add cmake/sanitizers.cmake + cmake/coverage.cmake (opt-in, default OFF);
  SLIC3R_ASAN forwarded to ENABLE_ASAN with deprecation warning
- Add test tooling: run_tests.py, run_release_tests.bat, junit-to-html.js
- Add CTestConfig.cmake and a tests aggregate target

Kept out: production packaging changes (expat/NSIS) carried by the stale
ci-test base; dev tooling (.clangd / .clang-tidy / compile_commands export)
kept for a separate PR; GMP/MPFR link fix preserved in tests/fff_print.

* fix(tests): make Catch2 v3 suites build and run on macOS

The v3 upgrade commit missed three test files added later via upstream
merges (#599/#702) that still include the v2 header, and passed the
GNU-ld-only -Wl,--no-as-needed flag unconditionally, which Apple ld64
rejects. Test binaries also never configured libslic3r's runtime
environment, so resources_dir() stayed empty (bed-temperature suites
read an empty nozzle_info.json) and boost log lines polluted
catch_discover_tests' stdout-based test enumeration with bogus,
always-failing test entries.

- Migrate test_mixed_filament_color_golden / test_profile_load_util /
  test_bed_temperature to <catch2/catch_test_macros.hpp>
- Guard -Wl,--no-as-needed with if(UNIX AND NOT APPLE) in the five test
  CMakeLists (Linux behaviour unchanged; macOS skips, the
  test_nanosvg_impl OBJECT library still links unconditionally)
- Bootstrap the test runtime in tests/catch_main.hpp with two
  mechanisms of opposite timing requirements: a prioritised
  constructor(101) raises the log level before any static initialiser
  runs (writes only a constant-initialised enum + the boost::log
  singleton; MSVC has no prioritised ctors and falls back to a plain
  static object with unspecified ordering), and a Catch2
  testRunStarting listener sets resources_dir(TEST_RESOURCES_DIR)
  after all static init — assigning the non-trivial std::string any
  earlier gets wiped by its own constructor (verified in lldb)
- Drop fff_print's per-suite TestResources static initializer, which
  suffered exactly that static-init-order wipe
- Refresh the stale TestResources reference in sanitizer-tests.yml

Verified on macOS (GUI=OFF, BUILD_TESTS=ON, arm64): 356 tests register
cleanly (no log-line pollution), 353/356 pass. The 3 bed-temperature
failures are a pre-existing product bug, not a regression:
PrintConfigDef's constructor never calls init_filament_option_keys(),
so DynamicPrintConfig::set_num_filaments() is a silent no-op and
multi-extruder configs collapse to one extruder. Linux CI verification
still pending (workflows are manual-dispatch).
zhangzhend0ng added a commit to zhangzhend0ng/OrcaSlicer that referenced this pull request Aug 27, 2026
…aker#749)

* test: upgrade test framework to Catch2 v3 and add CI pipelines

- Migrate from vendored Catch2 v2 (tests/catch2/catch.hpp) to FetchContent
  Catch2 v3 via cmake/catch2.cmake; update 43 test files to v3 headers
- Unify test CMake: TEST_LINK_LIBS, force-include catch_main.hpp, enable
  sla_print tests, fix headless linking with nanosvg_impl OBJECT library
- Add test-linux / sanitizer (ASan+UBSan) / coverage workflows, all manual
  trigger for now so they don't gate main or release branches
- Add cmake/sanitizers.cmake + cmake/coverage.cmake (opt-in, default OFF);
  SLIC3R_ASAN forwarded to ENABLE_ASAN with deprecation warning
- Add test tooling: run_tests.py, run_release_tests.bat, junit-to-html.js
- Add CTestConfig.cmake and a tests aggregate target

Kept out: production packaging changes (expat/NSIS) carried by the stale
ci-test base; dev tooling (.clangd / .clang-tidy / compile_commands export)
kept for a separate PR; GMP/MPFR link fix preserved in tests/fff_print.

* fix(tests): make Catch2 v3 suites build and run on macOS

The v3 upgrade commit missed three test files added later via upstream
merges (Snapmaker#599/Snapmaker#702) that still include the v2 header, and passed the
GNU-ld-only -Wl,--no-as-needed flag unconditionally, which Apple ld64
rejects. Test binaries also never configured libslic3r's runtime
environment, so resources_dir() stayed empty (bed-temperature suites
read an empty nozzle_info.json) and boost log lines polluted
catch_discover_tests' stdout-based test enumeration with bogus,
always-failing test entries.

- Migrate test_mixed_filament_color_golden / test_profile_load_util /
  test_bed_temperature to <catch2/catch_test_macros.hpp>
- Guard -Wl,--no-as-needed with if(UNIX AND NOT APPLE) in the five test
  CMakeLists (Linux behaviour unchanged; macOS skips, the
  test_nanosvg_impl OBJECT library still links unconditionally)
- Bootstrap the test runtime in tests/catch_main.hpp with two
  mechanisms of opposite timing requirements: a prioritised
  constructor(101) raises the log level before any static initialiser
  runs (writes only a constant-initialised enum + the boost::log
  singleton; MSVC has no prioritised ctors and falls back to a plain
  static object with unspecified ordering), and a Catch2
  testRunStarting listener sets resources_dir(TEST_RESOURCES_DIR)
  after all static init — assigning the non-trivial std::string any
  earlier gets wiped by its own constructor (verified in lldb)
- Drop fff_print's per-suite TestResources static initializer, which
  suffered exactly that static-init-order wipe
- Refresh the stale TestResources reference in sanitizer-tests.yml

Verified on macOS (GUI=OFF, BUILD_TESTS=ON, arm64): 356 tests register
cleanly (no log-line pollution), 353/356 pass. The 3 bed-temperature
failures are a pre-existing product bug, not a regression:
PrintConfigDef's constructor never calls init_filament_option_keys(),
so DynamicPrintConfig::set_num_filaments() is a silent no-op and
multi-extruder configs collapse to one extruder. Linux CI verification
still pending (workflows are manual-dispatch).
@LuckZAE
LuckZAE deleted the perf_profile_loading branch August 28, 2026 09:01
LiuLikeQian added a commit that referenced this pull request Sep 1, 2026
* fix(login): stop token extraction at first '?', '&' or '#' in callback URL (#741)

* Fix the issue where device 1 was not mounted, resulting in no model execution of consumable data synchronization. The synchronization was set to 0 consumables and then adding new consumables triggered a crash. (#740)

* fix: stay on Preview when re-dropping the same G-code file (#732)

* fix: stay on Preview when re-dropping the same G-code file

Re-dropping the same G-code file onto the window stranded the UI on the
(empty) 3D editor, so the already-loaded G-code preview looked like it
had disappeared.

PlaterDropTarget::OnDropFiles unconditionally switched to the 3D editor
before calling load_files. On a repeat drop, Plater::load_gcode then
early-returns via its same-file guard (m_last_loaded_gcode == filename
&& m_only_gcode) and never reaches its select_tab(tpPreview), leaving
the user on the 3D editor with an empty bed.

Fix in two parts:
- Only force the 3D editor when not already in only-gcode mode, so a
  repeat G-code drop does not yank the user off the Preview tab. Model
  drops and the first G-code drop are unaffected (only_gcode_mode() is
  false for them).
- After load_files, if we are in only-gcode mode, ensure the Preview tab
  is selected. No-op on a fresh load (load_gcode already switches), but
  guarantees we land on Preview when load_gcode no-ops on a repeat drop.

* fix: move same-file G-code view restore into load_gcode guard

Follow-up to 21a68ae945 ("fix: stay on Preview when re-dropping the same
G-code file"). That commit's post-load check in
PlaterDropTarget::OnDropFiles keyed off only_gcode_mode() after
load_files() returned, but that flag does not mean "we just handled a
G-code drop": on the 3MF "Load Geometry Only" path (open_3mf_file ->
priv::load_files) nothing resets m_only_gcode, so the flag stays
stale-true. Dropping a 3MF in only-gcode mode ended with
priv::load_files() switching to the 3D editor to show the loaded model,
only for the stale-flag check to yank the user back to the empty Preview
tab. The model became invisible, and since m_only_gcode was still set,
clicking Prepare offered the "will be closed before creating a new
model" confirm whose new_project() then discarded the model.

Restructure so each load path owns its final view:

- Plater::load_gcode: split the compound early-return guard. The
  not-a-G-code branch still returns silently, but the same-file guard
  (m_last_loaded_gcode == filename && m_only_gcode) now selects the
  Preview tab and preview panel before returning, mirroring the normal
  load path (select_tab(tpPreview) + set_current_panel(preview, true) +
  render()). "Re-opening the already-loaded G-code leaves you looking at
  it" is now an invariant of load_gcode itself, so every caller (drag &
  drop, File > Open G-code, file association) benefits.

- PlaterDropTarget::OnDropFiles: remove the post-load
  select_view_3D("Preview") check, which was the regression source (it
  also never ran for the early-returning SVG branch). The pre-load
  3D-editor switch stays gated on !only_gcode_mode() to avoid flashing
  the empty 3D editor; its comment is updated because load_gcode's guard
  now does switch back to Preview.

Behavior in only-gcode mode after this change: repeat-dropping the same
G-code stays on Preview; dropping a different G-code lands on Preview;
dropping a 3MF as geometry lands on the 3D editor with the model
visible (previously bounced back to Preview); dropping an STL still
shows "Cannot add models when in preview mode!" and stays on Preview.

* Fix ini bug from sentry (#750)

* fix empty hint bug

* fix crash when slicering

* test: upgrade test framework to Catch2 v3 and add CI pipelines (#749)

* test: upgrade test framework to Catch2 v3 and add CI pipelines

- Migrate from vendored Catch2 v2 (tests/catch2/catch.hpp) to FetchContent
  Catch2 v3 via cmake/catch2.cmake; update 43 test files to v3 headers
- Unify test CMake: TEST_LINK_LIBS, force-include catch_main.hpp, enable
  sla_print tests, fix headless linking with nanosvg_impl OBJECT library
- Add test-linux / sanitizer (ASan+UBSan) / coverage workflows, all manual
  trigger for now so they don't gate main or release branches
- Add cmake/sanitizers.cmake + cmake/coverage.cmake (opt-in, default OFF);
  SLIC3R_ASAN forwarded to ENABLE_ASAN with deprecation warning
- Add test tooling: run_tests.py, run_release_tests.bat, junit-to-html.js
- Add CTestConfig.cmake and a tests aggregate target

Kept out: production packaging changes (expat/NSIS) carried by the stale
ci-test base; dev tooling (.clangd / .clang-tidy / compile_commands export)
kept for a separate PR; GMP/MPFR link fix preserved in tests/fff_print.

* fix(tests): make Catch2 v3 suites build and run on macOS

The v3 upgrade commit missed three test files added later via upstream
merges (#599/#702) that still include the v2 header, and passed the
GNU-ld-only -Wl,--no-as-needed flag unconditionally, which Apple ld64
rejects. Test binaries also never configured libslic3r's runtime
environment, so resources_dir() stayed empty (bed-temperature suites
read an empty nozzle_info.json) and boost log lines polluted
catch_discover_tests' stdout-based test enumeration with bogus,
always-failing test entries.

- Migrate test_mixed_filament_color_golden / test_profile_load_util /
  test_bed_temperature to <catch2/catch_test_macros.hpp>
- Guard -Wl,--no-as-needed with if(UNIX AND NOT APPLE) in the five test
  CMakeLists (Linux behaviour unchanged; macOS skips, the
  test_nanosvg_impl OBJECT library still links unconditionally)
- Bootstrap the test runtime in tests/catch_main.hpp with two
  mechanisms of opposite timing requirements: a prioritised
  constructor(101) raises the log level before any static initialiser
  runs (writes only a constant-initialised enum + the boost::log
  singleton; MSVC has no prioritised ctors and falls back to a plain
  static object with unspecified ordering), and a Catch2
  testRunStarting listener sets resources_dir(TEST_RESOURCES_DIR)
  after all static init — assigning the non-trivial std::string any
  earlier gets wiped by its own constructor (verified in lldb)
- Drop fff_print's per-suite TestResources static initializer, which
  suffered exactly that static-init-order wipe
- Refresh the stale TestResources reference in sanitizer-tests.yml

Verified on macOS (GUI=OFF, BUILD_TESTS=ON, arm64): 356 tests register
cleanly (no log-line pollution), 353/356 pass. The 3 bed-temperature
failures are a pre-existing product bug, not a regression:
PrintConfigDef's constructor never calls init_filament_option_keys(),
so DynamicPrintConfig::set_num_filaments() is a silent no-op and
multi-extruder configs collapse to one extruder. Linux CI verification
still pending (workflows are manual-dispatch).

* fix: add wasm and otf MIME types to HttpServer (#751)

* Safeguard EdgeGrid.hpp (#752)

Co-authored-by: RF47 <162915171+RF47@users.noreply.github.com>

* fix: use literal format string for visibility icon in GCodeViewer legend (#756)

ImGui::Text() is a printf-style API. Passing the icon glyph string directly
as the format argument is a format-string misuse (-Wformat-security) and
would misrender if the string ever contained '%'. The extra ImVec2 argument
matched no Text() overload and was silently ignored by vsnprintf, so drop
it. No visual change.

* fix: crash in solve_extruder_order due to out-of-bounds access (Sentry #7256025247) (#754)

* add include file

* fix sentry bug in func Slic3r::solve_extruder_order

Root Cause: Array out-of-bounds cache.
Fix: Check bounds at the start of the function and return the initial value if out of bounds.

---------

Co-authored-by: lujiaxin <1091917314qq.com>

* fix: first layer height should not override variable layer height profile (#757)

A differing first layer height must not force regeneration of the layer height profile: doing so discards a valid variable layer height profile (e.g. loaded from a 3MF) and replaces it with a fixed-height profile. The first layer height is applied separately in generate_object_layers().

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* Fix crashes reported by Sentry during GUI shutdown/recreation (#753)

* fix: prevent crash on language switch during slicing via reentrancy guard

During GUI_App::recreate_GUI(), ProgressDialog::Update() internally calls
YieldFor(wxEVT_CATEGORY_UI), which dispatches pending wxCommandEvents
including on_slicing_completed. When this handler runs during GUI
reconstruction, it accesses model data that is in an inconsistent state
after mainframe->shutdown()->reset_canvas_volumes(), causing an access
violation in transformed_non_sinking_bounding_box().

- Guard on_slicing_completed with is_recreating_gui() to skip scene
  updates during GUI rebuild.
- Add bounds checking in transformed_non_sinking_bounding_box() as
  defense-in-depth against stale volume indices.
- Gate check_outside_state() entry on is_recreating_gui() to protect
  all volume iteration paths.

* fix: add null guards in bitmap creation and GCodeViewer progress dialog

- create_scaled_bitmap(): fall back to mainframe when win is null,
  preventing EXCEPTION_ACCESS_VIOLATION during UI refresh after
  background processing (SNAPMAKER_ORCA-NBQ)

- GCodeViewer::load_toolpaths(): verify mainframe exists before
  updating the progress dialog to avoid use-after-free when the
  parent window is destroyed during loading (SNAPMAKER_ORCA-NBV)

* fix(login): capture token when github oauth callback returns raw json (#758)

* fix(login): capture token when github oauth callback returns raw json

The oauth callback endpoint may answer 200 with the token json as the
page body instead of redirecting to a url containing "token=", which is
the only format OnNavigationRequest understands. The webview then shows
the raw json on screen and login never completes.

Poll the webview url for /api/oauth2/callback/ (WebView2 does not
reliably deliver navigation events for that hop), read the body with a
fire-and-forget script that smuggles it out through document.title, and
re-load the login host with ?token= so the existing capture path in
OnNavigationRequest completes the login. The poll is capped at 30s and
never blocks: wxWebView::RunScript would busy-pump the event loop on
every backend and freeze the app when the web process is dead.

* fix(login): parse oauth callback body without exceptions

The poll timer may fire while the callback page is still rendering, so
the smuggled title can carry an empty or partial body. json::parse then
throws parse_error inside the wx event handler and terminates the app
(seen crashing on macOS). Switch to the no-throw parse variant and
validate the structure (is_discarded / is_object / field types) before
using the token; an unreadable body just waits for the next poll.

* fix gcode preview bug (#765)

* feat: extract foreground change subscription from feature_wcp_systeminfo (#767)

Cherry-pick only the screen-off / foreground-change fix (for MQTT
disconnection when display turns off) from feature_wcp_systeminfo
commits 8f4da34 + fc777a0, dropping the unrelated sw_GetSystemInfo
interface (MAC address / OS info) that was mixed into 8f4da34.

- GUI_App: m_foreground_change_subscribers map + notify_foreground_change()
- MainFrame: NotifyActivateChange() on wxEVT_ACTIVATE, Windows session
  lock/unlock (WM_WTSSESSION_CHANGE) and console display on/off/dimmed
  (WM_POWERBROADCAST) notifications
- SSWCP: sw_SubscribeForegroundChange command (event_id=205890) handled
  at top of process() so event_id is written into m_header before
  subscribing; cleanup in sw_UnsubscribeAll / sw_Webview_Unsubscribe /
  on_webview_delete

* feat(sswcp): add sw_UpdateDeviceInfo, remove blocking query_machine_info from set_engine (#768)

* fix(tests): relax find_package(Qhull) to QUIET like the main build (#772)

Tests link Qhull through the in-tree 'qhull' interface target from
TEST_LINK_LIBS, so the QhullConfig.cmake discovery in each test
directory is redundant. With REQUIRED it hard-fails configuration
when the deps prefix ships no installed Qhull config (e.g. older
prebuilt OrcaSlicer_dep packages) even though the main build falls
back to the bundled sources fine. Align with deps_src/qhull and use
find_package(Qhull 7.2 QUIET).

* Feature:Add unified selected-object highlight rendering (#764)

* Feature highlight object (#746)

* feat: implement unified selection silhouette highlight with dual-FBO mask and stencil fallback

Replace the per-GLVolume depth-texture outline with a unified screen-space
approach that renders all selected volumes into a shared multisampled mask,
then composites a coverage-aware fill and a 2 px hard outline over the
finished scene without Gaussian blur.

Key changes:

- Add 4 new fragment shaders (110/140): selection_mask.fs and
  selection_composite.fs. The mask shader outputs flat coverage with
  alpha=1.0; the composite shader reads the resolved mask texture and
  emits anti-aliased fill (coverage × fillAlpha) plus a binary 2 px
  circular-neighbourhood outline to the default framebuffer.

- GLCanvas3D: introduce SelectionHighlightResources (dual FBO:
  4× MSAA RGBA8 color renderbuffer + RGBA8 resolve texture, no
  depth/stencil) and ESelectionHighlightMode (Disabled /
  UnifiedFramebuffer / StencilFallback).

- Implement Save/Restore helpers for the Mask, Composite, and Stencil
  passes, each capturing and restoring the full set of persistent GL
  state affected by that pass. Both ARB and EXT framebuffer paths are
  supported.

- EnsureSelectionHighlightResources(): lazily creates cross-API FBO
  resources and re-creates them only on canvas resize. Validates
  GL_RENDERBUFFER_SAMPLES and glCheckFramebufferStatus for both APIs.

- RenderSelectionHighlightMask(): binds the MSAA FBO, clears to
  transparent, draws selected opaque and transparent volumes through
  the mask shader, then resolves to the resolve texture with
  glBlitFramebuffer / glBlitFramebufferEXT.

- CompositeSelectionHighlight(): disables depth test, enables alpha
  blend, binds the resolve texture, and draws the background fullscreen
  quad with the composite shader to overlay fill and outline onto the
  finished scene.

- RenderSelectionStencilFallback(): when the unified framebuffer path
  is unavailable, uses the default framebuffer stencil attachment with
  a model-space 1.02× scale to draw an occlusion-dependent outline.

- ResolveSelectionHighlightMode(): selects UnifiedFramebuffer when FBO
  support, 4× MSAA capability, and both shaders are present; falls back
  to StencilFallback when GL_STENCIL_BITS > 0 and the mask shader is
  available; degrades to Disabled otherwise.

- Runtime capability checks: queries GL_MAX_SAMPLES (ARB or EXT),
  validates GL_STENCIL_BITS, and logs degradation paths once.

- Register selection_mask (flat.vs + selection_mask.fs) and
  selection_composite (background.vs + selection_composite.fs) in
  GLShadersManager.

Design constraints:
- Mask FBO has no depth/stencil attachment — only a color buffer.
- Fill preserves continuous MSAA-resolved coverage (no sign/step).
- Outline is a hard 2 px edge in framebuffer space (no DPI scaling).
- Both fill and outline composite after the main scene and are always
  visible (no depth testing), matching the requirement for
  see-through-occlusion behaviour.
- Old render_with_outline() and Gouraud depth-texture outline code
  are preserved but no longer used as the fallback; they will be
  removed in a follow-up cleanup.

* feat: widen selection outline to 4px with separable 4+4 max dilation

Replace the single-pass radius-2 circular dilation in the selection
composite shader with a two-pass separable max dilation (horizontal
radius 4 into a dedicated band, then vertical radius 4), producing a
~4px-wide outline at ~18 taps/pixel instead of the ~49 taps a radius-4
circular kernel would need; corners are squarer (Chebyshev kernel).

- Add selection_dilate.fs (110/140): horizontal max dilation over the
  resolved mask into a reusable dilation texture.
- selection_composite.fs (110/140): vertical max dilation over the
  dilated band with early-out once the band is hit.
- GLCanvas3D: add a dilation FBO/texture to the selection highlight
  resources, wire its lifecycle for both ARB and EXT framebuffers, gate
  the Unified path on the new shader, and run the horizontal pass inside
  CompositeSelectionHighlight.
- GLShadersManager: register the selection_dilate shader.

* feat: render selection outline as edge extraction plus Gaussian glow at reduced resolution

Replace the single-pass circular-dilation outline with a multi-pass
edge-detection and blurred-glow pipeline to get a soft ~4px outline.

Mask pass:
- Render selected volumes into a full-resolution mask texture, then
  downsample it to half resolution with the gaussian shader (radius 0).

Outline/glow passes (replaces DilateSelectionMaskHorizontal):
- selection_edge.fs: Sobel-style gradient magnitude on the half-res mask
  produces a thin edge band.
- selection_gaussian.fs: two-pass separable Gaussian blur; edge is blurred
  at half resolution, glow is downsampled to quarter resolution first for
  a wide soft falloff.
- selection_composite.fs: separate fill / outline / additive-glow passes;
  outline uses smoothstep exclusion to keep the band outside the fill and
  renders a fixed orange color instead of the canvas-type color.

Resources:
- Add six texture-backed FBOs (full-res mask, mask, edge temp/final,
  glow temp/final) with shared ARB/EXT framebuffer helpers and viewport
  save/restore.

Remove the previous selection_dilate shader and its registration.

* refactor: composite selection highlight in a single pass

Merge the fill, edge, and glow passes of the selection highlight into
one draw call by precomposing normal-alpha fill and edge followed by
additive glow inside the shader, removing the render_fill/render_glow
branches and the extra blend-mode switches.

* refactor: composite selection highlight fill, edge and glow in one pass

Merge the fill, edge, and glow passes of the selection highlight into a
single draw call. The shader now precomposes normal-alpha fill and edge
followed by additive glow, removing the render_fill/render_glow branches
and the extra blend-mode switches in GLCanvas3D.

* refactor: remove legacy selected-object outline rendering

Remove the deprecated "Show Selected Outline (beta)" feature, including
the depth-texture silhouette detection in the gouraud shader,
GLVolume::render_with_outline, the show_outline app-config flag, and the
corresponding menu entry. It is superseded by the new selection
highlight pipeline based on mask/edge/glow textures.

* fix: harden GL state save/restore and make selection highlight shaders optional

- Save/restore texture unit 0 binding and active texture in mask render state
- Use GL_FRAMEBUFFER(_EXT) instead of split draw/read framebuffer bindings
- Load selection highlight shaders as optional with warning instead of failing init
- Ignore local planning docs in .gitignore

* feat: keep selection highlight visible while a gizmo is running

Remove the m_gizmos.is_running() gate from ResolveSelectionHighlightMode()
and _render_selection() so the selection highlight is no longer suppressed
while a gizmo (move/rotate/scale, etc.) is active.

* refactor: simplify selection highlight checks and reduce GL state churn

- Drop redundant framebuffer support checks; rely on m_selectionFramebufferAvailable
- Release selection highlight resources after restoring previous GL bindings
- Keep gaussian shader active across the four blur passes

* refactor: precompute selection blur kernel on CPU and cut shader fetches

- Replace per-pixel Gaussian PDF evaluation and normalization in
  selection_gaussian.fs with CPU-built normalized sample uniforms
- Merge symmetric taps through bilinear offsets to reduce texture fetches
  per fragment, with fallback to the original nine-fetch kernel
- Factor the four blur passes and mask downsample into the shared
  RenderSelectionGaussianPass() helper
- Rename edge/glow temp targets to edgeBlurPingPong/glowBlurPingPong

* Fix selection mask downsampling at odd resolutions

Use adaptive area filtering when downsampling the full-resolution selection mask to avoid sampling phase drift at non-even canvas sizes. Keep the existing half-resolution edge detection and blur pipeline.

* fix: hide selection bounding box while gizmos are active

Keep the framebuffer selection highlight visible while skipping the
legacy selection bounding box during support, seam, painting, and
fuzzy-skin gizmo operations.

* fix(3mf): write Snapmaker_Orca application tag instead of BambuStudio (#762)

The 3MF Application metadata was written as "BambuStudio-<version>",
so other forks (e.g. upstream Orca Slicer) identified our projects as
Bambu projects. Write "Snapmaker_Orca-<version>" instead.

Also fix the version parse offset for the "Snapmaker_Orca-" prefix
(substr(11) -> substr(15)) so the generator version is read back
correctly from our own files.

* feat: render official filament gradients bottom-to-top (#778)

* feat: support vertical gradients for official filament colors

Render official filament gradients from bottom to top across color
swatches and filament synchronization views.

Normalize non-zero color mode values to gradient while persisting only
the supported segment and gradient modes.

Add optional TD value parsing and data for Full Spectrum filament SKUs.

* fix: render design-side color bar at top-half height to show full gradient range

The above-filament swatch in the sync dialog was generated at full card
height and then clipped to the top half, so gradient stops mapped to the
clipped lower portion were never visible. Generate the bitmap at the
top-half (splitY) height instead so the complete color range appears in
the visible area.

* fix: resolve tree-support slicing stall at 70% when base pattern spacing is 0 (#728)

- Root cause: when the effective support_base_pattern_spacing is 0 (per-object
  override or global default), the bed-contacting support base (layer 0, no
  raft) computed spacing = support_base_pattern_spacing * support_density = 0.
  This drove FillConcentric's while(!last.empty()) convergence loop into an
  infinite spin: distance=0 makes offset2_ex(last, -(0+0), +0) a no-op, so the
  polygon never shrinks. One worker burned 100% CPU while its peers blocked at
  the tbb::parallel_for barrier, stalling slicing at 70%.
- Fix: on the bed-contacting base layer, use ipRectilinear (which has no
  offset-convergence loop) instead of ipConcentric, and real flow spacing
  (always > 0) instead of the density-scaled pattern spacing.
- Verified with a per-iteration probe log: area_ratio stayed at 1.0 from
  i=1000 to i=1999 on the failing call; all other calls (distance != 0)
  converged normally.
- Ports upstream OrcaSlicer d2ca5d3a1e (#13454).

* fix: crash when switching to Filament view after importing upstream OrcaSlicer G-code (#743)

* fix: recognize upstream OrcaSlicer G-code on import

- Add "generated by OrcaSlicer" to GCodeProcessor::Producers so the embedded
  config block is parsed again instead of leaving extruders_count at 0
  (which rejected every T command and crashed the Filament view legend)
- Extend the load_from_gcode_file header whitelist with the matching prefix;
  the whitelist and the producer list must stay in sync, otherwise the whole
  import is aborted with "Not a gcode file generated by ..."
- Skip thumbnail blocks without a matching config option (only thumb0/thumb1
  are defined) with a warning instead of aborting the import: upstream
  OrcaSlicer gcode may carry more than two thumbnails

* fix: guard Filament view legend against degenerate gcode results

- Clamp the last_color table to max(1, extruders_count) bounded by the
  available tool colors, and route all color/volume lookups in
  generate_partial_times through bounds-checked helpers with gray/zero
  fallbacks
- Covers the last_color reads for PausePrint/ColorChange items, the
  last_color update, and used_filaments/m_filament_diameters indexing, so
  results with extruders_count == 0 or custom gcode referencing missing
  extruders can no longer trigger out-of-bounds reads when switching to
  the Filament view

* Feat: render lod system (#737)

* [Feat]: render_optimize, add LODSystem to rendering

* [Draft]: delete debug log code

* [Refactor]: remove enable_lod preference, make LOD always-on

Remove the "Improve rendering performance by LOD" preference item and
its enable_lod config plumbing. LOD rendering is now always enabled,
still gated by the low-memory and macOS-15 runtime guards.

* [Refactor]: fix IsMacVersion15 PascalCase naming convention

* [Fix]: macOS build error in CpuMemory - use Mach API instead of Linux sysinfo

sys/sysinfo.h is Linux-only and sysconf(_SC_AVPHYS_PAGES) is unsupported on
macOS. Split the __APPLE__ branch out from __linux__ and query free memory
via host_statistics64 (vm_statistics64) instead.

* [Fix]: close data race between background LOD simplification and rendering

SimplifyMesh() ran its detached worker thread straight into
GLModel::init_from() on the shared LOD model, while the main render
thread could concurrently call is_initialized()/set_color()/render()
on the same object — render() lazily uploads the very vectors that
init_from() is overwriting. This violates the threading contract
documented in GLModel.hpp ("use disable_render()/enable_render() when
initializing from outside the main thread") and is undefined behavior.
On large meshes, where simplification spans many frames, it shows up
as transient rendering artifacts or, rarely, crashes.

Fix, in three parts:

- load_object_volume() creates each LOD model render-disabled, with a
  shared_ptr<std::atomic<bool>> readiness flag created alongside it.

- The worker thread performs init_from() while the model is
  render-disabled (exclusive access), then stores ready=true with
  memory_order_release as its last touch of the object.

- The main thread runs promote_ready_lod_models() every frame from
  GLVolumeCollection::render(): an acquire load that, once the flag is
  set, calls enable_render() to take over the model. All render sites
  (render_with_outline depth pass, simple_render, the fallback debug
  log) now gate on !is_render_disabled() && is_initialized(), so a
  not-yet-ready LOD model falls back to the full-resolution mesh.

Volumes that share a LOD model via g_meshVolumesMap now share the
readiness flags too, so every holder can complete the handoff on its
own instead of depending on the first volume staying alive.

Visible behavior: LOD models activate only after they are fully
initialized (no half-built geometry can reach the GPU); until then the
original mesh renders. No other visual change.

Not addressed here (tracked separately): the detached-thread hazard at
app exit, and the dangling GLVolume*/TriangleMesh* entries accumulated
in g_meshVolumesMap.

* [Fix]: fix dangling pointers in the LOD mesh sharing map

g_meshVolumesMap accumulated tombstones: release_volume() existed but
had no callers, so every deleted GLVolume stayed registered as a
dangling pointer. The next volume loading the same mesh dereferenced
the dead object (*(volumes.begin()) followed by copying its
shared_ptr members) — a use-after-free that can resurrect destroyed
shared_ptrs and increment freed control blocks, i.e. heap corruption.

The key was a raw TriangleMesh* owned elsewhere: once the mesh was
freed, a new allocation reusing that address would falsely "share"
the previous mesh's LOD models, silently rendering another object's
simplified geometry at Middle/Small LOD.

Fix:

- The map value becomes MeshLodEntry { shared_ptr<const TriangleMesh>
  mesh; std::set<GLVolume*> volumes; }. The entry holds an owning
  reference to the mesh, so the raw pointer used as lookup key can
  never dangle or be reused by an unrelated mesh while the entry
  exists.

- Both volume deletion paths now unregister first:
  GLVolumeCollection::clear() and the direct delete in
  GLCanvas3D::reload_scene call release_volume() before delete. The
  entry — and its mesh reference — dies with its last volume.

Behavior note: reloading a mesh after its last volume is gone now
re-runs the simplification instead of "reusing" it through the stale
tombstone. LOD results remain cached as long as at least one volume
references the mesh, which covers instance duplication and the
cross-canvas sharing cases.

Also: move the platform headers in CpuMemory.cpp (windows.h,
sys/sysinfo.h, mach/*) outside namespace Slic3r — including system
headers inside a namespace places their declarations into it and
breaks with SDK changes.

* [Chore]: downgrade LOD logs from warning to info/debug

The LOD feature commits emitted every message at warning level,
but none of them indicate a fault — they are normal-flow
information: per-volume model creation, simplification results
(including expected quality fallbacks), and render-level
telemetry. At warning they pollute the log and drown real
warnings during scene loads and zoom gestures.

Split by frequency, following existing conventions in this file
("Loading print object toolpaths ..." is debug, one-shot load
events are info):

- info: one-shot / low-frequency lifecycle messages
  ("LOD: Creating simplified models", "LOD: Disabled for",
  "LOD simplify: completed successfully", "skipped init",
  "rejected (too few faces)", "rejected (out of AABB bounds)")
- debug: render-loop telemetry — the every-180-frames
  SMALL/MID/HIGH fallback prints and the zoom-driven
  "LOD level changed", which can fire many times per second
  during a zoom gesture.

11 call sites in 3DScene.cpp, severity only — no message text
changed.

* fix: crash slicing multi-material 3MF with raft after disabling supports (#784)

* fix: validate extrusion entity endpoints when chaining support entities

- chain_and_reorder_extrusion_entities() filtered unusable entities with an
  unchecked static_cast<ExtrusionEntityCollection*>(entity)->empty(), which
  dereferences nullptr entries and misses empty nested children; replace it
  with recursive endpoint validation (port of upstream OrcaSlicer PR #14074)
- make_perimeter_and_infill() now also receives direct paths, so check the
  entity type before testing the collection for emptiness
- add Catch2 regression tests for the chaining filter

* fix: guard enum choice value against invalid combobox selection

- Choice::get_value() indexed enum_values with the raw combobox selection;
  when Tab::toggle_options() rebuilds the enum list, a stale value (e.g. a
  tree support style left over after supports were disabled) may no longer
  be present, the selection stays wxNOT_FOUND and the lookup reads out of
  bounds
- restore a valid selection after the rebuild and clamp the index in
  get_value, falling back to the first enum entry

* fix: skip wipe tower raft-gap layer insert when next layer has no extruders

- fill_wipe_tower_partitions() inserts a wipe tower layer into the raft gap
  and copies lt_next.extruders.front(); on multi-material projects sliced
  once with supports enabled and then again with supports disabled, the
  layer above the insertion point can carry no extruders, so front()
  dereferences a null begin and crashes (0xC0000005 read of nullptr)
- skip the insertion for such layers and guard the m_layer_tools[j] access
  that would run out of range when no layer sits above the new print_z

* test: drop ShortestPath regression tests

Remove the test_shortest_path.cpp cases and their CMake mounting; the
regression they covered is superseded by existing slicing behavior and
the CI matrix does not need the extra suite.

* fix filament load path error. (#729)

* fix filament load path error.

* feature update the install for win.

* revert the changed for win nsi.

* fix: fall back to legacy color picker for incompatible filament presets (#795)

- Strip '@' suffix in GetFilamentMatchName so names like "PLA @vendor"
  match the color library entry "PLA"
- In ChangeExtruderColor, fall back to the legacy wx color dialog when
  the current filament preset is missing or not compatible with the
  active printer, instead of opening the Snapmaker color library dialog

* Feature high flow merge (#794)

* Feature high flow 0710 (#720)

* Added high-flow template parameters and related interfaces.

* Added "filament_flow_step_size", completing the reading mechanism for filament configuration.

* Preset changes and adapt for high_flow saving.

* Add a new template function named "get_value_at".

* feat: align filament_volume_type per filament and migrate it to coEnums.

* feat: add per-extruder nozzle_volume_type (standard / high_flow).

* feat-flow: support filament_max_volumetric_speed persistence, parsing, and G-code generation.

* feat: high-flow filament grouping, flow combo, and type adaptation

- Add FilamentVolumeType enum with to_string/from_string conversions
- Add filament_volume_type / nozzle_volume_type as coEnums in config system
- Add per-nozzle flow combo in sidebar; declare high flow for U1 0.4
- Add flow-type helper facade (FlowTypeHelper), high-flow compat checker (HighFlowCompat)
- Add slice-mode hover popup on slice button (SliceModePopup)
- Add custom filament grouping dialog with drag-and-drop (FilamentGroupDialog)
- Gate slicing behind grouping dialog in custom mode
- Add zh_CN translations for high-flow grouping UI
- Add filament_grouping_mode config option and grouping constants
- Fix: enable flow combo via vendor version bump
- Fix: decouple grouping from nozzle combos
- Fix: rebuild nozzle UI after diameter switch
- Fix: swap button uses SVG icon without gray background
- Fix: remove duplicate nozzle_volume_type registration
- Fix: FlowTypeHelper uses coEnums instead of coStrings for nozzle_volume_type
- Fix: FilamentGroupDialog uses FilamentVolumeType enum internally
- Add test_flow_type for enum conversion validation

* Batch modification of "process" parameters to support high-volume parameter access.

* Update consumable files.

* feat-flow: support standard and high-flow filament parameter variants

- add shared helpers for resolving filament parameters by nozzle flow type
- preserve standard and high-flow values during preset composition
- update slicing, G-code, calibration, and GUI consumers
- prevent calibration saves from overwriting other flow variants

* The process configuration file "process" and "machine"  added high-flow parameters.

* Add to snapmaker.json file.

* The filament file in the process configuration file section has added high-flow parameters.

* feat-flow: support floats-or-percents option fields

- create text controls for coFloatsOrPercents options
- support indexed default-value display and value parsing
- read and write individual float-or-percent vector elements
- preserve percentage values during GUI updates
- log unsupported option types instead of throwing an exception

* Delete a few unnecessary process files.

* feat-flow: serialize only active filament flow variant values in G-code.

* feat-flow: warn about incompatible nozzle flow types in newer 3MF files

Detect filament_extruder_map when loading a 3MF created by a newer
Snapmaker Orca version and display a compatibility warning.

Add the corresponding Simplified Chinese translation.

* feat: SSWCP flow type protocol, nozzle flow sync, and resolve_machine_info

Add SSWCPProtocol parsing unit with flow type normalization, filament/nozzle
flow type exposure, query_machine_info refactor with nozzle flow synchronization,
and resolve_machine_info field-priority merge replacing all query_machine_info
call sites.

Key changes:
- SSWCPProtocol: flow type parsing, normalize_machine_model, parse_extruder_nozzle_info
- resolve_machine_info: parallel system_info + objects.query, 3-state ResolveResult
- 3 call sites refactored (sw_mqtt_set_engine, nozzle sync, filament sync)
- parse_extruder_nozzle_info: leave volume_types empty when firmware lacks flow
  field, so user-configured high_flow is never overwritten on old firmware
- FlowTypeHelper: nozzle volume type support
- PresetBundle: connect_machine_info_list for cached nozzle slots
- MachineIPType: lock_guard exception safety
- Unit tests: 8 cases, 67 assertions
- Documentation: design doc, flow type sync, resolve_machine_info changes

* Update the process interface. Change all the configuration related to speed in the process to support high flow.

* fix: serialize flow support fields with commas in G-code

Use comma-separated values for filament_flow_support,
process_flow_support, and printer_flow_support when exporting
the G-code configuration block.

* The process configuration UI supports switching of traffic types, as well as switching of the dirty state for different traffic types.

* feat: add flow variant switch to filament settings pages

Extend the flow variant selector to support multiple pages and show
the Standard/High Flow switch on Filament, Cooling, Setting Overrides,
and Multimaterial pages.

Keep the selector hidden on other filament settings pages and update
variant-specific option indices and dirty states when switching modes.

* fix: isolate filament override states by flow variant

Use the active flow variant index only for filament options that
support Standard and High Flow values.

Keep non-variant override options on their original index to prevent
unrelated checkboxes from becoming selected when switching flow modes.

* feat: plain-text flow-variant selector UI on high-flow branch

* feat: mark high-flow filament parameters with a flow-variant icon

Draw a flow-variant marker icon to the left of each filament
flow-variant parameter's label, but only when the edited filament
supports high flow (filament_flow_support declares >1 variant).

- new resources/images/flow_variant.svg (teal/grey flow marker)
- ConfigOptionsGroup::get_config() accessor
- OG_CustomCtrl paints the icon in CtrlLine::render; the label column
  shrinks by the icon width so field columns stay aligned

* feat: hide flow-variant toggle when the preset declares one variant

Gate Tab::update_flow_variant_view_visibility on modes.size() > 1 so a
preset that only declares [standard] hides the whole selector instead of
showing a meaningless one-segment standard-only toggle. Uniform across
the filament, process and printer flow-variant views.

* fix: swap-groups button icon double-scaled on HiDPI

ScalableBitmap's px_cnt is a logical (DIP) size that create_scaled_bitmap
already passes through FromDIP; wrapping it in FromDIP again scaled the
icon by DPI squared, overflowing the 20x20 swap button on HiDPI displays.
Pass the raw 14, matching the other icons in this dialog.

* style: teal background for the selected nozzle tab

The selected tab in the per-nozzle CustomNotebook now fills with the
teal accent (#009688) with white text, matching the Figma nozzle
selector. The rest of the tab-bar styling is unchanged.

* feat: gate slice-mode popup on distinct selected nozzle flow types

The standard/custom filament-grouping hover popup (and the custom
FilamentGroupDialog confirm on slice) now appears only when the nozzles
actually mix flow variant types -- distinct_nozzle_flow_type_count() >= 2,
based on the per-nozzle flow combos rather than the printer's high-flow
capability. When every nozzle uses the same type there is nothing to
group, so slicing routes every filament to that one type (guaranteed by
get_config_idx / flow_variant_index returning index 0 for an unsupported
mode).

* Add high-traffic black and white list prompts: Do not recommend consumables prompt and unavailable consumables prompt.

* Fix the issues where the type name is not displayed completely, and where the right and left boundaries are not symmetrical.

* fix: preserve scalar option state with flow variants

Keep the original shallow comparison behavior for regular options on
pages that mix scalar and flow-variant fields. Apply indexed deep
comparison only to registered flow-variant options so page refreshes do
not affect unchanged scalar option state.

* fix: use selected flow variant for dependent controls

Resolve pressure advance and multitool ramming dependencies from the
currently selected flow variant instead of the printer nozzle flow type.

This keeps dependent controls isolated between standard and high-flow
filament settings.

* feat: slice flow follows the selected nozzle type when grouping is moot

When the custom per-filament grouping does not apply (standard mode, or
the nozzles are not mixing flow types), every filament now follows the
single selected nozzle flow type at slice time -- all-standard nozzles
slice standard, all-high-flow nozzles slice high flow -- instead of being
driven by a stale custom filament_volume_type mapping. High-flow values
apply only for a custom + mixed setup (per-filament dialog mapping) or
uniformly high-flow nozzles.

Adds FlowType::sync_filament_volume_types_for_slice(); the slice-button
handler calls it in the else branch of the custom-grouping gate.

* style: nozzle tab / flow icon / locale-aware brackets, and reword grouping copy

- CustomNotebook: deepen the unselected nozzle tab text to #6B6B6B,
  matching the process flow toggle's unselected grey
- flow-variant parameter icon (flow_variant.svg) updated to the new artwork
- flow-variant toggle brackets are locale-aware now: CJK brackets for
  Chinese, ASCII square brackets for other languages
- reword the custom filament grouping dialog intro and tip strings, with
  the matching zh_CN .po msgid updates

* feat: require a high-flow-capable filament to show the custom grouping popup

The standard/custom grouping hover popup and the FilamentGroupDialog
confirm on slice now appear only when -- in addition to the nozzles
mixing flow types -- at least one selected filament declares high_flow
in its filament_flow_support. Adds FlowType::any_filament_supports_high_flow().

* fix: preserve independent flow variant option states

- compare dirty states per flow variant, including nullable values
- preserve nil state for optional filament override fields
- fix checkbox and reset behavior after switching flow variants
- read nullable vector values using the selected variant index
- handle nullable float and percent updates with their actual types
- normalize process flow option vectors to the declared variant count
- prevent standard and high-flow speed values from sharing one slot

* A new black and white list mechanism for consumables has been added. The list of consumables that are not recommended or not supported will be accessed through a JSON file.

* fix: synced nozzle flow types not applied to UI

Two issues broke nozzle-flow-type sync from the printer:

1. select_complete_cached_nozzle_info cleared the caller's flows when the
   cache was incomplete, discarding the values just resolved from
   objects.query/system_info -- so the captured nozzle_volume_types was
   empty and set_nozzle_volume_types was never called. Now an incomplete
   cache leaves the resolved flows untouched (only a complete, valid cache
   overrides them).

2. In the uniform-diameter sync branch, update_nozzle_settings (which
   rebuilds the per-nozzle flow combos by reading nozzle_volume_type from
   config) ran BEFORE set_nozzle_volume_types, so the combos were rebuilt
   with stale values. Write the synced flow types first, then rebuild.

* fix: default synced nozzle flow types to standard when machine omits them

When resolve_machine_info got nozzle diameters but no flow types from
either system_info or objects.query, nozzle_volume_types stayed empty, so
the sync handler skipped set_nozzle_volume_types entirely -- the config
kept its old/preset value while the UI reported a successful sync.

Now resolve normalizes: if diameters are present but flows are absent,
fill flows with FLOW_MODE_STANDARD (one per nozzle). This matches the
read-side semantics (FlowType::nozzle_volume_types() already pads missing
entries with standard) and applies to both resolve call sites.

* fix: reset per-nozzle flow types to standard on new project

Printer presets carry no per-nozzle flow-type field (nozzle_volume_type
lives in the shared project config, not the preset). On New Project the
per-nozzle flow types therefore lingered at whatever the previous project
left -- e.g. high flow -- while the diameter correctly followed the newly
selected preset.

Add FlowType::reset_nozzle_volume_types_to_standard() (fills one standard
entry per nozzle, sized to the current nozzle count) and call it at the end
of Plater::new_project so a fresh project always starts on standard flow.

* fix: rebuild nozzle panel after new-project flow-type reset

The flow-type reset in Plater::new_project wrote nozzle_volume_type to
config but did not refresh the nozzle panel. Entry points that select a
preset first (home-page device card -> sw_NewProject) already rebuild the
panel via on_select_preset BEFORE new_project runs, so the combos kept
showing the pre-reset flow types.

Rebuild update_nozzle_settings after the reset (deferred via CallAfter so
no combo is destroyed mid-event on the select path). The menu Ctrl+N path
already worked; this makes the device-card path match.

* Update on the latest changes to process consumables.

* Add a modified updated version number.

* Adjust all consumable files to ensure a unique tree structure.

* Update the consumable version number to 02.03.01.02

* Revise the scattered node files of the partial process documents.

* fix: scroll overflowing colours in custom filament grouping dialog

* Restore renamed consumables to prevent user presets from becoming invalid.

* Revise the process documents by adding a "renamed_from" field to ensure compatibility after the process files are renamed. Also, modify the naming of some color-mixing processes to achieve a unified naming convention.

* After fixing the high traffic issue, close the software. The variable values in the pop-up window have incorrect changes.

* Fix the issue where modifying parameters does not take effect in the high-flow mode when restoring the filament retraction length.

* fix: localize flow toggle labels; refine custom filament dialog dark mode

* feat: custom filament dialog title bar; slice on flow-regroup confirm

* Fix dirty state for percent speed options

* Fix the issue where modifying the high-traffic temperature setting does not work.

* fix: preserve unselected indexed filament options during transfer

Keep indexed option keys such as `option#0` and `option#1` when
transferring preset changes. Cache the base vector option for reading,
but apply the cached values with the original indexed keys so only the
selected vector elements are updated in the target filament preset.

This prevents unmodified standard or high-flow volumetric capacity values
from being overwritten during filament migration.

* Fix the issue where the modified default_jerk and max_volumetric_extrusion_rate_slope cannot be enabled when in high traffic mode, as the expanded values controlled by them are unable to be activated.

* Revise the description of the color blending process.

* Fix the issue where the modifications to the parameters filament_wipe_distance and filament_z_hop_types do not take effect in the high-traffic mode.

* feat: add 3MF project schema compatibility warning

Add project schema version metadata for 3MF files and warn users when
loading a project created with a newer schema version. Continue loading
project settings and embedded presets while notifying users that the
nozzle flow rate type may not match the file.

* fix: reword 3MF schema version warning dialog and update zh_CN translation

* Modify the file name of the color mixing process.

* Merge the processing procedures based on the high-flow branch.

---------

Co-authored-by: lzqiang46-cyber <lzqiang46@gmail.com>
Co-authored-by: ZhangZheng <99784311@qq.com>

* Delete the color blending process.

* New color-mixing process.

* Integration of processes simplification.

* Delete 2 unnecessary files.

* The new process adds the "renamed_from" field to ensure that the user's preset settings are not lost.

* fix: Remember the per-nozzle flow selection (Standard/High Flow) across restarts: mirror it into the AppConfig "nozzle_volume_types" section and restore it after the startup blank-project reset; New Project still resets to Standard without wiping the memory.

* fix: UI fixes for nozzle tabs, filament grouping, and slice mode popup

* fix: Show full array values in preset compare/diff dialogs

* Fix the issue where the parameter values do not revert to the default model configuration after the consumable parameters are selected for override.

* fix: flow selector labels clipped at some resolutions; sync filament-grouping strings with zh_CN translations

* According to the product requirements, the traffic mode switching for the mobile capability of the device has been removed.

* feat: report per-nozzle flow type in sw_GetFileFilamentMapping

* fix(linux): keep slice button clickable while slice-mode hover popup is shown

* Hide the experimental adaptive pressure advance options from the filament UI

* revert try catch for the mqtt connect. (#723)

* fix revert try catch for the mqtt connect.

* fix add try catch for mqtt.

* feature add the exception catch for mqtt.

* fix exception not catch question

* Fix the compilation errors

* fix: always sync nozzle flow types when clicking nozzle sync button

* Update the official consumables and fix the errors in the process parameters.

* Update on the latest model changes.

* Some newly added consumable templates have been entered into the inventory.

* fix: guard resolve_machine_info late callbacks and drop blocking query in nozzle sync

---------

Co-authored-by: lzqiang46-cyber <lzqiang46@gmail.com>
Co-authored-by: ZhangZheng <99784311@qq.com>
Co-authored-by: Alves <LiuLikeQian@users.noreply.github.com>

* fix: carry flush volumes across U1 nozzle switch to prevent heap corruption (#805)

The U1 filament carry-over logic in Tab::select_preset restored the filament
presets and colours after update_selections(), but not flush_volumes_matrix /
flush_volumes_vector. The matrix was therefore left at the size of the new
nozzle's saved entry (e.g. 1x1 for a single-filament machine), mismatching the
carried-over filament count. The next filament switch made
auto_calc_flushing_volumes index the matrix with the filament count as the row
stride, writing doubles past the buffer and corrupting adjacent heap blocks.
The corruption later surfaced as a c0000374 (heap corruption) crash at an
arbitrary free call, with the crash site wandering between runs.

- Tab.cpp: capture the flush matrix/vector together with the filament state
  before the switch and restore both afterwards, so the flush state follows
  the filaments.
- Plater.cpp: validate matrix.size() == filamentCount^2 before writing in
  auto_calc_flushing_volumes; log an error and skip the recalculation on
  mismatch instead of writing out of bounds.

* fix: remove orphaned render_with_outline definition left by #737 (#764)

---------

Co-authored-by: ZhangZheng <67276816+LuckZAE@users.noreply.github.com>
Co-authored-by: zhouzengping <44285325+zhouzengping@users.noreply.github.com>
Co-authored-by: Kenshin627 <Kenshin627@users.noreply.github.com>
Co-authored-by: lhx <48871316+fire2wind@users.noreply.github.com>
Co-authored-by: SukiSunYuhang <sukiyuhang.sun@gmail.com>
Co-authored-by: lujiaxin001 <86400265+lujiaxin001@users.noreply.github.com>
Co-authored-by: RF47 <162915171+RF47@users.noreply.github.com>
Co-authored-by: mwz-iot <2952410757@qq.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Joyx <48636909+iesteem@users.noreply.github.com>
Co-authored-by: XieJiajun <68017138+PILIPALA030@users.noreply.github.com>
Co-authored-by: linzhiqiang <lzqiang46@gmail.com>
Co-authored-by: zackaree-shen <zackary_shen@qq.com>
Co-authored-by: Alves <LiuLikeQian@users.noreply.github.com>
Co-authored-by: ZhangZheng <99784311@qq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants