1 // Unit tests for ResampleEffect.
4 #include <gtest/gtest.h>
7 #include "effect_chain.h"
8 #include "flat_input.h"
9 #include "image_format.h"
10 #include "resample_effect.h"
11 #include "test_util.h"
19 return sin(M_PI * x) / (M_PI * x);
22 float lanczos(float x, float a)
27 return sinc(x) * sinc(x / a);
33 TEST(ResampleEffectTest, IdentityTransformDoesNothing) {
36 float data[size * size] = {
42 float out_data[size * size];
44 EffectChainTester tester(data, size, size, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
45 Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
46 ASSERT_TRUE(resample_effect->set_int("width", 4));
47 ASSERT_TRUE(resample_effect->set_int("height", 4));
48 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
50 expect_equal(data, out_data, size, size);
53 TEST(ResampleEffectTest, UpscaleByTwoGetsCorrectPixelCenters) {
56 float data[size * size] = {
57 0.0, 0.0, 0.0, 0.0, 0.0,
58 0.0, 0.0, 0.0, 0.0, 0.0,
59 0.0, 0.0, 1.0, 0.0, 0.0,
60 0.0, 0.0, 0.0, 0.0, 0.0,
61 0.0, 0.0, 0.0, 0.0, 0.0,
63 float expected_data[size * size * 4], out_data[size * size * 4];
65 for (int y = 0; y < size * 2; ++y) {
66 for (int x = 0; x < size * 2; ++x) {
67 float weight = lanczos((x - size + 0.5f) * 0.5f, 3.0f);
68 weight *= lanczos((y - size + 0.5f) * 0.5f, 3.0f);
69 expected_data[y * (size * 2) + x] = weight;
73 EffectChainTester tester(NULL, size * 2, size * 2, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
76 format.color_space = COLORSPACE_sRGB;
77 format.gamma_curve = GAMMA_LINEAR;
79 FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, size, size);
80 input->set_pixel_data(data);
81 tester.get_chain()->add_input(input);
83 Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
84 ASSERT_TRUE(resample_effect->set_int("width", size * 2));
85 ASSERT_TRUE(resample_effect->set_int("height", size * 2));
86 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
88 expect_equal(expected_data, out_data, size * 2, size * 2);
91 TEST(ResampleEffectTest, DownscaleByTwoGetsCorrectPixelCenters) {
94 // This isn't a perfect dot, since the Lanczos filter has a slight
95 // sharpening effect; the most important thing is that we have kept
96 // the texel center right (everything is nicely symmetric).
97 // The approximate magnitudes have been checked against ImageMagick.
98 float expected_data[size * size] = {
99 0.0045, -0.0067, -0.0598, -0.0067, 0.0045,
100 -0.0067, 0.0099, 0.0886, 0.0099, -0.0067,
101 -0.0598, 0.0886, 0.7930, 0.0886, -0.0598,
102 -0.0067, 0.0099, 0.0886, 0.0099, -0.0067,
103 0.0045, -0.0067, -0.0598, -0.0067, 0.0045,
105 float data[size * size * 4], out_data[size * size];
107 for (int y = 0; y < size * 2; ++y) {
108 for (int x = 0; x < size * 2; ++x) {
109 float weight = lanczos((x - size + 0.5f) * 0.5f, 3.0f);
110 weight *= lanczos((y - size + 0.5f) * 0.5f, 3.0f);
111 data[y * (size * 2) + x] = weight;
115 EffectChainTester tester(NULL, size, size, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
118 format.color_space = COLORSPACE_sRGB;
119 format.gamma_curve = GAMMA_LINEAR;
121 FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, size * 2, size * 2);
122 input->set_pixel_data(data);
123 tester.get_chain()->add_input(input);
125 Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
126 ASSERT_TRUE(resample_effect->set_int("width", size));
127 ASSERT_TRUE(resample_effect->set_int("height", size));
128 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
130 expect_equal(expected_data, out_data, size, size);
133 TEST(ResampleEffectTest, UpscaleByThreeGetsCorrectPixelCenters) {
136 float data[size * size] = {
137 0.0, 0.0, 0.0, 0.0, 0.0,
138 0.0, 0.0, 0.0, 0.0, 0.0,
139 0.0, 0.0, 1.0, 0.0, 0.0,
140 0.0, 0.0, 0.0, 0.0, 0.0,
141 0.0, 0.0, 0.0, 0.0, 0.0,
143 float out_data[size * size * 9];
145 EffectChainTester tester(NULL, size * 3, size * 3, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
148 format.color_space = COLORSPACE_sRGB;
149 format.gamma_curve = GAMMA_LINEAR;
151 FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, size, size);
152 input->set_pixel_data(data);
153 tester.get_chain()->add_input(input);
155 Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
156 ASSERT_TRUE(resample_effect->set_int("width", size * 3));
157 ASSERT_TRUE(resample_effect->set_int("height", size * 3));
158 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
160 // We only bother checking that the middle pixel is still correct,
161 // and that symmetry holds.
162 EXPECT_FLOAT_EQ(1.0, out_data[7 * (size * 3) + 7]);
163 for (unsigned y = 0; y < size * 3; ++y) {
164 for (unsigned x = 0; x < size * 3; ++x) {
165 EXPECT_FLOAT_EQ(out_data[y * (size * 3) + x], out_data[(size * 3 - y - 1) * (size * 3) + x]);
166 EXPECT_FLOAT_EQ(out_data[y * (size * 3) + x], out_data[y * (size * 3) + (size * 3 - x - 1)]);
171 TEST(ResampleEffectTest, HeavyResampleGetsSumRight) {
172 // Do only one resample pass, more specifically the last one, which goes to
173 // our fp32 output. This allows us to analyze the precision without intermediate
175 const int swidth = 1, sheight = 1280;
176 const int dwidth = 1, dheight = 64;
178 float data[swidth * sheight], out_data[dwidth * dheight], expected_data[dwidth * dheight];
179 for (int y = 0; y < sheight; ++y) {
180 for (int x = 0; x < swidth; ++x) {
181 data[y * swidth + x] = 1.0f;
184 for (int y = 0; y < dheight; ++y) {
185 for (int x = 0; x < dwidth; ++x) {
186 expected_data[y * dwidth + x] = 1.0f;
190 EffectChainTester tester(NULL, dwidth, dheight, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, GL_RGBA32F);
193 format.color_space = COLORSPACE_sRGB;
194 format.gamma_curve = GAMMA_LINEAR;
196 FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, swidth, sheight);
197 input->set_pixel_data(data);
199 tester.get_chain()->add_input(input);
200 Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
201 ASSERT_TRUE(resample_effect->set_int("width", dwidth));
202 ASSERT_TRUE(resample_effect->set_int("height", dheight));
203 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
205 // Require that we are within 10-bit accuracy. Note that this limit is for
206 // one pass only, but the limit is tight enough that it should be good enough
207 // for 10-bit accuracy even after two passes.
208 expect_equal(expected_data, out_data, dwidth, dheight, 0.1 / 1023.0);