Attempt to workaround some stop hangs by using MsgWait instead of Wait. change order of dsp / video shutdown. some comments.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2379 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
a32e29aaa5
commit
68f5cc1873
|
@ -133,18 +133,60 @@ void Event::Shutdown()
|
||||||
m_hEvent = 0;
|
m_hEvent = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Event::Set()
|
void Event::Set()
|
||||||
{
|
{
|
||||||
SetEvent(m_hEvent);
|
SetEvent(m_hEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Event::Wait()
|
void Event::Wait()
|
||||||
{
|
{
|
||||||
WaitForSingleObject(m_hEvent, INFINITE);
|
WaitForSingleObject(m_hEvent, INFINITE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline HRESULT MsgWaitForSingleObject(HANDLE handle, DWORD timeout)
|
||||||
|
{
|
||||||
|
return MsgWaitForMultipleObjects(1, &handle, FALSE, timeout, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Event::MsgWait()
|
||||||
|
{
|
||||||
|
// Adapted from MSDN example http://msdn.microsoft.com/en-us/library/ms687060.aspx
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
DWORD result;
|
||||||
|
MSG msg;
|
||||||
|
// Read all of the messages in this next loop,
|
||||||
|
// removing each message as we read it.
|
||||||
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
||||||
|
{
|
||||||
|
// If it is a quit message, exit.
|
||||||
|
if (msg.message == WM_QUIT)
|
||||||
|
return;
|
||||||
|
// Otherwise, dispatch the message.
|
||||||
|
DispatchMessage(&msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for any message sent or posted to this queue
|
||||||
|
// or for one of the passed handles be set to signaled.
|
||||||
|
result = MsgWaitForSingleObject(m_hEvent, INFINITE);
|
||||||
|
|
||||||
|
// The result tells us the type of event we have.
|
||||||
|
if (result == (WAIT_OBJECT_0 + 1))
|
||||||
|
{
|
||||||
|
// New messages have arrived.
|
||||||
|
// Continue to the top of the always while loop to
|
||||||
|
// dispatch them and resume waiting.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// result == WAIT_OBJECT_0
|
||||||
|
// Our event got signaled
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////
|
/////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -98,6 +98,11 @@ public:
|
||||||
|
|
||||||
void Set();
|
void Set();
|
||||||
void Wait();
|
void Wait();
|
||||||
|
#ifdef _WIN32
|
||||||
|
void MsgWait();
|
||||||
|
#else
|
||||||
|
void MsgWait() {Wait();}
|
||||||
|
#endif
|
||||||
|
|
||||||
// -----------------------------------------
|
// -----------------------------------------
|
||||||
#ifdef SETUP_TIMER_WAITING
|
#ifdef SETUP_TIMER_WAITING
|
||||||
|
|
|
@ -227,7 +227,7 @@ bool Init()
|
||||||
emuThreadGoing.Init();
|
emuThreadGoing.Init();
|
||||||
// This will execute EmuThread() further down in this file
|
// This will execute EmuThread() further down in this file
|
||||||
g_EmuThread = new Common::Thread(EmuThread, NULL);
|
g_EmuThread = new Common::Thread(EmuThread, NULL);
|
||||||
emuThreadGoing.Wait();
|
emuThreadGoing.MsgWait();
|
||||||
emuThreadGoing.Shutdown();
|
emuThreadGoing.Shutdown();
|
||||||
#ifdef SETUP_TIMER_WAITING
|
#ifdef SETUP_TIMER_WAITING
|
||||||
VideoThreadRunning = true;
|
VideoThreadRunning = true;
|
||||||
|
@ -254,29 +254,27 @@ void Stop()
|
||||||
StopReachedEnd = false;
|
StopReachedEnd = false;
|
||||||
EmuThreadReachedEnd = false;
|
EmuThreadReachedEnd = false;
|
||||||
#endif
|
#endif
|
||||||
|
Host_SetWaitCursor(true); // hourglass!
|
||||||
Host_SetWaitCursor(true);
|
|
||||||
if (PowerPC::GetState() == PowerPC::CPU_POWERDOWN)
|
if (PowerPC::GetState() == PowerPC::CPU_POWERDOWN)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Stop the CPU
|
// Stop the CPU
|
||||||
PowerPC::Stop();
|
PowerPC::Stop();
|
||||||
CCPU::StepOpcode(); // Kick it if it's waiting
|
CCPU::StepOpcode(); // Kick it if it's waiting (code stepping wait loop)
|
||||||
|
|
||||||
|
// Wait until the CPU finishes exiting the main run loop
|
||||||
cpuRunloopQuit.Wait();
|
cpuRunloopQuit.Wait();
|
||||||
cpuRunloopQuit.Shutdown();
|
cpuRunloopQuit.Shutdown();
|
||||||
// At this point, we must be out of the CPU:s runloop.
|
// At this point, we must be out of the CPU:s runloop.
|
||||||
|
|
||||||
// Silence audio - stops audio thread.
|
// Stop audio thread.
|
||||||
CPluginManager::GetInstance().GetDSP()->DSP_StopSoundStream();
|
CPluginManager::GetInstance().GetDSP()->DSP_StopSoundStream();
|
||||||
|
|
||||||
// If dual core mode, the CPU thread should immediately exit here.
|
// If dual core mode, the CPU thread should immediately exit here.
|
||||||
|
if (_CoreParameter.bUseDualCore) {
|
||||||
Console::Print("Stop [Main Thread]: Wait for Video Loop...\n");
|
Console::Print("Stop [Main Thread]: Wait for Video Loop to exit...\n");
|
||||||
|
|
||||||
// Should be moved inside the plugin.
|
|
||||||
if (_CoreParameter.bUseDualCore)
|
|
||||||
CPluginManager::GetInstance().GetVideo()->Video_ExitLoop();
|
CPluginManager::GetInstance().GetVideo()->Video_ExitLoop();
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef SETUP_TIMER_WAITING
|
#ifdef SETUP_TIMER_WAITING
|
||||||
StopUpToVideoDone = true;
|
StopUpToVideoDone = true;
|
||||||
|
@ -288,15 +286,8 @@ void Stop()
|
||||||
//Console::Print("Stop() will continue\n");
|
//Console::Print("Stop() will continue\n");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Video_EnterLoop() should now exit so that EmuThread() will continue concurrently with the rest
|
// Video_EnterLoop() should now exit so that EmuThread() will continue concurrently with the rest
|
||||||
of the commands in this function */
|
// of the commands in this function. We no longer rely on Postmessage. */
|
||||||
|
|
||||||
/* The quit is to get it out of its message loop. There is no guarantee of when this will occur though.
|
|
||||||
And since we have no while(GetMessage()) loop we can't wait for this to happen, or say exactly when
|
|
||||||
the loop has ended */
|
|
||||||
#ifdef _WIN32
|
|
||||||
//PostMessage((HWND)g_pWindowHandle, WM_QUIT, 0, 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Close the trace file
|
// Close the trace file
|
||||||
Core::StopTrace();
|
Core::StopTrace();
|
||||||
|
@ -530,7 +521,6 @@ THREAD_RETURN EmuThread(void *pArg)
|
||||||
cpuThread = new Common::Thread(CpuThread, pArg);
|
cpuThread = new Common::Thread(CpuThread, pArg);
|
||||||
Common::SetCurrentThreadName("Video thread");
|
Common::SetCurrentThreadName("Video thread");
|
||||||
|
|
||||||
// I bet that many of our stopping problems come from this loop not properly exiting.
|
|
||||||
Plugins.GetVideo()->Video_EnterLoop();
|
Plugins.GetVideo()->Video_EnterLoop();
|
||||||
}
|
}
|
||||||
#ifdef SETUP_TIMER_WAITING
|
#ifdef SETUP_TIMER_WAITING
|
||||||
|
|
|
@ -82,9 +82,10 @@ bool SCoreStartupParameter::AutoSetup(EBootBios _BootBios)
|
||||||
DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(m_strFilename.c_str());
|
DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(m_strFilename.c_str());
|
||||||
if (pVolume == NULL)
|
if (pVolume == NULL)
|
||||||
{
|
{
|
||||||
|
PanicAlert(bootDrive ?
|
||||||
PanicAlert(bootDrive ? "Drive could not be mounted" :
|
"Disc in %s could not be read - no disc, or not a GC/Wii backup.\n"
|
||||||
"Your GCM/ISO file seems to be invalid, or not a GC/Wii ISO." );
|
"Please note that original Gamecube and Wii discs cannot be read by most PC DVD drives.":
|
||||||
|
"Your GCM/ISO file seems to be invalid, or not a GC/Wii ISO.", m_strFilename.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
m_strName = pVolume->GetName();
|
m_strName = pVolume->GetName();
|
||||||
|
|
|
@ -208,17 +208,6 @@ void CPluginManager::ShutdownPlugins()
|
||||||
//m_wiimote[i] = NULL;
|
//m_wiimote[i] = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_video)
|
|
||||||
{
|
|
||||||
m_video->Shutdown();
|
|
||||||
// With this option, this is done on boot instead
|
|
||||||
#ifndef SETUP_DONT_FREE_PLUGIN_ON_STOP
|
|
||||||
delete m_video;
|
|
||||||
m_video = NULL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (m_dsp)
|
if (m_dsp)
|
||||||
{
|
{
|
||||||
m_dsp->Shutdown();
|
m_dsp->Shutdown();
|
||||||
|
@ -228,6 +217,16 @@ void CPluginManager::ShutdownPlugins()
|
||||||
m_dsp = NULL;
|
m_dsp = NULL;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_video)
|
||||||
|
{
|
||||||
|
m_video->Shutdown();
|
||||||
|
// With this option, this is done on boot instead
|
||||||
|
#ifndef SETUP_DONT_FREE_PLUGIN_ON_STOP
|
||||||
|
delete m_video;
|
||||||
|
m_video = NULL;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//////////////////////////////////////////////
|
//////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,6 @@ EDiscType GetDiscType(IBlobReader& _rReader);
|
||||||
IVolume* CreateVolumeFromFilename(const std::string& _rFilename)
|
IVolume* CreateVolumeFromFilename(const std::string& _rFilename)
|
||||||
{
|
{
|
||||||
IBlobReader* pReader = CreateBlobReader(_rFilename.c_str());
|
IBlobReader* pReader = CreateBlobReader(_rFilename.c_str());
|
||||||
|
|
||||||
if (pReader == NULL)
|
if (pReader == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ extern u8* g_pVideoData;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
static bool fifoStateRun = false;
|
static volatile bool fifoStateRun = false;
|
||||||
static u8 *videoBuffer;
|
static u8 *videoBuffer;
|
||||||
static Common::Event fifo_exit_event;
|
static Common::Event fifo_exit_event;
|
||||||
// STATE_TO_SAVE
|
// STATE_TO_SAVE
|
||||||
|
@ -97,11 +97,16 @@ void Video_SendFifoData(u8* _uData, u32 len)
|
||||||
OpcodeDecoder_Run();
|
OpcodeDecoder_Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Executed from another thread, no the graphics thread!
|
||||||
|
// Basically, all it does is set a flag so that the loop will eventually exit, then
|
||||||
|
// waits for the event to be set, which happens when the loop does exit.
|
||||||
|
// If we look stuck in here, then the video thread is stuck in something and won't exit
|
||||||
|
// the loop. Switch to the video thread and investigate.
|
||||||
void Fifo_ExitLoop()
|
void Fifo_ExitLoop()
|
||||||
{
|
{
|
||||||
fifoStateRun = false;
|
fifoStateRun = false;
|
||||||
#ifndef SETUP_TIMER_WAITING
|
#ifndef SETUP_TIMER_WAITING
|
||||||
fifo_exit_event.Wait();
|
fifo_exit_event.MsgWait();
|
||||||
fifo_exit_event.Shutdown();
|
fifo_exit_event.Shutdown();
|
||||||
#else
|
#else
|
||||||
//Console::Print("Video: Fifo_ExitLoop: Done:%i\n", fifo_exit_event.DoneWait());
|
//Console::Print("Video: Fifo_ExitLoop: Done:%i\n", fifo_exit_event.DoneWait());
|
||||||
|
@ -114,6 +119,7 @@ void Fifo_ExitLoop()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
||||||
{
|
{
|
||||||
fifoStateRun = true;
|
fifoStateRun = true;
|
||||||
|
|
|
@ -154,6 +154,9 @@ void Shutdown()
|
||||||
glDeleteTextures(1, &s_srcTexture);
|
glDeleteTextures(1, &s_srcTexture);
|
||||||
glDeleteRenderbuffersEXT(1, &s_dstRenderBuffer);
|
glDeleteRenderbuffersEXT(1, &s_dstRenderBuffer);
|
||||||
glDeleteFramebuffersEXT(1, &s_texConvFrameBuffer);
|
glDeleteFramebuffersEXT(1, &s_texConvFrameBuffer);
|
||||||
|
s_srcTexture = 0;
|
||||||
|
s_dstRenderBuffer = 0;
|
||||||
|
s_texConvFrameBuffer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EncodeToRam(GLuint srcTexture, const TRectangle& sourceRc,
|
void EncodeToRam(GLuint srcTexture, const TRectangle& sourceRc,
|
||||||
|
|
Loading…
Reference in New Issue