- /* Calculate the offset to the start of the region of the UBO
- * dereferenced by *rvalue. This may be a variable offset if an
- * array dereference has a variable index.
- */
- while (deref) {
- switch (deref->ir_type) {
- case ir_type_dereference_variable: {
- *const_offset += ubo_var->Offset;
- deref = NULL;
- break;
- }
-
- case ir_type_dereference_array: {
- ir_dereference_array *deref_array = (ir_dereference_array *) deref;
- unsigned array_stride;
- if (deref_array->array->type->is_vector()) {
- /* We get this when storing or loading a component out of a vector
- * with a non-constant index. This happens for v[i] = f where v is
- * a vector (or m[i][j] = f where m is a matrix). If we don't
- * lower that here, it gets turned into v = vector_insert(v, i,
- * f), which loads the entire vector, modifies one component and
- * then write the entire thing back. That breaks if another
- * thread or SIMD channel is modifying the same vector.
- */
- array_stride = 4;
- if (deref_array->array->type->is_double())
- array_stride *= 2;
- } else if (deref_array->array->type->is_matrix() && *row_major) {
- /* When loading a vector out of a row major matrix, the
- * step between the columns (vectors) is the size of a
- * float, while the step between the rows (elements of a
- * 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->without_array()->is_interface()) {
- /* We're processing an array dereference of an interface instance
- * array. The thing being dereferenced *must* be a variable
- * dereference because interfaces cannot be embedded in other
- * types. In terms of calculating the offsets for the lowering
- * pass, we don't care about the array index. All elements of an
- * interface instance array will have the same offsets relative to
- * the base of the block that backs them.
- */
- deref = deref_array->array->as_dereference();
- break;
- } else {
- /* 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);
-
- /* The array type will give the correct interface packing
- * information
- */
- if (packing == GLSL_INTERFACE_PACKING_STD430) {
- array_stride = deref_array->type->std430_array_stride(array_row_major);
- } else {
- array_stride = deref_array->type->std140_size(array_row_major);
- array_stride = glsl_align(array_stride, 16);
- }
- }
-
- ir_rvalue *array_index = deref_array->array_index;
- if (array_index->type->base_type == GLSL_TYPE_INT)
- array_index = i2u(array_index);
-
- ir_constant *const_index =
- array_index->constant_expression_value(NULL);
- if (const_index) {
- *const_offset += array_stride * const_index->value.u[0];
- } else {
- *offset = add(*offset,
- mul(array_index,
- new(mem_ctx) ir_constant(array_stride)));
- }
- deref = deref_array->array->as_dereference();
- break;
- }
-
- case ir_type_dereference_record: {
- ir_dereference_record *deref_record = (ir_dereference_record *) deref;
- const glsl_type *struct_type = deref_record->record->type;
- unsigned intra_struct_offset = 0;
-
- for (unsigned int i = 0; i < struct_type->length; i++) {
- const glsl_type *type = struct_type->fields.structure[i].type;
-
- 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 = 0;
-
- if (packing == GLSL_INTERFACE_PACKING_STD430)
- field_align = type->std430_base_alignment(field_row_major);
- else
- field_align = type->std140_base_alignment(field_row_major);
-
- intra_struct_offset = glsl_align(intra_struct_offset, field_align);
-
- if (strcmp(struct_type->fields.structure[i].name,
- deref_record->field) == 0)
- break;
-
- if (packing == GLSL_INTERFACE_PACKING_STD430)
- intra_struct_offset += type->std430_size(field_row_major);
- else
- 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 += intra_struct_offset;
- deref = deref_record->record->as_dereference();
- break;
- }
-
- case ir_type_swizzle: {
- ir_swizzle *deref_swizzle = (ir_swizzle *) deref;
-
- assert(deref_swizzle->mask.num_components == 1);
-
- *const_offset += deref_swizzle->mask.x * sizeof(int);
- deref = deref_swizzle->val->as_dereference();
- break;
- }
-
- default:
- assert(!"not reached");
- deref = NULL;
- break;
- }
- }