Skip to content

Commit

Permalink
GS-HW: Limit BP overlap check to stop FMV flicker.
Browse files Browse the repository at this point in the history
Games changing the double buffer addresses get screwed up, make sure we don't misdetect
  • Loading branch information
refractionpcsx2 committed Aug 26, 2022
1 parent 4ef879d commit 878e06c
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 15 deletions.
2 changes: 1 addition & 1 deletion pcsx2/GS/Renderers/HW/GSRendererHW.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
28 changes: 17 additions & 11 deletions pcsx2/GS/Renderers/HW/GSTextureCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<GSRendererHW*>(g_gs_renderer.get())->GetTextureScaleFactor();
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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
Expand All @@ -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<int>(static_cast<float>(needed_height) * old_texture->GetScale().y);
const int scaled_needed_height = std::max(static_cast<int>(static_cast<float>(needed_height) * old_texture->GetScale().y), old_texture->GetHeight());
const int needed_width = std::min(real_w, static_cast<int>(dispfb.TBW * 64));
const int scaled_needed_width = static_cast<int>(static_cast<float>(needed_width) * old_texture->GetScale().x);
const int scaled_needed_width = std::max(static_cast<int>(static_cast<float>(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)
Expand Down
6 changes: 3 additions & 3 deletions pcsx2/GS/Renderers/HW/GSTextureCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ class GSTextureCache

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

Expand All @@ -335,8 +335,8 @@ class GSTextureCache
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;
Expand Down

0 comments on commit 878e06c

Please sign in to comment.