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:
skidau 2011-10-15 22:19:42 +11:00
parent da9bd95a68
commit 5d14bb5e70
5 changed files with 110 additions and 16 deletions

View File

@ -28,6 +28,7 @@
#include "StringUtil.h" #include "StringUtil.h"
#include "VideoBackendBase.h" #include "VideoBackendBase.h"
#include "State.h"
namespace VideoInterface namespace VideoInterface
{ {
@ -698,6 +699,9 @@ void UpdateInterrupts()
{ {
ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_VI, false); ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_VI, false);
} }
if (m_InterruptRegister[1].IR_INT && m_InterruptRegister[1].IR_MASK)
State::ProcessRequestedStates(1);
} }
u32 GetXFBAddressTop() u32 GetXFBAddressTop()

View File

@ -81,6 +81,9 @@ void DoState(PointerWrap &p)
SystemTimers::DecrementerSet(); SystemTimers::DecrementerSet();
SystemTimers::TimeBaseSet(); SystemTimers::TimeBaseSet();
if (jit && p.GetMode() == PointerWrap::MODE_READ)
jit->GetBlockCache()->ClearSafe();
} }
void ResetRegisters() void ResetRegisters()

View File

@ -31,6 +31,9 @@
#include "VideoBackendBase.h" #include "VideoBackendBase.h"
#include <lzo/lzo1x.h> #include <lzo/lzo1x.h>
#include "HW/Memmap.h"
#include "HW/VideoInterface.h"
#include "HW/SystemTimers.h"
namespace State namespace State
{ {
@ -64,6 +67,12 @@ static std::vector<u8> g_current_buffer;
static std::thread g_save_thread; 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 // Don't forget to increase this after doing changes on the savestate system
static const int STATE_VERSION = 5; static const int STATE_VERSION = 5;
@ -73,6 +82,13 @@ struct StateHeader
size_t size; size_t size;
}; };
enum
{
STATE_NONE = 0,
STATE_SAVE = 1,
STATE_LOAD = 2,
};
static bool g_use_compression = true; static bool g_use_compression = true;
void EnableCompression(bool compression) void EnableCompression(bool compression)
@ -105,6 +121,12 @@ void DoState(PointerWrap &p)
g_video_backend->RunLoop(true); 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) void LoadBufferStateCallback(u64 userdata, int cyclesLate)
{ {
u8* ptr = &g_current_buffer[0]; u8* ptr = &g_current_buffer[0];
@ -217,10 +239,6 @@ void SaveFileStateCallback(u64 userdata, int cyclesLate)
// Pause the core while we save the state // Pause the core while we save the state
CCPU::EnableStepping(true); CCPU::EnableStepping(true);
// Wait for the other threaded sub-systems to stop too
// TODO: this is ugly
SLEEP(100);
Flush(); Flush();
// Measure the size of the buffer. // Measure the size of the buffer.
@ -318,10 +336,6 @@ void LoadFileStateCallback(u64 userdata, int cyclesLate)
// Stop the core while we load the state // Stop the core while we load the state
CCPU::EnableStepping(true); CCPU::EnableStepping(true);
// Wait for the other threaded sub-systems to stop too
// TODO: uglyyy
SLEEP(100);
Flush(); Flush();
// Save temp buffer for undo load state // Save temp buffer for undo load state
@ -350,6 +364,8 @@ void LoadFileStateCallback(u64 userdata, int cyclesLate)
Movie::EndPlayInput(false); Movie::EndPlayInput(false);
} }
ResetCounters();
g_op_in_progress = false; g_op_in_progress = false;
// resume dat core // resume dat core
@ -386,6 +402,11 @@ void Init()
ev_BufferSave = CoreTiming::RegisterEvent("SaveBufferState", &SaveBufferStateCallback); ev_BufferSave = CoreTiming::RegisterEvent("SaveBufferState", &SaveBufferStateCallback);
ev_BufferVerify = CoreTiming::RegisterEvent("VerifyBufferState", &VerifyBufferStateCallback); ev_BufferVerify = CoreTiming::RegisterEvent("VerifyBufferState", &VerifyBufferStateCallback);
waiting = STATE_NONE;
waitingslot = 0;
hook = 0;
ResetCounters();
if (lzo_init() != LZO_E_OK) if (lzo_init() != LZO_E_OK)
PanicAlertT("Internal LZO Error - lzo_init() failed"); 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); 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) if (g_op_in_progress)
return; return;
g_op_in_progress = true; g_op_in_progress = true;
g_current_filename = filename; g_current_filename = filename;
CoreTiming::ScheduleEvent_Threadsafe_Immediate(ev);
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) void SaveAs(const std::string &filename)
{ {
g_last_filename = filename; SaveAs(filename, true);
ScheduleFileEvent(filename, ev_FileSave); }
void LoadAs(const std::string &filename, bool immediate)
{
ScheduleFileEvent(filename, ev_FileLoad, immediate);
} }
void LoadAs(const std::string &filename) void LoadAs(const std::string &filename)
{ {
ScheduleFileEvent(filename, ev_FileLoad); LoadAs(filename, true);
} }
void VerifyAt(const std::string &filename) 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) void Save(int slot)
{ {
SaveAs(MakeStateFilename(slot)); if (waiting == STATE_NONE)
{
waiting = STATE_SAVE;
waitingslot = slot;
}
} }
void Load(int slot) void Load(int slot)
{ {
LoadAs(MakeStateFilename(slot)); if (waiting == STATE_NONE)
{
waiting = STATE_LOAD;
waitingslot = slot;
}
} }
void Verify(int slot) void Verify(int slot)

View File

@ -26,6 +26,7 @@ namespace State
{ {
void Init(); void Init();
void Shutdown(); void Shutdown();
void EnableCompression(bool compression); void EnableCompression(bool compression);
@ -39,6 +40,8 @@ void Save(int slot);
void Load(int slot); void Load(int slot);
void Verify(int slot); void Verify(int slot);
bool ProcessRequestedStates(int priority);
void SaveAs(const std::string &filename); void SaveAs(const std::string &filename);
void LoadAs(const std::string &filename); void LoadAs(const std::string &filename);
void VerifyAt(const std::string &filename); void VerifyAt(const std::string &filename);

View File

@ -31,6 +31,7 @@
#include "CommandProcessor.h" #include "CommandProcessor.h"
#include "HW/ProcessorInterface.h" #include "HW/ProcessorInterface.h"
#include "DLCache.h" #include "DLCache.h"
#include "State.h"
namespace PixelEngine namespace PixelEngine
{ {
@ -329,6 +330,8 @@ void UpdateFinishInterrupt(bool active)
{ {
ProcessorInterface::SetInterrupt(INT_CAUSE_PE_FINISH, active); ProcessorInterface::SetInterrupt(INT_CAUSE_PE_FINISH, active);
interruptSetFinish = active; interruptSetFinish = active;
if (active)
State::ProcessRequestedStates(0);
} }
} }