Merge pull request #9509 from hrydgard/secondary-replace-fix

If an entry already exists in the secondary texture cache, delete it properly
This commit is contained in:
Henrik Rydgård 2017-03-26 19:21:21 +02:00 committed by GitHub
commit 60b8ffa3a0

View File

@ -436,11 +436,12 @@ void TextureCacheCommon::Decimate() {
VERBOSE_LOG(G3D, "Decimated texture cache, saved %d estimated bytes - now %d bytes", had - cacheSizeEstimate_, cacheSizeEstimate_); VERBOSE_LOG(G3D, "Decimated texture cache, saved %d estimated bytes - now %d bytes", had - cacheSizeEstimate_, cacheSizeEstimate_);
} }
// If enabled, we also need to clear the secondary cache.
if (g_Config.bTextureSecondaryCache && secondCacheSizeEstimate_ >= TEXCACHE_SECOND_MIN_PRESSURE) { if (g_Config.bTextureSecondaryCache && secondCacheSizeEstimate_ >= TEXCACHE_SECOND_MIN_PRESSURE) {
const u32 had = secondCacheSizeEstimate_; const u32 had = secondCacheSizeEstimate_;
for (TexCache::iterator iter = secondCache_.begin(); iter != secondCache_.end(); ) { for (TexCache::iterator iter = secondCache_.begin(); iter != secondCache_.end(); ) {
// In low memory mode, we kill them all. // In low memory mode, we kill them all since secondary cache is disabled.
if (lowMemoryMode_ || iter->second->lastFrame + TEXTURE_SECOND_KILL_AGE < gpuStats.numFlips) { if (lowMemoryMode_ || iter->second->lastFrame + TEXTURE_SECOND_KILL_AGE < gpuStats.numFlips) {
ReleaseTexture(iter->second.get(), true); ReleaseTexture(iter->second.get(), true);
secondCacheSizeEstimate_ -= EstimateTexMemoryUsage(iter->second.get()); secondCacheSizeEstimate_ -= EstimateTexMemoryUsage(iter->second.get());
@ -1379,6 +1380,9 @@ void TextureCacheCommon::ApplyTexture() {
int w = gstate.getTextureWidth(0); int w = gstate.getTextureWidth(0);
int h = gstate.getTextureHeight(0); int h = gstate.getTextureHeight(0);
entry->fullhash = QuickTexHash(replacer_, entry->addr, entry->bufw, w, h, GETextureFormat(entry->format), entry); entry->fullhash = QuickTexHash(replacer_, entry->addr, entry->bufw, w, h, GETextureFormat(entry->format), entry);
// TODO: Here we could check the secondary cache; maybe the texture is in there?
// We would need to abort the build if so.
} }
if (nextNeedsChange_) { if (nextNeedsChange_) {
// This texture existed previously, let's handle the change. // This texture existed previously, let's handle the change.
@ -1392,7 +1396,8 @@ void TextureCacheCommon::ApplyTexture() {
replaceImages = HandleTextureChange(entry, "hash fail", true, doDelete); replaceImages = HandleTextureChange(entry, "hash fail", true, doDelete);
nextNeedsRebuild_ = true; nextNeedsRebuild_ = true;
} else if (nextTexture_ != nullptr) { } else if (nextTexture_ != nullptr) {
// Secondary cache picked a different texture, use it. // The secondary cache may choose an entry from its storage by setting nextTexture_.
// This means we should set that, instead of our previous entry.
entry = nextTexture_; entry = nextTexture_;
nextTexture_ = nullptr; nextTexture_ = nullptr;
UpdateMaxSeenV(entry, gstate.isModeThrough()); UpdateMaxSeenV(entry, gstate.isModeThrough());
@ -1419,6 +1424,7 @@ void TextureCacheCommon::Clear(bool delete_them) {
for (TexCache::iterator iter = cache_.begin(); iter != cache_.end(); ++iter) { for (TexCache::iterator iter = cache_.begin(); iter != cache_.end(); ++iter) {
ReleaseTexture(iter->second.get(), delete_them); ReleaseTexture(iter->second.get(), delete_them);
} }
// In case the setting was changed, we ALWAYS clear the secondary cache (enabled or not.)
for (TexCache::iterator iter = secondCache_.begin(); iter != secondCache_.end(); ++iter) { for (TexCache::iterator iter = secondCache_.begin(); iter != secondCache_.end(); ++iter) {
ReleaseTexture(iter->second.get(), delete_them); ReleaseTexture(iter->second.get(), delete_them);
} }
@ -1463,31 +1469,46 @@ bool TextureCacheCommon::CheckFullHash(TexCacheEntry *entry, bool &doDelete) {
} }
// Don't give up just yet. Let's try the secondary cache if it's been invalidated before. // Don't give up just yet. Let's try the secondary cache if it's been invalidated before.
// If it's failed a bunch of times, then the second cache is just wasting time and VRAM.
if (g_Config.bTextureSecondaryCache) { if (g_Config.bTextureSecondaryCache) {
// Don't forget this one was unreliable (in case we match a secondary entry.) // Don't forget this one was unreliable (in case we match a secondary entry.)
entry->status |= TexCacheEntry::STATUS_UNRELIABLE; entry->status |= TexCacheEntry::STATUS_UNRELIABLE;
// If it's failed a bunch of times, then the second cache is just wasting time and VRAM.
// In that case, skip.
if (entry->numInvalidated > 2 && entry->numInvalidated < 128 && !lowMemoryMode_) { if (entry->numInvalidated > 2 && entry->numInvalidated < 128 && !lowMemoryMode_) {
// We have a new hash: look for that hash in the secondary cache.
u64 secondKey = fullhash | (u64)entry->cluthash << 32; u64 secondKey = fullhash | (u64)entry->cluthash << 32;
TexCache::iterator secondIter = secondCache_.find(secondKey); TexCache::iterator secondIter = secondCache_.find(secondKey);
if (secondIter != secondCache_.end()) { if (secondIter != secondCache_.end()) {
// Found it, but does it match our current params? If not, abort.
TexCacheEntry *secondEntry = secondIter->second.get(); TexCacheEntry *secondEntry = secondIter->second.get();
if (secondEntry->Matches(entry->dim, entry->format, entry->maxLevel)) { if (secondEntry->Matches(entry->dim, entry->format, entry->maxLevel)) {
// Reset the numInvalidated value lower, we got a match. // Reset the numInvalidated value lower, we got a match.
if (entry->numInvalidated > 8) { if (entry->numInvalidated > 8) {
--entry->numInvalidated; --entry->numInvalidated;
} }
// Now just use our archived texture, instead of entry.
nextTexture_ = secondEntry; nextTexture_ = secondEntry;
return true; return true;
} }
} else { } else {
// It wasn't found, so we're about to throw away entry and rebuild a texture.
// Let's save this in the secondary cache in case it gets used again.
secondKey = entry->fullhash | ((u64)entry->cluthash << 32); secondKey = entry->fullhash | ((u64)entry->cluthash << 32);
secondCacheSizeEstimate_ += EstimateTexMemoryUsage(entry); secondCacheSizeEstimate_ += EstimateTexMemoryUsage(entry);
// Is this wise? We simply copy the entry.
// If the entry already exists in the secondary texture cache, drop it nicely.
auto oldIter = secondCache_.find(secondKey);
if (oldIter != secondCache_.end()) {
ReleaseTexture(oldIter->second.get(), true);
}
// Archive the entire texture entry as is, since we'll use its params if it is seen again.
// We keep parameters on the current entry, since we are STILL building a new texture here.
secondCache_[secondKey].reset(new TexCacheEntry(*entry)); secondCache_[secondKey].reset(new TexCacheEntry(*entry));
// Make sure we don't delete the texture we just copied. // Make sure we don't delete the texture we just archived.
entry->texturePtr = nullptr; entry->texturePtr = nullptr;
doDelete = false; doDelete = false;
} }