On 02/24/2014 05:34 PM, Anuj Phogat wrote:
> 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;
> }
> 
> Signed-off-by: Anuj Phogat <anuj.pho...@gmail.com>
> Cc: <mesa-sta...@lists.freedesktop.org>
> ---
>   src/glsl/ast_to_hir.cpp         |  5 ++++
>   src/glsl/glsl_parser_extras.cpp | 16 +++++++++++
>   src/glsl/glsl_parser_extras.h   |  1 +
>   src/glsl/linker.cpp             | 60 
> +++++++++++++++++++++++++++++++++++++++++
>   src/mesa/main/mtypes.h          |  8 ++++++
>   5 files changed, 90 insertions(+)
> 
> diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp
> index f5dacfd..b639f98 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->fs_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 fcbbf44..f953713 100644
> --- a/src/glsl/glsl_parser_extras.cpp
> +++ b/src/glsl/glsl_parser_extras.cpp
> @@ -201,6 +201,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->fs_uses_gl_fragcoord = false;
>      this->fs_redeclares_gl_fragcoord = false;
>      this->fs_origin_upper_left = false;
>      this->fs_pixel_center_integer = false;
> @@ -1363,6 +1364,14 @@ 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->fs_uses_gl_fragcoord);
> +      assert(!state->fs_redeclares_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;
> @@ -1396,6 +1405,13 @@ set_shader_inout_layout(struct gl_shader *shader,
>         }
>         break;
>   
> +   case MESA_SHADER_FRAGMENT:
> +      shader->redeclares_gl_fragcoord = state->fs_redeclares_gl_fragcoord;
> +      shader->uses_gl_fragcoord = state->fs_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 2017913..511ca48 100644
> --- a/src/glsl/glsl_parser_extras.h
> +++ b/src/glsl/glsl_parser_extras.h
> @@ -427,6 +427,7 @@ struct _mesa_glsl_parse_state {
>      const struct gl_extensions *extensions;
>   
>      bool uses_builtin_functions;
> +   bool fs_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 f6b2661..1268aef 100644
> --- a/src/glsl/linker.cpp
> +++ b/src/glsl/linker.cpp
> @@ -1194,6 +1194,65 @@ 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);
> +
> +   return ((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));

I don't think this logic catches the redefined-but-not-used cases.

layout(origin_upper_left) in vec4 gl_FragCoord;
void main()
{
    foo();
    gl_FragColor = gl_FragData;
}

---

layout(pixel_center_integer) in vec4 gl_FragCoord;
void foo()
{
}

I think in the loop in link_fs_input_layout_qualifiers you want:

   /* 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.
    */
   if ((linked_shader->redeclares_gl_fragcoord
        && !shader->redeclares_gl_fragcoord
        && shader->uses_gl_fragcoord)
       || (shader->redeclares_gl_fragcoord
           && !linked_shader->redeclares_gl_fragcoord
           && linked_shader->uses_gl_fragcoord)) {
      // error
   }

   /* From the GLSL 1.50 spec, page 39:
    *
    *     "All redeclarations of gl_FragCoord in all fragment shaders in a
    *     single program must have the same set of qualifiers."
    */
   if (linked_shader->redeclares_gl_fragcoord && shader->redeclares_gl_fragcoord
       && (shader->origin_upper_left != linked_shader->origin_upper_left
           || shader->pixel_center_integer != 
linked_shader->pixel_center_integer)){
      // error
   }

   /* Update the linked shader state.  Note that uses_gl_fragcoord should
    * accumulate the results.  The other values should replace.  If there
    * are multiple redeclarations, all the fields except uses_gl_fragcoord
    * are already known to be the same.
    */
   if (shader->redeclares_gl_fragcoord) {
      linked_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 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 qualifiers for gl_FragCoord\n");
> +         return;
> +      } else if (shader->redeclares_gl_fragcoord || 
> 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,
> @@ -1471,6 +1530,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 fbbca55..dd2ee82 100644
> --- a/src/mesa/main/mtypes.h
> +++ b/src/mesa/main/mtypes.h
> @@ -2414,6 +2414,14 @@ struct gl_shader
>      struct glsl_symbol_table *symbols;
>   
>      bool uses_builtin_functions;
> +   bool uses_gl_fragcoord;
> +   bool redeclares_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.
> 

_______________________________________________
mesa-dev mailing list
mesa-dev@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/mesa-dev

Reply via email to