From 94eaacae3036c421dcd346360c0bf835bd211469 Mon Sep 17 00:00:00 2001 From: Scott Mansell Date: Thu, 16 Jun 2016 21:51:39 +1200 Subject: [PATCH] TextureCache: Track efb copies used in a partially updated texture Fixes a major preformance regression in Skies of Arcadia during battle transisions. I had plans for a more advanced version of this code after 5.0, but here is a minimal implemenation for now. --- Source/Core/VideoCommon/TextureCacheBase.cpp | 29 +++++++++++++++++--- Source/Core/VideoCommon/TextureCacheBase.h | 15 ++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp index ee8491fb86..906f8e19c0 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/TextureCacheBase.cpp @@ -319,6 +319,7 @@ TextureCacheBase::TCacheEntryBase* TextureCacheBase::DoPartialTextureUpdates(Tex TCacheEntryBase* entry = iter->second; if (entry != entry_to_update && entry->IsEfbCopy() + && entry->references.count(entry_to_update) == 0 && entry->OverlapsMemoryRange(entry_to_update->addr, entry_to_update->size_in_bytes) && entry->memory_stride == numBlocksX * block_size) { @@ -329,6 +330,8 @@ TextureCacheBase::TCacheEntryBase* TextureCacheBase::DoPartialTextureUpdates(Tex TCacheEntryBase *decoded_entry = entry->ApplyPalette(palette, tlutfmt); if (decoded_entry) { + // Link the efb copy with the partially updated texture, so we won't apply this partial update again + entry->CreateReference(entry_to_update); // Mark the texture update as used, as if it was loaded directly entry->frameCount = FRAMECOUNT_INVALID; entry = decoded_entry; @@ -394,12 +397,20 @@ TextureCacheBase::TCacheEntryBase* TextureCacheBase::DoPartialTextureUpdates(Tex dstrect.right = (dst_x + copy_width); dstrect.bottom = (dst_y + copy_height); entry_to_update->CopyRectangleFromTexture(entry, srcrect, dstrect); - // Mark the texture update as used, as if it was loaded directly - entry->frameCount = FRAMECOUNT_INVALID; - // Remove the converted texture, it won't be used anywhere else + if (isPaletteTexture) + { + // Remove the converted texture, it won't be used anywhere else FreeTexture(GetTexCacheIter(entry)); + } + else + { + // Link the two textures together, so we won't apply this partial update again + entry->CreateReference(entry_to_update); + // Mark the texture update as used, as if it was loaded directly + entry->frameCount = FRAMECOUNT_INVALID; + } } else { @@ -1301,6 +1312,16 @@ TextureCacheBase::TexCache::iterator TextureCacheBase::GetTexCacheIter(TextureCa return textures_by_address.end(); } +void TextureCacheBase::TCacheEntryBase::Reset() +{ + // Unlink any references + for (auto& reference : references) + reference->references.erase(this); + + references.clear(); + frameCount = FRAMECOUNT_INVALID; +} + TextureCacheBase::TexCache::iterator TextureCacheBase::FreeTexture(TexCache::iterator iter) { if (iter == textures_by_address.end()) @@ -1314,7 +1335,7 @@ TextureCacheBase::TexCache::iterator TextureCacheBase::FreeTexture(TexCache::ite entry->textures_by_hash_iter = textures_by_hash.end(); } - entry->frameCount = FRAMECOUNT_INVALID; + entry->Reset(); texture_pool.emplace(entry->config, entry); return textures_by_address.erase(iter); diff --git a/Source/Core/VideoCommon/TextureCacheBase.h b/Source/Core/VideoCommon/TextureCacheBase.h index e87dfc29d1..bb8dfe1111 100644 --- a/Source/Core/VideoCommon/TextureCacheBase.h +++ b/Source/Core/VideoCommon/TextureCacheBase.h @@ -8,6 +8,7 @@ #include #include #include +#include #include "Common/CommonTypes.h" #include "VideoCommon/BPMemory.h" @@ -68,6 +69,11 @@ public: // Keep an iterator to the entry in textures_by_hash, so it does not need to be searched when removing the cache entry std::multimap::iterator textures_by_hash_iter; + // This is used to keep track of both: + // * efb copies used by this partially updated texture + // * partially updated textures which refer to this efb copy + std::unordered_set references; + void SetGeneralParameters(u32 _addr, u32 _size, u32 _format) { addr = _addr; @@ -89,11 +95,20 @@ public: hash = _hash; } + // This texture entry is used by the other entry as a sub-texture + void CreateReference(TCacheEntryBase* other_entry) + { + this->references.emplace(other_entry); + other_entry->references.emplace(this); + } + void SetEfbCopy(u32 stride); + void Reset(); // Prepare for reuse TCacheEntryBase(const TCacheEntryConfig& c) : config(c) {} virtual ~TCacheEntryBase(); + virtual void Bind(unsigned int stage) = 0; virtual bool Save(const std::string& filename, unsigned int level) = 0;