virtual void leave_record(const glsl_type *type, const char *, bool row_major, const unsigned packing) { assert(type->is_record()); if (this->buffer_block_index == -1) return; if (packing == GLSL_INTERFACE_PACKING_STD430) this->ubo_byte_offset = glsl_align( this->ubo_byte_offset, type->std430_base_alignment(row_major)); else this->ubo_byte_offset = glsl_align( this->ubo_byte_offset, type->std140_base_alignment(row_major)); }
virtual void visit_field(const glsl_type *type, const char *name, bool row_major, const glsl_type *record_type) { assert(this->index < this->num_variables); gl_uniform_buffer_variable *v = &this->variables[this->index++]; v->Name = ralloc_strdup(mem_ctx, name); v->Type = type; v->RowMajor = row_major; if (this->is_array_instance) { v->IndexName = ralloc_strdup(mem_ctx, name); char *open_bracket = strchr(v->IndexName, '['); assert(open_bracket != NULL); char *close_bracket = strchr(open_bracket, ']'); assert(close_bracket != NULL); /* Length of the tail without the ']' but with the NUL. */ unsigned len = strlen(close_bracket + 1) + 1; memmove(open_bracket, close_bracket + 1, len); } else { v->IndexName = v->Name; } const unsigned alignment = record_type ? record_type->std140_base_alignment(!!v->RowMajor) : type->std140_base_alignment(!!v->RowMajor); unsigned size = type->std140_size(!!v->RowMajor); this->offset = glsl_align(this->offset, alignment); v->Offset = this->offset; this->offset += size; /* From the GL_ARB_uniform_buffer_object spec: * * "For uniform blocks laid out according to [std140] rules, the * minimum buffer object size returned by the * UNIFORM_BLOCK_DATA_SIZE query is derived by taking the offset of * the last basic machine unit consumed by the last uniform of the * uniform block (including any end-of-array or end-of-structure * padding), adding one, and rounding up to the next multiple of * the base alignment required for a vec4." */ this->buffer_size = glsl_align(this->offset, 16); }
virtual void leave_record(const glsl_type *type, const char *, bool row_major) { assert(type->is_record()); if (this->ubo_block_index == -1) return; this->ubo_byte_offset = glsl_align( this->ubo_byte_offset, type->std140_base_alignment(row_major)); }
virtual void visit_field(const glsl_struct_field *field) { /* FINISHME: When support for doubles (dvec4, etc.) is added to the * FINISHME: compiler, this may be incorrect for a structure in a UBO * FINISHME: like struct s { struct { float f } s1; dvec4 v; };. */ this->offset = glsl_align(this->offset, field->type->std140_base_alignment(false)); }
virtual void visit_field(const glsl_type *type, const char *name, bool row_major) { assert(!type->is_record()); assert(!(type->is_array() && type->fields.array->is_record())); assert(!type->is_interface()); assert(!(type->is_array() && type->fields.array->is_interface())); (void) row_major; unsigned id; bool found = this->map->get(id, name); assert(found); if (!found) return; /* If there is already storage associated with this uniform, it means * that it was set while processing an earlier shader stage. For * example, we may be processing the uniform in the fragment shader, but * the uniform was already processed in the vertex shader. */ if (this->uniforms[id].storage != NULL) { /* If the uniform already has storage set from another shader stage, * mark the samplers used for this shader stage. */ if (type->contains_sampler()) { const unsigned count = MAX2(1, this->uniforms[id].array_elements); const unsigned shadow = (type->is_array()) ? type->fields.array->sampler_shadow : type->sampler_shadow; for (unsigned i = 0; i < count; i++) { const unsigned s = this->uniforms[id].sampler + i; this->shader_samplers_used |= 1U << s; this->shader_shadow_samplers |= shadow << s; } } return; } const glsl_type *base_type; if (type->is_array()) { this->uniforms[id].array_elements = type->length; base_type = type->fields.array; } else { this->uniforms[id].array_elements = 0; base_type = type; } if (base_type->is_sampler()) { this->uniforms[id].sampler = this->next_sampler; /* Increment the sampler by 1 for non-arrays and by the number of * array elements for arrays. */ this->next_sampler += MAX2(1, this->uniforms[id].array_elements); const gl_texture_index target = base_type->sampler_index(); const unsigned shadow = base_type->sampler_shadow; for (unsigned i = this->uniforms[id].sampler ; i < MIN2(this->next_sampler, MAX_SAMPLERS) ; i++) { this->targets[i] = target; this->shader_samplers_used |= 1U << i; this->shader_shadow_samplers |= shadow << i; } } else { this->uniforms[id].sampler = ~0; } this->uniforms[id].name = ralloc_strdup(this->uniforms, name); this->uniforms[id].type = base_type; this->uniforms[id].initialized = 0; this->uniforms[id].num_driver_storage = 0; this->uniforms[id].driver_storage = NULL; this->uniforms[id].storage = this->values; if (this->ubo_block_index != -1) { this->uniforms[id].block_index = this->ubo_block_index; unsigned alignment = type->std140_base_alignment(ubo_row_major); this->ubo_byte_offset = glsl_align(this->ubo_byte_offset, alignment); this->uniforms[id].offset = this->ubo_byte_offset; this->ubo_byte_offset += type->std140_size(ubo_row_major); if (type->is_array()) { this->uniforms[id].array_stride = glsl_align(type->fields.array->std140_size(ubo_row_major), 16); } else { this->uniforms[id].array_stride = 0; } if (type->is_matrix() || (type->is_array() && type->fields.array->is_matrix())) { this->uniforms[id].matrix_stride = 16; this->uniforms[id].row_major = ubo_row_major; } else { this->uniforms[id].matrix_stride = 0; this->uniforms[id].row_major = false; } } else { this->uniforms[id].block_index = -1; this->uniforms[id].offset = -1; this->uniforms[id].array_stride = -1; this->uniforms[id].matrix_stride = -1; this->uniforms[id].row_major = false; } this->values += values_for_type(type); }
virtual void visit_field(const glsl_type *type, const char *name, bool row_major, const glsl_type *record_type, bool last_field) { assert(!type->without_array()->is_record()); assert(!type->without_array()->is_interface()); unsigned id; bool found = this->map->get(id, name); assert(found); if (!found) return; const glsl_type *base_type; if (type->is_array()) { this->uniforms[id].array_elements = type->length; base_type = type->fields.array; } else { this->uniforms[id].array_elements = 0; base_type = type; } /* This assigns uniform indices to sampler and image uniforms. */ handle_samplers(base_type, &this->uniforms[id]); handle_images(base_type, &this->uniforms[id]); /* If there is already storage associated with this uniform, it means * that it was set while processing an earlier shader stage. For * example, we may be processing the uniform in the fragment shader, but * the uniform was already processed in the vertex shader. */ if (this->uniforms[id].storage != NULL) { return; } /* Assign explicit locations. */ if (current_var->data.explicit_location) { /* Set sequential locations for struct fields. */ if (record_type != NULL) { const unsigned entries = MAX2(1, this->uniforms[id].array_elements); this->uniforms[id].remap_location = current_var->data.location + field_counter; field_counter += entries; } else { this->uniforms[id].remap_location = current_var->data.location; } } else { /* Initialize to to indicate that no location is set */ this->uniforms[id].remap_location = UNMAPPED_UNIFORM_LOC; } this->uniforms[id].name = ralloc_strdup(this->uniforms, name); this->uniforms[id].type = base_type; this->uniforms[id].initialized = 0; this->uniforms[id].num_driver_storage = 0; this->uniforms[id].driver_storage = NULL; this->uniforms[id].storage = this->values; this->uniforms[id].atomic_buffer_index = -1; if (this->ubo_block_index != -1) { this->uniforms[id].block_index = this->ubo_block_index; const unsigned alignment = record_type ? record_type->std140_base_alignment(row_major) : type->std140_base_alignment(row_major); this->ubo_byte_offset = glsl_align(this->ubo_byte_offset, alignment); this->uniforms[id].offset = this->ubo_byte_offset; this->ubo_byte_offset += type->std140_size(row_major); if (last_field) this->ubo_byte_offset = glsl_align(this->ubo_byte_offset, 16); if (type->is_array()) { this->uniforms[id].array_stride = glsl_align(type->fields.array->std140_size(row_major), 16); } else { this->uniforms[id].array_stride = 0; } if (type->without_array()->is_matrix()) { this->uniforms[id].matrix_stride = 16; this->uniforms[id].row_major = row_major; } else { this->uniforms[id].matrix_stride = 0; this->uniforms[id].row_major = false; } } else { this->uniforms[id].block_index = -1; this->uniforms[id].offset = -1; this->uniforms[id].array_stride = -1; this->uniforms[id].matrix_stride = -1; this->uniforms[id].row_major = false; } this->values += values_for_type(type); }
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->is_matrix() || (this->is_array() && this->fields.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; for (unsigned i = 0; i < this->length; i++) { const struct glsl_type *field_type = this->fields.structure[i].type; unsigned align = field_type->std140_base_alignment(row_major); size = glsl_align(size, align); size += field_type->std140_size(row_major); } size = glsl_align(size, this->fields.structure[0].type->std140_base_alignment(row_major)); return size; } assert(!"not reached"); return -1; }
virtual void visit_field(const glsl_type *type, const char *name, bool row_major) { assert(!type->is_record()); assert(!(type->is_array() && type->fields.array->is_record())); assert(!type->is_interface()); assert(!(type->is_array() && type->fields.array->is_interface())); (void) row_major; unsigned id; bool found = this->map->get(id, name); assert(found); if (!found) return; const glsl_type *base_type; if (type->is_array()) { this->uniforms[id].array_elements = type->length; base_type = type->fields.array; } else { this->uniforms[id].array_elements = 0; base_type = type; } /* This assigns sampler uniforms to sampler units. */ handle_samplers(base_type, &this->uniforms[id]); /* If there is already storage associated with this uniform, it means * that it was set while processing an earlier shader stage. For * example, we may be processing the uniform in the fragment shader, but * the uniform was already processed in the vertex shader. */ if (this->uniforms[id].storage != NULL) { return; } this->uniforms[id].name = ralloc_strdup(this->uniforms, name); this->uniforms[id].type = base_type; this->uniforms[id].initialized = 0; this->uniforms[id].num_driver_storage = 0; this->uniforms[id].driver_storage = NULL; this->uniforms[id].storage = this->values; if (this->ubo_block_index != -1) { this->uniforms[id].block_index = this->ubo_block_index; unsigned alignment = type->std140_base_alignment(ubo_row_major); this->ubo_byte_offset = glsl_align(this->ubo_byte_offset, alignment); this->uniforms[id].offset = this->ubo_byte_offset; this->ubo_byte_offset += type->std140_size(ubo_row_major); if (type->is_array()) { this->uniforms[id].array_stride = glsl_align(type->fields.array->std140_size(ubo_row_major), 16); } else { this->uniforms[id].array_stride = 0; } if (type->is_matrix() || (type->is_array() && type->fields.array->is_matrix())) { this->uniforms[id].matrix_stride = 16; this->uniforms[id].row_major = ubo_row_major; } else { this->uniforms[id].matrix_stride = 0; this->uniforms[id].row_major = false; } } else { this->uniforms[id].block_index = -1; this->uniforms[id].offset = -1; this->uniforms[id].array_stride = -1; this->uniforms[id].matrix_stride = -1; this->uniforms[id].row_major = false; } this->values += values_for_type(type); }
virtual void visit_field(const glsl_type *type, const char *name, bool row_major, const glsl_type *record_type, bool /* last_field */) { assert(!type->without_array()->is_record()); assert(!type->without_array()->is_interface()); unsigned id; bool found = this->map->get(id, name); assert(found); if (!found) return; const glsl_type *base_type; if (type->is_array()) { this->uniforms[id].array_elements = type->length; base_type = type->fields.array; } else { this->uniforms[id].array_elements = 0; base_type = type; } /* This assigns uniform indices to sampler and image uniforms. */ handle_samplers(base_type, &this->uniforms[id]); handle_images(base_type, &this->uniforms[id]); handle_subroutines(base_type, &this->uniforms[id]); /* If there is already storage associated with this uniform or if the * uniform is set as builtin, it means that it was set while processing * an earlier shader stage. For example, we may be processing the * uniform in the fragment shader, but the uniform was already processed * in the vertex shader. */ if (this->uniforms[id].storage != NULL || this->uniforms[id].builtin) { return; } /* Assign explicit locations. */ if (current_var->data.explicit_location) { /* Set sequential locations for struct fields. */ if (record_type != NULL) { const unsigned entries = MAX2(1, this->uniforms[id].array_elements); this->uniforms[id].remap_location = current_var->data.location + field_counter; field_counter += entries; } else { this->uniforms[id].remap_location = current_var->data.location; } } else { /* Initialize to to indicate that no location is set */ this->uniforms[id].remap_location = UNMAPPED_UNIFORM_LOC; } this->uniforms[id].name = ralloc_strdup(this->uniforms, name); this->uniforms[id].type = base_type; this->uniforms[id].initialized = 0; this->uniforms[id].num_driver_storage = 0; this->uniforms[id].driver_storage = NULL; this->uniforms[id].atomic_buffer_index = -1; this->uniforms[id].hidden = current_var->data.how_declared == ir_var_hidden; this->uniforms[id].builtin = is_gl_identifier(name); /* Do not assign storage if the uniform is builtin */ if (!this->uniforms[id].builtin) this->uniforms[id].storage = this->values; if (this->ubo_block_index != -1) { this->uniforms[id].block_index = this->ubo_block_index; const unsigned alignment = type->std140_base_alignment(row_major); this->ubo_byte_offset = glsl_align(this->ubo_byte_offset, alignment); this->uniforms[id].offset = this->ubo_byte_offset; this->ubo_byte_offset += type->std140_size(row_major); if (type->is_array()) { this->uniforms[id].array_stride = glsl_align(type->fields.array->std140_size(row_major), 16); } else { this->uniforms[id].array_stride = 0; } if (type->without_array()->is_matrix()) { const glsl_type *matrix = type->without_array(); const unsigned N = matrix->base_type == GLSL_TYPE_DOUBLE ? 8 : 4; const unsigned items = row_major ? matrix->matrix_columns : matrix->vector_elements; assert(items <= 4); this->uniforms[id].matrix_stride = glsl_align(items * N, 16); this->uniforms[id].row_major = row_major; } else { this->uniforms[id].matrix_stride = 0; this->uniforms[id].row_major = false; } } else { this->uniforms[id].block_index = -1; this->uniforms[id].offset = -1; this->uniforms[id].array_stride = -1; this->uniforms[id].matrix_stride = -1; this->uniforms[id].row_major = false; } this->values += values_for_type(type); }
/** * Takes a deref and recursively calls itself to break the deref down to the * point that the reads or writes generated are contiguous scalars or vectors. */ void lower_buffer_access::emit_access(void *mem_ctx, bool is_write, ir_dereference *deref, ir_variable *base_offset, unsigned int deref_offset, bool row_major, int matrix_columns, unsigned int packing, unsigned int write_mask) { if (deref->type->is_record()) { unsigned int field_offset = 0; for (unsigned i = 0; i < deref->type->length; i++) { const struct glsl_struct_field *field = &deref->type->fields.structure[i]; ir_dereference *field_deref = new(mem_ctx) ir_dereference_record(deref->clone(mem_ctx, NULL), field->name); field_offset = glsl_align(field_offset, field->type->std140_base_alignment(row_major)); emit_access(mem_ctx, is_write, field_deref, base_offset, deref_offset + field_offset, row_major, 1, packing, writemask_for_size(field_deref->type->vector_elements)); field_offset += field->type->std140_size(row_major); } return; } if (deref->type->is_array()) { unsigned array_stride = packing == GLSL_INTERFACE_PACKING_STD430 ? deref->type->fields.array->std430_array_stride(row_major) : glsl_align(deref->type->fields.array->std140_size(row_major), 16); for (unsigned i = 0; i < deref->type->length; i++) { ir_constant *element = new(mem_ctx) ir_constant(i); ir_dereference *element_deref = new(mem_ctx) ir_dereference_array(deref->clone(mem_ctx, NULL), element); emit_access(mem_ctx, is_write, element_deref, base_offset, deref_offset + i * array_stride, row_major, 1, packing, writemask_for_size(element_deref->type->vector_elements)); } return; } if (deref->type->is_matrix()) { for (unsigned i = 0; i < deref->type->matrix_columns; i++) { ir_constant *col = new(mem_ctx) ir_constant(i); ir_dereference *col_deref = new(mem_ctx) ir_dereference_array(deref->clone(mem_ctx, NULL), col); if (row_major) { /* For a row-major matrix, the next column starts at the next * element. */ int size_mul = deref->type->is_double() ? 8 : 4; emit_access(mem_ctx, is_write, col_deref, base_offset, deref_offset + i * size_mul, row_major, deref->type->matrix_columns, packing, writemask_for_size(col_deref->type->vector_elements)); } else { int size_mul; /* std430 doesn't round up vec2 size to a vec4 size */ if (packing == GLSL_INTERFACE_PACKING_STD430 && deref->type->vector_elements == 2 && !deref->type->is_double()) { size_mul = 8; } else { /* std140 always rounds the stride of arrays (and matrices) to a * vec4, so matrices are always 16 between columns/rows. With * doubles, they will be 32 apart when there are more than 2 rows. * * For both std140 and std430, if the member is a * three-'component vector with components consuming N basic * machine units, the base alignment is 4N. For vec4, base * alignment is 4N. */ size_mul = (deref->type->is_double() && deref->type->vector_elements > 2) ? 32 : 16; } emit_access(mem_ctx, is_write, col_deref, base_offset, deref_offset + i * size_mul, row_major, deref->type->matrix_columns, packing, writemask_for_size(col_deref->type->vector_elements)); } } return; } assert(deref->type->is_scalar() || deref->type->is_vector()); if (!row_major) { ir_rvalue *offset = add(base_offset, new(mem_ctx) ir_constant(deref_offset)); unsigned mask = is_write ? write_mask : (1 << deref->type->vector_elements) - 1; insert_buffer_access(mem_ctx, deref, deref->type, offset, mask, -1); } 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 || 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. However a double matrix may either be 16 * or 32 depending on the number of columns. */ assert(matrix_columns <= 4); unsigned matrix_stride = 0; /* Matrix stride for std430 mat2xY matrices are not rounded up to * vec4 size. From OpenGL 4.3 spec, section 7.6.2.2 "Standard Uniform * Block Layout": * * "2. If the member is a two- or four-component vector with components * consuming N basic machine units, the base alignment is 2N or 4N, * respectively." [...] * "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." [...] * "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)." [...] * "When using the std430 storage layout, shader storage blocks will be * laid out in buffer storage identically to uniform and shader storage * blocks using the std140 layout, except that the base alignment and * stride of arrays of scalars and vectors in rule 4 and of structures in * rule 9 are not rounded up a multiple of the base alignment of a vec4." */ if (packing == GLSL_INTERFACE_PACKING_STD430 && matrix_columns == 2) matrix_stride = 2 * N; else matrix_stride = glsl_align(matrix_columns * N, 16); const glsl_type *deref_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 = add(base_offset, new(mem_ctx) ir_constant(deref_offset + i * matrix_stride)); if (!is_write || ((1U << i) & write_mask)) insert_buffer_access(mem_ctx, deref, deref_type, chan_offset, (1U << i), i); } } }
/** * This function initializes various values that will be used later by * emit_access when actually emitting loads or stores. * * Note: const_offset is an input as well as an output, clients must * initialize it to the offset of the variable in the underlying block, and * this function will adjust it by adding the constant offset of the member * being accessed into that variable. */ void lower_buffer_access::setup_buffer_access(void *mem_ctx, ir_variable *var, ir_rvalue *deref, ir_rvalue **offset, unsigned *const_offset, bool *row_major, int *matrix_columns, const glsl_struct_field **struct_field, unsigned packing) { *offset = new(mem_ctx) ir_constant(0u); *row_major = is_dereferenced_thing_row_major(deref); *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 * array dereference has a variable index. */ while (deref) { switch (deref->ir_type) { case ir_type_dereference_variable: { 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) { if (struct_field) *struct_field = &struct_type->fields.structure[i]; 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; } } }
virtual void visit_field(const glsl_struct_field *field) { this->offset = glsl_align(this->offset, field->type->std140_base_alignment(false)); }