summaryrefslogtreecommitdiff
path: root/src/mesa/drivers/dri/i965/brw_wm_fp.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/drivers/dri/i965/brw_wm_fp.c')
-rw-r--r--src/mesa/drivers/dri/i965/brw_wm_fp.c112
1 files changed, 79 insertions, 33 deletions
diff --git a/src/mesa/drivers/dri/i965/brw_wm_fp.c b/src/mesa/drivers/dri/i965/brw_wm_fp.c
index b9e8dd2e96e..5dc076a8257 100644
--- a/src/mesa/drivers/dri/i965/brw_wm_fp.c
+++ b/src/mesa/drivers/dri/i965/brw_wm_fp.c
@@ -226,9 +226,42 @@ static struct prog_instruction * emit_op(struct brw_wm_compile *c,
0, 0, 0, /* tex unit, target, shadow */
src0, src1, src2);
}
-
+/* Many Mesa opcodes produce the same value across all the result channels.
+ * We'd rather not have to support that splatting in the opcode implementations,
+ * and brw_wm_pass*.c wants to optimize them out by shuffling references around
+ * anyway. We can easily get both by emitting the opcode to one channel, and
+ * then MOVing it to the others, which brw_wm_pass*.c already understands.
+ */
+static struct prog_instruction *emit_scalar_insn(struct brw_wm_compile *c,
+ const struct prog_instruction *inst0)
+{
+ struct prog_instruction *inst;
+ unsigned int dst_chan;
+ unsigned int other_channel_mask;
+
+ if (inst0->DstReg.WriteMask == 0)
+ return NULL;
+
+ dst_chan = _mesa_ffs(inst0->DstReg.WriteMask) - 1;
+ inst = get_fp_inst(c);
+ *inst = *inst0;
+ inst->DstReg.WriteMask = 1 << dst_chan;
+
+ other_channel_mask = inst0->DstReg.WriteMask & ~(1 << dst_chan);
+ if (other_channel_mask != 0) {
+ inst = emit_op(c,
+ OPCODE_MOV,
+ dst_mask(inst0->DstReg, other_channel_mask),
+ 0,
+ src_swizzle1(src_reg_from_dst(inst0->DstReg), dst_chan),
+ src_undef(),
+ src_undef());
+ }
+ return inst;
+}
+
/***********************************************************************
* Special instructions for interpolation and other tasks
@@ -376,14 +409,6 @@ static void emit_interp( struct brw_wm_compile *c,
}
break;
case FRAG_ATTRIB_FOGC:
- /* The FOGC input is really special. When a program uses glFogFragCoord,
- * the results returned are supposed to be (f,0,0,1). But for Mesa GLSL,
- * the glFrontFacing and glPointCoord values are also stashed in FOGC.
- * So, write the interpolated fog value to X, then either 0, 1, or the
- * stashed values to Y, Z, W. Note that this means that
- * glFogFragCoord.yzw can be wrong in those cases!
- */
-
/* Interpolate the fog coordinate */
emit_op(c,
WM_PINTERP,
@@ -393,26 +418,40 @@ static void emit_interp( struct brw_wm_compile *c,
deltas,
get_pixel_w(c));
- /* Move the front facing value into FOGC.y if it's needed. */
- if (c->fp->program.UsesFrontFacing) {
- emit_op(c,
- WM_FRONTFACING,
- dst_mask(dst, WRITEMASK_Y),
- 0,
- src_undef(),
- src_undef(),
- src_undef());
- } else {
- emit_op(c,
- OPCODE_MOV,
- dst_mask(dst, WRITEMASK_Y),
- 0,
- src_swizzle1(interp, SWIZZLE_ZERO),
- src_undef(),
- src_undef());
- }
+ emit_op(c,
+ OPCODE_MOV,
+ dst_mask(dst, WRITEMASK_YZW),
+ 0,
+ src_swizzle(interp,
+ SWIZZLE_ZERO,
+ SWIZZLE_ZERO,
+ SWIZZLE_ZERO,
+ SWIZZLE_ONE),
+ src_undef(),
+ src_undef());
+ break;
+
+ case FRAG_ATTRIB_FACE:
+ /* XXX review/test this case */
+ emit_op(c,
+ WM_FRONTFACING,
+ dst_mask(dst, WRITEMASK_X),
+ 0,
+ src_undef(),
+ src_undef(),
+ src_undef());
+ break;
+
+ case FRAG_ATTRIB_PNTC:
+ /* XXX review/test this case */
+ emit_op(c,
+ WM_PINTERP,
+ dst_mask(dst, WRITEMASK_XY),
+ 0,
+ interp,
+ deltas,
+ get_pixel_w(c));
- /* Should do the PointCoord thing here. */
emit_op(c,
OPCODE_MOV,
dst_mask(dst, WRITEMASK_ZW),
@@ -425,6 +464,7 @@ static void emit_interp( struct brw_wm_compile *c,
src_undef(),
src_undef());
break;
+
default:
emit_op(c,
WM_PINTERP,
@@ -683,7 +723,7 @@ static void precalc_tex( struct brw_wm_compile *c,
/* tmp0 = 1 / tmp1 */
emit_op(c, OPCODE_RCP,
- tmp0,
+ dst_mask(tmp0, WRITEMASK_X),
0,
tmp1src,
src_undef(),
@@ -694,7 +734,7 @@ static void precalc_tex( struct brw_wm_compile *c,
tmpcoord,
0,
src0,
- tmp0src,
+ src_swizzle1(tmp0src, SWIZZLE_X),
src_undef());
release_temp(c, tmp0);
@@ -717,7 +757,11 @@ static void precalc_tex( struct brw_wm_compile *c,
tmpcoord,
0,
inst->SrcReg[0],
- scale,
+ src_swizzle(scale,
+ SWIZZLE_X,
+ SWIZZLE_Y,
+ SWIZZLE_ONE,
+ SWIZZLE_ONE),
src_undef());
coord = src_reg_from_dst(tmpcoord);
@@ -1134,9 +1178,11 @@ void brw_wm_pass_fp( struct brw_wm_compile *c )
break;
case OPCODE_PRINT:
break;
-
default:
- emit_insn(c, inst);
+ if (brw_wm_is_scalar_result(inst->Opcode))
+ emit_scalar_insn(c, inst);
+ else
+ emit_insn(c, inst);
break;
}
}