perf(ui): hoist loop-invariant per-item math out of the per-pixel loop (#125)
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>
This commit is contained in:
parent
2783e47674
commit
ac9180076c
3 changed files with 45 additions and 20 deletions
|
|
@ -70,6 +70,13 @@ shared vec4 s_v1[UI_CHUNK];
|
|||
shared vec4 s_v2[UI_CHUNK];
|
||||
shared vec4 s_v3[UI_CHUNK];
|
||||
shared uvec4 s_v4[UI_CHUNK];
|
||||
// Per-item constants precomputed once at cooperative-load time, REUSED across
|
||||
// phases like the s_v* scratch (the per-pixel inner loops read them instead of
|
||||
// recomputing per pixel × item):
|
||||
// images: s_inv = 1.0/rect.zw
|
||||
// text: s_inv = 1.0/rect.zw, s_band = SDF AA scale (a divide + two maxes)
|
||||
shared vec2 s_inv[UI_CHUNK];
|
||||
shared float s_band[UI_CHUNK];
|
||||
shared uint s_keep[UI_CHUNK];
|
||||
shared uint s_order[UI_CHUNK];
|
||||
shared uint s_count;
|
||||
|
|
@ -232,6 +239,7 @@ void main() {
|
|||
s_v1[lid] = uiImageHeap[heap].items[idx].uv;
|
||||
s_v2[lid] = uiImageHeap[heap].items[idx].tint;
|
||||
s_v4[lid] = uiImageHeap[heap].items[idx].slots;
|
||||
s_inv[lid] = 1.0 / s_v0[lid].zw;
|
||||
keep = uiAabbOverlapsTile(s_v0[lid].xy, s_v0[lid].xy + s_v0[lid].zw,
|
||||
tileMin, tileMax);
|
||||
}
|
||||
|
|
@ -249,7 +257,7 @@ void main() {
|
|||
if (sp.x < lo.x || sp.y < lo.y) continue;
|
||||
if (sp.x >= hi.x || sp.y >= hi.y) continue;
|
||||
|
||||
vec2 t = (sp - s_v0[c].xy) / s_v0[c].zw;
|
||||
vec2 t = (sp - s_v0[c].xy) * s_inv[c];
|
||||
vec2 uv = mix(s_v1[c].xy, s_v1[c].zw, t);
|
||||
|
||||
uint texSlot = s_v4[c].x;
|
||||
|
|
@ -282,6 +290,13 @@ void main() {
|
|||
s_v0[lid] = uiGlyphHeap[heap].items[idx].rect;
|
||||
s_v1[lid] = uiGlyphHeap[heap].items[idx].uv;
|
||||
s_v2[lid] = uiGlyphHeap[heap].items[idx].color;
|
||||
s_inv[lid] = 1.0 / s_v0[lid].zw;
|
||||
// SDF AA band — atlas-px per screen-px, constant per glyph
|
||||
// (uvSpan * kAtlasSize(1024) / screenSpan), max'd to 1px floor.
|
||||
vec2 uvSpan = s_v1[lid].zw - s_v1[lid].xy;
|
||||
vec2 atlasPerScreen = (uvSpan * 1024.0) * s_inv[lid];
|
||||
float scalePx = max(atlasPerScreen.x, atlasPerScreen.y);
|
||||
s_band[lid] = max(scalePx, 0.0001);
|
||||
keep = uiAabbOverlapsTile(s_v0[lid].xy, s_v0[lid].xy + s_v0[lid].zw,
|
||||
tileMin, tileMax);
|
||||
}
|
||||
|
|
@ -299,7 +314,7 @@ void main() {
|
|||
if (sp.x < lo.x || sp.y < lo.y) continue;
|
||||
if (sp.x >= hi.x || sp.y >= hi.y) continue;
|
||||
|
||||
vec2 t = (sp - s_v0[c].xy) / s_v0[c].zw;
|
||||
vec2 t = (sp - s_v0[c].xy) * s_inv[c];
|
||||
vec2 uv = mix(s_v1[c].xy, s_v1[c].zw, t);
|
||||
|
||||
// Font slots are push constants — provably dynamically uniform,
|
||||
|
|
@ -312,12 +327,8 @@ void main() {
|
|||
|
||||
float dAtlas = (ON_EDGE - sdf) * DIST_SCALE;
|
||||
|
||||
vec2 uvSpan = s_v1[c].zw - s_v1[c].xy;
|
||||
vec2 atlasPerScreen = (uvSpan * 1024.0) / s_v0[c].zw;
|
||||
float scalePx = max(atlasPerScreen.x, atlasPerScreen.y);
|
||||
float band = max(scalePx, 0.0001);
|
||||
|
||||
float a = clamp(0.5 - dAtlas / band, 0.0, 1.0);
|
||||
// band (the AA scale) was precomputed once per glyph at load.
|
||||
float a = clamp(0.5 - dAtlas / s_band[c], 0.0, 1.0);
|
||||
if (a <= 0.0) continue;
|
||||
|
||||
vec4 col = s_v2[c];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue