summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKenneth Graunke <[email protected]>2010-10-14 11:40:19 -0700
committerKenneth Graunke <[email protected]>2010-10-14 12:40:16 -0700
commit897f6d3c7d06316b0535971cc2de318157c23692 (patch)
treeedd5d5dc7e7192667e4386ef035e8b8b96b22fdb
parentf541b685aaf404fa7c8142f51d91c2720d82f264 (diff)
i965: Correctly emit the RNDZ instruction.
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.
-rw-r--r--src/mesa/drivers/dri/i965/brw_eu.h9
-rw-r--r--src/mesa/drivers/dri/i965/brw_eu_emit.c25
2 files changed, 31 insertions, 3 deletions
diff --git a/src/mesa/drivers/dri/i965/brw_eu.h b/src/mesa/drivers/dri/i965/brw_eu.h
index c0deb238c2c..c16613e3df5 100644
--- a/src/mesa/drivers/dri/i965/brw_eu.h
+++ b/src/mesa/drivers/dri/i965/brw_eu.h
@@ -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:
diff --git a/src/mesa/drivers/dri/i965/brw_eu_emit.c b/src/mesa/drivers/dri/i965/brw_eu_emit.c
index 41286382d0e..68c6c47763b 100644
--- a/src/mesa/drivers/dri/i965/brw_eu_emit.c
+++ b/src/mesa/drivers/dri/i965/brw_eu_emit.c
@@ -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,