Merge pull request #4420 from unknownbrackets/savestates

Enable rewind feature in UI, fix a savestate bug
This commit is contained in:
Henrik Rydgård 2013-11-03 03:21:51 -08:00
commit b2298a9e86
8 changed files with 50 additions and 7 deletions

View file

@ -75,6 +75,7 @@ void Config::Load(const char *iniFileName, const char *controllerIniFilename) {
general->Get("EnableCheats", &bEnableCheats, false);
general->Get("ScreenshotsAsPNG", &bScreenshotsAsPNG, false);
general->Get("StateSlot", &iCurrentStateSlot, 0);
general->Get("RewindFlipFrequency", &iRewindFlipFrequency, 0);
general->Get("GridView1", &bGridView1, true);
general->Get("GridView2", &bGridView2, true);
general->Get("GridView3", &bGridView3, true);
@ -341,6 +342,7 @@ void Config::Save() {
general->Set("EnableCheats", bEnableCheats);
general->Set("ScreenshotsAsPNG", bScreenshotsAsPNG);
general->Set("StateSlot", iCurrentStateSlot);
general->Set("RewindFlipFrequency", iRewindFlipFrequency);
general->Set("GridView1", bGridView1);
general->Set("GridView2", bGridView2);
general->Set("GridView3", bGridView3);

View file

@ -92,6 +92,7 @@ public:
int iForceMaxEmulatedFPS;
int iMaxRecent;
int iCurrentStateSlot;
int iRewindFlipFrequency;
bool bEnableCheats;
bool bReloadCheats;
bool bDisableStencilTest;

View file

@ -520,7 +520,7 @@ public:
virtual void DoState(PointerWrap &p)
{
auto s = p.Section("Thread", 1);
auto s = p.Section("Thread", 1, 2);
if (!s)
return;
@ -537,6 +537,12 @@ public:
p.Do(pendingMipsCalls);
p.Do(pushedStacks);
p.Do(currentStack);
if (s >= 2)
{
p.Do(waitingThreads);
p.Do(pausedWaits);
}
}
NativeThread nt;

View file

@ -75,7 +75,7 @@ namespace SaveState
CChunkFileReader::Error Save()
{
int n = next_++ % size_;
if (n == first_)
if ((next_ % size_) == first_)
++first_;
SaveStart state;
@ -89,7 +89,7 @@ namespace SaveState
CChunkFileReader::Error Restore()
{
// No valid states left.
if (next_ == first_)
if (Empty())
return CChunkFileReader::ERROR_BAD_FILE;
int n = (next_-- + size_) % size_;
@ -100,6 +100,17 @@ namespace SaveState
return CChunkFileReader::LoadPtr(&states_[n][0], state);
}
void Clear()
{
first_ = 0;
next_ = 0;
}
bool Empty()
{
return next_ == first_;
}
typedef std::vector<u8> StateBuffer;
int first_;
int next_;
@ -114,8 +125,6 @@ namespace SaveState
// 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;
// TODO: Any reason for this to be configurable?
const static float rewindMaxWallFrequency = 1.0f;
static float rewindLastTime = 0.0f;
@ -179,6 +188,11 @@ namespace SaveState
Enqueue(Operation(SAVESTATE_REWIND, std::string(""), callback, cbUserData));
}
bool CanRewind()
{
return !rewindStates.Empty();
}
// Slot utilities
@ -302,7 +316,7 @@ namespace SaveState
static inline void CheckRewindState()
{
if (gpuStats.numFlips % rewindStateFreq != 0)
if (gpuStats.numFlips % g_Config.iRewindFlipFrequency != 0)
return;
// For fast-forwarding, otherwise they may be useless and too close.
@ -317,7 +331,7 @@ namespace SaveState
void Process()
{
if (rewindStateFreq != 0)
if (g_Config.iRewindFlipFrequency != 0 && gpuStats.numFlips != 0)
CheckRewindState();
if (!needsProcess)
@ -429,5 +443,6 @@ namespace SaveState
pspFileSystem.MkDir("ms0:/PSP/PPSSPP_STATE");
std::lock_guard<std::recursive_mutex> guard(mutex);
rewindStates.Clear();
}
}

View file

@ -52,6 +52,9 @@ namespace SaveState
// Warning: callback will be called on a different thread.
void Rewind(Callback callback = 0, void *cbUserData = 0);
// Returns true if there are rewind snapshots available.
bool CanRewind();
// Check if there's any save stating needing to be done. Normally called once per frame.
void Process();
};

View file

@ -254,6 +254,7 @@ void GameSettingsScreen::CreateViews() {
systemSettings->Add(new CheckBox(&g_Config.bSeparateIOThread, s->T("I/O on thread (experimental)")))->SetEnabled(!PSP_IsInited());
#endif
systemSettings->Add(new PopupSliderChoice(&g_Config.iLockedCPUSpeed, 0, 1000, s->T("Change CPU Clock", "Change CPU Clock (0 = default)"), screenManager()));
systemSettings->Add(new PopupSliderChoice(&g_Config.iRewindFlipFrequency, 0, 1800, s->T("Rewind Snapshot Frequency (0 = off, mem hog)"), screenManager()));
systemSettings->Add(new CheckBox(&g_Config.bAtomicAudioLocks, s->T("Atomic Audio locks (experimental)")))->SetEnabled(!PSP_IsInited());

View file

@ -779,6 +779,12 @@ void GamePauseScreen::CreateViews() {
loadStateButton_ = leftColumnItems->Add(new Choice(i->T("Load State")));
loadStateButton_->OnClick.Handle(this, &GamePauseScreen::OnLoadState);
if (g_Config.iRewindFlipFrequency > 0) {
UI::Choice *rewindButton = leftColumnItems->Add(new Choice(i->T("Rewind")));
rewindButton->SetEnabled(SaveState::CanRewind());
rewindButton->OnClick.Handle(this, &GamePauseScreen::OnRewind);
}
ViewGroup *rightColumn = new ScrollView(ORIENT_VERTICAL, new LinearLayoutParams(300, FILL_PARENT, actionMenuMargins));
root_->Add(rightColumn);
@ -833,6 +839,14 @@ UI::EventReturn GamePauseScreen::OnSaveState(UI::EventParams &e) {
screenManager()->finishDialog(this, DR_CANCEL);
return UI::EVENT_DONE;
}
UI::EventReturn GamePauseScreen::OnRewind(UI::EventParams &e) {
SaveState::Rewind(0, 0);
screenManager()->finishDialog(this, DR_CANCEL);
return UI::EVENT_DONE;
}
UI::EventReturn GamePauseScreen::OnCwCheat(UI::EventParams &e) {
screenManager()->push(new CwCheatScreen());
return UI::EVENT_DONE;

View file

@ -72,6 +72,7 @@ private:
UI::EventReturn OnSaveState(UI::EventParams &e);
UI::EventReturn OnLoadState(UI::EventParams &e);
UI::EventReturn OnRewind(UI::EventParams &e);
UI::EventReturn OnStateSelected(UI::EventParams &e);
UI::EventReturn OnCwCheat(UI::EventParams &e);