Add support for overriding the output origin.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Wed, 16 Sep 2015 22:39:43 +0000 (00:39 +0200)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Wed, 16 Sep 2015 22:39:43 +0000 (00:39 +0200)
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
effect_chain.h
effect_chain_test.cpp
version.h
vs.130.vert
vs.300es.vert
vs.vert

index 4c2df4c..8d030c2 100644 (file)
@@ -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.
index e07c2e9..2e89c3b 100644 (file)
@@ -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<Phase *> phases;
 
        unsigned num_dither_bits;
+       OutputOrigin output_origin;
        bool finalized;
 
        ResourcePool *resource_pool;
index 28ccc70..d79c933 100644 (file)
@@ -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:
index d1a773a..be23939 100644 (file)
--- 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)
index 7b4ebab..7d00f3c 100644 (file)
@@ -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
 }
index 542be89..c3a0a2b 100644 (file)
@@ -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 (file)
--- 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
 }