[Mesa-dev] [PATCH v5 25/70] glsl: Add std430 related member functions to glsl_type class
Jordan Justen
jordan.l.justen at intel.com
Tue Sep 15 12:03:49 PDT 2015
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 guess I've looked at this enough at this point to say
Reviewed-by: Jordan Justen <jordan.l.justen at intel.com>
> >
> >> + * 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