From 9838dd9df27007b8206bffd2d2146c75cf2ca0a4 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Mon, 18 Nov 2024 13:24:01 +1000 Subject: [PATCH] GPU/TextureCache: Purge copy-target sources from hash cache Saves some VRAM/hash cache usage by disacarding hash cache entries that are discarded by a copy, but unfortunately cannot stop the uploads. --- src/core/gpu_hw_texture_cache.cpp | 43 ++++++++++++++++++++++--------- src/core/gpu_hw_texture_cache.h | 4 +-- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/src/core/gpu_hw_texture_cache.cpp b/src/core/gpu_hw_texture_cache.cpp index 630456b78..cac90ac19 100644 --- a/src/core/gpu_hw_texture_cache.cpp +++ b/src/core/gpu_hw_texture_cache.cpp @@ -246,16 +246,18 @@ static void DestroyPipelines(); static const Source* ReturnSource(Source* source, const GSVector4i uv_rect, PaletteRecordFlags flags); static Source* CreateSource(SourceKey key); +static HashCacheKey GetHashCacheKey(SourceKey key, HashType tex_hash, HashType pal_hash); static HashCacheEntry* LookupHashCache(SourceKey key, HashType tex_hash, HashType pal_hash); static void ApplyTextureReplacements(SourceKey key, HashType tex_hash, HashType pal_hash, HashCacheEntry* entry); +static void RemoveFromHashCache(HashCacheEntry* entry, SourceKey key, HashType tex_hash, HashType pal_hash); static void RemoveFromHashCache(HashCache::iterator it); static void ClearHashCache(); static bool IsPageDrawn(u32 page_index, const GSVector4i rect); static void InvalidatePageSources(u32 pn); -static void InvalidatePageSources(u32 pn, const GSVector4i rc); +static void InvalidatePageSources(u32 pn, const GSVector4i rc, bool remove_from_hash_cache = false); static void InvalidateSources(); -static void DestroySource(Source* src); +static void DestroySource(Source* src, bool remove_from_hash_cache = false); static HashType HashPage(u8 page, GPUTextureMode mode); static HashType HashPalette(GPUTexturePaletteReg palette, GPUTextureMode mode); @@ -902,7 +904,7 @@ void GPUTextureCache::CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 w // copy and invalidate GPU_SW_Rasterizer::CopyVRAM(src_x, src_y, dst_x, dst_y, width, height, check_mask, set_mask); - AddWrittenRectangle(dst_bounds, convert_copies_to_writes); + AddWrittenRectangle(dst_bounds, convert_copies_to_writes, true); } void GPUTextureCache::WriteVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, bool set_mask, bool check_mask, @@ -931,11 +933,11 @@ void GPUTextureCache::WriteVRAM(u32 x, u32 y, u32 width, u32 height, const void* s_last_vram_write = it; } -void GPUTextureCache::AddWrittenRectangle(const GSVector4i rect, bool update_vram_writes) +void GPUTextureCache::AddWrittenRectangle(const GSVector4i rect, bool update_vram_writes, bool remove_from_hash_cache) { - LoopRectPages(rect, [&rect, &update_vram_writes](u32 pn) { + LoopRectPages(rect, [&rect, &update_vram_writes, &remove_from_hash_cache](u32 pn) { PageEntry& page = s_pages[pn]; - InvalidatePageSources(pn, rect); + InvalidatePageSources(pn, rect, remove_from_hash_cache); if (page.num_draw_rects > 0) { @@ -1372,7 +1374,7 @@ void GPUTextureCache::InvalidatePageSources(u32 pn) DebugAssert(!ps.head && !ps.tail); } -void GPUTextureCache::InvalidatePageSources(u32 pn, const GSVector4i rc) +void GPUTextureCache::InvalidatePageSources(u32 pn, const GSVector4i rc, bool remove_from_hash_cache) { DebugAssert(pn < NUM_VRAM_PAGES); @@ -1390,11 +1392,11 @@ void GPUTextureCache::InvalidatePageSources(u32 pn, const GSVector4i rc) } GL_INS_FMT("Invalidate source {} in page {} due to overlapping with {}", SourceToString(src), pn, rc); - DestroySource(src); + DestroySource(src, remove_from_hash_cache); } } -void GPUTextureCache::DestroySource(Source* src) +void GPUTextureCache::DestroySource(Source* src, bool remove_from_hash_cache) { GL_INS_FMT("Invalidate source {}", SourceToString(src)); @@ -1420,9 +1422,13 @@ void GPUTextureCache::DestroySource(Source* src) for (u32 i = 0; i < src->num_page_refs; i++) ListUnlink(src->page_refs[i]); - DebugAssert(src->from_hash_cache && src->from_hash_cache->ref_count > 0); + HashCacheEntry* hcentry = src->from_hash_cache; + DebugAssert(hcentry && hcentry->ref_count > 0); ListUnlink(src->hash_cache_ref); - src->from_hash_cache->ref_count--; + hcentry->ref_count--; + if (hcentry->ref_count == 0 && remove_from_hash_cache) + RemoveFromHashCache(hcentry, src->key, src->texture_hash, src->palette_hash); + delete src; } @@ -2013,9 +2019,14 @@ void GPUTextureCache::InitializeVRAMWritePaletteRecord(VRAMWrite::PaletteRecord* } } +GPUTextureCache::HashCacheKey GPUTextureCache::GetHashCacheKey(SourceKey key, HashType tex_hash, HashType pal_hash) +{ + return HashCacheKey{tex_hash, pal_hash, static_cast(key.mode)}; +} + GPUTextureCache::HashCacheEntry* GPUTextureCache::LookupHashCache(SourceKey key, HashType tex_hash, HashType pal_hash) { - const HashCacheKey hkey = {tex_hash, pal_hash, static_cast(key.mode)}; + const HashCacheKey hkey = GetHashCacheKey(key, tex_hash, pal_hash); const auto it = s_hash_cache.find(hkey); if (it != s_hash_cache.end()) @@ -2048,6 +2059,14 @@ GPUTextureCache::HashCacheEntry* GPUTextureCache::LookupHashCache(SourceKey key, return &s_hash_cache.emplace(hkey, std::move(entry)).first->second; } +void GPUTextureCache::RemoveFromHashCache(HashCacheEntry* entry, SourceKey key, HashType tex_hash, HashType pal_hash) +{ + const HashCacheKey hckey = GetHashCacheKey(key, tex_hash, pal_hash); + const auto iter = s_hash_cache.find(hckey); + Assert(iter != s_hash_cache.end() && &iter->second == entry); + RemoveFromHashCache(iter); +} + void GPUTextureCache::RemoveFromHashCache(HashCache::iterator it) { ListIterate(it->second.sources, [](Source* source) { DestroySource(source); }); diff --git a/src/core/gpu_hw_texture_cache.h b/src/core/gpu_hw_texture_cache.h index dd629a40f..8fc601e64 100644 --- a/src/core/gpu_hw_texture_cache.h +++ b/src/core/gpu_hw_texture_cache.h @@ -109,13 +109,13 @@ void Shutdown(); void Invalidate(); -void AddWrittenRectangle(const GSVector4i rect, bool update_vram_writes = false); +void AddWrittenRectangle(const GSVector4i rect, bool update_vram_writes = false, bool remove_from_hash_cache = false); void AddDrawnRectangle(const GSVector4i rect, const GSVector4i clip_rect); void CopyVRAM(u32 src_x, u32 src_y, u32 dst_x, u32 dst_y, u32 width, u32 height, bool set_mask, bool check_mask, const GSVector4i src_bounds, const GSVector4i dst_bounds); void WriteVRAM(u32 x, u32 y, u32 width, u32 height, const void* data, bool set_mask, bool check_mask, - const GSVector4i bounds); + const GSVector4i bounds); const Source* LookupSource(SourceKey key, const GSVector4i uv_rect, PaletteRecordFlags flags);