refactor(viewport): unify content-viewport clipping on the stencil path

Rectangular paper viewports now go through the same GPU stencil clip as
non-rectangular ones: viewport_clip_boundary_ndc returns the four rect
corners (a full-target mask) instead of nothing, so the render path has
no rect/non-rect special case — every content viewport carries a clip
boundary and draws with stencil reference 0xFF.

With a single clip path, the old per-wire / -image / -wipeout scissor
mechanism is fully dead and removed: compute_*_scissors, the
*_pixel_scissors buffers, the project_scissor helper, the per-pass
set_scissor_rect blocks, the vp_scissor field threaded through
WireModel / ImageModel / HatchModel and their GPU mirrors (WireGpu /
ImageGpu / WipeoutGpu / HatchWebGpu), from_run's scissor parameter, the
scissor grouping in build_wire_buffers, and the is_arena_eligible gate.
Net -245 lines across 54 files.

Rectangular viewports still clip exactly via their own render rectangle;
the stencil mask is a redundant full-target no-op there, kept only so
the clip code path stays uniform. XCLIP keeps its CPU wire clip.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan SevenandClaude Opus 4.8 committed 2026-07-20 11:06:28 +03:00
1 parent c97c2a8250
commit 626e8091f7
54 files changed
+32 -277

No files matched your search

-8
View File
@@ -90,13 +90,6 @@ fn handle_of(w: &WireModel) -> Option<Handle> {
crate::scene::Scene::handle_from_wire_name(&w.name)
}
/// True if the set can use the arena: no per-wire scissor (paper viewports). Mesh
/// fills no longer disqualify it — the render layer splits the set into a regular
/// and a mesh-edge subset, one arena each.
pub fn is_arena_eligible(wires: &[WireModel]) -> bool {
wires.iter().all(|w| w.vp_scissor.is_none())
}
/// True when `w`'s edge segments belong to a mesh/solid whose fill is drawn in a
/// separate pass — such wires need the draw loop's mesh-edge treatment, so they
/// go in their own arena. `mesh_names` are the entities that emit a fill.
@@ -439,7 +432,6 @@ impl WireArena {
vec![WireGpu {
instance_buffer: self.inst_buf.clone(),
instance_count: self.inst_tail,
vp_scissor: None,
is_3d_mesh_edge: self.mesh_edge,
const_bind_group: Some(self.const_bind_group.clone()),
}]