diff --git a/Core/Screenshot.h b/Core/Screenshot.h index 6514830d3a..b529fad494 100644 --- a/Core/Screenshot.h +++ b/Core/Screenshot.h @@ -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); diff --git a/GPU/Common/ShaderTranslation.cpp b/GPU/Common/ShaderTranslation.cpp index 675451fca6..5a0e9027ab 100644 --- a/GPU/Common/ShaderTranslation.cpp +++ b/GPU/Common/ShaderTranslation.cpp @@ -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 \ No newline at end of file +#endif diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 58ba41814d..49b4a03981 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -34,7 +34,7 @@ #include #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) { diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index 9cb2d04d0f..bcca4c19f5 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -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". };