mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-10 08:09:26 +01:00
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.
This commit is contained in:
parent
aa07f0903b
commit
94eaacae30
@ -319,6 +319,7 @@ TextureCacheBase::TCacheEntryBase* TextureCacheBase::DoPartialTextureUpdates(Tex
|
|||||||
TCacheEntryBase* entry = iter->second;
|
TCacheEntryBase* entry = iter->second;
|
||||||
if (entry != entry_to_update
|
if (entry != entry_to_update
|
||||||
&& entry->IsEfbCopy()
|
&& entry->IsEfbCopy()
|
||||||
|
&& entry->references.count(entry_to_update) == 0
|
||||||
&& entry->OverlapsMemoryRange(entry_to_update->addr, entry_to_update->size_in_bytes)
|
&& entry->OverlapsMemoryRange(entry_to_update->addr, entry_to_update->size_in_bytes)
|
||||||
&& entry->memory_stride == numBlocksX * block_size)
|
&& entry->memory_stride == numBlocksX * block_size)
|
||||||
{
|
{
|
||||||
@ -329,6 +330,8 @@ TextureCacheBase::TCacheEntryBase* TextureCacheBase::DoPartialTextureUpdates(Tex
|
|||||||
TCacheEntryBase *decoded_entry = entry->ApplyPalette(palette, tlutfmt);
|
TCacheEntryBase *decoded_entry = entry->ApplyPalette(palette, tlutfmt);
|
||||||
if (decoded_entry)
|
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
|
// Mark the texture update as used, as if it was loaded directly
|
||||||
entry->frameCount = FRAMECOUNT_INVALID;
|
entry->frameCount = FRAMECOUNT_INVALID;
|
||||||
entry = decoded_entry;
|
entry = decoded_entry;
|
||||||
@ -394,12 +397,20 @@ TextureCacheBase::TCacheEntryBase* TextureCacheBase::DoPartialTextureUpdates(Tex
|
|||||||
dstrect.right = (dst_x + copy_width);
|
dstrect.right = (dst_x + copy_width);
|
||||||
dstrect.bottom = (dst_y + copy_height);
|
dstrect.bottom = (dst_y + copy_height);
|
||||||
entry_to_update->CopyRectangleFromTexture(entry, srcrect, dstrect);
|
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)
|
if (isPaletteTexture)
|
||||||
|
{
|
||||||
|
// Remove the converted texture, it won't be used anywhere else
|
||||||
FreeTexture(GetTexCacheIter(entry));
|
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
|
else
|
||||||
{
|
{
|
||||||
@ -1301,6 +1312,16 @@ TextureCacheBase::TexCache::iterator TextureCacheBase::GetTexCacheIter(TextureCa
|
|||||||
return textures_by_address.end();
|
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)
|
TextureCacheBase::TexCache::iterator TextureCacheBase::FreeTexture(TexCache::iterator iter)
|
||||||
{
|
{
|
||||||
if (iter == textures_by_address.end())
|
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->textures_by_hash_iter = textures_by_hash.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->frameCount = FRAMECOUNT_INVALID;
|
entry->Reset();
|
||||||
texture_pool.emplace(entry->config, entry);
|
texture_pool.emplace(entry->config, entry);
|
||||||
|
|
||||||
return textures_by_address.erase(iter);
|
return textures_by_address.erase(iter);
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "VideoCommon/BPMemory.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
|
// 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;
|
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)
|
void SetGeneralParameters(u32 _addr, u32 _size, u32 _format)
|
||||||
{
|
{
|
||||||
addr = _addr;
|
addr = _addr;
|
||||||
@ -89,11 +95,20 @@ public:
|
|||||||
hash = _hash;
|
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 SetEfbCopy(u32 stride);
|
||||||
|
void Reset(); // Prepare for reuse
|
||||||
|
|
||||||
TCacheEntryBase(const TCacheEntryConfig& c) : config(c) {}
|
TCacheEntryBase(const TCacheEntryConfig& c) : config(c) {}
|
||||||
virtual ~TCacheEntryBase();
|
virtual ~TCacheEntryBase();
|
||||||
|
|
||||||
|
|
||||||
virtual void Bind(unsigned int stage) = 0;
|
virtual void Bind(unsigned int stage) = 0;
|
||||||
virtual bool Save(const std::string& filename, unsigned int level) = 0;
|
virtual bool Save(const std::string& filename, unsigned int level) = 0;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user