diff --git a/pcsx2/GS/Renderers/HW/GSHwHack.cpp b/pcsx2/GS/Renderers/HW/GSHwHack.cpp index aff3f89a4a..cbba464bd5 100644 --- a/pcsx2/GS/Renderers/HW/GSHwHack.cpp +++ b/pcsx2/GS/Renderers/HW/GSHwHack.cpp @@ -608,7 +608,7 @@ bool GSHwHack::GSC_NFSUndercover(GSRendererHW& r, int& skip) if (RPRIM->TME && Frame.PSM == PSMCT16S && Frame.FBMSK != 0 && Frame.FBW == 10 && Texture.TBW == 1 && Texture.TBP0 == 0x02800 && Texture.PSM == PSMZ16S) { GSVertex* v = &r.m_vertex.buff[1]; - v[0].XYZ.X = static_cast(RCONTEXT->XYOFFSET.OFX + (r.m_r.z << 4)); + v[0].XYZ.X = static_cast(RCONTEXT->XYOFFSET.OFX + ((r.m_r.z * 2) << 4)); v[0].XYZ.Y = static_cast(RCONTEXT->XYOFFSET.OFY + (r.m_r.w << 4)); v[0].U = r.m_r.z << 4; v[0].V = r.m_r.w << 4; diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 1b4e579cd5..6c013cae0e 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -400,30 +400,27 @@ void GSRendererHW::ConvertSpriteTextureShuffle(bool& write_ba, bool& read_ba, GS return; } - bool half_bottom_vert = true; bool half_right_vert = true; - bool half_bottom_uv = true; - bool half_right_uv = true; + bool half_bottom_vert = true; + bool half_right_uv = !m_copy_16bit_to_target_shuffle; + bool half_bottom_uv = !m_copy_16bit_to_target_shuffle; if (m_same_group_texture_shuffle) { if (m_cached_ctx.FRAME.FBW != rt->m_TEX0.TBW && m_cached_ctx.FRAME.FBW == rt->m_TEX0.TBW * 2) - half_right_vert = false; - else half_bottom_vert = false; + else + half_right_vert = false; } else { // Different source (maybe?) // If a game does the texture and frame doubling differently, they can burn in hell. - if (m_cached_ctx.TEX0.TBP0 != m_cached_ctx.FRAME.Block()) + if (!m_copy_16bit_to_target_shuffle && m_cached_ctx.TEX0.TBP0 != m_cached_ctx.FRAME.Block()) { - // No super source of truth here, since the width can get batted around, the valid is probably our best bet. - const int tex_width = tex->m_target ? tex->m_from_target->m_valid.z : (tex->m_TEX0.TBW * 64); - const int tex_tbw = tex->m_target ? tex->m_from_target_TEX0.TBW : tex->m_TEX0.TBW; - const int clamp_minu = m_context->CLAMP.MINU; - const int clamp_maxu = m_context->CLAMP.MAXU; - int max_tex_draw_width = std::min(static_cast(m_vt.m_max.t.x), 1 << m_cached_ctx.TEX0.TW); + unsigned int max_tex_draw_width = std::min(static_cast(m_vt.m_max.t.x + (!read_ba ? 8 : 0)), 1 << m_cached_ctx.TEX0.TW); + const unsigned int clamp_minu = m_context->CLAMP.MINU; + const unsigned int clamp_maxu = m_context->CLAMP.MAXU; switch (m_context->CLAMP.WMS) { @@ -437,28 +434,34 @@ void GSRendererHW::ConvertSpriteTextureShuffle(bool& write_ba, bool& read_ba, GS break; } - if ((static_cast(m_cached_ctx.TEX0.TBW * 64) >= std::min(tex_width * 2, 1024) && tex_tbw != m_cached_ctx.TEX0.TBW) || (m_cached_ctx.TEX0.TBW * 64) < floor(max_tex_draw_width)) - { - half_right_uv = false; - half_right_vert = false; - } - else + // No super source of truth here, since the width can get batted around, the valid is probably our best bet. + // Dogs will reuse the Z in a different size format for a completely unrelated draw with an FBW of 2, then go back to using it in full width + const bool size_is_wrong = tex->m_target ? (static_cast(tex->m_from_target_TEX0.TBW * 64) < tex->m_from_target->m_valid.z / 2) : false; + const int tex_width = tex->m_target ? std::min(tex->m_from_target->m_valid.z, size_is_wrong ? tex->m_from_target->m_valid.z : static_cast(tex->m_from_target_TEX0.TBW * 64)) : max_tex_draw_width; + const int tex_tbw = tex->m_target ? tex->m_from_target_TEX0.TBW : tex->m_TEX0.TBW; + + if (static_cast(m_cached_ctx.TEX0.TBW * 64) >= (tex_width * 2) && tex_tbw != m_cached_ctx.TEX0.TBW) { half_bottom_uv = false; half_bottom_vert = false; } + else + { + half_right_uv = false; + half_right_vert = false; + } } else { if ((floor(m_vt.m_max.p.y) <= rt->m_valid.w) && ((floor(m_vt.m_max.p.x) > (m_cached_ctx.FRAME.FBW * 64)) || (rt->m_TEX0.TBW != m_cached_ctx.FRAME.FBW))) { - half_right_vert = false; - half_right_uv = false; + half_bottom_vert = false; + half_bottom_uv = false; } else { - half_bottom_vert = false; - half_bottom_uv = false; + half_right_vert = false; + half_right_uv = false; } } } @@ -480,7 +483,7 @@ void GSRendererHW::ConvertSpriteTextureShuffle(bool& write_ba, bool& read_ba, GS else v[i + 1 - reversed_U].U += 128u; - if (!half_bottom_vert) + if (half_bottom_vert) { // Height is too big (2x). const int tex_offset = v[i].V & 0xF; @@ -492,12 +495,30 @@ void GSRendererHW::ConvertSpriteTextureShuffle(bool& write_ba, bool& read_ba, GS v[i].XYZ.Y = static_cast(tmp.x); v[i + 1].XYZ.Y = static_cast(tmp.z); - if (!half_bottom_uv) + if (half_bottom_uv) { v[i].V = static_cast(tmp.y); v[i + 1].V = static_cast(tmp.w); } } + else if (half_right_vert) + { + // Width is too big (2x). + const int tex_offset = v[i].U & 0xF; + const GSVector4i offset(o.OFX, tex_offset, o.OFX, tex_offset); + + GSVector4i tmp(v[i].XYZ.X, v[i].U, v[i + 1].XYZ.X, v[i + 1].U); + tmp = GSVector4i(tmp - offset).srl32<1>() + offset; + + v[i].XYZ.X = static_cast(tmp.x); + v[i + 1].XYZ.X = static_cast(tmp.z); + + if (half_right_uv) + { + v[i].U = static_cast(tmp.y); + v[i + 1].U = static_cast(tmp.w); + } + } } } else @@ -519,7 +540,7 @@ void GSRendererHW::ConvertSpriteTextureShuffle(bool& write_ba, bool& read_ba, GS else v[i + 1 - reversed_S].ST.S += offset_8pix; - if (!half_bottom_vert) + if (half_bottom_vert) { // Height is too big (2x). const GSVector4i offset(o.OFY, o.OFY); @@ -531,12 +552,30 @@ void GSRendererHW::ConvertSpriteTextureShuffle(bool& write_ba, bool& read_ba, GS v[i].XYZ.Y = static_cast(tmp.x); v[i + 1].XYZ.Y = static_cast(tmp.y); - if (!half_bottom_uv) + if (half_bottom_uv) { v[i].ST.T /= 2.0f; v[i + 1].ST.T /= 2.0f; } } + else if (half_right_vert) + { + // Width is too big (2x). + const GSVector4i offset(o.OFX, o.OFX); + + GSVector4i tmp(v[i].XYZ.X, v[i + 1].XYZ.X); + tmp = GSVector4i(tmp - offset).srl32<1>() + offset; + + //fprintf(stderr, "Before %d, After %d\n", v[i + 1].XYZ.Y, tmp.y); + v[i].XYZ.X = static_cast(tmp.x); + v[i + 1].XYZ.X = static_cast(tmp.y); + + if (half_right_uv) + { + v[i].ST.S /= 2.0f; + v[i + 1].ST.S /= 2.0f; + } + } } } @@ -554,7 +593,7 @@ void GSRendererHW::ConvertSpriteTextureShuffle(bool& write_ba, bool& read_ba, GS m_vt.m_max.t.x += 8.0f; } - if (!half_right_vert) + if (half_right_vert) { m_vt.m_min.p.x /= 2.0f; m_vt.m_max.p.x /= 2.0f; @@ -562,7 +601,7 @@ void GSRendererHW::ConvertSpriteTextureShuffle(bool& write_ba, bool& read_ba, GS m_context->scissor.in.z = m_vt.m_max.p.x + 8.0f; } - if (!half_bottom_vert) + if (half_bottom_vert) { m_vt.m_min.p.y /= 2.0f; m_vt.m_max.p.y /= 2.0f; @@ -571,16 +610,16 @@ void GSRendererHW::ConvertSpriteTextureShuffle(bool& write_ba, bool& read_ba, GS } // Only do this is the source is being interpreted as 16bit - if (!half_bottom_uv) + if (half_bottom_uv) { m_vt.m_min.t.y /= 2.0f; m_vt.m_max.t.y /= 2.0f; } - if (!half_right_uv) + if (half_right_uv) { - m_vt.m_min.t.y /= 2.0f; - m_vt.m_max.t.y /= 2.0f; + m_vt.m_min.t.x /= 2.0f; + m_vt.m_max.t.x /= 2.0f; } }