Skip to content

Commit

Permalink
GS/HW: Allow 1:1 quads to be optimized for textures. Fixes for shuffles
Browse files Browse the repository at this point in the history
  • Loading branch information
refractionpcsx2 committed Jan 16, 2025
1 parent a508d4e commit 86b5e60
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 11 deletions.
37 changes: 31 additions & 6 deletions pcsx2/GS/GSState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3871,7 +3871,8 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL
const GSVector2 grad(uv_range / pos_range);
// Adjust texture range when sprites get scissor clipped. Since we linearly interpolate, this
// optimization doesn't work when perspective correction is enabled.
if (m_vt.m_primclass == GS_SPRITE_CLASS && PRIM->FST == 1 && m_primitive_covers_without_gaps != NoGapsType::GapsFound)
// Allowing for quads when the gradiant is 1. It's not guaranteed (would need to check the grandient on each vector), but should be close enough.
if ((m_vt.m_primclass == GS_SPRITE_CLASS || (m_vt.m_primclass == GS_TRIANGLE_CLASS && TrianglesAreQuads(false) && grad.x == 1.0f && grad.y == 1.0f)) && m_primitive_covers_without_gaps != NoGapsType::GapsFound)
{
// When coordinates are fractional, GS appears to draw to the right/bottom (effectively
// taking the ceiling), not to the top/left (taking the floor).
Expand All @@ -3882,11 +3883,24 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL

const GSVertex* vert_first = &m_vertex.buff[m_index.buff[0]];
const GSVertex* vert_second = &m_vertex.buff[m_index.buff[1]];
const GSVertex* vert_third = &m_vertex.buff[m_index.buff[2]];

GSVector4 new_st = st;
bool u_forward_check = false;
bool x_forward_check = false;
if (m_vt.m_primclass == GS_TRIANGLE_CLASS)
{
u_forward_check = PRIM->FST ? ((vert_first->U < vert_second->U) || (vert_first->U < vert_third->U)) : (((vert_first->ST.S / vert_first->RGBAQ.Q) < (vert_second->ST.S / vert_second->RGBAQ.Q)) || ((vert_first->ST.S / vert_first->RGBAQ.Q) < (vert_third->ST.S / vert_third->RGBAQ.Q)));
x_forward_check = (vert_first->XYZ.X < vert_second->XYZ.X) || (vert_first->XYZ.X < vert_third->XYZ.X);
}
else
{
u_forward_check = PRIM->FST ? (vert_first->U < vert_second->U) : ((vert_first->ST.T / vert_first->RGBAQ.Q) < (vert_second->ST.T / vert_first->RGBAQ.Q));
x_forward_check = vert_first->XYZ.Y < vert_second->XYZ.Y;
}
// Check if the UV coords are going in a different direction to the verts, if they match direction, no need to swap
const bool u_forward = vert_first->U < vert_second->U;
const bool x_forward = vert_first->XYZ.X < vert_second->XYZ.X;
const bool u_forward = u_forward_check;
const bool x_forward = x_forward_check;
const bool swap_x = u_forward != x_forward;

if (int_rc.left < scissored_rc.left)
Expand All @@ -3909,9 +3923,20 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL
st.x = new_st.x;
st.z = new_st.z;
}

const bool v_forward = vert_first->V < vert_second->V;
const bool y_forward = vert_first->XYZ.Y < vert_second->XYZ.Y;
bool v_forward_check = false;
bool y_forward_check = false;
if (m_vt.m_primclass == GS_TRIANGLE_CLASS)
{
v_forward_check = PRIM->FST ? ((vert_first->V < vert_second->V) || (vert_first->V < vert_third->V)) : (((vert_first->ST.T / vert_first->RGBAQ.Q) < (vert_second->ST.T / vert_second->RGBAQ.Q)) || ((vert_first->ST.T / vert_first->RGBAQ.Q) < (vert_third->ST.T / vert_third->RGBAQ.Q)));
y_forward_check = (vert_first->XYZ.Y < vert_second->XYZ.Y) || (vert_first->XYZ.Y < vert_third->XYZ.Y);
}
else
{
v_forward_check = PRIM->FST ? (vert_first->V < vert_second->V) : ((vert_first->ST.T / vert_first->RGBAQ.Q) < (vert_second->ST.T / vert_first->RGBAQ.Q));
y_forward_check = vert_first->XYZ.Y < vert_second->XYZ.Y;
}
const bool v_forward = v_forward_check;
const bool y_forward = y_forward_check;
const bool swap_y = v_forward != y_forward;

if (int_rc.top < scissored_rc.top)
Expand Down
2 changes: 1 addition & 1 deletion pcsx2/GS/Renderers/HW/GSHwHack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1081,7 +1081,7 @@ bool GSHwHack::OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds,

const GSVector4 sRect(0.0f, 0.0f, static_cast<float>(copy_size.x) / static_cast<float>(src_size.x), static_cast<float>(copy_size.y) / static_cast<float>(src_size.y));
// This is kind of a bodge because the game confuses everything since the source is really 16bit and it assumes it's really drawing 16bit on the copy back, resizing the target.
const GSVector4 dRect(0, 0, copy_size.x, copy_size.y * (src->m_32_bits_fmt ? 1 : 2));
const GSVector4 dRect(0, 0, copy_size.x, copy_size.y);

g_gs_device->StretchRect(src->m_texture, sRect, rt, dRect, true, true, true, false);

Expand Down
8 changes: 4 additions & 4 deletions pcsx2/GS/Renderers/HW/GSRendererHW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2584,7 +2584,7 @@ void GSRendererHW::Draw()
GIFRegTEX0 FRAME_TEX0;
bool shuffle_target = false;
if (!no_rt && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16 && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp >= 16 &&
(m_vt.m_primclass == GS_SPRITE_CLASS || (m_vt.m_primclass == GS_TRIANGLE_CLASS && (m_index.tail % 6) == 0 && TrianglesAreQuads(true))))
(m_vt.m_primclass == GS_SPRITE_CLASS || (m_vt.m_primclass == GS_TRIANGLE_CLASS && (m_index.tail % 6) == 0 && TrianglesAreQuads(true) && m_index.tail > 6)))
{
if (!shuffle_target && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp == 16)
{
Expand Down Expand Up @@ -2653,7 +2653,7 @@ void GSRendererHW::Draw()
return;
}

possible_shuffle &= src && (src->m_from_target != nullptr && (src->m_from_target->m_32_bits_fmt) || (m_skip && possible_shuffle));
possible_shuffle &= src && (src->m_from_target != nullptr || (m_skip && possible_shuffle));
// We don't know the alpha range of direct sources when we first tried to optimize the alpha test.
// Moving the texture lookup before the ATST optimization complicates things a lot, so instead,
// recompute it, and everything derived from it again if it changes.
Expand Down Expand Up @@ -4429,7 +4429,7 @@ __ri bool GSRendererHW::EmulateChannelShuffle(GSTextureCache::Target* src, bool
// Performance GPU note: it could be wise to reduce the size to
// the rendered size of the framebuffer

if (GSConfig.UserHacks_TextureInsideRt == GSTextureInRtMode::Disabled || (!m_in_target_draw && IsPageCopy()))
if (GSConfig.UserHacks_TextureInsideRt == GSTextureInRtMode::Disabled || (!m_in_target_draw && IsPageCopy()) || m_conf.ps.urban_chaos_hle || m_conf.ps.tales_of_abyss_hle)
{
GSVertex* s = &m_vertex.buff[0];
s[0].XYZ.X = static_cast<u16>(m_context->XYOFFSET.OFX + 0);
Expand Down Expand Up @@ -5703,7 +5703,7 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
target_region = false;
source_region.bits = 0;
//copied_rt = tex->m_from_target != nullptr;
if (m_in_target_draw)
if (page_offset && m_in_target_draw)
{
copy_size.x = m_r.width();
copy_size.y = m_r.height();
Expand Down

0 comments on commit 86b5e60

Please sign in to comment.