From fdcf923c75da1be426196c0527582ce23c8855dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 9 Jun 2026 10:34:28 +0200 Subject: [PATCH] TexCache: Stop bitpacking the hash status into the status flags --- GPU/Common/TextureCacheCommon.cpp | 61 +++++++++++++++---------------- GPU/Common/TextureCacheCommon.h | 19 ++++------ UI/ImDebugger/ImGe.cpp | 1 + 3 files changed, 39 insertions(+), 42 deletions(-) diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 5125f7611d..adc1c54ef5 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -498,7 +498,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { match = false; } - bool rehash = entry->GetHashStatus() == TexCacheEntry::STATUS_UNRELIABLE; + bool rehash = entry->hashStatus == TexHashStatus::Unreliable; // First let's see if another texture with the same address had a hashfail. if (entry->status & TexCacheEntry::STATUS_CLUT_RECHECK) { @@ -545,7 +545,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { if (minihash != entry->minihash) { match = false; reason = "minihash"; - } else if (entry->GetHashStatus() == TexCacheEntry::STATUS_RELIABLE) { + } else if (entry->hashStatus == TexHashStatus::Reliable) { rehash = false; } } @@ -651,14 +651,14 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { VERBOSE_LOG(Log::G3D, "No texture in cache for %08x, decoding...", texaddr); entry = new TexCacheEntry{}; cache_[cachekey].reset(entry); - + entry->status = {}; if (PPGeIsFontTextureAddress(texaddr)) { // It's the builtin font texture. - entry->status = TexCacheEntry::STATUS_RELIABLE; + entry->hashStatus = TexHashStatus::Reliable; } else if (g_Config.bTextureBackoffCache && !IsVideo(texaddr)) { - entry->status = TexCacheEntry::STATUS_HASHING; + entry->hashStatus = TexHashStatus::Hashing; } else { - entry->status = TexCacheEntry::STATUS_UNRELIABLE; + entry->hashStatus = TexHashStatus::Unreliable; } if (hasClutGPU) { @@ -908,8 +908,8 @@ void TextureCacheCommon::HandleTextureChange(TexCacheEntry *const entry, const c } // Mark as hashing, if marked as reliable. - if (entry->GetHashStatus() == TexCacheEntry::STATUS_RELIABLE) { - entry->SetHashStatus(TexCacheEntry::STATUS_HASHING); + if (entry->hashStatus == TexHashStatus::Reliable) { + entry->hashStatus = TexHashStatus::Hashing; } // Also, mark any textures with the same address but different clut. They need rechecking. @@ -2605,9 +2605,9 @@ bool TextureCacheCommon::CheckFullHash(TexCacheEntry *entry, bool &doDelete) { if (fullhash == entry->fullhash) { if (g_Config.bTextureBackoffCache && !isVideo) { - if (entry->GetHashStatus() != TexCacheEntry::STATUS_HASHING && entry->numFrames > TexCacheEntry::FRAMES_REGAIN_TRUST) { + if (entry->hashStatus != TexHashStatus::Hashing && entry->numFrames > TexCacheEntry::FRAMES_REGAIN_TRUST) { // Reset to STATUS_HASHING. - entry->SetHashStatus(TexCacheEntry::STATUS_HASHING); + entry->hashStatus = TexHashStatus::Hashing; entry->status &= ~TexCacheEntry::STATUS_CHANGE_FREQUENT; } } else if (entry->numFrames > TEXCACHE_FRAME_CHANGE_FREQUENT_REGAIN_TRUST) { @@ -2620,7 +2620,7 @@ 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. if (PSP_CoreParameter().compat.flags().SecondaryTextureCache) { // Don't forget this one was unreliable (in case we match a secondary entry.) - entry->status |= TexCacheEntry::STATUS_UNRELIABLE; + entry->hashStatus = TexHashStatus::Unreliable; // If it's failed a bunch of times, then the second cache is just wasting time and VRAM. // In that case, skip. @@ -2710,8 +2710,8 @@ void TextureCacheCommon::Invalidate(u32 addr, int size, GPUInvalidationType type // Quick check for overlap. Yes the check is right. if (addr < texEnd && addr_end > texAddr) { - if (entry->GetHashStatus() == TexCacheEntry::STATUS_RELIABLE) { - entry->SetHashStatus(TexCacheEntry::STATUS_HASHING); + if (entry->hashStatus == TexHashStatus::Reliable) { + entry->hashStatus = TexHashStatus::Hashing; } if (type == GPU_INVALIDATE_FORCE) { // Just random values to force the hash not to match. @@ -2748,11 +2748,11 @@ void TextureCacheCommon::InvalidateAll(GPUInvalidationType /*unused*/) { } timesInvalidatedAllThisFrame_++; - for (TexCache::iterator iter = cache_.begin(), end = cache_.end(); iter != end; ++iter) { - if (iter->second->GetHashStatus() == TexCacheEntry::STATUS_RELIABLE) { - iter->second->SetHashStatus(TexCacheEntry::STATUS_HASHING); + for (auto &[key, e] : cache_) { + if (e->hashStatus == TexHashStatus::Reliable) { + e->hashStatus = TexHashStatus::Hashing; } - iter->second->invalidHint++; + e->invalidHint++; } } @@ -3096,19 +3096,21 @@ CheckAlphaResult TextureCacheCommon::CheckCLUTAlpha(const uint8_t *pixelData, GE } } +const char *TexHashStatusToString(TexHashStatus status) { + switch (status) { + case TexHashStatus::Hashing: + return "Hashing"; + case TexHashStatus::Reliable: + return "Reliable"; + case TexHashStatus::Unreliable: + return "Unreliable"; + default: + return "Unknown"; + } +} + std::string TexStatusToString(TexCacheEntry::TexStatus status) { std::string result; - switch (status & TexCacheEntry::STATUS_MASK) { - case TexCacheEntry::STATUS_HASHING: - result += "HASHING "; - break; - case TexCacheEntry::STATUS_RELIABLE: - result += "RELIABLE "; - break; - case TexCacheEntry::STATUS_UNRELIABLE: - result += "UNRELIABLE "; - break; - } if (status & TexCacheEntry::STATUS_ALPHA_MASK) { result += "ALPHA"; } @@ -3121,9 +3123,6 @@ std::string TexStatusToString(TexCacheEntry::TexStatus status) { if (status & TexCacheEntry::STATUS_CHANGE_FREQUENT) { result += "FREQ "; } - if (status & TexCacheEntry::STATUS_UNRELIABLE) { - result += "UNREL "; - } if (status & TexCacheEntry::STATUS_TO_SCALE) { result += "TOSCALE "; } diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index 8a1d770db1..aee6950b29 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -130,6 +130,11 @@ struct TextureDefinition { // At one point we might merge the concepts of framebuffers and textures, but that // moment is far away. +enum class TexHashStatus : u8 { + Hashing = 0, + Reliable, // Don't bother rehashing. + Unreliable, // Always recheck hash. +}; // TODO: Shrink this struct. There is some fluff. struct TexCacheEntry { @@ -141,11 +146,6 @@ struct TexCacheEntry { const static int FRAMES_REGAIN_TRUST = 1000; enum TexStatus { - STATUS_HASHING = 0x00, - STATUS_RELIABLE = 0x01, // Don't bother rehashing. - STATUS_UNRELIABLE = 0x02, // Always recheck hash. - STATUS_MASK = 0x03, - STATUS_ALPHA_UNKNOWN = 0x04, STATUS_ALPHA_FULL = 0x00, // Has no alpha channel, or always full alpha. STATUS_ALPHA_MASK = 0x04, @@ -184,6 +184,8 @@ struct TexCacheEntry { u8 maxLevel; u16 dim; u16 bufw; + TexHashStatus hashStatus; + union { GLRTexture *textureName; void *texturePtr; @@ -202,12 +204,6 @@ struct TexCacheEntry { u16 maxSeenV; ReplacedTexture *replacedTexture; - TexStatus GetHashStatus() { - return TexStatus(status & STATUS_MASK); - } - void SetHashStatus(TexStatus newStatus) { - status = (status & ~STATUS_MASK) | newStatus; - } TexStatus GetAlphaStatus() { return TexStatus(status & STATUS_ALPHA_MASK); } @@ -239,6 +235,7 @@ struct TexCacheEntry { u32 EstimateTexMemoryUsage() const; }; +const char *TexHashStatusToString(TexHashStatus status); std::string TexStatusToString(TexCacheEntry::TexStatus status); // Can't be unordered_map, we use lower_bound ... although for some reason that (used to?) compiles on MSVC. diff --git a/UI/ImDebugger/ImGe.cpp b/UI/ImDebugger/ImGe.cpp index aac694102a..b551cd8f8d 100644 --- a/UI/ImDebugger/ImGe.cpp +++ b/UI/ImDebugger/ImGe.cpp @@ -177,6 +177,7 @@ void DrawTexturesWindow(ImConfig &cfg, TextureCacheCommon *textureCache) { ImGui::Image(texId, ImVec2(w, h)); ImGui::Text("%08x: %dx%d, %d mips, %s", (uint32_t)(cfg.selectedTexAddr & 0xFFFFFFFF), w, h, entry->maxLevel + 1, GeTextureFormatToString((GETextureFormat)entry->format)); ImGui::Text("Stride: %d", entry->bufw); + ImGui::Text("Hash status: %s", TexHashStatusToString(entry->hashStatus)); ImGui::Text("Status: %08x: %s", entry->status, TexStatusToString((TexCacheEntry::TexStatus)(entry->status)).c_str()); ImGui::Text("Hash: %08x", entry->fullhash); ImGui::Text("CLUT Hash: %08x", entry->cluthash);