GS/HW: Handle end-of-memory wrapping for surface Overlaps()

This commit is contained in:
Stenzek 2023-02-26 15:22:59 +10:00 committed by refractionpcsx2
parent 753efd8c4a
commit e08ae7e8fa
3 changed files with 22 additions and 15 deletions

View File

@ -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
{

View File

@ -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;
}

View File

@ -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);