UI rewrite 3rd attempt

This commit is contained in:
Jorijn van der Graaf 2026-05-02 21:08:20 +02:00
commit 1f5697326c
48 changed files with 2155 additions and 6190 deletions

View file

@ -0,0 +1,61 @@
// 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);
}