Phase 5 updates

Phase 5 · Slice 22 ·

GPU culling and indirect draws

  • crates/render/src/cull.rs and cull.wgsl: each frame the shared opaque runs' instances go through a compute pass per view: bounding spheres (mesh bounds computed at upload, scaled by the instance's transform) against the view frustum, then against the depth pyramid (Hi-Z) the view built last frame. Visible instances are compacted into a per-view list and counted into the runs' DrawIndexedIndirect arguments; the opaque pass draws them indirectly (per-draw vertex-buffer offsets, so no first-instance feature is needed).
  • Two-phase occlusion: the view's depth after phase one becomes its new pyramid (a compute copy and min-reduction mip chain, reverse-Z), and the instances phase one held back as occluded are tested against it and drawn in a second pass before the transparent geometry. Nothing visible is lost to a stale pyramid; the pyramid is kept for the next frame.
  • Transparent items, per-view masked opaque runs, shadow casters and reflection captures keep the CPU path. Off where compute isn't available, or with TASSIX_GPU_CULLING=0.
  • A GPU test checks the frustum and occlusion counts across frames (a wall hiding a grid, then removed) and that images match with culling off; all render, e2e and conformance tests pass with it on.
  • Not yet: bindless materials (runs still bind textures), multi-draw indirect, culling shadow casters, mesh LODs selected on the GPU.
  • Next: render benchmark scenes with frame-time budgets in CI.