[Mesa-dev] [PATCH 26/28] glsl: lower tessellation varyings packed with component layout qualifier

Timothy Arceri timothy.arceri at collabora.com
Tue Dec 29 01:35:07 PST 2015


On Tue, 2015-12-29 at 16:00 +1100, Timothy Arceri wrote:
> For tessellation shaders we cannot just copy everything to the packed
> varyings like we do in other stages as tessellation uses shared
> memory for
> varyings, therefore it is only safe to copy array elements that the
> shader
> actually uses.
> 
> This class searches the IR for uses of varyings and then creates
> instructions that copy those vars to a packed varying. This means it
> is
> easy to end up with duplicate copies if the varying is used more than
> once,
> also arrays of arrays create a duplicate copy for each dimension that
> exists. These issues are not easily resolved without breaking various
> corner cases so we leave it to a later IR stage to clean up the mess.
> 
> Note that neither GLSL IR nor NIR can currently can't clean up the
> duplicates when and indirect is used as an array index. This patch
> assumes that NIR will eventually be able to clean this up.
> ---
>  src/glsl/lower_packed_varyings.cpp | 421
> +++++++++++++++++++++++++++++++++++++
>  1 file changed, 421 insertions(+)
> 
> diff --git a/src/glsl/lower_packed_varyings.cpp
> b/src/glsl/lower_packed_varyings.cpp
> index b606cc8..9522969 100644
> --- a/src/glsl/lower_packed_varyings.cpp
> +++ b/src/glsl/lower_packed_varyings.cpp
> @@ -148,10 +148,28 @@
>  #include "ir.h"
>  #include "ir_builder.h"
>  #include "ir_optimization.h"
> +#include "ir_rvalue_visitor.h"
>  #include "program/prog_instruction.h"
> +#include "util/hash_table.h"
>  
>  using namespace ir_builder;
>  
> +/**
> + * Creates new type for and array when the base type changes.
> + */
> +static const glsl_type *
> +update_packed_array_type(const glsl_type *type, const glsl_type
> *packed_type)
> +{
> +   const glsl_type *element_type = type->fields.array;
> +   if (element_type->is_array()) {
> +     const glsl_type *new_array_type =
> +        update_packed_array_type(element_type, packed_type);
> +      return glsl_type::get_array_instance(new_array_type, type
> ->length);
> +   } else {
> +      return glsl_type::get_array_instance(packed_type, type
> ->length);
> +   }
> +}
> +
>  static bool
>  needs_lowering(ir_variable *var, bool has_enhanced_layouts,
>                 bool disable_varying_packing)
> @@ -205,6 +223,51 @@ create_packed_var(void * const mem_ctx, const
> char *packed_name,
>     return packed_var;
>  }
>  
> +/**
> + * Creates a packed varying for the tessellation packing.
> + */
> +static ir_variable *
> +create_tess_packed_var(void *mem_ctx, ir_variable *unpacked_var)
> +{
> +   /* create packed varying name using location */
> +   char location_str[11];
> +   snprintf(location_str, 11, "%d", unpacked_var->data.location);
> +   char *packed_name;
> +   if ((ir_variable_mode) unpacked_var->data.mode ==
> ir_var_shader_out)
> +      packed_name = ralloc_asprintf(mem_ctx, "packed_out:%s",
> location_str);
> +   else
> +      packed_name = ralloc_asprintf(mem_ctx, "packed_in:%s",
> location_str);
> +
> +   const glsl_type *packed_type;
> +   switch (unpacked_var->type->without_array()->base_type) {
> +   case GLSL_TYPE_UINT:
> +      packed_type = glsl_type::uvec4_type;
> +      break;
> +   case GLSL_TYPE_INT:
> +      packed_type = glsl_type::ivec4_type;
> +      break;
> +   case GLSL_TYPE_FLOAT:
> +      packed_type = glsl_type::vec4_type;
> +      break;
> +   case GLSL_TYPE_DOUBLE:
> +      packed_type = glsl_type::dvec4_type;
> +      break;
> +   default:
> +      assert(!"Unexpected type in tess varying packing");
> +      return NULL;
> +   }
> +
> +   /* Create array new array type */
> +   if (unpacked_var->type->is_array()) {
> +      packed_type = update_packed_array_type(unpacked_var->type,
> packed_type);
> +   }
> +
> +   return create_packed_var(mem_ctx, packed_name, packed_type,
> unpacked_var,
> +                            (ir_variable_mode) unpacked_var
> ->data.mode,
> +                            unpacked_var->data.location,
> +                            unpacked_var->type->is_array());
> +}
> +
>  namespace {
>  
>  /**
> @@ -763,6 +826,296 @@
> lower_packed_varyings_gs_splicer::visit_leave(ir_emit_vertex *ev)
>  }
>  
>  
> +/**
> + * For tessellation shaders we cannot just copy everything to the
> packed
> + * varyings like we do in other stages as tessellation uses shared
> memory for
> + * varyings, therefore it is only safe to copy array elements that
> the shader
> + * actually uses.
> + *
> + * This class searches the IR for uses of varyings and then creates
> + * instructions that copy those vars to a packed varying. This means
> it is
> + * easy to end up with duplicate copies if the varying is used more
> than once,
> + * also arrays of arrays create a duplicate copy for each dimension
> that
> + * exists. These issues are not easily resolved without breaking
> various
> + * corner cases so we leave it to a later IR stage to clean up the
> mess.
> + */
> +class lower_packed_varyings_tess_visitor : public ir_rvalue_visitor
> +{
> +public:
> +   lower_packed_varyings_tess_visitor(void *mem_ctx, hash_table
> *varyings,
> +                                      ir_variable_mode mode)
> +   : mem_ctx(mem_ctx), varyings(varyings), mode(mode)
> +   {
> +   }
> +
> +   virtual ~lower_packed_varyings_tess_visitor()
> +   {
> +   }
> +
> +   virtual ir_visitor_status visit_leave(ir_assignment *);
> +   virtual ir_visitor_status visit_leave(ir_dereference_array *);
> +
> +   ir_dereference *create_dereference(ir_dereference *deref,
> +                                      unsigned *dimensions);
> +   unsigned create_extra_array_dereference(unsigned inner_dimension,
> +                                           const glsl_type
> **types_list,
> +                                           ir_dereference
> **packed_deref_list,
> +                                           ir_dereference
> **deref_list);
> +   ir_variable *get_packed_var(ir_variable *var);
> +   void handle_rvalue(ir_rvalue **rvalue);
> +
> +   /**
> +    * Exec list into which the visitor should insert the packing
> instructions.
> +    * Caller provides this list; it should insert the instructions
> into the
> +    * appropriate place in the shader once the visitor has finished
> running.
> +    */
> +   exec_list new_instructions;
> +
> +private:
> +   /**
> +    * Memory context used to allocate new instructions for the
> shader.
> +    */
> +   void * const mem_ctx;
> +
> +   hash_table *varyings;
> +
> +   ir_variable_mode mode;
> +};
> +
> +/**
> + * Search the hash table for a packed varying for this variable.
> + */
> +ir_variable *
> +lower_packed_varyings_tess_visitor::get_packed_var(ir_variable *var)
> +{
> +   assert(var);
> +
> +   const struct hash_entry *entry =
> +      _mesa_hash_table_search(varyings, var);
> +
> +   return entry ? (ir_variable *) entry->data : NULL;
> +}
> +
> +ir_dereference *
> +lower_packed_varyings_tess_visitor::create_dereference(ir_dereferenc
> e *deref,
> +                                                       unsigned
> *dimension)
> +{
> +   ir_dereference_array *deref_array = deref
> ->as_dereference_array();
> +   if (deref_array) {
> +      (*dimension)--;
> +      ir_dereference *array =
> +         create_dereference(deref_array->array->as_dereference(),
> dimension);
> +      return new(this->mem_ctx)
> +         ir_dereference_array(array, deref_array->array_index);

The array_index needs to be cloned here I've fixed this locally.


More information about the mesa-dev mailing list