[Mesa-dev] [PATCH v5 25/70] glsl: Add std430 related member functions to glsl_type class

Samuel Iglesias Gonsálvez siglesias at igalia.com
Thu Sep 10 22:48:55 PDT 2015



On 10/09/15 20:13, Jordan Justen wrote:
> On 2015-09-10 06:35:41, Iago Toral Quiroga wrote:
>> From: Samuel Iglesias Gonsalvez <siglesias at igalia.com>
>>
>> They are used to calculate size, base alignment and array stride values
>> for a glsl_type following std430 rules.
>>
>> Signed-off-by: Samuel Iglesias Gonsalvez <siglesias at igalia.com>
>> ---
>>  src/glsl/glsl_types.cpp | 209 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  src/glsl/glsl_types.h   |  19 +++++
>>  2 files changed, 228 insertions(+)
>>
>> diff --git a/src/glsl/glsl_types.cpp b/src/glsl/glsl_types.cpp
>> index 755618a..d97991a 100644
>> --- a/src/glsl/glsl_types.cpp
>> +++ b/src/glsl/glsl_types.cpp
>> @@ -1357,6 +1357,215 @@ glsl_type::std140_size(bool row_major) const
>>     return -1;
>>  }
>>  
>> +unsigned
>> +glsl_type::std430_base_alignment(bool row_major) const
>> +{
>> +
>> +   unsigned N = is_double() ? 8 : 4;
>> +
>> +   /* (1) If the member is a scalar consuming <N> basic machine units, the
>> +    *     base alignment is <N>.
>> +    *
>> +    * (2) If the member is a two- or four-component vector with components
>> +    *     consuming <N> basic machine units, the base alignment is 2<N> or
>> +    *     4<N>, respectively.
>> +    *
>> +    * (3) If the member is a three-component vector with components consuming
>> +    *     <N> basic machine units, the base alignment is 4<N>.
>> +    */
>> +   if (this->is_scalar() || this->is_vector()) {
>> +      switch (this->vector_elements) {
>> +      case 1:
>> +         return N;
>> +      case 2:
>> +         return 2 * N;
>> +      case 3:
>> +      case 4:
>> +         return 4 * N;
>> +      }
>> +   }
>> +
>> +   /* OpenGL 4.30 spec, section 7.6.2.2 "Standard Uniform Block Layout":
>> +    *
>> +    * "When using the "std430" storage layout, shader storage
>> +    * blocks will be laid out in buffer storage identically to uniform and
>> +    * shader storage blocks using the "std140" layout, except that the base
>> +    * alignment of arrays of scalars and vectors in rule (4) and of structures
> 
> Looking at the 4.3 spec (and 4.5), it actually adds "and stride"
> following "base alignment". The extension spec *does not* have the
> "and stride" text.
> 

OK. If you agree, I will keep OpenGL 4.3 (and later) spec wording in all
the places where this snippet is pasted.

> This seems to be an inconsistency between the extension spec and the
> actual spec, but the OpenGL spec form would produce more tightly
> packed arrays.
> 
> Maybe we want to confirm what another implementation does?
> 

Both NVIDIA and ATI proprietary drivers don't round up the stride of
arrays of vectors to a multiple of a vec4 size, i.e., they are following
the OpenGL spec. For example: for an array of vec2, they are returning
an stride value of 8, not 16 as in std140.

Sam

> -Jordan
> 
>> +    * in rule (9) are not rounded up a multiple of the base alignment of a
>> +    * vec4."
>> +    */
>> +
>> +   /* (1) If the member is a scalar consuming <N> basic machine units, the
>> +    *     base alignment is <N>.
>> +    *
>> +    * (2) If the member is a two- or four-component vector with components
>> +    *     consuming <N> basic machine units, the base alignment is 2<N> or
>> +    *     4<N>, respectively.
>> +    *
>> +    * (3) If the member is a three-component vector with components consuming
>> +    *     <N> basic machine units, the base alignment is 4<N>.
>> +    */
>> +   if (this->is_array())
>> +      return this->fields.array->std430_base_alignment(row_major);
>> +
>> +   /* (5) If the member is a column-major matrix with <C> columns and
>> +    *     <R> rows, the matrix is stored identically to an array of
>> +    *     <C> column vectors with <R> components each, according to
>> +    *     rule (4).
>> +    *
>> +    * (7) If the member is a row-major matrix with <C> columns and <R>
>> +    *     rows, the matrix is stored identically to an array of <R>
>> +    *     row vectors with <C> components each, according to rule (4).
>> +    */
>> +   if (this->is_matrix()) {
>> +      const struct glsl_type *vec_type, *array_type;
>> +      int c = this->matrix_columns;
>> +      int r = this->vector_elements;
>> +
>> +      if (row_major) {
>> +         vec_type = get_instance(base_type, c, 1);
>> +         array_type = glsl_type::get_array_instance(vec_type, r);
>> +      } else {
>> +         vec_type = get_instance(base_type, r, 1);
>> +         array_type = glsl_type::get_array_instance(vec_type, c);
>> +      }
>> +
>> +      return array_type->std430_base_alignment(false);
>> +   }
>> +
>> +      /* (9) If the member is a structure, the base alignment of the
>> +    *     structure is <N>, where <N> is the largest base alignment
>> +    *     value of any of its members, and rounded up to the base
>> +    *     alignment of a vec4. The individual members of this
>> +    *     sub-structure are then assigned offsets by applying this set
>> +    *     of rules recursively, where the base offset of the first
>> +    *     member of the sub-structure is equal to the aligned offset
>> +    *     of the structure. 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 (this->is_record()) {
>> +      unsigned base_alignment = 0;
>> +      for (unsigned i = 0; i < this->length; i++) {
>> +         bool field_row_major = row_major;
>> +         const enum glsl_matrix_layout matrix_layout =
>> +            glsl_matrix_layout(this->fields.structure[i].matrix_layout);
>> +         if (matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR) {
>> +            field_row_major = true;
>> +         } else if (matrix_layout == GLSL_MATRIX_LAYOUT_COLUMN_MAJOR) {
>> +            field_row_major = false;
>> +         }
>> +
>> +         const struct glsl_type *field_type = this->fields.structure[i].type;
>> +         base_alignment = MAX2(base_alignment,
>> +                               field_type->std430_base_alignment(field_row_major));
>> +      }
>> +      return base_alignment;
>> +   }
>> +   assert(!"not reached");
>> +   return -1;
>> +}
>> +
>> +unsigned
>> +glsl_type::std430_array_stride(bool row_major) const
>> +{
>> +   unsigned N = is_double() ? 8 : 4;
>> +
>> +   /* Notice that the array stride of a vec3 is not 3 * N but 4 * N.
>> +    * See OpenGL 4.30 spec, section 7.6.2.2 "Standard Uniform Block Layout"
>> +    *
>> +    * (3) If the member is a three-component vector with components consuming
>> +    *     <N> basic machine units, the base alignment is 4<N>.
>> +    */
>> +   if (this->is_vector() && this->vector_elements == 3)
>> +      return 4 * N;
>> +
>> +   /* By default use std430_size(row_major) */
>> +   return this->std430_size(row_major);
>> +}
>> +
>> +unsigned
>> +glsl_type::std430_size(bool row_major) const
>> +{
>> +   unsigned N = is_double() ? 8 : 4;
>> +
>> +   /* OpenGL 4.30 spec, section 7.6.2.2 "Standard Uniform Block Layout":
>> +    *
>> +    * "When using the "std430" storage layout, shader storage
>> +    * blocks will be laid out in buffer storage identically to uniform and
>> +    * shader storage blocks using the "std140" layout, except that the base
>> +    * alignment of arrays of scalars and vectors in rule (4) and of structures
>> +    * in rule (9) are not rounded up a multiple of the base alignment of a
>> +    * vec4."
>> +    */
>> +   if (this->is_scalar() || this->is_vector())
>> +         return this->vector_elements * N;
>> +
>> +   if (this->without_array()->is_matrix()) {
>> +      const struct glsl_type *element_type;
>> +      const struct glsl_type *vec_type;
>> +      unsigned int array_len;
>> +
>> +      if (this->is_array()) {
>> +         element_type = this->fields.array;
>> +         array_len = this->length;
>> +      } else {
>> +         element_type = this;
>> +         array_len = 1;
>> +      }
>> +
>> +      if (row_major) {
>> +         vec_type = get_instance(element_type->base_type,
>> +                                 element_type->matrix_columns, 1);
>> +
>> +         array_len *= element_type->vector_elements;
>> +      } else {
>> +         vec_type = get_instance(element_type->base_type,
>> +                                 element_type->vector_elements, 1);
>> +         array_len *= element_type->matrix_columns;
>> +      }
>> +      const glsl_type *array_type = glsl_type::get_array_instance(vec_type,
>> +                                                                  array_len);
>> +
>> +      return array_type->std430_size(false);
>> +   }
>> +
>> +   if (this->is_array()) {
>> +      if (this->fields.array->is_record())
>> +         return this->length * this->fields.array->std430_size(row_major);
>> +      else
>> +         return this->length * this->fields.array->std430_base_alignment(row_major);
>> +   }
>> +
>> +   if (this->is_record() || this->is_interface()) {
>> +      unsigned size = 0;
>> +      unsigned max_align = 0;
>> +
>> +      for (unsigned i = 0; i < this->length; i++) {
>> +         bool field_row_major = row_major;
>> +         const enum glsl_matrix_layout matrix_layout =
>> +            glsl_matrix_layout(this->fields.structure[i].matrix_layout);
>> +         if (matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR) {
>> +            field_row_major = true;
>> +         } else if (matrix_layout == GLSL_MATRIX_LAYOUT_COLUMN_MAJOR) {
>> +            field_row_major = false;
>> +         }
>> +
>> +         const struct glsl_type *field_type = this->fields.structure[i].type;
>> +         unsigned align = field_type->std430_base_alignment(field_row_major);
>> +         size = glsl_align(size, align);
>> +         size += field_type->std430_size(field_row_major);
>> +
>> +         max_align = MAX2(align, max_align);
>> +      }
>> +      size = glsl_align(size, max_align);
>> +      return size;
>> +   }
>> +
>> +   assert(!"not reached");
>> +   return -1;
>> +}
>>  
>>  unsigned
>>  glsl_type::count_attribute_slots() const
>> diff --git a/src/glsl/glsl_types.h b/src/glsl/glsl_types.h
>> index 02a398f..5a6548d 100644
>> --- a/src/glsl/glsl_types.h
>> +++ b/src/glsl/glsl_types.h
>> @@ -326,6 +326,25 @@ struct glsl_type {
>>     unsigned std140_size(bool row_major) const;
>>  
>>     /**
>> +    * Alignment in bytes of the start of this type in a std430 shader
>> +    * storage block.
>> +    */
>> +   unsigned std430_base_alignment(bool row_major) const;
>> +
>> +   /**
>> +    * Calculate array stride in bytes of this type in a std430 shader storage
>> +    * block.
>> +    */
>> +   unsigned std430_array_stride(bool row_major) const;
>> +
>> +   /**
>> +    * Size in bytes of this type in a std430 shader storage block.
>> +    *
>> +    * Note that this is not GL_BUFFER_SIZE
>> +    */
>> +   unsigned std430_size(bool row_major) const;
>> +
>> +   /**
>>      * \brief Can this type be implicitly converted to another?
>>      *
>>      * \return True if the types are identical or if this type can be converted
>> -- 
>> 1.9.1
>>
> 


More information about the mesa-dev mailing list