perf(ui): hoist loop-invariant per-item/per-glyph math out of the per-pixel loop (#125) #142

Merged
catbot merged 1 commit from claude/issue-125 into master 2026-06-18 15:22:46 +02:00
Member

Summary

Hoists loop-invariant per-item / per-glyph math out of the per-pixel inner loop and into shared memory at cooperative-load time, where each item is already streamed in once per workgroup. The compiler can't hoist these itself — they read shared memory at a varying index.

Two values, both precomputed once per item into new shared slots:

  1. Per-pixel reciprocal of item-constant rect size (ui-images, ui-text, ui-fused images+text phases): invRectSize = 1.0/rect.zw precomputed at load, so (sp - rect.xy) / rect.zw becomes a multiply by s_invRectSize[c].
  2. Per-glyph SDF AA band (ui-text, ui-fused text phase): the band scale — a vec2 divide plus two maxes that depend only on the glyph's uv span and rect size — is now computed once per glyph into s_band[c].

In ui-fused the new shared slots (s_inv, s_band) are reused across the four phases like the existing s_v* scratch, so the LDS bump stays at the per-category level rather than summing.

Testing

  • crafter-build test — all 23 tests pass, including UIFusedShader (compiles the real kernel with glslang + spirv-val and pins the push-constant layout).
  • All three shaders compile under glslang --target-env vulkan1.4 and pass spirv-val with the engine's block-layout flags.
  • Built and ran the HelloUI example against a live device; text, rounded quads, slider circle, and progress bar all render correctly (text remains crisp, confirming the SDF-band hoist).

Screenshots

result

Resolves #125

## Summary Hoists loop-invariant per-item / per-glyph math out of the per-pixel inner loop and into shared memory at cooperative-load time, where each item is already streamed in once per workgroup. The compiler can't hoist these itself — they read shared memory at a varying index. Two values, both precomputed once per item into new shared slots: 1. **Per-pixel reciprocal of item-constant rect size** (`ui-images`, `ui-text`, `ui-fused` images+text phases): `invRectSize = 1.0/rect.zw` precomputed at load, so `(sp - rect.xy) / rect.zw` becomes a multiply by `s_invRectSize[c]`. 2. **Per-glyph SDF AA band** (`ui-text`, `ui-fused` text phase): the `band` scale — a vec2 divide plus two maxes that depend only on the glyph's uv span and rect size — is now computed once per glyph into `s_band[c]`. In `ui-fused` the new shared slots (`s_inv`, `s_band`) are reused across the four phases like the existing `s_v*` scratch, so the LDS bump stays at the per-category level rather than summing. ## Testing - `crafter-build test` — all 23 tests pass, including `UIFusedShader` (compiles the real kernel with glslang + spirv-val and pins the push-constant layout). - All three shaders compile under glslang `--target-env vulkan1.4` and pass `spirv-val` with the engine's block-layout flags. - Built and ran the `HelloUI` example against a live device; text, rounded quads, slider circle, and progress bar all render correctly (text remains crisp, confirming the SDF-band hoist). ## Screenshots ![result](https://forgejo.catcrafts.net/attachments/6958fbf9-e7f8-4dcc-91d7-767ada036ce4) Resolves #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>
catbot merged commit 2c07abee00 into master 2026-06-18 15:22:46 +02:00
catbot deleted branch claude/issue-125 2026-06-18 15:22:46 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Catcrafts/Crafter.Graphics!142
No description provided.