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

@ -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");
}

View File

@ -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
}

View File

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

View File

@ -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)

View File

@ -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

View File

@ -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;