From f034cb45bb7e21151eb034c696aec8c294454e91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 11 Jun 2026 10:40:21 +0200 Subject: [PATCH] Unify UpdateCurrentClut between D3D11 and Vulkan (GLES is still different) --- GPU/Common/TextureCacheCommon.cpp | 38 +++++++++++++++++++++++++++++++ GPU/Common/TextureCacheCommon.h | 2 +- GPU/D3D11/TextureCacheD3D11.cpp | 36 ----------------------------- GPU/D3D11/TextureCacheD3D11.h | 1 - GPU/GLES/TextureCacheGLES.cpp | 1 + GPU/Vulkan/TextureCacheVulkan.cpp | 38 ------------------------------- GPU/Vulkan/TextureCacheVulkan.h | 1 - 7 files changed, 40 insertions(+), 77 deletions(-) diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 9d145d9495..5503436d2c 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -19,6 +19,7 @@ #include +#include "ext/xxhash.h" #include "Common/Common.h" #include "Common/Data/Convert/ColorConv.h" #include "Common/Data/Collections/TinySet.h" @@ -369,6 +370,43 @@ SamplerCacheKey TextureCacheCommon::GetFramebufferSamplingParams(u16 bufferWidth return key; } +// NOTE: this is overridden in TextureCacheGLES, with some extra color conversion. +void TextureCacheCommon::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) { + const u32 clutBaseBytes = clutFormat == GE_CMODE_32BIT_ABGR8888 ? (clutBase * sizeof(u32)) : (clutBase * sizeof(u16)); + // Technically, these extra bytes weren't loaded, but hopefully it was loaded earlier. + // If not, we're going to hash random data, which hopefully doesn't cause a performance issue. + // + // TODO: Actually, this seems like a hack. The game can upload part of a CLUT and reference other data. + // clutTotalBytes_ is the last amount uploaded. We should hash clutMaxBytes_, but this will often hash + // unrelated old entries for small palettes. + // Adding clutBaseBytes may just be mitigating this for some usage patterns. + const u32 clutExtendedBytes = std::min(clutTotalBytes_ + clutBaseBytes, clutMaxBytes_); + + if (replacer_.Enabled()) + clutHash_ = XXH32((const char *)clutBufRaw_, clutExtendedBytes, 0xC0108888); + else + clutHash_ = XXH3_64bits((const char *)clutBufRaw_, clutExtendedBytes) & 0xFFFFFFFF; + clutBuf_ = clutBufRaw_; + + // Special optimization: fonts typically draw clut4 with just alpha values in a single color. + clutAlphaLinear_ = false; + clutAlphaLinearColor_ = 0; + if (clutFormat == GE_CMODE_16BIT_ABGR4444 && clutIndexIsSimple) { + const u16_le *clut = GetCurrentClut(); + clutAlphaLinear_ = true; + clutAlphaLinearColor_ = clut[15] & 0x0FFF; + for (int i = 0; i < 16; ++i) { + u16 step = clutAlphaLinearColor_ | (i << 12); + if (clut[i] != step) { + clutAlphaLinear_ = false; + break; + } + } + } + + clutLastFormat_ = gstate.clutformat; +} + // TODO: This should be called from the through mode bbox check. void TextureCacheCommon::UpdateMaxSeenV(TexCacheEntry *entry, bool throughMode) { // If the texture is >= 512 pixels tall... diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index 20ce55dea9..1e85aa8309 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -400,7 +400,7 @@ protected: void HandleTextureChange(TexCacheEntry *const entry, const char *reason, bool initialMatch, bool doDelete); virtual void BuildTexture(TexCacheEntry *const entry) = 0; - virtual void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) = 0; + virtual void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple); // only overridden in GLES bool CheckFullHash(TexCacheEntry *entry, bool &doDelete); virtual void BindAsClutTexture(Draw::Texture *tex, bool smooth) {} diff --git a/GPU/D3D11/TextureCacheD3D11.cpp b/GPU/D3D11/TextureCacheD3D11.cpp index b9bca156bb..d2825d8428 100644 --- a/GPU/D3D11/TextureCacheD3D11.cpp +++ b/GPU/D3D11/TextureCacheD3D11.cpp @@ -209,42 +209,6 @@ void TextureCacheD3D11::ForgetLastTexture() { context_->PSSetShaderResources(0, 4, nullTex); } -void TextureCacheD3D11::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) { - const u32 clutBaseBytes = clutBase * (clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16)); - // Technically, these extra bytes weren't loaded, but hopefully it was loaded earlier. - // If not, we're going to hash random data, which hopefully doesn't cause a performance issue. - // - // TODO: Actually, this seems like a hack. The game can upload part of a CLUT and reference other data. - // clutTotalBytes_ is the last amount uploaded. We should hash clutMaxBytes_, but this will often hash - // unrelated old entries for small palettes. - // Adding clutBaseBytes may just be mitigating this for some usage patterns. - const u32 clutExtendedBytes = std::min(clutTotalBytes_ + clutBaseBytes, clutMaxBytes_); - - if (replacer_.Enabled()) - clutHash_ = XXH32((const char *)clutBufRaw_, clutExtendedBytes, 0xC0108888); - else - clutHash_ = XXH3_64bits((const char *)clutBufRaw_, clutExtendedBytes) & 0xFFFFFFFF; - clutBuf_ = clutBufRaw_; - - // Special optimization: fonts typically draw clut4 with just alpha values in a single color. - clutAlphaLinear_ = false; - clutAlphaLinearColor_ = 0; - if (clutFormat == GE_CMODE_16BIT_ABGR4444 && clutIndexIsSimple) { - const u16_le *clut = GetCurrentClut(); - clutAlphaLinear_ = true; - clutAlphaLinearColor_ = clut[15] & 0x0FFF; - for (int i = 0; i < 16; ++i) { - u16 step = clutAlphaLinearColor_ | (i << 12); - if (clut[i] != step) { - clutAlphaLinear_ = false; - break; - } - } - } - - clutLastFormat_ = gstate.clutformat; -} - void TextureCacheD3D11::BindTexture(TexCacheEntry *entry, bool flatZ) { if (!entry) { ID3D11ShaderResourceView *textureView = nullptr; diff --git a/GPU/D3D11/TextureCacheD3D11.h b/GPU/D3D11/TextureCacheD3D11.h index c56a390f27..58c0962227 100644 --- a/GPU/D3D11/TextureCacheD3D11.h +++ b/GPU/D3D11/TextureCacheD3D11.h @@ -73,7 +73,6 @@ protected: private: DXGI_FORMAT GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) const; - void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) override; void BuildTexture(TexCacheEntry *const entry) override; diff --git a/GPU/GLES/TextureCacheGLES.cpp b/GPU/GLES/TextureCacheGLES.cpp index 5184004b0b..b7634b09b5 100644 --- a/GPU/GLES/TextureCacheGLES.cpp +++ b/GPU/GLES/TextureCacheGLES.cpp @@ -147,6 +147,7 @@ void TextureCacheGLES::StartFrame() { } } +// TODO: This is almost the same as the Common one, just with some extra color conversion. Should merge. void TextureCacheGLES::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) { const u32 clutBaseBytes = clutFormat == GE_CMODE_32BIT_ABGR8888 ? (clutBase * sizeof(u32)) : (clutBase * sizeof(u16)); // Technically, these extra bytes weren't loaded, but hopefully it was loaded earlier. diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 8c1ad6766b..99f2ab2092 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -19,8 +19,6 @@ #include #include -#include "ext/xxhash.h" - #include "Common/File/VFS/VFS.h" #include "Common/Data/Text/I18n.h" #include "Common/LogReporting.h" @@ -582,42 +580,6 @@ void TextureCacheVulkan::StartFrame() { computeShaderManager_.BeginFrame(); } -void TextureCacheVulkan::UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) { - const u32 clutBaseBytes = clutFormat == GE_CMODE_32BIT_ABGR8888 ? (clutBase * sizeof(u32)) : (clutBase * sizeof(u16)); - // Technically, these extra bytes weren't loaded, but hopefully it was loaded earlier. - // If not, we're going to hash random data, which hopefully doesn't cause a performance issue. - // - // TODO: Actually, this seems like a hack. The game can upload part of a CLUT and reference other data. - // clutTotalBytes_ is the last amount uploaded. We should hash clutMaxBytes_, but this will often hash - // unrelated old entries for small palettes. - // Adding clutBaseBytes may just be mitigating this for some usage patterns. - const u32 clutExtendedBytes = std::min(clutTotalBytes_ + clutBaseBytes, clutMaxBytes_); - - if (replacer_.Enabled()) - clutHash_ = XXH32((const char *)clutBufRaw_, clutExtendedBytes, 0xC0108888); - else - clutHash_ = XXH3_64bits((const char *)clutBufRaw_, clutExtendedBytes) & 0xFFFFFFFF; - clutBuf_ = clutBufRaw_; - - // Special optimization: fonts typically draw clut4 with just alpha values in a single color. - clutAlphaLinear_ = false; - clutAlphaLinearColor_ = 0; - if (clutFormat == GE_CMODE_16BIT_ABGR4444 && clutIndexIsSimple) { - const u16_le *clut = GetCurrentClut(); - clutAlphaLinear_ = true; - clutAlphaLinearColor_ = clut[15] & 0x0FFF; - for (int i = 0; i < 16; ++i) { - u16 step = clutAlphaLinearColor_ | (i << 12); - if (clut[i] != step) { - clutAlphaLinear_ = false; - break; - } - } - } - - clutLastFormat_ = gstate.clutformat; -} - void TextureCacheVulkan::BindTexture(TexCacheEntry *entry, bool flatZ) { if (!entry || !entry->vkTex) { Unbind(); diff --git a/GPU/Vulkan/TextureCacheVulkan.h b/GPU/Vulkan/TextureCacheVulkan.h index 031894368e..1ded35f009 100644 --- a/GPU/Vulkan/TextureCacheVulkan.h +++ b/GPU/Vulkan/TextureCacheVulkan.h @@ -118,7 +118,6 @@ private: void LoadVulkanTextureLevel(TexCacheEntry &entry, uint8_t *writePtr, int rowPitch, int level, int scaleFactor, VkFormat dstFmt); static VkFormat GetDestFormat(GETextureFormat format, GEPaletteFormat clutFormat) ; - void UpdateCurrentClut(GEPaletteFormat clutFormat, u32 clutBase, bool clutIndexIsSimple) override; void BuildTexture(TexCacheEntry *const entry) override;