ir_to_mesa: Produce multiple scalar ops when required to produce vec4s.
authorEric Anholt <eric@anholt.net>
Thu, 6 May 2010 00:21:18 +0000 (17:21 -0700)
committerEric Anholt <eric@anholt.net>
Thu, 24 Jun 2010 22:05:19 +0000 (15:05 -0700)
Fixes the code emitted in a test shader for vec2 texcoord / vec2 tex_size.

ir_to_mesa.cpp
ir_to_mesa.h
mesa_codegen.brg

index eb55f82e27ff5effd62cf14aaa8999e2e1ca097c..77ca6df73c709d21c40bbeb2b84c2d3a34062a95 100644 (file)
@@ -94,6 +94,51 @@ ir_to_mesa_emit_op1(struct mbtree *tree, enum prog_opcode op,
                              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,
@@ -553,7 +598,7 @@ do_ir_to_mesa(exec_list *instructions)
       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]);
index cef27f8b79cd17bdc376c9db3ac88c59c4a91078..c8ceb4c1715fdda34f7ef06db8228b8763931bc1 100644 (file)
@@ -45,6 +45,7 @@ typedef struct ir_to_mesa_src_reg {
 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;
@@ -159,6 +160,11 @@ ir_to_mesa_emit_op3(struct mbtree *tree, enum prog_opcode op,
                    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)
 {
@@ -166,6 +172,7 @@ 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;
 }
index f1f24dab84ffd1d1fdccc52b6e471e386882f8e8..3191a44c2103923e8fd6dac567c33adceb27d64b 100644 (file)
@@ -184,10 +184,9 @@ vec4: dp2_vec4_vec4(vec4, vec4) 1
 
 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),
@@ -197,10 +196,9 @@ vec4: div_vec4_vec4(vec4, vec4) 1
 
 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),