diff options
author | Brian Paul <[email protected]> | 2012-06-29 16:59:46 -0600 |
---|---|---|
committer | Brian Paul <[email protected]> | 2012-07-05 08:03:19 -0600 |
commit | 30f8575fde673f2279aee1fbe89e7df07cb81081 (patch) | |
tree | 59625501e0f6949b05cafa1266a6f4014c3afccd | |
parent | 0bd3a75de9002e73214cde883691da558db7bc70 (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.c | 55 |
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 ); |