From 5298e6a966ece3e1757693ff11ddfe03fe99692a Mon Sep 17 00:00:00 2001 From: refractionpcsx2 Date: Wed, 15 Nov 2023 18:44:44 +0000 Subject: [PATCH] GS/HW: Improve Round Sprite upscaling fix to cause less problems --- pcsx2/GS/Renderers/HW/GSRendererHW.cpp | 174 +++++++++++++++---------- 1 file changed, 107 insertions(+), 67 deletions(-) diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 6c013cae0e46a..8a3dab97c1718 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -1704,106 +1704,146 @@ void GSRendererHW::RoundSpriteOffset() for (u32 i = 0; i < count; i += 2) { // Performance note: if it had any impact on perf, someone would port it to SSE (AKA GSVector) - - // Compute the coordinate of first and last texels (in native with a linear filtering) + // if the draw is page aligned, then don't round it. + const int tex_width = std::max(1, (v[i + 1].U - v[i].U) >> 4); const int ox = m_context->XYOFFSET.OFX; - const int X0 = v[i].XYZ.X - ox; - const int X1 = v[i + 1].XYZ.X - ox; const int Lx = (v[i + 1].XYZ.X - v[i].XYZ.X); - const float ax0 = alpha0(Lx, X0, X1); - const float ax1 = alpha1(Lx, X0, X1); - const u16 tx0 = Interpolate_UV(ax0, v[i].U, v[i + 1].U); - const u16 tx1 = Interpolate_UV(ax1, v[i].U, v[i + 1].U); -#ifdef DEBUG_U - 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 - const int oy = m_context->XYOFFSET.OFY; - const int Y0 = v[i].XYZ.Y - oy; - const int Y1 = v[i + 1].XYZ.Y - oy; - const int Ly = (v[i + 1].XYZ.Y - v[i].XYZ.Y); - const float ay0 = alpha0(Ly, Y0, Y1); - const float ay1 = alpha1(Ly, Y0, Y1); - const u16 ty0 = Interpolate_UV(ay0, v[i].V, v[i + 1].V); - const u16 ty1 = Interpolate_UV(ay1, v[i].V, v[i + 1].V); -#ifdef DEBUG_V - if (debug) + if ((((Lx - ox) >> 4) % tex_width) != 0) { - 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 - + // Compute the coordinate of first and last texels (in native with a linear filtering) + const int X0 = v[i].XYZ.X - ox; + const int X1 = v[i + 1].XYZ.X - ox; + const float ax0 = alpha0(Lx, X0, X1); + const float ax1 = alpha1(Lx, X0, X1); + const u16 tx0 = Interpolate_UV(ax0, v[i].U, v[i + 1].U); + const u16 tx1 = Interpolate_UV(ax1, v[i].U, v[i + 1].U); + //DevCon.Warning("Tex width %d draw width %d (X %x -> %x U %x -> %x", tex_width, ((v[i + 1].XYZ.X - v[i].XYZ.X) >> 4), X0, X1, v[i].U, v[i+1].U); #ifdef DEBUG_U - if (debug) - fprintf(stderr, "GREP_BEFORE %d => %d\n", v[i].U, v[i + 1].U); -#endif -#ifdef DEBUG_V - if (debug) - fprintf(stderr, "GREP_BEFORE %d => %d\n", v[i].V, v[i + 1].V); + 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 - #if 1 - // Use rounded value of the newly computed texture coordinate. It ensures - // that sampling will remains inside texture boundary - // - // Note for bilinear: by definition it will never work correctly! A sligh modification - // of interpolation migth trigger a discard (with alpha testing) - // Let's use something simple that correct really bad case (for a couple of 2D games). - // I hope it won't create too much glitches. - if (linear) - { - const int Lu = v[i + 1].U - v[i].U; - // Note 32 is based on taisho-mononoke - if ((Lu > 0) && (Lu <= (Lx + 32))) + // Use rounded value of the newly computed texture coordinate. It ensures + // that sampling will remains inside texture boundary + // + // Note for bilinear: by definition it will never work correctly! A sligh modification + // of interpolation migth trigger a discard (with alpha testing) + // Let's use something simple that correct really bad case (for a couple of 2D games). + // I hope it won't create too much glitches. + if (linear) { - v[i + 1].U -= 8; + const int Lu = v[i + 1].U - v[i].U; + // Note 32 is based on taisho-mononoke + if ((Lu > 0) && (Lu <= (Lx + 32))) + { + v[i + 1].U -= 8; + } } + else + { + if (tx0 <= tx1) + { + v[i].U = tx0; + v[i + 1].U = tx1 + 16; + } + else + { + v[i].U = tx0 + 15; + v[i + 1].U = tx1; + } + } +#endif } else { - if (tx0 <= tx1) + if (((v[i + 1].U & 0xf) ^ ((v[i + 1].XYZ.X - ox) & 0xf)) && ((v[i + 1].U - v[i].U) >> 4) == tex_width && (Lx >> 4) / tex_width <= 2) { - v[i].U = tx0; - v[i + 1].U = tx1 + 16; + v[i].U &= ~0xf; + v[i + 1].U -= 8; } else { - v[i].U = tx0 + 15; - v[i + 1].U = tx1; + v[i].U &= ~0xf; + v[i + 1].U &= ~0xf; + v[i].U |= (v[i].XYZ.X - ox) & 0xf; + v[i + 1].U |= (v[i + 1].XYZ.X - ox) & 0xf; } } + + const int tex_height = std::max(1, (v[i + 1].V - v[i].V) >> 4); + const int oy = m_context->XYOFFSET.OFY; + const int Ly = (v[i + 1].XYZ.Y - v[i].XYZ.Y); + + if ((((Ly - oy) >> 4) % tex_height) != 0) + { + const int Y0 = v[i].XYZ.Y - oy; + const int Y1 = v[i + 1].XYZ.Y - oy; + const float ay0 = alpha0(Ly, Y0, Y1); + const float ay1 = alpha1(Ly, Y0, Y1); + const u16 ty0 = Interpolate_UV(ay0, v[i].V, v[i + 1].V); + const u16 ty1 = Interpolate_UV(ay1, v[i].V, v[i + 1].V); +#ifdef DEBUG_V + 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 #if 1 - if (linear) - { - const int Lv = v[i + 1].V - v[i].V; - if ((Lv > 0) && (Lv <= (Ly + 32))) + if (linear) { - v[i + 1].V -= 8; + const int Lv = v[i + 1].V - v[i].V; + if ((Lv > 0) && (Lv <= (Ly + 32))) + { + v[i + 1].V -= 8; + } + } + else + { + if (ty0 <= ty1) + { + v[i].V = ty0; + v[i + 1].V = ty1 + 16; + } + else + { + v[i].V = ty0 + 15; + v[i + 1].V = ty1; + } } +#endif } else { - if (ty0 <= ty1) + if (((v[i + 1].V & 0xf) ^ ((v[i + 1].XYZ.Y - oy) & 0xf)) && ((v[i + 1].V - v[i].V) >> 4) == tex_height && (Ly >> 4) / tex_height <= 2) { - v[i].V = ty0; - v[i + 1].V = ty1 + 16; + v[i].V &= ~0xf; + v[i + 1].V -= 8; } else { - v[i].V = ty0 + 15; - v[i + 1].V = ty1; + v[i].V &= ~0xf; + v[i + 1].V &= ~0xf; + v[i].V |= (v[i].XYZ.Y - oy) & 0xf; + v[i + 1].V |= (v[i + 1].XYZ.Y - oy) & 0xf; } } +#ifdef DEBUG_U + if (debug) + fprintf(stderr, "GREP_BEFORE %d => %d\n", v[i].U, v[i + 1].U); +#endif +#ifdef DEBUG_V + if (debug) + fprintf(stderr, "GREP_BEFORE %d => %d\n", v[i].V, v[i + 1].V); #endif + #ifdef DEBUG_U if (debug) fprintf(stderr, "GREP_AFTER %d => %d\n\n", v[i].U, v[i + 1].U);