void program_resource_visitor::recursion(const glsl_type *t, char **name, size_t name_length, bool row_major, const glsl_type *record_type, bool last_field) { /* Records need to have each field processed individually. * * Arrays of records need to have each array element processed * individually, then each field of the resulting array elements processed * individually. */ if (t->is_record() || t->is_interface()) { if (record_type == NULL && t->is_record()) record_type = t; for (unsigned i = 0; i < t->length; i++) { const char *field = t->fields.structure[i].name; size_t new_length = name_length; if (t->fields.structure[i].type->is_record()) this->visit_field(&t->fields.structure[i]); /* Append '.field' to the current variable name. */ if (name_length == 0) { ralloc_asprintf_rewrite_tail(name, &new_length, "%s", field); } else { ralloc_asprintf_rewrite_tail(name, &new_length, ".%s", field); } /* The layout of structures at the top level of the block is set * during parsing. For matrices contained in multiple levels of * structures in the block, the inner structures have no layout. * These cases must potentially inherit the layout from the outer * levels. */ bool field_row_major = row_major; const enum glsl_matrix_layout matrix_layout = glsl_matrix_layout(t->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; } recursion(t->fields.structure[i].type, name, new_length, field_row_major, record_type, (i + 1) == t->length); /* Only the first leaf-field of the record gets called with the * record type pointer. */ record_type = NULL; } } else if (t->is_array() && (t->fields.array->is_record() || t->fields.array->is_interface())) { if (record_type == NULL && t->fields.array->is_record()) record_type = t->fields.array; for (unsigned i = 0; i < t->length; i++) { size_t new_length = name_length; /* Append the subscript to the current variable name */ ralloc_asprintf_rewrite_tail(name, &new_length, "[%u]", i); recursion(t->fields.array, name, new_length, row_major, record_type, (i + 1) == t->length); /* Only the first leaf-field of the record gets called with the * record type pointer. */ record_type = NULL; } } else { this->visit_field(t, *name, row_major, record_type, last_field); } }
/** * Determine if a thing being dereferenced is row-major * * There is some trickery here. * * If the thing being dereferenced is a member of uniform block \b without an * instance name, then the name of the \c ir_variable is the field name of an * interface type. If this field is row-major, then the thing referenced is * row-major. * * If the thing being dereferenced is a member of uniform block \b with an * instance name, then the last dereference in the tree will be an * \c ir_dereference_record. If that record field is row-major, then the * thing referenced is row-major. */ bool lower_buffer_access::is_dereferenced_thing_row_major(const ir_rvalue *deref) { bool matrix = false; const ir_rvalue *ir = deref; while (true) { matrix = matrix || ir->type->without_array()->is_matrix(); switch (ir->ir_type) { case ir_type_dereference_array: { const ir_dereference_array *const array_deref = (const ir_dereference_array *) ir; ir = array_deref->array; break; } case ir_type_dereference_record: { const ir_dereference_record *const record_deref = (const ir_dereference_record *) ir; ir = record_deref->record; const int idx = ir->type->field_index(record_deref->field); assert(idx >= 0); const enum glsl_matrix_layout matrix_layout = glsl_matrix_layout(ir->type->fields.structure[idx].matrix_layout); switch (matrix_layout) { case GLSL_MATRIX_LAYOUT_INHERITED: break; case GLSL_MATRIX_LAYOUT_COLUMN_MAJOR: return false; case GLSL_MATRIX_LAYOUT_ROW_MAJOR: return matrix || deref->type->without_array()->is_record(); } break; } case ir_type_dereference_variable: { const ir_dereference_variable *const var_deref = (const ir_dereference_variable *) ir; const enum glsl_matrix_layout matrix_layout = glsl_matrix_layout(var_deref->var->data.matrix_layout); switch (matrix_layout) { case GLSL_MATRIX_LAYOUT_INHERITED: { /* For interface block matrix variables we handle inherited * layouts at HIR generation time, but we don't do that for shared * variables, which are always column-major */ ir_variable *var = deref->variable_referenced(); assert((var->is_in_buffer_block() && !matrix) || var->data.mode == ir_var_shader_shared); return false; } case GLSL_MATRIX_LAYOUT_COLUMN_MAJOR: return false; case GLSL_MATRIX_LAYOUT_ROW_MAJOR: return matrix || deref->type->without_array()->is_record(); } unreachable("invalid matrix layout"); break; } default: return false; } } /* The tree must have ended with a dereference that wasn't an * ir_dereference_variable. That is invalid, and it should be impossible. */ unreachable("invalid dereference tree"); return false; }
void program_resource_visitor::recursion(const glsl_type *t, char **name, size_t name_length, bool row_major, const glsl_type *record_type, const unsigned packing, bool last_field, unsigned record_array_count, const glsl_struct_field *named_ifc_member) { /* Records need to have each field processed individually. * * Arrays of records need to have each array element processed * individually, then each field of the resulting array elements processed * individually. */ if (t->is_interface() && named_ifc_member) { ralloc_asprintf_rewrite_tail(name, &name_length, ".%s", named_ifc_member->name); recursion(named_ifc_member->type, name, name_length, row_major, NULL, packing, false, record_array_count, NULL); } else if (t->is_record() || t->is_interface()) { if (record_type == NULL && t->is_record()) record_type = t; if (t->is_record()) this->enter_record(t, *name, row_major, packing); for (unsigned i = 0; i < t->length; i++) { const char *field = t->fields.structure[i].name; size_t new_length = name_length; if (t->fields.structure[i].type->is_record()) this->visit_field(&t->fields.structure[i]); if (t->is_interface() && t->fields.structure[i].offset != -1) this->set_buffer_offset(t->fields.structure[i].offset); /* Append '.field' to the current variable name. */ if (name_length == 0) { ralloc_asprintf_rewrite_tail(name, &new_length, "%s", field); } else { ralloc_asprintf_rewrite_tail(name, &new_length, ".%s", field); } /* The layout of structures at the top level of the block is set * during parsing. For matrices contained in multiple levels of * structures in the block, the inner structures have no layout. * These cases must potentially inherit the layout from the outer * levels. */ bool field_row_major = row_major; const enum glsl_matrix_layout matrix_layout = glsl_matrix_layout(t->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; } recursion(t->fields.structure[i].type, name, new_length, field_row_major, record_type, packing, (i + 1) == t->length, record_array_count, NULL); /* Only the first leaf-field of the record gets called with the * record type pointer. */ record_type = NULL; } if (t->is_record()) { (*name)[name_length] = '\0'; this->leave_record(t, *name, row_major, packing); } } else if (t->without_array()->is_record() || t->without_array()->is_interface() || (t->is_array() && t->fields.array->is_array())) { if (record_type == NULL && t->fields.array->is_record()) record_type = t->fields.array; unsigned length = t->length; /* Shader storage block unsized arrays: add subscript [0] to variable * names */ if (t->is_unsized_array()) length = 1; record_array_count *= length; for (unsigned i = 0; i < length; i++) { size_t new_length = name_length; /* Append the subscript to the current variable name */ ralloc_asprintf_rewrite_tail(name, &new_length, "[%u]", i); recursion(t->fields.array, name, new_length, row_major, record_type, packing, (i + 1) == t->length, record_array_count, named_ifc_member); /* Only the first leaf-field of the record gets called with the * record type pointer. */ record_type = NULL; } } else { this->set_record_array_count(record_array_count); this->visit_field(t, *name, row_major, record_type, packing, last_field); } }
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->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(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; 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->std140_base_alignment(field_row_major); size = glsl_align(size, align); size += field_type->std140_size(field_row_major); max_align = MAX2(align, max_align); if (field_type->is_record() && (i + 1 < this->length)) size = glsl_align(size, 16); } size = glsl_align(size, MAX2(max_align, 16)); return size; } assert(!"not reached"); return -1; }