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
This commit is contained in:
XTra.KrazzY 2009-06-26 22:36:44 +00:00
parent 8a6fcdc2bc
commit 46b0fd3c96
6 changed files with 72 additions and 45 deletions

View File

@ -71,13 +71,6 @@ namespace AudioCommon
soundStream = NULL; 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"); INFO_LOG(DSPHLE, "Done shutting down sound stream");
} }

View File

@ -184,7 +184,10 @@ void ReconnectWiimote()
#endif #endif
bool isRunning()
{
return (GetState() != CORE_UNINITIALIZED) || g_bHwInit;
}
// This is called from the GUI thread. See the booting call schedule in BootManager.cpp // This is called from the GUI thread. See the booting call schedule in BootManager.cpp
@ -563,25 +566,23 @@ void EmuThreadEnd()
} }
#endif #endif
// The hardware is uninitialized
g_bHwInit = false;
HW::Shutdown(); HW::Shutdown();
Plugins.ShutdownPlugins(); Plugins.ShutdownPlugins();
// The hardware is uninitialized
g_bHwInit = false;
INFO_LOG(MASTER_LOG, "EmuThread exited"); 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. Host_UpdateMainFrame();
if (_CoreParameter.hMainWindow == g_pWindowHandle)
Host_UpdateMainFrame();
#ifdef SETUP_TIMER_WAITING #ifdef SETUP_TIMER_WAITING
EmuThreadReachedEnd = true; EmuThreadReachedEnd = true;
Host_UpdateGUI(); Host_UpdateGUI();
INFO_LOG(CONSOLE, "Stop [Video Thread]: Done\n"); INFO_LOG(CONSOLE, "Stop [Video Thread]: Done\n");
delete g_EmuThread; // Wait for emuthread to close. delete g_EmuThread; // Wait for emuthread to close.
g_EmuThread = 0; g_EmuThread = 0;
#endif #else
#ifndef SETUP_TIMER_WAITING
return 0; return 0;
#endif #endif
} }

View File

@ -44,6 +44,8 @@ namespace Core
bool Init(); bool Init();
void Stop(); void Stop();
bool isRunning();
void SetState(EState _State); void SetState(EState _State);
EState GetState(); EState GetState();

View File

@ -78,26 +78,21 @@ void DoState(PointerWrap &p)
CoreTiming::DoState(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; lzo_uint out_len = 0;
delete saveArg;
FILE *f = fopen(cur_filename.c_str(), "wb"); FILE *f = fopen(cur_filename.c_str(), "wb");
if(f == NULL) { if(f == NULL) {
Core::DisplayMessage("Could not save state", 2000); 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) { if (bCompressed) {
fwrite(&sz, sizeof(int), 1, f); fwrite(&sz, sizeof(int), 1, f);
} else { } else {
@ -139,7 +134,39 @@ void SaveStateCallback(u64 userdata, int cyclesLate)
delete [] buffer; delete [] buffer;
Core::DisplayMessage(StringFromFormat("Saved State to %s", 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) void LoadStateCallback(u64 userdata, int cyclesLate)
@ -214,7 +241,11 @@ void State_Init()
void State_Shutdown() void State_Shutdown()
{ {
// nothing to do, here for consistency. if(saveThread)
{
delete saveThread;
saveThread = NULL;
}
} }
std::string MakeStateFilename(int state_number) std::string MakeStateFilename(int state_number)

View File

@ -28,4 +28,10 @@ void State_Shutdown();
void State_Save(int slot); void State_Save(int slot);
void State_Load(int slot); void State_Load(int slot);
typedef struct
{
u8 *buffer;
size_t size;
} saveStruct;
#endif #endif

View File

@ -584,19 +584,13 @@ void CFrame::DoStop()
Core::Stop(); Core::Stop();
/* #ifdef SETUP_TIMER_WAITING
This is needed together with the option to not "delete g_EmuThread" in Core.cpp, because then // Idle-wait for core to completely shut down (without this wait the
we have to wait a moment before GetState() == CORE_UNINITIALIZED so that UpdateGUI() works. // GameCtrlPanel is restored to a state where we can open another game
It's also needed when a WaitForSingleObject() has timed out so that the ShutDown() process // and effectively crash Dolphin)
has continued without all threads having come to a rest. It's not compatible with the while(Core::isRunning())
SETUP_TIMER_WAITING option (because the Stop returns before it's finished). SLEEP(10);
#endif
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
UpdateGUI(); UpdateGUI();
} }
@ -828,7 +822,7 @@ void CFrame::UpdateGUI()
#endif #endif
// Save status // Save status
bool initialized = Core::GetState() != Core::CORE_UNINITIALIZED; bool initialized = Core::isRunning();
bool running = Core::GetState() == Core::CORE_RUN; bool running = Core::GetState() == Core::CORE_RUN;
bool paused = Core::GetState() == Core::CORE_PAUSE; bool paused = Core::GetState() == Core::CORE_PAUSE;