From 878e06cd36fb1f0eec19fb3fda90bf603c6e771f Mon Sep 17 00:00:00 2001 From: refractionpcsx2 Date: Mon, 22 Aug 2022 23:08:23 +0100 Subject: [PATCH] GS-HW: Limit BP overlap check to stop FMV flicker. Games changing the double buffer addresses get screwed up, make sure we don't misdetect --- pcsx2/GS/Renderers/HW/GSRendererHW.cpp | 2 +- pcsx2/GS/Renderers/HW/GSTextureCache.cpp | 28 ++++++++++++++---------- pcsx2/GS/Renderers/HW/GSTextureCache.h | 6 ++--- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 5be9c065b1..f3a22f1ee0 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -254,7 +254,7 @@ GSTexture* GSRendererHW::GetOutput(int i, int& y_offset) GSTexture* t = nullptr; GSVector2i size = GetOutputSize(fb_height); - if (GSTextureCache::Target* rt = m_tc->LookupDisplayTarget(TEX0, GetOutputSize(fb_height), fb_height, fb_width)) + if (GSTextureCache::Target* rt = m_tc->LookupDisplayTarget(TEX0, GetOutputSize(fb_height), fb_width, fb_height)) { t = rt->m_texture; diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index 27bb94519a..93f55ea6e3 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -414,7 +414,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con return src; } -GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, int type, bool used, u32 fbmask, const bool is_frame, const int real_h, const int real_w) +GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, int type, bool used, u32 fbmask, const bool is_frame, const int real_w, const int real_h) { const GSLocalMemory::psm_t& psm_s = GSLocalMemory::m_psm[TEX0.PSM]; const GSVector2& new_s = static_cast(g_gs_renderer.get())->GetTextureScaleFactor(); @@ -470,7 +470,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, con dst = t; GL_CACHE("TC: Lookup Frame %dx%d, perfect hit: %d (0x%x -> 0x%x %s)", size.x, size.y, dst->m_texture->GetID(), bp, t->m_end_block, psm_str(TEX0.PSM)); if (real_h > 0 || real_w > 0) - ScaleTargetForDisplay(dst, TEX0, real_h, real_w); + ScaleTargetForDisplay(dst, TEX0, real_w, real_h); break; } @@ -479,14 +479,21 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, con // 2nd try ! Try to find a frame that include the bp if (!dst) { + const int page_width = std::max(1, (real_w / psm_s.pgs.x)); + const int page_height = std::max(1, (real_h / psm_s.pgs.y)); + const int pitch = (std::max(1U, TEX0.TBW) * 64) / psm_s.pgs.x; + const u32 end_bp = bp + ((page_width << 5) + ((page_height * pitch) << 5)); + for (auto t : list) { - if (t->m_TEX0.TBP0 < bp && bp <= t->m_end_block) + // Make sure the target is inside the texture + if (t->m_TEX0.TBP0 < bp && bp <= t->m_end_block && end_bp > t->m_TEX0.TBP0 && end_bp <= t->m_end_block) { dst = t; - GL_CACHE("TC: Lookup Frame %dx%d, inclusive hit: %d (0x%x, took 0x%x -> 0x%x %s)", size.x, size.y, t->m_texture->GetID(), bp, t->m_TEX0.TBP0, t->m_end_block, psm_str(TEX0.PSM)); + GL_CACHE("TC: Lookup Frame %dx%d, inclusive hit: %d (0x%x, took 0x%x -> 0x%x %s endbp 0x%x)", size.x, size.y, t->m_texture->GetID(), bp, t->m_TEX0.TBP0, t->m_end_block, psm_str(TEX0.PSM), end_bp); + if (real_h > 0 || real_w > 0) - ScaleTargetForDisplay(dst, TEX0, real_h, real_w); + ScaleTargetForDisplay(dst, TEX0, real_w, real_h); break; } @@ -623,12 +630,12 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, con return dst; } -GSTextureCache::Target* GSTextureCache::LookupDisplayTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, const int real_h, const int real_w) +GSTextureCache::Target* GSTextureCache::LookupDisplayTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, const int real_w, const int real_h) { - return LookupTarget(TEX0, size, RenderTarget, true, 0, true, real_h, real_w); + return LookupTarget(TEX0, size, RenderTarget, true, 0, true, real_w, real_h); } -void GSTextureCache::ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb, int real_h, int real_w) +void GSTextureCache::ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb, int real_w, int real_h) { // This handles a case where you have two images stacked on top of one another (usually FMVs), and // the size of the top framebuffer is larger than the height of the image. Usually happens when @@ -655,12 +662,11 @@ void GSTextureCache::ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb, // Take that into consideration to find the extent of the target which will be sampled. GSTexture* old_texture = t->m_texture; const int needed_height = std::min(real_h + y_offset, GSRendererHW::MAX_FRAMEBUFFER_HEIGHT); - const int scaled_needed_height = static_cast(static_cast(needed_height) * old_texture->GetScale().y); + const int scaled_needed_height = std::max(static_cast(static_cast(needed_height) * old_texture->GetScale().y), old_texture->GetHeight()); const int needed_width = std::min(real_w, static_cast(dispfb.TBW * 64)); - const int scaled_needed_width = static_cast(static_cast(needed_width) * old_texture->GetScale().x); + const int scaled_needed_width = std::max(static_cast(static_cast(needed_width) * old_texture->GetScale().x), old_texture->GetWidth()); if (scaled_needed_height <= old_texture->GetHeight() && scaled_needed_width <= old_texture->GetWidth()) return; - // We're expanding, so create a new texture. GSTexture* new_texture = g_gs_device->CreateRenderTarget(scaled_needed_width, scaled_needed_height, GSTexture::Format::Color, false); if (!new_texture) diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.h b/pcsx2/GS/Renderers/HW/GSTextureCache.h index bf7ddb63e2..70fa3dcc95 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.h +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.h @@ -311,7 +311,7 @@ protected: /// Expands a target when the block pointer for a display framebuffer is within another target, but the read offset /// plus the height is larger than the current size of the target. - void ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb, int real_h, int real_w); + void ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb, int real_w, int real_h); HashCacheEntry* LookupHashCache(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, bool& paltex, const u32* clut, const GSVector2i* lod); @@ -335,8 +335,8 @@ public: Source* LookupSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r, const GSVector2i* lod); Source* LookupDepthSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, const GSVector4i& r, bool palette = false); - Target* LookupTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, int type, bool used, u32 fbmask = 0, const bool is_frame = false, const int real_h = 0, const int real_w = 0); - Target* LookupDisplayTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, const int real_h, const int real_w); + Target* LookupTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, int type, bool used, u32 fbmask = 0, const bool is_frame = false, const int real_w = 0, const int real_h = 0); + Target* LookupDisplayTarget(const GIFRegTEX0& TEX0, const GSVector2i& size, const int real_w, const int real_h); /// Looks up a target in the cache, and only returns it if the BP/BW/PSM match exactly. Target* GetExactTarget(u32 BP, u32 BW, u32 PSM) const;