summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Paul <[email protected]>2012-06-29 16:59:46 -0600
committerBrian Paul <[email protected]>2012-07-05 08:03:19 -0600
commit30f8575fde673f2279aee1fbe89e7df07cb81081 (patch)
tree59625501e0f6949b05cafa1266a6f4014c3afccd
parent0bd3a75de9002e73214cde883691da558db7bc70 (diff)
svga: properly implement TRUNC instruction
Was previously implemented with FLOOR. Fixes quite a few piglit tests of float->int conversion, integer division, etc. v2: clean up left over debug/devel code, per Jose Reviewed-by: José Fonseca <[email protected]>
-rw-r--r--src/gallium/drivers/svga/svga_tgsi_insn.c55
1 files changed, 54 insertions, 1 deletions
diff --git a/src/gallium/drivers/svga/svga_tgsi_insn.c b/src/gallium/drivers/svga/svga_tgsi_insn.c
index 42df4195fcc..40c743306c7 100644
--- a/src/gallium/drivers/svga/svga_tgsi_insn.c
+++ b/src/gallium/drivers/svga/svga_tgsi_insn.c
@@ -2398,6 +2398,57 @@ static boolean emit_log(struct svga_shader_emitter *emit,
}
+/**
+ * Translate TGSI TRUNC instruction.
+ * We need to truncate toward zero. Ex: trunc(-1.9) = -1
+ * Different approaches are needed for VS versus PS.
+ */
+static boolean
+emit_trunc(struct svga_shader_emitter *emit,
+ const struct tgsi_full_instruction *insn)
+{
+ SVGA3dShaderDestToken dst = translate_dst_register(emit, insn, 0);
+ const struct src_register src0 =
+ translate_src_register(emit, &insn->Src[0] );
+ SVGA3dShaderDestToken t1 = get_temp(emit);
+
+ /* t1 = fract(abs(src0)) */
+ if (!submit_op1(emit, inst_token(SVGA3DOP_FRC), t1, absolute(src0)))
+ return FALSE;
+
+ /* t1 = abs(src0) - t1 */
+ if (!submit_op2(emit, inst_token(SVGA3DOP_ADD), t1, absolute(src0),
+ negate(src(t1))))
+ return FALSE;
+
+ /*
+ * Now we need to multiply t1 by the sign of the original value.
+ */
+ if (emit->unit == PIPE_SHADER_VERTEX) {
+ /* For VS: use SGN instruction */
+ /* Need another temp plus two extra/dummy registers */
+ SVGA3dShaderDestToken t2 = get_temp(emit), t3 = get_temp(emit),
+ t4 = get_temp(emit);
+
+ /* t2 = sign(src0) */
+ if (!submit_op3(emit, inst_token(SVGA3DOP_SGN), t2, src0,
+ src(t3), src(t4)))
+ return FALSE;
+
+ /* dst = t1 * t2 */
+ if (!submit_op2(emit, inst_token(SVGA3DOP_MUL), dst, src(t1), src(t2)))
+ return FALSE;
+ }
+ else {
+ /* For FS: Use CMP instruction */
+ return submit_op3(emit, inst_token( SVGA3DOP_CMP ), dst,
+ src0, src(t1), negate(src(t1)));
+ }
+
+ return TRUE;
+}
+
+
static boolean emit_bgnsub( struct svga_shader_emitter *emit,
unsigned position,
const struct tgsi_full_instruction *insn )
@@ -2488,9 +2539,11 @@ static boolean svga_emit_instruction( struct svga_shader_emitter *emit,
return emit_call( emit, insn );
case TGSI_OPCODE_FLR:
- case TGSI_OPCODE_TRUNC: /* should be TRUNC, not FLR */
return emit_floor( emit, insn );
+ case TGSI_OPCODE_TRUNC:
+ return emit_trunc( emit, insn );
+
case TGSI_OPCODE_CEIL:
return emit_ceil( emit, insn );