// Custom UI compute shader. Demonstrates the Tier 1 dispatch path: // the user defines their own item struct, writes their own GLSL alongside // the standard shaders (sharing the same UIDispatchHeader contract via // ui-shared.glsl), and dispatches it via UIRenderer::Dispatch. // // What it does: each item is a circle. For every pixel the workgroup tile // owns, if the pixel falls inside any item-circle, the pixel's RGB is // inverted (1 - rgb). Composes naturally with whatever previous dispatches // drew into the swapchain image — works on top of standard quads, custom // effects, anything. #version 460 #extension GL_GOOGLE_include_directive : enable #include "ui-shared.glsl" // Application-defined item: just (cx, cy, radius, _pad). Layout matches the // C++ InverseCircleItem struct in main.cpp byte-for-byte under std430. struct InverseCircleItem { vec4 centerRadius; }; layout(descriptor_heap, std430) readonly buffer InvCircleBuf { InverseCircleItem items[]; } invCircleHeap[]; // NVIDIA workaround — same per-member-load pattern the library shaders use // for the descriptor-heap'd SSBO composite-load issue. InverseCircleItem LoadInverseCircleItem(uint heap, uint i) { InverseCircleItem it; it.centerRadius = invCircleHeap[heap].items[i].centerRadius; return it; } layout(push_constant) uniform PC { UIDispatchHeader hdr; } pc; layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; void main() { ivec2 screenPx; if (!uiResolveScreenPixel(pc.hdr, screenPx)) return; vec2 sp = vec2(screenPx) + 0.5; // Find the strongest circle coverage at this pixel — using max instead // of literal per-item invert so overlapping circles don't double-invert // back to the original. float coverage = 0.0; for (uint i = 0u; i < pc.hdr.itemCount; ++i) { InverseCircleItem it = LoadInverseCircleItem(pc.hdr.itemBuffer, i); vec2 c = it.centerRadius.xy; float r = it.centerRadius.z; float d = length(sp - c) - r; coverage = max(coverage, clamp(0.5 - d, 0.0, 1.0)); } if (coverage <= 0.0) return; vec4 dst = imageLoad(uiImages[pc.hdr.outImage], screenPx); dst.rgb = mix(dst.rgb, vec3(1.0) - dst.rgb, coverage); imageStore(uiImages[pc.hdr.outImage], screenPx, dst); }