mirror of https://github.com/PCSX2/pcsx2.git
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:
parent
a317e9c038
commit
2eab0f9757
|
@ -13,8 +13,6 @@
|
|||
GSClut::GSClut(GSLocalMemory* mem)
|
||||
: m_mem(mem)
|
||||
{
|
||||
static constexpr u32 CLUT_ALLOC_SIZE = 4096 * 2;
|
||||
|
||||
// 1k + 1k for mirrored area simulating wrapping memory
|
||||
m_clut = static_cast<u16*>(_aligned_malloc(CLUT_ALLOC_SIZE, VECTOR_ALIGNMENT));
|
||||
if (!m_clut)
|
||||
|
@ -94,10 +92,8 @@ GSClut::GSClut(GSLocalMemory* mem)
|
|||
|
||||
GSClut::~GSClut()
|
||||
{
|
||||
if (m_gpu_clut4)
|
||||
delete m_gpu_clut4;
|
||||
if (m_gpu_clut8)
|
||||
delete m_gpu_clut8;
|
||||
delete m_gpu_clut4;
|
||||
delete m_gpu_clut8;
|
||||
|
||||
_aligned_free(m_clut);
|
||||
}
|
||||
|
@ -130,6 +126,16 @@ void GSClut::SetNextCLUTTEX0(u64 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)
|
||||
{
|
||||
if (m_write.dirty & 2)
|
||||
|
|
|
@ -13,16 +13,18 @@ class GSTexture;
|
|||
|
||||
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_gm;
|
||||
static const GSVector4i m_rm;
|
||||
|
||||
GSLocalMemory* m_mem;
|
||||
|
||||
u32 m_CBP[2];
|
||||
u16* m_clut;
|
||||
u32* m_buff32;
|
||||
u64* m_buff64;
|
||||
u32 m_CBP[2] = {};
|
||||
u16* m_clut = nullptr;
|
||||
u32* m_buff32 = nullptr;
|
||||
u64* m_buff64 = nullptr;
|
||||
|
||||
struct alignas(32) WriteState
|
||||
{
|
||||
|
@ -31,7 +33,7 @@ class alignas(32) GSClut final : public GSAlignedClass<32>
|
|||
u8 dirty;
|
||||
u64 next_tex0;
|
||||
bool IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXCLUT& TEXCLUT);
|
||||
} m_write;
|
||||
} m_write = {};
|
||||
|
||||
struct alignas(32) ReadState
|
||||
{
|
||||
|
@ -42,7 +44,7 @@ class alignas(32) GSClut final : public GSAlignedClass<32>
|
|||
int amin, amax;
|
||||
bool IsDirty(const GIFRegTEX0& TEX0);
|
||||
bool IsDirty(const GIFRegTEX0& TEX0, const GIFRegTEXA& TEXA);
|
||||
} m_read;
|
||||
} m_read = {};
|
||||
|
||||
GSTexture* m_gpu_clut4 = nullptr;
|
||||
GSTexture* m_gpu_clut8 = nullptr;
|
||||
|
@ -96,6 +98,7 @@ public:
|
|||
|
||||
__fi GSTexture* GetGPUTexture() const { return m_current_gpu_clut; }
|
||||
|
||||
void Reset();
|
||||
bool InvalidateRange(u32 start_block, u32 end_block, bool is_draw = false);
|
||||
u8 IsInvalid();
|
||||
void ClearDrawInvalidity();
|
||||
|
|
|
@ -140,6 +140,7 @@ void GSState::Reset(bool hardware_reset)
|
|||
memset(&m_v, 0, sizeof(m_v));
|
||||
|
||||
m_env.Reset();
|
||||
m_mem.m_clut.Reset();
|
||||
|
||||
PRIM = &m_env.PRIM;
|
||||
|
||||
|
@ -181,6 +182,7 @@ void GSState::Reset(bool hardware_reset)
|
|||
m_index.tail = 0;
|
||||
m_scanmask_used = 0;
|
||||
m_texflush_flag = false;
|
||||
m_channel_shuffle = false;
|
||||
m_dirty_gs_regs = 0;
|
||||
m_backed_up_ctx = -1;
|
||||
|
||||
|
@ -2708,6 +2710,7 @@ int GSState::Defrost(const freezeData* fd)
|
|||
|
||||
ReadState(&m_q, data);
|
||||
|
||||
m_prev_env = m_env;
|
||||
PRIM = &m_env.PRIM;
|
||||
|
||||
UpdateContext();
|
||||
|
@ -2725,6 +2728,10 @@ int GSState::Defrost(const freezeData* fd)
|
|||
|
||||
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);
|
||||
|
||||
ResetPCRTC();
|
||||
|
|
Loading…
Reference in New Issue