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)
|
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)
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
|
|
Loading…
Reference in New Issue