Support top-left origin for compute shaders.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 25 Nov 2017 10:26:54 +0000 (11:26 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Sat, 25 Nov 2017 10:26:58 +0000 (11:26 +0100)
effect_chain.cpp
effect_chain_test.cpp
footer.comp
header.comp
init.cpp

index a4d9c86..b821023 100644 (file)
@@ -555,20 +555,31 @@ void EffectChain::compile_glsl_program(Phase *phase)
                extract_uniform_declarations(effect->uniforms_mat3, "mat3", effect_id, &phase->uniforms_mat3, &frag_shader_uniforms);
        }
 
-       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);
+       // the origin, tell the vertex or compute shader so.
+       bool is_last_phase;
+       if (has_dummy_effect) {
+               is_last_phase = (phase->output_node->outgoing_links.size() == 1 &&
+                       phase->output_node->outgoing_links[0]->effect->effect_type_id() == "ComputeShaderOutputDisplayEffect");
+       } else {
+               is_last_phase = phase->output_node->outgoing_links.empty();
+       }
+       if (is_last_phase && output_origin == OUTPUT_ORIGIN_TOP_LEFT) {
+               if (phase->is_compute_shader) {
+                       frag_shader_header += "#define FLIP_ORIGIN 1\n";
+               } else {
+                       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';
+                       vert_shader[pos + needle.size() - 1] = '1';
+               }
        }
 
+       frag_shader = frag_shader_header + frag_shader_uniforms + frag_shader;
+
        if (phase->is_compute_shader) {
                phase->glsl_program_num = resource_pool->compile_glsl_compute_program(frag_shader);
 
index 324ddae..31e8a5d 100644 (file)
@@ -99,7 +99,22 @@ TEST(MirrorTest, BasicTest) {
        expect_equal(expected_data, out_data, 3, 2);
 }
 
-TEST(EffectChainTest, TopLeftOrigin) {
+class WithAndWithoutComputeShaderTest : public testing::TestWithParam<string> {
+};
+INSTANTIATE_TEST_CASE_P(WithAndWithoutComputeShaderTest,
+                        WithAndWithoutComputeShaderTest,
+                        testing::Values("fragment", "compute"));
+
+// An effect that does nothing, but as a compute shader.
+class IdentityComputeEffect : public Effect {
+public:
+       IdentityComputeEffect() {}
+       virtual string effect_type_id() const { return "IdentityComputeEffect"; }
+       virtual bool is_compute_shader() const { return true; }
+       string output_fragment_shader() { return read_file("identity.comp"); }
+};
+
+TEST_P(WithAndWithoutComputeShaderTest, TopLeftOrigin) {
        float data[] = {
                0.0f, 0.25f, 0.3f,
                0.75f, 1.0f, 1.0f,
@@ -113,6 +128,9 @@ TEST(EffectChainTest, TopLeftOrigin) {
        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);
+       if (GetParam() == "compute") {
+               tester.get_chain()->add_effect(new IdentityComputeEffect());
+       }
        tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
 
        expect_equal(expected_data, out_data, 3, 2);
@@ -1113,21 +1131,6 @@ public:
        bool sets_virtual_output_size() const override { return false; }
 };
 
-class WithAndWithoutComputeShaderTest : public testing::TestWithParam<string> {
-};
-INSTANTIATE_TEST_CASE_P(WithAndWithoutComputeShaderTest,
-                        WithAndWithoutComputeShaderTest,
-                        testing::Values("fragment", "compute"));
-
-// An effect that does nothing, but as a compute shader.
-class IdentityComputeEffect : public Effect {
-public:
-       IdentityComputeEffect() {}
-       virtual string effect_type_id() const { return "IdentityComputeEffect"; }
-       virtual bool is_compute_shader() const { return true; }
-       string output_fragment_shader() { return read_file("identity.comp"); }
-};
-
 // An effect that promises one-to-one sampling (unlike IdentityEffect).
 class OneToOneEffect : public Effect {
 public:
index a28014d..c4d1305 100644 (file)
@@ -5,6 +5,10 @@
 #define SQUARE_ROOT_TRANSFORMATION 0
 #endif
 
+#ifndef FLIP_ORIGIN
+#define FLIP_ORIGIN 0
+#endif
+
 void main()
 {
        INPUT();
@@ -30,5 +34,10 @@ void cs_output(ivec2 coord, vec4 val)
        // Make sure we don't give negative values to sqrt.
        val.rgb = sqrt(max(val.rgb, 0.0));
 #endif
+
+#if FLIP_ORIGIN
+       coord.y = imageSize(outbuf).y - coord.y - 1;
+#endif
+
        imageStore(outbuf, coord, val);
 }
index 3c07007..dc2fd08 100644 (file)
@@ -1,6 +1,7 @@
 #version 150
 #extension GL_ARB_compute_shader : enable
 #extension GL_ARB_shader_image_load_store : enable
+#extension GL_ARB_shader_image_size : enable
 
 // FIXME this needs to be auto-output or something
 uniform restrict writeonly image2D outbuf;
index ce2ce50..5e6c642 100644 (file)
--- a/init.cpp
+++ b/init.cpp
@@ -318,7 +318,8 @@ bool check_extensions()
                (epoxy_is_desktop_gl() &&
                 (epoxy_gl_version() >= 43 ||
                  (epoxy_has_gl_extension("GL_ARB_compute_shader") &&
-                  epoxy_has_gl_extension("GL_ARB_shader_image_load_store"))));
+                  epoxy_has_gl_extension("GL_ARB_shader_image_load_store") &&
+                  epoxy_has_gl_extension("GL_ARB_shader_image_size"))));
 
        return true;
 }