[Mesa-dev] [PATCH 5/5] glsl: Pack flat "varyings" of mixed types together.

Kenneth Graunke kenneth at whitecape.org
Mon Jan 7 13:25:00 PST 2013


On 01/02/2013 10:59 AM, Paul Berry wrote:
> This patch enhances the varying packing code so that flat varyings of
> uint, int, and float types can be packed together.
>
> We accomplish this in lower_packed_varyings.cpp by making the type of
> all flat varyings ivec4, and then using information-preserving type
> conversions (e.g. ir_unop_bitcast_f2i) to convert all other types to
> ints.
>
> The varying_matches::compute_packing_class() function is updated to
> reflect the fact that varying packing no longer needs to segregate
> varyings of different base types.
>
> Fixes piglit test varying-packing-mixed-types.
> ---
>   src/glsl/link_varyings.cpp         | 20 +++++++----
>   src/glsl/lower_packed_varyings.cpp | 72 +++++++++++++++++++++++++++++++++-----
>   2 files changed, 78 insertions(+), 14 deletions(-)
>
> diff --git a/src/glsl/link_varyings.cpp b/src/glsl/link_varyings.cpp
> index b9c3f5d..5c27f23 100644
> --- a/src/glsl/link_varyings.cpp
> +++ b/src/glsl/link_varyings.cpp
> @@ -777,17 +777,25 @@ varying_matches::store_locations(unsigned producer_base,
>   unsigned
>   varying_matches::compute_packing_class(ir_variable *var)
>   {
> -   /* In this initial implementation we conservatively assume that variables
> -    * can only be packed if their base type (float/int/uint/bool) matches and
> -    * their interpolation and centroid qualifiers match.
> +   /* Without help from the back-end, there is no way to pack together
> +    * variables with different interpolation types, because
> +    * lower_packed_varyings must choose exactly one interpolation type for
> +    * each packed varying it creates.
>       *
> -    * TODO: relax these restrictions when the driver back-end permits.
> +    * However, we can safely pack together floats, ints, and uints, because:
> +    *
> +    * - varyings of base type "int" and "uint" must use the "flat"
> +    *   interpolation type, which can only occur in GLSL 1.30 and above.
> +    *
> +    * - On platforms that support GLSL 1.30 and above, lower_packed_varyings
> +    *   can store flat floats as ints without losing any information (using
> +    *   the ir_unop_bitcast_* opcodes).
> +    *
> +    * Therefore, the packing class depends only on the interpolation type.
>       */
>      unsigned packing_class = var->centroid ? 1 : 0;
>      packing_class *= 4;
>      packing_class += var->interpolation;
> -   packing_class *= GLSL_TYPE_ERROR;
> -   packing_class += var->type->get_scalar_type()->base_type;
>      return packing_class;
>   }
>
> diff --git a/src/glsl/lower_packed_varyings.cpp b/src/glsl/lower_packed_varyings.cpp
> index 09c551c..9cf1075 100644
> --- a/src/glsl/lower_packed_varyings.cpp
> +++ b/src/glsl/lower_packed_varyings.cpp
> @@ -66,6 +66,10 @@
>    * performance.  However, hopefully in most cases the performance loss will
>    * either be absorbed by a later optimization pass, or it will be offset by
>    * memory bandwidth savings (because fewer varyings are used).
> + *
> + * This lowering pass also packs flat floats, ints, and uints together, by
> + * using ivec4 as the base type of flat "varyings", and using appropriate
> + * casts to convert floats and uints into ints.
>    */
>
>   #include "glsl_symbol_table.h"
> @@ -90,6 +94,7 @@ public:
>      void run(exec_list *instructions);
>
>   private:
> +   ir_assignment *bitwise_assign(ir_rvalue *lhs, ir_rvalue *rhs);
>      unsigned lower_rvalue(ir_rvalue *rvalue, unsigned fine_location,
>                            ir_variable *unpacked_var, const char *name);
>      unsigned lower_arraylike(ir_rvalue *rvalue, unsigned array_size,
> @@ -181,6 +186,55 @@ lower_packed_varyings_visitor::run(exec_list *instructions)
>      }
>   }
>
> +
> +/**
> + * Make an ir_assignment from \c rhs to \c lhs, performing appropriate
> + * bitcasts if necessary to match up types.
> + */
> +ir_assignment *
> +lower_packed_varyings_visitor::bitwise_assign(ir_rvalue *lhs, ir_rvalue *rhs)
> +{
> +   if (lhs->type->base_type != rhs->type->base_type) {
> +      /* Since we only mix types in flat varyings, and we always store flat
> +       * varyings as type ivec4, we need only produce conversions to and from
> +       * int.
> +       */
> +      switch (rhs->type->base_type) {
> +      case GLSL_TYPE_UINT:
> +         rhs = new(this->mem_ctx)
> +            ir_expression(ir_unop_u2i, lhs->type, rhs);
> +         break;
> +      case GLSL_TYPE_FLOAT:
> +         rhs = new(this->mem_ctx)
> +            ir_expression(ir_unop_bitcast_f2i, lhs->type, rhs);
> +         break;
> +      case GLSL_TYPE_INT:
> +         switch (lhs->type->base_type) {
> +         case GLSL_TYPE_UINT:
> +            rhs = new(this->mem_ctx)
> +               ir_expression(ir_unop_i2u, lhs->type, rhs);
> +            break;
> +         case GLSL_TYPE_FLOAT:
> +            rhs = new(this->mem_ctx)
> +               ir_expression(ir_unop_bitcast_i2f, lhs->type, rhs);
> +            break;
> +         case GLSL_TYPE_INT:
> +            /* No conversion needed */
> +            break;
> +         default:
> +            assert(!"Unexpected type conversion while lowering varyings");
> +            break;
> +         }
> +         break;
> +      default:
> +         assert(!"Unexpected type conversion while lowering varyings");
> +         break;
> +      }
> +   }
> +   return new(this->mem_ctx) ir_assignment(lhs, rhs);
> +}

I find this function rather difficult to follow.  It does both all the 
conversions necessary for packing -and- unpacking (which I believe are 
non-overlapping sets).  Also, the it's easy to forget about the 
surrounding lhs->type != rhs->type check which effectively restricts 
this to dealing with flat data.

It might be simpler if it was split into separate pack/unpack functions.

Either way, this series gets a:
Reviewed-by: Kenneth Graunke <kenneth at whitecape.org>

> +
>   /**
>    * Recursively pack or unpack the given varying (or portion of a varying) by
>    * traversing all of its constituent vectors.
> @@ -262,12 +316,10 @@ lower_packed_varyings_visitor::lower_rvalue(ir_rvalue *rvalue,
>         ir_swizzle *swizzle = new(this->mem_ctx)
>            ir_swizzle(packed_deref, swizzle_values, components);
>         if (this->mode == ir_var_out) {
> -         ir_assignment *assignment = new(this->mem_ctx)
> -            ir_assignment(swizzle, rvalue);
> +         ir_assignment *assignment = this->bitwise_assign(swizzle, rvalue);
>            this->main_instructions->push_tail(assignment);
>         } else {
> -         ir_assignment *assignment = new(this->mem_ctx)
> -            ir_assignment(rvalue, swizzle);
> +         ir_assignment *assignment = this->bitwise_assign(rvalue, swizzle);
>            this->main_instructions->push_head(assignment);
>         }
>         return fine_location + components;
> @@ -306,8 +358,9 @@ lower_packed_varyings_visitor::lower_arraylike(ir_rvalue *rvalue,
>    * If no packed varying has been created for the given varying location yet,
>    * create it and add it to the shader before returning it.
>    *
> - * The newly created varying inherits its base type (float, uint, or int) and
> - * interpolation parameters from \c unpacked_var.
> + * The newly created varying inherits its interpolation parameters from \c
> + * unpacked_var.  Its base type is ivec4 if we are lowering a flat varying,
> + * vec4 otherwise.
>    */
>   ir_variable *
>   lower_packed_varyings_visitor::get_packed_varying(unsigned location,
> @@ -318,8 +371,11 @@ lower_packed_varyings_visitor::get_packed_varying(unsigned location,
>      assert(slot < locations_used);
>      if (this->packed_varyings[slot] == NULL) {
>         char *packed_name = ralloc_asprintf(this->mem_ctx, "packed:%s", name);
> -      const glsl_type *packed_type = glsl_type::get_instance(
> -            unpacked_var->type->get_scalar_type()->base_type, 4, 1);
> +      const glsl_type *packed_type;
> +      if (unpacked_var->interpolation == INTERP_QUALIFIER_FLAT)
> +         packed_type = glsl_type::ivec4_type;
> +      else
> +         packed_type = glsl_type::vec4_type;
>         ir_variable *packed_var = new(this->mem_ctx)
>            ir_variable(packed_type, packed_name, this->mode);
>         packed_var->centroid = unpacked_var->centroid;
>



More information about the mesa-dev mailing list