diff options
Diffstat (limited to 'src/glsl/lower_ubo_reference.cpp')
-rw-r--r-- | src/glsl/lower_ubo_reference.cpp | 57 |
1 files changed, 33 insertions, 24 deletions
diff --git a/src/glsl/lower_ubo_reference.cpp b/src/glsl/lower_ubo_reference.cpp index 43dd067fa8a..4ea4ccb03f2 100644 --- a/src/glsl/lower_ubo_reference.cpp +++ b/src/glsl/lower_ubo_reference.cpp @@ -140,7 +140,8 @@ public: void handle_rvalue(ir_rvalue **rvalue); void emit_ubo_loads(ir_dereference *deref, ir_variable *base_offset, - unsigned int deref_offset, bool row_major); + unsigned int deref_offset, bool row_major, + int matrix_columns); ir_expression *ubo_load(const struct glsl_type *type, ir_rvalue *offset); @@ -265,6 +266,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 = is_dereferenced_thing_row_major(deref); + int matrix_columns = 1; /* Calculate the offset to the start of the region of the UBO * dereferenced by *rvalue. This may be a variable offset if an @@ -288,6 +290,9 @@ lower_ubo_reference_visitor::handle_rvalue(ir_rvalue **rvalue) * vector) is handled below in emit_ubo_loads. */ array_stride = 4; + if (deref_array->array->type->is_double()) + array_stride *= 2; + matrix_columns = deref_array->array->type->matrix_columns; } else if (deref_array->type->is_interface()) { /* We're processing an array dereference of an interface instance * array. The thing being dereferenced *must* be a variable @@ -334,15 +339,6 @@ lower_ubo_reference_visitor::handle_rvalue(ir_rvalue **rvalue) const glsl_type *struct_type = deref_record->record->type; unsigned intra_struct_offset = 0; - /* glsl_type::std140_base_alignment doesn't grok interfaces. Use - * 16-bytes for the alignment because that is the general minimum of - * std140. - */ - const unsigned struct_alignment = struct_type->is_interface() - ? 16 - : struct_type->std140_base_alignment(row_major); - - for (unsigned int i = 0; i < struct_type->length; i++) { const glsl_type *type = struct_type->fields.structure[i].type; @@ -372,7 +368,7 @@ lower_ubo_reference_visitor::handle_rvalue(ir_rvalue **rvalue) */ if (type->without_array()->is_record()) { intra_struct_offset = glsl_align(intra_struct_offset, - struct_alignment); + field_align); } } @@ -405,7 +401,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, row_major); + emit_ubo_loads(deref, load_offset, const_offset, row_major, matrix_columns); *rvalue = deref; progress = true; @@ -436,7 +432,8 @@ void lower_ubo_reference_visitor::emit_ubo_loads(ir_dereference *deref, ir_variable *base_offset, unsigned int deref_offset, - bool row_major) + bool row_major, + int matrix_columns) { if (deref->type->is_record()) { unsigned int field_offset = 0; @@ -453,7 +450,7 @@ lower_ubo_reference_visitor::emit_ubo_loads(ir_dereference *deref, field->type->std140_base_alignment(row_major)); emit_ubo_loads(field_deref, base_offset, deref_offset + field_offset, - row_major); + row_major, 1); field_offset += field->type->std140_size(row_major); } @@ -472,7 +469,7 @@ lower_ubo_reference_visitor::emit_ubo_loads(ir_dereference *deref, element); emit_ubo_loads(element_deref, base_offset, deref_offset + i * array_stride, - row_major); + row_major, 1); } return; } @@ -488,14 +485,18 @@ lower_ubo_reference_visitor::emit_ubo_loads(ir_dereference *deref, /* For a row-major matrix, the next column starts at the next * element. */ - emit_ubo_loads(col_deref, base_offset, deref_offset + i * 4, - row_major); + int size_mul = deref->type->is_double() ? 8 : 4; + emit_ubo_loads(col_deref, base_offset, deref_offset + i * size_mul, + row_major, deref->type->matrix_columns); } else { /* std140 always rounds the stride of arrays (and matrices) to a - * vec4, so matrices are always 16 between columns/rows. + * vec4, so matrices are always 16 between columns/rows. With + * doubles, they will be 32 apart when there are more than 2 rows. */ - emit_ubo_loads(col_deref, base_offset, deref_offset + i * 16, - row_major); + int size_mul = (deref->type->is_double() && + deref->type->vector_elements > 2) ? 32 : 16; + emit_ubo_loads(col_deref, base_offset, deref_offset + i * size_mul, + row_major, deref->type->matrix_columns); } } return; @@ -510,16 +511,24 @@ lower_ubo_reference_visitor::emit_ubo_loads(ir_dereference *deref, base_ir->insert_before(assign(deref->clone(mem_ctx, NULL), ubo_load(deref->type, offset))); } else { + unsigned N = deref->type->is_double() ? 8 : 4; + /* We're dereffing a column out of a row-major matrix, so we * gather the vector from each stored row. */ - assert(deref->type->base_type == GLSL_TYPE_FLOAT); + assert(deref->type->base_type == GLSL_TYPE_FLOAT || + deref->type->base_type == GLSL_TYPE_DOUBLE); /* Matrices, row_major or not, are stored as if they were * arrays of vectors of the appropriate size in std140. * Arrays have their strides rounded up to a vec4, so the - * matrix stride is always 16. + * matrix stride is always 16. However a double matrix may either be 16 + * or 32 depending on the number of columns. */ - unsigned matrix_stride = 16; + assert(matrix_columns <= 4); + unsigned matrix_stride = glsl_align(matrix_columns * N, 16); + + const glsl_type *ubo_type = deref->type->base_type == GLSL_TYPE_FLOAT ? + glsl_type::float_type : glsl_type::double_type; for (unsigned i = 0; i < deref->type->vector_elements; i++) { ir_rvalue *chan_offset = @@ -527,7 +536,7 @@ lower_ubo_reference_visitor::emit_ubo_loads(ir_dereference *deref, new(mem_ctx) ir_constant(deref_offset + i * matrix_stride)); base_ir->insert_before(assign(deref->clone(mem_ctx, NULL), - ubo_load(glsl_type::float_type, + ubo_load(ubo_type, chan_offset), (1U << i))); } |