docs(rendering): mark Phase 4 done, drop deferred / non-goal phases

Phase 4-B (batched hatch pipeline) is in; Phase 4.1 (multi-draw
indirect / GPU compute cull) stays as a deliberate non-goal because
iced 0.14 doesn't expose the required wgpu features to widget
pipelines, and the single-draw batched path already collapses N
bind-group swaps + N draw calls into one. Phase 4.2 (Hi-Z occlusion)
only matters for perspective 3D, which H7CAD doesn't ship.

The doc is now a short stub — the per-phase rationale lives at the
call sites (search for "Phase N.X" comments).

Co-Authored-By: Claude Opus 4.7 <[email protected]>
This commit is contained in:
Hakan SevenandClaude Opus 4.7 committed 2026-05-17 20:18:55 +03:00
1 parent 798a391207
commit 66fca6e591
1 file changed
+35 -72
+35 -72
View File
@@ -1,76 +1,39 @@
# Rendering Optimization Roadmap: Culling & Level of Detail
# Rendering Optimization Roadmap
## Background
Phases 1–4 have all landed. This document is kept as a stub so the
git history points somewhere; the optimisations themselves are
documented inline at the call sites:
H7CAD renders all entities every frame regardless of camera position or zoom level. No spatial
acceleration, no LOD, no frustum culling. Every wire, hatch, mesh, and image is uploaded and
drawn unconditionally. This scales poorly for large drawings (100k+ entities) and dense 3D solids.
- **Phase 1** – per-frame LOD ladder, scissor cull (search for
`Phase 1.*` in `scene/pipeline/mod.rs`).
- **Phase 2** – quadtree spatial index for top-level entities, plus
draw-time frustum cull for hatches / wipeouts / meshes
(`Phase 2.1`, `2.2`, `2.3`).
- **Phase 3** – LOD substitution for far / sub-pixel content
(`Phase 3.2`, `3.3`, `3.4`).
- **Phase 4-B** – batched hatch pipeline. Every hatch is uploaded
into shared storage buffers (`hatch_batched_gpu.rs`) and drawn in
one `pass.draw(0..6N, 0..1)`; the per-instance `visibility` buffer
doubles as a CPU-driven cull mask (sub-pixel + frustum) that the
vertex shader honours by emitting an out-of-NDC clip position for
skipped instances. Replaces N bind-group swaps + N draw calls with
a single draw.
Current pipeline order:
1. Hatch fills → 2. Images → 3. Meshes → 4. Face3D fills → 5. Face3D edges →
6. Wires → 7. Wipeouts → 8. Selection overlay → 9. MSAA resolve → 10. Blit
---
## Phase 4 — GPU-Side Culling (Advanced)
**Goal:** Offload culling to the GPU; zero CPU cost for large entity counts.
### 4.1 Indirect Draw + Compute Cull
Convert per-entity draw calls to indirect draw calls (`draw_indirect` / `draw_indexed_indirect`).
Run a compute shader pre-pass that tests each entity's AABB against the frustum and writes
`DrawIndirectArgs` only for visible entities.
```wgsl
// cull.wgsl
@compute @workgroup_size(64)
fn cull_entities(@builtin(global_invocation_id) id: vec3<u32>) {
let entity = entities[id.x];
if frustum_test(entity.aabb) {
// atomically append to indirect draw buffer
let slot = atomicAdd(&draw_count, 1u);
draw_args[slot] = entity.draw_args;
}
}
```
Requires restructuring entity data into GPU-side storage buffers. High complexity; tackle after
Phases 1–3 prove insufficient.
### 4.2 Hierarchical Z-Buffer Occlusion Culling (3D Only)
For dense 3D solid scenes, use a Hi-Z buffer to cull occluded meshes:
1. Render depth-only pass for large opaque solids.
2. Downsample depth into mip chain (Hi-Z pyramid).
3. Compute shader tests each mesh AABB against Hi-Z; skips occluded meshes.
Relevant only for perspective (3D) mode with many overlapping solids.
---
## Implementation Order
```
Phase 4.1 Indirect draw + GPU cull high complexity, defer
Phase 4.2 Hi-Z occlusion high complexity, 3D only, last
```
---
## Key Files to Modify
| File | Change |
|------|--------|
| `src/scene/mod.rs` | Quadtree/octree; LOD epoch tracking |
| `src/scene/pipeline/mod.rs` | Cull hatch/image entities before upload loops |
| `src/shaders/cull.wgsl` | New — Phase 4 compute culling shader |
---
## Success Metrics
- **Phase 2 target:** Pan/zoom frame cost O(visible) not O(total).
- **Phase 4 target:** GPU-cull overhead < 0.5 ms for 1M entity scene.
## Deliberate non-goals
- **Phase 4.1 (multi-draw indirect / compute cull)** — iced 0.14
doesn't expose `Features::MULTI_DRAW_INDIRECT` to widget pipelines.
Without it, single-draw indirect adds no real saving over the
current batched draw. Revisit if iced surfaces the feature flag,
or if H7CAD ever swaps the shader widget for a custom wgpu surface.
- **Phase 4.2 (Hi-Z occlusion)** — pays off only for perspective 3D
with many overlapping opaque meshes. H7CAD is orthographic
top-down for every realistic workflow, so the win is theoretical.
- **Per-mutation incremental quadtree updates** — `entity_index_cache`
rebuilds lazily on `geometry_epoch` change. Full rebuild is ~50 ms
on a 100 k-entity doc; promote to per-mutation `insert`/`remove`/
`update` if profiling shows that as a hot spot during heavy edits.
- **Per-hatch viewport scissor in the batched path** — paper-space
MSPACE viewports can render hatches past the viewport border for
now. Add a per-instance scissor rect (computed from `vp_scissor`)
if it shows up as a visible artefact.