oarust 0.8.6

GPU-first semantic computing engine written in Rust
// DrawRect.slang — alpha-blended filled rectangle on the compose storage image.
//
// Donor: oacpp/source/cpp/lib/oa/ui/shader/compute/drawRect.slang
// Adaptation: exact donor shader body.
//
// Dispatch: (ceil(dst_w / 8), ceil(dst_h / 8), 1)

#include "compositor_common.slang"

struct PushConstants {
	uint dst_idx;
	int  dst_x;
	int  dst_y;
	uint dst_w;
	uint dst_h;
	uint rgba;
	int  clip_x;
	int  clip_y;
	uint clip_w;
	uint clip_h;
	float corner_radius;
}

[[vk::push_constant]] PushConstants pc;
[[vk::binding(1, 0)]] RWTexture2D<float4> images[];

float roundedRectCoverage(uint x, uint y) {
	float radius = min(
		max(pc.corner_radius, 0.0),
		0.5 * float(min(pc.dst_w, pc.dst_h)));
	if (radius <= 0.0) return 1.0;
	float2 halfSize = 0.5 * float2(float(pc.dst_w), float(pc.dst_h));
	float2 local = float2(float(x), float(y)) + 0.5 - halfSize;
	float2 q = abs(local) - (halfSize - radius);
	float distance = length(max(q, float2(0.0, 0.0)))
		+ min(max(q.x, q.y), 0.0) - radius;
	return saturate(0.5 - distance);
}

[shader("compute")]
[numthreads(8, 8, 1)]
void main(uint3 gid : SV_GroupID, uint3 lid : SV_GroupThreadID) {
	uint x = gid.x * 8 + lid.x;
	uint y = gid.y * 8 + lid.y;
	if (x >= pc.dst_w || y >= pc.dst_h) return;

	int dstX = pc.dst_x + int(x);
	int dstY = pc.dst_y + int(y);
	if (dstX < pc.clip_x || dstY < pc.clip_y
		|| uint(dstX - pc.clip_x) >= pc.clip_w
		|| uint(dstY - pc.clip_y) >= pc.clip_h) return;
	uint imageWidth;
	uint imageHeight;
	images[pc.dst_idx].GetDimensions(imageWidth, imageHeight);
	if (dstX < 0 || dstY < 0
		|| dstX >= int(imageWidth) || dstY >= int(imageHeight)) return;

	float coverage = roundedRectCoverage(x, y);
	if (coverage <= 0.0) return;

	float4 src = uiUnpackRgba(pc.rgba);
	src.a *= coverage;
	uint2 dstCoord = uint2(uint(dstX), uint(dstY));
	float4 dst = images[pc.dst_idx][dstCoord];
	images[pc.dst_idx][dstCoord] = uiSourceOver(src, dst);
}