summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon/Src/TextureCacheBase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Core/VideoCommon/Src/TextureCacheBase.cpp')
-rw-r--r--Source/Core/VideoCommon/Src/TextureCacheBase.cpp92
1 files changed, 81 insertions, 11 deletions
diff --git a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp
index ea008dc898..41af7ac946 100644
--- a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp
+++ b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp
@@ -30,6 +30,8 @@ unsigned int TextureCache::temp_size;
TextureCache::TexCache TextureCache::textures;
+TextureCache::TexPool TextureCache::texPool;
+
TextureCache::BackupConfig TextureCache::backup_config;
bool invalidate_texture_cache_requested;
@@ -68,6 +70,13 @@ void TextureCache::Invalidate()
delete iter->second;
textures.clear();
+
+ TexPool::iterator
+ iter2 = texPool.begin(),
+ tcend2 = texPool.end();
+ for (; iter2 != tcend2; ++iter2)
+ delete iter2->second;
+ texPool.clear();
}
TextureCache::~TextureCache()
@@ -135,7 +144,7 @@ void TextureCache::Cleanup()
// EFB copies living on the host GPU are unrecoverable and thus shouldn't be deleted
&& ! iter->second->IsEfbCopy() )
{
- delete iter->second;
+ PoolTexture(iter->second);
textures.erase(iter++);
}
else
@@ -143,6 +152,21 @@ void TextureCache::Cleanup()
++iter;
}
}
+
+ TexPool::iterator iter2 = texPool.begin();
+ TexPool::iterator tcend2 = texPool.end();
+ while (iter2 != tcend2)
+ {
+ if (frameCount > TEXTURE_KILL_THRESHOLD + iter2->second->frameCount)
+ {
+ delete iter2->second;
+ texPool.erase(iter2++);
+ }
+ else
+ {
+ ++iter2;
+ }
+ }
}
void TextureCache::InvalidateRange(u32 start_address, u32 size)
@@ -155,7 +179,7 @@ void TextureCache::InvalidateRange(u32 start_address, u32 size)
const int rangePosition = iter->second->IntersectsMemoryRange(start_address, size);
if (0 == rangePosition)
{
- delete iter->second;
+ PoolTexture(iter->second);
textures.erase(iter++);
}
else
@@ -215,7 +239,7 @@ void TextureCache::ClearRenderTargets()
{
if (iter->second->type == TCET_EC_VRAM)
{
- delete iter->second;
+ PoolTexture(iter->second);
textures.erase(iter++);
}
else
@@ -426,8 +450,8 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int const stage,
}
else
{
- // delete the texture and make a new one
- delete entry;
+ // pool the texture and make a new one
+ PoolTexture(entry);
entry = NULL;
}
}
@@ -445,8 +469,8 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int const stage,
expandedWidth = width;
expandedHeight = height;
- // If we thought we could reuse the texture before, make sure to delete it now!
- delete entry;
+ // If we thought we could reuse the texture before, make sure to pool it now!
+ PoolTexture(entry);
entry = NULL;
}
using_custom_texture = true;
@@ -473,6 +497,15 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int const stage,
const bool use_native_mips = use_mipmaps && !using_custom_lods && (width == nativeW && height == nativeH);
texLevels = (use_native_mips || using_custom_lods) ? texLevels : 1; // TODO: Should be forced to 1 for non-pow2 textures (e.g. efb copies with automatically adjusted IR)
+ // try to search for a pooled texture
+ if (NULL == entry)
+ {
+ // Try to find a matching texture in the pool. We pool unused texture as they often just change the type.
+ // This happens in eg efb2ram which overwrites half of a texture. So most of this textures are only pooled
+ // for some frames.
+ textures[texID] = entry = GetPooledTexture ( width, height, full_format, texLevels, false );
+ }
+
// create the entry/texture
if (NULL == entry)
{
@@ -821,16 +854,23 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
else if (!(entry->type == TCET_EC_VRAM && entry->virtual_width == scaled_tex_w && entry->virtual_height == scaled_tex_h))
{
// remove it and recreate it as a render target
- delete entry;
+ PoolTexture(entry);
entry = NULL;
}
}
if (NULL == entry)
{
- // create the texture
- textures[dstAddr] = entry = g_texture_cache->CreateRenderTargetTexture(scaled_tex_w, scaled_tex_h);
-
+ // search for a compatible pooled texture
+ entry = GetPooledTexture(scaled_tex_w, scaled_tex_h, 0, 0, true);
+
+ if (NULL == entry)
+ {
+ // create the texture
+ entry = g_texture_cache->CreateRenderTargetTexture(scaled_tex_w, scaled_tex_h);
+ }
+ textures[dstAddr] = entry;
+
// TODO: Using the wrong dstFormat, dumb...
entry->SetGeneralParameters(dstAddr, 0, dstFormat, 1);
entry->SetDimensions(tex_w, tex_h, scaled_tex_w, scaled_tex_h);
@@ -842,3 +882,33 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
entry->FromRenderTarget(dstAddr, dstFormat, srcFormat, srcRect, isIntensity, scaleByHalf, cbufid, colmat);
}
+
+TextureCache::TCacheEntryBase* TextureCache::GetPooledTexture ( u32 width, u32 height, u32 full_format, u32 maxlevel, bool isEfbCopy )
+{
+ TCacheEntryBase* entry = NULL;
+ std::pair<TexPool::iterator, TexPool::iterator> bounds;
+ bounds = texPool.equal_range(std::make_pair(width, height));
+ while(!entry && bounds.first != bounds.second) {
+ entry = bounds.first->second;
+ if (
+ (isEfbCopy && entry->IsEfbCopy()) ||
+ (!isEfbCopy && entry->type == TCET_NORMAL && full_format == entry->format && entry->num_mipmaps == maxlevel) ||
+ (!isEfbCopy && entry->type == TCET_EC_DYNAMIC)
+ )
+ {
+ texPool.erase(bounds.first);
+ }
+ else
+ {
+ entry = NULL;
+ bounds.first++;
+ }
+ }
+ return entry;
+}
+
+void TextureCache::PoolTexture(TextureCache::TCacheEntryBase* entry)
+{
+ entry->frameCount = frameCount;
+ texPool.insert(std::make_pair(std::make_pair(entry->virtual_width, entry->virtual_height), entry));
+}