From 1677ef3189ce7e6663b8f074cbb517407497d513 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sat, 30 Jul 2022 15:13:33 +1000 Subject: [PATCH] GS/TextureCache: Elide copies when source matches target Assuming everything matches up, instead of copying the target, we can just sample it directly. It's the same as doing the copy first, except we save GPU time. --- pcsx2/GS/Renderers/HW/GSRendererHW.cpp | 3 +- pcsx2/GS/Renderers/HW/GSTextureCache.cpp | 74 ++++++++++++++++-------- 2 files changed, 51 insertions(+), 26 deletions(-) diff --git a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp index c78ff6d160..bcc68ce9b9 100644 --- a/pcsx2/GS/Renderers/HW/GSRendererHW.cpp +++ b/pcsx2/GS/Renderers/HW/GSRendererHW.cpp @@ -142,8 +142,9 @@ bool GSRendererHW::UpdateTexIsFB(GSTextureCache::Target* dst, const GIFRegTEX0& if (!m_tex_is_fb && !m_vt.IsLinear()) { // Make sure that we're not sampling away from the area we're rendering. + // We need to take the absolute here, because Beyond Good and Evil undithers itself using a -1,-1 offset. const GSVector4 diff(m_vt.m_min.p.xyxy(m_vt.m_max.p) - m_vt.m_min.t.xyxy(m_vt.m_max.t)); - if ((diff < GSVector4(1.0f)).alltrue()) + if ((diff.abs() < GSVector4(1.0f)).alltrue()) m_tex_is_fb = true; } } diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index d82e6b44c3..2730a75f57 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -1642,13 +1642,55 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con } } - // Don't be fooled by the name. 'dst' is the old target (hence the input) - // 'src' is the new texture cache entry (hence the output) - GSTexture* sTex = dst->m_texture; - GSTexture* dTex = use_texture ? - g_gs_device->CreateTexture(w, h, false, GSTexture::Format::Color, true) : - g_gs_device->CreateRenderTarget(w, h, GSTexture::Format::Color, false); - src->m_texture = dTex; + // Assuming everything matches up, instead of copying the target, we can just sample it directly. + // It's the same as doing the copy first, except we save GPU time. + if (!half_right && // not the size change from above + use_texture && // not reinterpreting the RT + w == dst->m_texture->GetWidth() && h == dst->m_texture->GetHeight() && // same dimensions + !m_temporary_source // not the shuffle case above + ) + { + // sample the target directly + src->m_texture = dst->m_texture; + src->m_shared_texture = true; + src->m_target = true; // So renderer can check if a conversion is required + src->m_from_target = &dst->m_texture; // avoid complex condition on the renderer + src->m_from_target_TEX0 = dst->m_TEX0; + src->m_32_bits_fmt = dst->m_32_bits_fmt; + src->m_valid_rect = dst->m_valid; + src->m_end_block = dst->m_end_block; + + // kill the source afterwards, since we don't want to have to track changes to the target + m_temporary_source = src; + } + else + { + // Don't be fooled by the name. 'dst' is the old target (hence the input) + // 'src' is the new texture cache entry (hence the output) + GSTexture* sTex = dst->m_texture; + GSTexture* dTex = use_texture ? + g_gs_device->CreateTexture(w, h, false, GSTexture::Format::Color, true) : + g_gs_device->CreateRenderTarget(w, h, GSTexture::Format::Color, false); + src->m_texture = dTex; + + if (use_texture) + { + g_gs_device->CopyRect(sTex, dTex, sRect, destX, destY); + } + else + { + GSVector4 sRectF(sRect); + sRectF.z /= sTex->GetWidth(); + sRectF.w /= sTex->GetHeight(); + + g_gs_device->StretchRect(sTex, sRectF, dTex, GSVector4(destX, destY, w, h), shader, false); + } + + if (src->m_texture) + src->m_texture->SetScale(scale); + else + ASSERT(0); + } // GH: by default (m_paltex == 0) GS converts texture to the 32 bit format // However it is different here. We want to reuse a Render Target as a texture. @@ -1658,24 +1700,6 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con AttachPaletteToSource(src, psm.pal, true); } - if (use_texture) - { - g_gs_device->CopyRect(sTex, dTex, sRect, destX, destY); - } - else - { - GSVector4 sRectF(sRect); - sRectF.z /= sTex->GetWidth(); - sRectF.w /= sTex->GetHeight(); - - g_gs_device->StretchRect(sTex, sRectF, dTex, GSVector4(destX, destY, w, h), shader, false); - } - - if (src->m_texture) - src->m_texture->SetScale(scale); - else - ASSERT(0); - // Offset hack. Can be enabled via GS options. // The offset will be used in Draw(). float modxy = 0.0f;