perf: warm the interaction handle index during open

The first hover over the canvas after opening a large drawing froze the
UI for a second:

    hover-detail  query=0.2 handles=986.1 ... candidates=253
    hover-dwell   986.6ms

`interaction_handle_index` and the insert-hatch map it reads are built
lazily, and first use is that hover. Neither can move to the loader
thread: they read `hatches`, `meshes` and `block_meshes`, which are
installed on the real `Scene` only after the loader has finished.

Build them at the end of the open instead, where the user is already
waiting. This does not make the work cheaper -- open grows by roughly the
second the hover used to cost -- but a second inside an operation that is
already seconds long reads very differently from a second-long freeze on
a mouse move.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
PanosandClaude Opus 5 committed 2026-09-05 09:10:48 +03:00
1 parent d5d9ceec45
commit 38f576c296
2 files changed
+18

No files matched your search

+2
View File
@@ -1438,6 +1438,8 @@ pub(super) fn on_open_file(&mut self) -> Task<Message> {
if let Some(prepared) = prepared_geometry {
self.tabs[i].scene.install_prepared_open_geometry(prepared);
}
// Pay for the interaction index here, not on the first hover.
self.tabs[i].scene.warm_interaction_caches();
self.tabs[i]
.scene
.replace_selection(rustc_hash::FxHashSet::default());
+16
View File
@@ -7874,6 +7874,22 @@ impl Scene {
}
}
/// Build the interaction handle index and the insert-hatch map now, while
/// the drawing is still opening.
///
/// Both are built lazily on first use, and first use is the user's first
/// hover over the canvas — where the cold build cost 992 ms mid-gesture
/// (`hover-detail ... handles=986.1`). They cannot move to the loader
/// thread: they read `hatches` / `meshes` / `block_meshes`, which are
/// installed on the real `Scene` after the loader is done.
///
/// This does not make the work cheaper, it moves it to where the user is
/// already waiting. A second on an open that is already seconds long reads
/// very differently from a second-long freeze on a mouse move.
pub(crate) fn warm_interaction_caches(&self) {
let _ = self.interaction_handle_index();
}
fn interaction_handle_index(
&self,
) -> Arc<crate::scene::pick::interaction_index::InteractionHandleIndex> {