diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 0889ed365b..dc231c2324 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -165,11 +165,12 @@ GSTexture* GSRendererHW::GetOutput(int i, float& scale, int& y_offset) if (GSTextureCache::Target* rt = g_texture_cache->LookupDisplayTarget(TEX0, framebufferSize, GetTextureScaleFactor(), false)) { + const u32 bp_adj = (TEX0.TBP0 < rt->m_TEX0.TBP0 && rt->UnwrappedEndBlock() > GS_MAX_BLOCKS) ? (TEX0.TBP0 + GS_MAX_BLOCKS) : TEX0.TBP0; rt->Update(); t = rt->m_texture; scale = rt->m_scale; - const int delta = TEX0.TBP0 - rt->m_TEX0.TBP0; + const int delta = bp_adj - rt->m_TEX0.TBP0; if (delta > 0 && curFramebuffer.FBW != 0) { const int pages = delta >> 5u; diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index e81885f786..66d30d3ecc 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -1769,8 +1769,10 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const (GSLocalMemory::m_psm[color_psm].bpp >= 16 || (/*possible_shuffle &&*/ GSLocalMemory::m_psm[color_psm].bpp == 8 && GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp >= 16)) && // Channel shuffles or non indexed lookups. t->m_age <= 1 && (!found_t || t->m_last_draw > dst->m_last_draw) /*&& CanTranslate(bp, bw, psm, block_boundary_rect, t->m_TEX0.TBP0, t->m_TEX0.PSM, t->m_TEX0.TBW)*/) { + const u32 end_block = GSLocalMemory::GetEndBlockAddress(bp, TEX0.TBW, TEX0.PSM, r); + const u32 adj_bp = (end_block < t->m_TEX0.TBP0 && t->UnwrappedEndBlock() > GS_MAX_BLOCKS) ? (bp + GS_MAX_BLOCKS) : bp; u32 rt_tbw = std::max(1U, t->m_TEX0.TBW); - u32 horz_page_offset = ((bp - t->m_TEX0.TBP0) >> 5) % rt_tbw; + u32 horz_page_offset = ((adj_bp - t->m_TEX0.TBP0) >> 5) % rt_tbw; if (GSLocalMemory::m_psm[psm].bpp == GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp && bw != rt_tbw && block_boundary_rect.height() > GSLocalMemory::m_psm[psm].pgs.y) continue; @@ -1783,7 +1785,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const ((t->m_TEX0.TBW < (horz_page_offset + ((block_boundary_rect.z + GSLocalMemory::m_psm[psm].pgs.x - 1) / GSLocalMemory::m_psm[psm].pgs.x)) || (t->m_TEX0.TBW != bw && block_boundary_rect.w > GSLocalMemory::m_psm[psm].pgs.y)))) { - DbgCon.Warning("BP %x - 16bit bad match for target bp %x bw %d src %d format %d", bp, t->m_TEX0.TBP0, t->m_TEX0.TBW, bw, t->m_TEX0.PSM); + DbgCon.Warning("BP %x - 16bit bad match for target bp %x bw %d src %d format %d", adj_bp, t->m_TEX0.TBP0, t->m_TEX0.TBW, bw, t->m_TEX0.PSM); continue; } // Keep note that 2 bw is basically 1 normal page, as bw is in 64 pixels, and 8bit pages are 128 pixels wide, aka 2 bw. @@ -1795,7 +1797,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const ((GSLocalMemory::m_psm[psm].bpp == 32) ? bw : ((bw + 1) / 2)) <= t->m_TEX0.TBW) && !(((GSLocalMemory::m_psm[psm].bpp == 32) ? bw : ((bw + 1) / 2)) == rt_tbw))))) { - DbgCon.Warning("BP %x - 8bit bad match for target bp %x bw %d src %d format %d", bp, t->m_TEX0.TBP0, t->m_TEX0.TBW, bw, t->m_TEX0.PSM); + DbgCon.Warning("BP %x - 8bit bad match for target bp %x bw %d src %d format %d", adj_bp, t->m_TEX0.TBP0, t->m_TEX0.TBW, bw, t->m_TEX0.PSM); continue; } else if (!possible_shuffle && GSLocalMemory::m_psm[psm].bpp <= 8 && TEX0.TBW == 1) @@ -1833,16 +1835,16 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const else // Formats are not compatible for normal draws, only shuffles. continue; } - if (bp > t->m_TEX0.TBP0) + if (adj_bp > t->m_TEX0.TBP0) { - if (!region.HasEither() && GSLocalMemory::m_psm[psm].bpp == 32 && (t->m_TEX0.TBW - (((bp - t->m_TEX0.TBP0) >> 5) % rt_tbw)) < static_cast((block_boundary_rect.width() + 63) / 64)) + if (!region.HasEither() && GSLocalMemory::m_psm[psm].bpp == 32 && (t->m_TEX0.TBW - (((adj_bp - t->m_TEX0.TBP0) >> 5) % rt_tbw)) < static_cast((block_boundary_rect.width() + 63) / 64)) { DbgCon.Warning("Bad alignmenet"); continue; } // Make sure it's inside if not a shuffle, sometimes valid areas can get messy, like TOCA Race Driver 2 where it goes over to 480, but it's rounded up to 512 in the shuffle. - if (!possible_shuffle && !t->Inside(bp, bw, psm, block_boundary_rect)) + if (!possible_shuffle && !t->Inside(adj_bp, bw, psm, block_boundary_rect)) continue; GSVector4i new_rect = (GSLocalMemory::m_psm[color_psm].bpp != GSLocalMemory::m_psm[t->m_TEX0.PSM].bpp && (psm & 0x7) != PSMCT16) ? block_boundary_rect : rect; @@ -1852,7 +1854,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const // Hitman Blood Money is an example of this in the theatre. const u32 rt_tbw = (possible_shuffle || bw == 1 || GSUtil::GetChannelMask(psm) != 0x8 || frame.FBW <= bw || frame.FBW == t->m_TEX0.TBW || bw == t->m_TEX0.TBW) ? t->m_TEX0.TBW : frame.FBW; - const bool can_translate = CanTranslate(bp, bw, src_psm, new_rect, t->m_TEX0.TBP0, t->m_TEX0.PSM, rt_tbw); + const bool can_translate = CanTranslate(adj_bp, bw, src_psm, new_rect, t->m_TEX0.TBP0, t->m_TEX0.PSM, rt_tbw); if (can_translate) { const bool swizzle_match = GSLocalMemory::m_psm[src_psm].depth == GSLocalMemory::m_psm[t->m_TEX0.PSM].depth; @@ -1862,7 +1864,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const if (swizzle_match) { - rect = TranslateAlignedRectByPage(t->m_TEX0.TBP0, t->m_end_block, rt_tbw, t->m_TEX0.PSM, t->m_valid, bp, src_psm, bw, new_rect); + rect = TranslateAlignedRectByPage(t->m_TEX0.TBP0, t->m_end_block, rt_tbw, t->m_TEX0.PSM, t->m_valid, adj_bp, src_psm, bw, new_rect); rect.x -= new_rect.x; rect.y -= new_rect.y; } @@ -1882,7 +1884,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const new_rect.z = (new_rect.z + (page_size.x - 1)) & ~(page_size.x - 1); new_rect.w = (new_rect.w + (page_size.y - 1)) & ~(page_size.y - 1); } - rect = TranslateAlignedRectByPage(t, bp & ~((1 << 5) - 1), src_psm, bw, new_rect); + rect = TranslateAlignedRectByPage(t, adj_bp & ~((1 << 5) - 1), src_psm, bw, new_rect); rect.x -= new_rect.x & ~(page_size.x - 1); rect.y -= new_rect.y & ~(page_size.y - 1); } @@ -1914,7 +1916,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const } else { - SurfaceOffset so = ComputeSurfaceOffset(bp, bw, src_psm, new_rect, t); + SurfaceOffset so = ComputeSurfaceOffset(adj_bp, bw, src_psm, new_rect, t); if (!so.is_valid && t->Wraps()) { // Improves Beyond Good & Evil shadow. @@ -2673,10 +2675,12 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe for (auto i = list.begin(); i != list.end(); ++i) { Target* t = *i; + const u32 end_block = GSLocalMemory::GetEndBlockAddress(bp, TEX0.TBW, TEX0.PSM, GSVector4i(0, size.y, size.x, size.y + 1)); + const u32 bp_adj = (end_block < t->m_TEX0.TBP0 && t->UnwrappedEndBlock() > GS_MAX_BLOCKS) ? (bp + GS_MAX_BLOCKS) : bp; const bool half_buffer_match = GSConfig.UserHacks_TextureInsideRt >= GSTextureInRtMode::InsideTargets && TEX0.TBW == t->m_TEX0.TBW && TEX0.PSM == t->m_TEX0.PSM && bp == GSLocalMemory::GetStartBlockAddress(t->m_TEX0.TBP0, t->m_TEX0.TBW, t->m_TEX0.PSM, GSVector4i(0, size.y, size.x, size.y + 1)); // Make sure the target is inside the texture - if (t->m_TEX0.TBP0 <= bp && bp <= t->m_end_block && (half_buffer_match || t->Inside(bp, TEX0.TBW, TEX0.PSM, GSVector4i::loadh(size)))) + if (t->m_TEX0.TBP0 <= bp_adj && bp_adj <= t->UnwrappedEndBlock() && (half_buffer_match || t->Inside(bp_adj, TEX0.TBW, TEX0.PSM, GSVector4i::loadh(size)))) { if (dst && (GSState::s_n - dst->m_last_draw) < (GSState::s_n - t->m_last_draw)) continue; diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.h b/pcsx2/GS/Renderers/HW/GSTextureCache.h index 429d16bada..c002e6b31e 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.h +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.h @@ -32,8 +32,18 @@ public: constexpr static bool CheckOverlap(const u32 a_bp, const u32 a_bp_end, const u32 b_bp, const u32 b_bp_end) noexcept { - const bool valid = a_bp <= a_bp_end && b_bp <= b_bp_end; - const bool overlap = a_bp <= b_bp_end && a_bp_end >= b_bp; + u32 b_bp_start_synced = b_bp; + u32 b_bp_end_synced = b_bp_end; + + // Check for wrapping + if (a_bp_end > GS_MAX_BLOCKS && b_bp_end < a_bp) + { + b_bp_start_synced += GS_MAX_BLOCKS; + b_bp_end_synced += GS_MAX_BLOCKS; + } + + const bool valid = a_bp <= a_bp_end && b_bp_start_synced <= b_bp_end_synced; + const bool overlap = a_bp <= b_bp_end_synced && a_bp_end >= b_bp_start_synced; return valid && overlap; }