diff options
Diffstat (limited to 'mesalib/src/glsl/glsl_types.cpp')
-rw-r--r-- | mesalib/src/glsl/glsl_types.cpp | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/mesalib/src/glsl/glsl_types.cpp b/mesalib/src/glsl/glsl_types.cpp index 8a34b8eb0..3d7866058 100644 --- a/mesalib/src/glsl/glsl_types.cpp +++ b/mesalib/src/glsl/glsl_types.cpp @@ -628,3 +628,223 @@ glsl_type::can_implicitly_convert_to(const glsl_type *desired) const && this->is_integer() && this->vector_elements == desired->vector_elements; } + +unsigned +glsl_type::std140_base_alignment(bool row_major) const +{ + /* (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 4; + case 2: + return 8; + case 3: + case 4: + return 16; + } + } + + /* (4) If the member is an array of scalars or vectors, the base alignment + * and array stride are set to match the base alignment of a single + * array element, according to rules (1), (2), and (3), and rounded up + * to the base alignment of a vec4. The array may have padding at the + * end; the base offset of the member following the array is rounded up + * to the next multiple of the base alignment. + * + * (6) If the member is an array of <S> column-major matrices with <C> + * columns and <R> rows, the matrix is stored identically to a row of + * <S>*<C> column vectors with <R> components each, according to rule + * (4). + * + * (8) If the member is an array of <S> row-major matrices with <C> columns + * and <R> rows, the matrix is stored identically to a row of <S>*<R> + * row vectors with <C> components each, according to rule (4). + * + * (10) If the member is an array of <S> structures, the <S> elements of + * the array are laid out in order, according to rule (9). + */ + if (this->is_array()) { + if (this->fields.array->is_scalar() || + this->fields.array->is_vector() || + this->fields.array->is_matrix()) { + return MAX2(this->fields.array->std140_base_alignment(row_major), 16); + } else { + assert(this->fields.array->is_record()); + return this->fields.array->std140_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; + if (row_major) { + vec_type = get_instance(GLSL_TYPE_FLOAT, this->vector_elements, 1); + } else { + vec_type = get_instance(GLSL_TYPE_FLOAT, this->matrix_columns, 1); + } + + return vec_type->std140_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 = 16; + for (unsigned i = 0; i < this->length; i++) { + const struct glsl_type *field_type = this->fields.structure[i].type; + base_alignment = MAX2(base_alignment, + field_type->std140_base_alignment(row_major)); + } + return base_alignment; + } + + assert(!"not reached"); + return -1; +} + +static unsigned +align(unsigned val, unsigned align) +{ + return (val + align - 1) / align * align; +} + +unsigned +glsl_type::std140_size(bool row_major) const +{ + /* (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()) { + return this->vector_elements * 4; + } + + /* (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). + * + * (6) If the member is an array of <S> column-major matrices with <C> + * columns and <R> rows, the matrix is stored identically to a row of + * <S>*<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). + * + * (8) If the member is an array of <S> row-major matrices with <C> columns + * and <R> rows, the matrix is stored identically to a row of <S>*<R> + * row vectors with <C> components each, according to rule (4). + */ + if (this->is_matrix() || (this->is_array() && + this->fields.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(GLSL_TYPE_FLOAT, + element_type->matrix_columns, 1); + array_len *= element_type->vector_elements; + } else { + vec_type = get_instance(GLSL_TYPE_FLOAT, + 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->std140_size(false); + } + + /* (4) If the member is an array of scalars or vectors, the base alignment + * and array stride are set to match the base alignment of a single + * array element, according to rules (1), (2), and (3), and rounded up + * to the base alignment of a vec4. The array may have padding at the + * end; the base offset of the member following the array is rounded up + * to the next multiple of the base alignment. + * + * (10) If the member is an array of <S> structures, the <S> elements of + * the array are laid out in order, according to rule (9). + */ + if (this->is_array()) { + if (this->fields.array->is_record()) { + return this->length * this->fields.array->std140_size(row_major); + } else { + unsigned element_base_align = + this->fields.array->std140_base_alignment(row_major); + return this->length * MAX2(element_base_align, 16); + } + } + + /* (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 size = 0; + for (unsigned i = 0; i < this->length; i++) { + const struct glsl_type *field_type = this->fields.structure[i].type; + unsigned align = field_type->std140_base_alignment(row_major); + size = (size + align - 1) / align * align; + size += field_type->std140_size(row_major); + } + size = align(size, + this->fields.structure[0].type->std140_base_alignment(row_major)); + return size; + } + + assert(!"not reached"); + return -1; +} |