Release Movit 1.3.2. (From a branch, since I do not want to break ABI compatibility...
[movit] / colorspace_conversion_effect_test.cpp
1 // Unit tests for ColorspaceConversionEffect.
2
3 #include <epoxy/gl.h>
4
5 #include "colorspace_conversion_effect.h"
6 #include "gtest/gtest.h"
7 #include "test_util.h"
8
9 namespace movit {
10
11 TEST(ColorspaceConversionEffectTest, Reversible) {
12         float data[] = {
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,
19         };
20         float temp_data[4 * 6], out_data[4 * 6];
21
22         {
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);
25         }
26         {
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);
29         }
30
31         expect_equal(data, out_data, 4, 6);
32 }
33
34 TEST(ColorspaceConversionEffectTest, sRGB_Primaries) {
35         float data[] = {
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,
41         };
42         float out_data[4 * 5];
43
44         EffectChainTester tester(data, 1, 5, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_sRGB, GAMMA_LINEAR);
45         tester.run(out_data, GL_RGBA, COLORSPACE_XYZ, GAMMA_LINEAR);
46
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]);
52
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]);
59
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]);
66
67         // Convert the primaries from XYZ to xyz, and compare to the references
68         // given by Rec. 709 (which are shared with sRGB).
69
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]);
76
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]);
83
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]);
90 }
91
92 TEST(ColorspaceConversionEffectTest, Rec601_525_Primaries) {
93         float data[] = {
94                 0.0f, 0.0f, 0.0f, 1.0f,
95                 1.0f, 1.0f, 1.0f, 1.0f,
96                 1.0f, 0.0f, 0.0f, 1.0f,
97                 0.0f, 1.0f, 0.0f, 1.0f,
98                 0.0f, 0.0f, 1.0f, 1.0f,
99         };
100         float out_data[4 * 5];
101
102         EffectChainTester tester(data, 1, 5, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_REC_601_525, GAMMA_LINEAR);
103         tester.run(out_data, GL_RGBA, COLORSPACE_XYZ, GAMMA_LINEAR);
104
105         // Black should stay black.
106         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 0]);
107         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 1]);
108         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 2]);
109         EXPECT_FLOAT_EQ(1.0f, out_data[0 * 4 + 3]);
110
111         // Convert the primaries from XYZ to xyz, and compare to the references
112         // given by Rec. 601.
113         float white_xyz_sum = out_data[1 * 4 + 0] + out_data[1 * 4 + 1] + out_data[1 * 4 + 2];
114         float white_x = out_data[1 * 4 + 0] / white_xyz_sum;
115         float white_y = out_data[1 * 4 + 1] / white_xyz_sum;
116         EXPECT_NEAR(0.3127, white_x, 1e-3);
117         EXPECT_NEAR(0.3290, white_y, 1e-3);
118         EXPECT_FLOAT_EQ(1.0f, out_data[1 * 4 + 3]);
119
120         float red_xyz_sum = out_data[2 * 4 + 0] + out_data[2 * 4 + 1] + out_data[2 * 4 + 2];
121         float red_x = out_data[2 * 4 + 0] / red_xyz_sum;
122         float red_y = out_data[2 * 4 + 1] / red_xyz_sum;
123         EXPECT_NEAR(0.630, red_x, 1e-3);
124         EXPECT_NEAR(0.340, red_y, 1e-3);
125         EXPECT_FLOAT_EQ(1.0f, out_data[2 * 4 + 3]);
126
127         float green_xyz_sum = out_data[3 * 4 + 0] + out_data[3 * 4 + 1] + out_data[3 * 4 + 2];
128         float green_x = out_data[3 * 4 + 0] / green_xyz_sum;
129         float green_y = out_data[3 * 4 + 1] / green_xyz_sum;
130         EXPECT_NEAR(0.310, green_x, 1e-3);
131         EXPECT_NEAR(0.595, green_y, 1e-3);
132         EXPECT_FLOAT_EQ(1.0f, out_data[3 * 4 + 3]);
133
134         float blue_xyz_sum = out_data[4 * 4 + 0] + out_data[4 * 4 + 1] + out_data[4 * 4 + 2];
135         float blue_x = out_data[4 * 4 + 0] / blue_xyz_sum;
136         float blue_y = out_data[4 * 4 + 1] / blue_xyz_sum;
137         EXPECT_NEAR(0.155, blue_x, 1e-3);
138         EXPECT_NEAR(0.070, blue_y, 1e-3);
139         EXPECT_FLOAT_EQ(1.0f, out_data[4 * 4 + 3]);
140 }
141
142 TEST(ColorspaceConversionEffectTest, Rec601_625_Primaries) {
143         float data[] = {
144                 0.0f, 0.0f, 0.0f, 1.0f,
145                 1.0f, 1.0f, 1.0f, 1.0f,
146                 1.0f, 0.0f, 0.0f, 1.0f,
147                 0.0f, 1.0f, 0.0f, 1.0f,
148                 0.0f, 0.0f, 1.0f, 1.0f,
149         };
150         float out_data[4 * 5];
151
152         EffectChainTester tester(data, 1, 5, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_REC_601_625, GAMMA_LINEAR);
153         tester.run(out_data, GL_RGBA, COLORSPACE_XYZ, GAMMA_LINEAR);
154
155         // Black should stay black.
156         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 0]);
157         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 1]);
158         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 2]);
159         EXPECT_FLOAT_EQ(1.0f, out_data[0 * 4 + 3]);
160
161         // Convert the primaries from XYZ to xyz, and compare to the references
162         // given by Rec. 601.
163         float white_xyz_sum = out_data[1 * 4 + 0] + out_data[1 * 4 + 1] + out_data[1 * 4 + 2];
164         float white_x = out_data[1 * 4 + 0] / white_xyz_sum;
165         float white_y = out_data[1 * 4 + 1] / white_xyz_sum;
166         EXPECT_NEAR(0.3127, white_x, 1e-3);
167         EXPECT_NEAR(0.3290, white_y, 1e-3);
168         EXPECT_FLOAT_EQ(1.0f, out_data[1 * 4 + 3]);
169
170         float red_xyz_sum = out_data[2 * 4 + 0] + out_data[2 * 4 + 1] + out_data[2 * 4 + 2];
171         float red_x = out_data[2 * 4 + 0] / red_xyz_sum;
172         float red_y = out_data[2 * 4 + 1] / red_xyz_sum;
173         EXPECT_NEAR(0.640, red_x, 1e-3);
174         EXPECT_NEAR(0.330, red_y, 1e-3);
175         EXPECT_FLOAT_EQ(1.0f, out_data[2 * 4 + 3]);
176
177         float green_xyz_sum = out_data[3 * 4 + 0] + out_data[3 * 4 + 1] + out_data[3 * 4 + 2];
178         float green_x = out_data[3 * 4 + 0] / green_xyz_sum;
179         float green_y = out_data[3 * 4 + 1] / green_xyz_sum;
180         EXPECT_NEAR(0.290, green_x, 1e-3);
181         EXPECT_NEAR(0.600, green_y, 1e-3);
182         EXPECT_FLOAT_EQ(1.0f, out_data[3 * 4 + 3]);
183
184         float blue_xyz_sum = out_data[4 * 4 + 0] + out_data[4 * 4 + 1] + out_data[4 * 4 + 2];
185         float blue_x = out_data[4 * 4 + 0] / blue_xyz_sum;
186         float blue_y = out_data[4 * 4 + 1] / blue_xyz_sum;
187         EXPECT_NEAR(0.150, blue_x, 1e-3);
188         EXPECT_NEAR(0.060, blue_y, 1e-3);
189         EXPECT_FLOAT_EQ(1.0f, out_data[4 * 4 + 3]);
190 }
191
192 TEST(ColorspaceConversionEffectTest, Rec2020_Primaries) {
193         float data[] = {
194                 0.0f, 0.0f, 0.0f, 1.0f,
195                 1.0f, 1.0f, 1.0f, 1.0f,
196                 1.0f, 0.0f, 0.0f, 1.0f,
197                 0.0f, 1.0f, 0.0f, 1.0f,
198                 0.0f, 0.0f, 1.0f, 1.0f,
199         };
200         float out_data[4 * 5];
201
202         EffectChainTester tester(data, 1, 5, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_REC_2020, GAMMA_LINEAR);
203         tester.run(out_data, GL_RGBA, COLORSPACE_XYZ, GAMMA_LINEAR);
204
205         // Black should stay black.
206         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 0]);
207         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 1]);
208         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 2]);
209         EXPECT_FLOAT_EQ(1.0f, out_data[0 * 4 + 3]);
210
211         // Convert the primaries from XYZ to xyz, and compare to the references
212         // given by Rec. 2020.
213         float white_xyz_sum = out_data[1 * 4 + 0] + out_data[1 * 4 + 1] + out_data[1 * 4 + 2];
214         float white_x = out_data[1 * 4 + 0] / white_xyz_sum;
215         float white_y = out_data[1 * 4 + 1] / white_xyz_sum;
216         EXPECT_NEAR(0.3127, white_x, 1e-3);
217         EXPECT_NEAR(0.3290, white_y, 1e-3);
218         EXPECT_FLOAT_EQ(1.0f, out_data[1 * 4 + 3]);
219
220         float red_xyz_sum = out_data[2 * 4 + 0] + out_data[2 * 4 + 1] + out_data[2 * 4 + 2];
221         float red_x = out_data[2 * 4 + 0] / red_xyz_sum;
222         float red_y = out_data[2 * 4 + 1] / red_xyz_sum;
223         EXPECT_NEAR(0.708, red_x, 1e-3);
224         EXPECT_NEAR(0.292, red_y, 1e-3);
225         EXPECT_FLOAT_EQ(1.0f, out_data[2 * 4 + 3]);
226
227         float green_xyz_sum = out_data[3 * 4 + 0] + out_data[3 * 4 + 1] + out_data[3 * 4 + 2];
228         float green_x = out_data[3 * 4 + 0] / green_xyz_sum;
229         float green_y = out_data[3 * 4 + 1] / green_xyz_sum;
230         EXPECT_NEAR(0.170, green_x, 1e-3);
231         EXPECT_NEAR(0.797, green_y, 1e-3);
232         EXPECT_FLOAT_EQ(1.0f, out_data[3 * 4 + 3]);
233
234         float blue_xyz_sum = out_data[4 * 4 + 0] + out_data[4 * 4 + 1] + out_data[4 * 4 + 2];
235         float blue_x = out_data[4 * 4 + 0] / blue_xyz_sum;
236         float blue_y = out_data[4 * 4 + 1] / blue_xyz_sum;
237         EXPECT_NEAR(0.131, blue_x, 1e-3);
238         EXPECT_NEAR(0.046, blue_y, 1e-3);
239         EXPECT_FLOAT_EQ(1.0f, out_data[4 * 4 + 3]);
240 }
241
242 TEST(ColorspaceConversionEffectTest, sRGBToRec601_525) {
243         float data[] = {
244                 0.0f, 0.0f, 0.0f, 1.0f,
245                 1.0f, 1.0f, 1.0f, 1.0f,
246                 1.0f, 0.0f, 0.0f, 1.0f,
247                 0.0f, 1.0f, 0.0f, 1.0f,
248                 0.0f, 0.0f, 1.0f, 1.0f,
249                 0.0f, 1.0f, 1.0f, 0.5f,
250         };
251
252         // I have to admit that most of these come from the code itself;
253         // however, they do make sense if you look at the two gamuts
254         // in xy space.
255         float expected_data[] = {
256                 // Black should stay black.
257                 0.0f, 0.0f, 0.0f, 1.0f,
258
259                 // White should stay white (both use the D65 white point).
260                 1.0f, 1.0f, 1.0f, 1.0f,
261
262                 // sRGB red is slightly out-of-gamut for Rec. 601/525.
263                 1.064f, -0.020f, 0.0f, 1.0f,
264
265                 // Green too.
266                 -0.055f, 1.036f, 0.004f, 1.0f,
267
268                 // The blues are much closer; it _is_ still out-of-gamut,
269                 // but not actually more saturated (farther from the
270                 // white point).
271                 -0.010f, -0.017f, 0.994f, 1.0f,
272
273                 // Cyan is a mix of green and blue. Note: The alpha is kept.
274                 -0.065f, 1.0195f, 0.998f, 0.5f,
275         };
276         float out_data[4 * 6];
277
278         EffectChainTester tester(data, 1, 6, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_sRGB, GAMMA_LINEAR);
279         tester.run(out_data, GL_RGBA, COLORSPACE_REC_601_525, GAMMA_LINEAR);
280
281         expect_equal(expected_data, out_data, 4, 6);
282 }
283
284 }  // namespace movit