perf: build hatch/image/mesh caches off the UI thread

Parsing + DerivedCaches construction now runs entirely in a dedicated
OS thread inside open_path(). FileOpened handler only assigns the
pre-built caches, keeping the UI thread free during file load.

- Add build_derived_caches(): parallel hatch + mesh tessellation via rayon
- Extend Message::FileOpened / open_path return type with DerivedCaches
- Drop populate_*_from_document() calls from FileOpened handler
This commit is contained in:
Hakan Seven 2026-05-06 23:04:53 +03:00
commit 2da3640b45
4 changed files with 172 additions and 51 deletions

View file

@ -212,7 +212,7 @@ pub enum DsField {
pub enum Message {
Tick(Instant),
OpenFile,
FileOpened(Result<(String, PathBuf, CadDocument), String>),
FileOpened(Result<(String, PathBuf, CadDocument, crate::scene::DerivedCaches), String>),
SaveFile,
SaveAs,
// ── Custom Save-As dialog ─────────────────────────────────────────────

View file

@ -35,7 +35,7 @@ impl H7CAD {
Message::OpenFile => Task::perform(crate::io::pick_and_open(), Message::FileOpened),
Message::FileOpened(Ok((name, path, doc))) => {
Message::FileOpened(Ok((name, path, doc, caches))) => {
let entity_count = doc.entities().count();
self.command_line
.push_output(&format!("Opened \"{name}\" — {entity_count} entities"));
@ -87,10 +87,12 @@ impl H7CAD {
}
}
self.tabs[i].scene.compute_and_set_world_offset();
self.tabs[i].scene.populate_hatches_from_document();
self.tabs[i].scene.populate_images_from_document();
self.tabs[i].scene.populate_meshes_from_document();
// Caches were built on the background thread inside open_path().
self.tabs[i].scene.world_offset = caches.world_offset;
self.tabs[i].scene.local_extent_max = caches.local_extent_max;
self.tabs[i].scene.hatches = caches.hatches;
self.tabs[i].scene.images = caches.images;
self.tabs[i].scene.meshes = caches.meshes;
self.tabs[i].scene.selected = std::collections::HashSet::new();
self.tabs[i].scene.preview_wires = vec![];
self.tabs[i].scene.current_layout = "Model".to_string();