GS: Only copy texture coverage area for current FRAME/Z sources

This commit is contained in:
Connor McLaughlin 2022-04-21 23:49:55 +10:00 committed by refractionpcsx2
parent b344ee094f
commit 8181cc8528
4 changed files with 57 additions and 6 deletions

View File

@ -162,6 +162,13 @@ void GSRendererHW::PurgeTextureCache()
m_tc->RemoveAll(); m_tc->RemoveAll();
} }
bool GSRendererHW::IsPossibleTextureShuffle(GSTextureCache::Source* src) const
{
return (PRIM->TME && m_vt.m_primclass == GS_SPRITE_CLASS &&
src->m_32_bits_fmt && GSLocalMemory::m_psm[src->m_TEX0.PSM].bpp == 16 &&
GSLocalMemory::m_psm[m_context->FRAME.PSM].bpp == 16);
}
void GSRendererHW::SetGameCRC(u32 crc, int options) void GSRendererHW::SetGameCRC(u32 crc, int options)
{ {
GSRenderer::SetGameCRC(crc, options); GSRenderer::SetGameCRC(crc, options);
@ -1711,6 +1718,11 @@ void GSRendererHW::Draw()
// //
// Temporary source *must* be invalidated before normal, because otherwise it'll be double freed.
m_tc->InvalidateTemporarySource();
//
if ((fm & fm_mask) != fm_mask && rt) if ((fm & fm_mask) != fm_mask && rt)
{ {
//rt->m_valid = rt->m_valid.runion(r); //rt->m_valid = rt->m_valid.runion(r);

View File

@ -186,4 +186,7 @@ public:
// Called by the texture cache to know if current texture is useful // Called by the texture cache to know if current texture is useful
virtual bool IsDummyTexture() const { return false; } virtual bool IsDummyTexture() const { return false; }
// Called by the texture cache when optimizing the copy range for sources
bool IsPossibleTextureShuffle(GSTextureCache::Source* src) const;
}; };

View File

@ -391,7 +391,7 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const GIFRegTEX0& TEX0, con
GL_CACHE("TC: src miss (0x%x, 0x%x, %s)", TEX0.TBP0, psm_s.pal > 0 ? TEX0.CBP : 0, psm_str(TEX0.PSM)); GL_CACHE("TC: src miss (0x%x, 0x%x, %s)", TEX0.TBP0, psm_s.pal > 0 ? TEX0.CBP : 0, psm_str(TEX0.PSM));
} }
#endif #endif
src = CreateSource(TEX0, TEXA, dst, half_right, x_offset, y_offset, lod); src = CreateSource(TEX0, TEXA, dst, half_right, x_offset, y_offset, lod, &r);
new_source = true; new_source = true;
} }
else else
@ -1165,7 +1165,7 @@ void GSTextureCache::IncAge()
} }
//Fixme: Several issues in here. Not handling depth stencil, pitch conversion doesnt work. //Fixme: Several issues in here. Not handling depth stencil, pitch conversion doesnt work.
GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, Target* dst, bool half_right, int x_offset, int y_offset, const GSVector2i* lod) GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, Target* dst, bool half_right, int x_offset, int y_offset, const GSVector2i* lod, const GSVector4i* src_range)
{ {
const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[TEX0.PSM]; const GSLocalMemory::psm_t& psm = GSLocalMemory::m_psm[TEX0.PSM];
Source* src = new Source(m_renderer, TEX0, TEXA, false); Source* src = new Source(m_renderer, TEX0, TEXA, false);
@ -1340,8 +1340,10 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
GSVector2 scale = is_8bits ? GSVector2(1, 1) : dst->m_texture->GetScale(); GSVector2 scale = is_8bits ? GSVector2(1, 1) : dst->m_texture->GetScale();
GSVector4i sRect(0, 0, w, h);
const bool use_texture = shader == ShaderConvert::COPY; const bool use_texture = shader == ShaderConvert::COPY;
GSVector4i sRect(0, 0, w, h);
int destX = 0;
int destY = 0;
if (half_right) if (half_right)
{ {
@ -1361,6 +1363,27 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
DevCon.Error("Invalid half-right copy with width %d from %dx%d texture", half_width * 2, w, h); DevCon.Error("Invalid half-right copy with width %d from %dx%d texture", half_width * 2, w, h);
} }
} }
else if (src_range && dst->m_TEX0.TBW == TEX0.TBW && !is_8bits)
{
// optimization for TBP == FRAME
const GSDrawingContext* const context = m_renderer->m_context;
if (context->FRAME.Block() == TEX0.TBP0 || context->ZBUF.Block() == TEX0.TBP0)
{
// if it looks like a texture shuffle, we might read up to +/- 8 pixels on either side.
GSVector4 adjusted_src_range(*src_range);
if (static_cast<GSRendererHW*>(m_renderer)->IsPossibleTextureShuffle(src))
adjusted_src_range += GSVector4(-8.0f, 0.0f, 8.0f, 0.0f);
// don't forget to scale the copy range
adjusted_src_range = adjusted_src_range * GSVector4(scale).xyxy();
sRect = sRect.rintersect(GSVector4i(adjusted_src_range));
destX = sRect.x;
destY = sRect.y;
// clean up immediately afterwards
m_temporary_source = src;
}
}
// Don't be fooled by the name. 'dst' is the old target (hence the input) // 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) // 'src' is the new texture cache entry (hence the output)
@ -1380,7 +1403,7 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
if (use_texture) if (use_texture)
{ {
g_gs_device->CopyRect(sTex, dTex, sRect, 0, 0); g_gs_device->CopyRect(sTex, dTex, sRect, destX, destY);
} }
else else
{ {
@ -1388,7 +1411,7 @@ GSTextureCache::Source* GSTextureCache::CreateSource(const GIFRegTEX0& TEX0, con
sRectF.z /= sTex->GetWidth(); sRectF.z /= sTex->GetWidth();
sRectF.w /= sTex->GetHeight(); sRectF.w /= sTex->GetHeight();
g_gs_device->StretchRect(sTex, sRectF, dTex, GSVector4(0, 0, w, h), shader, false); g_gs_device->StretchRect(sTex, sRectF, dTex, GSVector4(destX, destY, w, h), shader, false);
} }
if (src->m_texture) if (src->m_texture)
@ -2439,6 +2462,15 @@ GSTextureCache::SurfaceOffset GSTextureCache::ComputeSurfaceOffset(const Surface
return so; return so;
} }
void GSTextureCache::InvalidateTemporarySource()
{
if (!m_temporary_source)
return;
m_src.RemoveAt(m_temporary_source);
m_temporary_source = nullptr;
}
void GSTextureCache::InjectHashCacheTexture(const HashCacheKey& key, GSTexture* tex) void GSTextureCache::InjectHashCacheTexture(const HashCacheKey& key, GSTexture* tex)
{ {
auto it = m_hash_cache.find(key); auto it = m_hash_cache.find(key);

View File

@ -285,8 +285,9 @@ protected:
static u8* m_temp; static u8* m_temp;
constexpr static size_t S_SURFACE_OFFSET_CACHE_MAX_SIZE = std::numeric_limits<u16>::max(); constexpr static size_t S_SURFACE_OFFSET_CACHE_MAX_SIZE = std::numeric_limits<u16>::max();
std::unordered_map<SurfaceOffsetKey, SurfaceOffset, SurfaceOffsetKeyHash, SurfaceOffsetKeyEqual> m_surface_offset_cache; std::unordered_map<SurfaceOffsetKey, SurfaceOffset, SurfaceOffsetKeyHash, SurfaceOffsetKeyEqual> m_surface_offset_cache;
Source* m_temporary_source = nullptr; // invalidated after the draw
Source* CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, Target* t = NULL, bool half_right = false, int x_offset = 0, int y_offset = 0, const GSVector2i* lod = nullptr); Source* CreateSource(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, Target* t = NULL, bool half_right = false, int x_offset = 0, int y_offset = 0, const GSVector2i* lod = nullptr, const GSVector4i* src_range = nullptr);
Target* CreateTarget(const GIFRegTEX0& TEX0, int w, int h, int type, const bool clear); Target* CreateTarget(const GIFRegTEX0& TEX0, int w, int h, int type, const bool clear);
HashCacheEntry* LookupHashCache(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, bool& paltex, const u32* clut, const GSVector2i* lod); HashCacheEntry* LookupHashCache(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA, bool& paltex, const u32* clut, const GSVector2i* lod);
@ -333,6 +334,9 @@ public:
SurfaceOffset ComputeSurfaceOffset(const uint32_t bp, const uint32_t bw, const uint32_t psm, const GSVector4i& r, const Target* t); SurfaceOffset ComputeSurfaceOffset(const uint32_t bp, const uint32_t bw, const uint32_t psm, const GSVector4i& r, const Target* t);
SurfaceOffset ComputeSurfaceOffset(const SurfaceOffsetKey& sok); SurfaceOffset ComputeSurfaceOffset(const SurfaceOffsetKey& sok);
/// Invalidates a temporary source, a partial copy only created from the current RT/DS for the current draw.
void InvalidateTemporarySource();
/// Injects a texture into the hash cache, by using GSTexture::Swap(), transitively applying to all sources. Ownership of tex is transferred. /// Injects a texture into the hash cache, by using GSTexture::Swap(), transitively applying to all sources. Ownership of tex is transferred.
void InjectHashCacheTexture(const HashCacheKey& key, GSTexture* tex); void InjectHashCacheTexture(const HashCacheKey& key, GSTexture* tex);
}; };