Improves register pressure, since otherwise we end up emitting loads for all the elements in the RHS and them emitting stores for all elements in the LHS.
Fixes the following piglit test: tests/spec/arb_shader_storage_buffer_object/execution/large-field-copy.shader_test --- Jordan, this fixes the link failure for the the test you provided. Needs more testing and I have to check if I need to do something for structs that contain arrays too, etc I'll do that on Monday unless someone else comes with a better idea to fix this. src/glsl/lower_ubo_reference.cpp | 61 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/glsl/lower_ubo_reference.cpp b/src/glsl/lower_ubo_reference.cpp index b74aa3d..7d48960 100644 --- a/src/glsl/lower_ubo_reference.cpp +++ b/src/glsl/lower_ubo_reference.cpp @@ -154,6 +154,7 @@ public: ir_call *ssbo_load(const struct glsl_type *type, ir_rvalue *offset); + bool check_for_ssbo_array_copy(ir_assignment *ir); void check_for_ssbo_store(ir_assignment *ir); void write_to_memory(ir_dereference *deref, ir_variable *var, @@ -1133,9 +1134,69 @@ lower_ubo_reference_visitor::check_for_ssbo_store(ir_assignment *ir) } +bool +lower_ubo_reference_visitor::check_for_ssbo_array_copy(ir_assignment *ir) +{ + if (!ir || !ir->lhs || !ir->rhs) + return false; + + ir_dereference *rhs_deref = ir->rhs->as_dereference(); + if (!rhs_deref) + return false; + + ir_dereference *lhs_deref = ir->lhs->as_dereference(); + if (!lhs_deref) + return false; + + /* LHS and RHS must be SSBO variables */ + ir_variable *lhs_var = ir->lhs->variable_referenced(); + if (!lhs_var || !lhs_var->is_in_shader_storage_block()) + return false; + + ir_variable *rhs_var = ir->rhs->variable_referenced(); + if (!rhs_var || !rhs_var->is_in_shader_storage_block()) + return false; + + /* LHS and RHS must be variable dereferences. + * FIXME: arrays of arrays? + */ + if (!ir->lhs->as_dereference_variable() || + !ir->rhs->as_dereference_variable()) + return false; + + /* LHS and RHS must be arrays */ + if (!rhs_var->type->is_array() || !lhs_var->type->is_array()) + return false; + + assert(lhs_deref->type->length == rhs_deref->type->length); + + for (unsigned i = 0; i < lhs_deref->type->length; i++) { + ir_dereference *lhs_i = + new(mem_ctx) ir_dereference_array(lhs_deref->clone(mem_ctx, NULL), + new(mem_ctx) ir_constant(i)); + + ir_dereference *rhs_i = + new(mem_ctx) ir_dereference_array(rhs_deref->clone(mem_ctx, NULL), + new(mem_ctx) ir_constant(i)); + ir->insert_after(assign(lhs_i, rhs_i)); + } + + ir->remove(); + return true; +} + ir_visitor_status lower_ubo_reference_visitor::visit_enter(ir_assignment *ir) { + /* Array copies could involve large amounts of SSBO load/store + * operations. To improve register pressure we want to special-case + * this and split the array copy into many individual element copies. + * This way we avoid emitting all the loads for the RHS first and + * all the writes for the LHS second. + */ + if (check_for_ssbo_array_copy(ir)) + return visit_continue_with_parent; + check_ssbo_unsized_array_length_assignment(ir); check_for_ssbo_store(ir); return rvalue_visit(ir); -- 1.9.1 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev