[Mesa-dev] [PATCH 2/3] glsl: Link error if fs defines conflicting qualifiers for gl_FragCoord

Anuj Phogat anuj.phogat at gmail.com
Mon Feb 10 17:29:57 PST 2014


GLSL 1.50 spec says:
   "If gl_FragCoord is redeclared in any fragment shader in a program,
    it must be redeclared in all the fragment shaders in that
    program that have a static use gl_FragCoord. All redeclarations of
    gl_FragCoord in all fragment shaders in a single program must
    have the same set of qualifiers."

This patch causes the shader link to fail if we have multiple fragment
shaders with conflicting layout qualifiers for gl_FragCoord. For example:

fragment shader 1:
layout(origin_upper_left, pixel_center_integer) in vec4 gl_FragCoord;

void foo();
void main()
{
   gl_FragColor = vec4(gl_FragCoord.xyz, 1.0);
   foo();
}

fragment shader 2:
layout(origin_upper_left) in vec4 gl_FragCoord;
void foo()
{
   gl_FragColor.a = gl_FragCoord.z;
}

Cc: <mesa-stable at lists.freedesktop.org>
Signed-off-by: Anuj Phogat <anuj.phogat at gmail.com>
---
 src/glsl/ast_to_hir.cpp         |  5 ++++
 src/glsl/glsl_parser_extras.cpp | 14 +++++++++
 src/glsl/glsl_parser_extras.h   |  1 +
 src/glsl/linker.cpp             | 63 +++++++++++++++++++++++++++++++++++++++++
 src/mesa/main/mtypes.h          |  7 +++++
 5 files changed, 90 insertions(+)

diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp
index 7d7d89b..3b2e05a 100644
--- a/src/glsl/ast_to_hir.cpp
+++ b/src/glsl/ast_to_hir.cpp
@@ -120,6 +120,11 @@ _mesa_ast_to_hir(exec_list *instructions, struct _mesa_glsl_parse_state *state)
       instructions->push_head(var);
    }
 
+   /* Figure out if gl_FragCoord is actually used in fragment shader */
+   ir_variable *const var = state->symbols->get_variable("gl_FragCoord");
+   if (var != NULL)
+      state->uses_gl_fragcoord = var->data.used;
+
    /* From section 7.1 (Built-In Language Variables) of the GLSL 4.10 spec:
     *
     *     If multiple shaders using members of a built-in block belonging to
diff --git a/src/glsl/glsl_parser_extras.cpp b/src/glsl/glsl_parser_extras.cpp
index b06337e..07fd1c7 100644
--- a/src/glsl/glsl_parser_extras.cpp
+++ b/src/glsl/glsl_parser_extras.cpp
@@ -193,6 +193,7 @@ _mesa_glsl_parse_state::_mesa_glsl_parse_state(struct gl_context *_ctx,
    this->default_uniform_qualifier->flags.q.shared = 1;
    this->default_uniform_qualifier->flags.q.column_major = 1;
 
+   this->uses_gl_fragcoord = false;
    this->fs_origin_upper_left = false;
    this->fs_pixel_center_integer = false;
 
@@ -1350,6 +1351,13 @@ set_shader_inout_layout(struct gl_shader *shader,
       assert(!state->cs_input_local_size_specified);
    }
 
+   if (shader->Stage != MESA_SHADER_FRAGMENT) {
+      /* Should have been prevented by the parser. */
+      assert(!state->uses_gl_fragcoord);
+      assert(!state->fs_pixel_center_integer);
+      assert(!state->fs_origin_upper_left);
+   }
+
    switch (shader->Stage) {
    case MESA_SHADER_GEOMETRY:
       shader->Geom.VerticesOut = 0;
@@ -1379,6 +1387,12 @@ set_shader_inout_layout(struct gl_shader *shader,
       }
       break;
 
+   case MESA_SHADER_FRAGMENT:
+      shader->uses_gl_fragcoord = state->uses_gl_fragcoord;
+      shader->pixel_center_integer = state->fs_pixel_center_integer;
+      shader->origin_upper_left = state->fs_origin_upper_left;
+      break;
+
    default:
       /* Nothing to do. */
       break;
diff --git a/src/glsl/glsl_parser_extras.h b/src/glsl/glsl_parser_extras.h
index 674dae5..eddcf77 100644
--- a/src/glsl/glsl_parser_extras.h
+++ b/src/glsl/glsl_parser_extras.h
@@ -393,6 +393,7 @@ struct _mesa_glsl_parse_state {
    const struct gl_extensions *extensions;
 
    bool uses_builtin_functions;
+   bool uses_gl_fragcoord;
 
    /**
     * For geometry shaders, size of the most recently seen input declaration
diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp
index bcd7394..f8564ca 100644
--- a/src/glsl/linker.cpp
+++ b/src/glsl/linker.cpp
@@ -1194,6 +1194,68 @@ private:
    hash_table *unnamed_interfaces;
 };
 
+static bool
+fs_uses_conflicting_layout_qualifiers(struct gl_shader *shader,
+                                      struct gl_shader *linked_shader)
+{
+   bool qual_absent_in_shader_but_present_in_linked_shader =
+      (!shader->origin_upper_left && linked_shader->origin_upper_left) ||
+      (!shader->pixel_center_integer && linked_shader->pixel_center_integer);
+
+   bool qual_present_in_shader_but_absent_in_linked_shader =
+      (shader->origin_upper_left && !linked_shader->origin_upper_left) ||
+      (shader->pixel_center_integer && !linked_shader->pixel_center_integer);
+
+   if ((qual_absent_in_shader_but_present_in_linked_shader &&
+        shader->uses_gl_fragcoord) ||
+       (qual_present_in_shader_but_absent_in_linked_shader &&
+        linked_shader->uses_gl_fragcoord))
+      return true;
+
+   return false;
+}
+
+/**
+ * Performs the cross-validation of layout qualifiers specified in
+ * redeclaration of gl_FragCoord for the attached fragment shaders,
+ * and propagates them to the linked FS and linked shader program.
+ */
+static void
+link_fs_input_layout_qualifiers(struct gl_shader_program *prog,
+	                        struct gl_shader *linked_shader,
+	                        struct gl_shader **shader_list,
+	                        unsigned num_shaders)
+{
+   linked_shader->uses_gl_fragcoord = false;
+   linked_shader->origin_upper_left = false;
+   linked_shader->pixel_center_integer = false;
+
+   if (linked_shader->Stage != MESA_SHADER_FRAGMENT || prog->Version < 150)
+      return;
+
+   /* From the GLSL 1.50 spec, page 39:
+    *    "If gl_FragCoord is redeclared in any fragment shader in a program,
+    *     it must be redeclared in all the fragment shaders in that program
+    *     that have a static use gl_FragCoord. All redeclarations of
+    *     gl_FragCoord in all fragment shaders in a single program must have
+    *     the same set of qualifiers."
+    */
+
+   for (unsigned i = 0; i < num_shaders; i++) {
+      struct gl_shader *shader = shader_list[i];
+
+      if (fs_uses_conflicting_layout_qualifiers(shader, linked_shader)) {
+         linker_error(prog, "fragment shader defined with conflicting "
+                      "layout qualifier for gl_FragCoord\n");
+         return;
+      } else if (shader->uses_gl_fragcoord) {
+         linked_shader->uses_gl_fragcoord = shader->uses_gl_fragcoord;
+         linked_shader->origin_upper_left = shader->origin_upper_left;
+         linked_shader->pixel_center_integer = shader->pixel_center_integer;
+      }
+   }
+}
+
 /**
  * Performs the cross-validation of geometry shader max_vertices and
  * primitive type layout qualifiers for the attached geometry shaders,
@@ -1453,6 +1515,7 @@ link_intrastage_shaders(void *mem_ctx,
    linked->NumUniformBlocks = num_uniform_blocks;
    ralloc_steal(linked, linked->UniformBlocks);
 
+   link_fs_input_layout_qualifiers(prog, linked, shader_list, num_shaders);
    link_gs_inout_layout_qualifiers(prog, linked, shader_list, num_shaders);
    link_cs_input_layout_qualifiers(prog, linked, shader_list, num_shaders);
 
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 205b2f2..bbb6231 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -2412,6 +2412,13 @@ struct gl_shader
    struct glsl_symbol_table *symbols;
 
    bool uses_builtin_functions;
+   bool uses_gl_fragcoord;
+
+   /**
+    * Fragment shader state from GLSL 1.50 layout qualifiers.
+    */
+   bool origin_upper_left;
+   bool pixel_center_integer;
 
    /**
     * Geometry shader state from GLSL 1.50 layout qualifiers.
-- 
1.8.3.1



More information about the mesa-dev mailing list