From d2156c86eba1fe89481df61243cc303490f782d0 Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Fri, 10 Apr 2015 09:42:39 +0200 Subject: [PATCH] gsdx: improve previous hack for bilinear sprite PS2 uses a -0.5 offset before sampling so texels must be rounded to half-pixel boundary If fixes glitches on Venus and taisho-mononoke Note: I didn't fixed yet texture render in reverse because I don't have any test for it. --- plugins/GSdx/GSRendererHW.cpp | 50 ++++++++++++++++++++++++----------- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/plugins/GSdx/GSRendererHW.cpp b/plugins/GSdx/GSRendererHW.cpp index 890519e344..7d9f30fdf0 100644 --- a/plugins/GSdx/GSRendererHW.cpp +++ b/plugins/GSdx/GSRendererHW.cpp @@ -396,16 +396,23 @@ void GSRendererHW::Draw() else if ((m_userhacks_round_sprite_offset == 2) || (m_userhacks_round_sprite_offset == 1 && !m_vt.IsLinear())) { //#define DEBUG_U //#define DEBUG_V + //bool debug = m_vt.IsLinear(); + const int half = m_vt.IsLinear() ? 8 : 0; + for(size_t i = 0; i < count; i += 2) { - // Compute the coordinate of first texels (in native) + // Performance note: if it had any impact on perf, someone would port it to SSE + + // Compute the coordinate of first and last texels (in native with a linear filtering) float ax0 = alpha0(context->XYOFFSET.OFX, v[i].XYZ.X, v[i+1].XYZ.X); float ax1 = alpha1(context->XYOFFSET.OFX, v[i].XYZ.X, v[i+1].XYZ.X); int tx0 = Interpolate_UV(ax0, v[i].U, v[i+1].U); int tx1 = Interpolate_UV(ax1, v[i].U, v[i+1].U); #ifdef DEBUG_U - fprintf(stderr, "u0:%d and u1:%d\n", v[i].U, v[i+1].U); - fprintf(stderr, "a0:%f and a1:%f\n", ax0, ax1); - fprintf(stderr, "t0:%d and t1:%d\n", tx0, tx1); + if (debug) { + fprintf(stderr, "u0:%d and u1:%d\n", v[i].U, v[i+1].U); + fprintf(stderr, "a0:%f and a1:%f\n", ax0, ax1); + fprintf(stderr, "t0:%d and t1:%d\n", tx0, tx1); + } #endif float ay0 = alpha0(context->XYOFFSET.OFY, v[i].XYZ.Y, v[i+1].XYZ.Y); @@ -413,22 +420,33 @@ void GSRendererHW::Draw() int ty0 = Interpolate_UV(ay0, v[i].V, v[i+1].V); int ty1 = Interpolate_UV(ay1, v[i].V, v[i+1].V); #ifdef DEBUG_V - fprintf(stderr, "v0:%d and v1:%d\n", v[i].V, v[i+1].V); - fprintf(stderr, "a0:%f and a1:%f\n", ay0, ay1); - fprintf(stderr, "t0:%d and t1:%d\n", ty0, ty1); + if (debug) { + fprintf(stderr, "v0:%d and v1:%d\n", v[i].V, v[i+1].V); + fprintf(stderr, "a0:%f and a1:%f\n", ay0, ay1); + fprintf(stderr, "t0:%d and t1:%d\n", ty0, ty1); + } #endif #ifdef DEBUG_U - fprintf(stderr, "GREP_BEFORE %d => %d\n", v[i].U, v[i+1].U); + if (debug) + fprintf(stderr, "GREP_BEFORE %d => %d\n", v[i].U, v[i+1].U); #endif #ifdef DEBUG_V - fprintf(stderr, "GREP_BEFORE %d => %d\n", v[i].V, v[i+1].V); + if (debug) + fprintf(stderr, "GREP_BEFORE %d => %d\n", v[i].V, v[i+1].V); #endif #if 1 + // Use rounded value of the newly computed texture coordinate. It ensures + // that sampling will remains inside texture boundary + // + // Note for bilinear: in this mode the PS2 add -0.5 offset (aka half) and 4 texels + // will be sampled so (t0 - 8) and (t1 - 8 + 16) must be valid. + // + // Minus half for t1 case might be too much if (tx0 < tx1) { - v[i].U = tx0 + 1; - v[i+1].U = tx1 + 1 + 16; + v[i].U = tx0 + half + 1; + v[i+1].U = tx1 - half + 1 + 16; } else { v[i].U = tx0 + 15; v[i+1].U = tx1 + 15 + 16; @@ -436,8 +454,8 @@ void GSRendererHW::Draw() #endif #if 1 if (ty0 < ty1) { - v[i].V = ty0 + 1; - v[i+1].V = ty1 + 1 + 16; + v[i].V = ty0 + half + 1; + v[i+1].V = ty1 - half + 1 + 16; } else { v[i].V = ty0 + 15; v[i+1].V = ty1 + 15 + 16; @@ -445,10 +463,12 @@ void GSRendererHW::Draw() #endif #ifdef DEBUG_U - fprintf(stderr, "GREP_AFTER %d => %d\n\n", v[i].U, v[i+1].U); + if (debug) + fprintf(stderr, "GREP_AFTER %d => %d\n\n", v[i].U, v[i+1].U); #endif #ifdef DEBUG_V - fprintf(stderr, "GREP_AFTER %d => %d\n\n", v[i].V, v[i+1].V); + if (debug) + fprintf(stderr, "GREP_AFTER %d => %d\n\n", v[i].V, v[i+1].V); #endif }