perf(scene): batch the wire pass into per-run draw calls

Phase 3.3. upload_wires built one GPU instance buffer + one draw call per
WireModel — tens of thousands on a large drawing, a major per-frame CPU /
driver cost. Merge maximal runs of consecutive wires that share scissor +
mesh-edge state into one concatenated instance buffer each (WireGpu::
from_run); the existing draw loop then issues a single draw per run. A 2D
model (uniform None scissor, no mesh edges) collapses to one buffer + one
draw.

Runs are consecutive, never globally regrouped, so the sorted wire order
is preserved exactly — depth-biased overlap and alpha blending both
resolve in submission order, so the image is unchanged. from_run
guarantees instance order (index-ordered collect + sequential flatten).
The WireInstance layout, shader, scissor projection and draw loop are
untouched; only buffer packing changed. Selection overlay stays per-wire.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan Seven 2026-06-05 09:35:18 +03:00
commit c6e17deb7e
3 changed files with 83 additions and 6 deletions

View file

@ -212,7 +212,18 @@ Today every wire GPU buffer is re-uploaded when
pool — `HashMap<Handle, GpuSlot>` — uploads only the slots that actually
changed. Big win in CAD-edit scenarios.
### 3.3 Single-draw batched wire pipeline (Phase 4-B-style)
### 3.3 Single-draw batched wire pipeline (Phase 4-B-style) ✅ DONE
`upload_wires` made one GPU buffer + one draw call per `WireModel` (tens of
thousands on a large drawing). Now it merges maximal runs of *consecutive*
wires sharing scissor + mesh-edge state into one concatenated instance buffer
each (`WireGpu::from_run`), so the existing draw loop issues one draw per run
— a 2D model collapses to a single buffer + single draw. Runs stay
*consecutive* (not globally regrouped) so the sorted draw order is preserved
bit-for-bit; depth bias and alpha blending are unchanged. The `WireInstance`
layout, shader, scissor logic and draw loop are untouched — only the buffer
packing changed. (No iced widget-pipeline limits were hit: the change lives
entirely inside the existing custom wgpu pipeline.)
Every `WireModel` today costs one draw call plus a bind-group swap. Port
the batched hatch pipeline (`hatch_batched_gpu.rs`) to wires: