From 419bbfe5e46add3df115882dbf489ccfe080d2f9 Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Thu, 17 Sep 2015 00:39:43 +0200 Subject: [PATCH] Add support for overriding the output origin. For me, this was needed when I wanted to render directly into VA-API's encoder buffers, which are always top-left origin (and FBOs are always bottom-left origin). --- effect_chain.cpp | 12 ++++++++++++ effect_chain.h | 24 ++++++++++++++++++++++++ effect_chain_test.cpp | 19 +++++++++++++++++++ version.h | 2 +- vs.130.vert | 7 +++++++ vs.300es.vert | 7 +++++++ vs.vert | 7 +++++++ 7 files changed, 77 insertions(+), 1 deletion(-) diff --git a/effect_chain.cpp b/effect_chain.cpp index 4c2df4c..8d030c2 100644 --- a/effect_chain.cpp +++ b/effect_chain.cpp @@ -39,6 +39,7 @@ EffectChain::EffectChain(float aspect_nom, float aspect_denom, ResourcePool *res aspect_denom(aspect_denom), dither_effect(NULL), num_dither_bits(0), + output_origin(OUTPUT_ORIGIN_BOTTOM_LEFT), finalized(false), resource_pool(resource_pool), do_phase_timing(false) { @@ -407,6 +408,17 @@ void EffectChain::compile_glsl_program(Phase *phase) frag_shader = frag_shader_header + frag_shader_uniforms + frag_shader; string vert_shader = read_version_dependent_file("vs", "vert"); + + // If we're the last phase and need to flip the picture to compensate for + // the origin, tell the vertex shader so. + if (phase->output_node->outgoing_links.empty() && output_origin == OUTPUT_ORIGIN_TOP_LEFT) { + const string needle = "#define FLIP_ORIGIN 0"; + size_t pos = vert_shader.find(needle); + assert(pos != string::npos); + + vert_shader[pos + needle.size() - 1] = '1'; + } + phase->glsl_program_num = resource_pool->compile_glsl_program(vert_shader, frag_shader); // Collect the resulting location numbers for each uniform. diff --git a/effect_chain.h b/effect_chain.h index e07c2e9..2e89c3b 100644 --- a/effect_chain.h +++ b/effect_chain.h @@ -83,6 +83,21 @@ enum YCbCrOutputSplitting { YCBCR_OUTPUT_PLANAR, }; +// Where (0,0) is taken to be in the output. If you want to render to an +// OpenGL screen, you should keep the default of bottom-left, as that is +// OpenGL's natural coordinate system. However, there are cases, such as if you +// render to an FBO and read the pixels back into some other system, where +// you'd want a top-left origin; if so, an additional flip step will be added +// at the very end (but done in a vertex shader, so it will have zero extra +// cost). +// +// Note that Movit's coordinate system in general consistently puts (0,0) in +// the top left for _input_, no matter what you set as output origin. +enum OutputOrigin { + OUTPUT_ORIGIN_BOTTOM_LEFT, + OUTPUT_ORIGIN_TOP_LEFT, +}; + // A node in the graph; basically an effect and some associated information. class Node { public: @@ -225,6 +240,14 @@ public: this->num_dither_bits = num_bits; } + // Set where (0,0) is taken to be in the output. The default is + // OUTPUT_ORIGIN_BOTTOM_LEFT, which is usually what you want + // (see OutputOrigin above for more details). + void set_output_origin(OutputOrigin output_origin) + { + this->output_origin = output_origin; + } + void finalize(); // Measure the GPU time used for each actual phase during rendering. @@ -378,6 +401,7 @@ private: std::vector phases; unsigned num_dither_bits; + OutputOrigin output_origin; bool finalized; ResourcePool *resource_pool; diff --git a/effect_chain_test.cpp b/effect_chain_test.cpp index 28ccc70..d79c933 100644 --- a/effect_chain_test.cpp +++ b/effect_chain_test.cpp @@ -98,6 +98,25 @@ TEST(MirrorTest, BasicTest) { expect_equal(expected_data, out_data, 3, 2); } +TEST(EffectChainTest, TopLeftOrigin) { + float data[] = { + 0.0f, 0.25f, 0.3f, + 0.75f, 1.0f, 1.0f, + }; + // Note that EffectChainTester assumes bottom-left origin, so by setting + // top-left, we will get flipped data back. + float expected_data[6] = { + 0.75f, 1.0f, 1.0f, + 0.0f, 0.25f, 0.3f, + }; + float out_data[6]; + EffectChainTester tester(data, 3, 2, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR); + tester.get_chain()->set_output_origin(OUTPUT_ORIGIN_TOP_LEFT); + tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR); + + expect_equal(expected_data, out_data, 3, 2); +} + // A dummy effect that inverts its input. class InvertEffect : public Effect { public: diff --git a/version.h b/version.h index d1a773a..be23939 100644 --- a/version.h +++ b/version.h @@ -5,6 +5,6 @@ // changes, even within git versions. There is no specific version // documentation outside the regular changelogs, though. -#define MOVIT_VERSION 4 +#define MOVIT_VERSION 5 #endif // !defined(_MOVIT_VERSION_H) diff --git a/vs.130.vert b/vs.130.vert index 7b4ebab..7d00f3c 100644 --- a/vs.130.vert +++ b/vs.130.vert @@ -4,6 +4,10 @@ in vec2 position; in vec2 texcoord; out vec2 tc; +// Will be overridden by compile_glsl_program() if needed. +// (It cannot just be prepended, as #version must be before everything.) +#define FLIP_ORIGIN 0 + void main() { // The result of glOrtho(0.0, 1.0, 0.0, 1.0, 0.0, 1.0) is: @@ -14,4 +18,7 @@ void main() // 0.000 0.000 0.000 1.000 gl_Position = vec4(2.0 * position.x - 1.0, 2.0 * position.y - 1.0, -1.0, 1.0); tc = texcoord; +#if FLIP_ORIGIN + tc.y = 1.0f - tc.y; +#endif } diff --git a/vs.300es.vert b/vs.300es.vert index 542be89..c3a0a2b 100644 --- a/vs.300es.vert +++ b/vs.300es.vert @@ -6,6 +6,10 @@ in vec2 position; in vec2 texcoord; out vec2 tc; +// Will be overridden by compile_glsl_program() if needed. +// (It cannot just be prepended, as #version must be before everything.) +#define FLIP_ORIGIN 0 + void main() { // The result of glOrtho(0.0, 1.0, 0.0, 1.0, 0.0, 1.0) is: @@ -16,4 +20,7 @@ void main() // 0.000 0.000 0.000 1.000 gl_Position = vec4(2.0 * position.x - 1.0, 2.0 * position.y - 1.0, -1.0, 1.0); tc = texcoord; +#if FLIP_ORIGIN + tc.y = 1.0f - tc.y; +#endif } diff --git a/vs.vert b/vs.vert index 0ba2fdc..dac2df9 100644 --- a/vs.vert +++ b/vs.vert @@ -2,6 +2,10 @@ attribute vec2 position; attribute vec2 texcoord; varying vec2 tc; +// Will be overridden by compile_glsl_program() if needed. +// (It cannot just be prepended, as #version must be before everything.) +#define FLIP_ORIGIN 0 + void main() { // The result of glOrtho(0.0, 1.0, 0.0, 1.0, 0.0, 1.0) is: @@ -12,4 +16,7 @@ void main() // 0.000 0.000 0.000 1.000 gl_Position = vec4(2.0 * position.x - 1.0, 2.0 * position.y - 1.0, -1.0, 1.0); tc = texcoord; +#if FLIP_ORIGIN + tc.y = 1.0f - tc.y; +#endif } -- 2.39.2