GS: Favour newer targets unless no match found. No age update on frame.

This commit is contained in:
refractionpcsx2 2022-11-20 01:51:45 +00:00
parent 05dd0831c1
commit a2a635a141
3 changed files with 30 additions and 14 deletions

View File

@ -1691,7 +1691,6 @@ void GSRendererHW::Draw()
// The rectangle of the draw
m_r = GSVector4i(m_vt.m_min.p.xyxy(m_vt.m_max.p)).rintersect(GSVector4i(context->scissor.in));
if (!GSConfig.UserHacks_DisableSafeFeatures)
{
// Constant Direct Write without texture/test/blending (aka a GS mem clear)
@ -1701,13 +1700,13 @@ void GSRendererHW::Draw()
&& !m_context->TEST.ATE // no alpha test
&& (!m_context->TEST.ZTE || m_context->TEST.ZTST == ZTST_ALWAYS) // no depth test
&& (m_vt.m_eq.rgba == 0xFFFF) // constant color write
&& m_r.x == 0 && m_r.y == 0) { // Likely full buffer write
&& m_r.x == 0 && m_r.y == 0) // Likely full buffer write
{
if (OI_GsMemClear() && m_r.w > 1024)
{
if ((fm & fm_mask) != fm_mask)
{
m_tc->InvalidateVideoMem(context->offset.fb, m_r, true);
m_tc->InvalidateVideoMemType(GSTextureCache::RenderTarget, context->FRAME.Block());
@ -1840,7 +1839,8 @@ void GSRendererHW::Draw()
&& !m_context->TEST.ATE // no alpha test
&& (!m_context->TEST.ZTE || m_context->TEST.ZTST == ZTST_ALWAYS) // no depth test
&& (m_vt.m_eq.rgba == 0xFFFF) // constant color write
&& m_r.x == 0 && m_r.y == 0) { // Likely full buffer write
&& m_r.x == 0 && m_r.y == 0) // Likely full buffer write
{
OI_DoubleHalfClear(rt, ds);
}
}

View File

@ -446,6 +446,8 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, con
Target* dst = nullptr;
auto& list = m_dst[type];
Target* old_found = nullptr;
if (!is_frame)
{
for (auto i = list.begin(); i != list.end(); ++i)
@ -477,8 +479,11 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, con
// If the frame is older than 30 frames (0.5 seconds) then it hasn't been updated for ages, so it's probably not a valid output frame.
// The rest of the checks will get better equality, so suffer less from misdetection.
// Kind of arbitrary but it's low enough to not break Grandia Xtreme and high enough not to break Mission Impossible Operation Surma.
if (t->m_age > 30)
if (t->m_age > 30 && !old_found)
{
old_found = t;
continue;
}
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));
@ -497,6 +502,11 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, con
// Make sure the target is inside the texture
if (t->m_TEX0.TBP0 <= bp && bp <= t->m_end_block && t->Inside(bp, TEX0.TBW, TEX0.PSM, GSVector4i(0, 0, real_w, real_h)))
{
if (old_found && t->m_age > 4)
{
continue;
}
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));
@ -508,6 +518,11 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, con
}
}
if (!dst && old_found)
{
dst = old_found;
}
// 3rd try ! Try to find a frame that doesn't contain valid data (honestly I'm not sure we need to do it)
if (!dst)
{
@ -530,7 +545,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, con
{
GL_CACHE("TC: Lookup %s(%s) %dx%d, hit: %d (0x%x, %s)", is_frame ? "Frame" : "Target", to_string(type), size.x, size.y, dst->m_texture->GetID(), bp, psm_str(TEX0.PSM));
dst->Update();
dst->Update(!is_frame || old_found == dst);
const GSVector2& old_s = dst->m_texture->GetScale();
if (new_s != old_s)
@ -573,7 +588,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, con
if (dst_match)
{
dst_match->Update();
dst_match->Update(true);
calcRescale(dst_match->m_texture);
dst = CreateTarget(TEX0, new_size.x, new_size.y, type, clear);
dst->m_32_bits_fmt = dst_match->m_32_bits_fmt;
@ -624,7 +639,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(const GIFRegTEX0& TEX0, con
max_h = std::min<int>(max_h, TEX0.TBW * 64);
dst->m_dirty.push_back(GSDirtyRect(GSVector4i(0, 0, TEX0.TBW * 64, is_frame ? real_h : max_h), TEX0.PSM, TEX0.TBW));
dst->Update();
dst->Update(true);
}
}
if (used)
@ -733,7 +748,7 @@ void GSTextureCache::ExpandTarget(const GIFRegBITBLTBUF& BITBLTBUF, const GSVect
dst->ResizeTexture(upsc_width, upsc_height);
dst->m_dirty.push_back(GSDirtyRect(r, TEX0.PSM, TEX0.TBW));
GetTargetHeight(TEX0.TBP0, TEX0.TBW, TEX0.PSM, r.w);
dst->Update();
dst->Update(true);
}
}
}
@ -1753,7 +1768,7 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
src->m_valid_rect = dst->m_valid;
src->m_end_block = dst->m_end_block;
dst->Update();
dst->Update(true);
// do not round here!!! if edge becomes a black pixel and addressing mode is clamp => everything outside the clamped area turns into black (kh2 shadows)
@ -2666,8 +2681,9 @@ GSTextureCache::Target::Target(const GIFRegTEX0& TEX0, const bool depth_supporte
m_dirty_alpha = GSLocalMemory::m_psm[TEX0.PSM].trbpp != 24;
}
void GSTextureCache::Target::Update()
void GSTextureCache::Target::Update(bool reset_age)
{
if(reset_age)
Surface::UpdateAge();
// FIXME: the union of the rects may also update wrong parts of the render target (but a lot faster :)
@ -2770,7 +2786,7 @@ void GSTextureCache::Target::UpdateIfDirtyIntersects(const GSVector4i& rc)
// but, to keep things simple, just update the whole thing
GL_CACHE("TC: Update dirty rectangle [%d,%d,%d,%d] due to intersection with [%d,%d,%d,%d]",
dirty_rc.x, dirty_rc.y, dirty_rc.z, dirty_rc.w, rc.x, rc.y, rc.z, rc.w);
Update();
Update(true);
break;
}
}

View File

@ -203,7 +203,7 @@ public:
void UpdateValidity(const GSVector4i& rect);
void Update();
void Update(bool reset_age);
/// Updates the target, if the dirty area intersects with the specified rectangle.
void UpdateIfDirtyIntersects(const GSVector4i& rc);