From 6cd4909e7aef7ad7cce0190bca6d2efeee8de55a Mon Sep 17 00:00:00 2001 From: refractionpcsx2 Date: Tue, 11 Feb 2025 12:27:48 +0000 Subject: [PATCH] GS/HW: Fix Z Tex in RT regions + read back sources for SW if needed --- pcsx2/GS/Renderers/HW/GSRendererHW.cpp | 18 +++++++++++++++--- pcsx2/GS/Renderers/HW/GSTextureCache.cpp | 4 ++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 52a165eec9ee8e..4ba50ba38e9188 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -504,12 +504,12 @@ void GSRendererHW::ConvertSpriteTextureShuffle(u32& process_rg, u32& process_ba, const int width_diff = static_cast(m_env.CTXT[m_env.PRIM.CTXT].TEX0.TBW) - static_cast((m_cached_ctx.FRAME.FBW + 1) >> 1); // We can check the future for a clue as this can be more accurate, be careful of different draws like channel shuffles or single page draws. - if (m_env.CTXT[m_env.PRIM.CTXT].TEX0.TBP0 == m_cached_ctx.FRAME.Block() && GSLocalMemory::m_psm[m_env.CTXT[m_env.PRIM.CTXT].TEX0.PSM].bpp == 32 && width_diff >= 0) + if (m_env.CTXT[m_env.PRIM.CTXT].TEX0.TBP0 == m_cached_ctx.FRAME.Block() && GSLocalMemory::m_psm[m_env.CTXT[m_env.PRIM.CTXT].TEX0.PSM].bpp > 16 && GSLocalMemory::m_psm[m_env.CTXT[m_env.PRIM.CTXT].TEX0.PSM].bpp == 32 && width_diff >= 0) { // width_diff will be zero is both are BW == 1, so be careful of that. const bool same_width = width_diff > 0 || (m_cached_ctx.FRAME.FBW == 1 && width_diff == 0); // Draw is double width and the draw is twice the width of the next draws texture. - if (!same_width && max_tex_draw_width >= (m_cached_ctx.FRAME.FBW * 64)) + if ((!same_width && max_tex_draw_width >= (m_cached_ctx.FRAME.FBW * 64)) || (single_direction_doubled && (m_vt.m_max.p.x >= (rt->m_valid.z * 2)))) { half_bottom_uv = false; half_bottom_vert = false; @@ -7383,6 +7383,7 @@ bool GSRendererHW::CanUseSwPrimRender(bool no_rt, bool no_ds, bool draw_sprite_t if ((req_color && !src_target->m_valid_rgb) || (req_alpha && (!src_target->m_valid_alpha_low || !src_target->m_valid_alpha_high))) return true; + bool req_readback = false; // If the EE has written over our sample area, we're fine to do this on the CPU, despite the target. if (!src_target->m_dirty.empty()) { @@ -7408,11 +7409,22 @@ bool GSRendererHW::CanUseSwPrimRender(bool no_rt, bool no_ds, bool draw_sprite_t } } } + else + { + // If the target isn't dirty we might have valid data, so let's check their areas overlap, if so we need to read it back for SW. + GSVector4i src_rect = GSVector4i(m_vt.m_min.t.x, m_vt.m_min.t.y, m_vt.m_max.t.x, m_vt.m_max.t.x); + GSVector4i area = g_texture_cache->TranslateAlignedRectByPage(src_target, m_cached_ctx.TEX0.TBP0, m_cached_ctx.TEX0.PSM, m_cached_ctx.TEX0.TBW, src_rect, false); + req_readback = !area.rintersect(src_target->m_drawn_since_read).eq(GSVector4i::zero()); + } // Make sure it actually makes sense to use this target as a source, given the formats, and it wouldn't just sample as garbage. // We can't rely exclusively on the dirty rect check above, because sometimes the targets are from older frames and too large. if (!GSUtil::HasSameSwizzleBits(m_cached_ctx.TEX0.PSM, src_target->m_TEX0.PSM) && (!src_target->m_32_bits_fmt || GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp != 16)) - return true; + { + if (req_readback) + g_texture_cache->Read(src_target, src_target->m_drawn_since_read); + return true; + } return false; } diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index 5f72a463eed16e..858d1a6bc2ab93 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -1160,8 +1160,8 @@ GSTextureCache::Source* GSTextureCache::LookupDepthSource(const bool is_depth, c if (inside_target) { // Need to set it up as a region target. - src->m_region.SetX(block_boundary_rect.x, block_boundary_rect.z); - src->m_region.SetY(block_boundary_rect.y, block_boundary_rect.w); + src->m_region.SetX(block_boundary_rect.x, src->m_from_target->m_valid.z); + src->m_region.SetY(block_boundary_rect.y, src->m_from_target->m_valid.w); } if (GSRendererHW::GetInstance()->IsTBPFrameOrZ(dst->m_TEX0.TBP0))