From: Steinar H. Gunderson Date: Mon, 10 Mar 2014 00:28:46 +0000 (+0100) Subject: Merge branch 'master' into epoxy X-Git-Tag: 1.1~12^2~39 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=8c7e53028a3ef4805d2608643041a5d7e6bd1b6e;hp=-c;p=movit Merge branch 'master' into epoxy --- 8c7e53028a3ef4805d2608643041a5d7e6bd1b6e diff --combined Makefile.in index 7d4a645,db9628d..660bf7a --- a/Makefile.in +++ b/Makefile.in @@@ -8,16 -8,12 +8,16 @@@ datarootdir = @datarootdir datadir = @datadir@ top_builddir = @top_builddir@ with_demo_app = @with_demo_app@ +with_SDL2 = @with_SDL2@ CC=@CC@ CXX=@CXX@ -CXXFLAGS=-Wall @CXXFLAGS@ -I$(GTEST_DIR)/include @Eigen3_CFLAGS@ @GLEW_CFLAGS@ -LDFLAGS=@GLEW_LIBS@ @SDL_LIBS@ -lpthread -DEMO_LDLIBS=@SDL_image_LIBS@ -lrt -lpthread @libpng_LIBS@ +CXXFLAGS=-Wall @CXXFLAGS@ -I$(GTEST_DIR)/include @SDL2_CFLAGS@ @SDL_CFLAGS@ @Eigen3_CFLAGS@ @epoxy_CFLAGS@ +ifeq ($(with_SDL2),yes) +CXXFLAGS += -DHAVE_SDL2 +endif +LDFLAGS=@epoxy_LIBS@ @SDL2_LIBS@ @SDL_LIBS@ -lpthread +DEMO_LDLIBS=@SDL2_image_LIBS@ @SDL_image_LIBS@ -lrt -lpthread @libpng_LIBS@ SHELL=@SHELL@ LIBTOOL=@LIBTOOL@ --tag=CXX RANLIB=ranlib @@@ -59,6 -55,7 +59,7 @@@ TESTED_EFFECTS += dither_effec TESTED_EFFECTS += deconvolution_sharpen_effect TESTED_EFFECTS += fft_pass_effect TESTED_EFFECTS += vignette_effect + TESTED_EFFECTS += slice_effect UNTESTED_EFFECTS = sandbox_effect UNTESTED_EFFECTS += mirror_effect diff --combined flat_input.cpp index 46799e5,b8ea706..6036cf7 --- a/flat_input.cpp +++ b/flat_input.cpp @@@ -1,6 -1,6 +1,6 @@@ #include #include -#include +#include #include "effect_util.h" #include "flat_input.h" @@@ -24,7 -24,7 +24,7 @@@ FlatInput::FlatInput(ImageFormat image_ pitch(width), pixel_data(NULL) { - assert(type == GL_FLOAT || type == GL_UNSIGNED_BYTE); + assert(type == GL_FLOAT || type == GL_HALF_FLOAT || type == GL_UNSIGNED_BYTE); register_int("output_linear_gamma", &output_linear_gamma); register_int("needs_mipmaps", &needs_mipmaps); } @@@ -46,7 -46,17 +46,17 @@@ void FlatInput::set_gl_state(GLuint gls GLint internal_format; GLenum format; if (type == GL_FLOAT) { - internal_format = GL_RGBA32F_ARB; + if (pixel_format == FORMAT_RG) { + internal_format = GL_RG32F; + } else { + internal_format = GL_RGBA32F; + } + } else if (type == GL_HALF_FLOAT) { + if (pixel_format == FORMAT_RG) { + internal_format = GL_RG16F; + } else { + internal_format = GL_RGBA16F; + } } else if (output_linear_gamma) { assert(type == GL_UNSIGNED_BYTE); internal_format = GL_SRGB8_ALPHA8; @@@ -66,6 -76,8 +76,8 @@@ format = GL_BGRA; } else if (pixel_format == FORMAT_GRAYSCALE) { format = GL_LUMINANCE; + } else if (pixel_format == FORMAT_RG) { + format = GL_RG; } else { assert(false); } diff --combined flat_input.h index c11d0a0,12a94d9..caa68b7 --- a/flat_input.h +++ b/flat_input.h @@@ -1,12 -1,13 +1,13 @@@ #ifndef _MOVIT_FLAT_INPUT_H #define _MOVIT_FLAT_INPUT_H 1 -#include +#include #include #include #include "effect.h" #include "effect_chain.h" + #include "fp16.h" #include "image_format.h" #include "init.h" #include "input.h" @@@ -38,6 -39,7 +39,7 @@@ public case FORMAT_RGBA_POSTMULTIPLIED_ALPHA: case FORMAT_BGRA_POSTMULTIPLIED_ALPHA: return OUTPUT_POSTMULTIPLIED_ALPHA; + case FORMAT_RG: case FORMAT_RGB: case FORMAT_BGR: case FORMAT_GRAYSCALE: @@@ -75,6 -77,14 +77,14 @@@ invalidate_pixel_data(); } + void set_pixel_data(const fp16_int_t *pixel_data, GLuint pbo = 0) + { + assert(this->type == GL_HALF_FLOAT); + this->pixel_data = pixel_data; + this->pbo = pbo; + invalidate_pixel_data(); + } + void set_pixel_data(const float *pixel_data, GLuint pbo = 0) { assert(this->type == GL_FLOAT); diff --combined slice_effect.cpp index 0000000,09b91b9..3cdd415 mode 000000,100644..100644 --- a/slice_effect.cpp +++ b/slice_effect.cpp @@@ -1,0 -1,76 +1,76 @@@ -#include ++#include + + #include "slice_effect.h" + #include "effect_util.h" + #include "util.h" + + using namespace std; + + namespace movit { + + SliceEffect::SliceEffect() + { + register_int("input_slice_size", &input_slice_size); + register_int("output_slice_size", &output_slice_size); + register_int("direction", (int *)&direction); + } + + string SliceEffect::output_fragment_shader() + { + char buf[256]; + sprintf(buf, "#define DIRECTION_VERTICAL %d\n", (direction == VERTICAL)); + return buf + read_file("slice_effect.frag"); + } + + void SliceEffect::inform_input_size(unsigned input_num, unsigned width, unsigned height) + { + assert(input_num == 0); + input_width = width; + input_height = height; + } + + void SliceEffect::get_output_size(unsigned *width, unsigned *height, + unsigned *virtual_width, unsigned *virtual_height) const + { + if (direction == HORIZONTAL) { + *width = div_round_up(input_width, input_slice_size) * output_slice_size; + *height = input_height; + } else { + *width = input_width; + *height = div_round_up(input_height, input_slice_size) * output_slice_size; + } + *virtual_width = *width; + *virtual_height = *height; + } + + void SliceEffect::set_gl_state(GLuint glsl_program_num, const string &prefix, unsigned *sampler_num) + { + Effect::set_gl_state(glsl_program_num, prefix, sampler_num); + + unsigned output_width, output_height; + get_output_size(&output_width, &output_height, &output_width, &output_height); + + if (direction == HORIZONTAL) { + set_uniform_float(glsl_program_num, prefix, "output_coord_to_slice_num", float(output_width) / float(output_slice_size)); + set_uniform_float(glsl_program_num, prefix, "slice_num_to_input_coord", float(input_slice_size) / float(input_width)); + set_uniform_float(glsl_program_num, prefix, "slice_offset_to_input_coord", float(output_slice_size) / float(input_width)); + } else { + set_uniform_float(glsl_program_num, prefix, "output_coord_to_slice_num", float(output_height) / float(output_slice_size)); + set_uniform_float(glsl_program_num, prefix, "slice_num_to_input_coord", float(input_slice_size) / float(input_height)); + set_uniform_float(glsl_program_num, prefix, "slice_offset_to_input_coord", float(output_slice_size) / float(input_height)); + } + + // Normalized coordinates could potentially cause blurring of the + // image; it's not critical, but we have set changes_output_size() + // and needs_texture_bounce(), so simply turning off the interpolation + // is allowed. + assert(*sampler_num == 1); + glActiveTexture(GL_TEXTURE0); + check_error(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + check_error(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + check_error(); + } + + } // namespace movit diff --combined slice_effect.h index 0000000,6380c16..3448941 mode 000000,100644..100644 --- a/slice_effect.h +++ b/slice_effect.h @@@ -1,0 -1,43 +1,43 @@@ + #ifndef _MOVIT_SLICE_EFFECT_H + #define _MOVIT_SLICE_EFFECT_H 1 + + // SliceEffect takes an image, cuts it into (potentially overlapping) slices, + // and puts those slices back together again consecutively. It is primarily + // useful in an overlap-discard setting, where it can do both the overlap and + // discard roles, where one does convolutions by means of many small FFTs, but + // could also work as a (relatively boring) video effect on its own. + // + // Note that vertical slices happen from the bottom, not the top, due to the + // OpenGL coordinate system. + -#include ++#include + #include + + #include "effect.h" + + namespace movit { + + class SliceEffect : public Effect { + public: + SliceEffect(); + virtual std::string effect_type_id() const { return "SliceEffect"; } + std::string output_fragment_shader(); + virtual bool needs_texture_bounce() const { return true; } + virtual bool changes_output_size() const { return true; } + virtual void inform_input_size(unsigned input_num, unsigned width, unsigned height); + virtual void get_output_size(unsigned *width, unsigned *height, + unsigned *virtual_width, unsigned *virtual_height) const; + + void set_gl_state(GLuint glsl_program_num, const std::string &prefix, unsigned *sampler_num); + + enum Direction { HORIZONTAL = 0, VERTICAL = 1 }; + + private: + int input_width, input_height; + int input_slice_size, output_slice_size; + Direction direction; + }; + + } // namespace movit + + #endif // !defined(_MOVIT_SLICE_EFFECT_H) diff --combined slice_effect_test.cpp index 0000000,efa6803..410439a mode 000000,100644..100644 --- a/slice_effect_test.cpp +++ b/slice_effect_test.cpp @@@ -1,0 -1,117 +1,117 @@@ + // Unit tests for SliceEffect. + -#include ++#include + + #include "effect_chain.h" + #include "flat_input.h" + #include "gtest/gtest.h" + #include "image_format.h" + #include "input.h" + #include "slice_effect.h" + #include "test_util.h" + + namespace movit { + + TEST(SliceEffectTest, Identity) { + const int size = 3, output_size = 4; + float data[size * size] = { + 0.0f, 0.1f, 0.2f, + 0.4f, 0.3f, 0.8f, + 0.5f, 0.2f, 0.1f, + }; + float expected_data[output_size * size] = { + 0.0f, 0.1f, 0.2f, 0.2f, + 0.4f, 0.3f, 0.8f, 0.8f, + 0.5f, 0.2f, 0.1f, 0.1f, + }; + float out_data[output_size * size]; + + EffectChainTester tester(NULL, output_size, size, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR); + tester.add_input(data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, size, size); + + Effect *slice_effect = tester.get_chain()->add_effect(new SliceEffect()); + ASSERT_TRUE(slice_effect->set_int("input_slice_size", 2)); + ASSERT_TRUE(slice_effect->set_int("output_slice_size", 2)); + ASSERT_TRUE(slice_effect->set_int("direction", SliceEffect::HORIZONTAL)); + tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR); + + expect_equal(expected_data, out_data, output_size, size); + } + + TEST(SliceEffectTest, HorizontalOverlap) { + float data[5 * 2] = { + 0.0f, 0.1f, 0.2f, 0.3f, 0.4f, + 0.4f, 0.3f, 0.2f, 0.1f, 0.0f, + }; + float expected_data[9 * 2] = { + 0.0f, 0.1f, 0.2f, 0.2f, 0.3f, 0.4f, 0.4f, 0.4f, 0.4f, + 0.4f, 0.3f, 0.2f, 0.2f, 0.1f, 0.0f, 0.0f, 0.0f, 0.0f, + }; + float out_data[9 * 2]; + + EffectChainTester tester(NULL, 9, 2, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR); + tester.add_input(data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, 5, 2); + + Effect *slice_effect = tester.get_chain()->add_effect(new SliceEffect()); + ASSERT_TRUE(slice_effect->set_int("input_slice_size", 2)); + ASSERT_TRUE(slice_effect->set_int("output_slice_size", 3)); + ASSERT_TRUE(slice_effect->set_int("direction", SliceEffect::HORIZONTAL)); + tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR); + + expect_equal(expected_data, out_data, 9, 2); + } + + TEST(SliceEffectTest, HorizontalDiscard) { + float data[6 * 2] = { + 0.0f, 0.1f, 0.2f, 0.2f, 0.3f, 0.4f, + 0.4f, 0.3f, 0.2f, 0.2f, 0.1f, 0.0f, + }; + float expected_data[4 * 2] = { + 0.0f, 0.1f, 0.2f, 0.3f, + 0.4f, 0.3f, 0.2f, 0.1f, + }; + float out_data[4 * 2]; + + EffectChainTester tester(NULL, 4, 2, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR); + tester.add_input(data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, 6, 2); + + Effect *slice_effect = tester.get_chain()->add_effect(new SliceEffect()); + ASSERT_TRUE(slice_effect->set_int("input_slice_size", 3)); + ASSERT_TRUE(slice_effect->set_int("output_slice_size", 2)); + ASSERT_TRUE(slice_effect->set_int("direction", SliceEffect::HORIZONTAL)); + tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR); + + expect_equal(expected_data, out_data, 4, 2); + } + + TEST(SliceEffectTest, VerticalOverlapSlicesFromBottom) { + float data[2 * 3] = { + 0.0f, 0.1f, + + 0.4f, 0.3f, + 0.6f, 0.2f, + }; + float expected_data[2 * 6] = { + 0.0f, 0.1f, + 0.0f, 0.1f, + 0.0f, 0.1f, + + 0.0f, 0.1f, + 0.4f, 0.3f, + 0.6f, 0.2f, + }; + float out_data[2 * 6]; + + EffectChainTester tester(NULL, 2, 6, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR); + tester.add_input(data, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, 2, 3); + + Effect *slice_effect = tester.get_chain()->add_effect(new SliceEffect()); + ASSERT_TRUE(slice_effect->set_int("input_slice_size", 2)); + ASSERT_TRUE(slice_effect->set_int("output_slice_size", 3)); + ASSERT_TRUE(slice_effect->set_int("direction", SliceEffect::VERTICAL)); + tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR); + + expect_equal(expected_data, out_data, 2, 6); + } + + } // namespace movit diff --combined test_util.cpp index ea3a011,cb97236..ec9cbf9 --- a/test_util.cpp +++ b/test_util.cpp @@@ -2,11 -2,11 +2,11 @@@ #include #include #include +#include +#include +#include #include "flat_input.h" -#include "glew.h" -#include "gtest/gtest.h" -#include "gtest/gtest-message.h" #include "init.h" #include "resource_pool.h" #include "test_util.h" @@@ -85,25 -85,39 +85,39 @@@ EffectChainTester::~EffectChainTester( check_error(); } - Input *EffectChainTester::add_input(const float *data, MovitPixelFormat pixel_format, Colorspace color_space, GammaCurve gamma_curve) + Input *EffectChainTester::add_input(const float *data, MovitPixelFormat pixel_format, Colorspace color_space, GammaCurve gamma_curve, int input_width, int input_height) { ImageFormat format; format.color_space = color_space; format.gamma_curve = gamma_curve; - FlatInput *input = new FlatInput(format, pixel_format, GL_FLOAT, width, height); + if (input_width == -1) { + input_width = width; + } + if (input_height == -1) { + input_height = height; + } + + FlatInput *input = new FlatInput(format, pixel_format, GL_FLOAT, input_width, input_height); input->set_pixel_data(data); chain.add_input(input); return input; } - Input *EffectChainTester::add_input(const unsigned char *data, MovitPixelFormat pixel_format, Colorspace color_space, GammaCurve gamma_curve) + Input *EffectChainTester::add_input(const unsigned char *data, MovitPixelFormat pixel_format, Colorspace color_space, GammaCurve gamma_curve, int input_width, int input_height) { ImageFormat format; format.color_space = color_space; format.gamma_curve = gamma_curve; - FlatInput *input = new FlatInput(format, pixel_format, GL_UNSIGNED_BYTE, width, height); + if (input_width == -1) { + input_width = width; + } + if (input_height == -1) { + input_height = height; + } + + FlatInput *input = new FlatInput(format, pixel_format, GL_UNSIGNED_BYTE, input_width, input_height); input->set_pixel_data(data); chain.add_input(input); return input; diff --combined test_util.h index b44d326,ff568ba..e5e6551 --- a/test_util.h +++ b/test_util.h @@@ -1,7 -1,7 +1,7 @@@ #ifndef _MOVIT_TEST_UTIL_H #define _MOVIT_TEST_UTIL_H 1 -#include +#include #include "effect_chain.h" #include "image_format.h" @@@ -19,8 -19,8 +19,8 @@@ public ~EffectChainTester(); EffectChain *get_chain() { return &chain; } - Input *add_input(const float *data, MovitPixelFormat pixel_format, Colorspace color_space, GammaCurve gamma_curve); - Input *add_input(const unsigned char *data, MovitPixelFormat pixel_format, Colorspace color_space, GammaCurve gamma_curve); + Input *add_input(const float *data, MovitPixelFormat pixel_format, Colorspace color_space, GammaCurve gamma_curve, int input_width = -1, int input_height = -1); + Input *add_input(const unsigned char *data, MovitPixelFormat pixel_format, Colorspace color_space, GammaCurve gamma_curve, int input_width = -1, int input_height = -1); void run(float *out_data, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format = OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED); void run(unsigned char *out_data, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format = OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED); diff --combined util.cpp index cd820bc,8162f71..372064b --- a/util.cpp +++ b/util.cpp @@@ -1,4 -1,4 +1,4 @@@ -#include +#include #include #include #include @@@ -215,4 -215,9 +215,9 @@@ void cleanup_vertex_attribute(GLuint gl check_error(); } + unsigned div_round_up(unsigned a, unsigned b) + { + return (a + b - 1) / b; + } + } // namespace movit diff --combined util.h index 7784102,c59231d..5c15c9f --- a/util.h +++ b/util.h @@@ -3,7 -3,7 +3,7 @@@ // Various utilities. -#include +#include #include #include #include @@@ -34,6 -34,9 +34,9 @@@ void print_3x3_matrix(const Eigen::Matr // Output a GLSL 3x3 matrix declaration. std::string output_glsl_mat3(const std::string &name, const Eigen::Matrix3d &m); + // Calculate a / b, rounding up. Does not handle overflow correctly. + unsigned div_round_up(unsigned a, unsigned b); + // Calculate where to sample, and with what weight, if one wants to use // the GPU's bilinear hardware to sample w1 * x[0] + w2 * x[1]. //