+TEST(GammaCompressionEffectTest, Rec709_Accuracy) {
+ float data[256], expected_data[256], out_data[256];
+
+ for (int i = 0; i < 256; ++i) {
+ double x = i / 255.0;
+
+ expected_data[i] = x;
+
+ // Rec. 2020, page 3.
+ if (x < 0.018 * 4.5) {
+ data[i] = x / 4.5;
+ } else {
+ data[i] = pow((x + 0.099) / 1.099, 1.0 / 0.45);
+ }
+ }
+
+ EffectChainTester tester(data, 256, 1, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, GL_RGBA32F);
+ tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_REC_709);
+
+ // Maximum absolute error is 25% of one pixel level. For comparison,
+ // a straightforward ALU solution (using a branch and pow()), used as a
+ // “high anchor” to indicate limitations of float arithmetic etc.,
+ // reaches maximum absolute error of 3.7% of one pixel level
+ // and rms of 3.5e-6.
+ expect_equal(expected_data, out_data, 256, 1, 0.25 / 255.0, 1e-5);
+}
+
+// This test tests the same gamma ramp as Rec709_Accuracy, but with 10-bit
+// input range and somewhat looser error bounds. (One could claim that this is
+// already on the limit of what we can reasonably do with fp16 input, if you
+// look at the local relative error.)
+TEST(GammaCompressionEffectTest, Rec2020_10Bit_Accuracy) {
+ float data[1024], expected_data[1024], out_data[1024];
+
+ for (int i = 0; i < 1024; ++i) {
+ double x = i / 1023.0;
+
+ expected_data[i] = x;
+
+ // Rec. 2020, page 3.
+ if (x < 0.018 * 4.5) {
+ data[i] = x / 4.5;
+ } else {
+ data[i] = pow((x + 0.099) / 1.099, 1.0 / 0.45);
+ }
+ }
+
+ EffectChainTester tester(data, 1024, 1, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, GL_RGBA32F);
+ tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_REC_2020_10_BIT);
+
+ // Maximum absolute error is 30% of one pixel level. For comparison,
+ // a straightforward ALU solution (using a branch and pow()), used as a
+ // “high anchor” to indicate limitations of float arithmetic etc.,
+ // reaches maximum absolute error of 25.2% of one pixel level
+ // and rms of 1.8e-6, so this is probably mostly related to input precision.
+ expect_equal(expected_data, out_data, 1024, 1, 0.30 / 1023.0, 1e-5);
+}
+