From cc18340d5c647560c9a731b5b61f22f314233e1c Mon Sep 17 00:00:00 2001 From: lightningterror <18107717+lightningterror@users.noreply.github.com> Date: Wed, 31 Jul 2024 11:35:41 +0200 Subject: [PATCH] GS/TC: Kill old target if the two are misaligned. --- pcsx2/GS/Renderers/HW/GSTextureCache.cpp | 48 ++++++++++++++++++------ pcsx2/GS/Renderers/HW/GSTextureCache.h | 2 +- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index 15fd02952fa7e..f13b08d14f228 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -2090,7 +2090,7 @@ GSTextureCache::Target* GSTextureCache::LookupTarget(GIFRegTEX0 TEX0, const GSVe std::swap(dst->m_texture, tex); PreloadTarget(TEX0, size, GSVector2i(dst->m_valid.z, dst->m_valid.w), is_frame, preload, - preserve_target, draw_rect, dst); + preserve_target, draw_rect, dst, fbmask); g_gs_device->StretchRect(tex, GSVector4::cxpr(0.0f, 0.0f, 1.0f, 1.0f), dst->m_texture, GSVector4(dst->m_texture->GetRect()), false, false, false, true); g_gs_device->Recycle(tex); @@ -2356,7 +2356,7 @@ GSTextureCache::Target* GSTextureCache::CreateTarget(GIFRegTEX0 TEX0, const GSVe if (!dst) [[unlikely]] return nullptr; - const bool was_clear = PreloadTarget(TEX0, size, valid_size, is_frame, preload, preserve_target, draw_rect, dst, src); + const bool was_clear = PreloadTarget(TEX0, size, valid_size, is_frame, preload, preserve_target, draw_rect, dst, fbmask, src); dst->m_is_frame = is_frame; @@ -2443,7 +2443,7 @@ GSTextureCache::Target* GSTextureCache::CreateTarget(GIFRegTEX0 TEX0, const GSVe } bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, const GSVector2i& valid_size, bool is_frame, - bool preload, bool preserve_target, const GSVector4i draw_rect, Target* dst, GSTextureCache::Source* src) + bool preload, bool preserve_target, const GSVector4i draw_rect, Target* dst, u32 fbmask, GSTextureCache::Source* src) { // In theory new textures contain invalidated data. Still in theory a new target // must contains the content of the GS memory. @@ -2605,6 +2605,28 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons if (dst != t && t->m_TEX0.TBW == dst->m_TEX0.TBW && t->m_TEX0.PSM == dst->m_TEX0.PSM && t->m_TEX0.TBW > 4) if (t->Overlaps(dst->m_TEX0.TBP0, dst->m_TEX0.TBW, dst->m_TEX0.PSM, dst->m_valid)) { + // If the two targets are misaligned, it's likely a relocation, so we can just kill the old target. + const bool full_coverage = (g_gs_renderer->m_primitive_covers_without_gaps == g_gs_renderer->NoGapsType::FullCover); + if (full_coverage && ((((t->m_TEX0.TBP0 - dst->m_TEX0.TBP0) >> 5) % dst->m_TEX0.TBW) != 0)) + { + const u32 temp_mask = fbmask &= GSLocalMemory::m_psm[dst->m_TEX0.PSM].fmsk; + if (temp_mask) + { + t->m_valid_rgb &= !!(temp_mask & 0x00FFFFFF); + t->m_valid_alpha_low &= !!(temp_mask & 0x0F000000); + t->m_valid_alpha_high &= !!(temp_mask & 0xF0000000); + i++; + } + else + { + InvalidateSourcesFromTarget(t); + i = list.erase(j); + delete t; + } + + continue; + } + // could be overwriting a double buffer, so if it's the second half of it, just reduce the size down to half. if (((((t->UnwrappedEndBlock() + 1) - t->m_TEX0.TBP0) >> 1) + t->m_TEX0.TBP0) == dst->m_TEX0.TBP0) { @@ -2628,20 +2650,22 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons continue; } - const int dst_offset = ((((t->m_TEX0.TBP0 - dst->m_TEX0.TBP0) >> 5) / dst->m_TEX0.TBW) * GSLocalMemory::m_psm[t->m_TEX0.PSM].pgs.y); - const int dst_offset_scaled = dst_offset * dst->m_scale; - const GSVector4i dst_rect = GSVector4i(t->m_valid.x, dst_offset, t->m_valid.z, dst_offset + overlapping_pages_height); - if (((!hw_clear && (preserve_target || preload)) || dst_rect.rintersect(draw_rect).rempty()) && dst->GetScale() == t->GetScale()) + const int dst_offset_width = (((t->m_TEX0.TBP0 - dst->m_TEX0.TBP0) >> 5) % dst->m_TEX0.TBW) * GSLocalMemory::m_psm[t->m_TEX0.PSM].pgs.x; + const int dst_offset_height = ((((t->m_TEX0.TBP0 - dst->m_TEX0.TBP0) >> 5) / dst->m_TEX0.TBW) * GSLocalMemory::m_psm[t->m_TEX0.PSM].pgs.y); + const int dst_offset_scaled_width = dst_offset_width * dst->m_scale; + const int dst_offset_scaled_height = dst_offset_height * dst->m_scale; + const GSVector4i dst_rect_scale = GSVector4i(t->m_valid.x, dst_offset_height, t->m_valid.z, dst_offset_height + overlapping_pages_height); + if (((!hw_clear && (preserve_target || preload)) || dst_rect_scale.rintersect(draw_rect).rempty()) && dst->GetScale() == t->GetScale()) { - const int copy_width = (t->m_texture->GetWidth()) > (dst->m_texture->GetWidth()) ? (dst->m_texture->GetWidth()) : t->m_texture->GetWidth(); + const int copy_width = ((t->m_texture->GetWidth()) > (dst->m_texture->GetWidth()) ? (dst->m_texture->GetWidth()) : t->m_texture->GetWidth()) - dst_offset_scaled_width; const int copy_height = overlapping_pages_height * t->m_scale; - GL_INS("RT double buffer copy from FBP 0x%x, %dx%d => %d,%d", t->m_TEX0.TBP0, copy_width, copy_height, 0, dst_offset_scaled); + GL_INS("RT double buffer copy from FBP 0x%x, %dx%d => %d,%d", t->m_TEX0.TBP0, copy_width, copy_height, 0, dst_offset_scaled_height); pxAssert(copy_width <= dst->GetTexture()->GetWidth() && copy_height <= dst->GetTexture()->GetHeight() && copy_width <= t->GetTexture()->GetWidth() && copy_height <= t->GetTexture()->GetHeight()); - pxAssert(dst_offset_scaled > 0); + pxAssert(dst_offset_scaled_height > 0); // Clear the dirty first dst->Update(); @@ -2649,13 +2673,13 @@ bool GSTextureCache::PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, cons if (!t->m_valid_rgb || !(t->m_valid_alpha_high || t->m_valid_alpha_low) || t->m_scale != dst->m_scale) { const GSVector4 src_rect = GSVector4(0, 0, copy_width, copy_height) / (GSVector4(t->m_texture->GetSize()).xyxy()); - const GSVector4 dst_rect = GSVector4(0, dst_offset, copy_width, dst_offset + copy_height); + const GSVector4 dst_rect = GSVector4(dst_offset_scaled_width, dst_offset_scaled_height, dst_offset_scaled_width + copy_width, dst_offset_scaled_width + copy_height); g_gs_device->StretchRect(t->m_texture, src_rect, dst->m_texture, dst_rect, t->m_valid_rgb, t->m_valid_rgb, t->m_valid_rgb, t->m_valid_alpha_high || t->m_valid_alpha_low); } else { // Invalidate has been moved to after DrawPrims(), because we might kill the current sources' backing. - g_gs_device->CopyRect(t->m_texture, dst->m_texture, GSVector4i(0, 0, copy_width, copy_height), 0, dst_offset_scaled); + g_gs_device->CopyRect(t->m_texture, dst->m_texture, GSVector4i(0, 0, copy_width, copy_height), dst_offset_scaled_width, dst_offset_scaled_height); } } diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.h b/pcsx2/GS/Renderers/HW/GSTextureCache.h index c2551f4b399d2..8f8eee361a85c 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.h +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.h @@ -435,7 +435,7 @@ class GSTextureCache Source* CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, Target* t, bool half_right, int x_offset, int y_offset, const GSVector2i* lod, const GSVector4i* src_range, GSTexture* gpu_clut, SourceRegion region); bool PreloadTarget(GIFRegTEX0 TEX0, const GSVector2i& size, const GSVector2i& valid_size, bool is_frame, - bool preload, bool preserve_target, const GSVector4i draw_rect, Target* dst, GSTextureCache::Source* src = nullptr); + bool preload, bool preserve_target, const GSVector4i draw_rect, Target* dst, u32 fbmask, GSTextureCache::Source* src = nullptr); // Returns scaled texture size. static GSVector2i ScaleRenderTargetSize(const GSVector2i& sz, float scale);