ifcviewer: GPU cull drives rendering under IFC_GPU_CULL=1

Promote the compute cull from a validation shader to the actual draw
driver.  With the gate on, the CPU cull fan-out is skipped and MDI
consumes gpu_indirect_buffer / gpu_visible_ssbo directly.

- uploadGpuCullStaticBuffers() pre-fills per-mesh DrawElementsIndirect
  commands and a mesh_base prefix sum so the compact shader can scatter
  survivors into a fixed per-mesh range.  Instance count for each
  command is zeroed by a tiny reset dispatch, then the compact shader
  atomically writes survivors and increments instanceCount.
- Draw loop branches on the gate: single CCW MDI with all mesh
  commands.  Fwd/rev winding split, LOD selection, and HiZ are still
  CPU-path-only; reflected instances render with wrong winding under
  this gate (step 3b).
- Once-per-second readback of each model's indirect buffer populates
  the survivor / visible-object / visible-triangle stats so the
  [frame] line reflects what the GPU actually drew.

Known regression: sub_draws is the full mesh count per model (~172k on
the test dataset) vs the handful of non-empty commands the CPU path
produces.  Command-processor overhead from zero-instance sub-draws is
what drives the FPS drop, not the cull itself (0.05 ms).  Compacting
non-empty commands requires glMultiDrawElementsIndirectCount, a GL 4.6
entrypoint not exposed by Qt's QOpenGLFunctions_4_5_Core; deferring to
3a-followup so we don't bolt a getProcAddress loader into the renderer
mid-restructure.

IFC_GPU_CULL is off by default, so this does not affect normal runs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dion Moult
2026-04-17 07:26:31 +10:00
parent a0cc4b874b
commit 0b122ae1f5
3 changed files with 322 additions and 73 deletions
+11 -1
View File
@@ -793,6 +793,16 @@ single giant model / <18 cores CPU BVH trv Phase 3E GPU cull (plann
- [x] Phase 3D — Parallel per-model CPU cull (`std::async` fan-out)
- [x] Quantized VBO (16 B/vert, sidecar v6)
- [x] Event-driven rendering (zero idle CPU/GPU, cull skipped on still frames)
- [ ] **Phase 3E — GPU-side compute-shader culling** (next; replaces the HiZ readback)
- [~] **Phase 3E — GPU-side compute-shader culling** (in progress)
- [x] 3a: `IFC_GPU_CULL=1` drives rendering via compute cull (frustum +
contribution, single bucket per mesh). Correctness matches CPU
path; perf regressed — we submit one sub-draw per mesh even
when `instanceCount=0`. Fix is MDI compaction via
`glMultiDrawElementsIndirectCount`, deferred to 3a-followup so
we don't pull a GL 4.6 entrypoint loader into this commit.
- [ ] 3a-followup: compact non-empty commands, use count-buffer MDI
- [ ] 3b: fwd/rev reflection bucketing on GPU
- [ ] 3c: LOD0/LOD1 selection on GPU
- [ ] 3d: HiZ with same-frame depth pre-pass
- [ ] Vulkan/MoltenVK backend for macOS
- [ ] Embedded Python scripting console