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