diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 7443b869cf..8c58c2f60f 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -979,8 +979,11 @@ void GSRendererHW::InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const GS break; } - if(!skip) - g_texture_cache->InvalidateLocalMem(m_mem.GetOffset(BITBLTBUF.SBP, BITBLTBUF.SBW, BITBLTBUF.SPSM), r); + if (!skip) + { + const bool recursive_copy = (BITBLTBUF.SBP == BITBLTBUF.DBP) && (m_env.TRXDIR.XDIR == 2); + g_texture_cache->InvalidateLocalMem(m_mem.GetOffset(BITBLTBUF.SBP, BITBLTBUF.SBW, BITBLTBUF.SPSM), r, recursive_copy); + } } void GSRendererHW::Move() diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index 36f7097221..f708916fa3 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -2252,8 +2252,9 @@ void GSTextureCache::InvalidateVideoMem(const GSOffset& off, const GSVector4i& r } // Goal: retrive the data from the GPU to the GS memory. -// Called each time you want to read from the GS memory -void GSTextureCache::InvalidateLocalMem(const GSOffset& off, const GSVector4i& r) +// Called each time you want to read from the GS memory. +// full_flush is set when it's a Local->Local stransfer and both src and destination are the same. +void GSTextureCache::InvalidateLocalMem(const GSOffset& off, const GSVector4i& r, bool full_flush) { const u32 bp = off.bp(); const u32 psm = off.psm(); @@ -2306,7 +2307,7 @@ void GSTextureCache::InvalidateLocalMem(const GSOffset& off, const GSVector4i& r const bool swizzle_match = GSLocalMemory::m_psm[psm].depth == GSLocalMemory::m_psm[t->m_TEX0.PSM].depth; // Calculate the rect offset if the BP doesn't match. GSVector4i targetr = {}; - if (t->readbacks_since_draw > 1) + if (full_flush || t->readbacks_since_draw > 1) { targetr = t->m_drawn_since_read; } @@ -2440,7 +2441,7 @@ void GSTextureCache::InvalidateLocalMem(const GSOffset& off, const GSVector4i& r const bool swizzle_match = GSLocalMemory::m_psm[psm].depth == GSLocalMemory::m_psm[t->m_TEX0.PSM].depth; // Calculate the rect offset if the BP doesn't match. GSVector4i targetr = {}; - if (t->readbacks_since_draw > 1) + if (full_flush || t->readbacks_since_draw > 1) { targetr = t->m_drawn_since_read; } diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.h b/pcsx2/GS/Renderers/HW/GSTextureCache.h index 76ada32588..2c95a4ead3 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.h +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.h @@ -464,7 +464,7 @@ public: void InvalidateVideoMemType(int type, u32 bp); void InvalidateVideoMemSubTarget(GSTextureCache::Target* rt); void InvalidateVideoMem(const GSOffset& off, const GSVector4i& r, bool eewrite = false, bool target = true); - void InvalidateLocalMem(const GSOffset& off, const GSVector4i& r); + void InvalidateLocalMem(const GSOffset& off, const GSVector4i& r, bool full_flush = false); /// Removes any targets overlapping the specified BP and rectangle. void InvalidateVideoMemTargets(int type, u32 bp, u32 bw, u32 psm, const GSVector4i& r);