--- 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 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev