]> git.sesse.net Git - movit/blob - flat_input_test.cpp
Fix a Valgrind hit.
[movit] / flat_input_test.cpp
1 // Unit tests for FlatInput.
2
3 #include <epoxy/gl.h>
4 #include <stddef.h>
5
6 #include "effect_chain.h"
7 #include "flat_input.h"
8 #include "gtest/gtest.h"
9 #include "resource_pool.h"
10 #include "test_util.h"
11 #include "util.h"
12
13 using namespace std;
14
15 namespace movit {
16
17 TEST(FlatInput, SimpleGrayscale) {
18         const int size = 4;
19
20         float data[size] = {
21                 0.0,
22                 0.5,
23                 0.7,
24                 1.0,
25         };
26         float expected_data[4 * size] = {
27                 0.0, 0.0, 0.0, 1.0,
28                 0.5, 0.5, 0.5, 1.0,
29                 0.7, 0.7, 0.7, 1.0,
30                 1.0, 1.0, 1.0, 1.0,
31         };
32         float out_data[4 * size];
33
34         EffectChainTester tester(data, 1, size, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
35         tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR);
36
37         expect_equal(expected_data, out_data, 4, size);
38 }
39
40 TEST(FlatInput, RGB) {
41         const int size = 5;
42
43         float data[3 * size] = {
44                 0.0, 0.0, 0.0,
45                 0.5, 0.0, 0.0,
46                 0.0, 0.5, 0.0,
47                 0.0, 0.0, 0.7,
48                 0.0, 0.3, 0.7,
49         };
50         float expected_data[4 * size] = {
51                 0.0, 0.0, 0.0, 1.0,
52                 0.5, 0.0, 0.0, 1.0,
53                 0.0, 0.5, 0.0, 1.0,
54                 0.0, 0.0, 0.7, 1.0,
55                 0.0, 0.3, 0.7, 1.0,
56         };
57         float out_data[4 * size];
58
59         EffectChainTester tester(data, 1, size, FORMAT_RGB, COLORSPACE_sRGB, GAMMA_LINEAR);
60         tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR);
61
62         expect_equal(expected_data, out_data, 4, size);
63 }
64
65 TEST(FlatInput, RGBA) {
66         const int size = 5;
67
68         float data[4 * size] = {
69                 0.0, 0.0, 0.0, 1.0,
70                 0.5, 0.0, 0.0, 0.3,
71                 0.0, 0.5, 0.0, 0.7,
72                 0.0, 0.0, 0.7, 1.0,
73                 0.0, 0.3, 0.7, 0.2,
74         };
75         float expected_data[4 * size] = {
76                 0.0, 0.0, 0.0, 1.0,
77                 0.5, 0.0, 0.0, 0.3,
78                 0.0, 0.5, 0.0, 0.7,
79                 0.0, 0.0, 0.7, 1.0,
80                 0.0, 0.3, 0.7, 0.2,
81         };
82         float out_data[4 * size];
83
84         EffectChainTester tester(data, 1, size, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_sRGB, GAMMA_LINEAR);
85         tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR);
86
87         expect_equal(expected_data, out_data, 4, size);
88 }
89
90 // Note: The sRGB conversion itself is tested in EffectChainTester,
91 // since it also wants to test the chain building itself.
92 // Here, we merely test that alpha is left alone; the test will usually
93 // run using the sRGB OpenGL extension, but might be run with a
94 // GammaExpansionEffect if the card/driver happens not to support that.
95 TEST(FlatInput, AlphaIsNotModifiedBySRGBConversion) {
96         const int size = 5;
97
98         unsigned char data[4 * size] = {
99                 0, 0, 0, 0,
100                 0, 0, 0, 63,
101                 0, 0, 0, 127,
102                 0, 0, 0, 191,
103                 0, 0, 0, 255,
104         };
105         float expected_data[4 * size] = {
106                 0, 0, 0, 0.0 / 255.0,
107                 0, 0, 0, 63.0 / 255.0,
108                 0, 0, 0, 127.0 / 255.0,
109                 0, 0, 0, 191.0 / 255.0,
110                 0, 0, 0, 255.0 / 255.0,
111         };
112         float out_data[4 * size];
113
114         EffectChainTester tester(nullptr, 1, size);
115         tester.add_input(data, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_sRGB, GAMMA_sRGB);
116         tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR);
117
118         expect_equal(expected_data, out_data, 4, size);
119 }
120
121 TEST(FlatInput, BGR) {
122         const int size = 5;
123
124         float data[3 * size] = {
125                 0.0, 0.0, 0.0,
126                 0.5, 0.0, 0.0,
127                 0.0, 0.5, 0.0,
128                 0.0, 0.0, 0.7,
129                 0.0, 0.3, 0.7,
130         };
131         float expected_data[4 * size] = {
132                 0.0, 0.0, 0.0, 1.0,
133                 0.0, 0.0, 0.5, 1.0,
134                 0.0, 0.5, 0.0, 1.0,
135                 0.7, 0.0, 0.0, 1.0,
136                 0.7, 0.3, 0.0, 1.0,
137         };
138         float out_data[4 * size];
139
140         EffectChainTester tester(data, 1, size, FORMAT_BGR, COLORSPACE_sRGB, GAMMA_LINEAR);
141         tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR);
142
143         expect_equal(expected_data, out_data, 4, size);
144 }
145
146 TEST(FlatInput, BGRA) {
147         const int size = 5;
148
149         float data[4 * size] = {
150                 0.0, 0.0, 0.0, 1.0,
151                 0.5, 0.0, 0.0, 0.3,
152                 0.0, 0.5, 0.0, 0.7,
153                 0.0, 0.0, 0.7, 1.0,
154                 0.0, 0.3, 0.7, 0.2,
155         };
156         float expected_data[4 * size] = {
157                 0.0, 0.0, 0.0, 1.0,
158                 0.0, 0.0, 0.5, 0.3,
159                 0.0, 0.5, 0.0, 0.7,
160                 0.7, 0.0, 0.0, 1.0,
161                 0.7, 0.3, 0.0, 0.2,
162         };
163         float out_data[4 * size];
164
165         EffectChainTester tester(data, 1, size, FORMAT_BGRA_POSTMULTIPLIED_ALPHA, COLORSPACE_sRGB, GAMMA_LINEAR);
166         tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR);
167
168         expect_equal(expected_data, out_data, 4, size);
169 }
170
171 TEST(FlatInput, Pitch) {
172         const int pitch = 3;
173         const int width = 2;
174         const int height = 4;
175
176         float data[pitch * height] = {
177                 0.0, 1.0, 999.0f,
178                 0.5, 0.5, 999.0f,
179                 0.7, 0.2, 999.0f,
180                 1.0, 0.6, 999.0f,
181         };
182         float expected_data[4 * width * height] = {
183                 0.0, 0.0, 0.0, 1.0,  1.0, 1.0, 1.0, 1.0,
184                 0.5, 0.5, 0.5, 1.0,  0.5, 0.5, 0.5, 1.0,
185                 0.7, 0.7, 0.7, 1.0,  0.2, 0.2, 0.2, 1.0,
186                 1.0, 1.0, 1.0, 1.0,  0.6, 0.6, 0.6, 1.0,
187         };
188         float out_data[4 * width * height];
189
190         EffectChainTester tester(nullptr, width, height);
191
192         ImageFormat format;
193         format.color_space = COLORSPACE_sRGB;
194         format.gamma_curve = GAMMA_LINEAR;
195
196         FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, width, height);
197         input->set_pitch(pitch);
198         input->set_pixel_data(data);
199         tester.get_chain()->add_input(input);
200
201         tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR);
202         expect_equal(expected_data, out_data, 4 * width, height);
203 }
204
205 TEST(FlatInput, UpdatedData) {
206         const int width = 2;
207         const int height = 4;
208
209         float data[width * height] = {
210                 0.0, 1.0,
211                 0.5, 0.5,
212                 0.7, 0.2,
213                 1.0, 0.6,
214         };
215         float out_data[width * height];
216
217         EffectChainTester tester(nullptr, width, height);
218
219         ImageFormat format;
220         format.color_space = COLORSPACE_sRGB;
221         format.gamma_curve = GAMMA_LINEAR;
222
223         FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, width, height);
224         input->set_pixel_data(data);
225         tester.get_chain()->add_input(input);
226
227         tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
228         expect_equal(data, out_data, width, height);
229
230         data[6] = 0.3;
231         input->invalidate_pixel_data();
232
233         tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
234         expect_equal(data, out_data, width, height);
235 }
236
237 TEST(FlatInput, PBO) {
238         const int width = 3;
239         const int height = 2;
240
241         float data[width * height] = {
242                 0.0, 1.0, 0.5,
243                 0.5, 0.5, 0.2,
244         };
245         float expected_data[4 * width * height] = {
246                 0.0, 0.0, 0.0, 1.0,  1.0, 1.0, 1.0, 1.0,  0.5, 0.5, 0.5, 1.0,
247                 0.5, 0.5, 0.5, 1.0,  0.5, 0.5, 0.5, 1.0,  0.2, 0.2, 0.2, 1.0,
248         };
249         float out_data[4 * width * height];
250
251         GLuint pbo;
252         glGenBuffers(1, &pbo);
253         glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, pbo);
254         glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, width * height * sizeof(float), data, GL_STREAM_DRAW);
255         glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0);
256
257         EffectChainTester tester(nullptr, width, height);
258
259         ImageFormat format;
260         format.color_space = COLORSPACE_sRGB;
261         format.gamma_curve = GAMMA_LINEAR;
262
263         FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, width, height);
264         input->set_pixel_data((float *)BUFFER_OFFSET(0), pbo);
265         tester.get_chain()->add_input(input);
266
267         tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR);
268         expect_equal(expected_data, out_data, 4 * width, height);
269
270         glDeleteBuffers(1, &pbo);
271 }
272
273 TEST(FlatInput, ExternalTexture) {
274         const int size = 5;
275
276         float data[3 * size] = {
277                 0.0, 0.0, 0.0,
278                 0.5, 0.0, 0.0,
279                 0.0, 0.5, 0.0,
280                 0.0, 0.0, 0.7,
281                 0.0, 0.3, 0.7,
282         };
283         float expected_data[4 * size] = {
284                 0.0, 0.0, 0.0, 1.0,
285                 0.5, 0.0, 0.0, 1.0,
286                 0.0, 0.5, 0.0, 1.0,
287                 0.0, 0.0, 0.7, 1.0,
288                 0.0, 0.3, 0.7, 1.0,
289         };
290         float out_data[4 * size];
291
292         EffectChainTester tester(nullptr, 1, size, FORMAT_RGB, COLORSPACE_sRGB, GAMMA_LINEAR);
293
294         ImageFormat format;
295         format.color_space = COLORSPACE_sRGB;
296         format.gamma_curve = GAMMA_LINEAR;
297
298         ResourcePool pool;
299         GLuint tex = pool.create_2d_texture(GL_RGB8, 1, size);
300         check_error();
301         glBindTexture(GL_TEXTURE_2D, tex);
302         check_error();
303         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
304         check_error();
305         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
306         check_error();
307         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, size, GL_RGB, GL_FLOAT, data);
308         check_error();
309         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
310         check_error();
311         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
312         check_error();
313
314         FlatInput *input = new FlatInput(format, FORMAT_RGB, GL_FLOAT, 1, size);
315         input->set_texture_num(tex);
316         tester.get_chain()->add_input(input);
317
318         tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR);
319
320         pool.release_2d_texture(tex);
321
322         expect_equal(expected_data, out_data, 4, size);
323 }
324
325 // Just an IdentityEffect, but marks as needing mipmaps, so that we can use it
326 // for downscaling to verify mipmaps were used.
327 class MipmapNeedingEffect : public Effect {
328 public:
329         MipmapNeedingEffect() {}
330         MipmapRequirements needs_mipmaps() const override { return NEEDS_MIPMAPS; }
331
332         string effect_type_id() const override { return "MipmapNeedingEffect"; }
333         string output_fragment_shader() override { return read_file("identity.frag"); }
334
335 private:
336         EffectChain *chain;
337 };
338
339 TEST(FlatInput, ExternalTextureMipmapState) {
340         const int width = 4;
341         const int height = 4;
342
343         float data[width * height] = {
344                 1.0, 0.0, 0.0, 0.0,
345                 0.0, 0.0, 0.0, 0.0,
346                 0.0, 0.0, 0.0, 0.0,
347                 0.0, 0.0, 0.0, 0.0,
348         };
349         float expected_data[] = {
350                 0.0625,
351         };
352         float out_data[1];
353
354         EffectChainTester tester(nullptr, 1, 1, FORMAT_RGB, COLORSPACE_sRGB, GAMMA_LINEAR);
355
356         ImageFormat format;
357         format.color_space = COLORSPACE_sRGB;
358         format.gamma_curve = GAMMA_LINEAR;
359
360         ResourcePool pool;
361         GLuint tex = pool.create_2d_texture(GL_R8, width, height);
362         check_error();
363         glBindTexture(GL_TEXTURE_2D, tex);
364         check_error();
365         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
366         check_error();
367         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
368         check_error();
369         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED, GL_FLOAT, data);
370         check_error();
371         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
372         check_error();
373         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
374         check_error();
375         glGenerateMipmap(GL_TEXTURE_2D);
376         check_error();
377
378         // Turn off mipmaps, so that we verify that Movit turns it back on.
379         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
380         check_error();
381
382         FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, width, height);
383         input->set_texture_num(tex);
384         tester.get_chain()->add_input(input);
385         tester.get_chain()->add_effect(new MipmapNeedingEffect);
386
387         tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
388
389         pool.release_2d_texture(tex);
390
391         expect_equal(expected_data, out_data, 1, 1);
392 }
393
394 TEST(FlatInput, NoData) {
395         const int width = 2;
396         const int height = 4;
397
398         float out_data[width * height];
399
400         EffectChainTester tester(nullptr, width, height);
401
402         ImageFormat format;
403         format.color_space = COLORSPACE_sRGB;
404         format.gamma_curve = GAMMA_LINEAR;
405
406         FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, width, height);
407         tester.get_chain()->add_input(input);
408
409         tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
410
411         // Don't care what the output was, just that it does not crash.
412 }
413
414 }  // namespace movit