glsl: Add std430 related member functions to glsl_type class

They are used to calculate size, base alignment and array stride values
for a glsl_type following std430 rules.

v2:
- Paste OpenGL 4.3 spec wording as it mentions stride of array. (Jordan)

Signed-off-by: Samuel Iglesias Gonsalvez <siglesias@igalia.com>
Reviewed-by: Jordan Justen <jordan.l.justen@intel.com>
Reviewed-by: Kristian Høgsberg <krh@bitplanet.net>
This commit is contained in:
Samuel Iglesias Gonsalvez 2015-08-31 07:44:47 +02:00
parent a40f917c4b
commit 35476c2bae
2 changed files with 226 additions and 0 deletions

View file

@ -1388,6 +1388,213 @@ 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 and
* stride 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.
*/
/* (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 and
* stride 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

View file

@ -333,6 +333,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?
*