[Mesa-dev] [PATCH v2 19/42] glsl ubo/ssbo: Move common code into lower_buffer_access::setup_buffer_access

Jordan Justen jordan.l.justen at intel.com
Thu Nov 19 10:54:20 PST 2015


On 2015-11-18 00:00:08, Iago Toral wrote:
> On Tue, 2015-11-17 at 21:54 -0800, Jordan Justen wrote:
> > This code will also be usable by the pass to lower shared variables.
> > 
> > Note, that *const_offset is adjusted by setup_buffer_access so it must
> > be initialized before calling setup_buffer_access.
> > 
> > v2:
> >  * Add comment for lower_buffer_access::setup_buffer_access
> > 
> > Signed-off-by: Jordan Justen <jordan.l.justen at intel.com>
> > Cc: Samuel Iglesias Gonsalvez <siglesias at igalia.com>
> > Cc: Iago Toral Quiroga <itoral at igalia.com>
> > Reviewed-by: Iago Toral Quiroga <itoral at igalia.com>
> > ---
> >  src/glsl/lower_buffer_access.cpp | 177 +++++++++++++++++++++++++++++++++++++++
> >  src/glsl/lower_buffer_access.h   |   5 ++
> >  src/glsl/lower_ubo_reference.cpp | 160 +----------------------------------
> >  3 files changed, 185 insertions(+), 157 deletions(-)
> > 
> > diff --git a/src/glsl/lower_buffer_access.cpp b/src/glsl/lower_buffer_access.cpp
> > index b5fe6e3..297ed69 100644
> > --- a/src/glsl/lower_buffer_access.cpp
> > +++ b/src/glsl/lower_buffer_access.cpp
> > @@ -305,4 +305,181 @@ lower_buffer_access::is_dereferenced_thing_row_major(const ir_rvalue *deref)
> >     return false;
> >  }
> >  
> > +/**
> > + * This function initializes various values that will be used later by
> > + * emit_access when actually emitting loads or stores.
> > + *
> > + * Note: const_offset is an input as well as an output. For UBO and SSBO, the
> > + * caller should initialize it to 0 to point to the start of the buffer
> > + * object. For compute shader shared variables it will be initialized to the
> > + * offset of variable in the shared variable storage block.
> 
> I think this is not true, your version changes UBO and SSBO to behave
> just like shader variables since you no longer ever update *const_offset
> when you find an ir_type_dereference_variable node. Instead, you always
> initialize *const_offset to the value of ubo_var->Offset in
> setup_for_load_or_store. I think you can just rewrite the note comment
> above as:
> 
> "const_offset is an input as well as an output, clients must initialize
> it to the offset of the variable in the underlying block, and this
> function will adjust it by adding the constant offset of the member
> being accessed into that variable"

Yeah, that sounds good. I'll use your version.

Thanks,

-Jordan

> 
> > + */
> > +void
> > +lower_buffer_access::setup_buffer_access(void *mem_ctx,
> > +                                         ir_variable *var,
> > +                                         ir_rvalue *deref,
> > +                                         ir_rvalue **offset,
> > +                                         unsigned *const_offset,
> > +                                         bool *row_major,
> > +                                         int *matrix_columns,
> > +                                         unsigned packing)
> > +{
> > +   *offset = new(mem_ctx) ir_constant(0u);
> > +   *row_major = is_dereferenced_thing_row_major(deref);
> > +   *matrix_columns = 1;
> > +
> > +   /* Calculate the offset to the start of the region of the UBO
> > +    * dereferenced by *rvalue.  This may be a variable offset if an
> > +    * array dereference has a variable index.
> > +    */
> > +   while (deref) {
> > +      switch (deref->ir_type) {
> > +      case ir_type_dereference_variable: {
> > +         deref = NULL;
> > +         break;
> > +      }
> > +
> > +      case ir_type_dereference_array: {
> > +         ir_dereference_array *deref_array = (ir_dereference_array *) deref;
> > +         unsigned array_stride;
> > +         if (deref_array->array->type->is_vector()) {
> > +            /* We get this when storing or loading a component out of a vector
> > +             * with a non-constant index. This happens for v[i] = f where v is
> > +             * a vector (or m[i][j] = f where m is a matrix). If we don't
> > +             * lower that here, it gets turned into v = vector_insert(v, i,
> > +             * f), which loads the entire vector, modifies one component and
> > +             * then write the entire thing back.  That breaks if another
> > +             * thread or SIMD channel is modifying the same vector.
> > +             */
> > +            array_stride = 4;
> > +            if (deref_array->array->type->is_double())
> > +               array_stride *= 2;
> > +         } else if (deref_array->array->type->is_matrix() && *row_major) {
> > +            /* When loading a vector out of a row major matrix, the
> > +             * step between the columns (vectors) is the size of a
> > +             * float, while the step between the rows (elements of a
> > +             * vector) is handled below in emit_ubo_loads.
> > +             */
> > +            array_stride = 4;
> > +            if (deref_array->array->type->is_double())
> > +               array_stride *= 2;
> > +            *matrix_columns = deref_array->array->type->matrix_columns;
> > +         } else if (deref_array->type->without_array()->is_interface()) {
> > +            /* We're processing an array dereference of an interface instance
> > +             * array. The thing being dereferenced *must* be a variable
> > +             * dereference because interfaces cannot be embedded in other
> > +             * types. In terms of calculating the offsets for the lowering
> > +             * pass, we don't care about the array index. All elements of an
> > +             * interface instance array will have the same offsets relative to
> > +             * the base of the block that backs them.
> > +             */
> > +            deref = deref_array->array->as_dereference();
> > +            break;
> > +         } else {
> > +            /* Whether or not the field is row-major (because it might be a
> > +             * bvec2 or something) does not affect the array itself. We need
> > +             * to know whether an array element in its entirety is row-major.
> > +             */
> > +            const bool array_row_major =
> > +               is_dereferenced_thing_row_major(deref_array);
> > +
> > +            /* The array type will give the correct interface packing
> > +             * information
> > +             */
> > +            if (packing == GLSL_INTERFACE_PACKING_STD430) {
> > +               array_stride = deref_array->type->std430_array_stride(array_row_major);
> > +            } else {
> > +               array_stride = deref_array->type->std140_size(array_row_major);
> > +               array_stride = glsl_align(array_stride, 16);
> > +            }
> > +         }
> > +
> > +         ir_rvalue *array_index = deref_array->array_index;
> > +         if (array_index->type->base_type == GLSL_TYPE_INT)
> > +            array_index = i2u(array_index);
> > +
> > +         ir_constant *const_index =
> > +            array_index->constant_expression_value(NULL);
> > +         if (const_index) {
> > +            *const_offset += array_stride * const_index->value.u[0];
> > +         } else {
> > +            *offset = add(*offset,
> > +                          mul(array_index,
> > +                              new(mem_ctx) ir_constant(array_stride)));
> > +         }
> > +         deref = deref_array->array->as_dereference();
> > +         break;
> > +      }
> > +
> > +      case ir_type_dereference_record: {
> > +         ir_dereference_record *deref_record = (ir_dereference_record *) deref;
> > +         const glsl_type *struct_type = deref_record->record->type;
> > +         unsigned intra_struct_offset = 0;
> > +
> > +         for (unsigned int i = 0; i < struct_type->length; i++) {
> > +            const glsl_type *type = struct_type->fields.structure[i].type;
> > +
> > +            ir_dereference_record *field_deref = new(mem_ctx)
> > +               ir_dereference_record(deref_record->record,
> > +                                     struct_type->fields.structure[i].name);
> > +            const bool field_row_major =
> > +               is_dereferenced_thing_row_major(field_deref);
> > +
> > +            ralloc_free(field_deref);
> > +
> > +            unsigned field_align = 0;
> > +
> > +            if (packing == GLSL_INTERFACE_PACKING_STD430)
> > +               field_align = type->std430_base_alignment(field_row_major);
> > +            else
> > +               field_align = type->std140_base_alignment(field_row_major);
> > +
> > +            intra_struct_offset = glsl_align(intra_struct_offset, field_align);
> > +
> > +            if (strcmp(struct_type->fields.structure[i].name,
> > +                       deref_record->field) == 0)
> > +               break;
> > +
> > +            if (packing == GLSL_INTERFACE_PACKING_STD430)
> > +               intra_struct_offset += type->std430_size(field_row_major);
> > +            else
> > +               intra_struct_offset += type->std140_size(field_row_major);
> > +
> > +            /* If the field just examined was itself a structure, apply rule
> > +             * #9:
> > +             *
> > +             *     "The structure may have padding at the end; the base offset
> > +             *     of the member following the sub-structure is rounded up to
> > +             *     the next multiple of the base alignment of the structure."
> > +             */
> > +            if (type->without_array()->is_record()) {
> > +               intra_struct_offset = glsl_align(intra_struct_offset,
> > +                                                field_align);
> > +
> > +            }
> > +         }
> > +
> > +         *const_offset += intra_struct_offset;
> > +         deref = deref_record->record->as_dereference();
> > +         break;
> > +      }
> > +
> > +      case ir_type_swizzle: {
> > +         ir_swizzle *deref_swizzle = (ir_swizzle *) deref;
> > +
> > +         assert(deref_swizzle->mask.num_components == 1);
> > +
> > +         *const_offset += deref_swizzle->mask.x * sizeof(int);
> > +         deref = deref_swizzle->val->as_dereference();
> > +         break;
> > +      }
> > +
> > +      default:
> > +         assert(!"not reached");
> > +         deref = NULL;
> > +         break;
> > +      }
> > +   }
> > +}
> > +
> >  } /* namespace lower_buffer_access */
> > diff --git a/src/glsl/lower_buffer_access.h b/src/glsl/lower_buffer_access.h
> > index b21ea28..f8e1070 100644
> > --- a/src/glsl/lower_buffer_access.h
> > +++ b/src/glsl/lower_buffer_access.h
> > @@ -50,6 +50,11 @@ public:
> >                      unsigned int packing, unsigned int write_mask);
> >  
> >     bool is_dereferenced_thing_row_major(const ir_rvalue *deref);
> > +
> > +   void setup_buffer_access(void *mem_ctx, ir_variable *var, ir_rvalue *deref,
> > +                            ir_rvalue **offset, unsigned *const_offset,
> > +                            bool *row_major, int *matrix_columns,
> > +                            unsigned packing);
> >  };
> >  
> >  } /* namespace lower_buffer_access */
> > diff --git a/src/glsl/lower_ubo_reference.cpp b/src/glsl/lower_ubo_reference.cpp
> > index ad7a522..5082da8 100644
> > --- a/src/glsl/lower_ubo_reference.cpp
> > +++ b/src/glsl/lower_ubo_reference.cpp
> > @@ -287,164 +287,10 @@ lower_ubo_reference_visitor::setup_for_load_or_store(ir_variable *var,
> >  
> >     assert(this->uniform_block);
> >  
> > -   *offset = new(mem_ctx) ir_constant(0u);
> > -   *const_offset = 0;
> > -   *row_major = is_dereferenced_thing_row_major(deref);
> > -   *matrix_columns = 1;
> > -
> > -   /* Calculate the offset to the start of the region of the UBO
> > -    * dereferenced by *rvalue.  This may be a variable offset if an
> > -    * array dereference has a variable index.
> > -    */
> > -   while (deref) {
> > -      switch (deref->ir_type) {
> > -      case ir_type_dereference_variable: {
> > -         *const_offset += ubo_var->Offset;
> > -         deref = NULL;
> > -         break;
> > -      }
> > -
> > -      case ir_type_dereference_array: {
> > -         ir_dereference_array *deref_array = (ir_dereference_array *) deref;
> > -         unsigned array_stride;
> > -         if (deref_array->array->type->is_vector()) {
> > -            /* We get this when storing or loading a component out of a vector
> > -             * with a non-constant index. This happens for v[i] = f where v is
> > -             * a vector (or m[i][j] = f where m is a matrix). If we don't
> > -             * lower that here, it gets turned into v = vector_insert(v, i,
> > -             * f), which loads the entire vector, modifies one component and
> > -             * then write the entire thing back.  That breaks if another
> > -             * thread or SIMD channel is modifying the same vector.
> > -             */
> > -            array_stride = 4;
> > -            if (deref_array->array->type->is_double())
> > -               array_stride *= 2;
> > -         } else if (deref_array->array->type->is_matrix() && *row_major) {
> > -            /* When loading a vector out of a row major matrix, the
> > -             * step between the columns (vectors) is the size of a
> > -             * float, while the step between the rows (elements of a
> > -             * vector) is handled below in emit_ubo_loads.
> > -             */
> > -            array_stride = 4;
> > -            if (deref_array->array->type->is_double())
> > -               array_stride *= 2;
> > -            *matrix_columns = deref_array->array->type->matrix_columns;
> > -         } else if (deref_array->type->without_array()->is_interface()) {
> > -            /* We're processing an array dereference of an interface instance
> > -             * array. The thing being dereferenced *must* be a variable
> > -             * dereference because interfaces cannot be embedded in other
> > -             * types. In terms of calculating the offsets for the lowering
> > -             * pass, we don't care about the array index. All elements of an
> > -             * interface instance array will have the same offsets relative to
> > -             * the base of the block that backs them.
> > -             */
> > -            deref = deref_array->array->as_dereference();
> > -            break;
> > -         } else {
> > -            /* Whether or not the field is row-major (because it might be a
> > -             * bvec2 or something) does not affect the array itself. We need
> > -             * to know whether an array element in its entirety is row-major.
> > -             */
> > -            const bool array_row_major =
> > -               is_dereferenced_thing_row_major(deref_array);
> > -
> > -            /* The array type will give the correct interface packing
> > -             * information
> > -             */
> > -            if (packing == GLSL_INTERFACE_PACKING_STD430) {
> > -               array_stride = deref_array->type->std430_array_stride(array_row_major);
> > -            } else {
> > -               array_stride = deref_array->type->std140_size(array_row_major);
> > -               array_stride = glsl_align(array_stride, 16);
> > -            }
> > -         }
> > -
> > -         ir_rvalue *array_index = deref_array->array_index;
> > -         if (array_index->type->base_type == GLSL_TYPE_INT)
> > -            array_index = i2u(array_index);
> > -
> > -         ir_constant *const_index =
> > -            array_index->constant_expression_value(NULL);
> > -         if (const_index) {
> > -            *const_offset += array_stride * const_index->value.u[0];
> > -         } else {
> > -            *offset = add(*offset,
> > -                          mul(array_index,
> > -                              new(mem_ctx) ir_constant(array_stride)));
> > -         }
> > -         deref = deref_array->array->as_dereference();
> > -         break;
> > -      }
> > -
> > -      case ir_type_dereference_record: {
> > -         ir_dereference_record *deref_record = (ir_dereference_record *) deref;
> > -         const glsl_type *struct_type = deref_record->record->type;
> > -         unsigned intra_struct_offset = 0;
> > -
> > -         for (unsigned int i = 0; i < struct_type->length; i++) {
> > -            const glsl_type *type = struct_type->fields.structure[i].type;
> > -
> > -            ir_dereference_record *field_deref = new(mem_ctx)
> > -               ir_dereference_record(deref_record->record,
> > -                                     struct_type->fields.structure[i].name);
> > -            const bool field_row_major =
> > -               is_dereferenced_thing_row_major(field_deref);
> > -
> > -            ralloc_free(field_deref);
> > -
> > -            unsigned field_align = 0;
> > -
> > -            if (packing == GLSL_INTERFACE_PACKING_STD430)
> > -               field_align = type->std430_base_alignment(field_row_major);
> > -            else
> > -               field_align = type->std140_base_alignment(field_row_major);
> > -
> > -            intra_struct_offset = glsl_align(intra_struct_offset, field_align);
> > -
> > -            if (strcmp(struct_type->fields.structure[i].name,
> > -                       deref_record->field) == 0)
> > -               break;
> > -
> > -            if (packing == GLSL_INTERFACE_PACKING_STD430)
> > -               intra_struct_offset += type->std430_size(field_row_major);
> > -            else
> > -               intra_struct_offset += type->std140_size(field_row_major);
> > -
> > -            /* If the field just examined was itself a structure, apply rule
> > -             * #9:
> > -             *
> > -             *     "The structure may have padding at the end; the base offset
> > -             *     of the member following the sub-structure is rounded up to
> > -             *     the next multiple of the base alignment of the structure."
> > -             */
> > -            if (type->without_array()->is_record()) {
> > -               intra_struct_offset = glsl_align(intra_struct_offset,
> > -                                                field_align);
> > -
> > -            }
> > -         }
> > -
> > -         *const_offset += intra_struct_offset;
> > -         deref = deref_record->record->as_dereference();
> > -         break;
> > -      }
> > -
> > -      case ir_type_swizzle: {
> > -         ir_swizzle *deref_swizzle = (ir_swizzle *) deref;
> > +   *const_offset = ubo_var->Offset;
> >  
> > -         assert(deref_swizzle->mask.num_components == 1);
> > -
> > -         *const_offset += deref_swizzle->mask.x * sizeof(int);
> > -         deref = deref_swizzle->val->as_dereference();
> > -         break;
> > -      }
> > -
> > -      default:
> > -         assert(!"not reached");
> > -         deref = NULL;
> > -         break;
> > -      }
> > -   }
> > +   setup_buffer_access(mem_ctx, var, deref, offset, const_offset, row_major,
> > +                       matrix_columns, packing);
> >  }
> >  
> >  void
> 
> 


More information about the mesa-dev mailing list