Changed the save state system to load/save only after the screen has been drawn. This should help stabilise the save states.
This commit is contained in:
parent
da9bd95a68
commit
5d14bb5e70
|
@ -28,6 +28,7 @@
|
|||
#include "StringUtil.h"
|
||||
|
||||
#include "VideoBackendBase.h"
|
||||
#include "State.h"
|
||||
|
||||
namespace VideoInterface
|
||||
{
|
||||
|
@ -698,6 +699,9 @@ void UpdateInterrupts()
|
|||
{
|
||||
ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_VI, false);
|
||||
}
|
||||
|
||||
if (m_InterruptRegister[1].IR_INT && m_InterruptRegister[1].IR_MASK)
|
||||
State::ProcessRequestedStates(1);
|
||||
}
|
||||
|
||||
u32 GetXFBAddressTop()
|
||||
|
|
|
@ -81,6 +81,9 @@ void DoState(PointerWrap &p)
|
|||
|
||||
SystemTimers::DecrementerSet();
|
||||
SystemTimers::TimeBaseSet();
|
||||
|
||||
if (jit && p.GetMode() == PointerWrap::MODE_READ)
|
||||
jit->GetBlockCache()->ClearSafe();
|
||||
}
|
||||
|
||||
void ResetRegisters()
|
||||
|
|
|
@ -31,6 +31,9 @@
|
|||
#include "VideoBackendBase.h"
|
||||
|
||||
#include <lzo/lzo1x.h>
|
||||
#include "HW/Memmap.h"
|
||||
#include "HW/VideoInterface.h"
|
||||
#include "HW/SystemTimers.h"
|
||||
|
||||
namespace State
|
||||
{
|
||||
|
@ -64,6 +67,12 @@ static std::vector<u8> g_current_buffer;
|
|||
|
||||
static std::thread g_save_thread;
|
||||
|
||||
static const u8 NUM_HOOKS = 2;
|
||||
static u8 waiting;
|
||||
static u8 waitingslot;
|
||||
static u64 lastCheckedStates[NUM_HOOKS];
|
||||
static u8 hook;
|
||||
|
||||
// Don't forget to increase this after doing changes on the savestate system
|
||||
static const int STATE_VERSION = 5;
|
||||
|
||||
|
@ -73,6 +82,13 @@ struct StateHeader
|
|||
size_t size;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
STATE_NONE = 0,
|
||||
STATE_SAVE = 1,
|
||||
STATE_LOAD = 2,
|
||||
};
|
||||
|
||||
static bool g_use_compression = true;
|
||||
|
||||
void EnableCompression(bool compression)
|
||||
|
@ -105,6 +121,12 @@ void DoState(PointerWrap &p)
|
|||
g_video_backend->RunLoop(true);
|
||||
}
|
||||
|
||||
void ResetCounters()
|
||||
{
|
||||
for (int i = 0; i < NUM_HOOKS; ++i)
|
||||
lastCheckedStates[i] = CoreTiming::GetTicks();
|
||||
}
|
||||
|
||||
void LoadBufferStateCallback(u64 userdata, int cyclesLate)
|
||||
{
|
||||
u8* ptr = &g_current_buffer[0];
|
||||
|
@ -217,10 +239,6 @@ void SaveFileStateCallback(u64 userdata, int cyclesLate)
|
|||
// Pause the core while we save the state
|
||||
CCPU::EnableStepping(true);
|
||||
|
||||
// Wait for the other threaded sub-systems to stop too
|
||||
// TODO: this is ugly
|
||||
SLEEP(100);
|
||||
|
||||
Flush();
|
||||
|
||||
// Measure the size of the buffer.
|
||||
|
@ -318,10 +336,6 @@ void LoadFileStateCallback(u64 userdata, int cyclesLate)
|
|||
// Stop the core while we load the state
|
||||
CCPU::EnableStepping(true);
|
||||
|
||||
// Wait for the other threaded sub-systems to stop too
|
||||
// TODO: uglyyy
|
||||
SLEEP(100);
|
||||
|
||||
Flush();
|
||||
|
||||
// Save temp buffer for undo load state
|
||||
|
@ -350,6 +364,8 @@ void LoadFileStateCallback(u64 userdata, int cyclesLate)
|
|||
Movie::EndPlayInput(false);
|
||||
}
|
||||
|
||||
ResetCounters();
|
||||
|
||||
g_op_in_progress = false;
|
||||
|
||||
// resume dat core
|
||||
|
@ -386,6 +402,11 @@ void Init()
|
|||
ev_BufferSave = CoreTiming::RegisterEvent("SaveBufferState", &SaveBufferStateCallback);
|
||||
ev_BufferVerify = CoreTiming::RegisterEvent("VerifyBufferState", &VerifyBufferStateCallback);
|
||||
|
||||
waiting = STATE_NONE;
|
||||
waitingslot = 0;
|
||||
hook = 0;
|
||||
ResetCounters();
|
||||
|
||||
if (lzo_init() != LZO_E_OK)
|
||||
PanicAlertT("Internal LZO Error - lzo_init() failed");
|
||||
}
|
||||
|
@ -413,40 +434,100 @@ static std::string MakeStateFilename(int number)
|
|||
SConfig::GetInstance().m_LocalCoreStartupParameter.GetUniqueID().c_str(), number);
|
||||
}
|
||||
|
||||
void ScheduleFileEvent(const std::string &filename, int ev)
|
||||
void ScheduleFileEvent(const std::string &filename, int ev, bool immediate)
|
||||
{
|
||||
if (g_op_in_progress)
|
||||
return;
|
||||
g_op_in_progress = true;
|
||||
|
||||
g_current_filename = filename;
|
||||
|
||||
if (immediate)
|
||||
CoreTiming::ScheduleEvent_Threadsafe_Immediate(ev);
|
||||
else
|
||||
CoreTiming::ScheduleEvent_Threadsafe(0, ev);
|
||||
}
|
||||
|
||||
void SaveAs(const std::string &filename, bool immediate)
|
||||
{
|
||||
g_last_filename = filename;
|
||||
ScheduleFileEvent(filename, ev_FileSave, immediate);
|
||||
}
|
||||
|
||||
void SaveAs(const std::string &filename)
|
||||
{
|
||||
g_last_filename = filename;
|
||||
ScheduleFileEvent(filename, ev_FileSave);
|
||||
SaveAs(filename, true);
|
||||
}
|
||||
|
||||
void LoadAs(const std::string &filename, bool immediate)
|
||||
{
|
||||
ScheduleFileEvent(filename, ev_FileLoad, immediate);
|
||||
}
|
||||
|
||||
void LoadAs(const std::string &filename)
|
||||
{
|
||||
ScheduleFileEvent(filename, ev_FileLoad);
|
||||
LoadAs(filename, true);
|
||||
}
|
||||
|
||||
void VerifyAt(const std::string &filename)
|
||||
{
|
||||
ScheduleFileEvent(filename, ev_FileVerify);
|
||||
ScheduleFileEvent(filename, ev_FileVerify, true);
|
||||
}
|
||||
|
||||
bool ProcessRequestedStates(int priority)
|
||||
{
|
||||
bool save = true;
|
||||
|
||||
if (hook == priority)
|
||||
{
|
||||
if (waiting == STATE_SAVE)
|
||||
{
|
||||
SaveAs(MakeStateFilename(waitingslot), false);
|
||||
waitingslot = 0;
|
||||
waiting = STATE_NONE;
|
||||
}
|
||||
else if (waiting == STATE_LOAD)
|
||||
{
|
||||
LoadAs(MakeStateFilename(waitingslot), false);
|
||||
waitingslot = 0;
|
||||
waiting = STATE_NONE;
|
||||
save = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Change hooks if the new hook gets called frequently (at least once a frame) and if the old
|
||||
// hook has not been called for the last 5 seconds
|
||||
if ((CoreTiming::GetTicks() - lastCheckedStates[priority]) < (VideoInterface::GetTicksPerFrame()))
|
||||
{
|
||||
lastCheckedStates[priority] = CoreTiming::GetTicks();
|
||||
if (hook < NUM_HOOKS && priority >= (hook + 1) &&
|
||||
(lastCheckedStates[priority] - lastCheckedStates[hook]) > (SystemTimers::GetTicksPerSecond() * 5))
|
||||
{
|
||||
hook++;
|
||||
}
|
||||
}
|
||||
else
|
||||
lastCheckedStates[priority] = CoreTiming::GetTicks();
|
||||
|
||||
return save;
|
||||
}
|
||||
|
||||
void Save(int slot)
|
||||
{
|
||||
SaveAs(MakeStateFilename(slot));
|
||||
if (waiting == STATE_NONE)
|
||||
{
|
||||
waiting = STATE_SAVE;
|
||||
waitingslot = slot;
|
||||
}
|
||||
}
|
||||
|
||||
void Load(int slot)
|
||||
{
|
||||
LoadAs(MakeStateFilename(slot));
|
||||
if (waiting == STATE_NONE)
|
||||
{
|
||||
waiting = STATE_LOAD;
|
||||
waitingslot = slot;
|
||||
}
|
||||
}
|
||||
|
||||
void Verify(int slot)
|
||||
|
|
|
@ -26,6 +26,7 @@ namespace State
|
|||
{
|
||||
|
||||
void Init();
|
||||
|
||||
void Shutdown();
|
||||
|
||||
void EnableCompression(bool compression);
|
||||
|
@ -39,6 +40,8 @@ void Save(int slot);
|
|||
void Load(int slot);
|
||||
void Verify(int slot);
|
||||
|
||||
bool ProcessRequestedStates(int priority);
|
||||
|
||||
void SaveAs(const std::string &filename);
|
||||
void LoadAs(const std::string &filename);
|
||||
void VerifyAt(const std::string &filename);
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "CommandProcessor.h"
|
||||
#include "HW/ProcessorInterface.h"
|
||||
#include "DLCache.h"
|
||||
#include "State.h"
|
||||
namespace PixelEngine
|
||||
{
|
||||
|
||||
|
@ -329,6 +330,8 @@ void UpdateFinishInterrupt(bool active)
|
|||
{
|
||||
ProcessorInterface::SetInterrupt(INT_CAUSE_PE_FINISH, active);
|
||||
interruptSetFinish = active;
|
||||
if (active)
|
||||
State::ProcessRequestedStates(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue