From 00c85c4a8fce31ee48d3685ea286d0e4b71e2ee4 Mon Sep 17 00:00:00 2001 From: TJnotJT Date: Sat, 18 Apr 2026 08:49:18 -0400 Subject: [PATCH] GS/TC: Use temporary source on invalid TEX0. --- pcsx2/GS/GSUtil.cpp | 24 ++++++++++++++++++++++++ pcsx2/GS/GSUtil.h | 2 ++ pcsx2/GS/Renderers/HW/GSTextureCache.cpp | 8 ++++++++ 3 files changed, 34 insertions(+) diff --git a/pcsx2/GS/GSUtil.cpp b/pcsx2/GS/GSUtil.cpp index 85be5b0836..ef080e6283 100644 --- a/pcsx2/GS/GSUtil.cpp +++ b/pcsx2/GS/GSUtil.cpp @@ -339,3 +339,27 @@ const char* GSUtil::GetPSMName(int psm) } return "BAD_PSM"; } + +bool GSUtil::IsValidPSM(int psm) +{ + switch (psm) + { + case PSMCT32: + case PSMCT24: + case PSMCT16: + case PSMCT16S: + case PSMT8: + case PSMT4: + case PSMT8H: + case PSMT4HL: + case PSMT4HH: + case PSMZ32: + case PSMZ24: + case PSMZ16: + case PSMZ16S: + case PSGPU24: + return true; + default: + return false; + } +} \ No newline at end of file diff --git a/pcsx2/GS/GSUtil.h b/pcsx2/GS/GSUtil.h index 90a5ad3048..de600bd9ca 100644 --- a/pcsx2/GS/GSUtil.h +++ b/pcsx2/GS/GSUtil.h @@ -28,6 +28,8 @@ public: static const char* GetACName(u32 ac); static const char* GetPerfMonCounterName(GSPerfMon::counter_t counter, bool hw = true); + static bool IsValidPSM(int psm); + static const u32* HasSharedBitsPtr(u32 dpsm); static bool HasSharedBits(u32 spsm, const u32* ptr); static bool HasSharedBits(u32 spsm, u32 dpsm); diff --git a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp index 0e54849e7b..e065c033db 100644 --- a/pcsx2/GS/Renderers/HW/GSTextureCache.cpp +++ b/pcsx2/GS/Renderers/HW/GSTextureCache.cpp @@ -1340,6 +1340,14 @@ GSTextureCache::Source* GSTextureCache::LookupSource(const bool is_color, const return nullptr; } + // Invalid values show up in dumps but it's unclear if it's a core issue or a bug in the games. + // Return a temporary source to prevent the lookup from corrupting the TC. + if (TEX0.TBW > 32 && !GSUtil::IsValidPSM(static_cast(TEX0.PSM))) + { + GL_CACHE("TC: Invalid TEX0 (TBW=%d, PSM=%x), using temporary source.", TEX0.TBW, TEX0.PSM); + return CreateSource(TEX0, TEXA, CLAMP, nullptr, 0, 0, nullptr, nullptr, nullptr, SourceRegion(), true); + } + const GSVector2i compare_lod(lod ? *lod : GSVector2i(0, 0)); Source* src = nullptr;