svga: properly implement TRUNC instruction
authorBrian Paul <brianp@vmware.com>
Fri, 29 Jun 2012 22:59:46 +0000 (16:59 -0600)
committerBrian Paul <brianp@vmware.com>
Thu, 5 Jul 2012 14:03:19 +0000 (08:03 -0600)
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 <jfonseca@vmware.com>
src/gallium/drivers/svga/svga_tgsi_insn.c

index 42df4195fcca1492a840217c5b48d7bbac0b42ac..40c743306c770f2ef5b2bff4cdf44ab3d7410dbb 100644 (file)
@@ -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 );