From 7cc6af8f852c4174c0162303c1d9a40802248609 Mon Sep 17 00:00:00 2001 From: refractionpcsx2 Date: Mon, 20 Nov 2023 21:16:20 +0000 Subject: [PATCH] GS/HW: Restrict making new targets if no uploads --- pcsx2/GS/Renderers/HW/GSRendererHW.cpp | 4 +- pcsx2/GS/Renderers/HW/GSTextureCache.cpp | 59 +++++++++++++++++++++++- pcsx2/GS/Renderers/HW/GSTextureCache.h | 2 +- 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 5ea2dc22d6766..cd9037bd56c6f 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -175,7 +175,7 @@ GSTexture* GSRendererHW::GetOutput(int i, float& scale, int& y_offset) TEX0.TBW = curFramebuffer.FBW; TEX0.PSM = curFramebuffer.PSM; - if (GSTextureCache::Target* rt = g_texture_cache->LookupDisplayTarget(TEX0, framebufferSize, GetTextureScaleFactor())) + if (GSTextureCache::Target* rt = g_texture_cache->LookupDisplayTarget(TEX0, framebufferSize, GetTextureScaleFactor(), false)) { rt->Update(); t = rt->m_texture; @@ -214,7 +214,7 @@ GSTexture* GSRendererHW::GetFeedbackOutput(float& scale) TEX0.TBW = m_regs->EXTBUF.EXBW; TEX0.PSM = PCRTCDisplays.PCRTCDisplays[index].PSM; - GSTextureCache::Target* rt = g_texture_cache->LookupDisplayTarget(TEX0, fb_size, GetTextureScaleFactor()); + GSTextureCache::Target* rt = g_texture_cache->LookupDisplayTarget(TEX0, fb_size, GetTextureScaleFactor(), true); if (!rt) return nullptr; diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index 5ddbe358a3efc..3ac50e7fd4f7c 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -2361,13 +2361,68 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons return hw_clear; } -GSTextureCache::Target* GSTextureCache::LookupDisplayTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale) +GSTextureCache::Target* GSTextureCache::LookupDisplayTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, bool is_feedback) { Target* dst = LookupTarget(TEX0, size, scale, RenderTarget, true, 0, true); if (dst) return dst; - return CreateTarget(TEX0, size, size, scale, RenderTarget, true, 0, true); + // Didn't find a target, check if the frame was uploaded. + + bool can_create = is_feedback; + + if (!is_feedback && GSRendererHW::GetInstance()->m_draw_transfers.size() > 0) + { + const GSVector4i newrect = GSVector4i::loadh(size); + const u32 rect_end = GSLocalMemory::GetUnwrappedEndBlockAddress(TEX0.TBP0, TEX0.TBW, TEX0.PSM, newrect); + + std::vector::reverse_iterator iter; + GSVector4i eerect = GSVector4i::zero(); + const int last_draw = GSRendererHW::GetInstance()->m_draw_transfers.back().draw; + + for (iter = GSRendererHW::GetInstance()->m_draw_transfers.rbegin(); iter != GSRendererHW::GetInstance()->m_draw_transfers.rend(); ) + { + // Would be nice to make this 100, but B-Boy seems to rely on data uploaded ~200 draws ago. Making it bigger for now to be safe. + if (last_draw - iter->draw > 500) + break; + + const u32 transfer_end = GSLocalMemory::GetUnwrappedEndBlockAddress(iter->blit.DBP, iter->blit.DBW, iter->blit.DPSM, iter->rect); + + // If the format, and location doesn't overlap + if (transfer_end >= TEX0.TBP0 && iter->blit.DBP <= rect_end && GSUtil::HasCompatibleBits(iter->blit.DPSM, TEX0.PSM)) + { + GSVector4i targetr = iter->rect; + + if (eerect.rempty()) + eerect = targetr; + else + eerect = eerect.runion(targetr); + + if (iter->zero_clear && iter->draw == last_draw) + { + can_create = false; + break; + } + + if (iter->blit.DBP == TEX0.TBP0 && transfer_end == rect_end) + { + iter = std::vector::reverse_iterator(GSRendererHW::GetInstance()->m_draw_transfers.erase(iter.base() - 1)); + } + else + ++iter; + + if (eerect.rintersect(newrect).eq(newrect)) + { + can_create = true; + break; + } + } + else + ++iter; + } + } + + return can_create ? CreateTarget(TEX0, size, size, scale, RenderTarget, true, 0, true) : nullptr; } void GSTextureCache::ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb, int real_w, int real_h) diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.h b/pcsx2/GS/Renderers/HW/GSTextureCache.h index 42b00b4d8e7e3..90899967c04a9 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.h +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.h @@ -483,7 +483,7 @@ class GSTextureCache Target* CreateTarget(GIFRegTEX0 TEX0, const GSVector2i& size, const GSVector2i& valid_size,float scale, int type, bool used = true, u32 fbmask = 0, bool is_frame = false, bool preload = GSConfig.PreloadFrameWithGSData, bool preserve_target = true, const GSVector4i draw_rc = GSVector4i::zero(), GSTextureCache::Source* src = nullptr); - Target* LookupDisplayTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale); + Target* LookupDisplayTarget(GIFRegTEX0 TEX0, const GSVector2i& size, float scale, bool is_feedback); /// Looks up a target in the cache, and only returns it if the BP/BW match exactly. Target* GetExactTarget(u32 BP, u32 BW, int type, u32 end_bp);