GS: Improve state load determinism

CLUT wasn't force reloaded, so if the game didn't write to TEX0 before
its first draw after loading a state, you got either the CLUT before the
state was loaded, or random/uninitialized garbage.

Do the same for reset as well, except zero it out in that case.
This commit is contained in:
Stenzek 2024-03-28 00:59:58 +10:00 committed by Connor McLaughlin
parent a317e9c038
commit 2eab0f9757
3 changed files with 28 additions and 12 deletions

View File

@ -13,8 +13,6 @@
GSClut::GSClut(GSLocalMemory* mem) GSClut::GSClut(GSLocalMemory* mem)
: m_mem(mem) : m_mem(mem)
{ {
static constexpr u32 CLUT_ALLOC_SIZE = 4096 * 2;
// 1k + 1k for mirrored area simulating wrapping memory // 1k + 1k for mirrored area simulating wrapping memory
m_clut = static_cast<u16*>(_aligned_malloc(CLUT_ALLOC_SIZE, VECTOR_ALIGNMENT)); m_clut = static_cast<u16*>(_aligned_malloc(CLUT_ALLOC_SIZE, VECTOR_ALIGNMENT));
if (!m_clut) if (!m_clut)
@ -94,9 +92,7 @@ GSClut::GSClut(GSLocalMemory* mem)
GSClut::~GSClut() GSClut::~GSClut()
{ {
if (m_gpu_clut4)
delete m_gpu_clut4; delete m_gpu_clut4;
if (m_gpu_clut8)
delete m_gpu_clut8; delete m_gpu_clut8;
_aligned_free(m_clut); _aligned_free(m_clut);
@ -130,6 +126,16 @@ void GSClut::SetNextCLUTTEX0(u64 TEX0)
m_write.next_tex0 = TEX0; m_write.next_tex0 = TEX0;
} }
void GSClut::Reset()
{
std::memset(m_CBP, 0, sizeof(m_CBP));
std::memset(m_clut, 0, CLUT_ALLOC_SIZE);
m_write = {};
m_write.dirty = 1;
m_read = {};
m_read.dirty = true;
}
bool GSClut::InvalidateRange(u32 start_block, u32 end_block, bool is_draw) bool GSClut::InvalidateRange(u32 start_block, u32 end_block, bool is_draw)
{ {
if (m_write.dirty & 2) if (m_write.dirty & 2)

View File

@ -13,16 +13,18 @@ class GSTexture;
class alignas(32) GSClut final : public GSAlignedClass<32> class alignas(32) GSClut final : public GSAlignedClass<32>
{ {
static constexpr u32 CLUT_ALLOC_SIZE = 4096 * 2;
static const GSVector4i m_bm; static const GSVector4i m_bm;
static const GSVector4i m_gm; static const GSVector4i m_gm;
static const GSVector4i m_rm; static const GSVector4i m_rm;
GSLocalMemory* m_mem; GSLocalMemory* m_mem;
u32 m_CBP[2]; u32 m_CBP[2] = {};
u16* m_clut; u16* m_clut = nullptr;
u32* m_buff32; u32* m_buff32 = nullptr;
u64* m_buff64; u64* m_buff64 = nullptr;
struct alignas(32) WriteState struct alignas(32) WriteState
{ {
@ -31,7 +33,7 @@ class alignas(32) GSClut final : public GSAlignedClass<32>
u8 dirty; u8 dirty;
u64 next_tex0; u64 next_tex0;
bool IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT); bool IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
} m_write; } m_write = {};
struct alignas(32) ReadState struct alignas(32) ReadState
{ {
@ -42,7 +44,7 @@ class alignas(32) GSClut final : public GSAlignedClass<32>
int amin, amax; int amin, amax;
bool IsDirty(const GIFRegTEX0& TEX0); bool IsDirty(const GIFRegTEX0& TEX0);
bool IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA); bool IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA);
} m_read; } m_read = {};
GSTexture* m_gpu_clut4 = nullptr; GSTexture* m_gpu_clut4 = nullptr;
GSTexture* m_gpu_clut8 = nullptr; GSTexture* m_gpu_clut8 = nullptr;
@ -96,6 +98,7 @@ public:
__fi GSTexture* GetGPUTexture() const { return m_current_gpu_clut; } __fi GSTexture* GetGPUTexture() const { return m_current_gpu_clut; }
void Reset();
bool InvalidateRange(u32 start_block, u32 end_block, bool is_draw = false); bool InvalidateRange(u32 start_block, u32 end_block, bool is_draw = false);
u8 IsInvalid(); u8 IsInvalid();
void ClearDrawInvalidity(); void ClearDrawInvalidity();

View File

@ -140,6 +140,7 @@ void GSState::Reset(bool hardware_reset)
memset(&m_v, 0, sizeof(m_v)); memset(&m_v, 0, sizeof(m_v));
m_env.Reset(); m_env.Reset();
m_mem.m_clut.Reset();
PRIM = &m_env.PRIM; PRIM = &m_env.PRIM;
@ -181,6 +182,7 @@ void GSState::Reset(bool hardware_reset)
m_index.tail = 0; m_index.tail = 0;
m_scanmask_used = 0; m_scanmask_used = 0;
m_texflush_flag = false; m_texflush_flag = false;
m_channel_shuffle = false;
m_dirty_gs_regs = 0; m_dirty_gs_regs = 0;
m_backed_up_ctx = -1; m_backed_up_ctx = -1;
@ -2708,6 +2710,7 @@ int GSState::Defrost(const freezeData* fd)
ReadState(&m_q, data); ReadState(&m_q, data);
m_prev_env = m_env;
PRIM = &m_env.PRIM; PRIM = &m_env.PRIM;
UpdateContext(); UpdateContext();
@ -2725,6 +2728,10 @@ int GSState::Defrost(const freezeData* fd)
UpdateScissor(); UpdateScissor();
// Force CLUT to be reloaded.
m_mem.m_clut.Reset();
(PRIM->CTXT == 0) ? ApplyTEX0<0>(m_context->TEX0) : ApplyTEX0<1>(m_context->TEX0);
g_perfmon.SetFrame(5000); g_perfmon.SetFrame(5000);
ResetPCRTC(); ResetPCRTC();