dst, src0, ir_to_mesa_undef, ir_to_mesa_undef);
}
+/**
+ * Emits Mesa scalar opcodes to produce unique answers across channels.
+ *
+ * Some Mesa opcodes are scalar-only, like ARB_fp/vp. The src X
+ * channel determines the result across all channels. So to do a vec4
+ * of this operation, we want to emit a scalar per source channel used
+ * to produce dest channels.
+ */
+void
+ir_to_mesa_emit_scalar_op1(struct mbtree *tree, enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0)
+{
+ int i, j;
+ int done_mask = 0;
+
+ /* Mesa RCP is a scalar operation splatting results to all channels,
+ * like ARB_fp/vp. So emit as many RCPs as necessary to cover our
+ * dst channels.
+ */
+ for (i = 0; i < 4; i++) {
+ int this_mask = (1 << i);
+ ir_to_mesa_instruction *inst;
+ ir_to_mesa_src_reg src = src0;
+
+ if (done_mask & this_mask)
+ continue;
+
+ int src_swiz = GET_SWZ(src.swizzle, i);
+ for (j = i + 1; j < 4; j++) {
+ if (GET_SWZ(src.swizzle, j) == src_swiz) {
+ this_mask |= (1 << j);
+ }
+ }
+ src.swizzle = MAKE_SWIZZLE4(src_swiz, src_swiz,
+ src_swiz, src_swiz);
+
+ inst = ir_to_mesa_emit_op1(tree, op,
+ dst,
+ src);
+ inst->dst_reg.writemask = this_mask;
+ done_mask |= this_mask;
+ }
+}
+
struct mbtree *
ir_to_mesa_visitor::create_tree(int op,
ir_instruction *ir,
mesa_inst->DstReg.File = inst->dst_reg.file;
mesa_inst->DstReg.Index = inst->dst_reg.index;
mesa_inst->DstReg.CondMask = COND_TR;
- mesa_inst->DstReg.WriteMask = WRITEMASK_XYZW;
+ mesa_inst->DstReg.WriteMask = inst->dst_reg.writemask;
mesa_inst->SrcReg[0] = mesa_src_reg_from_ir_src_reg(inst->src_reg[0]);
mesa_inst->SrcReg[1] = mesa_src_reg_from_ir_src_reg(inst->src_reg[1]);
mesa_inst->SrcReg[2] = mesa_src_reg_from_ir_src_reg(inst->src_reg[2]);
typedef struct ir_to_mesa_dst_reg {
int file; /**< PROGRAM_* from Mesa */
int index; /**< temporary index, VERT_ATTRIB_*, FRAG_ATTRIB_*, etc. */
+ int writemask; /**< Bitfield of WRITEMASK_[XYZW] */
} ir_to_mesa_dst_reg;
extern ir_to_mesa_src_reg ir_to_mesa_undef;
ir_to_mesa_src_reg src1,
ir_to_mesa_src_reg src2);
+void
+ir_to_mesa_emit_scalar_op1(struct mbtree *tree, enum prog_opcode op,
+ ir_to_mesa_dst_reg dst,
+ ir_to_mesa_src_reg src0);
+
inline ir_to_mesa_dst_reg
ir_to_mesa_dst_reg_from_src(ir_to_mesa_src_reg reg)
{
dst_reg.file = reg.file;
dst_reg.index = reg.index;
+ dst_reg.writemask = WRITEMASK_XYZW;
return dst_reg;
}
vec4: div_vec4_vec4(vec4, vec4) 1
{
- /* FINISHME: Mesa RCP only uses the X channel, this node is for vec4. */
- ir_to_mesa_emit_op1(tree, OPCODE_RCP,
- ir_to_mesa_dst_reg_from_src(tree->src_reg),
- tree->right->src_reg);
+ ir_to_mesa_emit_scalar_op1(tree, OPCODE_RCP,
+ ir_to_mesa_dst_reg_from_src(tree->src_reg),
+ tree->left->src_reg);
ir_to_mesa_emit_op2(tree, OPCODE_MUL,
ir_to_mesa_dst_reg_from_src(tree->src_reg),
vec4: sqrt_vec4(vec4) 1
{
- /* FINISHME: Mesa RSQ only uses the X channel, this node is for vec4. */
- ir_to_mesa_emit_op1(tree, OPCODE_RSQ,
- ir_to_mesa_dst_reg_from_src(tree->src_reg),
- tree->left->src_reg);
+ ir_to_mesa_emit_scalar_op1(tree, OPCODE_RSQ,
+ ir_to_mesa_dst_reg_from_src(tree->src_reg),
+ tree->left->src_reg);
ir_to_mesa_emit_op1(tree, OPCODE_RCP,
ir_to_mesa_dst_reg_from_src(tree->src_reg),