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
This commit is contained in:
XTra.KrazzY 2009-06-28 21:11:51 +00:00
parent e341985003
commit fd47eb7b44
7 changed files with 114 additions and 18 deletions

View File

@ -895,12 +895,10 @@ void Callback_KeyPress(int key, bool shift, bool control)
// 0x7a == VK_F12 // 0x7a == VK_F12
if (key == 0x7b) if (key == 0x7b)
{ {
// TODO: Move to memory buffer, implement last state before loading
if(shift) if(shift)
State_LoadAs(FULL_STATESAVES_DIR "lastState.sav"); State_UndoSaveState();
/*else else
State_LoadAs(FULL_STATESAVES_DIR "tempState.sav"); State_UndoLoadState();
*/
} }
} }

View File

@ -53,9 +53,15 @@ static int ev_Save, ev_BufferSave;
static int ev_Load, ev_BufferLoad; static int ev_Load, ev_BufferLoad;
static std::string cur_filename, lastFilename; 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 bool const bCompressed = true;
static Common::Thread *saveThread = NULL;
enum enum
{ {
version = 1, version = 1,
@ -79,6 +85,49 @@ void DoState(PointerWrap &p)
CoreTiming::DoState(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) THREAD_RETURN CompressAndDumpState(void *pArgs)
{ {
saveStruct *saveArg = (saveStruct *)pArgs; saveStruct *saveArg = (saveStruct *)pArgs;
@ -149,8 +198,6 @@ THREAD_RETURN CompressAndDumpState(void *pArgs)
return 0; return 0;
} }
Common::Thread *saveThread = NULL;
void SaveStateCallback(u64 userdata, int cyclesLate) void SaveStateCallback(u64 userdata, int cyclesLate)
{ {
// If already saving state, wait for it to finish // If already saving state, wait for it to finish
@ -193,6 +240,10 @@ void LoadStateCallback(u64 userdata, int cyclesLate)
saveThread = NULL; saveThread = NULL;
} }
// Save temp buffer for undo load state
cur_buffer = &undoLoad;
SaveBufferStateCallback(userdata, cyclesLate);
FILE *f = fopen(cur_filename.c_str(), "rb"); FILE *f = fopen(cur_filename.c_str(), "rb");
if (!f) { if (!f) {
Core::DisplayMessage("State not found", 2000); Core::DisplayMessage("State not found", 2000);
@ -270,6 +321,8 @@ void State_Init()
{ {
ev_Load = CoreTiming::RegisterEvent("LoadState", &LoadStateCallback); ev_Load = CoreTiming::RegisterEvent("LoadState", &LoadStateCallback);
ev_Save = CoreTiming::RegisterEvent("SaveState", &SaveStateCallback); ev_Save = CoreTiming::RegisterEvent("SaveState", &SaveStateCallback);
ev_BufferLoad = CoreTiming::RegisterEvent("LoadBufferState", &LoadBufferStateCallback);
ev_BufferSave = CoreTiming::RegisterEvent("SaveBufferState", &SaveBufferStateCallback);
} }
void State_Shutdown() void State_Shutdown()
@ -279,6 +332,12 @@ void State_Shutdown()
delete saveThread; delete saveThread;
saveThread = NULL; saveThread = NULL;
} }
if(undoLoad)
{
delete[] undoLoad;
undoLoad = NULL;
}
} }
std::string MakeStateFilename(int state_number) std::string MakeStateFilename(int state_number)
@ -316,3 +375,27 @@ void State_LoadLastSaved()
else else
State_LoadAs(lastFilename); 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");
}

View File

@ -20,6 +20,12 @@
#ifndef _STATE_H_ #ifndef _STATE_H_
#define _STATE_H_ #define _STATE_H_
typedef struct
{
u8 *buffer;
size_t size;
} saveStruct;
void State_Init(); void State_Init();
void State_Shutdown(); void State_Shutdown();
@ -32,12 +38,11 @@ void State_SaveAs(const std::string &filename);
void State_LoadAs(const std::string &filename); void State_LoadAs(const std::string &filename);
void State_LoadLastSaved(); void State_LoadLastSaved();
void State_UndoSaveState();
void State_UndoLoadState();
typedef struct void State_LoadFromBuffer(u8 **buffer);
{ void State_SaveToBuffer(u8 **buffer);
u8 *buffer;
size_t size;
} saveStruct;
typedef struct typedef struct

View File

@ -286,7 +286,8 @@ EVT_MENU(IDM_LISTUSA, CFrame::GameListChanged)
EVT_MENU(IDM_PURGECACHE, CFrame::GameListChanged) EVT_MENU(IDM_PURGECACHE, CFrame::GameListChanged)
EVT_MENU(IDM_LOADLASTSTATE, CFrame::OnLoadLastState) 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_LOADSTATEFILE, CFrame::OnLoadStateFromFile)
EVT_MENU(IDM_SAVESTATEFILE, CFrame::OnSaveStateToFile) EVT_MENU(IDM_SAVESTATEFILE, CFrame::OnSaveStateToFile)

View File

@ -188,7 +188,8 @@ class CFrame : public wxFrame
void OnLoadStateFromFile(wxCommandEvent& event); void OnLoadStateFromFile(wxCommandEvent& event);
void OnSaveStateToFile(wxCommandEvent& event); void OnSaveStateToFile(wxCommandEvent& event);
void OnLoadLastState(wxCommandEvent& event); void OnLoadLastState(wxCommandEvent& event);
void OnUndoState(wxCommandEvent& event); void OnUndoLoadState(wxCommandEvent& event);
void OnUndoSaveState(wxCommandEvent& event);
void OnConfigMain(wxCommandEvent& event); // Options void OnConfigMain(wxCommandEvent& event); // Options
void OnPluginGFX(wxCommandEvent& event); void OnPluginGFX(wxCommandEvent& event);

View File

@ -137,11 +137,12 @@ void CFrame::CreateMenu()
m_pSubMenuSave = emulationMenu->AppendSubMenu(saveMenu, _T("Sa&ve State")); m_pSubMenuSave = emulationMenu->AppendSubMenu(saveMenu, _T("Sa&ve State"));
saveMenu->Append(IDM_SAVESTATEFILE, _T("Save State...")); saveMenu->Append(IDM_SAVESTATEFILE, _T("Save State..."));
loadMenu->Append(IDM_UNDOSAVESTATE, _T("Last Overwritten State\tShift+F12"));
saveMenu->AppendSeparator(); saveMenu->AppendSeparator();
loadMenu->Append(IDM_LOADSTATEFILE, _T("Load State...")); loadMenu->Append(IDM_LOADSTATEFILE, _T("Load State..."));
loadMenu->Append(IDM_LOADLASTSTATE, _T("Last Saved State\tF11")); 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(); loadMenu->AppendSeparator();
for (int i = 1; i <= 8; i++) { for (int i = 1; i <= 8; i++) {
@ -716,11 +717,17 @@ void CFrame::OnLoadLastState(wxCommandEvent& WXUNUSED (event))
State_LoadLastSaved(); 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) void CFrame::OnLoadState(wxCommandEvent& event)
{ {
int id = event.GetId(); int id = event.GetId();

View File

@ -32,7 +32,8 @@ enum
IDM_LOADSTATE = 200, // File menu IDM_LOADSTATE = 200, // File menu
IDM_SAVESTATE, IDM_SAVESTATE,
IDM_LOADLASTSTATE, IDM_LOADLASTSTATE,
IDM_UNDOSTATE, IDM_UNDOLOADSTATE,
IDM_UNDOSAVESTATE,
IDM_LOADSTATEFILE, IDM_LOADSTATEFILE,
IDM_SAVESTATEFILE, IDM_SAVESTATEFILE,
IDM_SAVESLOT1, IDM_SAVESLOT1,