perf(ui): skip the destination read-modify-write on empty tiles (#127) #144

Merged
catbot merged 1 commit from claude/issue-127 into master 2026-06-18 15:27:08 +02:00
4 changed files with 60 additions and 28 deletions

View file

@ -23,12 +23,16 @@ void main() {
ivec2 screenPx; ivec2 screenPx;
bool valid = uiResolveScreenPixel(pc.hdr, screenPx); bool valid = uiResolveScreenPixel(pc.hdr, screenPx);
vec4 dst = vec4(0.0); // Defer the destination read-modify-write: a sparse UI leaves most tiles
vec2 sp = vec2(0.0); // untouched, so only load the pixel when the first surviving item blends
if (valid) { // over it (`loaded`), and only store when something actually touched it.
dst = imageLoad(uiImages[pc.hdr.outImage], screenPx); // The fused kernel amortizes a single load/store across all categories; the
sp = vec2(screenPx) + 0.5; // standalone Dispatch* path has no such umbrella and otherwise pays a full
} // read-modify-write per empty tile.
vec4 dst = vec4(0.0);
vec2 sp = vec2(0.0);
bool loaded = false;
if (valid) sp = vec2(screenPx) + 0.5;
vec2 tileMin, tileMax; vec2 tileMin, tileMax;
uiTileBounds(tileMin, tileMax); uiTileBounds(tileMin, tileMax);
@ -90,11 +94,15 @@ void main() {
} }
if (src.a <= 0.0) continue; if (src.a <= 0.0) continue;
if (!loaded) {
dst = imageLoad(uiImages[pc.hdr.outImage], screenPx);
loaded = true;
}
dst = uiBlendOver(dst, src); dst = uiBlendOver(dst, src);
} }
} }
barrier(); barrier();
} }
if (valid) imageStore(uiImages[pc.hdr.outImage], screenPx, dst); if (loaded) imageStore(uiImages[pc.hdr.outImage], screenPx, dst); // loaded ⇒ valid
} }

View file

@ -24,12 +24,16 @@ void main() {
ivec2 screenPx; ivec2 screenPx;
bool valid = uiResolveScreenPixel(pc.hdr, screenPx); bool valid = uiResolveScreenPixel(pc.hdr, screenPx);
vec4 dst = vec4(0.0); // Defer the destination read-modify-write: a sparse UI leaves most tiles
vec2 sp = vec2(0.0); // untouched, so only load the pixel when the first surviving item blends
if (valid) { // over it (`loaded`), and only store when something actually touched it.
dst = imageLoad(uiImages[pc.hdr.outImage], screenPx); // The fused kernel amortizes a single load/store across all categories; the
sp = vec2(screenPx) + 0.5; // standalone Dispatch* path has no such umbrella and otherwise pays a full
} // read-modify-write per empty tile.
vec4 dst = vec4(0.0);
vec2 sp = vec2(0.0);
bool loaded = false;
if (valid) sp = vec2(screenPx) + 0.5;
vec2 tileMin, tileMax; vec2 tileMin, tileMax;
uiTileBounds(tileMin, tileMax); uiTileBounds(tileMin, tileMax);
@ -80,11 +84,15 @@ void main() {
); );
vec4 src = sampled * s_tint[c]; vec4 src = sampled * s_tint[c];
if (src.a <= 0.0) continue; if (src.a <= 0.0) continue;
if (!loaded) {
dst = imageLoad(uiImages[pc.hdr.outImage], screenPx);
loaded = true;
}
dst = uiBlendOver(dst, src); dst = uiBlendOver(dst, src);
} }
} }
barrier(); barrier();
} }
if (valid) imageStore(uiImages[pc.hdr.outImage], screenPx, dst); if (loaded) imageStore(uiImages[pc.hdr.outImage], screenPx, dst); // loaded ⇒ valid
} }

View file

@ -27,12 +27,16 @@ void main() {
ivec2 screenPx; ivec2 screenPx;
bool valid = uiResolveScreenPixel(pc.hdr, screenPx); bool valid = uiResolveScreenPixel(pc.hdr, screenPx);
vec4 dst = vec4(0.0); // Defer the destination read-modify-write: a sparse UI leaves most tiles
vec2 sp = vec2(0.0); // untouched, so only load the pixel when the first surviving item blends
if (valid) { // over it (`loaded`), and only store when something actually touched it.
dst = imageLoad(uiImages[pc.hdr.outImage], screenPx); // The fused kernel amortizes a single load/store across all categories; the
sp = vec2(screenPx) + 0.5; // standalone Dispatch* path has no such umbrella and otherwise pays a full
} // read-modify-write per empty tile.
vec4 dst = vec4(0.0);
vec2 sp = vec2(0.0);
bool loaded = false;
if (valid) sp = vec2(screenPx) + 0.5;
vec2 tileMin, tileMax; vec2 tileMin, tileMax;
uiTileBounds(tileMin, tileMax); uiTileBounds(tileMin, tileMax);
@ -93,11 +97,15 @@ void main() {
} }
if (src.a <= 0.0) continue; if (src.a <= 0.0) continue;
if (!loaded) {
dst = imageLoad(uiImages[pc.hdr.outImage], screenPx);
loaded = true;
}
dst = uiBlendOver(dst, src); dst = uiBlendOver(dst, src);
} }
} }
barrier(); // done reading shared for this chunk before it's overwritten barrier(); // done reading shared for this chunk before it's overwritten
} }
if (valid) imageStore(uiImages[pc.hdr.outImage], screenPx, dst); if (loaded) imageStore(uiImages[pc.hdr.outImage], screenPx, dst); // loaded ⇒ valid
} }

View file

@ -31,12 +31,16 @@ void main() {
ivec2 screenPx; ivec2 screenPx;
bool valid = uiResolveScreenPixel(pc.hdr, screenPx); bool valid = uiResolveScreenPixel(pc.hdr, screenPx);
vec4 dst = vec4(0.0); // Defer the destination read-modify-write: a sparse UI leaves most tiles
vec2 sp = vec2(0.0); // untouched, so only load the pixel when the first surviving glyph blends
if (valid) { // over it (`loaded`), and only store when something actually touched it.
dst = imageLoad(uiImages[pc.hdr.outImage], screenPx); // The fused kernel amortizes a single load/store across all categories; the
sp = vec2(screenPx) + 0.5; // standalone Dispatch* path has no such umbrella and otherwise pays a full
} // read-modify-write per empty tile.
vec4 dst = vec4(0.0);
vec2 sp = vec2(0.0);
bool loaded = false;
if (valid) sp = vec2(screenPx) + 0.5;
vec2 tileMin, tileMax; vec2 tileMin, tileMax;
uiTileBounds(tileMin, tileMax); uiTileBounds(tileMin, tileMax);
@ -102,11 +106,15 @@ void main() {
vec4 col = s_color[c]; vec4 col = s_color[c];
vec4 src = vec4(col.rgb, col.a * a); vec4 src = vec4(col.rgb, col.a * a);
if (!loaded) {
dst = imageLoad(uiImages[pc.hdr.outImage], screenPx);
loaded = true;
}
dst = uiBlendOver(dst, src); dst = uiBlendOver(dst, src);
} }
} }
barrier(); barrier();
} }
if (valid) imageStore(uiImages[pc.hdr.outImage], screenPx, dst); if (loaded) imageStore(uiImages[pc.hdr.outImage], screenPx, dst); // loaded ⇒ valid
} }