1 // Unit tests for ResampleEffect.
6 #include "effect_chain.h"
7 #include "flat_input.h"
9 #include "gtest/gtest.h"
10 #include "image_format.h"
11 #include "resample_effect.h"
12 #include "test_util.h"
20 return sin(M_PI * x) / (M_PI * x);
23 float lanczos(float x, float a)
28 return sinc(x) * sinc(x / a);
34 TEST(ResampleEffectTest, IdentityTransformDoesNothing) {
37 float data[size * size] = {
43 float out_data[size * size];
45 EffectChainTester tester(data, size, size, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
46 Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
47 ASSERT_TRUE(resample_effect->set_int("width", 4));
48 ASSERT_TRUE(resample_effect->set_int("height", 4));
49 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
51 expect_equal(data, out_data, size, size);
54 TEST(ResampleEffectTest, UpscaleByTwoGetsCorrectPixelCenters) {
57 float data[size * size] = {
58 0.0, 0.0, 0.0, 0.0, 0.0,
59 0.0, 0.0, 0.0, 0.0, 0.0,
60 0.0, 0.0, 1.0, 0.0, 0.0,
61 0.0, 0.0, 0.0, 0.0, 0.0,
62 0.0, 0.0, 0.0, 0.0, 0.0,
64 float expected_data[size * size * 4], out_data[size * size * 4];
66 for (int y = 0; y < size * 2; ++y) {
67 for (int x = 0; x < size * 2; ++x) {
68 float weight = lanczos((x - size + 0.5f) * 0.5f, 3.0f);
69 weight *= lanczos((y - size + 0.5f) * 0.5f, 3.0f);
70 expected_data[y * (size * 2) + x] = weight;
74 EffectChainTester tester(NULL, size * 2, size * 2, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
77 format.color_space = COLORSPACE_sRGB;
78 format.gamma_curve = GAMMA_LINEAR;
80 FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, size, size);
81 input->set_pixel_data(data);
82 tester.get_chain()->add_input(input);
84 Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
85 ASSERT_TRUE(resample_effect->set_int("width", size * 2));
86 ASSERT_TRUE(resample_effect->set_int("height", size * 2));
87 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
89 expect_equal(expected_data, out_data, size * 2, size * 2);
92 TEST(ResampleEffectTest, DownscaleByTwoGetsCorrectPixelCenters) {
95 // This isn't a perfect dot, since the Lanczos filter has a slight
96 // sharpening effect; the most important thing is that we have kept
97 // the texel center right (everything is nicely symmetric).
98 // The approximate magnitudes have been checked against ImageMagick.
99 float expected_data[size * size] = {
100 0.0045, -0.0067, -0.0598, -0.0067, 0.0045,
101 -0.0067, 0.0099, 0.0886, 0.0099, -0.0067,
102 -0.0598, 0.0886, 0.7930, 0.0886, -0.0598,
103 -0.0067, 0.0099, 0.0886, 0.0099, -0.0067,
104 0.0045, -0.0067, -0.0598, -0.0067, 0.0045,
106 float data[size * size * 4], out_data[size * size];
108 for (int y = 0; y < size * 2; ++y) {
109 for (int x = 0; x < size * 2; ++x) {
110 float weight = lanczos((x - size + 0.5f) * 0.5f, 3.0f);
111 weight *= lanczos((y - size + 0.5f) * 0.5f, 3.0f);
112 data[y * (size * 2) + x] = weight;
116 EffectChainTester tester(NULL, size, size, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
119 format.color_space = COLORSPACE_sRGB;
120 format.gamma_curve = GAMMA_LINEAR;
122 FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, size * 2, size * 2);
123 input->set_pixel_data(data);
124 tester.get_chain()->add_input(input);
126 Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
127 ASSERT_TRUE(resample_effect->set_int("width", size));
128 ASSERT_TRUE(resample_effect->set_int("height", size));
129 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
131 expect_equal(expected_data, out_data, size, size);
134 TEST(ResampleEffectTest, UpscaleByThreeGetsCorrectPixelCenters) {
137 float data[size * size] = {
138 0.0, 0.0, 0.0, 0.0, 0.0,
139 0.0, 0.0, 0.0, 0.0, 0.0,
140 0.0, 0.0, 1.0, 0.0, 0.0,
141 0.0, 0.0, 0.0, 0.0, 0.0,
142 0.0, 0.0, 0.0, 0.0, 0.0,
144 float out_data[size * size * 9];
146 EffectChainTester tester(NULL, size * 3, size * 3, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
149 format.color_space = COLORSPACE_sRGB;
150 format.gamma_curve = GAMMA_LINEAR;
152 FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, size, size);
153 input->set_pixel_data(data);
154 tester.get_chain()->add_input(input);
156 Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
157 ASSERT_TRUE(resample_effect->set_int("width", size * 3));
158 ASSERT_TRUE(resample_effect->set_int("height", size * 3));
159 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
161 // We only bother checking that the middle pixel is still correct,
162 // and that symmetry holds.
163 EXPECT_FLOAT_EQ(1.0, out_data[7 * (size * 3) + 7]);
164 for (unsigned y = 0; y < size * 3; ++y) {
165 for (unsigned x = 0; x < size * 3; ++x) {
166 EXPECT_FLOAT_EQ(out_data[y * (size * 3) + x], out_data[(size * 3 - y - 1) * (size * 3) + x]);
167 EXPECT_FLOAT_EQ(out_data[y * (size * 3) + x], out_data[y * (size * 3) + (size * 3 - x - 1)]);
172 TEST(ResampleEffectTest, HeavyResampleGetsSumRight) {
173 // Do only one resample pass, more specifically the last one, which goes to
174 // our fp32 output. This allows us to analyze the precision without intermediate
176 const int swidth = 1, sheight = 1280;
177 const int dwidth = 1, dheight = 64;
179 float data[swidth * sheight], out_data[dwidth * dheight], expected_data[dwidth * dheight];
180 for (int y = 0; y < sheight; ++y) {
181 for (int x = 0; x < swidth; ++x) {
182 data[y * swidth + x] = 1.0f;
185 for (int y = 0; y < dheight; ++y) {
186 for (int x = 0; x < dwidth; ++x) {
187 expected_data[y * dwidth + x] = 1.0f;
191 EffectChainTester tester(NULL, dwidth, dheight, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, GL_RGBA32F);
194 format.color_space = COLORSPACE_sRGB;
195 format.gamma_curve = GAMMA_LINEAR;
197 FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, swidth, sheight);
198 input->set_pixel_data(data);
200 tester.get_chain()->add_input(input);
201 Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
202 ASSERT_TRUE(resample_effect->set_int("width", dwidth));
203 ASSERT_TRUE(resample_effect->set_int("height", dheight));
204 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
206 // Require that we are within 10-bit accuracy. Note that this limit is for
207 // one pass only, but the limit is tight enough that it should be good enough
208 // for 10-bit accuracy even after two passes.
209 expect_equal(expected_data, out_data, dwidth, dheight, 0.1 / 1023.0);