summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorScott Mansell <phiren@gmail.com>2016-06-16 21:51:39 +1200
committerScott Mansell <phiren@gmail.com>2016-06-17 23:46:22 +1200
commit94eaacae3036c421dcd346360c0bf835bd211469 (patch)
treed4eb497cd81d88e4ac1a3ca7a1538ac0036ddf5a /Source/Core
parentaa07f0903bbb7cec174371cfe53086676226c341 (diff)
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.
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/VideoCommon/TextureCacheBase.cpp29
-rw-r--r--Source/Core/VideoCommon/TextureCacheBase.h15
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 <memory>
#include <tuple>
#include <unordered_map>
+#include <unordered_set>
#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<u64, TCacheEntryBase*>::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<TCacheEntryBase*> 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;