1 // Unit tests for ColorspaceConversionEffect.
5 #include "colorspace_conversion_effect.h"
6 #include "gtest/gtest.h"
11 TEST(ColorspaceConversionEffectTest, Reversible) {
13 0.0f, 0.0f, 0.0f, 1.0f,
14 1.0f, 1.0f, 1.0f, 1.0f,
15 1.0f, 0.0f, 0.0f, 1.0f,
16 0.0f, 1.0f, 0.0f, 1.0f,
17 0.0f, 0.0f, 1.0f, 1.0f,
18 0.0f, 1.0f, 1.0f, 0.5f,
20 float temp_data[4 * 6], out_data[4 * 6];
23 EffectChainTester tester(data, 1, 6, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_sRGB, GAMMA_LINEAR);
24 tester.run(temp_data, GL_RGBA, COLORSPACE_REC_601_525, GAMMA_LINEAR);
27 EffectChainTester tester(temp_data, 1, 6, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_REC_601_525, GAMMA_LINEAR);
28 tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR);
31 expect_equal(data, out_data, 4, 6);
34 TEST(ColorspaceConversionEffectTest, sRGB_Primaries) {
36 0.0f, 0.0f, 0.0f, 1.0f,
37 1.0f, 1.0f, 1.0f, 1.0f,
38 1.0f, 0.0f, 0.0f, 1.0f,
39 0.0f, 1.0f, 0.0f, 1.0f,
40 0.0f, 0.0f, 1.0f, 1.0f,
42 float out_data[4 * 5];
44 EffectChainTester tester(data, 1, 5, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_sRGB, GAMMA_LINEAR, GL_RGBA32F);
45 tester.run(out_data, GL_RGBA, COLORSPACE_XYZ, GAMMA_LINEAR);
47 // Black should stay black.
48 EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 0]);
49 EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 1]);
50 EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 2]);
51 EXPECT_FLOAT_EQ(1.0f, out_data[0 * 4 + 3]);
53 // White point should be D65.
54 // XYZ values from http://en.wikipedia.org/wiki/CIE_Standard_Illuminant_D65.
55 EXPECT_NEAR(0.9505, out_data[1 * 4 + 0], 1e-3);
56 EXPECT_NEAR(1.0000, out_data[1 * 4 + 1], 1e-3);
57 EXPECT_NEAR(1.0889, out_data[1 * 4 + 2], 1e-3);
58 EXPECT_FLOAT_EQ(1.0f, out_data[1 * 4 + 3]);
60 float white_xyz_sum = out_data[1 * 4 + 0] + out_data[1 * 4 + 1] + out_data[1 * 4 + 2];
61 float white_x = out_data[1 * 4 + 0] / white_xyz_sum;
62 float white_y = out_data[1 * 4 + 1] / white_xyz_sum;
63 EXPECT_NEAR(0.3127, white_x, 1e-3);
64 EXPECT_NEAR(0.3290, white_y, 1e-3);
65 EXPECT_FLOAT_EQ(1.0f, out_data[1 * 4 + 3]);
67 // Convert the primaries from XYZ to xyz, and compare to the references
68 // given by Rec. 709 (which are shared with sRGB).
70 float red_xyz_sum = out_data[2 * 4 + 0] + out_data[2 * 4 + 1] + out_data[2 * 4 + 2];
71 float red_x = out_data[2 * 4 + 0] / red_xyz_sum;
72 float red_y = out_data[2 * 4 + 1] / red_xyz_sum;
73 EXPECT_NEAR(0.640, red_x, 1e-3);
74 EXPECT_NEAR(0.330, red_y, 1e-3);
75 EXPECT_FLOAT_EQ(1.0f, out_data[2 * 4 + 3]);
77 float green_xyz_sum = out_data[3 * 4 + 0] + out_data[3 * 4 + 1] + out_data[3 * 4 + 2];
78 float green_x = out_data[3 * 4 + 0] / green_xyz_sum;
79 float green_y = out_data[3 * 4 + 1] / green_xyz_sum;
80 EXPECT_NEAR(0.300, green_x, 1e-3);
81 EXPECT_NEAR(0.600, green_y, 1e-3);
82 EXPECT_FLOAT_EQ(1.0f, out_data[3 * 4 + 3]);
84 float blue_xyz_sum = out_data[4 * 4 + 0] + out_data[4 * 4 + 1] + out_data[4 * 4 + 2];
85 float blue_x = out_data[4 * 4 + 0] / blue_xyz_sum;
86 float blue_y = out_data[4 * 4 + 1] / blue_xyz_sum;
87 EXPECT_NEAR(0.150, blue_x, 1e-3);
88 EXPECT_NEAR(0.060, blue_y, 1e-3);
89 EXPECT_FLOAT_EQ(1.0f, out_data[4 * 4 + 3]);
91 // The forward matrix should be exactly as specified in the standard,
92 // up to floating-point precision. (We're not compliant with the
93 // inverse matrix, but we should be very close.)
94 EXPECT_FLOAT_EQ(0.4124f, out_data[2 * 4 + 0]);
95 EXPECT_FLOAT_EQ(0.2126f, out_data[2 * 4 + 1]);
96 EXPECT_FLOAT_EQ(0.0193f, out_data[2 * 4 + 2]);
98 EXPECT_FLOAT_EQ(0.3576f, out_data[3 * 4 + 0]);
99 EXPECT_FLOAT_EQ(0.7152f, out_data[3 * 4 + 1]);
100 EXPECT_FLOAT_EQ(0.1192f, out_data[3 * 4 + 2]);
102 EXPECT_FLOAT_EQ(0.1805f, out_data[4 * 4 + 0]);
103 EXPECT_FLOAT_EQ(0.0722f, out_data[4 * 4 + 1]);
104 EXPECT_FLOAT_EQ(0.9505f, out_data[4 * 4 + 2]);
107 TEST(ColorspaceConversionEffectTest, Rec601_525_Primaries) {
109 0.0f, 0.0f, 0.0f, 1.0f,
110 1.0f, 1.0f, 1.0f, 1.0f,
111 1.0f, 0.0f, 0.0f, 1.0f,
112 0.0f, 1.0f, 0.0f, 1.0f,
113 0.0f, 0.0f, 1.0f, 1.0f,
115 float out_data[4 * 5];
117 EffectChainTester tester(data, 1, 5, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_REC_601_525, GAMMA_LINEAR);
118 tester.run(out_data, GL_RGBA, COLORSPACE_XYZ, GAMMA_LINEAR);
120 // Black should stay black.
121 EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 0]);
122 EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 1]);
123 EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 2]);
124 EXPECT_FLOAT_EQ(1.0f, out_data[0 * 4 + 3]);
126 // Convert the primaries from XYZ to xyz, and compare to the references
127 // given by Rec. 601.
128 float white_xyz_sum = out_data[1 * 4 + 0] + out_data[1 * 4 + 1] + out_data[1 * 4 + 2];
129 float white_x = out_data[1 * 4 + 0] / white_xyz_sum;
130 float white_y = out_data[1 * 4 + 1] / white_xyz_sum;
131 EXPECT_NEAR(0.3127, white_x, 1e-3);
132 EXPECT_NEAR(0.3290, white_y, 1e-3);
133 EXPECT_FLOAT_EQ(1.0f, out_data[1 * 4 + 3]);
135 float red_xyz_sum = out_data[2 * 4 + 0] + out_data[2 * 4 + 1] + out_data[2 * 4 + 2];
136 float red_x = out_data[2 * 4 + 0] / red_xyz_sum;
137 float red_y = out_data[2 * 4 + 1] / red_xyz_sum;
138 EXPECT_NEAR(0.630, red_x, 1e-3);
139 EXPECT_NEAR(0.340, red_y, 1e-3);
140 EXPECT_FLOAT_EQ(1.0f, out_data[2 * 4 + 3]);
142 float green_xyz_sum = out_data[3 * 4 + 0] + out_data[3 * 4 + 1] + out_data[3 * 4 + 2];
143 float green_x = out_data[3 * 4 + 0] / green_xyz_sum;
144 float green_y = out_data[3 * 4 + 1] / green_xyz_sum;
145 EXPECT_NEAR(0.310, green_x, 1e-3);
146 EXPECT_NEAR(0.595, green_y, 1e-3);
147 EXPECT_FLOAT_EQ(1.0f, out_data[3 * 4 + 3]);
149 float blue_xyz_sum = out_data[4 * 4 + 0] + out_data[4 * 4 + 1] + out_data[4 * 4 + 2];
150 float blue_x = out_data[4 * 4 + 0] / blue_xyz_sum;
151 float blue_y = out_data[4 * 4 + 1] / blue_xyz_sum;
152 EXPECT_NEAR(0.155, blue_x, 1e-3);
153 EXPECT_NEAR(0.070, blue_y, 1e-3);
154 EXPECT_FLOAT_EQ(1.0f, out_data[4 * 4 + 3]);
157 TEST(ColorspaceConversionEffectTest, Rec601_625_Primaries) {
159 0.0f, 0.0f, 0.0f, 1.0f,
160 1.0f, 1.0f, 1.0f, 1.0f,
161 1.0f, 0.0f, 0.0f, 1.0f,
162 0.0f, 1.0f, 0.0f, 1.0f,
163 0.0f, 0.0f, 1.0f, 1.0f,
165 float out_data[4 * 5];
167 EffectChainTester tester(data, 1, 5, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_REC_601_625, GAMMA_LINEAR);
168 tester.run(out_data, GL_RGBA, COLORSPACE_XYZ, GAMMA_LINEAR);
170 // Black should stay black.
171 EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 0]);
172 EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 1]);
173 EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 2]);
174 EXPECT_FLOAT_EQ(1.0f, out_data[0 * 4 + 3]);
176 // Convert the primaries from XYZ to xyz, and compare to the references
177 // given by Rec. 601.
178 float white_xyz_sum = out_data[1 * 4 + 0] + out_data[1 * 4 + 1] + out_data[1 * 4 + 2];
179 float white_x = out_data[1 * 4 + 0] / white_xyz_sum;
180 float white_y = out_data[1 * 4 + 1] / white_xyz_sum;
181 EXPECT_NEAR(0.3127, white_x, 1e-3);
182 EXPECT_NEAR(0.3290, white_y, 1e-3);
183 EXPECT_FLOAT_EQ(1.0f, out_data[1 * 4 + 3]);
185 float red_xyz_sum = out_data[2 * 4 + 0] + out_data[2 * 4 + 1] + out_data[2 * 4 + 2];
186 float red_x = out_data[2 * 4 + 0] / red_xyz_sum;
187 float red_y = out_data[2 * 4 + 1] / red_xyz_sum;
188 EXPECT_NEAR(0.640, red_x, 1e-3);
189 EXPECT_NEAR(0.330, red_y, 1e-3);
190 EXPECT_FLOAT_EQ(1.0f, out_data[2 * 4 + 3]);
192 float green_xyz_sum = out_data[3 * 4 + 0] + out_data[3 * 4 + 1] + out_data[3 * 4 + 2];
193 float green_x = out_data[3 * 4 + 0] / green_xyz_sum;
194 float green_y = out_data[3 * 4 + 1] / green_xyz_sum;
195 EXPECT_NEAR(0.290, green_x, 1e-3);
196 EXPECT_NEAR(0.600, green_y, 1e-3);
197 EXPECT_FLOAT_EQ(1.0f, out_data[3 * 4 + 3]);
199 float blue_xyz_sum = out_data[4 * 4 + 0] + out_data[4 * 4 + 1] + out_data[4 * 4 + 2];
200 float blue_x = out_data[4 * 4 + 0] / blue_xyz_sum;
201 float blue_y = out_data[4 * 4 + 1] / blue_xyz_sum;
202 EXPECT_NEAR(0.150, blue_x, 1e-3);
203 EXPECT_NEAR(0.060, blue_y, 1e-3);
204 EXPECT_FLOAT_EQ(1.0f, out_data[4 * 4 + 3]);
207 TEST(ColorspaceConversionEffectTest, Rec2020_Primaries) {
209 0.0f, 0.0f, 0.0f, 1.0f,
210 1.0f, 1.0f, 1.0f, 1.0f,
211 1.0f, 0.0f, 0.0f, 1.0f,
212 0.0f, 1.0f, 0.0f, 1.0f,
213 0.0f, 0.0f, 1.0f, 1.0f,
215 float out_data[4 * 5];
217 EffectChainTester tester(data, 1, 5, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_REC_2020, GAMMA_LINEAR);
218 tester.run(out_data, GL_RGBA, COLORSPACE_XYZ, GAMMA_LINEAR);
220 // Black should stay black.
221 EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 0]);
222 EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 1]);
223 EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 2]);
224 EXPECT_FLOAT_EQ(1.0f, out_data[0 * 4 + 3]);
226 // Convert the primaries from XYZ to xyz, and compare to the references
227 // given by Rec. 2020.
228 float white_xyz_sum = out_data[1 * 4 + 0] + out_data[1 * 4 + 1] + out_data[1 * 4 + 2];
229 float white_x = out_data[1 * 4 + 0] / white_xyz_sum;
230 float white_y = out_data[1 * 4 + 1] / white_xyz_sum;
231 EXPECT_NEAR(0.3127, white_x, 1e-3);
232 EXPECT_NEAR(0.3290, white_y, 1e-3);
233 EXPECT_FLOAT_EQ(1.0f, out_data[1 * 4 + 3]);
235 float red_xyz_sum = out_data[2 * 4 + 0] + out_data[2 * 4 + 1] + out_data[2 * 4 + 2];
236 float red_x = out_data[2 * 4 + 0] / red_xyz_sum;
237 float red_y = out_data[2 * 4 + 1] / red_xyz_sum;
238 EXPECT_NEAR(0.708, red_x, 1e-3);
239 EXPECT_NEAR(0.292, red_y, 1e-3);
240 EXPECT_FLOAT_EQ(1.0f, out_data[2 * 4 + 3]);
242 float green_xyz_sum = out_data[3 * 4 + 0] + out_data[3 * 4 + 1] + out_data[3 * 4 + 2];
243 float green_x = out_data[3 * 4 + 0] / green_xyz_sum;
244 float green_y = out_data[3 * 4 + 1] / green_xyz_sum;
245 EXPECT_NEAR(0.170, green_x, 1e-3);
246 EXPECT_NEAR(0.797, green_y, 1e-3);
247 EXPECT_FLOAT_EQ(1.0f, out_data[3 * 4 + 3]);
249 float blue_xyz_sum = out_data[4 * 4 + 0] + out_data[4 * 4 + 1] + out_data[4 * 4 + 2];
250 float blue_x = out_data[4 * 4 + 0] / blue_xyz_sum;
251 float blue_y = out_data[4 * 4 + 1] / blue_xyz_sum;
252 EXPECT_NEAR(0.131, blue_x, 1e-3);
253 EXPECT_NEAR(0.046, blue_y, 1e-3);
254 EXPECT_FLOAT_EQ(1.0f, out_data[4 * 4 + 3]);
257 TEST(ColorspaceConversionEffectTest, sRGBToRec601_525) {
259 0.0f, 0.0f, 0.0f, 1.0f,
260 1.0f, 1.0f, 1.0f, 1.0f,
261 1.0f, 0.0f, 0.0f, 1.0f,
262 0.0f, 1.0f, 0.0f, 1.0f,
263 0.0f, 0.0f, 1.0f, 1.0f,
264 0.0f, 1.0f, 1.0f, 0.5f,
267 // I have to admit that most of these come from the code itself;
268 // however, they do make sense if you look at the two gamuts
270 float expected_data[] = {
271 // Black should stay black.
272 0.0f, 0.0f, 0.0f, 1.0f,
274 // White should stay white (both use the D65 white point).
275 1.0f, 1.0f, 1.0f, 1.0f,
277 // sRGB red is slightly out-of-gamut for Rec. 601/525.
278 1.064f, -0.020f, 0.0f, 1.0f,
281 -0.055f, 1.036f, 0.004f, 1.0f,
283 // The blues are much closer; it _is_ still out-of-gamut,
284 // but not actually more saturated (farther from the
286 -0.010f, -0.017f, 0.994f, 1.0f,
288 // Cyan is a mix of green and blue. Note: The alpha is kept.
289 -0.065f, 1.0195f, 0.998f, 0.5f,
291 float out_data[4 * 6];
293 EffectChainTester tester(data, 1, 6, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_sRGB, GAMMA_LINEAR);
294 tester.run(out_data, GL_RGBA, COLORSPACE_REC_601_525, GAMMA_LINEAR);
296 expect_equal(expected_data, out_data, 4, 6);