From e08ae7e8fa76d85f94abfaf7766f334dd2d88c41 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 26 Feb 2023 15:22:59 +1000 Subject: [PATCH] GS/HW: Handle end-of-memory wrapping for surface Overlaps() --- pcsx2/GS/GSLocalMemory.h | 6 ++++++ pcsx2/GS/Renderers/HW/GSTextureCache.cpp | 17 +++++++++-------- pcsx2/GS/Renderers/HW/GSTextureCache.h | 14 +++++++------- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/pcsx2/GS/GSLocalMemory.h b/pcsx2/GS/GSLocalMemory.h index f1b3eb8a28..c495f529b5 100644 --- a/pcsx2/GS/GSLocalMemory.h +++ b/pcsx2/GS/GSLocalMemory.h @@ -180,6 +180,12 @@ public: return BNHelper(*this, x, y).value(); } + /// Get the block number of the given pixel, without wrapping to MAX_BLOCKS + u32 bnNoWrap(int x, int y) const + { + return BNHelper(*this, x, y).valueNoWrap(); + } + /// Get a helper class for efficiently calculating multiple block numbers BNHelper bnMulti(int x, int y) const { diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index 86be04ed75..d77cb44112 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -1258,8 +1258,7 @@ void GSTextureCache::InvalidateVideoMem(const GSOffset& off, const GSVector4i& r 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); + const u32 end_bp = off.bnNoWrap(rect.z - 1, rect.w - 1); // Ideally in the future we can turn this on unconditionally, but for now it breaks too much. const bool check_inside_target = (GSConfig.UserHacks_TargetPartialInvalidation || GSConfig.UserHacks_TextureInsideRt); @@ -1275,7 +1274,7 @@ void GSTextureCache::InvalidateVideoMem(const GSOffset& off, const GSVector4i& r 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()) + if ((bp < t->m_TEX0.TBP0 && end_bp < t->m_TEX0.TBP0) || bp > t->UnwrappedEndBlock()) { ++i; continue; @@ -2927,21 +2926,23 @@ void GSTextureCache::Surface::UpdateAge() bool GSTextureCache::Surface::Inside(u32 bp, u32 bw, u32 psm, const GSVector4i& rect) { // Valid only for color formats. - const u32 end_block = GSLocalMemory::m_psm[psm].info.bn(rect.z - 1, rect.w - 1, bp, bw); - return bp >= m_TEX0.TBP0 && end_block <= m_end_block; + const GSOffset off(GSLocalMemory::m_psm[psm].info, bp, bw, psm); + const u32 end_block = off.bnNoWrap(rect.z - 1, rect.w - 1); + return bp >= m_TEX0.TBP0 && end_block <= UnwrappedEndBlock(); } bool GSTextureCache::Surface::Overlaps(u32 bp, u32 bw, u32 psm, const GSVector4i& rect) { // Valid only for color formats. - u32 end_block = GSLocalMemory::m_psm[psm].info.bn(rect.z - 1, rect.w - 1, bp, bw); - u32 start_block = GSLocalMemory::m_psm[psm].info.bn(rect.x, rect.y, bp, bw); + const GSOffset off(GSLocalMemory::m_psm[psm].info, bp, bw, psm); + u32 end_block = off.bnNoWrap(rect.z - 1, rect.w - 1); + u32 start_block = off.bnNoWrap(rect.x, rect.y); // Due to block ordering, end can be below start in a page, so if it's within a page, swap them. if (end_block < start_block && ((start_block - end_block) < (1 << 5))) { std::swap(start_block, end_block); } - const bool overlap = GSTextureCache::CheckOverlap(m_TEX0.TBP0, m_end_block, start_block, end_block); + const bool overlap = GSTextureCache::CheckOverlap(m_TEX0.TBP0, UnwrappedEndBlock(), start_block, end_block); return overlap; } diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.h b/pcsx2/GS/Renderers/HW/GSTextureCache.h index b7d236b54f..f845ea5196 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.h +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.h @@ -132,6 +132,13 @@ public: Surface(); virtual ~Surface(); + /// 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 UpdateAge(); bool Inside(u32 bp, u32 bw, u32 psm, const GSVector4i& rect); bool Overlaps(u32 bp, u32 bw, u32 psm, const GSVector4i& rect); @@ -249,13 +256,6 @@ 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); void UpdateValidBits(u32 bits_written);