From c7e9c9542e2ff33e83a10bf19cf4730700e3e405 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Wed, 22 Feb 2023 23:16:20 +1000 Subject: [PATCH] GS/HW: Don't try to dirty targets which don't overlap The current invalidation code sucks, but at least this stops things which are blatently wrong from happening. --- pcsx2/GS/Renderers/HW/GSRendererHW.cpp | 3 ++- pcsx2/GS/Renderers/HW/GSTextureCache.cpp | 11 +++++++++++ pcsx2/GS/Renderers/HW/GSTextureCache.h | 7 +++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 6aea2955f6..39bc4970c0 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -1330,7 +1330,8 @@ void GSRendererHW::Draw() // We trigger the sw prim render here super early, to avoid creating superfluous render targets. if (CanUseSwPrimRender(no_rt, no_ds, draw_sprite_tex) && SwPrimRender(*this, true)) { - GL_CACHE("Possible texture decompression, drawn with SwPrimRender()"); + GL_CACHE("Possible texture decompression, drawn with SwPrimRender() (BP %x BW %u TBP0 %x TBW %u)", + m_context->FRAME.Block(), m_context->FRAME.FBMSK, m_context->TEX0.TBP0, m_context->TEX0.TBW); return; } diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index 0c14c82b9a..7f31739c70 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -1192,6 +1192,10 @@ void GSTextureCache::InvalidateVideoMem(const GSOffset& off, const GSVector4i& r if (!target) return; + // Handle the case where the transfer wrapped around the end of GS memory. + const u32 end_bp = off.bn(rect.z - 1, rect.w - 1); + const u32 unwrapped_end_bp = end_bp + ((end_bp < bp) ? MAX_BLOCKS : 0); + for (int type = 0; type < 2; type++) { auto& list = m_dst[type]; @@ -1200,6 +1204,13 @@ void GSTextureCache::InvalidateVideoMem(const GSOffset& off, const GSVector4i& r auto j = i; Target* t = *j; + // Don't bother checking any further if the target doesn't overlap with the write/invalidation. + if ((bp < t->m_TEX0.TBP0 && unwrapped_end_bp < t->m_TEX0.TBP0) || bp > t->UnwrappedEndBlock()) + { + ++i; + continue; + } + // GH: (I think) this code is completely broken. Typical issue: // EE write an alpha channel into 32 bits texture // Results: the target is deleted (because HasCompatibleBits is false) diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.h b/pcsx2/GS/Renderers/HW/GSTextureCache.h index 5c3030f741..6c9c7fd37e 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.h +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.h @@ -248,6 +248,13 @@ public: Target(const GIFRegTEX0& TEX0, const bool depth_supported, const int type); ~Target(); + /// Returns true if the target wraps around the end of GS memory. + bool Wraps() const { return (m_end_block < m_TEX0.TBP0); } + + /// Returns the end block for the target, but doesn't wrap at 0x3FFF. + /// Can be used for overlap tests. + u32 UnwrappedEndBlock() const { return (m_end_block + (Wraps() ? MAX_BLOCKS : 0)); } + void ResizeValidity(const GSVector4i& rect); void UpdateValidity(const GSVector4i& rect, bool can_resize = true);