Merge pull request 'perf(ui): skip the destination read-modify-write on empty tiles (#127)' (#144) from claude/issue-127 into master
This commit is contained in:
commit
e1222c0ab7
4 changed files with 60 additions and 28 deletions
|
|
@ -23,12 +23,16 @@ void main() {
|
||||||
ivec2 screenPx;
|
ivec2 screenPx;
|
||||||
bool valid = uiResolveScreenPixel(pc.hdr, screenPx);
|
bool valid = uiResolveScreenPixel(pc.hdr, screenPx);
|
||||||
|
|
||||||
|
// Defer the destination read-modify-write: a sparse UI leaves most tiles
|
||||||
|
// untouched, so only load the pixel when the first surviving item blends
|
||||||
|
// over it (`loaded`), and only store when something actually touched it.
|
||||||
|
// The fused kernel amortizes a single load/store across all categories; the
|
||||||
|
// standalone Dispatch* path has no such umbrella and otherwise pays a full
|
||||||
|
// read-modify-write per empty tile.
|
||||||
vec4 dst = vec4(0.0);
|
vec4 dst = vec4(0.0);
|
||||||
vec2 sp = vec2(0.0);
|
vec2 sp = vec2(0.0);
|
||||||
if (valid) {
|
bool loaded = false;
|
||||||
dst = imageLoad(uiImages[pc.hdr.outImage], screenPx);
|
if (valid) sp = vec2(screenPx) + 0.5;
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,12 +29,16 @@ void main() {
|
||||||
ivec2 screenPx;
|
ivec2 screenPx;
|
||||||
bool valid = uiResolveScreenPixel(pc.hdr, screenPx);
|
bool valid = uiResolveScreenPixel(pc.hdr, screenPx);
|
||||||
|
|
||||||
|
// Defer the destination read-modify-write: a sparse UI leaves most tiles
|
||||||
|
// untouched, so only load the pixel when the first surviving item blends
|
||||||
|
// over it (`loaded`), and only store when something actually touched it.
|
||||||
|
// The fused kernel amortizes a single load/store across all categories; the
|
||||||
|
// standalone Dispatch* path has no such umbrella and otherwise pays a full
|
||||||
|
// read-modify-write per empty tile.
|
||||||
vec4 dst = vec4(0.0);
|
vec4 dst = vec4(0.0);
|
||||||
vec2 sp = vec2(0.0);
|
vec2 sp = vec2(0.0);
|
||||||
if (valid) {
|
bool loaded = false;
|
||||||
dst = imageLoad(uiImages[pc.hdr.outImage], screenPx);
|
if (valid) sp = vec2(screenPx) + 0.5;
|
||||||
sp = vec2(screenPx) + 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec2 tileMin, tileMax;
|
vec2 tileMin, tileMax;
|
||||||
uiTileBounds(tileMin, tileMax);
|
uiTileBounds(tileMin, tileMax);
|
||||||
|
|
@ -86,11 +90,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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,12 +27,16 @@ void main() {
|
||||||
ivec2 screenPx;
|
ivec2 screenPx;
|
||||||
bool valid = uiResolveScreenPixel(pc.hdr, screenPx);
|
bool valid = uiResolveScreenPixel(pc.hdr, screenPx);
|
||||||
|
|
||||||
|
// Defer the destination read-modify-write: a sparse UI leaves most tiles
|
||||||
|
// untouched, so only load the pixel when the first surviving item blends
|
||||||
|
// over it (`loaded`), and only store when something actually touched it.
|
||||||
|
// The fused kernel amortizes a single load/store across all categories; the
|
||||||
|
// standalone Dispatch* path has no such umbrella and otherwise pays a full
|
||||||
|
// read-modify-write per empty tile.
|
||||||
vec4 dst = vec4(0.0);
|
vec4 dst = vec4(0.0);
|
||||||
vec2 sp = vec2(0.0);
|
vec2 sp = vec2(0.0);
|
||||||
if (valid) {
|
bool loaded = false;
|
||||||
dst = imageLoad(uiImages[pc.hdr.outImage], screenPx);
|
if (valid) sp = vec2(screenPx) + 0.5;
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,12 +38,16 @@ void main() {
|
||||||
ivec2 screenPx;
|
ivec2 screenPx;
|
||||||
bool valid = uiResolveScreenPixel(pc.hdr, screenPx);
|
bool valid = uiResolveScreenPixel(pc.hdr, screenPx);
|
||||||
|
|
||||||
|
// Defer the destination read-modify-write: a sparse UI leaves most tiles
|
||||||
|
// untouched, so only load the pixel when the first surviving glyph blends
|
||||||
|
// over it (`loaded`), and only store when something actually touched it.
|
||||||
|
// The fused kernel amortizes a single load/store across all categories; the
|
||||||
|
// standalone Dispatch* path has no such umbrella and otherwise pays a full
|
||||||
|
// read-modify-write per empty tile.
|
||||||
vec4 dst = vec4(0.0);
|
vec4 dst = vec4(0.0);
|
||||||
vec2 sp = vec2(0.0);
|
vec2 sp = vec2(0.0);
|
||||||
if (valid) {
|
bool loaded = false;
|
||||||
dst = imageLoad(uiImages[pc.hdr.outImage], screenPx);
|
if (valid) sp = vec2(screenPx) + 0.5;
|
||||||
sp = vec2(screenPx) + 0.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
vec2 tileMin, tileMax;
|
vec2 tileMin, tileMax;
|
||||||
uiTileBounds(tileMin, tileMax);
|
uiTileBounds(tileMin, tileMax);
|
||||||
|
|
@ -110,11 +114,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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue