[Mesa-dev] [PATCH V4 6/6] i965/fs: add support for ir_*_interpolate_at_* expressions
Matt Turner
mattst88 at gmail.com
Sat Jul 12 00:09:29 PDT 2014
On Fri, Jul 11, 2014 at 8:20 PM, Chris Forbes <chrisf at ijw.co.nz> wrote:
> SIMD8-only for now.
>
> Signed-off-by: Chris Forbes <chrisf at ijw.co.nz>
> ---
> src/mesa/drivers/dri/i965/brw_fs.h | 1 +
> src/mesa/drivers/dri/i965/brw_fs_visitor.cpp | 135 ++++++++++++++++++++++++++-
> 2 files changed, 134 insertions(+), 2 deletions(-)
>
> diff --git a/src/mesa/drivers/dri/i965/brw_fs.h b/src/mesa/drivers/dri/i965/brw_fs.h
> index 48f1069..0bb328a 100644
> --- a/src/mesa/drivers/dri/i965/brw_fs.h
> +++ b/src/mesa/drivers/dri/i965/brw_fs.h
> @@ -390,6 +390,7 @@ public:
> const fs_reg &src0, const fs_reg &src1);
> bool try_emit_saturate(ir_expression *ir);
> bool try_emit_mad(ir_expression *ir);
> + void emit_interpolate_expression(ir_expression *ir);
Seems like a weird place to list the prototype, among the peephole functions.
> void try_replace_with_sel();
> bool opt_peephole_sel();
> bool opt_peephole_predicated_break();
> diff --git a/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp b/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp
> index 8e8affa..2f37986 100644
> --- a/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp
> +++ b/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp
> @@ -344,6 +344,118 @@ fs_visitor::try_emit_mad(ir_expression *ir)
> return true;
> }
>
> +static int
> +pack_pixel_offset(float x)
> +{
> + int n = MIN2((int)(x * 16), 7);
> + return n & 0xf;
> +}
> +
> +void
> +fs_visitor::emit_interpolate_expression(ir_expression *ir)
> +{
> + /* in SIMD16 mode, the pixel interpolator returns coords interleaved
> + * 8 channels at a time, same as the barycentric coords presented in
> + * the FS payload. this requires a bit of extra work to support.
> + */
> + no16("interpolate_at_* not yet supported in SIMD16 mode.");
> +
> + ir_dereference * deref = ir->operands[0]->as_dereference();
> + ir_swizzle * swiz = NULL;
> + if (!deref) {
> + /* the api does not allow a swizzle here, but the varying packing code
> + * may have pushed one into here.
> + */
> + swiz = ir->operands[0]->as_swizzle();
> + assert(swiz);
> + deref = swiz->val->as_dereference();
> + }
> + assert(deref);
> + ir_variable * var = deref->variable_referenced();
> + assert(var);
> +
> + /* 1. collect interpolation factors */
> +
> + fs_reg dst_x = fs_reg(this, glsl_type::get_instance(ir->type->base_type, 2, 1));
> + fs_reg dst_y = dst_x;
> + dst_y.reg_offset++;
> +
> + /* for most messages, we need one reg of ignored data; the hardware requires mlen==1
> + * even when there is no payload. in the per-slot offset case, we'll replace this with
> + * the proper source data. */
> + fs_reg src = fs_reg(this, glsl_type::float_type);
> + int mlen = 1; /* one reg unless overriden */
> + int msg_type = 0; /* message type to be packed into the descriptor */
> + int imm_data = 0; /* data to be packed into the message descriptor */
> +
> + switch (ir->operation) {
> + case ir_unop_interpolate_at_centroid:
> + {
> + msg_type = GEN7_PIXEL_INTERPOLATOR_LOC_CENTROID;
> + } break;
> +
> + case ir_binop_interpolate_at_sample:
> + {
> + ir_constant *sample_num = ir->operands[1]->as_constant();
> + assert(sample_num || !"nonconstant sample number should have been lowered.");
> +
> + msg_type = GEN7_PIXEL_INTERPOLATOR_LOC_SAMPLE;
> + imm_data = sample_num->value.i[0] << 4;
> + } break;
> +
> + case ir_binop_interpolate_at_offset:
> + {
Style. Other places where we need to declare variables in a case, we
just put { after the : and the closing brace on its own line, with the
break inside.
> + ir_constant *const_offset = ir->operands[1]->as_constant();
> + if (const_offset) {
> + msg_type = GEN7_PIXEL_INTERPOLATOR_LOC_SHARED_OFFSET;
> + imm_data = pack_pixel_offset(const_offset->value.f[0]) |
> + (pack_pixel_offset(const_offset->value.f[1]) << 4);
> + } else {
> + /* pack the operands: hw wants offsets as 4 bit signed ints */
> + ir->operands[1]->accept(this);
> + src = fs_reg(this, glsl_type::ivec2_type);
> + fs_reg src2 = src;
> + for (int i = 0; i < 2; i++) {
> + fs_reg temp = fs_reg(this, glsl_type::float_type);
> + emit(MUL(temp, this->result, fs_reg(16.0f)));
> + emit(MOV(src2, temp)); /* float to int */
> + fs_inst *inst = emit(BRW_OPCODE_SEL, src2, src2, fs_reg(7));
> + inst->conditional_mod = BRW_CONDITIONAL_L; /* min(src2, 7) */
> +
> + src2.reg_offset++;
> + this->result.reg_offset++;
> + }
> +
> + mlen = 2 * dispatch_width / 8;
> + msg_type = GEN7_PIXEL_INTERPOLATOR_LOC_PER_SLOT_OFFSET;
> + }
> + } break;
> +
> + default:
> + unreachable("not reached");
> + }
> +
> + fs_inst *inst = emit(FS_OPCODE_PIXEL_INTERPOLATOR_QUERY, dst_x, src);
> + inst->mlen = mlen;
> + inst->regs_written = 2 * dispatch_width / 8; /* 2 floats per slot returned */
> + inst->pi_noperspective = var->determine_interpolation_mode(key->flat_shade) == INTERP_QUALIFIER_NOPERSPECTIVE;
> + inst->pi_msg_type = msg_type;
> + inst->pi_msg_data = imm_data;
> +
> + /* 2. emit linterp */
> +
> + fs_reg res(this, ir->type);
> + this->result = res;
> +
> + for (int i = 0; i < ir->type->vector_elements; i++) {
> + int ch = swiz ? ((*(int *)&swiz->mask) >> 2*i) & 3 : i;
> + emit(FS_OPCODE_LINTERP, res,
> + dst_x, dst_y,
> + fs_reg(interp_reg(var->data.location, ch)));
> + res.reg_offset++;
> + }
> +}
> +
> void
> fs_visitor::visit(ir_expression *ir)
> {
> @@ -355,9 +467,22 @@ fs_visitor::visit(ir_expression *ir)
>
> if (try_emit_saturate(ir))
> return;
> - if (ir->operation == ir_binop_add) {
> +
> + /* Deal with the real oddball stuff first */
> + switch (ir->operation) {
> + case ir_binop_add:
> if (try_emit_mad(ir))
> - return;
> + return;
> + break;
> +
> + case ir_unop_interpolate_at_centroid:
> + case ir_binop_interpolate_at_offset:
> + case ir_binop_interpolate_at_sample:
> + emit_interpolate_expression(ir);
> + return;
> +
> + default:
> + break;
> }
>
> for (operand = 0; operand < ir->get_num_operands(); operand++) {
> @@ -815,6 +940,12 @@ fs_visitor::visit(ir_expression *ir)
> inst = emit(BRW_OPCODE_SEL, this->result, op[1], op[2]);
> inst->predicate = BRW_PREDICATE_NORMAL;
> break;
> +
> + case ir_unop_interpolate_at_centroid:
> + case ir_binop_interpolate_at_offset:
> + case ir_binop_interpolate_at_sample:
> + assert(!"not reached; already handled above");
> + break;
Use unreachable() here.
More information about the mesa-dev
mailing list