made savestates synchronous and immediate. this allows saving or loading while the emulator is paused, fixes issues where savestate hotkeys would get ignored if pressed too close together, might speed up savestates in some cases, and hopefully makes savestates more stable too.

the intent is to replace the haphazard scheduling and finger-crossing associated with saving/loading with the correct and minimal necessary wait for each thread to reach a known safe location before commencing the savestate operation, and for any already-paused components to not need to be resumed to do so.
This commit is contained in:
nitsuja
2011-12-30 20:16:12 -08:00
committed by skidau
parent 108f69eaa9
commit a81631b58e
33 changed files with 518 additions and 323 deletions

View File

@ -26,6 +26,7 @@
#include "ChunkFile.h"
#include "Fifo.h"
#include "HW/Memmap.h"
#include "Core.h"
volatile bool g_bSkipCurrentFrame = false;
extern u8* g_pVideoData;
@ -34,22 +35,44 @@ namespace
{
static volatile bool GpuRunningState = false;
static volatile bool EmuRunningState = false;
static u8 *videoBuffer;
static std::mutex m_csHWVidOccupied;
// STATE_TO_SAVE
static u8 *videoBuffer;
static int size = 0;
} // namespace
void Fifo_DoState(PointerWrap &p)
{
p.DoArray(videoBuffer, FIFO_SIZE);
p.Do(size);
int pos = (int)(g_pVideoData - videoBuffer); // get offset
p.Do(pos); // read or write offset (depends on the mode afaik)
g_pVideoData = &videoBuffer[pos]; // overwrite g_pVideoData -> expected no change when load ss and change when save ss
p.Do(pos); // read or write offset (depending on the mode)
if (p.GetMode() == PointerWrap::MODE_READ)
{
g_pVideoData = &videoBuffer[pos];
g_bSkipCurrentFrame = false;
}
}
void Fifo_PauseAndLock(bool doLock, bool unpauseOnUnlock)
{
if (doLock)
{
EmulatorState(false);
if (!Core::IsGPUThread())
m_csHWVidOccupied.lock();
_dbg_assert_(COMMON, !CommandProcessor::fifo.isGpuReadingData);
}
else
{
if (unpauseOnUnlock)
EmulatorState(true);
if (!Core::IsGPUThread())
m_csHWVidOccupied.unlock();
}
}
void Fifo_Init()
{
videoBuffer = (u8*)AllocateMemoryPages(FIFO_SIZE);
@ -127,6 +150,7 @@ void ResetVideoBuffer()
// Purpose: Keep the Core HW updated about the CPU-GPU distance
void RunGpuLoop()
{
std::lock_guard<std::mutex> lk(m_csHWVidOccupied);
GpuRunningState = true;
SCPFifoStruct &fifo = CommandProcessor::fifo;
@ -178,12 +202,13 @@ void RunGpuLoop()
Common::YieldCPU();
else
{
// While the emu is paused, we still handle async request such as Savestates then sleep.
// While the emu is paused, we still handle async requests then sleep.
while (!EmuRunningState)
{
g_video_backend->PeekMessages();
VideoFifo_CheckStateRequest();
m_csHWVidOccupied.unlock();
Common::SleepCurrentThread(1);
m_csHWVidOccupied.lock();
}
}
}