From 58e7b9a8164bdaad7b0c698b2d0d80db53d79a5c Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Sun, 29 Sep 2013 00:16:48 +0200 Subject: [PATCH] Clip below-zero (out-of-gamut) colors in LiftGammaGainEffect. pow(x, y) for x < 0 is undefined, and behaves differently on nVidia and Intel. This can reasonably happen when having inputs from a different gamut, or just a complex chain before the LGG effect; there's nothing in Movit that prohibits out-of-sRGB-gamut colors. Thus, we need to detect such inputs and clamp them. We could in theory check for the special case of y=1 (no gamma change) and allow negative values through then, but this wouldn't seem like a good solution, especially if animating gamma. Found and debugged by Christophe Thommeret. --- lift_gamma_gain_effect.frag | 4 ++++ lift_gamma_gain_effect_test.cpp | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/lift_gamma_gain_effect.frag b/lift_gamma_gain_effect.frag index 775941e..9047d64 100644 --- a/lift_gamma_gain_effect.frag +++ b/lift_gamma_gain_effect.frag @@ -6,6 +6,10 @@ vec4 FUNCNAME(vec2 tc) { vec4 x = INPUT(tc); x.rgb /= x.aaa; + + // pow() of negative numbers is undefined, so clip out-of-gamut values. + x.rgb = max(x.rgb, 0.0); + x.rgb = pow(x.rgb, vec3(1.0/2.2)); x.rgb += PREFIX(lift) * (vec3(1) - x.rgb); x.rgb = pow(x.rgb, PREFIX(inv_gamma_22)); diff --git a/lift_gamma_gain_effect_test.cpp b/lift_gamma_gain_effect_test.cpp index 0b63063..9850ba2 100644 --- a/lift_gamma_gain_effect_test.cpp +++ b/lift_gamma_gain_effect_test.cpp @@ -94,3 +94,23 @@ TEST(LiftGammaGainEffectTest, Gamma22IsApproximatelysRGB) { expect_equal(data, out_data, 4, 5); } + +TEST(LiftGammaGainEffectTest, OutOfGamutColorsAreClipped) { + float data[] = { + -0.5f, 0.3f, 0.0f, 1.0f, + 0.5f, 0.0f, 0.0f, 1.0f, + 0.0f, 1.5f, 0.5f, 0.3f, + }; + float expected_data[] = { + 0.0f, 0.3f, 0.0f, 1.0f, // Clipped to zero. + 0.5f, 0.0f, 0.0f, 1.0f, + 0.0f, 1.5f, 0.5f, 0.3f, + }; + + float out_data[3 * 4]; + EffectChainTester tester(data, 1, 3, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_sRGB, GAMMA_LINEAR); + tester.get_chain()->add_effect(new LiftGammaGainEffect()); + tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR); + + expect_equal(expected_data, out_data, 4, 3); +} -- 2.39.2