From 047b912fc58ecface93af11ce75411b2eda6122a Mon Sep 17 00:00:00 2001 From: arnav-hiwarkar Date: Thu, 12 Nov 2026 16:35:08 +0530 Subject: [PATCH] #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. --- crates/gpu/src/shaders/fx_tone.wgsl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/gpu/src/shaders/fx_tone.wgsl b/crates/gpu/src/shaders/fx_tone.wgsl index bcd23baa7..a47d5df59 100644 --- a/crates/gpu/src/shaders/fx_tone.wgsl +++ b/crates/gpu/src/shaders/fx_tone.wgsl @@ -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; }