X-Git-Url: https://git.sesse.net/?p=movit;a=blobdiff_plain;f=effect_chain_test.cpp;h=75491030b05b66f27fef22a17ca8e5f7ccf66dcd;hp=356d628e7e0fbd7dd2c293a9efafd34ed36cfed1;hb=8e37939a9bc1c902d0929dfae70e8d515de6e684;hpb=b10c546f579c7ccb5939161e61a71cd18a3f9bbd diff --git a/effect_chain_test.cpp b/effect_chain_test.cpp index 356d628..7549103 100644 --- a/effect_chain_test.cpp +++ b/effect_chain_test.cpp @@ -51,6 +51,7 @@ public: virtual std::string effect_type_id() const { return "IdentityEffect"; } std::string output_fragment_shader() { return read_file("identity.frag"); } bool needs_texture_bounce() const { return true; } + AlphaHandling alpha_handling() const { return DONT_CARE_ALPHA_TYPE; } }; TEST(EffectChainTest, TextureBouncePreservesIdentity) { @@ -96,24 +97,23 @@ public: }; // Like IdentityEffect, but rewrites itself out of the loop, -// splicing in a InvertEffect instead. Also stores the new node, -// so we later can check that there are gamma conversion effects -// on both sides. -class RewritingToInvertEffect : public Effect { +// splicing in a different effect instead. Also stores the new node, +// so we later can check whatever properties we'd like about the graph. +template +class RewritingEffect : public Effect { public: - RewritingToInvertEffect() {} - virtual std::string effect_type_id() const { return "RewritingToInvertEffect"; } + RewritingEffect() : effect(new T()), replaced_node(NULL) {} + virtual std::string effect_type_id() const { return "RewritingEffect[" + effect->effect_type_id() + "]"; } std::string output_fragment_shader() { EXPECT_TRUE(false); return read_file("identity.frag"); } virtual void rewrite_graph(EffectChain *graph, Node *self) { - Node *invert_node = graph->add_node(new InvertEffect()); - graph->replace_receiver(self, invert_node); - graph->replace_sender(self, invert_node); - + replaced_node = graph->add_node(effect); + graph->replace_receiver(self, replaced_node); + graph->replace_sender(self, replaced_node); self->disabled = true; - this->invert_node = invert_node; } - Node *invert_node; + T *effect; + Node *replaced_node; }; TEST(EffectChainTest, RewritingWorksAndGammaConversionsAreInserted) { @@ -127,11 +127,11 @@ TEST(EffectChainTest, RewritingWorksAndGammaConversionsAreInserted) { }; float out_data[6]; EffectChainTester tester(data, 3, 2, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_sRGB); - RewritingToInvertEffect *effect = new RewritingToInvertEffect(); + RewritingEffect *effect = new RewritingEffect(); tester.get_chain()->add_effect(effect); tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_sRGB); - Node *node = effect->invert_node; + Node *node = effect->replaced_node; ASSERT_EQ(1, node->incoming_links.size()); ASSERT_EQ(1, node->outgoing_links.size()); EXPECT_EQ("GammaExpansionEffect", node->incoming_links[0]->effect->effect_type_id()); @@ -152,11 +152,11 @@ TEST(EffectChainTest, RewritingWorksAndTexturesAreAskedForsRGB) { float out_data[2]; EffectChainTester tester(NULL, 2, 2); tester.add_input(data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_sRGB); - RewritingToInvertEffect *effect = new RewritingToInvertEffect(); + RewritingEffect *effect = new RewritingEffect(); tester.get_chain()->add_effect(effect); tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_sRGB); - Node *node = effect->invert_node; + Node *node = effect->replaced_node; ASSERT_EQ(1, node->incoming_links.size()); ASSERT_EQ(1, node->outgoing_links.size()); EXPECT_EQ("FlatInput", node->incoming_links[0]->effect->effect_type_id()); @@ -176,11 +176,11 @@ TEST(EffectChainTest, RewritingWorksAndColorspaceConversionsAreInserted) { }; float out_data[6]; EffectChainTester tester(data, 3, 2, FORMAT_GRAYSCALE, COLORSPACE_REC_601_525, GAMMA_LINEAR); - RewritingToInvertEffect *effect = new RewritingToInvertEffect(); + RewritingEffect *effect = new RewritingEffect(); tester.get_chain()->add_effect(effect); tester.run(out_data, GL_RED, COLORSPACE_REC_601_525, GAMMA_LINEAR); - Node *node = effect->invert_node; + Node *node = effect->replaced_node; ASSERT_EQ(1, node->incoming_links.size()); ASSERT_EQ(1, node->outgoing_links.size()); EXPECT_EQ("ColorspaceConversionEffect", node->incoming_links[0]->effect->effect_type_id()); @@ -244,25 +244,6 @@ TEST(EffectChainTester, HandlesInputChangingColorspace) { expect_equal(data, out_data, 4, 1); } -// Like RewritingToInvertEffect, but splicing in a MirrorEffect instead, -// which does not need linear light or sRGB primaries. -class RewritingToMirrorEffect : public Effect { -public: - RewritingToMirrorEffect() {} - virtual std::string effect_type_id() const { return "RewritingToMirrorEffect"; } - std::string output_fragment_shader() { EXPECT_TRUE(false); return read_file("identity.frag"); } - virtual void rewrite_graph(EffectChain *graph, Node *self) { - Node *mirror_node = graph->add_node(new MirrorEffect()); - graph->replace_receiver(self, mirror_node); - graph->replace_sender(self, mirror_node); - - self->disabled = true; - this->mirror_node = mirror_node; - } - - Node *mirror_node; -}; - TEST(EffectChainTest, NoGammaConversionsWhenLinearLightNotNeeded) { float data[] = { 0.0f, 0.25f, 0.3f, @@ -274,11 +255,11 @@ TEST(EffectChainTest, NoGammaConversionsWhenLinearLightNotNeeded) { }; float out_data[6]; EffectChainTester tester(data, 3, 2, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_sRGB); - RewritingToMirrorEffect *effect = new RewritingToMirrorEffect(); + RewritingEffect *effect = new RewritingEffect(); tester.get_chain()->add_effect(effect); tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_sRGB); - Node *node = effect->mirror_node; + Node *node = effect->replaced_node; ASSERT_EQ(1, node->incoming_links.size()); EXPECT_EQ(0, node->outgoing_links.size()); EXPECT_EQ("FlatInput", node->incoming_links[0]->effect->effect_type_id()); @@ -297,11 +278,11 @@ TEST(EffectChainTest, NoColorspaceConversionsWhensRGBPrimariesNotNeeded) { }; float out_data[6]; EffectChainTester tester(data, 3, 2, FORMAT_GRAYSCALE, COLORSPACE_REC_601_525, GAMMA_LINEAR); - RewritingToMirrorEffect *effect = new RewritingToMirrorEffect(); + RewritingEffect *effect = new RewritingEffect(); tester.get_chain()->add_effect(effect); tester.run(out_data, GL_RED, COLORSPACE_REC_601_525, GAMMA_LINEAR); - Node *node = effect->mirror_node; + Node *node = effect->replaced_node; ASSERT_EQ(1, node->incoming_links.size()); EXPECT_EQ(0, node->outgoing_links.size()); EXPECT_EQ("FlatInput", node->incoming_links[0]->effect->effect_type_id()); @@ -385,11 +366,11 @@ TEST(EffectChainTest, NoAlphaConversionsWhenPremultipliedAlphaNotNeeded) { }; float out_data[4 * size]; EffectChainTester tester(data, size, 1, FORMAT_RGBA_POSTMULTIPLIED_ALPHA, COLORSPACE_sRGB, GAMMA_LINEAR); - RewritingToMirrorEffect *effect = new RewritingToMirrorEffect(); + RewritingEffect *effect = new RewritingEffect(); tester.get_chain()->add_effect(effect); tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR); - Node *node = effect->mirror_node; + Node *node = effect->replaced_node; ASSERT_EQ(1, node->incoming_links.size()); EXPECT_EQ(0, node->outgoing_links.size()); EXPECT_EQ("FlatInput", node->incoming_links[0]->effect->effect_type_id()); @@ -415,7 +396,7 @@ private: int needs_mipmaps; }; -// Like RewritingToInvertEffect, but splicing in a BlueInput instead, +// Like RewritingEffect, but splicing in a BlueInput instead, // which outputs blank alpha. class RewritingToBlueInput : public Input { public: @@ -594,3 +575,118 @@ TEST(EffectChainTest, ResizeDownByFourThenUpByFour) { expect_equal(expected_data, out_data, 4, 16); } + +// An effect that multiplies with a constant. Used below. +class MultiplyEffect : public Effect { +public: + MultiplyEffect() { register_float("factor", &factor); } + virtual std::string effect_type_id() const { return "MultiplyEffect"; } + std::string output_fragment_shader() { return read_file("multiply.frag"); } + virtual AlphaHandling alpha_handling() const { return DONT_CARE_ALPHA_TYPE; } + +private: + float factor; +}; + +// An effect that adds its two inputs together. Used below. +class AddEffect : public Effect { +public: + AddEffect() {} + virtual std::string effect_type_id() const { return "AddEffect"; } + std::string output_fragment_shader() { return read_file("add.frag"); } + virtual unsigned num_inputs() const { return 2; } + virtual AlphaHandling alpha_handling() const { return DONT_CARE_ALPHA_TYPE; } +}; + +// Constructs the graph +// +// FlatInput | +// / \ | +// MultiplyEffect MultiplyEffect | +// \ / | +// AddEffect | +// +// and verifies that it gives the correct output. +TEST(EffectChainTest, DiamondGraph) { + float data[] = { + 1.0f, 1.0f, + 1.0f, 0.0f, + }; + float expected_data[] = { + 2.5f, 2.5f, + 2.5f, 0.0f, + }; + float out_data[2 * 2]; + + MultiplyEffect *mul_half = new MultiplyEffect(); + ASSERT_TRUE(mul_half->set_float("factor", 0.5f)); + + MultiplyEffect *mul_two = new MultiplyEffect(); + ASSERT_TRUE(mul_two->set_float("factor", 2.0f)); + + EffectChainTester tester(NULL, 2, 2); + + ImageFormat format; + format.color_space = COLORSPACE_sRGB; + format.gamma_curve = GAMMA_LINEAR; + + FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, 2, 2); + input->set_pixel_data(data); + + tester.get_chain()->add_input(input); + tester.get_chain()->add_effect(mul_half, input); + tester.get_chain()->add_effect(mul_two, input); + tester.get_chain()->add_effect(new AddEffect(), mul_half, mul_two); + tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR); + + expect_equal(expected_data, out_data, 2, 2); +} + +// Constructs the graph +// +// FlatInput | +// / \ | +// MultiplyEffect MultiplyEffect | +// \ | | +// \ BouncingIdentityEffect | +// \ / | +// AddEffect | +// +// and verifies that it gives the correct output. +TEST(EffectChainTest, DiamondGraphWithOneInputUsedInTwoPhases) { + float data[] = { + 1.0f, 1.0f, + 1.0f, 0.0f, + }; + float expected_data[] = { + 2.5f, 2.5f, + 2.5f, 0.0f, + }; + float out_data[2 * 2]; + + MultiplyEffect *mul_half = new MultiplyEffect(); + ASSERT_TRUE(mul_half->set_float("factor", 0.5f)); + + MultiplyEffect *mul_two = new MultiplyEffect(); + ASSERT_TRUE(mul_two->set_float("factor", 2.0f)); + + BouncingIdentityEffect *bounce = new BouncingIdentityEffect(); + + EffectChainTester tester(NULL, 2, 2); + + ImageFormat format; + format.color_space = COLORSPACE_sRGB; + format.gamma_curve = GAMMA_LINEAR; + + FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, 2, 2); + input->set_pixel_data(data); + + tester.get_chain()->add_input(input); + tester.get_chain()->add_effect(mul_half, input); + tester.get_chain()->add_effect(mul_two, input); + tester.get_chain()->add_effect(bounce, mul_two); + tester.get_chain()->add_effect(new AddEffect(), mul_half, bounce); + tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR); + + expect_equal(expected_data, out_data, 2, 2); +}