Perf: transparent pass is 601 per-submesh draws and now the largest render cost

Part of #158.

Problem

After #162 and #161 (closed), the transparent pass is the largest remaining render cost in the frame — 2.47 ms, 44 % of render.scene's 5.62 ms, and larger than the opaque submission it sits inside.

From docs/decisions/bistro-perf-baseline.md:

pass CPU draws indirect
render.main (incl. transparent) 3.93 ms 194 3,271
├─ render.transparent 2.47 ms 601 0
render.shadow 0.96 ms 776 13,084
render.prepass 0.38 ms 194 3,271
render.upload 0.26 ms 0 0

It is the one draw path that received neither of the two fixes above. 601 individual draws — one per transparent submesh — each doing its own reflection_probes.resolveForSubmesh, its own buildDrawParams, and a full uniform push and sampler bind, plus a back-to-front pdq sort over the whole set.

It cannot simply adopt the indirect path: correct alpha compositing needs per-submesh depth ordering, and an indirect multi-draw over a material group draws in buffer order.

Directions, roughly in order of effort

  • Hoist the per-draw work out of the sort loop. buildDrawParams and the probe resolve run per transparent submesh every frame even though both are per material; the only thing that genuinely varies per submesh is the index range and the sort key. Group the resolve, keep the sort per submesh.
  • Sort material-group runs, not individual submeshes, where a group's submeshes don't overlap in depth. Falls back to per-submesh where they do.
  • Sort on the GPU and drive an indirect draw from the sorted order — the general fix, and the largest.
  • Order-independent transparency — changes the look, so out of scope unless the sort itself proves unfixable.

Bistro's transparent set is foliage and storefront glass, so this is not a corner case for the sample.

Acceptance

  • render.transparent CPU measurably reduced against the baseline (#159 (closed) harness)
  • Fixed-camera before/after at the terrace viewpoint: foliage and glass composite identically
  • The interior stays visible through the storefront glass (the #156 acceptance shot)