From c88db3221c835f13edfd3fd297c9123b5a9b168a Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Tue, 10 May 2022 00:53:27 +1000 Subject: [PATCH] GS/TextureCache: Flush dirty areas of textures during TC move Dark Cloud does a bunch of VRAM writes overlapping the render target, then moves over the top of it. If we didn't flush these, the target would still be considered dirty, and later we'd trash the move destination, and/or not use it as a source. --- pcsx2/GS/Renderers/HW/GSTextureCache.cpp | 22 ++++++++++++++++++++++ pcsx2/GS/Renderers/HW/GSTextureCache.h | 3 +++ 2 files changed, 25 insertions(+) diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index e7288f2397..750cd4bcba 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -1069,6 +1069,11 @@ bool GSTextureCache::Move(u32 SBP, u32 SBW, u32 SPSM, int sx, int sy, u32 DBP, u if (!src || !dst || src->m_texture->GetScale() != dst->m_texture->GetScale()) return false; + // We don't want to copy "old" data that the game has overwritten with writes, + // so flush any overlapping dirty area. + src->UpdateIfDirtyIntersects(GSVector4i(sx, sy, sx + w, sy + h));; + dst->UpdateIfDirtyIntersects(GSVector4i(dx, dy, dx + w, dy + h)); + // Scale coordinates. const GSVector2 scale(src->m_texture->GetScale()); const int scaled_sx = static_cast(sx * scale.x); @@ -2233,6 +2238,23 @@ void GSTextureCache::Target::Update() UpdateValidity(r); } +void GSTextureCache::Target::UpdateIfDirtyIntersects(const GSVector4i& rc) +{ + for (const auto& dirty : m_dirty) + { + const GSVector4i dirty_rc(dirty.GetDirtyRect(m_TEX0)); + if (dirty_rc.rintersect(rc).rempty()) + continue; + + // strictly speaking, we only need to update the area outside of the move. + // but, to keep things simple, just update the whole thing + GL_CACHE("TC: Update dirty rectangle [%d,%d,%d,%d] due to intersection with [%d,%d,%d,%d]", + dirty_rc.x, dirty_rc.y, dirty_rc.z, dirty_rc.w, rc.x, rc.y, rc.z, rc.w); + Update(); + break; + } +} + void GSTextureCache::Target::UpdateValidity(const GSVector4i& rect) { m_valid = m_valid.runion(rect); diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.h b/pcsx2/GS/Renderers/HW/GSTextureCache.h index 32c4fcc691..16156191d5 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.h +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.h @@ -200,6 +200,9 @@ public: void UpdateValidity(const GSVector4i& rect); void Update(); + + /// Updates the target, if the dirty area intersects with the specified rectangle. + void UpdateIfDirtyIntersects(const GSVector4i& rc); }; class PaletteMap