From 5d14bb5e70dd1122c36e68ee529fcda8db67243e Mon Sep 17 00:00:00 2001 From: skidau Date: Sat, 15 Oct 2011 22:19:42 +1100 Subject: [PATCH] Changed the save state system to load/save only after the screen has been drawn. This should help stabilise the save states. --- Source/Core/Core/Src/HW/VideoInterface.cpp | 4 + Source/Core/Core/Src/PowerPC/PowerPC.cpp | 3 + Source/Core/Core/Src/State.cpp | 113 +++++++++++++++++--- Source/Core/Core/Src/State.h | 3 + Source/Core/VideoCommon/Src/PixelEngine.cpp | 3 + 5 files changed, 110 insertions(+), 16 deletions(-) diff --git a/Source/Core/Core/Src/HW/VideoInterface.cpp b/Source/Core/Core/Src/HW/VideoInterface.cpp index d8d6d98570..93c48d92f9 100644 --- a/Source/Core/Core/Src/HW/VideoInterface.cpp +++ b/Source/Core/Core/Src/HW/VideoInterface.cpp @@ -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() diff --git a/Source/Core/Core/Src/PowerPC/PowerPC.cpp b/Source/Core/Core/Src/PowerPC/PowerPC.cpp index 567f3ff98e..d4ec476280 100644 --- a/Source/Core/Core/Src/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/Src/PowerPC/PowerPC.cpp @@ -81,6 +81,9 @@ void DoState(PointerWrap &p) SystemTimers::DecrementerSet(); SystemTimers::TimeBaseSet(); + + if (jit && p.GetMode() == PointerWrap::MODE_READ) + jit->GetBlockCache()->ClearSafe(); } void ResetRegisters() diff --git a/Source/Core/Core/Src/State.cpp b/Source/Core/Core/Src/State.cpp index d942255d2a..650f5a788f 100644 --- a/Source/Core/Core/Src/State.cpp +++ b/Source/Core/Core/Src/State.cpp @@ -31,6 +31,9 @@ #include "VideoBackendBase.h" #include +#include "HW/Memmap.h" +#include "HW/VideoInterface.h" +#include "HW/SystemTimers.h" namespace State { @@ -64,6 +67,12 @@ static std::vector 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; - 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) { - 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) diff --git a/Source/Core/Core/Src/State.h b/Source/Core/Core/Src/State.h index 791468f154..111c4e24f0 100644 --- a/Source/Core/Core/Src/State.h +++ b/Source/Core/Core/Src/State.h @@ -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); diff --git a/Source/Core/VideoCommon/Src/PixelEngine.cpp b/Source/Core/VideoCommon/Src/PixelEngine.cpp index 2a328de95d..3b6d1b7487 100644 --- a/Source/Core/VideoCommon/Src/PixelEngine.cpp +++ b/Source/Core/VideoCommon/Src/PixelEngine.cpp @@ -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); } }