Signed-off-by: Chris Forbes <chr...@ijw.co.nz> --- src/mesa/drivers/dri/i965/brw_fs_visitor.cpp | 99 +++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-)
diff --git a/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp b/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp index 538f1b3..cd90a48 100644 --- a/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp +++ b/src/mesa/drivers/dri/i965/brw_fs_visitor.cpp @@ -328,7 +328,104 @@ fs_visitor::try_emit_mad(ir_expression *ir, int mul_arg) void fs_visitor::emit_interpolate_expression(ir_expression *ir) { - this->result = fs_reg(this, ir->type); + if (dispatch_width == 16) { + fail("interpolate_at_* not yet supported in SIMD16 mode."); + /* 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. + */ + return; + } + + ir_dereference * deref = ir->operands[0]->as_dereference(); + if (!deref) { + /* the api does not allow a swizzle here, but the varying packing code + * may have pushed one into here. + */ + ir_swizzle * 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 = 2; /* 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 = 1; /* interpolate at sample */ + imm_data = sample_num->value.i[0] << 4; + } break; + + case ir_binop_interpolate_at_offset: + { + ir_constant *const_offset = ir->operands[1]->as_constant(); + if (const_offset) { + msg_type = 0; /* per-message offset */ + imm_data = ((int)(const_offset->value.f[0] * 16)) | + ((int)(const_offset->value.f[1] * 16) << 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 */ + src2.reg_offset++; + this->result.reg_offset++; + } + + mlen = 2 * dispatch_width / 8; + msg_type = 3; /* per-slot offset */ + } + } break; + + default: + assert(!"Unreached"); + } + + 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(c->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++) { + emit(FS_OPCODE_LINTERP, res, + dst_x, dst_y, + fs_reg(interp_reg(var->location, i /* todo: swiz */))); + res.reg_offset++; + } } void -- 1.8.4.2 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev