From 68f5cc1873e637df12ab03c5b43f6121c59dcb4f Mon Sep 17 00:00:00 2001 From: hrydgard Date: Sun, 22 Feb 2009 22:49:42 +0000 Subject: [PATCH] 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 --- Source/Core/Common/Src/Thread.cpp | 48 +++++++++++++++++-- Source/Core/Common/Src/Thread.h | 5 ++ Source/Core/Core/Src/Core.cpp | 30 ++++-------- Source/Core/Core/Src/CoreParameter.cpp | 7 +-- Source/Core/Core/Src/PluginManager.cpp | 21 ++++---- Source/Core/DiscIO/Src/VolumeCreator.cpp | 1 - Source/Core/VideoCommon/Src/Fifo.cpp | 10 +++- .../Plugins/Plugin_VideoOGL/Src/OS/Win32.cpp | 4 +- .../Plugin_VideoOGL/Src/TextureConverter.cpp | 7 ++- 9 files changed, 89 insertions(+), 44 deletions(-) diff --git a/Source/Core/Common/Src/Thread.cpp b/Source/Core/Common/Src/Thread.cpp index a5c4e53cc6..7057a137ac 100644 --- a/Source/Core/Common/Src/Thread.cpp +++ b/Source/Core/Common/Src/Thread.cpp @@ -133,18 +133,60 @@ void Event::Shutdown() m_hEvent = 0; } - - void Event::Set() { SetEvent(m_hEvent); } - void Event::Wait() { 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; + } + } +} + ///////////////////////////////////// diff --git a/Source/Core/Common/Src/Thread.h b/Source/Core/Common/Src/Thread.h index 1787b9cc53..b2d5274196 100644 --- a/Source/Core/Common/Src/Thread.h +++ b/Source/Core/Common/Src/Thread.h @@ -98,6 +98,11 @@ public: void Set(); void Wait(); +#ifdef _WIN32 + void MsgWait(); +#else + void MsgWait() {Wait();} +#endif // ----------------------------------------- #ifdef SETUP_TIMER_WAITING diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp index 7727852af9..5a04722434 100644 --- a/Source/Core/Core/Src/Core.cpp +++ b/Source/Core/Core/Src/Core.cpp @@ -227,7 +227,7 @@ bool Init() emuThreadGoing.Init(); // This will execute EmuThread() further down in this file g_EmuThread = new Common::Thread(EmuThread, NULL); - emuThreadGoing.Wait(); + emuThreadGoing.MsgWait(); emuThreadGoing.Shutdown(); #ifdef SETUP_TIMER_WAITING VideoThreadRunning = true; @@ -254,29 +254,27 @@ void Stop() StopReachedEnd = false; EmuThreadReachedEnd = false; #endif - - Host_SetWaitCursor(true); + Host_SetWaitCursor(true); // hourglass! if (PowerPC::GetState() == PowerPC::CPU_POWERDOWN) return; // Stop the CPU 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.Shutdown(); // 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(); // If dual core mode, the CPU thread should immediately exit here. - - Console::Print("Stop [Main Thread]: Wait for Video Loop...\n"); - - // Should be moved inside the plugin. - if (_CoreParameter.bUseDualCore) + if (_CoreParameter.bUseDualCore) { + Console::Print("Stop [Main Thread]: Wait for Video Loop to exit...\n"); CPluginManager::GetInstance().GetVideo()->Video_ExitLoop(); + } #ifdef SETUP_TIMER_WAITING StopUpToVideoDone = true; @@ -288,15 +286,8 @@ void Stop() //Console::Print("Stop() will continue\n"); #endif - /* Video_EnterLoop() should now exit so that EmuThread() will continue concurrently with the rest - of the commands in this function */ - - /* 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 + // Video_EnterLoop() should now exit so that EmuThread() will continue concurrently with the rest + // of the commands in this function. We no longer rely on Postmessage. */ // Close the trace file Core::StopTrace(); @@ -530,7 +521,6 @@ THREAD_RETURN EmuThread(void *pArg) cpuThread = new Common::Thread(CpuThread, pArg); Common::SetCurrentThreadName("Video thread"); - // I bet that many of our stopping problems come from this loop not properly exiting. Plugins.GetVideo()->Video_EnterLoop(); } #ifdef SETUP_TIMER_WAITING diff --git a/Source/Core/Core/Src/CoreParameter.cpp b/Source/Core/Core/Src/CoreParameter.cpp index b32e86ae8a..3934d80a3a 100644 --- a/Source/Core/Core/Src/CoreParameter.cpp +++ b/Source/Core/Core/Src/CoreParameter.cpp @@ -82,9 +82,10 @@ bool SCoreStartupParameter::AutoSetup(EBootBios _BootBios) DiscIO::IVolume* pVolume = DiscIO::CreateVolumeFromFilename(m_strFilename.c_str()); if (pVolume == NULL) { - - PanicAlert(bootDrive ? "Drive could not be mounted" : - "Your GCM/ISO file seems to be invalid, or not a GC/Wii ISO." ); + PanicAlert(bootDrive ? + "Disc in %s could not be read - no disc, or not a GC/Wii backup.\n" + "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; } m_strName = pVolume->GetName(); diff --git a/Source/Core/Core/Src/PluginManager.cpp b/Source/Core/Core/Src/PluginManager.cpp index 6f6b825053..846cec1fc7 100644 --- a/Source/Core/Core/Src/PluginManager.cpp +++ b/Source/Core/Core/Src/PluginManager.cpp @@ -208,17 +208,6 @@ void CPluginManager::ShutdownPlugins() //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) { m_dsp->Shutdown(); @@ -228,6 +217,16 @@ void CPluginManager::ShutdownPlugins() m_dsp = NULL; #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 + } } ////////////////////////////////////////////// diff --git a/Source/Core/DiscIO/Src/VolumeCreator.cpp b/Source/Core/DiscIO/Src/VolumeCreator.cpp index db03256412..bb1d785abe 100644 --- a/Source/Core/DiscIO/Src/VolumeCreator.cpp +++ b/Source/Core/DiscIO/Src/VolumeCreator.cpp @@ -72,7 +72,6 @@ EDiscType GetDiscType(IBlobReader& _rReader); IVolume* CreateVolumeFromFilename(const std::string& _rFilename) { IBlobReader* pReader = CreateBlobReader(_rFilename.c_str()); - if (pReader == NULL) return NULL; diff --git a/Source/Core/VideoCommon/Src/Fifo.cpp b/Source/Core/VideoCommon/Src/Fifo.cpp index 168d893cdd..8a502b5ef2 100644 --- a/Source/Core/VideoCommon/Src/Fifo.cpp +++ b/Source/Core/VideoCommon/Src/Fifo.cpp @@ -35,7 +35,7 @@ extern u8* g_pVideoData; namespace { -static bool fifoStateRun = false; +static volatile bool fifoStateRun = false; static u8 *videoBuffer; static Common::Event fifo_exit_event; // STATE_TO_SAVE @@ -97,11 +97,16 @@ void Video_SendFifoData(u8* _uData, u32 len) 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() { fifoStateRun = false; #ifndef SETUP_TIMER_WAITING - fifo_exit_event.Wait(); + fifo_exit_event.MsgWait(); fifo_exit_event.Shutdown(); #else //Console::Print("Video: Fifo_ExitLoop: Done:%i\n", fifo_exit_event.DoneWait()); @@ -114,6 +119,7 @@ void Fifo_ExitLoop() #endif } +// void Fifo_EnterLoop(const SVideoInitialize &video_initialize) { fifoStateRun = true; diff --git a/Source/Plugins/Plugin_VideoOGL/Src/OS/Win32.cpp b/Source/Plugins/Plugin_VideoOGL/Src/OS/Win32.cpp index 82dfc241b1..2662937517 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/OS/Win32.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/OS/Win32.cpp @@ -306,8 +306,8 @@ HWND OpenWindow(HWND parent, HINSTANCE hInstance, int width, int height, const T m_hWnd = CreateWindow(m_szClassName, title, WS_CHILD, - CW_USEDEFAULT, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT, - parent, NULL, hInstance, NULL ); + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, + parent, NULL, hInstance, NULL); ShowWindow(m_hWnd, SW_SHOWMAXIMIZED); } diff --git a/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.cpp b/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.cpp index 6ca7f4d3bb..827d49b01e 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.cpp @@ -134,7 +134,7 @@ FRAGMENTSHADER& GetOrCreateEncodingShader(u32 format) void Init() { - glGenFramebuffersEXT( 1, &s_texConvFrameBuffer); + glGenFramebuffersEXT(1, &s_texConvFrameBuffer); glGenRenderbuffersEXT(1, &s_dstRenderBuffer); glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_dstRenderBuffer); @@ -153,7 +153,10 @@ void Shutdown() { glDeleteTextures(1, &s_srcTexture); 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,