Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GS/HW: Improve Round Sprite upscaling fix to cause less problems [TEST] #10278

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 108 additions & 68 deletions pcsx2/GS/Renderers/HW/GSRendererHW.cpp
Original file line number Diff line number Diff line change
@@ -1859,106 +1859,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)
{
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
{
v[i + 1].U -= 8;
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);
@@ -3336,7 +3376,7 @@ void GSRendererHW::Draw()
}

// Noting to do if no texture is sampled
if (PRIM->FST && draw_sprite_tex)
if (PRIM->FST && draw_sprite_tex && rt && rt->m_scale > 1)
{
if ((GSConfig.UserHacks_RoundSprite > 1) || (GSConfig.UserHacks_RoundSprite == 1 && !m_vt.IsLinear()))
{