+const glsl_type *
+glsl_type::get_explicit_std430_type(bool row_major) const
+{
+ if (this->is_vector() || this->is_scalar()) {
+ return this;
+ } else if (this->is_matrix()) {
+ const glsl_type *vec_type;
+ if (row_major)
+ vec_type = get_instance(this->base_type, this->matrix_columns, 1);
+ else
+ vec_type = get_instance(this->base_type, this->vector_elements, 1);
+ unsigned stride = vec_type->std430_array_stride(false);
+ return get_instance(this->base_type, this->vector_elements,
+ this->matrix_columns, stride, row_major);
+ } else if (this->is_array()) {
+ const glsl_type *elem_type =
+ this->fields.array->get_explicit_std430_type(row_major);
+ unsigned stride = this->fields.array->std430_array_stride(row_major);
+ return get_array_instance(elem_type, this->length, stride);
+ } else if (this->is_struct() || this->is_interface()) {
+ glsl_struct_field *fields = new glsl_struct_field[this->length];
+ unsigned offset = 0;
+ for (unsigned i = 0; i < length; i++) {
+ fields[i] = this->fields.structure[i];
+
+ bool field_row_major = row_major;
+ if (fields[i].matrix_layout == GLSL_MATRIX_LAYOUT_COLUMN_MAJOR) {
+ field_row_major = false;
+ } else if (fields[i].matrix_layout == GLSL_MATRIX_LAYOUT_ROW_MAJOR) {
+ field_row_major = true;
+ }
+ fields[i].type =
+ fields[i].type->get_explicit_std430_type(field_row_major);
+
+ unsigned fsize = fields[i].type->std430_size(field_row_major);
+ unsigned falign = fields[i].type->std430_base_alignment(field_row_major);
+ /* From the GLSL 460 spec section "Uniform and Shader Storage Block
+ * Layout Qualifiers":
+ *
+ * "The actual offset of a member is computed as follows: If
+ * offset was declared, start with that offset, otherwise start
+ * with the next available offset. If the resulting offset is not
+ * a multiple of the actual alignment, increase it to the first
+ * offset that is a multiple of the actual alignment. This results
+ * in the actual offset the member will have."
+ */
+ if (fields[i].offset >= 0) {
+ assert((unsigned)fields[i].offset >= offset);
+ offset = fields[i].offset;
+ }
+ offset = glsl_align(offset, falign);
+ fields[i].offset = offset;
+ offset += fsize;
+ }
+
+ const glsl_type *type;
+ if (this->is_struct())
+ type = get_struct_instance(fields, this->length, this->name);
+ else
+ type = get_interface_instance(fields, this->length,
+ (enum glsl_interface_packing)this->interface_packing,
+ this->interface_row_major,
+ this->name);
+
+ delete[] fields;
+ return type;
+ } else {
+ unreachable("Invalid type for SSBO");
+ }
+}
+
+const glsl_type *
+glsl_type::get_explicit_interface_type(bool supports_std430) const
+{
+ enum glsl_interface_packing packing =
+ this->get_internal_ifc_packing(supports_std430);
+ if (packing == GLSL_INTERFACE_PACKING_STD140) {
+ return this->get_explicit_std140_type(this->interface_row_major);
+ } else {
+ assert(packing == GLSL_INTERFACE_PACKING_STD430);
+ return this->get_explicit_std430_type(this->interface_row_major);
+ }
+}
+
+static unsigned
+explicit_type_scalar_byte_size(const glsl_type *type)
+{
+ if (type->base_type == GLSL_TYPE_BOOL)
+ return 4;
+ else
+ return glsl_base_type_get_bit_size(type->base_type) / 8;
+}
+
+/* This differs from get_explicit_std430_type() in that it:
+ * - can size arrays slightly smaller ("stride * (len - 1) + elem_size" instead
+ * of "stride * len")
+ * - consumes a glsl_type_size_align_func which allows 8 and 16-bit values to be
+ * packed more tightly
+ * - overrides any struct field offsets but get_explicit_std430_type() tries to
+ * respect any existing ones
+ */
+const glsl_type *
+glsl_type::get_explicit_type_for_size_align(glsl_type_size_align_func type_info,
+ unsigned *size, unsigned *alignment) const
+{
+ if (this->is_scalar()) {
+ type_info(this, size, alignment);
+ assert(*size == explicit_type_scalar_byte_size(this));
+ assert(*alignment == explicit_type_scalar_byte_size(this));
+ return this;
+ } else if (this->is_vector()) {
+ type_info(this, size, alignment);
+ assert(*alignment % explicit_type_scalar_byte_size(this) == 0);
+ return glsl_type::get_instance(this->base_type, this->vector_elements,
+ 1, 0, false, *alignment);
+ } else if (this->is_array()) {
+ unsigned elem_size, elem_align;
+ const struct glsl_type *explicit_element =
+ this->fields.array->get_explicit_type_for_size_align(type_info, &elem_size, &elem_align);
+
+ unsigned stride = align(elem_size, elem_align);
+
+ *size = stride * (this->length - 1) + elem_size;
+ *alignment = elem_align;
+ return glsl_type::get_array_instance(explicit_element, this->length, stride);
+ } else if (this->is_struct() || this->is_interface()) {
+ struct glsl_struct_field *fields = (struct glsl_struct_field *)
+ malloc(sizeof(struct glsl_struct_field) * this->length);
+
+ *size = 0;
+ *alignment = 0;
+ for (unsigned i = 0; i < this->length; i++) {
+ fields[i] = this->fields.structure[i];
+ assert(fields[i].matrix_layout != GLSL_MATRIX_LAYOUT_ROW_MAJOR);
+
+ unsigned field_size, field_align;
+ fields[i].type =
+ fields[i].type->get_explicit_type_for_size_align(type_info, &field_size, &field_align);
+ field_align = this->packed ? 1 : field_align;
+ fields[i].offset = align(*size, field_align);
+
+ *size = fields[i].offset + field_size;
+ *alignment = MAX2(*alignment, field_align);
+ }
+
+ const glsl_type *type;
+ if (this->is_struct()) {
+ type = get_struct_instance(fields, this->length, this->name,
+ this->packed, *alignment);
+ } else {
+ assert(!this->packed);
+ type = get_interface_instance(fields, this->length,
+ (enum glsl_interface_packing)this->interface_packing,
+ this->interface_row_major,
+ this->name);
+ }
+ free(fields);
+ return type;
+ } else if (this->is_matrix()) {
+ unsigned col_size, col_align;
+ type_info(this->column_type(), &col_size, &col_align);
+ unsigned stride = align(col_size, col_align);
+
+ *size = this->matrix_columns * stride;
+ /* Matrix and column alignments match. See glsl_type::column_type() */
+ *alignment = col_align;
+ return glsl_type::get_instance(this->base_type, this->vector_elements,
+ this->matrix_columns, stride, false, *alignment);
+ } else {
+ unreachable("Unhandled type.");
+ }
+}
+