Merge pull request #9447 from unknownbrackets/texcache

Always mark videos as frequently changing
This commit is contained in:
Henrik Rydgård 2017-03-18 20:27:58 +01:00 committed by GitHub
commit de72005b77
4 changed files with 54 additions and 46 deletions

View File

@ -28,13 +28,12 @@ enum ScreenshotType {
// What's being show on screen (e.g. including FPS, etc.)
SCREENSHOT_OUTPUT,
// What the game rendered (e.g. at render resolution) to the display.
// Can only be used while in game.
SCREENSHOT_DISPLAY,
// What the game is in-progress rendering now.
// Can only be used while in game.
SCREENSHOT_RENDER,
};
const u8 *ConvertBufferTo888RGB(const GPUDebugBuffer &buf, u8 *&temp, u32 &w, u32 &h);
// Can only be used while in game.
bool TakeGameScreenshot(const char *filename, ScreenshotFormat fmt, ScreenshotType type, int *width = nullptr, int *height = nullptr, int maxRes = -1);

View File

@ -210,7 +210,7 @@ bool TranslateShader(std::string *dest, ShaderLanguage destLang, TranslatedShade
// Can't fail, parsing worked, "linking" worked.
glslang::GlslangToSpv(*program.getIntermediate(shaderStage), spirv);
// Alright, step 1 done. Now let's takes this SPIR-V shader and output in our desired format.
// Alright, step 1 done. Now let's take this SPIR-V shader and output in our desired format.
switch (destLang) {
case GLSL_VULKAN:
@ -276,4 +276,4 @@ bool TranslateShader(std::string *dest, ShaderLanguage destLang, TranslatedShade
}
}
#endif
#endif

View File

@ -34,7 +34,7 @@
#include <emmintrin.h>
#endif
// Videos should be updated every few frames, so we forge quickly.
// Videos should be updated every few frames, so we forget quickly.
#define VIDEO_DECIMATE_AGE 4
// If a texture hasn't been seen for this many frames, get rid of it.
@ -349,11 +349,12 @@ void TextureCacheCommon::SetTexture(bool force) {
nextTexture_ = entry;
nextNeedsRehash_ = rehash;
nextNeedsChange_ = false;
// Might need a rebuild if the hash fails.
// Might need a rebuild if the hash fails, but that will be set later.
nextNeedsRebuild_ = false;
VERBOSE_LOG(G3D, "Texture at %08x Found in Cache, applying", texaddr);
return; //Done!
} else {
// Wasn't a match, we will rebuild.
nextChangeReason_ = reason;
nextNeedsChange_ = true;
}
@ -502,6 +503,16 @@ bool TextureCacheCommon::HandleTextureChange(TexCacheEntry *const entry, const c
}
}
entry->status |= TexCacheEntry::STATUS_UNRELIABLE;
if (entry->numFrames < TEXCACHE_FRAME_CHANGE_FREQUENT) {
if (entry->status & TexCacheEntry::STATUS_FREE_CHANGE) {
entry->status &= ~TexCacheEntry::STATUS_FREE_CHANGE;
} else {
entry->status |= TexCacheEntry::STATUS_CHANGE_FREQUENT;
}
}
entry->numFrames = 0;
return replaceImages;
}
@ -1356,7 +1367,6 @@ void TextureCacheCommon::ReadIndexedTex(u8 *out, int outPitch, int level, const
}
}
void TextureCacheCommon::ApplyTexture() {
TexCacheEntry *entry = nextTexture_;
if (entry == nullptr) {
@ -1368,6 +1378,13 @@ void TextureCacheCommon::ApplyTexture() {
bool replaceImages = false;
if (nextNeedsRebuild_) {
// Regardless of hash fails or otherwise, if this is a video, mark it frequently changing.
// This prevents temporary scaling perf hits on the first second of video.
bool isVideo = videos_.find(entry->addr & 0x3FFFFFFF) != videos_.end();
if (isVideo) {
entry->status |= TexCacheEntry::STATUS_CHANGE_FREQUENT;
}
if (nextNeedsRehash_) {
// Update the hash on the texture.
int w = gstate.getTextureWidth(0);
@ -1438,13 +1455,11 @@ void TextureCacheCommon::DeleteTexture(TexCache::iterator it) {
}
bool TextureCacheCommon::CheckFullHash(TexCacheEntry *entry, bool &doDelete) {
bool hashFail = false;
int w = gstate.getTextureWidth(0);
int h = gstate.getTextureHeight(0);
u32 fullhash = QuickTexHash(replacer_, entry->addr, entry->bufw, w, h, GETextureFormat(entry->format), entry);
if (fullhash != entry->fullhash) {
hashFail = true;
} else {
if (fullhash == entry->fullhash) {
if (g_Config.bTextureBackoffCache) {
if (entry->GetHashStatus() != TexCacheEntry::STATUS_HASHING && entry->numFrames > TexCacheEntry::FRAMES_REGAIN_TRUST) {
// Reset to STATUS_HASHING.
@ -1454,51 +1469,42 @@ bool TextureCacheCommon::CheckFullHash(TexCacheEntry *entry, bool &doDelete) {
} else if (entry->numFrames > TEXCACHE_FRAME_CHANGE_FREQUENT_REGAIN_TRUST) {
entry->status &= ~TexCacheEntry::STATUS_CHANGE_FREQUENT;
}
return true;
}
if (hashFail) {
// 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) {
// Don't forget this one was unreliable (in case we match a secondary entry.)
entry->status |= TexCacheEntry::STATUS_UNRELIABLE;
if (entry->numFrames < TEXCACHE_FRAME_CHANGE_FREQUENT) {
if (entry->status & TexCacheEntry::STATUS_FREE_CHANGE) {
entry->status &= ~TexCacheEntry::STATUS_FREE_CHANGE;
} else {
entry->status |= TexCacheEntry::STATUS_CHANGE_FREQUENT;
}
}
entry->numFrames = 0;
// 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 (entry->numInvalidated > 2 && entry->numInvalidated < 128 && !lowMemoryMode_) {
u64 secondKey = fullhash | (u64)entry->cluthash << 32;
TexCache::iterator secondIter = secondCache_.find(secondKey);
if (secondIter != secondCache_.end()) {
TexCacheEntry *secondEntry = secondIter->second.get();
if (secondEntry->Matches(entry->dim, entry->format, entry->maxLevel)) {
// Reset the numInvalidated value lower, we got a match.
if (entry->numInvalidated > 8) {
--entry->numInvalidated;
}
nextTexture_ = secondEntry;
return true;
if (entry->numInvalidated > 2 && entry->numInvalidated < 128 && !lowMemoryMode_) {
u64 secondKey = fullhash | (u64)entry->cluthash << 32;
TexCache::iterator secondIter = secondCache_.find(secondKey);
if (secondIter != secondCache_.end()) {
TexCacheEntry *secondEntry = secondIter->second.get();
if (secondEntry->Matches(entry->dim, entry->format, entry->maxLevel)) {
// Reset the numInvalidated value lower, we got a match.
if (entry->numInvalidated > 8) {
--entry->numInvalidated;
}
} else {
secondKey = entry->fullhash | ((u64)entry->cluthash << 32);
secondCacheSizeEstimate_ += EstimateTexMemoryUsage(entry);
// Is this wise? We simply copy the entry.
secondCache_[secondKey].reset(new TexCacheEntry(*entry));
doDelete = false;
nextTexture_ = secondEntry;
return true;
}
} else {
secondKey = entry->fullhash | ((u64)entry->cluthash << 32);
secondCacheSizeEstimate_ += EstimateTexMemoryUsage(entry);
// Is this wise? We simply copy the entry.
secondCache_[secondKey].reset(new TexCacheEntry(*entry));
doDelete = false;
}
}
// We know it failed, so update the full hash right away.
entry->fullhash = fullhash;
return false;
}
return true;
// We know it failed, so update the full hash right away.
entry->fullhash = fullhash;
return false;
}
void TextureCacheCommon::Invalidate(u32 addr, int size, GPUInvalidationType type) {

View File

@ -104,6 +104,9 @@ struct TexCacheEntry {
STATUS_DEPALETTIZE = 0x40, // Needs to go through a depalettize pass.
STATUS_TO_SCALE = 0x80, // Pending texture scaling in a later frame.
STATUS_IS_SCALED = 0x100, // Has been scaled (can't be replaceImages'd.)
// When hashing large textures, we optimize 512x512 down to 512x272 by default, since this
// is commonly the only part accessed. If access is made above 272, we hash the entire
// texture, and set this flag to allow scaling the texture just once for the new hash.
STATUS_FREE_CHANGE = 0x200, // Allow one change before marking "frequent".
};