forked from 1b-agent/opencadstudio-upstream
fix(render): hatch dpdx in uniform control flow (#414)
Tint (Chrome/Edge WebGPU) rejects derivative builtins reached after the family loop's non-uniform early return, invalidating hatch_web/wipeout shaders on Windows. Take dpdx/dpdy(xz) once at fs_main top and rotate into the family frame in check_family — same math, uniform flow. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
87049967a2
commit
1cf64161d3
3 files changed
+54
-12
No files matched your search
@@ -161,8 +161,13 @@ fn in_polygon(p: vec2<f32>) -> bool {
|
||||
|
||||
// ── Per-family hatch test (identical math to wipeout.wgsl) ─────────────────
|
||||
|
||||
// `ddx_xz`/`ddy_xz` are screen-space derivatives of `xz`, taken once in
|
||||
// fs_main: derivative builtins must run in uniform control flow, and the
|
||||
// per-family loop's early return makes later iterations non-uniform.
|
||||
fn check_family(
|
||||
xz: vec2<f32>,
|
||||
ddx_xz: vec2<f32>,
|
||||
ddy_xz: vec2<f32>,
|
||||
fam: LineFamily,
|
||||
cos_off: f32,
|
||||
sin_off: f32,
|
||||
@@ -183,10 +188,15 @@ fn check_family(
|
||||
let k = round(perp / perp_step);
|
||||
let dperp = perp - k * perp_step;
|
||||
let d = abs(dperp);
|
||||
let half_px = length(vec2<f32>(dpdx(perp), dpdy(perp))) * 0.5;
|
||||
// perp is linear in xz (offsets are constant), so its derivatives are the
|
||||
// xz derivatives rotated into the family frame.
|
||||
let half_px = length(vec2<f32>(
|
||||
-ddx_xz.x * sin_a + ddx_xz.y * cos_a,
|
||||
-ddy_xz.x * sin_a + ddy_xz.y * cos_a,
|
||||
)) * 0.5;
|
||||
|
||||
let wpx = length(vec2<f32>(dpdx(xz.x), dpdy(xz.x)));
|
||||
let wpy = length(vec2<f32>(dpdx(xz.y), dpdy(xz.y)));
|
||||
let wpx = length(vec2<f32>(ddx_xz.x, ddy_xz.x));
|
||||
let wpy = length(vec2<f32>(ddx_xz.y, ddy_xz.y));
|
||||
|
||||
if d > half_px * 2.0 { return false; }
|
||||
|
||||
@@ -220,6 +230,10 @@ fn check_family(
|
||||
// ── Fragment shader ────────────────────────────────────────────────────────
|
||||
|
||||
@fragment fn fs_main(v: VOut) -> @location(0) vec4<f32> {
|
||||
// Taken here, in uniform control flow — see check_family.
|
||||
let ddx_xz = dpdx(v.xz);
|
||||
let ddy_xz = dpdy(v.xz);
|
||||
|
||||
if !in_polygon(v.xz) { discard; }
|
||||
|
||||
let base_mode = h.mode & 0xFFu;
|
||||
@@ -271,7 +285,7 @@ fn check_family(
|
||||
let cos_off = cos(h.angle_offset);
|
||||
let sin_off = sin(h.angle_offset);
|
||||
for (var i = 0u; i < h.n_families; i++) {
|
||||
if check_family(v.xz, load_family(i), cos_off, sin_off, h.scale) {
|
||||
if check_family(v.xz, ddx_xz, ddy_xz, load_family(i), cos_off, sin_off, h.scale) {
|
||||
return h.color;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user