From 46b0fd3c9633f86becd679460c53ec68664d6370 Mon Sep 17 00:00:00 2001 From: "XTra.KrazzY" Date: Fri, 26 Jun 2009 22:36:44 +0000 Subject: [PATCH] 1. TAS Groundwork: Saving the state (compression and memory dump to file) is now done on a separate thread (thread-safe). Now state saving is silent and quick. 2. When stopping, GUI doesn't let the user choose another game and effectively crash Dolphin 3. Omitted an unneeded loop in AudioCommon git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3552 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/AudioCommon/Src/AudioCommon.cpp | 7 --- Source/Core/Core/Src/Core.cpp | 21 ++++---- Source/Core/Core/Src/Core.h | 2 + Source/Core/Core/Src/State.cpp | 59 ++++++++++++++++----- Source/Core/Core/Src/State.h | 6 +++ Source/Core/DolphinWX/Src/FrameTools.cpp | 22 +++----- 6 files changed, 72 insertions(+), 45 deletions(-) diff --git a/Source/Core/AudioCommon/Src/AudioCommon.cpp b/Source/Core/AudioCommon/Src/AudioCommon.cpp index 196ca37fdb..9e7100451a 100644 --- a/Source/Core/AudioCommon/Src/AudioCommon.cpp +++ b/Source/Core/AudioCommon/Src/AudioCommon.cpp @@ -70,13 +70,6 @@ namespace AudioCommon delete soundStream; soundStream = NULL; } - - // Check that soundstream already is stopped. - while (soundStream) - { - ERROR_LOG(DSPHLE, "Waiting for sound stream"); - Common::SleepCurrentThread(2000); - } INFO_LOG(DSPHLE, "Done shutting down sound stream"); } diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp index ed12462e67..71e071667b 100644 --- a/Source/Core/Core/Src/Core.cpp +++ b/Source/Core/Core/Src/Core.cpp @@ -184,7 +184,10 @@ void ReconnectWiimote() #endif - +bool isRunning() +{ + return (GetState() != CORE_UNINITIALIZED) || g_bHwInit; +} // This is called from the GUI thread. See the booting call schedule in BootManager.cpp @@ -563,25 +566,23 @@ void EmuThreadEnd() } #endif - // The hardware is uninitialized - g_bHwInit = false; - HW::Shutdown(); Plugins.ShutdownPlugins(); + // The hardware is uninitialized + g_bHwInit = false; + INFO_LOG(MASTER_LOG, "EmuThread exited"); - // The CPU should return when a game is stopped and cleanup should be done here, - // so we can restart the plugins (or load new ones) for the next game. - if (_CoreParameter.hMainWindow == g_pWindowHandle) - Host_UpdateMainFrame(); + + Host_UpdateMainFrame(); + #ifdef SETUP_TIMER_WAITING EmuThreadReachedEnd = true; Host_UpdateGUI(); INFO_LOG(CONSOLE, "Stop [Video Thread]: Done\n"); delete g_EmuThread; // Wait for emuthread to close. g_EmuThread = 0; -#endif -#ifndef SETUP_TIMER_WAITING +#else return 0; #endif } diff --git a/Source/Core/Core/Src/Core.h b/Source/Core/Core/Src/Core.h index 59f0d1aeac..cd018b9529 100644 --- a/Source/Core/Core/Src/Core.h +++ b/Source/Core/Core/Src/Core.h @@ -43,6 +43,8 @@ namespace Core // Init core bool Init(); void Stop(); + + bool isRunning(); void SetState(EState _State); EState GetState(); diff --git a/Source/Core/Core/Src/State.cpp b/Source/Core/Core/Src/State.cpp index 997556a810..5bac051599 100644 --- a/Source/Core/Core/Src/State.cpp +++ b/Source/Core/Core/Src/State.cpp @@ -78,26 +78,21 @@ void DoState(PointerWrap &p) CoreTiming::DoState(p); } -void SaveStateCallback(u64 userdata, int cyclesLate) +THREAD_RETURN CompressAndDumpState(void *pArgs) { + saveStruct *saveArg = (saveStruct *)pArgs; + u8 *buffer = saveArg->buffer; + size_t sz = saveArg->size; lzo_uint out_len = 0; + delete saveArg; + FILE *f = fopen(cur_filename.c_str(), "wb"); if(f == NULL) { Core::DisplayMessage("Could not save state", 2000); - return; + return 0; } - jit.ClearCache(); - u8 *ptr = 0; - PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); - DoState(p); - size_t sz = (size_t)ptr; - u8 *buffer = new u8[sz]; - ptr = buffer; - p.SetMode(PointerWrap::MODE_WRITE); - DoState(p); - if (bCompressed) { fwrite(&sz, sizeof(int), 1, f); } else { @@ -139,7 +134,39 @@ void SaveStateCallback(u64 userdata, int cyclesLate) delete [] buffer; Core::DisplayMessage(StringFromFormat("Saved State to %s", - cur_filename.c_str()).c_str(), 2000); + cur_filename.c_str()).c_str(), 2000); + + return 0; +} + +Common::Thread *saveThread = NULL; + +void SaveStateCallback(u64 userdata, int cyclesLate) +{ + // If already saving state, wait for it to finish + if(saveThread) + { + delete saveThread; + saveThread = NULL; + } + + jit.ClearCache(); + u8 *ptr = 0; + PointerWrap p(&ptr, PointerWrap::MODE_MEASURE); + DoState(p); + size_t sz = (size_t)ptr; + u8 *buffer = new u8[sz]; + ptr = buffer; + p.SetMode(PointerWrap::MODE_WRITE); + DoState(p); + + saveStruct *saveData = new saveStruct; + saveData->buffer = buffer; + saveData->size = sz; + + Core::DisplayMessage("Saving State...", 1000); + + saveThread = new Common::Thread(CompressAndDumpState, saveData); } void LoadStateCallback(u64 userdata, int cyclesLate) @@ -214,7 +241,11 @@ void State_Init() void State_Shutdown() { - // nothing to do, here for consistency. + if(saveThread) + { + delete saveThread; + saveThread = NULL; + } } std::string MakeStateFilename(int state_number) diff --git a/Source/Core/Core/Src/State.h b/Source/Core/Core/Src/State.h index 6254a5a7fe..19313b2c85 100644 --- a/Source/Core/Core/Src/State.h +++ b/Source/Core/Core/Src/State.h @@ -28,4 +28,10 @@ void State_Shutdown(); void State_Save(int slot); void State_Load(int slot); +typedef struct +{ + u8 *buffer; + size_t size; +} saveStruct; + #endif diff --git a/Source/Core/DolphinWX/Src/FrameTools.cpp b/Source/Core/DolphinWX/Src/FrameTools.cpp index 091865f79e..d7cda0e5dd 100644 --- a/Source/Core/DolphinWX/Src/FrameTools.cpp +++ b/Source/Core/DolphinWX/Src/FrameTools.cpp @@ -584,19 +584,13 @@ void CFrame::DoStop() Core::Stop(); - /* - This is needed together with the option to not "delete g_EmuThread" in Core.cpp, because then - we have to wait a moment before GetState() == CORE_UNINITIALIZED so that UpdateGUI() works. - It's also needed when a WaitForSingleObject() has timed out so that the ShutDown() process - has continued without all threads having come to a rest. It's not compatible with the - SETUP_TIMER_WAITING option (because the Stop returns before it's finished). - - Without this we just see the gray CPanel background because the ISO list will not be displayed. - */ - #ifndef SETUP_TIMER_WAITING - if (bRenderToMain) - while(Core::GetState() != Core::CORE_UNINITIALIZED) SLEEP(10); - #endif +#ifdef SETUP_TIMER_WAITING + // Idle-wait for core to completely shut down (without this wait the + // GameCtrlPanel is restored to a state where we can open another game + // and effectively crash Dolphin) + while(Core::isRunning()) + SLEEP(10); +#endif UpdateGUI(); } @@ -828,7 +822,7 @@ void CFrame::UpdateGUI() #endif // Save status - bool initialized = Core::GetState() != Core::CORE_UNINITIALIZED; + bool initialized = Core::isRunning(); bool running = Core::GetState() == Core::CORE_RUN; bool paused = Core::GetState() == Core::CORE_PAUSE;