perf(scene): decouple selection from wire tessellation
Picking an entity called bump_geometry, which invalidated the wire cache and re-tessellated the entire model just to repaint one entity — 30ms to 400ms on a large drawing (visible as a tess-ms spike on the PERF HUD). Selection highlight is no longer baked into tessellation. wires_for_block_ culled now feeds tessellate_entity an empty selection set, so wires are always base-coloured and the wire cache is selection-independent. The highlight is applied in the GPU xray overlay: prepare filters the cached wires by the live `selected ∪ hover` handle set, recolours them to WireModel::SELECTED, and batches them — rebuilt only when a new selection_generation (or the underlying wire content) changes. Pure select / deselect / hover paths now call bump_selection instead of bump_geometry, so a pick refreshes just the overlay — no re-tessellation, no main wire re-upload (geometry_epoch and wire_content_id are unchanged). Geometry edits, undo and file-open still bump_geometry and rebuild everything. Grips/properties refresh through their existing app paths. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
0d18e0d1bf
commit
ff9f49511b
4 changed files with 140 additions and 34 deletions
|
|
@ -81,6 +81,13 @@ pub struct ViewportData {
|
|||
/// world-space wire buffer when only the camera moved. Non-tile and
|
||||
/// preview/interim frames carry a fresh id each time → always re-upload.
|
||||
pub(super) wire_content_id: u64,
|
||||
/// `selected ∪ hover` handles for the GPU xray overlay. The highlight is no
|
||||
/// longer baked into the wire tessellation, so `prepare` rebuilds the
|
||||
/// selected-wire batch by filtering `wires` against this set.
|
||||
pub(super) highlight_handles: Arc<rustc_hash::FxHashSet<acadrust::Handle>>,
|
||||
/// Bumped on selection / hover change. Paired with `wire_content_id` to
|
||||
/// decide when the xray overlay batch needs rebuilding.
|
||||
pub(super) selection_generation: u64,
|
||||
/// Screen rectangle this viewport fills, **normalized** to the widget
|
||||
/// bounds (each component in 0..1). A single full-widget view is
|
||||
/// `(0, 0, 1, 1)`; tiled / floating viewports are sub-rectangles.
|
||||
|
|
@ -251,6 +258,20 @@ impl shader::Primitive for Primitive {
|
|||
inner.upload_wires(device, &vp.wires[..], &vp.draw_depths);
|
||||
inner.cached_wire_id = vp.wire_content_id;
|
||||
}
|
||||
// Selection xray overlay — rebuilt when the selection changes or the
|
||||
// underlying wires changed. A pick bumps only selection_generation,
|
||||
// so this refreshes without re-tessellating or re-uploading the main
|
||||
// wire buffers.
|
||||
let sel_key = (vp.wire_content_id, vp.selection_generation);
|
||||
if sel_key != inner.cached_selection {
|
||||
inner.upload_selected_wires(
|
||||
device,
|
||||
&vp.wires[..],
|
||||
&vp.highlight_handles,
|
||||
&vp.draw_depths,
|
||||
);
|
||||
inner.cached_selection = sel_key;
|
||||
}
|
||||
let vproj = vp.uniforms.view_proj;
|
||||
inner.compute_wire_scissors(vproj, clip_size.width, clip_size.height);
|
||||
inner.compute_wipeout_scissors(vproj, clip_size.width, clip_size.height);
|
||||
|
|
@ -747,6 +768,8 @@ impl Scene {
|
|||
geometry_epoch: self.geometry_epoch,
|
||||
camera_generation: self.camera_generation,
|
||||
wire_content_id,
|
||||
highlight_handles: self.highlight_handles(),
|
||||
selection_generation: self.selection_generation,
|
||||
screen_rect,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue