i965: Correctly emit the RNDZ instruction.
authorKenneth Graunke <kenneth@whitecape.org>
Thu, 14 Oct 2010 18:40:19 +0000 (11:40 -0700)
committerKenneth Graunke <kenneth@whitecape.org>
Thu, 14 Oct 2010 19:40:16 +0000 (12:40 -0700)
Simply using RNDU, RNDZ, or RNDE does not produce the desired result.
Rather, the RND* instructions place a value in the destination register
that may be 1 less than the correct answer.  They can also set per-channel
"increment bits" in a flag register, which, if set, mean dest needs to
be incremented by 1.  A second instruction - a predicated add -
completes the job.

Notably, RNDD always produces the correct answer in a single
instruction.

Fixes piglit test glsl-fs-trunc.

src/mesa/drivers/dri/i965/brw_eu.h
src/mesa/drivers/dri/i965/brw_eu_emit.c

index c0deb238c2c9240ededde711244518e28ca94a36..c16613e3df58686f8bc514a509a779e00deae2f5 100644 (file)
@@ -789,6 +789,10 @@ struct brw_instruction *brw_##OP(struct brw_compile *p,    \
              struct brw_reg src0,                      \
              struct brw_reg src1);
 
+#define ROUND(OP) \
+void brw_##OP(struct brw_compile *p, struct brw_reg dest, struct brw_reg src0);
+
+
 ALU1(MOV)
 ALU2(SEL)
 ALU1(NOT)
@@ -805,7 +809,6 @@ ALU2(ADD)
 ALU2(MUL)
 ALU1(FRC)
 ALU1(RNDD)
-ALU1(RNDZ)
 ALU2(MAC)
 ALU2(MACH)
 ALU1(LZD)
@@ -816,9 +819,11 @@ ALU2(DP2)
 ALU2(LINE)
 ALU2(PLN)
 
+ROUND(RNDZ)
+
 #undef ALU1
 #undef ALU2
-
+#undef ROUND
 
 
 /* Helpers for SEND instruction:
index 41286382d0ed164ec34c114331a12070b971cf95..68c6c47763bfd953c854775b763a71f810ad3794 100644 (file)
@@ -654,6 +654,26 @@ struct brw_instruction *brw_##OP(struct brw_compile *p,    \
    return brw_alu2(p, BRW_OPCODE_##OP, dest, src0, src1);      \
 }
 
+/* Rounding operations (other than RNDD) require two instructions - the first
+ * stores a rounded value (possibly the wrong way) in the dest register, but
+ * also sets a per-channel "increment bit" in the flag register.  A predicated
+ * add of 1.0 fixes dest to contain the desired result.
+ */
+#define ROUND(OP)                                                            \
+void brw_##OP(struct brw_compile *p,                                         \
+             struct brw_reg dest,                                            \
+             struct brw_reg src)                                             \
+{                                                                            \
+   struct brw_instruction *rnd, *add;                                        \
+   rnd = next_insn(p, BRW_OPCODE_##OP);                                              \
+   brw_set_dest(rnd, dest);                                                  \
+   brw_set_src0(rnd, src);                                                   \
+   rnd->header.destreg__conditionalmod = 0x7; /* turn on round-increments */  \
+                                                                             \
+   add = brw_ADD(p, dest, dest, brw_imm_f(1.0f));                            \
+   add->header.predicate_control = BRW_PREDICATE_NORMAL;                     \
+}
+
 
 ALU1(MOV)
 ALU2(SEL)
@@ -668,7 +688,6 @@ ALU2(RSL)
 ALU2(ASR)
 ALU1(FRC)
 ALU1(RNDD)
-ALU1(RNDZ)
 ALU2(MAC)
 ALU2(MACH)
 ALU1(LZD)
@@ -679,6 +698,10 @@ ALU2(DP2)
 ALU2(LINE)
 ALU2(PLN)
 
+
+ROUND(RNDZ)
+
+
 struct brw_instruction *brw_ADD(struct brw_compile *p,
                                struct brw_reg dest,
                                struct brw_reg src0,