#3487, #3488, #3489, #3490, #3491: Levels (Individual Controls): GPU saturates the curve before pow can overflow

WGSL leaves the result of an overflowing pow indeterminate, so clamping
after it did not guarantee the CPU's 1e30 bound on every backend. A curve
past the bound (log2|t| / gamma > 99.7) now saturates to +-1e30 without
calling pow; between 1e30 and 2^99.7 the clamp gives the same 1e30, so the
GPU matches the CPU everywhere.
This commit is contained in:
arnav-hiwarkar committed 2026-11-12 16:35:08 +05:30
1 parent c0387ea18a
commit 047b912fc5
1 file changed
+6 -2
+6 -2
View File
@@ -40,8 +40,12 @@ fn fxt_lv(i: u32, v: f32, clip_b: bool, clip_w: bool) -> f32 {
if (clip_w) {
t = min(t, 1.0);
}
// color2::LEVELS_IC_CURVE_LIMIT keeps the curve finite.
let curve = clamp(fxt_gamma(t, max(data[o + 2u], 0.01)), -1e30, 1e30);
// color2::LEVELS_IC_CURVE_LIMIT keeps the curve finite. WGSL leaves an overflowing pow
// indeterminate, so a curve past the bound saturates before pow: |t|^(1/g) > 1e30 once
// log2|t| / g > 99.66; between 1e30 and 2^99.7 the clamp gives the same 1e30.
let g = max(data[o + 2u], 0.01);
let saturate = abs(t) > 1.0 && log2(abs(t)) / g > 99.7;
let curve = select(clamp(fxt_gamma(t, g), -1e30, 1e30), sign(t) * 1e30, saturate);
return data[o + 3u] + (data[o + 4u] - data[o + 3u]) * curve;
}