[Mesa-dev] [PATCH v4 (part2) 38/59] glsl: lower SSBO atomic intrinsics
Iago Toral Quiroga
itoral at igalia.com
Wed Aug 5 01:30:35 PDT 2015
The first argument to SSBO atomics is a reference to a SSBO buffer variable
so we want to compute its block index and offset and provide these values
to an internal version of the intrinsic that takes them instead of the
buffer variable reference.
---
src/glsl/lower_ubo_reference.cpp | 141 +++++++++++++++++++++++++++++++++++++++
1 file changed, 141 insertions(+)
diff --git a/src/glsl/lower_ubo_reference.cpp b/src/glsl/lower_ubo_reference.cpp
index 495ffcf..c658a2c 100644
--- a/src/glsl/lower_ubo_reference.cpp
+++ b/src/glsl/lower_ubo_reference.cpp
@@ -178,6 +178,10 @@ public:
unsigned int unsized_array_stride);
unsigned calculate_unsized_array_stride(ir_dereference *deref);
+ ir_call *lower_ssbo_atomic_intrinsic(ir_call *ir);
+ 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;
@@ -1004,6 +1008,143 @@ lower_ubo_reference_visitor::visit_enter(ir_assignment *ir)
return rvalue_visit(ir);
}
+/* Lowers the intrinsic call to a new internal intrinsic that swaps the
+ * access to the buffer variable in the first parameter by an offset
+ * and block index. This involves creating the new internal intrinsic
+ * (i.e. the new function signature).
+ */
+ir_call *
+lower_ubo_reference_visitor::lower_ssbo_atomic_intrinsic(ir_call *ir)
+{
+ /* SSBO atomics usually have 2 parameters, the buffer variable and an
+ * integer argument. The exception is CompSwap, that has an additional
+ * integer parameter.
+ */
+ int param_count = ir->actual_parameters.length();
+ assert(param_count == 2 || param_count == 3);
+
+ /* First argument must be a scalar integer buffer variable */
+ exec_node *param = ir->actual_parameters.get_head();
+ ir_instruction *inst = (ir_instruction *) param;
+ assert(inst->ir_type == ir_type_dereference_variable ||
+ inst->ir_type == ir_type_dereference_array ||
+ inst->ir_type == ir_type_dereference_record);
+
+ ir_dereference *deref = (ir_dereference *) inst;
+ assert(deref->type->is_scalar() && deref->type->is_integer());
+
+ ir_variable *var = deref->variable_referenced();
+ assert(var);
+
+ /* Compute the offset to the start if the dereference and the
+ * block index
+ */
+ mem_ctx = ralloc_parent(shader->ir);
+
+ ir_rvalue *offset = NULL;
+ unsigned const_offset;
+ bool row_major;
+ int matrix_columns;
+
+ setup_for_load_or_store(var, deref,
+ &offset, &const_offset,
+ &row_major, &matrix_columns);
+ assert(offset);
+ assert(!row_major);
+ assert(matrix_columns == 1);
+
+ ir_rvalue *deref_offset =
+ add(offset, new(mem_ctx) ir_constant(const_offset));
+ ir_rvalue *block_index = this->uniform_block->clone(mem_ctx, NULL);
+
+ /* Create the new internal function signature that will take a block
+ * index and offset instead of a buffer variable
+ */
+ exec_list sig_params;
+ ir_variable *sig_param = new(mem_ctx)
+ ir_variable(glsl_type::uint_type, "block_ref" , ir_var_function_in);
+ sig_params.push_tail(sig_param);
+
+ sig_param = new(mem_ctx)
+ ir_variable(glsl_type::uint_type, "offset" , ir_var_function_in);
+ sig_params.push_tail(sig_param);
+
+ const glsl_type *type = deref->type->base_type == GLSL_TYPE_INT ?
+ glsl_type::int_type : glsl_type::uint_type;
+ param = param->get_next();
+ sig_param = new(mem_ctx)
+ ir_variable(type, "data1", ir_var_function_in);
+ sig_params.push_tail(sig_param);
+
+ if (param_count == 3) {
+ param = param->get_next();
+ sig_param = new(mem_ctx)
+ ir_variable(type, "data2", ir_var_function_in);
+ sig_params.push_tail(sig_param);
+ }
+
+ ir_function_signature *sig =
+ new(mem_ctx) ir_function_signature(deref->type,
+ shader_storage_buffer_object);
+ assert(sig);
+ sig->replace_parameters(&sig_params);
+ sig->is_intrinsic = true;
+
+ char func_name[64];
+ sprintf(func_name, "%s_internal", ir->callee_name());
+ ir_function *f = new(mem_ctx) ir_function(func_name);
+ f->add_signature(sig);
+
+ /* Now, create the call to the internal intrinsic */
+ exec_list call_params;
+ call_params.push_tail(block_index);
+ call_params.push_tail(deref_offset);
+ param = ir->actual_parameters.get_head()->get_next();
+ ir_rvalue *param_as_rvalue = ((ir_instruction *) param)->as_rvalue();
+ call_params.push_tail(param_as_rvalue->clone(mem_ctx, NULL));
+ if (param_count == 3) {
+ param = param->get_next();
+ param_as_rvalue = ((ir_instruction *) param)->as_rvalue();
+ call_params.push_tail(param_as_rvalue->clone(mem_ctx, NULL));
+ }
+ ir_dereference_variable *return_deref =
+ ir->return_deref->clone(mem_ctx, NULL);
+ return new(mem_ctx) ir_call(sig, return_deref, &call_params);
+}
+
+ir_call *
+lower_ubo_reference_visitor::check_for_ssbo_atomic_intrinsic(ir_call *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)) {
+ return lower_ssbo_atomic_intrinsic(ir);
+ }
+
+ return ir;
+}
+
+
+ir_visitor_status
+lower_ubo_reference_visitor::visit_enter(ir_call *ir)
+{
+ ir_call *new_ir = check_for_ssbo_atomic_intrinsic(ir);
+ if (new_ir != ir) {
+ progress = true;
+ base_ir->replace_with(new_ir);
+ return visit_continue_with_parent;
+ }
+
+ return rvalue_visit(ir);
+}
+
+
} /* unnamed namespace */
void
--
1.9.1
More information about the mesa-dev
mailing list