From 05a1b0203b90fbebac6c68f4a5a1106ec447bfa9 Mon Sep 17 00:00:00 2001 From: refractionpcsx2 Date: Thu, 14 Sep 2023 17:14:44 +0100 Subject: [PATCH] GS/HW: Tex in RT fixes handling shuffles --- pcsx2/GS/Renderers/HW/GSRendererHW.cpp | 3 ++- pcsx2/GS/Renderers/HW/GSTextureCache.cpp | 29 ++++++++++++------------ 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index 16e8bba812..ca80f39e5d 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -2266,8 +2266,9 @@ void GSRendererHW::Draw() // create that target, because the clear isn't black, it'll hang around and never get invalidated. const bool is_square = (t_size.y == t_size.x) && m_r.w >= 1023 && PrimitiveCoversWithoutGaps(); const bool is_clear = is_possible_mem_clear && is_square; + const bool possible_shuffle = ((src && src->m_target && src->m_from_target->m_32_bits_fmt) && GSLocalMemory::m_psm[m_cached_ctx.TEX0.PSM].bpp == 16 && GSLocalMemory::m_psm[m_cached_ctx.FRAME.PSM].bpp == 16) || IsPossibleChannelShuffle(); rt = g_texture_cache->LookupTarget(FRAME_TEX0, t_size, target_scale, GSTextureCache::RenderTarget, true, - fm, false, force_preload, preserve_rt_rgb, preserve_rt_alpha, unclamped_draw_rect, IsPossibleChannelShuffle(), is_possible_mem_clear && FRAME_TEX0.TBP0 != m_cached_ctx.ZBUF.Block()); + fm, false, force_preload, preserve_rt_rgb, preserve_rt_alpha, unclamped_draw_rect, possible_shuffle, is_possible_mem_clear && FRAME_TEX0.TBP0 != m_cached_ctx.ZBUF.Block()); // Draw skipped because it was a clear and there was no target. if (!rt) diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index 191fe0e418..32cde47357 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -1240,7 +1240,8 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con } } const bool t_clean = ((t->m_dirty.GetDirtyChannels() & GSUtil::GetChannelMask(psm)) == 0) || rect_clean; - + const u32 color_psm = ((psm & 0x30) == 0x30) ? (psm & ~0x30) : psm; + const u32 tex_color_psm = ((t->m_TEX0.PSM & 0x30) == 0x30) ? (t->m_TEX0.PSM & ~0x30) : t->m_TEX0.PSM; // Match if we haven't already got a tex in rt if (t_clean && GSUtil::HasSharedBits(bp, psm, t->m_TEX0.TBP0, t_psm)) { @@ -1302,9 +1303,9 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con } // Make sure the texture actually is INSIDE the RT, it's possibly not valid if it isn't. // Also check BP >= TBP, create source isn't equpped to expand it backwards and all data comes from the target. (GH3) - else if (GSConfig.UserHacks_TextureInsideRt >= GSTextureInRtMode::InsideTargets && psm >= PSMCT32 && - psm <= PSMCT16S && (GSUtil::HasCompatibleBits(t->m_TEX0.PSM, psm) || - (possible_shuffle && t->m_TEX0.PSM <= PSMCT24 && ((((t->UnwrappedEndBlock() + 1) - t->m_TEX0.TBP0) >> 1) + t->m_TEX0.TBP0) == bp)) && + else if (GSConfig.UserHacks_TextureInsideRt >= GSTextureInRtMode::InsideTargets && color_psm >= PSMCT32 && + color_psm <= PSMCT16S && (GSUtil::HasCompatibleBits(tex_color_psm, color_psm) || + (possible_shuffle && tex_color_psm <= PSMCT24 && ((((t->UnwrappedEndBlock() + 1) - t->m_TEX0.TBP0) >> 1) + t->m_TEX0.TBP0) == bp)) && (t->Overlaps(bp, bw, psm, r) || t->Wraps()) && t->m_age <= 1 && (!found_t || dst->m_TEX0.TBW < bw)) { @@ -1315,7 +1316,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con int src_psm = psm; // If the input is C16 and it's actually a shuffle of 32bits we need to correct the size. - if ((t->m_TEX0.PSM & 0xF) == PSMCT32 && (psm & 0x7) == PSMCT16 && possible_shuffle) + if ((tex_color_psm & 0xF) <= PSMCT24 && (psm & 0x7) == PSMCT16 && possible_shuffle) { src_psm = t->m_TEX0.PSM; // If it's taking double width for the shuffle, half that. @@ -1344,7 +1345,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con // Fixes Jak eyes rendering. // Fixes Xenosaga 3 last dungeon graphic bug. // Fixes Pause menu in The Getaway. - const bool can_translate = CanTranslate(bp, bw, psm, new_rect, t->m_TEX0.TBP0, t->m_TEX0.PSM, t->m_TEX0.TBW); + const bool can_translate = CanTranslate(bp, bw, src_psm, new_rect, t->m_TEX0.TBP0, t->m_TEX0.PSM, t->m_TEX0.TBW); if (can_translate) { const bool swizzle_match = GSLocalMemory::m_psm[src_psm].depth == GSLocalMemory::m_psm[t->m_TEX0.PSM].depth; @@ -1354,7 +1355,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con if (swizzle_match) { - rect = TranslateAlignedRectByPage(t, bp, psm, bw, new_rect); + rect = TranslateAlignedRectByPage(t, bp, src_psm, bw, new_rect); rect.x -= new_rect.x; rect.y -= new_rect.y; } @@ -1374,9 +1375,9 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con new_rect.z = (new_rect.z + (page_size.x - 1)) & ~(page_size.x - 1); new_rect.w = (new_rect.w + (page_size.y - 1)) & ~(page_size.y - 1); } - rect = TranslateAlignedRectByPage(t, bp & ~((1 << 5) - 1), psm, bw, new_rect); - rect.x -= new_rect.x & ~(page_size.y - 1); - rect.y -= new_rect.x & ~(page_size.y - 1); + rect = TranslateAlignedRectByPage(t, bp & ~((1 << 5) - 1), src_psm, bw, new_rect); + rect.x -= new_rect.x & ~(page_size.x - 1); + rect.y -= new_rect.y & ~(page_size.y - 1); } rect = rect.rintersect(t->m_valid); @@ -1409,12 +1410,12 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con } else { - SurfaceOffset so = ComputeSurfaceOffset(bp, bw, psm, new_rect, t); + SurfaceOffset so = ComputeSurfaceOffset(bp, bw, src_psm, new_rect, t); if (!so.is_valid && t->Wraps()) { // Improves Beyond Good & Evil shadow. const u32 bp_unwrap = bp + GSTextureCache::MAX_BP + 0x1; - so = ComputeSurfaceOffset(bp_unwrap, bw, psm, new_rect, t); + so = ComputeSurfaceOffset(bp_unwrap, bw, src_psm, new_rect, t); } if (so.is_valid) { @@ -1443,8 +1444,8 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con // I had a check on the end block too, but since the game's a bit rude, it channel shuffles into new // targets that it never regularly draws to, which means the end block for them won't be correct. // Omitting that check here seemed less risky than blowing CS targets out... - const GSVector2i& page_size = GSLocalMemory::m_psm[psm].pgs; - const GSOffset offset(GSLocalMemory::m_psm[psm].info, bp, bw, psm); + const GSVector2i& page_size = GSLocalMemory::m_psm[src_psm].pgs; + const GSOffset offset(GSLocalMemory::m_psm[src_psm].info, bp, bw, psm); if (bp < t->m_TEX0.TBP0 && region.HasX() && region.HasY() && (region.GetMinX() & (page_size.x - 1)) == 0 && (region.GetMinY() & (page_size.y - 1)) == 0 && offset.bn(region.GetMinX(), region.GetMinY()) == t->m_TEX0.TBP0)