`7c50a3e` renamed a length's `abs` component to `px` and took the WGSL `abs()` builtin in the rounded-rect distance with it, so every window failed shader validation on the first frame while `cargo test` stayed green. `naga` is reachable through `wgpu`, so a unit test now composes each shader file with the prelude the way the renderer does and parses and validates it; it reads the shader directory rather than naming primitives, so a new one is covered by adding its file. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
40 lines
1.1 KiB
WebGPU Shading Language
40 lines
1.1 KiB
WebGPU Shading Language
struct Rect {
|
|
color: u32,
|
|
radius: f32,
|
|
thickness: f32,
|
|
inner_radius: f32,
|
|
}
|
|
|
|
@group(1) @binding(0)
|
|
var<storage> rects: array<Rect>;
|
|
|
|
@fragment
|
|
fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
|
let rect = rects[in.idx];
|
|
var color = unpack4x8unorm(rect.color);
|
|
|
|
let edge = 0.5;
|
|
let size = in.bot_right - in.top_left;
|
|
let corner = size / 2.0;
|
|
let center = in.top_left + corner;
|
|
let pos = in.clip_position.xy;
|
|
|
|
let dist = distance_from_rect(pos, center, corner, rect.radius);
|
|
color.a *= 1.0 - smoothstep(-min(edge, rect.radius), edge, dist);
|
|
|
|
if rect.thickness > 0.0 {
|
|
let dist2 = distance_from_rect(pos, center, corner - rect.thickness, rect.inner_radius);
|
|
color.a *= smoothstep(-min(edge, rect.inner_radius), edge, dist2);
|
|
}
|
|
|
|
return masked(in, color);
|
|
}
|
|
|
|
fn distance_from_rect(pixel_pos: vec2<f32>, rect_center: vec2<f32>, rect_corner: vec2<f32>, radius: f32) -> f32 {
|
|
// vec from center to pixel
|
|
let p = pixel_pos - rect_center;
|
|
// vec from inner rect corner to pixel
|
|
let q = abs(p) - (rect_corner - radius);
|
|
return length(max(q, vec2(0.0))) - radius;
|
|
}
|