1 // Unit tests for EffectChain.
3 // Note that this also contains the tests for some of the simpler effects.
7 #include "effect_chain.h"
8 #include "flat_input.h"
9 #include "gtest/gtest.h"
10 #include "mirror_effect.h"
11 #include "resize_effect.h"
12 #include "test_util.h"
14 TEST(EffectChainTest, EmptyChain) {
20 EffectChainTester tester(data, 3, 2, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
21 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
23 expect_equal(data, out_data, 3, 2);
26 // An effect that does nothing.
27 class IdentityEffect : public Effect {
30 virtual std::string effect_type_id() const { return "IdentityEffect"; }
31 std::string output_fragment_shader() { return read_file("identity.frag"); }
34 TEST(EffectChainTest, Identity) {
40 EffectChainTester tester(data, 3, 2, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
41 tester.get_chain()->add_effect(new IdentityEffect());
42 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
44 expect_equal(data, out_data, 3, 2);
47 // An effect that does nothing, but requests texture bounce.
48 class BouncingIdentityEffect : public Effect {
50 BouncingIdentityEffect() {}
51 virtual std::string effect_type_id() const { return "IdentityEffect"; }
52 std::string output_fragment_shader() { return read_file("identity.frag"); }
53 bool needs_texture_bounce() const { return true; }
56 TEST(EffectChainTest, TextureBouncePreservesIdentity) {
62 EffectChainTester tester(data, 3, 2, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
63 tester.get_chain()->add_effect(new BouncingIdentityEffect());
64 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
66 expect_equal(data, out_data, 3, 2);
69 TEST(MirrorTest, BasicTest) {
74 float expected_data[6] = {
79 EffectChainTester tester(data, 3, 2, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
80 tester.get_chain()->add_effect(new MirrorEffect());
81 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
83 expect_equal(expected_data, out_data, 3, 2);
86 // A dummy effect that inverts its input.
87 class InvertEffect : public Effect {
90 virtual std::string effect_type_id() const { return "InvertEffect"; }
91 std::string output_fragment_shader() { return read_file("invert_effect.frag"); }
93 // A real invert would actually care about its alpha,
94 // but in this unit test, it only complicates things.
95 virtual AlphaHandling alpha_handling() const { return DONT_CARE_ALPHA_TYPE; }
98 // Like IdentityEffect, but rewrites itself out of the loop,
99 // splicing in a different effect instead. Also stores the new node,
100 // so we later can check whatever properties we'd like about the graph.
102 class RewritingEffect : public Effect {
104 RewritingEffect() : effect(new T()) {}
105 virtual std::string effect_type_id() const { return "RewritingEffect[" + effect->effect_type_id() + "]"; }
106 std::string output_fragment_shader() { EXPECT_TRUE(false); return read_file("identity.frag"); }
107 virtual void rewrite_graph(EffectChain *graph, Node *self) {
108 replaced_node = graph->add_node(effect);
109 graph->replace_receiver(self, replaced_node);
110 graph->replace_sender(self, replaced_node);
111 self->disabled = true;
118 TEST(EffectChainTest, RewritingWorksAndGammaConversionsAreInserted) {
123 float expected_data[6] = {
124 1.0f, 0.9771f, 0.9673f,
128 EffectChainTester tester(data, 3, 2, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_sRGB);
129 RewritingEffect<InvertEffect> *effect = new RewritingEffect<InvertEffect>();
130 tester.get_chain()->add_effect(effect);
131 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_sRGB);
133 Node *node = effect->replaced_node;
134 ASSERT_EQ(1, node->incoming_links.size());
135 ASSERT_EQ(1, node->outgoing_links.size());
136 EXPECT_EQ("GammaExpansionEffect", node->incoming_links[0]->effect->effect_type_id());
137 EXPECT_EQ("GammaCompressionEffect", node->outgoing_links[0]->effect->effect_type_id());
139 expect_equal(expected_data, out_data, 3, 2);
142 TEST(EffectChainTest, RewritingWorksAndTexturesAreAskedForsRGB) {
143 unsigned char data[] = {
147 float expected_data[4] = {
152 EffectChainTester tester(NULL, 2, 2);
153 tester.add_input(data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_sRGB);
154 RewritingEffect<InvertEffect> *effect = new RewritingEffect<InvertEffect>();
155 tester.get_chain()->add_effect(effect);
156 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_sRGB);
158 Node *node = effect->replaced_node;
159 ASSERT_EQ(1, node->incoming_links.size());
160 ASSERT_EQ(1, node->outgoing_links.size());
161 EXPECT_EQ("FlatInput", node->incoming_links[0]->effect->effect_type_id());
162 EXPECT_EQ("GammaCompressionEffect", node->outgoing_links[0]->effect->effect_type_id());
164 expect_equal(expected_data, out_data, 2, 2);
167 TEST(EffectChainTest, RewritingWorksAndColorspaceConversionsAreInserted) {
172 float expected_data[6] = {
177 EffectChainTester tester(data, 3, 2, FORMAT_GRAYSCALE, COLORSPACE_REC_601_525, GAMMA_LINEAR);
178 RewritingEffect<InvertEffect> *effect = new RewritingEffect<InvertEffect>();
179 tester.get_chain()->add_effect(effect);
180 tester.run(out_data, GL_RED, COLORSPACE_REC_601_525, GAMMA_LINEAR);
182 Node *node = effect->replaced_node;
183 ASSERT_EQ(1, node->incoming_links.size());
184 ASSERT_EQ(1, node->outgoing_links.size());
185 EXPECT_EQ("ColorspaceConversionEffect", node->incoming_links[0]->effect->effect_type_id());
186 EXPECT_EQ("ColorspaceConversionEffect", node->outgoing_links[0]->effect->effect_type_id());
188 expect_equal(expected_data, out_data, 3, 2);
191 // A fake input that can change its output colorspace and gamma between instantiation
193 class UnknownColorspaceInput : public FlatInput {
195 UnknownColorspaceInput(ImageFormat format, MovitPixelFormat pixel_format, GLenum type, unsigned width, unsigned height)
196 : FlatInput(format, pixel_format, type, width, height),
197 overridden_color_space(format.color_space),
198 overridden_gamma_curve(format.gamma_curve) {}
199 virtual std::string effect_type_id() const { return "UnknownColorspaceInput"; }
201 void set_color_space(Colorspace colorspace) {
202 overridden_color_space = colorspace;
204 void set_gamma_curve(GammaCurve gamma_curve) {
205 overridden_gamma_curve = gamma_curve;
207 Colorspace get_color_space() const { return overridden_color_space; }
208 GammaCurve get_gamma_curve() const { return overridden_gamma_curve; }
211 Colorspace overridden_color_space;
212 GammaCurve overridden_gamma_curve;
215 TEST(EffectChainTester, HandlesInputChangingColorspace) {
224 float out_data[size];
226 EffectChainTester tester(NULL, 4, 1, FORMAT_GRAYSCALE);
228 // First say that we have sRGB, linear input.
230 format.color_space = COLORSPACE_sRGB;
231 format.gamma_curve = GAMMA_LINEAR;
233 UnknownColorspaceInput *input = new UnknownColorspaceInput(format, FORMAT_GRAYSCALE, GL_FLOAT, 4, 1);
234 input->set_pixel_data(data);
235 tester.get_chain()->add_input(input);
237 // Now we change to Rec. 601 input.
238 input->set_color_space(COLORSPACE_REC_601_625);
239 input->set_gamma_curve(GAMMA_REC_601);
241 // Now ask for Rec. 601 output. Thus, our chain should now be a no-op.
242 tester.run(out_data, GL_RED, COLORSPACE_REC_601_625, GAMMA_REC_601);
243 expect_equal(data, out_data, 4, 1);
246 TEST(EffectChainTest, NoGammaConversionsWhenLinearLightNotNeeded) {
251 float expected_data[6] = {
256 EffectChainTester tester(data, 3, 2, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_sRGB);
257 RewritingEffect<MirrorEffect> *effect = new RewritingEffect<MirrorEffect>();
258 tester.get_chain()->add_effect(effect);
259 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_sRGB);
261 Node *node = effect->replaced_node;
262 ASSERT_EQ(1, node->incoming_links.size());
263 EXPECT_EQ(0, node->outgoing_links.size());
264 EXPECT_EQ("FlatInput", node->incoming_links[0]->effect->effect_type_id());
266 expect_equal(expected_data, out_data, 3, 2);
269 TEST(EffectChainTest, NoColorspaceConversionsWhensRGBPrimariesNotNeeded) {
274 float expected_data[6] = {
279 EffectChainTester tester(data, 3, 2, FORMAT_GRAYSCALE, COLORSPACE_REC_601_525, GAMMA_LINEAR);
280 RewritingEffect<MirrorEffect> *effect = new RewritingEffect<MirrorEffect>();
281 tester.get_chain()->add_effect(effect);
282 tester.run(out_data, GL_RED, COLORSPACE_REC_601_525, GAMMA_LINEAR);
284 Node *node = effect->replaced_node;
285 ASSERT_EQ(1, node->incoming_links.size());
286 EXPECT_EQ(0, node->outgoing_links.size());
287 EXPECT_EQ("FlatInput", node->incoming_links[0]->effect->effect_type_id());
289 expect_equal(expected_data, out_data, 3, 2);
292 // The identity effect needs linear light, and thus will get conversions on both sides.
293 // Verify that sRGB data is properly converted to and from linear light for the entire ramp.
294 TEST(EffectChainTest, IdentityThroughsRGBConversions) {
296 for (unsigned i = 0; i < 256; ++i) {
300 EffectChainTester tester(data, 256, 1, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_sRGB);
301 tester.get_chain()->add_effect(new IdentityEffect());
302 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_sRGB);
304 expect_equal(data, out_data, 256, 1);
307 // Same, but uses the forward sRGB table from the GPU.
308 TEST(EffectChainTest, IdentityThroughGPUsRGBConversions) {
309 unsigned char data[256];
310 float expected_data[256];
311 for (unsigned i = 0; i < 256; ++i) {
313 expected_data[i] = i / 255.0;
316 EffectChainTester tester(NULL, 256, 1);
317 tester.add_input(data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_sRGB);
318 tester.get_chain()->add_effect(new IdentityEffect());
319 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_sRGB);
321 expect_equal(expected_data, out_data, 256, 1);
324 // Same, for the Rec. 601/709 gamma curve.
325 TEST(EffectChainTest, IdentityThroughRec709) {
327 for (unsigned i = 0; i < 256; ++i) {
331 EffectChainTester tester(data, 256, 1, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_REC_709);
332 tester.get_chain()->add_effect(new IdentityEffect());
333 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_REC_709);
335 expect_equal(data, out_data, 256, 1);
338 // The identity effect needs premultiplied alpha, and thus will get conversions on both sides.
339 TEST(EffectChainTest, IdentityThroughAlphaConversions) {
341 float data[4 * size] = {
342 0.8f, 0.0f, 0.0f, 0.5f,
343 0.0f, 0.2f, 0.2f, 0.3f,
344 0.1f, 0.0f, 1.0f, 1.0f,
347 EffectChainTester tester(data, size, 1, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_sRGB, GAMMA_LINEAR);
348 tester.get_chain()->add_effect(new IdentityEffect());
349 tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR);
351 expect_equal(data, out_data, 4, size);
354 TEST(EffectChainTest, NoAlphaConversionsWhenPremultipliedAlphaNotNeeded) {
356 float data[4 * size] = {
357 0.8f, 0.0f, 0.0f, 0.5f,
358 0.0f, 0.2f, 0.2f, 0.3f,
359 0.1f, 0.0f, 1.0f, 1.0f,
361 float expected_data[4 * size] = {
362 0.1f, 0.0f, 1.0f, 1.0f,
363 0.0f, 0.2f, 0.2f, 0.3f,
364 0.8f, 0.0f, 0.0f, 0.5f,
366 float out_data[4 * size];
367 EffectChainTester tester(data, size, 1, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_sRGB, GAMMA_LINEAR);
368 RewritingEffect<MirrorEffect> *effect = new RewritingEffect<MirrorEffect>();
369 tester.get_chain()->add_effect(effect);
370 tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR);
372 Node *node = effect->replaced_node;
373 ASSERT_EQ(1, node->incoming_links.size());
374 EXPECT_EQ(0, node->outgoing_links.size());
375 EXPECT_EQ("FlatInput", node->incoming_links[0]->effect->effect_type_id());
377 expect_equal(expected_data, out_data, 4, size);
380 // An input that outputs only blue, which has blank alpha.
381 class BlueInput : public Input {
383 BlueInput() { register_int("needs_mipmaps", &needs_mipmaps); }
384 virtual std::string effect_type_id() const { return "IdentityEffect"; }
385 std::string output_fragment_shader() { return read_file("blue.frag"); }
386 virtual AlphaHandling alpha_handling() const { return OUTPUT_BLANK_ALPHA; }
387 virtual void finalize() {}
388 virtual bool can_output_linear_gamma() const { return true; }
389 virtual unsigned get_width() const { return 1; }
390 virtual unsigned get_height() const { return 1; }
391 virtual Colorspace get_color_space() const { return COLORSPACE_sRGB; }
392 virtual GammaCurve get_gamma_curve() const { return GAMMA_LINEAR; }
398 // Like RewritingEffect<InvertEffect>, but splicing in a BlueInput instead,
399 // which outputs blank alpha.
400 class RewritingToBlueInput : public Input {
402 RewritingToBlueInput() { register_int("needs_mipmaps", &needs_mipmaps); }
403 virtual std::string effect_type_id() const { return "RewritingToBlueInput"; }
404 std::string output_fragment_shader() { EXPECT_TRUE(false); return read_file("identity.frag"); }
405 virtual void rewrite_graph(EffectChain *graph, Node *self) {
406 Node *blue_node = graph->add_node(new BlueInput());
407 graph->replace_receiver(self, blue_node);
408 graph->replace_sender(self, blue_node);
410 self->disabled = true;
411 this->blue_node = blue_node;
414 // Dummy values that we need to implement because we inherit from Input.
415 // Same as BlueInput.
416 virtual AlphaHandling alpha_handling() const { return OUTPUT_BLANK_ALPHA; }
417 virtual void finalize() {}
418 virtual bool can_output_linear_gamma() const { return true; }
419 virtual unsigned get_width() const { return 1; }
420 virtual unsigned get_height() const { return 1; }
421 virtual Colorspace get_color_space() const { return COLORSPACE_sRGB; }
422 virtual GammaCurve get_gamma_curve() const { return GAMMA_LINEAR; }
430 TEST(EffectChainTest, NoAlphaConversionsWithBlankAlpha) {
432 float data[4 * size] = {
433 0.0f, 0.0f, 1.0f, 1.0f,
434 0.0f, 0.0f, 1.0f, 1.0f,
435 0.0f, 0.0f, 1.0f, 1.0f,
437 float out_data[4 * size];
438 EffectChainTester tester(NULL, size, 1);
439 RewritingToBlueInput *input = new RewritingToBlueInput();
440 tester.get_chain()->add_input(input);
441 tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR, OUTPUT_ALPHA_PREMULTIPLIED);
443 Node *node = input->blue_node;
444 EXPECT_EQ(0, node->incoming_links.size());
445 EXPECT_EQ(0, node->outgoing_links.size());
447 expect_equal(data, out_data, 4, size);
450 // Effectively scales down its input linearly by 4x (and repeating it),
451 // which is not attainable without mipmaps.
452 class MipmapNeedingEffect : public Effect {
454 MipmapNeedingEffect() {}
455 virtual bool needs_mipmaps() const { return true; }
456 virtual std::string effect_type_id() const { return "MipmapNeedingEffect"; }
457 std::string output_fragment_shader() { return read_file("mipmap_needing_effect.frag"); }
458 void set_gl_state(GLuint glsl_program_num, const std::string& prefix, unsigned *sampler_num)
460 glActiveTexture(GL_TEXTURE0);
462 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
464 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
469 TEST(EffectChainTest, MipmapGenerationWorks) {
470 float data[] = { // In 4x4 blocks.
471 1.0f, 0.0f, 0.0f, 0.0f,
472 0.0f, 0.0f, 0.0f, 0.0f,
473 0.0f, 0.0f, 0.0f, 0.0f,
474 0.0f, 0.0f, 0.0f, 1.0f,
476 0.0f, 0.0f, 0.0f, 0.0f,
477 0.0f, 0.5f, 0.0f, 0.0f,
478 0.0f, 0.0f, 1.0f, 0.0f,
479 0.0f, 0.0f, 0.0f, 0.0f,
481 1.0f, 1.0f, 1.0f, 1.0f,
482 1.0f, 1.0f, 1.0f, 1.0f,
483 1.0f, 1.0f, 1.0f, 1.0f,
484 1.0f, 1.0f, 1.0f, 1.0f,
486 0.0f, 0.0f, 0.0f, 0.0f,
487 0.0f, 1.0f, 1.0f, 0.0f,
488 0.0f, 1.0f, 1.0f, 0.0f,
489 0.0f, 0.0f, 0.0f, 0.0f,
491 float expected_data[] = { // Repeated four times each way.
492 0.125f, 0.125f, 0.125f, 0.125f,
493 0.09375f, 0.09375f, 0.09375f, 0.09375f,
494 1.0f, 1.0f, 1.0f, 1.0f,
495 0.25f, 0.25f, 0.25f, 0.25f,
497 0.125f, 0.125f, 0.125f, 0.125f,
498 0.09375f, 0.09375f, 0.09375f, 0.09375f,
499 1.0f, 1.0f, 1.0f, 1.0f,
500 0.25f, 0.25f, 0.25f, 0.25f,
502 0.125f, 0.125f, 0.125f, 0.125f,
503 0.09375f, 0.09375f, 0.09375f, 0.09375f,
504 1.0f, 1.0f, 1.0f, 1.0f,
505 0.25f, 0.25f, 0.25f, 0.25f,
507 0.125f, 0.125f, 0.125f, 0.125f,
508 0.09375f, 0.09375f, 0.09375f, 0.09375f,
509 1.0f, 1.0f, 1.0f, 1.0f,
510 0.25f, 0.25f, 0.25f, 0.25f,
512 float out_data[4 * 16];
513 EffectChainTester tester(data, 4, 16, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
514 tester.get_chain()->add_effect(new MipmapNeedingEffect());
515 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
517 expect_equal(expected_data, out_data, 4, 16);
520 TEST(EffectChainTest, ResizeDownByFourThenUpByFour) {
521 float data[] = { // In 4x4 blocks.
522 1.0f, 0.0f, 0.0f, 0.0f,
523 0.0f, 0.0f, 0.0f, 0.0f,
524 0.0f, 0.0f, 0.0f, 0.0f,
525 0.0f, 0.0f, 0.0f, 1.0f,
527 0.0f, 0.0f, 0.0f, 0.0f,
528 0.0f, 0.5f, 0.0f, 0.0f,
529 0.0f, 0.0f, 1.0f, 0.0f,
530 0.0f, 0.0f, 0.0f, 0.0f,
532 1.0f, 1.0f, 1.0f, 1.0f,
533 1.0f, 1.0f, 1.0f, 1.0f,
534 1.0f, 1.0f, 1.0f, 1.0f,
535 1.0f, 1.0f, 1.0f, 1.0f,
537 0.0f, 0.0f, 0.0f, 0.0f,
538 0.0f, 1.0f, 1.0f, 0.0f,
539 0.0f, 1.0f, 1.0f, 0.0f,
540 0.0f, 0.0f, 0.0f, 0.0f,
542 float expected_data[] = { // Repeated four times horizontaly, interpolated vertically.
543 0.1250f, 0.1250f, 0.1250f, 0.1250f,
544 0.1250f, 0.1250f, 0.1250f, 0.1250f,
545 0.1211f, 0.1211f, 0.1211f, 0.1211f,
546 0.1133f, 0.1133f, 0.1133f, 0.1133f,
547 0.1055f, 0.1055f, 0.1055f, 0.1055f,
548 0.0977f, 0.0977f, 0.0977f, 0.0977f,
549 0.2070f, 0.2070f, 0.2070f, 0.2070f,
550 0.4336f, 0.4336f, 0.4336f, 0.4336f,
551 0.6602f, 0.6602f, 0.6602f, 0.6602f,
552 0.8867f, 0.8867f, 0.8867f, 0.8867f,
553 0.9062f, 0.9062f, 0.9062f, 0.9062f,
554 0.7188f, 0.7188f, 0.7188f, 0.7188f,
555 0.5312f, 0.5312f, 0.5312f, 0.5312f,
556 0.3438f, 0.3438f, 0.3438f, 0.3438f,
557 0.2500f, 0.2500f, 0.2500f, 0.2500f,
558 0.2500f, 0.2500f, 0.2500f, 0.2500f,
560 float out_data[4 * 16];
562 ResizeEffect *downscale = new ResizeEffect();
563 ASSERT_TRUE(downscale->set_int("width", 1));
564 ASSERT_TRUE(downscale->set_int("height", 4));
566 ResizeEffect *upscale = new ResizeEffect();
567 ASSERT_TRUE(upscale->set_int("width", 4));
568 ASSERT_TRUE(upscale->set_int("height", 16));
570 EffectChainTester tester(data, 4, 16, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
571 tester.get_chain()->add_effect(downscale);
572 tester.get_chain()->add_effect(upscale);
573 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
575 expect_equal(expected_data, out_data, 4, 16);
578 // An effect that multiplies with a constant. Used below.
579 class MultiplyEffect : public Effect {
581 MultiplyEffect() { register_float("factor", &factor); }
582 virtual std::string effect_type_id() const { return "MultiplyEffect"; }
583 std::string output_fragment_shader() { return read_file("multiply.frag"); }
584 virtual AlphaHandling alpha_handling() const { return DONT_CARE_ALPHA_TYPE; }
590 // An effect that adds its two inputs together. Used below.
591 class AddEffect : public Effect {
594 virtual std::string effect_type_id() const { return "AddEffect"; }
595 std::string output_fragment_shader() { return read_file("add.frag"); }
596 virtual unsigned num_inputs() const { return 2; }
597 virtual AlphaHandling alpha_handling() const { return DONT_CARE_ALPHA_TYPE; }
600 // Constructs the graph
604 // MultiplyEffect MultiplyEffect |
608 // and verifies that it gives the correct output.
609 TEST(EffectChainTest, DiamondGraph) {
614 float expected_data[] = {
618 float out_data[2 * 2];
620 MultiplyEffect *mul_half = new MultiplyEffect();
621 ASSERT_TRUE(mul_half->set_float("factor", 0.5f));
623 MultiplyEffect *mul_two = new MultiplyEffect();
624 ASSERT_TRUE(mul_two->set_float("factor", 2.0f));
626 EffectChainTester tester(NULL, 2, 2);
629 format.color_space = COLORSPACE_sRGB;
630 format.gamma_curve = GAMMA_LINEAR;
632 FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, 2, 2);
633 input->set_pixel_data(data);
635 tester.get_chain()->add_input(input);
636 tester.get_chain()->add_effect(mul_half, input);
637 tester.get_chain()->add_effect(mul_two, input);
638 tester.get_chain()->add_effect(new AddEffect(), mul_half, mul_two);
639 tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
641 expect_equal(expected_data, out_data, 2, 2);