From a2a635a141499f5ba010769ae2ac9b1c6067a46e Mon Sep 17 00:00:00 2001 From: refractionpcsx2 Date: Sun, 20 Nov 2022 01:51:45 +0000 Subject: [PATCH] GS: Favour newer targets unless no match found. No age update on frame. --- pcsx2/GS/Renderers/HW/GSRendererHW.cpp | 8 +++--- pcsx2/GS/Renderers/HW/GSTextureCache.cpp | 34 +++++++++++++++++------- pcsx2/GS/Renderers/HW/GSTextureCache.h | 2 +- 3 files changed, 30 insertions(+), 14 deletions(-) diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index d539f1baac..2231a3187c 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -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); } } diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index 874a39ab8f..91842b097f 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -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(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,9 +2681,10 @@ 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) { - Surface::UpdateAge(); + if(reset_age) + Surface::UpdateAge(); // FIXME: the union of the rects may also update wrong parts of the render target (but a lot faster :) // GH: it must be doable @@ -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; } } diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.h b/pcsx2/GS/Renderers/HW/GSTextureCache.h index 67653d0e41..f8d9eadaac 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.h +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.h @@ -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);