X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fglsl%2Flower_ubo_reference.cpp;h=a172054bac8279f399e2b00867e8b12642d29f86;hb=d97b060e6f305ce4ad050881944404b920c86edf;hp=152f0a3eb08fc44d90370a344f068ab85779c311;hpb=afa4129cf6ee0a64811b118d270f1b05d7d05325;p=mesa.git diff --git a/src/glsl/lower_ubo_reference.cpp b/src/glsl/lower_ubo_reference.cpp index 152f0a3eb08..a172054bac8 100644 --- a/src/glsl/lower_ubo_reference.cpp +++ b/src/glsl/lower_ubo_reference.cpp @@ -40,96 +40,6 @@ 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_rvalue *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->without_array()->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 lower_buffer_access::lower_buffer_access { @@ -142,26 +52,25 @@ public: void handle_rvalue(ir_rvalue **rvalue); ir_visitor_status visit_enter(ir_assignment *ir); - void setup_for_load_or_store(ir_variable *var, + void setup_for_load_or_store(void *mem_ctx, + ir_variable *var, ir_rvalue *deref, ir_rvalue **offset, unsigned *const_offset, bool *row_major, int *matrix_columns, unsigned packing); - ir_expression *ubo_load(const struct glsl_type *type, + ir_expression *ubo_load(void *mem_ctx, const struct glsl_type *type, ir_rvalue *offset); - ir_call *ssbo_load(const struct glsl_type *type, + ir_call *ssbo_load(void *mem_ctx, const struct glsl_type *type, ir_rvalue *offset); bool check_for_buffer_array_copy(ir_assignment *ir); bool check_for_buffer_struct_copy(ir_assignment *ir); void check_for_ssbo_store(ir_assignment *ir); - void write_to_memory(ir_dereference *deref, - ir_variable *var, - ir_variable *write_var, - unsigned write_mask); - ir_call *ssbo_store(ir_rvalue *deref, ir_rvalue *offset, + void write_to_memory(void *mem_ctx, ir_dereference *deref, ir_variable *var, + ir_variable *write_var, unsigned write_mask); + ir_call *ssbo_store(void *mem_ctx, ir_rvalue *deref, ir_rvalue *offset, unsigned write_mask); enum { @@ -184,7 +93,7 @@ public: ir_expression *process_ssbo_unsized_array_length(ir_rvalue **, ir_dereference *, ir_variable *); - ir_expression *emit_ssbo_get_buffer_size(); + ir_expression *emit_ssbo_get_buffer_size(void *mem_ctx); unsigned calculate_unsized_array_stride(ir_dereference *deref, unsigned packing); @@ -193,7 +102,6 @@ public: ir_call *check_for_ssbo_atomic_intrinsic(ir_call *ir); ir_visitor_status visit_enter(ir_call *ir); - void *mem_ctx; struct gl_shader *shader; struct gl_uniform_buffer_variable *ubo_var; ir_rvalue *uniform_block; @@ -332,7 +240,8 @@ interface_field_name(void *mem_ctx, char *base_name, ir_rvalue *d, } void -lower_ubo_reference_visitor::setup_for_load_or_store(ir_variable *var, +lower_ubo_reference_visitor::setup_for_load_or_store(void *mem_ctx, + ir_variable *var, ir_rvalue *deref, ir_rvalue **offset, unsigned *const_offset, @@ -377,164 +286,10 @@ lower_ubo_reference_visitor::setup_for_load_or_store(ir_variable *var, assert(this->uniform_block); - *offset = new(mem_ctx) ir_constant(0u); - *const_offset = 0; - *row_major = is_dereferenced_thing_row_major(deref); - *matrix_columns = 1; + *const_offset = ubo_var->Offset; - /* 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; - } - } + setup_buffer_access(mem_ctx, var, deref, offset, const_offset, row_major, + matrix_columns, packing); } void @@ -551,7 +306,7 @@ lower_ubo_reference_visitor::handle_rvalue(ir_rvalue **rvalue) if (!var || !var->is_in_buffer_block()) return; - mem_ctx = ralloc_parent(shader->ir); + void *mem_ctx = ralloc_parent(shader->ir); ir_rvalue *offset = NULL; unsigned const_offset; @@ -566,7 +321,7 @@ lower_ubo_reference_visitor::handle_rvalue(ir_rvalue **rvalue) /* Compute the offset to the start if the dereference as well as other * information we need to configure the write */ - setup_for_load_or_store(var, deref, + setup_for_load_or_store(mem_ctx, var, deref, &offset, &const_offset, &row_major, &matrix_columns, packing); @@ -596,7 +351,8 @@ lower_ubo_reference_visitor::handle_rvalue(ir_rvalue **rvalue) } ir_expression * -lower_ubo_reference_visitor::ubo_load(const glsl_type *type, +lower_ubo_reference_visitor::ubo_load(void *mem_ctx, + const glsl_type *type, ir_rvalue *offset) { ir_rvalue *block_ref = this->uniform_block->clone(mem_ctx, NULL); @@ -615,7 +371,8 @@ shader_storage_buffer_object(const _mesa_glsl_parse_state *state) } ir_call * -lower_ubo_reference_visitor::ssbo_store(ir_rvalue *deref, +lower_ubo_reference_visitor::ssbo_store(void *mem_ctx, + ir_rvalue *deref, ir_rvalue *offset, unsigned write_mask) { @@ -655,7 +412,8 @@ lower_ubo_reference_visitor::ssbo_store(ir_rvalue *deref, } ir_call * -lower_ubo_reference_visitor::ssbo_load(const struct glsl_type *type, +lower_ubo_reference_visitor::ssbo_load(void *mem_ctx, + const struct glsl_type *type, ir_rvalue *offset) { exec_list sig_params; @@ -701,11 +459,11 @@ lower_ubo_reference_visitor::insert_buffer_access(void *mem_ctx, switch (this->buffer_access_type) { case ubo_load_access: base_ir->insert_before(assign(deref->clone(mem_ctx, NULL), - ubo_load(type, offset), + ubo_load(mem_ctx, type, offset), mask)); break; case ssbo_load_access: { - ir_call *load_ssbo = ssbo_load(type, offset); + ir_call *load_ssbo = ssbo_load(mem_ctx, type, offset); base_ir->insert_before(load_ssbo); ir_rvalue *value = load_ssbo->return_deref->as_rvalue()->clone(mem_ctx, NULL); ir_assignment *assignment = @@ -715,10 +473,11 @@ lower_ubo_reference_visitor::insert_buffer_access(void *mem_ctx, } case ssbo_store_access: if (channel >= 0) { - base_ir->insert_after(ssbo_store(swizzle(deref, channel, 1), + base_ir->insert_after(ssbo_store(mem_ctx, + swizzle(deref, channel, 1), offset, 1)); } else { - base_ir->insert_after(ssbo_store(deref, offset, mask)); + base_ir->insert_after(ssbo_store(mem_ctx, deref, offset, mask)); } break; default: @@ -727,7 +486,8 @@ lower_ubo_reference_visitor::insert_buffer_access(void *mem_ctx, } void -lower_ubo_reference_visitor::write_to_memory(ir_dereference *deref, +lower_ubo_reference_visitor::write_to_memory(void *mem_ctx, + ir_dereference *deref, ir_variable *var, ir_variable *write_var, unsigned write_mask) @@ -743,7 +503,7 @@ lower_ubo_reference_visitor::write_to_memory(ir_dereference *deref, /* Compute the offset to the start if the dereference as well as other * information we need to configure the write */ - setup_for_load_or_store(var, deref, + setup_for_load_or_store(mem_ctx, var, deref, &offset, &const_offset, &row_major, &matrix_columns, packing); @@ -834,7 +594,7 @@ lower_ubo_reference_visitor::check_ssbo_unsized_array_length_assignment(ir_assig } ir_expression * -lower_ubo_reference_visitor::emit_ssbo_get_buffer_size() +lower_ubo_reference_visitor::emit_ssbo_get_buffer_size(void *mem_ctx) { ir_rvalue *block_ref = this->uniform_block->clone(mem_ctx, NULL); return new(mem_ctx) ir_expression(ir_unop_get_buffer_size, @@ -908,7 +668,7 @@ lower_ubo_reference_visitor::process_ssbo_unsized_array_length(ir_rvalue **rvalu ir_dereference *deref, ir_variable *var) { - mem_ctx = ralloc_parent(*rvalue); + void *mem_ctx = ralloc_parent(*rvalue); ir_rvalue *base_offset = NULL; unsigned const_offset; @@ -922,14 +682,14 @@ lower_ubo_reference_visitor::process_ssbo_unsized_array_length(ir_rvalue **rvalu /* Compute the offset to the start if the dereference as well as other * information we need to calculate the length. */ - setup_for_load_or_store(var, deref, + setup_for_load_or_store(mem_ctx, var, deref, &base_offset, &const_offset, &row_major, &matrix_columns, packing); /* array.length() = * max((buffer_object_size - offset_of_array) / stride_of_array, 0) */ - ir_expression *buffer_size = emit_ssbo_get_buffer_size(); + ir_expression *buffer_size = emit_ssbo_get_buffer_size(mem_ctx); ir_expression *offset_of_array = new(mem_ctx) ir_expression(ir_binop_add, base_offset, @@ -963,13 +723,13 @@ lower_ubo_reference_visitor::check_for_ssbo_store(ir_assignment *ir) return; ir_variable *var = ir->lhs->variable_referenced(); - if (!var || !var->is_in_buffer_block()) + if (!var || !var->is_in_shader_storage_block()) return; /* We have a write to a buffer variable, so declare a temporary and rewrite * the assignment so that the temporary is the LHS. */ - mem_ctx = ralloc_parent(shader->ir); + void *mem_ctx = ralloc_parent(shader->ir); const glsl_type *type = rvalue->type; ir_variable *write_var = new(mem_ctx) ir_variable(type, @@ -979,7 +739,7 @@ lower_ubo_reference_visitor::check_for_ssbo_store(ir_assignment *ir) ir->lhs = new(mem_ctx) ir_dereference_variable(write_var); /* Now we have to write the value assigned to the temporary back to memory */ - write_to_memory(deref, var, write_var, ir->write_mask); + write_to_memory(mem_ctx, deref, var, write_var, ir->write_mask); progress = true; } @@ -1022,7 +782,7 @@ lower_ubo_reference_visitor::check_for_buffer_array_copy(ir_assignment *ir) return false; assert(lhs_deref->type->length == rhs_deref->type->length); - mem_ctx = ralloc_parent(shader->ir); + void *mem_ctx = ralloc_parent(shader->ir); for (unsigned i = 0; i < lhs_deref->type->length; i++) { ir_dereference *lhs_i = @@ -1070,7 +830,7 @@ lower_ubo_reference_visitor::check_for_buffer_struct_copy(ir_assignment *ir) return false; assert(lhs_deref->type->record_compare(rhs_deref->type)); - mem_ctx = ralloc_parent(shader->ir); + void *mem_ctx = ralloc_parent(shader->ir); for (unsigned i = 0; i < lhs_deref->type->length; i++) { const char *field_name = lhs_deref->type->fields.structure[i].name; @@ -1141,7 +901,7 @@ lower_ubo_reference_visitor::lower_ssbo_atomic_intrinsic(ir_call *ir) /* Compute the offset to the start if the dereference and the * block index */ - mem_ctx = ralloc_parent(shader->ir); + void *mem_ctx = ralloc_parent(shader->ir); ir_rvalue *offset = NULL; unsigned const_offset; @@ -1151,7 +911,7 @@ lower_ubo_reference_visitor::lower_ssbo_atomic_intrinsic(ir_call *ir) this->buffer_access_type = ssbo_atomic_access; - setup_for_load_or_store(var, deref, + setup_for_load_or_store(mem_ctx, var, deref, &offset, &const_offset, &row_major, &matrix_columns, packing); @@ -1195,7 +955,7 @@ lower_ubo_reference_visitor::lower_ssbo_atomic_intrinsic(ir_call *ir) sig->is_intrinsic = true; char func_name[64]; - sprintf(func_name, "%s_internal", ir->callee_name()); + sprintf(func_name, "%s_ssbo", ir->callee_name()); ir_function *f = new(mem_ctx) ir_function(func_name); f->add_signature(sig); @@ -1219,15 +979,29 @@ lower_ubo_reference_visitor::lower_ssbo_atomic_intrinsic(ir_call *ir) ir_call * lower_ubo_reference_visitor::check_for_ssbo_atomic_intrinsic(ir_call *ir) { + exec_list& params = ir->actual_parameters; + + if (params.length() < 2 || params.length() > 3) + return ir; + + ir_rvalue *rvalue = + ((ir_instruction *) params.get_head())->as_rvalue(); + if (!rvalue) + return ir; + + ir_variable *var = rvalue->variable_referenced(); + if (!var || !var->is_in_shader_storage_block()) + return ir; + const char *callee = ir->callee_name(); - if (!strcmp("__intrinsic_ssbo_atomic_add", callee) || - !strcmp("__intrinsic_ssbo_atomic_min", callee) || - !strcmp("__intrinsic_ssbo_atomic_max", callee) || - !strcmp("__intrinsic_ssbo_atomic_and", callee) || - !strcmp("__intrinsic_ssbo_atomic_or", callee) || - !strcmp("__intrinsic_ssbo_atomic_xor", callee) || - !strcmp("__intrinsic_ssbo_atomic_exchange", callee) || - !strcmp("__intrinsic_ssbo_atomic_comp_swap", callee)) { + if (!strcmp("__intrinsic_atomic_add", callee) || + !strcmp("__intrinsic_atomic_min", callee) || + !strcmp("__intrinsic_atomic_max", callee) || + !strcmp("__intrinsic_atomic_and", callee) || + !strcmp("__intrinsic_atomic_or", callee) || + !strcmp("__intrinsic_atomic_xor", callee) || + !strcmp("__intrinsic_atomic_exchange", callee) || + !strcmp("__intrinsic_atomic_comp_swap", callee)) { return lower_ssbo_atomic_intrinsic(ir); }