[Mesa-dev] [PATCH v4 17/17] glsl linker: compare interface blocks during interstage linking

Kenneth Graunke kenneth at whitecape.org
Wed May 22 11:00:49 PDT 2013


On 05/16/2013 05:44 PM, Jordan Justen wrote:
> Verify that interface blocks match when linking separate shader
> stages into a program.
>
> Fixes piglit glsl-1.50 tests:
> * linker/interface-blocks-vs-fs-member-count-mismatch.shader_test
> * linker/interface-blocks-vs-fs-member-order-mismatch.shader_test
>
> Signed-off-by: Jordan Justen <jordan.l.justen at intel.com>
> ---
>   src/glsl/interface_blocks.cpp |   47 +++++++++++++++++++++++++++++++++++++++--
>   src/glsl/interface_blocks.h   |    4 ++++
>   src/glsl/linker.cpp           |    6 ++++++
>   3 files changed, 55 insertions(+), 2 deletions(-)

In my mind, validating interface blocks within a single stage and 
between two adjacent stages are really separate tasks that work 
differently.  Intrastage has an arbitrarily long list of, say, vertex 
shaders; interstage has exactly two.

I really dislike how this patch conflates the two.  I also find creating 
a list with exactly two elements, looping over it, and special-casing 
every element to be quite ugly.

Sorry for taking so long on this series and coming in with harsh 
feedback. :(

I'll send out a proposed v5 that does this a bit differently and still 
passes all of your piglit tests.

> diff --git a/src/glsl/interface_blocks.cpp b/src/glsl/interface_blocks.cpp
> index 6dfd0c4..b458b59 100644
> --- a/src/glsl/interface_blocks.cpp
> +++ b/src/glsl/interface_blocks.cpp
> @@ -30,14 +30,21 @@
>   #include "glsl_symbol_table.h"
>   #include "main/macros.h"
>   #include "program/hash_table.h"
> +#include "linker.h"
>
>   static bool
>   cross_validate_interface_blocks(const gl_shader **shader_list,
> -                                unsigned num_shaders)
> +                                unsigned num_shaders,
> +                                bool interstage)
>   {
>      bool ok = true;
>      glsl_symbol_table interfaces;
>
> +   /* Interstage linking checks assume 2 shaders. First the producer, and
> +    * then the consumer.
> +    */
> +   assert(!interstage || num_shaders == 2);
> +
>      for (unsigned int i = 0; ok && i < num_shaders; i++) {
>         if (shader_list[i] == NULL)
>            continue;
> @@ -52,6 +59,18 @@ cross_validate_interface_blocks(const gl_shader **shader_list,
>            if (iface_type == NULL)
>               continue;
>
> +         /* If we are checking interstage linking then we assume:
> +          *  * The first shader (producer) has i == 0, and for the
> +          *    producer we don't need to check input interfaces.
> +          *  * The second shader (consumer) has i == 1, and for the
> +          *    consumer we don't need to check output interfaces.
> +          */
> +         if (interstage &&
> +             ((var->mode == ir_var_shader_in && i == 0) ||
> +              (var->mode == ir_var_shader_out && i == 1))
> +            )
> +            continue;
> +
>            const char *iface_name = iface_type->name;
>
>            const glsl_type *old_iface_type =
> @@ -70,6 +89,18 @@ cross_validate_interface_blocks(const gl_shader **shader_list,
>            ok &= old_iface_type == iface_type;
>            if (!ok)
>               break;
> +
> +         /* For interstage linking, if the interface is an input, then
> +          * we need to verify that its type matches a previously declared
> +          * output type.
> +          */
> +         if (interstage && var->mode == ir_var_shader_in) {
> +            old_iface_type =
> +               interfaces.get_interface(iface_name, ir_var_shader_out);
> +            ok &= old_iface_type == iface_type;
> +            if (!ok)
> +               break;
> +         }
>         }
>      }
>
> @@ -81,6 +112,18 @@ validate_intrastage_interface_blocks(const gl_shader **shader_list,
>                                        unsigned num_shaders)
>   {
>      return cross_validate_interface_blocks(shader_list,
> -                                          num_shaders);
> +                                          num_shaders,
> +                                          false);
> +}
> +
> +bool
> +validate_interstage_interface_blocks(const gl_shader *producer,
> +                                     const gl_shader *consumer)
> +{
> +   const gl_shader *shader_list[] = { producer, consumer };
> +
> +   return cross_validate_interface_blocks((const gl_shader **) shader_list,
> +                                          ARRAY_SIZE(shader_list),
> +                                          true);
>   }
>
> diff --git a/src/glsl/interface_blocks.h b/src/glsl/interface_blocks.h
> index 4c37c02..58c847c 100644
> --- a/src/glsl/interface_blocks.h
> +++ b/src/glsl/interface_blocks.h
> @@ -29,4 +29,8 @@ bool
>   validate_intrastage_interface_blocks(const gl_shader **shader_list,
>                                        unsigned num_shaders);
>
> +bool
> +validate_interstage_interface_blocks(const gl_shader *producer,
> +                                     const gl_shader *consumer);
> +
>   #endif /* GLSL_INTERFACE_BLOCKS_H */
> diff --git a/src/glsl/linker.cpp b/src/glsl/linker.cpp
> index 4f2cab2..71203b1 100644
> --- a/src/glsl/linker.cpp
> +++ b/src/glsl/linker.cpp
> @@ -1729,6 +1729,12 @@ link_shaders(struct gl_context *ctx, struct gl_shader_program *prog)
>   	 if (prog->_LinkedShaders[i] == NULL)
>   	    continue;
>
> +         if (!validate_interstage_interface_blocks(prog->_LinkedShaders[prev],
> +                                                   prog->_LinkedShaders[i])) {
> +            linker_error(prog, "interface block mismatch between shader stages\n");
> +            goto done;
> +         }
> +
>   	 if (!cross_validate_outputs_to_inputs(prog,
>   					       prog->_LinkedShaders[prev],
>   					       prog->_LinkedShaders[i]))
>



More information about the mesa-dev mailing list