diff options
Diffstat (limited to 'src/glsl/lower_ubo_reference.cpp')
-rw-r--r-- | src/glsl/lower_ubo_reference.cpp | 135 |
1 files changed, 120 insertions, 15 deletions
diff --git a/src/glsl/lower_ubo_reference.cpp b/src/glsl/lower_ubo_reference.cpp index 2890d3e74d8..48675da2f2b 100644 --- a/src/glsl/lower_ubo_reference.cpp +++ b/src/glsl/lower_ubo_reference.cpp @@ -40,6 +40,96 @@ using namespace ir_builder; +/** + * 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. + */ +static bool +is_dereferenced_thing_row_major(const ir_dereference *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: + assert(!matrix); + return false; + case GLSL_MATRIX_LAYOUT_COLUMN_MAJOR: + return false; + case GLSL_MATRIX_LAYOUT_ROW_MAJOR: + return matrix || deref->type->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; +} + namespace { class lower_ubo_reference_visitor : public ir_rvalue_enter_visitor { public: @@ -50,7 +140,7 @@ public: void handle_rvalue(ir_rvalue **rvalue); void emit_ubo_loads(ir_dereference *deref, ir_variable *base_offset, - unsigned int deref_offset); + unsigned int deref_offset, bool row_major); ir_expression *ubo_load(const struct glsl_type *type, ir_rvalue *offset); @@ -174,7 +264,7 @@ lower_ubo_reference_visitor::handle_rvalue(ir_rvalue **rvalue) ir_rvalue *offset = new(mem_ctx) ir_constant(0u); unsigned const_offset = 0; - bool row_major = ubo_var->RowMajor; + bool row_major = is_dereferenced_thing_row_major(deref); /* Calculate the offset to the start of the region of the UBO * dereferenced by *rvalue. This may be a variable offset if an @@ -240,14 +330,24 @@ lower_ubo_reference_visitor::handle_rvalue(ir_rvalue **rvalue) unsigned max_field_align = 16; for (unsigned int i = 0; i < struct_type->length; i++) { const glsl_type *type = struct_type->fields.structure[i].type; - unsigned field_align = type->std140_base_alignment(row_major); + + ir_dereference_record *field_deref = + new(mem_ctx) ir_dereference_record(deref_record->record, + struct_type->fields.structure[i].name); + const bool field_row_major = + is_dereferenced_thing_row_major(field_deref); + + ralloc_free(field_deref); + + unsigned field_align = type->std140_base_alignment(field_row_major); + max_field_align = MAX2(field_align, max_field_align); intra_struct_offset = glsl_align(intra_struct_offset, field_align); if (strcmp(struct_type->fields.structure[i].name, deref_record->field) == 0) break; - intra_struct_offset += type->std140_size(row_major); + intra_struct_offset += type->std140_size(field_row_major); } const_offset = glsl_align(const_offset, max_field_align); @@ -279,7 +379,7 @@ lower_ubo_reference_visitor::handle_rvalue(ir_rvalue **rvalue) base_ir->insert_before(assign(load_offset, offset)); deref = new(mem_ctx) ir_dereference_variable(load_var); - emit_ubo_loads(deref, load_offset, const_offset); + emit_ubo_loads(deref, load_offset, const_offset, row_major); *rvalue = deref; progress = true; @@ -309,7 +409,8 @@ lower_ubo_reference_visitor::ubo_load(const glsl_type *type, void lower_ubo_reference_visitor::emit_ubo_loads(ir_dereference *deref, ir_variable *base_offset, - unsigned int deref_offset) + unsigned int deref_offset, + bool row_major) { if (deref->type->is_record()) { unsigned int field_offset = 0; @@ -323,18 +424,19 @@ lower_ubo_reference_visitor::emit_ubo_loads(ir_dereference *deref, field_offset = glsl_align(field_offset, - field->type->std140_base_alignment(ubo_var->RowMajor)); + field->type->std140_base_alignment(row_major)); - emit_ubo_loads(field_deref, base_offset, deref_offset + field_offset); + emit_ubo_loads(field_deref, base_offset, deref_offset + field_offset, + row_major); - field_offset += field->type->std140_size(ubo_var->RowMajor); + field_offset += field->type->std140_size(row_major); } return; } if (deref->type->is_array()) { unsigned array_stride = - glsl_align(deref->type->fields.array->std140_size(ubo_var->RowMajor), + glsl_align(deref->type->fields.array->std140_size(row_major), 16); for (unsigned i = 0; i < deref->type->length; i++) { @@ -343,7 +445,8 @@ lower_ubo_reference_visitor::emit_ubo_loads(ir_dereference *deref, new(mem_ctx) ir_dereference_array(deref->clone(mem_ctx, NULL), element); emit_ubo_loads(element_deref, base_offset, - deref_offset + i * array_stride); + deref_offset + i * array_stride, + row_major); } return; } @@ -355,16 +458,18 @@ lower_ubo_reference_visitor::emit_ubo_loads(ir_dereference *deref, new(mem_ctx) ir_dereference_array(deref->clone(mem_ctx, NULL), col); - if (ubo_var->RowMajor) { + if (row_major) { /* For a row-major matrix, the next column starts at the next * element. */ - emit_ubo_loads(col_deref, base_offset, deref_offset + i * 4); + emit_ubo_loads(col_deref, base_offset, deref_offset + i * 4, + row_major); } else { /* std140 always rounds the stride of arrays (and matrices) to a * vec4, so matrices are always 16 between columns/rows. */ - emit_ubo_loads(col_deref, base_offset, deref_offset + i * 16); + emit_ubo_loads(col_deref, base_offset, deref_offset + i * 16, + row_major); } } return; @@ -373,7 +478,7 @@ lower_ubo_reference_visitor::emit_ubo_loads(ir_dereference *deref, assert(deref->type->is_scalar() || deref->type->is_vector()); - if (!ubo_var->RowMajor) { + if (!row_major) { ir_rvalue *offset = add(base_offset, new(mem_ctx) ir_constant(deref_offset)); base_ir->insert_before(assign(deref->clone(mem_ctx, NULL), |