summaryrefslogtreecommitdiff
path: root/Source/Core/VideoCommon/TextureCacheBase.cpp
diff options
context:
space:
mode:
authormimimi085181 <mimimi085181@gmail.com>2017-06-29 23:09:32 +0200
committermimimi085181 <mimimi085181@gmail.com>2017-07-10 01:49:27 +0200
commit53663c00b931c675199ab9f0eb0d0af18083995d (patch)
treee0011ff224154fb5489eac15c2aa2c013cfcd5f7 /Source/Core/VideoCommon/TextureCacheBase.cpp
parent07ab81e1bd66acd2a9b0aa494c17b11fb65cce3c (diff)
Implement minimal emulation of TMEM caching
This is a remake of https://github.com/dolphin-emu/dolphin/pull/3749 Full credit goes to phire. Old message: "If none of the texture registers have changed and TMEM hasn't been invalidated or changed in other ways, we can blindly reuse the old texture cache entries without rehashing. Not only does this fix the bloom effect in Spyro: A Hero's Tail (The game abused texture cache) but it will also provide speedups for other games which use the same texture over multiple draw calls, especially when safe texture cache is in use." Changed the pr per phire's instructions to only return the current texture(s) if none of the texture registers were changed. If any texture register was changed, fall back to the default hashing and rebuilding textures from memory.
Diffstat (limited to 'Source/Core/VideoCommon/TextureCacheBase.cpp')
-rw-r--r--Source/Core/VideoCommon/TextureCacheBase.cpp54
1 files changed, 45 insertions, 9 deletions
diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp
index c61fa1fe5e..f0733c7ea0 100644
--- a/Source/Core/VideoCommon/TextureCacheBase.cpp
+++ b/Source/Core/VideoCommon/TextureCacheBase.cpp
@@ -42,6 +42,8 @@ static const int TEXTURE_POOL_KILL_THRESHOLD = 3;
std::unique_ptr<TextureCacheBase> g_texture_cache;
+std::bitset<8> TextureCacheBase::valid_bind_points;
+
TextureCacheBase::TCacheEntry::TCacheEntry(std::unique_ptr<AbstractTexture> tex)
: texture(std::move(tex))
{
@@ -76,11 +78,17 @@ TextureCacheBase::TextureCacheBase()
HiresTexture::Init();
SetHash64Function();
+
+ InvalidateAllBindPoints();
}
void TextureCacheBase::Invalidate()
{
- UnbindTextures();
+ InvalidateAllBindPoints();
+ for (size_t i = 0; i < bound_textures.size(); ++i)
+ {
+ bound_textures[i] = nullptr;
+ }
for (auto& tex : textures_by_address)
{
@@ -138,7 +146,11 @@ void TextureCacheBase::Cleanup(int _frameCount)
TexAddrCache::iterator tcend = textures_by_address.end();
while (iter != tcend)
{
- if (iter->second->frameCount == FRAMECOUNT_INVALID)
+ if (iter->second->tmem_only)
+ {
+ iter = InvalidateTexture(iter);
+ }
+ else if (iter->second->frameCount == FRAMECOUNT_INVALID)
{
iter->second->frameCount = _frameCount;
++iter;
@@ -307,7 +319,7 @@ TextureCacheBase::DoPartialTextureUpdates(TCacheEntry* entry_to_update, u8* pale
while (iter.first != iter.second)
{
TCacheEntry* entry = iter.first->second;
- if (entry != entry_to_update && entry->IsEfbCopy() &&
+ if (entry != entry_to_update && entry->IsEfbCopy() && !entry->tmem_only &&
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)
@@ -450,6 +462,9 @@ TextureCacheBase::TCacheEntry* TextureCacheBase::ReturnEntry(unsigned int stage,
GFX_DEBUGGER_PAUSE_AT(NEXT_TEXTURE_CHANGE, true);
+ // We need to keep track of invalided textures until they have actually been replaced or re-loaded
+ valid_bind_points.set(stage);
+
return entry;
}
@@ -457,18 +472,19 @@ void TextureCacheBase::BindTextures()
{
for (size_t i = 0; i < bound_textures.size(); ++i)
{
- if (bound_textures[i])
+ if (IsValidBindPoint(static_cast<u32>(i)) && bound_textures[i])
bound_textures[i]->texture->Bind(static_cast<u32>(i));
}
}
-void TextureCacheBase::UnbindTextures()
-{
- bound_textures.fill(nullptr);
-}
-
TextureCacheBase::TCacheEntry* TextureCacheBase::Load(const u32 stage)
{
+ // if this stage was not invalidated by changes to texture registers, keep the current texture
+ if (IsValidBindPoint(stage) && bound_textures[stage])
+ {
+ return ReturnEntry(stage, bound_textures[stage]);
+ }
+
const FourTexUnits& tex = bpmem.tex[stage >> 2];
const u32 id = stage & 3;
const u32 address = (tex.texImage3[id].image_base /* & 0x1FFFFF*/) << 5;
@@ -610,6 +626,14 @@ TextureCacheBase::TCacheEntry* TextureCacheBase::Load(const u32 stage)
while (iter != iter_range.second)
{
TCacheEntry* entry = iter->second;
+
+ // Skip entries that are only left in our texture cache for the tmem cache emulation
+ if (entry->tmem_only)
+ {
+ ++iter;
+ continue;
+ }
+
// Do not load strided EFB copies, they are not meant to be used directly
if (entry->IsEfbCopy() && entry->native_width == nativeW && entry->native_height == nativeH &&
entry->memory_stride == entry->BytesPerRow())
@@ -1466,6 +1490,18 @@ TextureCacheBase::InvalidateTexture(TexAddrCache::iterator iter)
entry->textures_by_hash_iter = textures_by_hash.end();
}
+ for (size_t i = 0; i < bound_textures.size(); ++i)
+ {
+ // If the entry is currently bound and not invalidated, keep it, but mark it as invalidated.
+ // This way it can still be used via tmem cache emulation, but nothing else.
+ // Spyro: A Hero's Tail is known for using such overwritten textures.
+ if (bound_textures[i] == entry && IsValidBindPoint(static_cast<u32>(i)))
+ {
+ bound_textures[i]->tmem_only = true;
+ return ++iter;
+ }
+ }
+
auto config = entry->texture->GetConfig();
texture_pool.emplace(config, TexPoolEntry(std::move(entry->texture)));