case GLSL_MATRIX_LAYOUT_COLUMN_MAJOR:
return false;
case GLSL_MATRIX_LAYOUT_ROW_MAJOR:
- return matrix || deref->type->is_record();
+ return matrix || deref->type->without_array()->is_record();
}
unreachable("invalid matrix layout");
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);
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
* 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
deref = deref_array->array->as_dereference();
break;
} else {
- array_stride = deref_array->type->std140_size(row_major);
+ /* Whether or not the field is row-major (because it might be a
+ * bvec2 or something) does not affect the array itself. We need
+ * to know whether an array element in its entirety is row-major.
+ */
+ const bool array_row_major =
+ is_dereferenced_thing_row_major(deref_array);
+
+ array_stride = deref_array->type->std140_size(array_row_major);
array_stride = glsl_align(array_stride, 16);
}
const glsl_type *struct_type = deref_record->record->type;
unsigned intra_struct_offset = 0;
- 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(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(field_row_major);
+
+ /* If the field just examined was itself a structure, apply rule
+ * #9:
+ *
+ * "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 (type->without_array()->is_record()) {
+ intra_struct_offset = glsl_align(intra_struct_offset,
+ field_align);
+
+ }
}
- const_offset = glsl_align(const_offset, max_field_align);
const_offset += intra_struct_offset;
deref = deref_record->record->as_dereference();
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;
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;
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);
}
element);
emit_ubo_loads(element_deref, base_offset,
deref_offset + i * array_stride,
- row_major);
+ row_major, 1);
}
return;
}
/* 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;
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 =
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)));
}