1 // Unit tests for EffectChain.
3 // Note that this also contains the tests for some of the simpler effects.
5 #include "effect_chain.h"
6 #include "flat_input.h"
7 #include "mirror_effect.h"
9 #include "gtest/gtest.h"
16 class EffectChainTester {
18 EffectChainTester(const float *data, unsigned width, unsigned height, ColorSpace color_space, GammaCurve gamma_curve)
19 : chain(width, height), width(width), height(height)
22 format.color_space = color_space;
23 format.gamma_curve = gamma_curve;
25 FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, width, height);
26 input->set_pixel_data(data);
27 chain.add_input(input);
30 EffectChain *get_chain() { return &chain; }
32 void run(float *out_data, ColorSpace color_space, GammaCurve gamma_curve)
35 format.color_space = color_space;
36 format.gamma_curve = gamma_curve;
37 chain.add_output(format);
40 glViewport(0, 0, width, height);
41 chain.render_to_screen();
43 glReadPixels(0, 0, width, height, GL_RED, GL_FLOAT, out_data);
45 // Flip upside-down to compensate for different origin.
46 for (unsigned y = 0; y < height / 2; ++y) {
47 unsigned flip_y = height - y - 1;
48 for (unsigned x = 0; x < width; ++x) {
49 std::swap(out_data[y * width + x], out_data[flip_y * width + x]);
56 unsigned width, height;
59 void expect_equal(const float *ref, const float *result, unsigned width, unsigned height)
61 float largest_difference = -1.0f;
62 float squared_difference = 0.0f;
64 for (unsigned y = 0; y < height; ++y) {
65 for (unsigned x = 0; x < width; ++x) {
66 float diff = ref[y * width + x] - result[y * width + x];
67 largest_difference = std::max(largest_difference, fabsf(diff));
68 squared_difference += diff * diff;
72 const float largest_difference_limit = 1.5 / 255.0;
73 const float rms_limit = 0.5 / 255.0;
75 EXPECT_LT(largest_difference, largest_difference_limit);
77 float rms = sqrt(squared_difference) / (width * height);
78 EXPECT_LT(rms, rms_limit);
80 if (largest_difference >= largest_difference_limit || rms >= rms_limit) {
81 fprintf(stderr, "Dumping matrices for easier debugging, since at least one test failed.\n");
83 fprintf(stderr, "Reference:\n");
84 for (unsigned y = 0; y < height; ++y) {
85 for (unsigned x = 0; x < width; ++x) {
86 fprintf(stderr, "%7.4f ", ref[y * width + x]);
88 fprintf(stderr, "\n");
91 fprintf(stderr, "\nResult:\n");
92 for (unsigned y = 0; y < height; ++y) {
93 for (unsigned x = 0; x < width; ++x) {
94 fprintf(stderr, "%7.4f ", result[y * width + x]);
96 fprintf(stderr, "\n");
101 TEST(EffectChainTest, EmptyChain) {
107 EffectChainTester tester(data, 3, 2, COLORSPACE_sRGB, GAMMA_LINEAR);
108 tester.run(out_data, COLORSPACE_sRGB, GAMMA_LINEAR);
110 expect_equal(data, out_data, 3, 2);
113 // An effect that does nothing.
114 class IdentityEffect : public Effect {
117 virtual std::string effect_type_id() const { return "IdentityEffect"; }
118 std::string output_fragment_shader() { return read_file("identity.frag"); }
121 TEST(EffectChainTest, Identity) {
127 EffectChainTester tester(data, 3, 2, COLORSPACE_sRGB, GAMMA_LINEAR);
128 tester.get_chain()->add_effect(new IdentityEffect());
129 tester.run(out_data, COLORSPACE_sRGB, GAMMA_LINEAR);
131 expect_equal(data, out_data, 3, 2);
134 // An effect that does nothing, but requests texture bounce.
135 class BouncingIdentityEffect : public Effect {
137 BouncingIdentityEffect() {}
138 virtual std::string effect_type_id() const { return "IdentityEffect"; }
139 std::string output_fragment_shader() { return read_file("identity.frag"); }
140 bool needs_texture_bounce() const { return true; }
143 TEST(EffectChainTest, TextureBouncePreservesIdentity) {
149 EffectChainTester tester(data, 3, 2, COLORSPACE_sRGB, GAMMA_LINEAR);
150 tester.get_chain()->add_effect(new BouncingIdentityEffect());
151 tester.run(out_data, COLORSPACE_sRGB, GAMMA_LINEAR);
153 expect_equal(data, out_data, 3, 2);
156 TEST(MirrorTest, BasicTest) {
161 float expected_data[6] = {
166 EffectChainTester tester(data, 3, 2, COLORSPACE_sRGB, GAMMA_LINEAR);
167 tester.get_chain()->add_effect(new MirrorEffect());
168 tester.run(out_data, COLORSPACE_sRGB, GAMMA_LINEAR);
170 expect_equal(expected_data, out_data, 3, 2);