From 6b079a4e12ea6e40680215190f88483548717e2b Mon Sep 17 00:00:00 2001 From: Brian Degenhardt Date: Wed, 22 Jul 2026 09:39:53 -0700 Subject: [PATCH] GS: add texture-cache hit/miss perfmon counters There were no texture-cache hit/miss counters at all. Hit/miss was visible only as GL_CACHE strings, which are compiled out unless ENABLE_OGL_DEBUG is set and are further gated on UseDebugDevice at emit time -- so on a shipped build the texture cache is completely opaque. For a tiler-bound title, source misses (upload + swizzle) are a prime suspect we could not see. Adds TCSourceHit/Miss, TCTargetHit/Miss and HashCacheHit/Miss, incremented at the existing hit/miss forks in LookupSource and the hash cache lookup. The new entries are appended after the ROV counters so the aliased slots (TextureCopies = Fillrate, TextureUploads = SyncPoint) keep their indices. Also fills in the three missing HW counter names. names_hw was declared [CounterLastHW] but had only 10 initialisers, leaving TextureCopiesROV, DrawCallsROV and BarriersROV as null pointers -- GSPerfMon::Dump iterates to CounterLastHW and passed them straight to fprintf %s. --- pcsx2/GS/GSPerfMon.h | 10 ++++++++++ pcsx2/GS/GSUtil.cpp | 11 ++++++++++- pcsx2/GS/Renderers/HW/GSTextureCache.cpp | 8 ++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/pcsx2/GS/GSPerfMon.h b/pcsx2/GS/GSPerfMon.h index d4defa8125..a0bb0595c9 100644 --- a/pcsx2/GS/GSPerfMon.h +++ b/pcsx2/GS/GSPerfMon.h @@ -26,6 +26,16 @@ public: TextureCopiesROV, // Overlaps with regular texture copies. DrawCallsROV, // Overlaps with regular draw calls. BarriersROV, // Overlaps with regular barriers. + + // Texture cache lookup outcomes (HW only). Appended last so the aliased + // slots below keep their existing indices. + TCTargetHit, + TCTargetMiss, + TCSourceHit, + TCSourceMiss, + HashCacheHit, + HashCacheMiss, + CounterLast, // Reused counters for HW. diff --git a/pcsx2/GS/GSUtil.cpp b/pcsx2/GS/GSUtil.cpp index d98a00d9b0..e050a53543 100644 --- a/pcsx2/GS/GSUtil.cpp +++ b/pcsx2/GS/GSUtil.cpp @@ -190,7 +190,16 @@ const char* GSUtil::GetPerfMonCounterName(GSPerfMon::counter_t counter, bool hw) "TextureCopies", "TextureUploads", "Barriers", - "RenderPasses" + "RenderPasses", + "TextureCopiesROV", + "DrawCallsROV", + "BarriersROV", + "TCTargetHit", + "TCTargetMiss", + "TCSourceHit", + "TCSourceMiss", + "HashCacheHit", + "HashCacheMiss" }; return counter < std::size(names_hw) ? names_hw[counter] : ""; } diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index 05b7472b3e..ca54b8e5a5 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -2150,6 +2150,10 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const if (!src) { + // A Source has to be built: upload + swizzle. This is the expensive outcome. + g_perfmon.Put(GSPerfMon::TCSourceMiss, 1); + g_perfmon.Put(dst ? GSPerfMon::TCTargetHit : GSPerfMon::TCTargetMiss, 1); + #ifdef ENABLE_OGL_DEBUG if (dst) { @@ -2225,6 +2229,8 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const } else { + g_perfmon.Put(GSPerfMon::TCSourceHit, 1); + GL_CACHE("TC: src hit: (0x%x, 0x%x, %s)", TEX0.TBP0, psm_s.pal > 0 ? TEX0.CBP : 0, GSUtil::GetPSMName(TEX0.PSM)); @@ -7036,6 +7042,7 @@ GSTextureCache::HashCacheEntry* GSTextureCache::LookupHashCache(const GIFRegTEX0 if (it != m_hash_cache.end()) { // super easy, cache hit. remove paltex if it's a replacement texture. + g_perfmon.Put(GSPerfMon::HashCacheHit, 1); GL_CACHE("TC: HC Hit: %" PRIx64 " %" PRIx64 " R-%ux%u", key.TEX0Hash, key.CLUTHash, key.region_width, key.region_height); HashCacheEntry* entry = &it->second; paltex &= (entry->texture->GetFormat() == GSTexture::Format::UNorm8); @@ -7044,6 +7051,7 @@ GSTextureCache::HashCacheEntry* GSTextureCache::LookupHashCache(const GIFRegTEX0 } // cache miss. + g_perfmon.Put(GSPerfMon::HashCacheMiss, 1); GL_CACHE("TC: HC Miss: %" PRIx64 " %" PRIx64 " R-%ux%u", key.TEX0Hash, key.CLUTHash, key.region_width, key.region_height); // check for a replacement texture with the full clut key