From fd47eb7b44da76f3f05f5042fcceb583ebb4f329 Mon Sep 17 00:00:00 2001 From: "XTra.KrazzY" Date: Sun, 28 Jun 2009 21:11:51 +0000 Subject: [PATCH] Save States: 1. Added "Undo Load State" which... undoes load state :) 2. Implemented saving/loading to memory buffers (very fast) for temporal states such as for "undo load state" git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3585 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Core/Src/Core.cpp | 8 +-- Source/Core/Core/Src/State.cpp | 87 +++++++++++++++++++++++- Source/Core/Core/Src/State.h | 15 ++-- Source/Core/DolphinWX/Src/Frame.cpp | 3 +- Source/Core/DolphinWX/Src/Frame.h | 3 +- Source/Core/DolphinWX/Src/FrameTools.cpp | 13 +++- Source/Core/DolphinWX/Src/Globals.h | 3 +- 7 files changed, 114 insertions(+), 18 deletions(-) diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp index dcb4352037..ba251211bb 100644 --- a/Source/Core/Core/Src/Core.cpp +++ b/Source/Core/Core/Src/Core.cpp @@ -895,12 +895,10 @@ void Callback_KeyPress(int key, bool shift, bool control) // 0x7a == VK_F12 if (key == 0x7b) { - // TODO: Move to memory buffer, implement last state before loading if(shift) - State_LoadAs(FULL_STATESAVES_DIR "lastState.sav"); - /*else - State_LoadAs(FULL_STATESAVES_DIR "tempState.sav"); - */ + State_UndoSaveState(); + else + State_UndoLoadState(); } } diff --git a/Source/Core/Core/Src/State.cpp b/Source/Core/Core/Src/State.cpp index 123e8d653a..920fa20fd8 100644 --- a/Source/Core/Core/Src/State.cpp +++ b/Source/Core/Core/Src/State.cpp @@ -53,9 +53,15 @@ static int ev_Save, ev_BufferSave; static int ev_Load, ev_BufferLoad; static std::string cur_filename, lastFilename; +static u8 **cur_buffer = NULL; + +// Temporary undo state buffers +static u8 *undoLoad = NULL; static bool const bCompressed = true; +static Common::Thread *saveThread = NULL; + enum { version = 1, @@ -79,6 +85,49 @@ void DoState(PointerWrap &p) CoreTiming::DoState(p); } +void LoadBufferStateCallback(u64 userdata, int cyclesLate) +{ + if(!cur_buffer || !*cur_buffer) { + Core::DisplayMessage("State does not exist", 1000); + return; + } + + jit.ClearCache(); + + u8 *ptr = *cur_buffer; + PointerWrap p(&ptr, PointerWrap::MODE_READ); + DoState(p); + + cur_buffer = NULL; + + Core::DisplayMessage("Loaded state", 2000); +} + +void SaveBufferStateCallback(u64 userdata, int cyclesLate) +{ + size_t sz; + + if(!cur_buffer) { + Core::DisplayMessage("Error saving state", 1000); + return; + } + + jit.ClearCache(); + + u8 *ptr = NULL; + + PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); + DoState(p); + sz = (size_t)ptr; + + *cur_buffer = new u8[sz]; + ptr = *cur_buffer; + p.SetMode(PointerWrap::MODE_WRITE); + DoState(p); + + cur_buffer = NULL; +} + THREAD_RETURN CompressAndDumpState(void *pArgs) { saveStruct *saveArg = (saveStruct *)pArgs; @@ -149,8 +198,6 @@ THREAD_RETURN CompressAndDumpState(void *pArgs) return 0; } -Common::Thread *saveThread = NULL; - void SaveStateCallback(u64 userdata, int cyclesLate) { // If already saving state, wait for it to finish @@ -193,6 +240,10 @@ void LoadStateCallback(u64 userdata, int cyclesLate) saveThread = NULL; } + // Save temp buffer for undo load state + cur_buffer = &undoLoad; + SaveBufferStateCallback(userdata, cyclesLate); + FILE *f = fopen(cur_filename.c_str(), "rb"); if (!f) { Core::DisplayMessage("State not found", 2000); @@ -270,6 +321,8 @@ void State_Init() { ev_Load = CoreTiming::RegisterEvent("LoadState", &LoadStateCallback); ev_Save = CoreTiming::RegisterEvent("SaveState", &SaveStateCallback); + ev_BufferLoad = CoreTiming::RegisterEvent("LoadBufferState", &LoadBufferStateCallback); + ev_BufferSave = CoreTiming::RegisterEvent("SaveBufferState", &SaveBufferStateCallback); } void State_Shutdown() @@ -279,6 +332,12 @@ void State_Shutdown() delete saveThread; saveThread = NULL; } + + if(undoLoad) + { + delete[] undoLoad; + undoLoad = NULL; + } } std::string MakeStateFilename(int state_number) @@ -316,3 +375,27 @@ void State_LoadLastSaved() else State_LoadAs(lastFilename); } + +void State_LoadFromBuffer(u8 **buffer) +{ + cur_buffer = buffer; + CoreTiming::ScheduleEvent_Threadsafe(0, ev_BufferLoad); +} + +void State_SaveToBuffer(u8 **buffer) +{ + cur_buffer = buffer; + CoreTiming::ScheduleEvent_Threadsafe(0, ev_BufferSave); +} + +// Load the last state before loading the state +void State_UndoLoadState() +{ + State_LoadFromBuffer(&undoLoad); +} + +// Load the state that the last save state overwritten on +void State_UndoSaveState() +{ + State_LoadAs(FULL_STATESAVES_DIR "lastState.sav"); +} diff --git a/Source/Core/Core/Src/State.h b/Source/Core/Core/Src/State.h index b22df727d8..34b4714987 100644 --- a/Source/Core/Core/Src/State.h +++ b/Source/Core/Core/Src/State.h @@ -20,6 +20,12 @@ #ifndef _STATE_H_ #define _STATE_H_ +typedef struct +{ + u8 *buffer; + size_t size; +} saveStruct; + void State_Init(); void State_Shutdown(); @@ -32,12 +38,11 @@ void State_SaveAs(const std::string &filename); void State_LoadAs(const std::string &filename); void State_LoadLastSaved(); +void State_UndoSaveState(); +void State_UndoLoadState(); -typedef struct -{ - u8 *buffer; - size_t size; -} saveStruct; +void State_LoadFromBuffer(u8 **buffer); +void State_SaveToBuffer(u8 **buffer); typedef struct diff --git a/Source/Core/DolphinWX/Src/Frame.cpp b/Source/Core/DolphinWX/Src/Frame.cpp index ab24dc8465..9a00225ab5 100644 --- a/Source/Core/DolphinWX/Src/Frame.cpp +++ b/Source/Core/DolphinWX/Src/Frame.cpp @@ -286,7 +286,8 @@ EVT_MENU(IDM_LISTUSA, CFrame::GameListChanged) EVT_MENU(IDM_PURGECACHE, CFrame::GameListChanged) EVT_MENU(IDM_LOADLASTSTATE, CFrame::OnLoadLastState) -EVT_MENU(IDM_UNDOSTATE, CFrame::OnUndoState) +EVT_MENU(IDM_UNDOLOADSTATE, CFrame::OnUndoLoadState) +EVT_MENU(IDM_UNDOSAVESTATE, CFrame::OnUndoSaveState) EVT_MENU(IDM_LOADSTATEFILE, CFrame::OnLoadStateFromFile) EVT_MENU(IDM_SAVESTATEFILE, CFrame::OnSaveStateToFile) diff --git a/Source/Core/DolphinWX/Src/Frame.h b/Source/Core/DolphinWX/Src/Frame.h index 08d0c96198..209daf0d60 100644 --- a/Source/Core/DolphinWX/Src/Frame.h +++ b/Source/Core/DolphinWX/Src/Frame.h @@ -188,7 +188,8 @@ class CFrame : public wxFrame void OnLoadStateFromFile(wxCommandEvent& event); void OnSaveStateToFile(wxCommandEvent& event); void OnLoadLastState(wxCommandEvent& event); - void OnUndoState(wxCommandEvent& event); + void OnUndoLoadState(wxCommandEvent& event); + void OnUndoSaveState(wxCommandEvent& event); void OnConfigMain(wxCommandEvent& event); // Options void OnPluginGFX(wxCommandEvent& event); diff --git a/Source/Core/DolphinWX/Src/FrameTools.cpp b/Source/Core/DolphinWX/Src/FrameTools.cpp index ffe0d54d54..df01d7a6a8 100644 --- a/Source/Core/DolphinWX/Src/FrameTools.cpp +++ b/Source/Core/DolphinWX/Src/FrameTools.cpp @@ -137,11 +137,12 @@ void CFrame::CreateMenu() m_pSubMenuSave = emulationMenu->AppendSubMenu(saveMenu, _T("Sa&ve State")); saveMenu->Append(IDM_SAVESTATEFILE, _T("Save State...")); + loadMenu->Append(IDM_UNDOSAVESTATE, _T("Last Overwritten State\tShift+F12")); saveMenu->AppendSeparator(); loadMenu->Append(IDM_LOADSTATEFILE, _T("Load State...")); loadMenu->Append(IDM_LOADLASTSTATE, _T("Last Saved State\tF11")); - loadMenu->Append(IDM_UNDOSTATE, _T("Last Overwritten State\tF12")); + loadMenu->Append(IDM_UNDOLOADSTATE, _T("Undo Load State\tF12")); loadMenu->AppendSeparator(); for (int i = 1; i <= 8; i++) { @@ -716,11 +717,17 @@ void CFrame::OnLoadLastState(wxCommandEvent& WXUNUSED (event)) State_LoadLastSaved(); } -void CFrame::OnUndoState(wxCommandEvent& WXUNUSED (event)) +void CFrame::OnUndoLoadState(wxCommandEvent& WXUNUSED (event)) { - State_LoadAs(FULL_STATESAVES_DIR "lastState.sav"); + State_UndoLoadState(); } +void CFrame::OnUndoSaveState(wxCommandEvent& WXUNUSED (event)) +{ + State_UndoSaveState(); +} + + void CFrame::OnLoadState(wxCommandEvent& event) { int id = event.GetId(); diff --git a/Source/Core/DolphinWX/Src/Globals.h b/Source/Core/DolphinWX/Src/Globals.h index 819b24337b..3db47415b0 100644 --- a/Source/Core/DolphinWX/Src/Globals.h +++ b/Source/Core/DolphinWX/Src/Globals.h @@ -32,7 +32,8 @@ enum IDM_LOADSTATE = 200, // File menu IDM_SAVESTATE, IDM_LOADLASTSTATE, - IDM_UNDOSTATE, + IDM_UNDOLOADSTATE, + IDM_UNDOSAVESTATE, IDM_LOADSTATEFILE, IDM_SAVESTATEFILE, IDM_SAVESLOT1,