GS/HW: Modify the conditions for updating GPU CLUT to be as optimal as possible

This commit is contained in:
refractionpcsx2
2026-01-18 17:45:58 +00:00
parent 835dd3e250
commit a61feb5548
7 changed files with 29 additions and 28 deletions

View File

@@ -9,6 +9,7 @@
#include "GS/Renderers/Common/GSDevice.h"
#include "GS/Renderers/Common/GSRenderer.h"
#include "common/AlignedMalloc.h"
#include "common/Console.h"
GSClut::GSClut(GSLocalMemory* mem)
: m_mem(mem)
@@ -409,7 +410,6 @@ void GSClut::Read32(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA)
}
}
m_current_gpu_clut = nullptr;
if (GSConfig.UserHacks_GPUTargetCLUTMode != GSGPUTargetCLUTMode::Disabled)
{
const bool is_4bit = (TEX0.PSM == PSMT4 || TEX0.PSM == PSMT4HL || TEX0.PSM == PSMT4HH);
@@ -440,27 +440,36 @@ void GSClut::Read32(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA)
GSTexture* dst = is_4bit ? m_gpu_clut4 : m_gpu_clut8;
const u32 dst_size = is_4bit ? 16 : 256;
const u32 dOffset = (TEX0.CSA & ((TEX0.CPSM == PSMCT16 || TEX0.CPSM == PSMCT16S) ? 15u : 31u)) << 4;
bool new_clut = false;
if (src != m_current_gpu_clut && (src != m_last_gpu_clut || m_gpu_clut_last_offset != offset))
m_gpu_clut_dirty = true;
if (!dst)
{
// allocate texture lazily
dst = g_gs_device->CreateRenderTarget(dst_size, 1, GSTexture::Format::Color, false);
is_4bit ? (m_gpu_clut4 = dst) : (m_gpu_clut8 = dst);
new_clut = true;
m_gpu_clut_dirty = true;
}
if (dst)
{
GL_PUSH("Update GPU CLUT [CBP=%04X, CPSM=%s, CBW=%u, CSA=%u, Offset=(%d,%d)]",
TEX0.CBP, GSUtil::GetPSMName(TEX0.CPSM), CBW, TEX0.CSA, offset.x, offset.y);
if (new_clut || g_gs_renderer->GetLastGPUCLUTDraw() == GSState::s_n)
if (m_gpu_clut_dirty)
{
m_last_gpu_clut = src;
g_gs_device->UpdateCLUTTexture(src, scale, offset.x, offset.y, dst, dOffset, dst_size);
}
m_gpu_clut_dirty = false;
m_current_gpu_clut = dst;
m_gpu_clut_last_offset = offset;
}
return;
}
}
m_current_gpu_clut = nullptr;
}
}

View File

@@ -49,6 +49,10 @@ class alignas(32) GSClut final : public GSAlignedClass<32>
GSTexture* m_gpu_clut4 = nullptr;
GSTexture* m_gpu_clut8 = nullptr;
GSTexture* m_current_gpu_clut = nullptr;
GSTexture* m_last_gpu_clut = nullptr;
GSVector2i m_gpu_clut_last_offset = 0;
u64 m_gpu_clut_draw = 0;
bool m_gpu_clut_dirty = true;
typedef void (GSClut::*writeCLUT)(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
@@ -97,7 +101,14 @@ public:
~GSClut();
__fi GSTexture* GetGPUTexture() const { return m_current_gpu_clut; }
__fi void SetGPUTextureDirty(u64 draw, GSTexture* texture)
{
if (texture == m_last_gpu_clut && draw > m_gpu_clut_draw)
{
m_gpu_clut_draw = draw;
m_gpu_clut_dirty = true;
}
}
void Reset();
bool InvalidateRange(u32 start_block, u32 end_block, bool is_draw = false);
u8 IsInvalid();

View File

@@ -51,7 +51,6 @@ public:
virtual float GetTextureScaleFactor() { return 1.0f; }
GSVector2i GetInternalResolution();
float GetModXYOffset();
virtual u64 GetLastGPUCLUTDraw() { return GSState::s_n; }
virtual GSTexture* LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVector2i& offset, float* scale, const GSVector2i& size);

View File

@@ -59,11 +59,6 @@ void GSRendererHW::ReadbackTextureCache()
g_texture_cache->ReadbackAll();
}
u64 GSRendererHW::GetLastGPUCLUTDraw()
{
return g_texture_cache->GetLastGPUCLUTDraw();
}
GSTexture* GSRendererHW::LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVector2i& offset, float* scale, const GSVector2i& size)
{
return g_texture_cache->LookupPaletteSource(CBP, CPSM, CBW, offset, scale, size);
@@ -4884,6 +4879,9 @@ void GSRendererHW::Draw()
if ((fm & fm_mask) != fm_mask && !no_rt)
{
if (m_mem.m_clut.GetGPUTexture() && m_mem.m_clut.GetGPUTexture() == rt->m_texture)
m_mem.m_clut.SetGPUTextureDirty(rt->m_last_draw, rt->m_texture);
g_texture_cache->InvalidateVideoMem(context->offset.fb, real_rect, false);
// Remove overwritten Zs at the FBP.

View File

@@ -242,7 +242,6 @@ public:
void PurgeTextureCache(bool sources, bool targets, bool hash_cache) override;
void ReadbackTextureCache() override;
u64 GetLastGPUCLUTDraw() override;
GSTexture* LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVector2i& offset, float* scale, const GSVector2i& size) override;

View File

@@ -7064,18 +7064,7 @@ GSTexture* GSTextureCache::LookupPaletteSource(u32 CBP, u32 CPSM, u32 CBW, GSVec
continue;
}
if (m_last_clut_target != nullptr && m_last_clut_target == t)
{
if (t->m_last_draw > m_last_gpu_clut_draw)
{
m_last_gpu_clut_draw = GSState::s_n;
}
}
else
{
m_last_clut_target = t;
m_last_gpu_clut_draw = GSState::s_n;
}
GSRendererHW::GetInstance()->m_mem.m_clut.SetGPUTextureDirty(t->m_last_draw, t->m_texture);
offset = this_offset;
*scale = t->m_scale;

View File

@@ -441,9 +441,6 @@ protected:
GSTexture* m_temporary_z = nullptr; // invalidated after the draw
TempZAddress m_temporary_z_info;
Target* m_last_clut_target = nullptr;
u64 m_last_gpu_clut_draw = 0;
std::unique_ptr<GSDownloadTexture> m_color_download_texture;
std::unique_ptr<GSDownloadTexture> m_uint16_download_texture;
std::unique_ptr<GSDownloadTexture> m_uint32_download_texture;
@@ -484,7 +481,6 @@ public:
__fi u64 GetTotalHashCacheMemoryUsage() const { return (m_hash_cache_memory_usage + m_hash_cache_replacement_memory_usage); }
__fi u64 GetSourceMemoryUsage() const { return m_source_memory_usage; }
__fi u64 GetTargetMemoryUsage() const { return m_target_memory_usage; }
__fi u64 GetLastGPUCLUTDraw() { return m_last_gpu_clut_draw; };
void Read(Target* t, const GSVector4i& r);
void Read(Source* t, const GSVector4i& r);