[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