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

Samuel Iglesias Gonsálvez siglesias at igalia.com
Tue Sep 15 22:14:03 PDT 2015



On 15/09/15 21:03, Jordan Justen wrote:
> On 2015-09-10 22:48:55, Samuel Iglesias Gonsálvez wrote:
>> 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.
> 
> Well, my concern was that the 'and stride' part might mean that vec3
> array stride should be 12 rather than 16. But, I tested NVidia, and
> they seem to use a stride of 16 for a vec3 array. So, I think your
> interpretation is correct.
> 
> I still say we could still use an update to idr's ubo-lolz branch to
> handle ssbo and std430, but this would also involve extending shader
> runner to better support ssbo.
> 

I have already done that work. I have a ubo-lolz modified branch [0]
with an initial support of SSBOs and std430.

About ssbo support for shader_runner, I have sent a couple of patches to
piglit [1] and I plan to send a new version of them today with a generic
approach (so it is not only for SSBOs but for other interface types
defined in ARB_program_interface_query extension).

FWIW, I executed [0] with no errors during 15 minutes.

[0] https://github.com/Igalia/piglit.git
    Branch: ssbo-random-tests-std430-v2
[1] http://lists.freedesktop.org/archives/piglit/2015-September/017080.html

> I guess I've looked at this enough at this point to say
> 
> Reviewed-by: Jordan Justen <jordan.l.justen at intel.com>
> 

Thanks!

Sam

>>>
>>>> +    * 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