Perf: frame-constant data re-pushed in every 576-byte per-draw uniform

Part of #158. Phase 2 — no fidelity change.

Problem

types.FragUB is 576 bytes, pushed on every draw. Two of its members don't vary across draws within a frame:

  • cascade_vp[4][16] — 256 bytes
  • env_sh[9][4] — 144 bytes

That's 400 bytes of frame-constant data re-uploaded per draw call, 70 % of the push.

The precedent for fixing it is already in the same file: scene lights were moved out of the per-draw uniform into a storage buffer bound once per pass, and types.zig documents exactly that reasoning — "Scene lights are NOT here — they live in a separate storage buffer bound once per frame, so this stays small per draw." The cascade and SH data never got the same treatment.

Scope

  • Move cascade_vp, cascade_splits, cascade_depth_scale and env_sh into a second fragment uniform slot, pushed once per render pass.
  • Per-draw push drops from 576 B to ~176 B.
  • Update scene.frag.glsl's uniform block layout to match, and shadow_mask/depth_normal where they mirror it.

This block is also the natural home for the irradiance-volume constants in #166, which is why it is worth doing before that lands rather than after.

Acceptance

  • Per-draw fragment uniform push measured at ~176 B
  • Rendering byte-identical — fixed-camera before/after pair
  • Before/after render.main CPU time recorded
Edited by Bruno Massa