//
// Note that this also contains the tests for some of the simpler effects.
-#include <GL/glew.h>
+#include <epoxy/gl.h>
#include <assert.h>
#include "effect.h"
#include "effect_chain.h"
#include "flat_input.h"
#include "gtest/gtest.h"
+#include "init.h"
#include "input.h"
#include "mirror_effect.h"
#include "multiply_effect.h"
#include "test_util.h"
#include "util.h"
+using namespace std;
+
+namespace movit {
+
TEST(EffectChainTest, EmptyChain) {
float data[] = {
0.0f, 0.25f, 0.3f,
class IdentityEffect : public Effect {
public:
IdentityEffect() {}
- virtual std::string effect_type_id() const { return "IdentityEffect"; }
- std::string output_fragment_shader() { return read_file("identity.frag"); }
+ virtual string effect_type_id() const { return "IdentityEffect"; }
+ string output_fragment_shader() { return read_file("identity.frag"); }
};
TEST(EffectChainTest, Identity) {
class BouncingIdentityEffect : public Effect {
public:
BouncingIdentityEffect() {}
- virtual std::string effect_type_id() const { return "IdentityEffect"; }
- std::string output_fragment_shader() { return read_file("identity.frag"); }
+ virtual string effect_type_id() const { return "IdentityEffect"; }
+ 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; }
};
class InvertEffect : public Effect {
public:
InvertEffect() {}
- virtual std::string effect_type_id() const { return "InvertEffect"; }
- std::string output_fragment_shader() { return read_file("invert_effect.frag"); }
+ virtual string effect_type_id() const { return "InvertEffect"; }
+ string output_fragment_shader() { return read_file("invert_effect.frag"); }
// A real invert would actually care about its alpha,
// but in this unit test, it only complicates things.
class RewritingEffect : public Effect {
public:
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 string effect_type_id() const { return "RewritingEffect[" + effect->effect_type_id() + "]"; }
+ string output_fragment_shader() { EXPECT_TRUE(false); return read_file("identity.frag"); }
virtual void rewrite_graph(EffectChain *graph, Node *self) {
replaced_node = graph->add_node(effect);
graph->replace_receiver(self, replaced_node);
: FlatInput(format, pixel_format, type, width, height),
overridden_color_space(format.color_space),
overridden_gamma_curve(format.gamma_curve) {}
- virtual std::string effect_type_id() const { return "UnknownColorspaceInput"; }
+ virtual string effect_type_id() const { return "UnknownColorspaceInput"; }
void set_color_space(Colorspace colorspace) {
overridden_color_space = colorspace;
class BlueInput : public Input {
public:
BlueInput() { register_int("needs_mipmaps", &needs_mipmaps); }
- virtual std::string effect_type_id() const { return "IdentityEffect"; }
- std::string output_fragment_shader() { return read_file("blue.frag"); }
+ virtual string effect_type_id() const { return "IdentityEffect"; }
+ string output_fragment_shader() { return read_file("blue.frag"); }
virtual AlphaHandling alpha_handling() const { return OUTPUT_BLANK_ALPHA; }
virtual void finalize() {}
virtual bool can_output_linear_gamma() const { return true; }
class RewritingToBlueInput : public Input {
public:
RewritingToBlueInput() : blue_node(NULL) { register_int("needs_mipmaps", &needs_mipmaps); }
- virtual std::string effect_type_id() const { return "RewritingToBlueInput"; }
- std::string output_fragment_shader() { EXPECT_TRUE(false); return read_file("identity.frag"); }
+ virtual string effect_type_id() const { return "RewritingToBlueInput"; }
+ string output_fragment_shader() { EXPECT_TRUE(false); return read_file("identity.frag"); }
virtual void rewrite_graph(EffectChain *graph, Node *self) {
Node *blue_node = graph->add_node(new BlueInput());
graph->replace_receiver(self, blue_node);
class BlankAlphaPreservingEffect : public Effect {
public:
BlankAlphaPreservingEffect() {}
- virtual std::string effect_type_id() const { return "BlankAlphaPreservingEffect"; }
- std::string output_fragment_shader() { return read_file("identity.frag"); }
+ virtual string effect_type_id() const { return "BlankAlphaPreservingEffect"; }
+ string output_fragment_shader() { return read_file("identity.frag"); }
virtual AlphaHandling alpha_handling() const { return INPUT_PREMULTIPLIED_ALPHA_KEEP_BLANK; }
};
public:
MipmapNeedingEffect() {}
virtual bool needs_mipmaps() const { return true; }
- virtual std::string effect_type_id() const { return "MipmapNeedingEffect"; }
- std::string output_fragment_shader() { return read_file("mipmap_needing_effect.frag"); }
- void set_gl_state(GLuint glsl_program_num, const std::string& prefix, unsigned *sampler_num)
+ virtual string effect_type_id() const { return "MipmapNeedingEffect"; }
+ string output_fragment_shader() { return read_file("mipmap_needing_effect.frag"); }
+ void set_gl_state(GLuint glsl_program_num, const string& prefix, unsigned *sampler_num)
{
glActiveTexture(GL_TEXTURE0);
check_error();
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 string effect_type_id() const { return "AddEffect"; }
+ 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; }
};
input_width = width;
input_height = height;
}
- virtual std::string effect_type_id() const { return "SizeStoringEffect"; }
+ virtual string effect_type_id() const { return "SizeStoringEffect"; }
int input_width, input_height;
};
height(height),
virtual_width(virtual_width),
virtual_height(virtual_height) {}
- virtual std::string effect_type_id() const { return "VirtualResizeEffect"; }
- std::string output_fragment_shader() { return read_file("identity.frag"); }
+ virtual string effect_type_id() const { return "VirtualResizeEffect"; }
+ string output_fragment_shader() { return read_file("identity.frag"); }
virtual bool changes_output_size() const { return true; }
// since bilinear scaling from 2x2 → 3x3 → 2x2 is not very exact.
expect_equal(data, out_data, size, size);
}
+
+// Does not use EffectChainTest, so that it can construct an EffectChain without
+// a shared ResourcePool (which is also properly destroyed afterwards).
+// Also turns on debugging to test that code path.
+TEST(EffectChainTest, IdentityWithOwnPool) {
+ const int width = 3, height = 2;
+ float data[] = {
+ 0.0f, 0.25f, 0.3f,
+ 0.75f, 1.0f, 1.0f,
+ };
+ const float expected_data[] = {
+ 0.75f, 1.0f, 1.0f,
+ 0.0f, 0.25f, 0.3f,
+ };
+ float out_data[6];
+
+ EffectChain chain(width, height);
+ movit_debug_level = MOVIT_DEBUG_ON;
+
+ ImageFormat format;
+ format.color_space = COLORSPACE_sRGB;
+ format.gamma_curve = GAMMA_LINEAR;
+
+ FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, width, height);
+ input->set_pixel_data(data);
+ chain.add_input(input);
+ chain.add_output(format, OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
+
+ GLuint texnum, fbo;
+ glGenTextures(1, &texnum);
+ check_error();
+ glBindTexture(GL_TEXTURE_2D, texnum);
+ check_error();
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ check_error();
+
+ glGenFramebuffers(1, &fbo);
+ check_error();
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+ check_error();
+ glFramebufferTexture2D(
+ GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ texnum,
+ 0);
+ check_error();
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ check_error();
+
+ chain.finalize();
+
+ chain.render_to_fbo(fbo, width, height);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+ glReadPixels(0, 0, width, height, GL_RED, GL_FLOAT, out_data);
+
+ expect_equal(expected_data, out_data, width, height);
+
+ // Reset the debug status again.
+ movit_debug_level = MOVIT_DEBUG_OFF;
+}
+
+} // namespace movit