diff --git a/pcsx2/GS/GSState.cpp b/pcsx2/GS/GSState.cpp index bb8bbcc1f9..a16ce93b02 100644 --- a/pcsx2/GS/GSState.cpp +++ b/pcsx2/GS/GSState.cpp @@ -1764,7 +1764,7 @@ void GSState::FlushWrite() r.top = m_env.TRXPOS.DSAY; r.right = r.left + m_env.TRXREG.RRW; r.bottom = r.top + m_env.TRXREG.RRH; - + ExpandTarget(m_env.BITBLTBUF, r); InvalidateVideoMem(m_env.BITBLTBUF, r); const GSLocalMemory::writeImage wi = GSLocalMemory::m_psm[m_env.BITBLTBUF.DPSM].wi; @@ -2026,7 +2026,7 @@ void GSState::Write(const u8* mem, int len) r.top = m_env.TRXPOS.DSAY; r.right = r.left + m_env.TRXREG.RRW; r.bottom = r.top + m_env.TRXREG.RRH; - + ExpandTarget(m_env.BITBLTBUF, r); InvalidateVideoMem(blit, r); (m_mem.*psm.wi)(m_tr.x, m_tr.y, mem, m_tr.total, blit, m_env.TRXPOS, m_env.TRXREG); diff --git a/pcsx2/GS/GSState.h b/pcsx2/GS/GSState.h index a01194dcff..9987519cc7 100644 --- a/pcsx2/GS/GSState.h +++ b/pcsx2/GS/GSState.h @@ -373,6 +373,7 @@ public: virtual void PurgePool() = 0; virtual void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r) {} virtual void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r, bool clut = false) {} + virtual void ExpandTarget(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r) {} virtual void Move(); diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 6a7d0a0073..8e55ea4200 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -853,6 +853,11 @@ GSVector2i GSRendererHW::GetTargetSize(GSVector2i* unscaled_size) static_cast(static_cast(height) * GSConfig.UpscaleMultiplier)); } +void GSRendererHW::ExpandTarget(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r) +{ + m_tc->ExpandTarget(BITBLTBUF, r); +} + void GSRendererHW::InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r) { // printf("[%d] InvalidateVideoMem %d,%d - %d,%d %05x (%d)\n", (int)m_perfmon.GetFrame(), r.left, r.top, r.right, r.bottom, (int)BITBLTBUF.DBP, (int)BITBLTBUF.DPSM); diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.h b/pcsx2/GS/Renderers/HW/GSRendererHW.h index 14122e3c01..4d7ce6dade 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.h +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.h @@ -198,6 +198,7 @@ public: GSTexture* GetOutput(int i, int& y_offset) override; GSTexture* GetFeedbackOutput() override; + void ExpandTarget(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r); void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r) override; void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r, bool clut = false) override; void Move() override; diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index 3cfc76052c..874a39ab8f 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -700,6 +700,43 @@ void GSTextureCache::ScaleTargetForDisplay(Target* t, const GIFRegTEX0& dispfb, GetTargetHeight(t->m_TEX0.TBP0, t->m_TEX0.TBW, t->m_TEX0.PSM, static_cast(needed_height)); } +// Expands targets where the write from the EE overlaps the edge of a render target and uses the same base pointer. +void GSTextureCache::ExpandTarget(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r) +{ + GIFRegTEX0 TEX0; + TEX0.TBP0 = BITBLTBUF.DBP; + TEX0.TBW = BITBLTBUF.DBW; + TEX0.PSM = BITBLTBUF.DPSM; + Target* dst = nullptr; + auto& list = m_dst[RenderTarget]; + + for (auto i = list.begin(); i != list.end(); ++i) + { + Target* t = *i; + + if (TEX0.TBP0 == t->m_TEX0.TBP0 && t->Overlaps(TEX0.TBP0, TEX0.TBW, TEX0.PSM, r)) + { + list.MoveFront(i.Index()); + + dst = t; + break; + } + } + + if (dst) + { + const GSVector2i rect_scaled = GSVector2i(r.z * g_gs_renderer->GetUpscaleMultiplier(), r.w * g_gs_renderer->GetUpscaleMultiplier()); + const int upsc_width = std::max(rect_scaled.x, dst->m_texture->GetWidth()); + const int upsc_height = std::max(rect_scaled.y, dst->m_texture->GetHeight()); + if (dst->m_texture->GetWidth() < upsc_width || dst->m_texture->GetHeight() < upsc_height) + { + 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(); + } + } +} // Goal: Depth And Target at the same address is not possible. On GS it is // the same memory but not on the Dx/GL. Therefore a write to the Depth/Target // must invalidate the Target/Depth respectively @@ -2283,7 +2320,8 @@ bool GSTextureCache::Surface::Overlaps(u32 bp, u32 bw, u32 psm, const GSVector4i { // Valid only for color formats. const u32 end_block = GSLocalMemory::m_psm[psm].info.bn(rect.z - 1, rect.w - 1, bp, bw); - const bool overlap = GSTextureCache::CheckOverlap(m_TEX0.TBP0, m_end_block, bp, end_block); + const u32 start_block = GSLocalMemory::m_psm[psm].info.bn(rect.x, rect.y, bp, bw); + const bool overlap = GSTextureCache::CheckOverlap(m_TEX0.TBP0, m_end_block, start_block, end_block); return overlap; } diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.h b/pcsx2/GS/Renderers/HW/GSTextureCache.h index 8345495f2a..67653d0e41 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.h +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.h @@ -345,6 +345,7 @@ public: u32 GetTargetHeight(u32 fbp, u32 fbw, u32 psm, u32 min_height); + void ExpandTarget(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r); void InvalidateVideoMemType(int type, u32 bp); void InvalidateVideoMemSubTarget(GSTextureCache::Target* rt); void InvalidateVideoMem(const GSOffset& off, const GSVector4i& r, bool target = true); diff --git a/pcsx2/GS/Renderers/SW/GSRendererSW.cpp b/pcsx2/GS/Renderers/SW/GSRendererSW.cpp index 4aaa583887..89af3cbb26 100644 --- a/pcsx2/GS/Renderers/SW/GSRendererSW.cpp +++ b/pcsx2/GS/Renderers/SW/GSRendererSW.cpp @@ -616,6 +616,8 @@ void GSRendererSW::Sync(int reason) g_perfmon.Put(GSPerfMon::Fillrate, pixels); } +void GSRendererSW::ExpandTarget(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r) {} + void GSRendererSW::InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r) { if (LOG) diff --git a/pcsx2/GS/Renderers/SW/GSRendererSW.h b/pcsx2/GS/Renderers/SW/GSRendererSW.h index 85c63b99c3..32c2c05bfa 100644 --- a/pcsx2/GS/Renderers/SW/GSRendererSW.h +++ b/pcsx2/GS/Renderers/SW/GSRendererSW.h @@ -75,6 +75,7 @@ protected: void Draw() override; void Queue(GSRingHeap::SharedPtr& item); void Sync(int reason); + void ExpandTarget(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r); void InvalidateVideoMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r) override; void InvalidateLocalMem(const GIFRegBITBLTBUF& BITBLTBUF, const GSVector4i& r, bool clut = false) override;