The cooperative-load section already streams each item into shared memory
once per workgroup, but the per-pixel inner loop then recomputed values
that are constant for the whole item/glyph. The compiler can't hoist them
itself — they read shared memory at a varying index.
Precompute them once per item at load time into new shared slots:
- ui-images / ui-text / ui-fused (images+text phases): invRectSize =
1.0/rect.zw, turning the per-pixel `(sp-rect.xy)/rect.zw` vec2 divide
into a multiply.
- ui-text / ui-fused (text phase): the SDF AA `band` (a vec2 divide +
two maxes depending only on the glyph's uv span and rect size).
In ui-fused the new slots (s_inv, s_band) are reused across phases like
the existing s_v* scratch, so the LDS bump is per-category, not summed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Each 8×8-tile workgroup previously had all 64 threads walk the entire
item list, re-reading every item from the SSBO 64× and running the
per-pixel reject for items that never touch the tile — O(tiles × N)
item loads dominated by SSBO traffic.
The workgroup now streams the item list in chunks of 64: each thread
loads one item, tests its AABB against the whole tile, and the survivors
are compacted — in original buffer order — into shared memory. Every
thread then runs the unchanged per-pixel accumulate over only those
survivors. This drops SSBO traffic ~64× (each item read once per
workgroup instead of once per pixel) and shrinks the inner loop to the
items that actually overlap the tile.
Draw order is preserved exactly: chunks run in array order and the
in-chunk compaction is a stable in-order scan, so later items still
overdraw earlier ones (no atomic-append nondeterminism). The inner loop
body is byte-for-byte the original per-pixel logic, so output is
pixel-identical — the cull only decides which items reach it. Threads
no longer early-return so every thread reaches the workgroup barriers.
Applied to ui-quads, ui-circles, ui-images and ui-text; shared helpers
(uiTileBounds / uiAabbOverlapsTile) live in ui-shared.glsl.
Resolves#46
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>