GS/HW: Allow 1:1 quads to be optimized for textures. Fixes for shuffles

This commit is contained in:
refractionpcsx2 2025-01-16 18:16:57 +00:00
parent 1ac2d9fba3
commit fd53ce2ec6
3 changed files with 36 additions and 11 deletions

View File

@ -3871,7 +3871,8 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL
const GSVector2 grad(uv_range / pos_range); const GSVector2 grad(uv_range / pos_range);
// Adjust texture range when sprites get scissor clipped. Since we linearly interpolate, this // Adjust texture range when sprites get scissor clipped. Since we linearly interpolate, this
// optimization doesn't work when perspective correction is enabled. // 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 // When coordinates are fractional, GS appears to draw to the right/bottom (effectively
// taking the ceiling), not to the top/left (taking the floor). // taking the ceiling), not to the top/left (taking the floor).
@ -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_first = &m_vertex.buff[m_index.buff[0]];
const GSVertex* vert_second = &m_vertex.buff[m_index.buff[1]]; 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; 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 // 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 u_forward = u_forward_check;
const bool x_forward = vert_first->XYZ.X < vert_second->XYZ.X; const bool x_forward = x_forward_check;
const bool swap_x = u_forward != x_forward; const bool swap_x = u_forward != x_forward;
if (int_rc.left < scissored_rc.left) if (int_rc.left < scissored_rc.left)
@ -3909,9 +3923,20 @@ GSState::TextureMinMaxResult GSState::GetTextureMinMax(GIFRegTEX0 TEX0, GIFRegCL
st.x = new_st.x; st.x = new_st.x;
st.z = new_st.z; st.z = new_st.z;
} }
bool v_forward_check = false;
const bool v_forward = vert_first->V < vert_second->V; bool y_forward_check = false;
const bool y_forward = vert_first->XYZ.Y < vert_second->XYZ.Y; 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; const bool swap_y = v_forward != y_forward;
if (int_rc.top < scissored_rc.top) if (int_rc.top < scissored_rc.top)

View File

@ -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)); 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. // 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); g_gs_device->StretchRect(src->m_texture, sRect, rt, dRect, true, true, true, false);

View File

@ -2584,7 +2584,7 @@ void GSRendererHW::Draw()
GIFRegTEX0 FRAME_TEX0; GIFRegTEX0 FRAME_TEX0;
bool shuffle_target = false; 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 && 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) if (!shuffle_target && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp == 16)
{ {
@ -2653,7 +2653,7 @@ void GSRendererHW::Draw()
return; 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. // 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, // 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. // recompute it, and everything derived from it again if it changes.
@ -4429,7 +4429,7 @@ __ri bool GSRendererHW::EmulateChannelShuffle(GSTextureCache::Target* src, bool
// Performance GPU note: it could be wise to reduce the size to // Performance GPU note: it could be wise to reduce the size to
// the rendered size of the framebuffer // 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]; GSVertex* s = &m_vertex.buff[0];
s[0].XYZ.X = static_cast<u16>(m_context->XYOFFSET.OFX + 0); s[0].XYZ.X = static_cast<u16>(m_context->XYOFFSET.OFX + 0);
@ -5703,7 +5703,7 @@ __ri void GSRendererHW::HandleTextureHazards(const GSTextureCache::Target* rt, c
target_region = false; target_region = false;
source_region.bits = 0; source_region.bits = 0;
//copied_rt = tex->m_from_target != nullptr; //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.x = m_r.width();
copy_size.y = m_r.height(); copy_size.y = m_r.height();