[Mesa-dev] [PATCH 57/74] i965/fs: Implement shader storage buffer object atomic intrinsics

Iago Toral Quiroga itoral at igalia.com
Thu May 14 07:07:00 PDT 2015


---
 src/mesa/drivers/dri/i965/brw_fs.h           |   1 +
 src/mesa/drivers/dri/i965/brw_fs_visitor.cpp | 108 +++++++++++++++++++++++++++
 2 files changed, 109 insertions(+)

diff --git a/src/mesa/drivers/dri/i965/brw_fs.h b/src/mesa/drivers/dri/i965/brw_fs.h
index 40b7ec2..5708420 100644
--- a/src/mesa/drivers/dri/i965/brw_fs.h
+++ b/src/mesa/drivers/dri/i965/brw_fs.h
@@ -441,6 +441,7 @@ public:
    void dump_instruction(backend_instruction *inst, FILE *file);
 
    void visit_atomic_counter_intrinsic(ir_call *ir);
+   void visit_atomic_intrinsic(ir_call *ir);
 
    const void *const key;
    const struct brw_sampler_prog_key_data *key_tex;
diff --git a/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp b/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp
index 3904fc5..ce4c50f 100644
--- a/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp
+++ b/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp
@@ -3316,6 +3316,105 @@ fs_visitor::visit_atomic_counter_intrinsic(ir_call *ir)
 }
 
 void
+fs_visitor::visit_atomic_intrinsic(ir_call *ir)
+{
+   /* The first argument to an atomic operation can only be a buffer variable
+    * which at this point must have been lowered by lower_ubo_reference to
+    * a ir_binop_ssbo_load expression. The ir_binop_ssbo_load expression
+    * contains the surface index and offset data we need.
+    */
+   ir_instruction *inst = (ir_instruction *) ir->actual_parameters.get_head();
+   ir_expression *ssbo_expr = inst->as_expression();
+   assert(ssbo_expr);
+
+   ir_constant *const_uniform_block = ssbo_expr->operands[0]->as_constant();
+
+   fs_reg surface;
+   if (const_uniform_block) {
+      unsigned surf_index = stage_prog_data->binding_table.ubo_start +
+                            const_uniform_block->value.u[0];
+      surface = fs_reg(surf_index);
+      brw_mark_surface_used(prog_data, surf_index);
+   } else {
+      ssbo_expr->operands[0]->accept(this);
+      surface = this->result;
+      emit(ADD(surface, surface,
+               fs_reg(stage_prog_data->binding_table.ubo_start)));
+
+      /* Assume this may touch any UBO. This is the same we do for other
+       * UBO/SSBO accesses with non-constant surface.
+       */
+      brw_mark_surface_used(prog_data,
+                            stage_prog_data->binding_table.ubo_start +
+                            shader_prog->NumUniformBlocks - 1);
+   }
+
+   ssbo_expr->operands[1]->accept(this);
+   fs_reg offset = this->result;
+
+   int param_count = ir->actual_parameters.length();
+   assert(param_count == 2 || param_count == 3);
+
+   /* Get data1 parameter (this is always present) */
+   ir_instruction *param = (ir_instruction *) ((exec_node *)inst)->next;
+   assert(param);
+   param->accept(this);
+   fs_reg data1 = this->result;
+   fs_reg data2;
+
+   /* Emit the actual atomic operation operation */
+   const bool uses_kill = (stage == MESA_SHADER_FRAGMENT &&
+                           ((brw_wm_prog_data *)prog_data)->uses_kill);
+   fs_builder bld(devinfo, mem_ctx, alloc, instructions, dispatch_width,
+                  stage, uses_kill);
+   bld.set_annotation(current_annotation);
+   bld.set_base_ir(base_ir);
+
+   const char *callee = ir->callee->function_name();
+   ir->return_deref->accept(this);
+   fs_reg dst = this->result;
+
+   unsigned atomic_op;
+   if (!strcmp("__intrinsic_atomic_add", callee)) {
+      atomic_op = BRW_AOP_ADD;
+   } else if (!strcmp("__intrinsic_atomic_and", callee)) {
+      atomic_op = BRW_AOP_AND;
+   } else if (!strcmp("__intrinsic_atomic_or", callee)) {
+      atomic_op = BRW_AOP_OR;
+   } else if (!strcmp("__intrinsic_atomic_xor", callee)) {
+      atomic_op = BRW_AOP_XOR;
+   } else if (!strcmp("__intrinsic_atomic_min", callee)) {
+      if (dst.type == BRW_REGISTER_TYPE_D)
+         atomic_op = BRW_AOP_IMIN;
+      else
+         atomic_op = BRW_AOP_UMIN;
+   } else if (!strcmp("__intrinsic_atomic_max", callee)) {
+      if (dst.type == BRW_REGISTER_TYPE_D)
+         atomic_op = BRW_AOP_IMAX;
+      else
+         atomic_op = BRW_AOP_UMAX;
+   } else if (!strcmp("__intrinsic_atomic_exchange", callee)) {
+      atomic_op = BRW_AOP_MOV;
+   } else if (!strcmp("__intrinsic_atomic_comp_swap", callee)) {
+      param = (ir_instruction *) ((exec_node *)inst)->next->next;
+      assert(param);
+      param->accept(this);
+      data2 = this->result;
+      atomic_op = BRW_AOP_CMPWR;
+   } else {
+      unreachable("Unsupported atomic intrinsic");
+   }
+
+   fs_reg atomic_result =
+      surface_access::emit_untyped_atomic(bld, surface, offset,
+                                          data1, data2,
+                                          1 /* dims */, 1 /* rsize */,
+                                          atomic_op,
+                                          BRW_PREDICATE_NONE);
+   emit(MOV(dst, atomic_result));
+}
+
+void
 fs_visitor::visit(ir_call *ir)
 {
    const char *callee = ir->callee->function_name();
@@ -3324,6 +3423,15 @@ fs_visitor::visit(ir_call *ir)
        !strcmp("__intrinsic_atomic_increment", callee) ||
        !strcmp("__intrinsic_atomic_predecrement", callee)) {
       visit_atomic_counter_intrinsic(ir);
+   } else 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)) {
+      visit_atomic_intrinsic(ir);
    } else {
       unreachable("Unsupported intrinsic.");
    }
-- 
1.9.1



More information about the mesa-dev mailing list