mirror of
https://github.com/libretro/ppsspp.git
synced 2024-12-02 22:26:25 +00:00
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:
commit
60b8ffa3a0
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user