]> git.sesse.net Git - movit/blob - resample_effect_test.cpp
Compute version of ResampleEffect.
[movit] / resample_effect_test.cpp
1 // Unit tests for ResampleEffect.
2
3 #include <epoxy/gl.h>
4 #include <gtest/gtest.h>
5 #include <math.h>
6
7 #include <memory>
8
9 #include "effect_chain.h"
10 #include "flat_input.h"
11 #include "fp16.h"
12 #include "image_format.h"
13 #include "init.h"
14 #include "resample_effect.h"
15 #include "test_util.h"
16
17 using namespace std;
18
19 namespace movit {
20
21 namespace {
22
23 float sinc(float x)
24 {
25         return sin(M_PI * x) / (M_PI * x);
26 }
27
28 float lanczos(float x, float a)
29 {
30         if (fabs(x) >= a) {
31                 return 0.0f;
32         } else {
33                 return sinc(x) * sinc(x / a);
34         }
35 }
36
37 }  // namespace
38
39 class ResampleEffectTest : public testing::TestWithParam<string> {
40 protected:
41         ResampleEffectTest() : disabler(GetParam() == "fragment") {}
42         bool should_skip() { return disabler.should_skip(); }
43
44 private:
45         DisableComputeShadersTemporarily disabler;
46 };
47
48 TEST_P(ResampleEffectTest, IdentityTransformDoesNothing) {
49         const int size = 4;
50
51         float data[size * size] = {
52                 0.0, 1.0, 0.0, 1.0,
53                 0.0, 1.0, 1.0, 0.0,
54                 0.0, 0.5, 1.0, 0.5,
55                 0.0, 0.0, 0.0, 0.0,
56         };
57         float out_data[size * size];
58
59         EffectChainTester tester(data, size, size, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
60         Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
61         ASSERT_TRUE(resample_effect->set_int("width", 4));
62         ASSERT_TRUE(resample_effect->set_int("height", 4));
63         tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
64
65         expect_equal(data, out_data, size, size);
66 }
67
68 TEST_P(ResampleEffectTest, UpscaleByTwoGetsCorrectPixelCenters) {
69         const int size = 5;
70
71         float data[size * size] = {
72                 0.0, 0.0, 0.0, 0.0, 0.0,
73                 0.0, 0.0, 0.0, 0.0, 0.0,
74                 0.0, 0.0, 1.0, 0.0, 0.0,
75                 0.0, 0.0, 0.0, 0.0, 0.0,
76                 0.0, 0.0, 0.0, 0.0, 0.0,
77         };
78         float expected_data[size * size * 4], out_data[size * size * 4];
79
80         for (int y = 0; y < size * 2; ++y) {
81                 for (int x = 0; x < size * 2; ++x) {
82                         float weight = lanczos((x - size + 0.5f) * 0.5f, 3.0f);
83                         weight *= lanczos((y - size + 0.5f) * 0.5f, 3.0f);
84                         expected_data[y * (size * 2) + x] = weight;
85                 }
86         }
87
88         EffectChainTester tester(nullptr, size * 2, size * 2, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
89
90         ImageFormat format;
91         format.color_space = COLORSPACE_sRGB;
92         format.gamma_curve = GAMMA_LINEAR;
93
94         FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, size, size);
95         input->set_pixel_data(data);
96         tester.get_chain()->add_input(input);
97
98         Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
99         ASSERT_TRUE(resample_effect->set_int("width", size * 2));
100         ASSERT_TRUE(resample_effect->set_int("height", size * 2));
101         tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
102
103         expect_equal(expected_data, out_data, size * 2, size * 2);
104 }
105
106 TEST_P(ResampleEffectTest, DownscaleByTwoGetsCorrectPixelCenters) {
107         const int size = 5;
108
109         // This isn't a perfect dot, since the Lanczos filter has a slight
110         // sharpening effect; the most important thing is that we have kept
111         // the texel center right (everything is nicely symmetric).
112         // The approximate magnitudes have been checked against ImageMagick.
113         float expected_data[size * size] = {
114                  0.0045, -0.0067, -0.0599, -0.0067,  0.0045,
115                 -0.0067,  0.0100,  0.0892,  0.0100, -0.0067,
116                 -0.0599,  0.0890,  0.7925,  0.0892, -0.0599,
117                 -0.0067,  0.0100,  0.0890,  0.0100, -0.0067,
118                  0.0045, -0.0067, -0.0599, -0.0067,  0.0045,
119         };
120         float data[size * size * 4], out_data[size * size];
121
122         for (int y = 0; y < size * 2; ++y) {
123                 for (int x = 0; x < size * 2; ++x) {
124                         float weight = lanczos((x - size + 0.5f) * 0.5f, 3.0f);
125                         weight *= lanczos((y - size + 0.5f) * 0.5f, 3.0f);
126                         data[y * (size * 2) + x] = weight;
127                 }
128         }
129
130         EffectChainTester tester(nullptr, size, size, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
131
132         ImageFormat format;
133         format.color_space = COLORSPACE_sRGB;
134         format.gamma_curve = GAMMA_LINEAR;
135
136         FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, size * 2, size * 2);
137         input->set_pixel_data(data);
138         tester.get_chain()->add_input(input);
139
140         Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
141         ASSERT_TRUE(resample_effect->set_int("width", size));
142         ASSERT_TRUE(resample_effect->set_int("height", size));
143         tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
144
145         expect_equal(expected_data, out_data, size, size);
146 }
147
148 TEST_P(ResampleEffectTest, UpscaleByThreeGetsCorrectPixelCenters) {
149         const int size = 5;
150
151         float data[size * size] = {
152                 0.0, 0.0, 0.0, 0.0, 0.0,
153                 0.0, 0.0, 0.0, 0.0, 0.0,
154                 0.0, 0.0, 1.0, 0.0, 0.0,
155                 0.0, 0.0, 0.0, 0.0, 0.0,
156                 0.0, 0.0, 0.0, 0.0, 0.0,
157         };
158         float out_data[size * size * 9];
159
160         EffectChainTester tester(nullptr, size * 3, size * 3, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
161
162         ImageFormat format;
163         format.color_space = COLORSPACE_sRGB;
164         format.gamma_curve = GAMMA_LINEAR;
165
166         FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, size, size);
167         input->set_pixel_data(data);
168         tester.get_chain()->add_input(input);
169
170         Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
171         ASSERT_TRUE(resample_effect->set_int("width", size * 3));
172         ASSERT_TRUE(resample_effect->set_int("height", size * 3));
173         tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
174
175         // We only bother checking that the middle pixel is still correct,
176         // and that symmetry holds. Note that the middle weight in practice
177         // becomes something like 0.99999 due to the normalization
178         // (some supposedly zero weights become 1e-6 or so), and then after
179         // squaring, the error compounds. Ironically, less texture precision
180         // here will give a more accurate result, since the weight can get
181         // rounded towards 1.0.
182         EXPECT_NEAR(1.0, out_data[7 * (size * 3) + 7], 1e-3);
183         for (unsigned y = 0; y < size * 3; ++y) {
184                 for (unsigned x = 0; x < size * 3; ++x) {
185                         EXPECT_NEAR(out_data[y * (size * 3) + x], out_data[(size * 3 - y - 1) * (size * 3) + x], 1e-6);
186                         EXPECT_NEAR(out_data[y * (size * 3) + x], out_data[y * (size * 3) + (size * 3 - x - 1)], 1e-6);
187                 }
188         }
189 }
190
191 TEST_P(ResampleEffectTest, HeavyResampleGetsSumRight) {
192         // Do only one resample pass, more specifically the last one, which goes to
193         // our fp32 output. This allows us to analyze the precision without intermediate
194         // fp16 rounding.
195         const int swidth = 1, sheight = 1280;
196         const int dwidth = 1, dheight = 64;
197
198         float data[swidth * sheight], out_data[dwidth * dheight], expected_data[dwidth * dheight];
199         for (int y = 0; y < sheight; ++y) {
200                 for (int x = 0; x < swidth; ++x) {
201                         data[y * swidth + x] = 1.0f;
202                 }
203         }
204         for (int y = 0; y < dheight; ++y) {
205                 for (int x = 0; x < dwidth; ++x) {
206                         expected_data[y * dwidth + x] = 1.0f;
207                 }
208         }
209
210         EffectChainTester tester(nullptr, dwidth, dheight, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, GL_RGBA32F);
211
212         ImageFormat format;
213         format.color_space = COLORSPACE_sRGB;
214         format.gamma_curve = GAMMA_LINEAR;
215
216         FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, swidth, sheight);
217         input->set_pixel_data(data);
218
219         tester.get_chain()->add_input(input);
220         Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
221         ASSERT_TRUE(resample_effect->set_int("width", dwidth));
222         ASSERT_TRUE(resample_effect->set_int("height", dheight));
223         tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
224
225         // Require that we are within 10-bit accuracy. Note that this limit is for
226         // one pass only, but the limit is tight enough that it should be good enough
227         // for 10-bit accuracy even after two passes.
228         expect_equal(expected_data, out_data, dwidth, dheight, 0.12 / 1023.0);
229 }
230
231 TEST_P(ResampleEffectTest, ReadWholePixelFromLeft) {
232         const int size = 5;
233
234         float data[size * size] = {
235                 0.0, 0.0, 0.0, 0.0, 0.0,
236                 0.0, 0.0, 0.0, 0.0, 0.0,
237                 0.0, 0.0, 1.0, 0.0, 0.0,
238                 0.0, 0.0, 0.0, 0.0, 0.0,
239                 0.0, 0.0, 0.0, 0.0, 0.0,
240         };
241         float expected_data[size * size] = {
242                 0.0, 0.0, 0.0, 0.0, 0.0,
243                 0.0, 0.0, 0.0, 0.0, 0.0,
244                 0.0, 1.0, 0.0, 0.0, 0.0,
245                 0.0, 0.0, 0.0, 0.0, 0.0,
246                 0.0, 0.0, 0.0, 0.0, 0.0,
247         };
248         float out_data[size * size];
249
250         EffectChainTester tester(data, size, size, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
251         Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
252         ASSERT_TRUE(resample_effect->set_int("width", size));
253         ASSERT_TRUE(resample_effect->set_int("height", size));
254         ASSERT_TRUE(resample_effect->set_float("left", 1.0f));
255         tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
256
257         expect_equal(expected_data, out_data, size, size);
258 }
259
260 TEST_P(ResampleEffectTest, ReadQuarterPixelFromLeft) {
261         const int size = 5;
262
263         float data[size * size] = {
264                 0.0, 0.0, 0.0, 0.0, 0.0,
265                 0.0, 0.0, 0.0, 0.0, 0.0,
266                 0.0, 0.0, 1.0, 0.0, 0.0,
267                 0.0, 0.0, 0.0, 0.0, 0.0,
268                 0.0, 0.0, 0.0, 0.0, 0.0,
269         };
270
271         float expected_data[size * size] = {
272                 0.0, 0.0, 0.0, 0.0, 0.0,
273                 0.0, 0.0, 0.0, 0.0, 0.0,
274
275                 // sin(x*pi)/(x*pi) * sin(x*pi/3)/(x*pi/3) for
276                 // x = -1.75, -0.75, 0.25, 1.25, 2.25.
277                 // Note that the weight is mostly on the left side.
278                 -0.06779, 0.27019, 0.89007, -0.13287, 0.03002,
279
280                 0.0, 0.0, 0.0, 0.0, 0.0,
281                 0.0, 0.0, 0.0, 0.0, 0.0,
282         };
283         float out_data[size * size];
284
285         EffectChainTester tester(data, size, size, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
286         Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
287         ASSERT_TRUE(resample_effect->set_int("width", size));
288         ASSERT_TRUE(resample_effect->set_int("height", size));
289         ASSERT_TRUE(resample_effect->set_float("left", 0.25f));
290         tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
291
292         expect_equal(expected_data, out_data, size, size);
293 }
294
295 TEST_P(ResampleEffectTest, ReadQuarterPixelFromTop) {
296         const int width = 3;
297         const int height = 5;
298
299         float data[width * height] = {
300                 0.0, 0.0, 0.0,
301                 0.0, 0.0, 0.0,
302                 1.0, 0.0, 0.0,
303                 0.0, 0.0, 0.0,
304                 0.0, 0.0, 0.0,
305         };
306
307         // See ReadQuarterPixelFromLeft for explanation of the data.
308         float expected_data[width * height] = {
309                 -0.06779, 0.0, 0.0,
310                  0.27019, 0.0, 0.0,
311                  0.89007, 0.0, 0.0,
312                 -0.13287, 0.0, 0.0,
313                  0.03002, 0.0, 0.0,
314         };
315         float out_data[width * height];
316
317         EffectChainTester tester(data, width, height, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
318         Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
319         ASSERT_TRUE(resample_effect->set_int("width", width));
320         ASSERT_TRUE(resample_effect->set_int("height", height));
321         ASSERT_TRUE(resample_effect->set_float("top", 0.25f));
322         tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
323
324         expect_equal(expected_data, out_data, width, height);
325 }
326
327 TEST_P(ResampleEffectTest, ReadHalfPixelFromLeftAndScale) {
328         const int src_width = 4;
329         const int dst_width = 8;
330
331         float data[src_width * 1] = {
332                 1.0, 2.0, 3.0, 4.0,
333         };
334         float expected_data[dst_width * 1] = {
335                 // Empirical; the real test is that we are the same for 0.499 and 0.501.
336                 1.1553, 1.7158, 2.2500, 2.7461, 3.2812, 3.8418, 4.0703, 4.0508
337         };
338         float out_data[dst_width * 1];
339
340         EffectChainTester tester(nullptr, dst_width, 1, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
341
342         ImageFormat format;
343         format.color_space = COLORSPACE_sRGB;
344         format.gamma_curve = GAMMA_LINEAR;
345
346         FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, src_width, 1);
347         input->set_pixel_data(data);
348         tester.get_chain()->add_input(input);
349
350         Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
351         ASSERT_TRUE(resample_effect->set_int("width", dst_width));
352         ASSERT_TRUE(resample_effect->set_int("height", 1));
353
354         // Check that we are (almost) the same no matter the rounding.
355         ASSERT_TRUE(resample_effect->set_float("left", 0.499f));
356         tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
357         expect_equal(expected_data, out_data, dst_width, 1, 1.5f / 255.0f, 0.4f / 255.0f);
358
359         ASSERT_TRUE(resample_effect->set_float("left", 0.501f));
360         tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
361         expect_equal(expected_data, out_data, dst_width, 1, 1.5f / 255.0f, 0.4f / 255.0f);
362 }
363
364 TEST_P(ResampleEffectTest, Zoom) {
365         const int width = 5;
366         const int height = 3;
367
368         float data[width * height] = {
369                 0.0, 0.0, 0.0, 0.0, 0.0,
370                 0.2, 0.4, 0.6, 0.4, 0.2,
371                 0.0, 0.0, 0.0, 0.0, 0.0,
372         };
373         float expected_data[width * height] = {
374                 0.0, 0.0,    0.0, 0.0,    0.0,
375                 0.4, 0.5396, 0.6, 0.5396, 0.4,
376                 0.0, 0.0,    0.0, 0.0,    0.0,
377         };
378         float out_data[width * height];
379
380         EffectChainTester tester(data, width, height, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
381         Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
382         ASSERT_TRUE(resample_effect->set_int("width", width));
383         ASSERT_TRUE(resample_effect->set_int("height", height));
384         ASSERT_TRUE(resample_effect->set_float("zoom_x", 2.0f));
385         tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
386
387         expect_equal(expected_data, out_data, width, height);
388 }
389
390 TEST_P(ResampleEffectTest, VerticalZoomFromTop) {
391         const int width = 5;
392         const int height = 5;
393
394         float data[width * height] = {
395                 0.2, 0.4, 0.6, 0.4, 0.2,
396                 0.0, 0.0, 0.0, 0.0, 0.0,
397                 0.0, 0.0, 0.0, 0.0, 0.0,
398                 0.0, 0.0, 0.0, 0.0, 0.0,
399                 0.0, 0.0, 0.0, 0.0, 0.0,
400         };
401
402         // Largely empirical data; the main point is that the top line
403         // is unchanged, since that's our zooming point.
404         float expected_data[width * height] = {
405                  0.2000,  0.4000,  0.6000,  0.4000,  0.2000,
406                  0.1389,  0.2778,  0.4167,  0.2778,  0.1389,
407                  0.0600,  0.1199,  0.1798,  0.1199,  0.0600,
408                  0.0000,  0.0000,  0.0000,  0.0000,  0.0000,
409                 -0.0229, -0.0459, -0.0688, -0.0459, -0.0229,
410         };
411         float out_data[width * height];
412
413         EffectChainTester tester(data, width, height, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
414         Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
415         ASSERT_TRUE(resample_effect->set_int("width", width));
416         ASSERT_TRUE(resample_effect->set_int("height", height));
417         ASSERT_TRUE(resample_effect->set_float("zoom_y", 3.0f));
418         ASSERT_TRUE(resample_effect->set_float("zoom_center_y", 0.5f / height));
419         tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
420
421         expect_equal(expected_data, out_data, width, height);
422 }
423
424 TEST_P(ResampleEffectTest, Precision) {
425         const int size = 1920;  // Difficult non-power-of-two size.
426         const int offset = 5;
427
428         // Deliberately put the data of interest very close to the right,
429         // where texture coordinates are farther from 0 and thus less precise.
430         float data[size * 2] = {0};
431         data[size - offset] = 1.0f;
432         float expected_data[size * 2] = {0};
433         for (int x = 0; x < size * 2; ++x) {
434                 expected_data[x] = lanczos((x - (size - 2 * offset + 1) + 0.5f) * 0.5f, 3.0f);
435         }
436         float out_data[size * 2];
437
438         EffectChainTester tester(data, size * 2, 1, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
439         Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
440         ASSERT_TRUE(resample_effect->set_int("width", size * 2));
441         ASSERT_TRUE(resample_effect->set_int("height", 1));
442         ASSERT_TRUE(resample_effect->set_float("zoom_x", 2.0f));
443         tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
444
445         expect_equal(expected_data, out_data, size, 1);
446 }
447
448 INSTANTIATE_TEST_CASE_P(ResampleEffectTest,
449                         ResampleEffectTest,
450                         testing::Values("fragment", "compute"));
451
452 #ifdef HAVE_BENCHMARK
453 template<> inline uint8_t from_fp32<uint8_t>(float x) { return lrintf(x * 255.0f); }
454
455 template<class T>
456 void BM_ResampleEffect(benchmark::State &state, GammaCurve gamma_curve, GLenum output_format, const std::string &shader_type)
457 {
458         DisableComputeShadersTemporarily disabler(shader_type == "fragment");
459         if (disabler.should_skip(&state)) return;
460
461         unsigned in_width = state.range(0), in_height = state.range(1);
462         unsigned out_width = state.range(2), out_height = state.range(3);
463
464         unique_ptr<T[]> data(new T[in_width * in_height * 4]);
465         unique_ptr<T[]> out_data(new T[out_width * out_height * 4]);
466
467         for (unsigned i = 0; i < in_width * in_height * 4; ++i) {
468                 data[i] = from_fp32<T>(rand() / (RAND_MAX + 1.0));
469         }
470
471         EffectChainTester tester(nullptr, out_width, out_height, FORMAT_BGRA_POSTMULTIPLIED_ALPHA, COLORSPACE_sRGB, gamma_curve, output_format);
472         tester.add_input(data.get(), FORMAT_BGRA_POSTMULTIPLIED_ALPHA, COLORSPACE_sRGB, gamma_curve, in_width, in_height);
473         Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
474
475         ASSERT_TRUE(resample_effect->set_int("width", out_width));
476         ASSERT_TRUE(resample_effect->set_int("height", out_height));
477
478         tester.benchmark(state, out_data.get(), GL_BGRA, COLORSPACE_sRGB, gamma_curve, OUTPUT_ALPHA_FORMAT_PREMULTIPLIED);
479 }
480
481 void BM_ResampleEffectHalf(benchmark::State &state, GammaCurve gamma_curve, const std::string &shader_type)
482 {
483         BM_ResampleEffect<fp16_int_t>(state, gamma_curve, GL_RGBA16F, shader_type);
484 }
485
486 void BM_ResampleEffectInt8(benchmark::State &state, GammaCurve gamma_curve, const std::string &shader_type)
487 {
488         BM_ResampleEffect<uint8_t>(state, gamma_curve, GL_RGBA8, shader_type);
489 }
490
491 BENCHMARK_CAPTURE(BM_ResampleEffectInt8, Int8Upscale, GAMMA_REC_709, "fragment")->Args({640, 360, 1280, 720})->Args({320, 180, 1280, 720})->Args({321, 181, 1280, 720})->UseRealTime()->Unit(benchmark::kMicrosecond);
492 BENCHMARK_CAPTURE(BM_ResampleEffectHalf, Float16Upscale, GAMMA_LINEAR, "fragment")->Args({640, 360, 1280, 720})->Args({320, 180, 1280, 720})->Args({321, 181, 1280, 720})->UseRealTime()->Unit(benchmark::kMicrosecond);
493 BENCHMARK_CAPTURE(BM_ResampleEffectInt8, Int8Downscale, GAMMA_REC_709, "fragment")->Args({1280, 720, 640, 360})->Args({1280, 720, 320, 180})->Args({1280, 720, 321, 181})->UseRealTime()->Unit(benchmark::kMicrosecond);
494 BENCHMARK_CAPTURE(BM_ResampleEffectHalf, Float16Downscale, GAMMA_LINEAR, "fragment")->Args({1280, 720, 640, 360})->Args({1280, 720, 320, 180})->Args({1280, 720, 321, 181})->UseRealTime()->Unit(benchmark::kMicrosecond);
495 BENCHMARK_CAPTURE(BM_ResampleEffectInt8, Int8UpscaleCompute, GAMMA_REC_709, "compute")->Args({640, 360, 1280, 720})->Args({320, 180, 1280, 720})->Args({321, 181, 1280, 720})->UseRealTime()->Unit(benchmark::kMicrosecond);
496 BENCHMARK_CAPTURE(BM_ResampleEffectHalf, Float16UpscaleCompute, GAMMA_LINEAR, "compute")->Args({640, 360, 1280, 720})->Args({320, 180, 1280, 720})->Args({321, 181, 1280, 720})->UseRealTime()->Unit(benchmark::kMicrosecond);
497 BENCHMARK_CAPTURE(BM_ResampleEffectInt8, Int8DownscaleCompute, GAMMA_REC_709, "compute")->Args({1280, 720, 640, 360})->Args({1280, 720, 320, 180})->Args({1280, 720, 321, 181})->UseRealTime()->Unit(benchmark::kMicrosecond);
498 BENCHMARK_CAPTURE(BM_ResampleEffectHalf, Float16DownscaleCompute, GAMMA_LINEAR, "compute")->Args({1280, 720, 640, 360})->Args({1280, 720, 320, 180})->Args({1280, 720, 321, 181})->UseRealTime()->Unit(benchmark::kMicrosecond);
499
500 void BM_ComputeBilinearScalingWeights(benchmark::State &state)
501 {
502         constexpr unsigned src_size = 1280;
503         constexpr unsigned dst_size = 35;
504         int old_precision = movit_texel_subpixel_precision;
505         movit_texel_subpixel_precision = 64;  // To get consistent results across GPUs; this is a CPU test.
506
507         // One iteration warmup to make sure the Lanczos table is computed.
508         calculate_bilinear_scaling_weights(src_size, dst_size, 0.999f, 0.0f, BilinearFormatConstraints::ALLOW_FP16_AND_FP32);
509
510         for (auto _ : state) {
511                 ScalingWeights weights = calculate_bilinear_scaling_weights(src_size, dst_size, 0.999f, 0.0f, BilinearFormatConstraints::ALLOW_FP16_AND_FP32);
512         }
513
514         movit_texel_subpixel_precision = old_precision;
515 }
516 BENCHMARK(BM_ComputeBilinearScalingWeights)->Unit(benchmark::kMicrosecond);
517
518 void BM_ComputeBilinearScalingWeightsNoFP16(benchmark::State &state)
519 {
520         constexpr unsigned src_size = 1280;
521         constexpr unsigned dst_size = 35;
522         int old_precision = movit_texel_subpixel_precision;
523         movit_texel_subpixel_precision = 64;  // To get consistent results across GPUs; this is a CPU test.
524
525         // One iteration warmup to make sure the Lanczos table is computed.
526         calculate_bilinear_scaling_weights(src_size, dst_size, 0.999f, 0.0f, BilinearFormatConstraints::ALLOW_FP32_ONLY);
527
528         for (auto _ : state) {
529                 ScalingWeights weights = calculate_bilinear_scaling_weights(src_size, dst_size, 0.999f, 0.0f, BilinearFormatConstraints::ALLOW_FP32_ONLY);
530         }
531
532         movit_texel_subpixel_precision = old_precision;
533 }
534 BENCHMARK(BM_ComputeBilinearScalingWeightsNoFP16)->Unit(benchmark::kMicrosecond);
535
536 void BM_ComputeRawScalingWeights(benchmark::State &state)
537 {
538         constexpr unsigned src_size = 1280;
539         constexpr unsigned dst_size = 35;
540
541         // One iteration warmup to make sure the Lanczos table is computed.
542         calculate_raw_scaling_weights(src_size, dst_size, 0.999f, 0.0f);
543
544         for (auto _ : state) {
545                 ScalingWeights weights = calculate_raw_scaling_weights(src_size, dst_size, 0.999f, 0.0f);
546         }
547 }
548 BENCHMARK(BM_ComputeRawScalingWeights)->Unit(benchmark::kMicrosecond);
549
550 #endif
551
552 }  // namespace movit