The Phase 2.1 step-4 attempt at culling hatches inside
`synced_hatch_models` was wrong: GPU hatch/wipeout buffers are
uploaded on geometry_epoch only (see render.rs — they're "static
buffers"), so any CPU-side cull at build time would freeze the
visible set at the geometry epoch boundary and never re-evaluate on
pan. Reverted that approach; the build-time function now returns the
full visible set again and the cache key is back to geometry_epoch.
The actual per-frame frustum cull moves into the existing draw-time
skip-flag machinery:
- `compute_hatch_lod` now also folds in `aabb_offscreen` (ORed with
the existing Phase 3.3 sub-pixel skip), so out-of-view hatches are
skipped at the draw call.
- New `compute_wipeout_lod` + `wipeout_skip_flags` mirror the hatch
path. The wipeout draw loop honors the flag.
- `Primitive::prepare` calls the new compute step alongside the rest.
Per-frame projection + skip is a few hundred microseconds on dense
docs; far cheaper than re-uploading GPU buffers per pan tick.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>