diff --git a/pcsx2/GS/GSState.cpp b/pcsx2/GS/GSState.cpp index 18787838d1..0ea7b95589 100644 --- a/pcsx2/GS/GSState.cpp +++ b/pcsx2/GS/GSState.cpp @@ -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). @@ -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) @@ -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) diff --git a/pcsx2/GS/Renderers/HW/GSHwHack.cpp b/pcsx2/GS/Renderers/HW/GSHwHack.cpp index 7114126577..bf6849f307 100644 --- a/pcsx2/GS/Renderers/HW/GSHwHack.cpp +++ b/pcsx2/GS/Renderers/HW/GSHwHack.cpp @@ -1081,7 +1081,7 @@ bool GSHwHack::OI_SonicUnleashed(GSRendererHW& r, GSTexture* rt, GSTexture* ds, const GSVector4 sRect(0.0f, 0.0f, static_cast(copy_size.x) / static_cast(src_size.x), static_cast(copy_size.y) / static_cast(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); diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 8d64b1e6ee..71a85cf719 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -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) { @@ -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. @@ -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(m_context->XYOFFSET.OFX + 0); @@ -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();