Add basic support for rewinding (not enabled.)

This commit is contained in:
Unknown W. Brackets 2013-09-29 19:57:51 -07:00
parent e55c05503a
commit b3c6e6c012
2 changed files with 91 additions and 0 deletions

View file

@ -32,6 +32,7 @@
#include "Core/MemMap.h"
#include "Core/MIPS/MIPS.h"
#include "Core/MIPS/JitCommon/JitCommon.h"
#include "GPU/GPUState.h"
#include "UI/OnScreenDisplay.h"
#include "i18n/i18n.h"
@ -47,6 +48,7 @@ namespace SaveState
SAVESTATE_SAVE,
SAVESTATE_LOAD,
SAVESTATE_VERIFY,
SAVESTATE_REWIND,
};
struct Operation
@ -62,10 +64,58 @@ namespace SaveState
void *cbUserData;
};
struct StateRingbuffer
{
StateRingbuffer(int size) : first_(0), next_(0), size_(size)
{
states_.resize(size);
}
CChunkFileReader::Error Save()
{
int n = next_++ % size_;
if (n == first_)
++first_;
SaveStart state;
size_t sz = CChunkFileReader::MeasurePtr(state);
if (states_[n].size() < sz)
states_[n].resize(sz);
return CChunkFileReader::SavePtr(states_[n].data(), state);
}
CChunkFileReader::Error Restore()
{
// No valid states left.
if (next_ == first_)
return CChunkFileReader::ERROR_BAD_FILE;
int n = (next_-- + size_) % size_;
if (states_[n].empty())
return CChunkFileReader::ERROR_BAD_FILE;
SaveStart state;
return CChunkFileReader::LoadPtr(states_[n].data(), state);
}
typedef std::vector<u8> StateBuffer;
int first_;
int next_;
int size_;
std::vector<StateBuffer> states_;
};
static bool needsProcess = false;
static std::vector<Operation> pending;
static std::recursive_mutex mutex;
// TODO: Should this be configurable?
static const int REWIND_NUM_STATES = 5;
static StateRingbuffer rewindStates(REWIND_NUM_STATES);
// TODO: g_Config setting or something instead.
static int rewindStateFreq = 0;
void SaveStart::DoState(PointerWrap &p)
{
auto s = p.Section("SaveStart", 1);
@ -120,6 +170,11 @@ namespace SaveState
Enqueue(Operation(SAVESTATE_VERIFY, std::string(""), callback, cbUserData));
}
void Rewind(Callback callback, void *cbUserData)
{
Enqueue(Operation(SAVESTATE_REWIND, std::string(""), callback, cbUserData));
}
// Slot utilities
@ -230,6 +285,12 @@ namespace SaveState
void Process()
{
if (rewindStateFreq != 0)
{
if (gpuStats.numFlips % rewindStateFreq == 0)
rewindStates.Save();
}
if (!needsProcess)
return;
needsProcess = false;
@ -289,6 +350,32 @@ namespace SaveState
callbackResult = CChunkFileReader::Verify(state) == CChunkFileReader::ERROR_NONE;
break;
case SAVESTATE_REWIND:
INFO_LOG(COMMON, "Rewinding to recent savestate snapshot");
result = rewindStates.Restore();
if (result == CChunkFileReader::ERROR_NONE) {
osm.Show(s->T("Loaded State"), 2.0);
callbackResult = true;
} else if (result == CChunkFileReader::ERROR_BROKEN_STATE) {
// Cripes. Good news is, we might have more. Let's try those too, better than a reset.
do
result = rewindStates.Restore();
while (result == CChunkFileReader::ERROR_BROKEN_STATE);
if (result == CChunkFileReader::ERROR_NONE) {
osm.Show(s->T("Loaded State"), 2.0);
callbackResult = true;
} else {
// We tried our best.
HandleFailure();
callbackResult = false;
}
} else {
osm.Show(s->T("Load savestate failed"), 2.0);
callbackResult = false;
}
break;
default:
ERROR_LOG(COMMON, "Savestate failure: unknown operation type %d", op.type);
callbackResult = false;