diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp index 635befa22d..3a0bac0d6d 100644 --- a/Source/Core/Core/Src/Core.cpp +++ b/Source/Core/Core/Src/Core.cpp @@ -102,7 +102,6 @@ SCoreStartupParameter g_CoreStartupParameter; // This event is set when the emuthread starts. Common::Event emuThreadGoing; Common::Event cpuRunloopQuit; -Common::Event gpuRunloopQuit; // Display messages and return values @@ -208,32 +207,32 @@ void Stop() // - Hammertime! if (PowerPC::GetState() == PowerPC::CPU_POWERDOWN) return; - WARN_LOG(CONSOLE, "%s", StopMessage(true, "Stop CPU").c_str()); - // Stop the CPU + WARN_LOG(CONSOLE, "%s", StopMessage(true, "Stop CPU").c_str()); PowerPC::Stop(); CCPU::StepOpcode(); // Kick it if it's waiting (code stepping wait loop) - // If dual core mode, the CPU thread should immediately exit here. if (_CoreParameter.bCPUThread) { + // 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. NOTICE_LOG(CONSOLE, "%s", StopMessage(true, "Wait for Video Loop to exit ...").c_str()); CPluginManager::GetInstance().GetVideo()->Video_ExitLoop(); - } - // 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. + // Wait until the CPU finishes exiting the main run loop + cpuRunloopQuit.Wait(); + } // Close the trace file Core::StopTrace(); - WARN_LOG(CONSOLE, "%s", StopMessage(true, "Shutting down core").c_str()); // Update mouse pointer Host_SetWaitCursor(false); WARN_LOG(CONSOLE, "%s", StopMessage(true, "Stopping Emu thread ...").c_str()); #ifdef _WIN32 - DWORD Wait = g_EmuThread->WaitForDeath(5000); + // The whole shutdown process shouldn't take more than ~200ms. 2000ms timeout is more than enough. + DWORD Wait = g_EmuThread->WaitForDeath(2000); switch(Wait) { case WAIT_ABANDONED: @@ -292,11 +291,9 @@ THREAD_RETURN CpuThread(void *pArg) CCPU::Run(); // The shutdown function of OpenGL is not thread safe - // So we have to do it here + // So we have to call the shutdown from the thread that started it. if (!_CoreParameter.bCPUThread) { - // Wait for GPU loop to exit - gpuRunloopQuit.Wait(); Plugins.ShutdownVideoPlugin(); } @@ -310,7 +307,6 @@ THREAD_RETURN CpuThread(void *pArg) THREAD_RETURN EmuThread(void *pArg) { cpuRunloopQuit.Init(); - gpuRunloopQuit.Init(); Common::SetCurrentThreadName("Emuthread - starting"); const SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter; @@ -320,7 +316,7 @@ THREAD_RETURN EmuThread(void *pArg) Common::Thread::SetCurrentThreadAffinity(2); // Force to second core INFO_LOG(OSREPORT, "Starting core = %s mode", _CoreParameter.bWii ? "Wii" : "Gamecube"); - INFO_LOG(OSREPORT, "CPU Thread seperate = %s", _CoreParameter.bCPUThread ? "Yes" : "No"); + INFO_LOG(OSREPORT, "CPU Thread separate = %s", _CoreParameter.bCPUThread ? "Yes" : "No"); HW::Init(); @@ -450,6 +446,11 @@ THREAD_RETURN EmuThread(void *pArg) Callback_PeekMessages(); Common::SleepCurrentThread(20); } + + // Wait for CpuThread to exit + NOTICE_LOG(CONSOLE, "%s", StopMessage(true, "Stopping CPU-GPU thread ...").c_str()); + cpuRunloopQuit.Wait(); + NOTICE_LOG(CONSOLE, "%s", StopMessage(true, "CPU thread stopped.").c_str()); #else // On unix platforms, the Emulation main thread IS the CPU & video thread // So there's only one thread, imho, that's much better than on windows :P @@ -457,18 +458,16 @@ THREAD_RETURN EmuThread(void *pArg) #endif } - NOTICE_LOG(CONSOLE, "%s", StopMessage(false, "Stop() and Video Loop Ended").c_str()); // We have now exited the Video Loop - gpuRunloopQuit.Set(); - // Wait for cpu loop to exit - cpuRunloopQuit.Wait(); + NOTICE_LOG(CONSOLE, "%s", StopMessage(false, "Stop() and Video Loop Ended").c_str()); + // At this point, the CpuThread has already returned in SC mode. + // But it may still be waiting in Dual Core mode. if (cpuThread) { - NOTICE_LOG(CONSOLE, "%s", StopMessage(true, "Stopping CPU thread ...").c_str()); // There is a CPU thread - join it. -#ifdef _WIN32 - DWORD Wait = cpuThread->WaitForDeath(3000); +#ifdef _WIN32 + DWORD Wait = cpuThread->WaitForDeath(1000); switch(Wait) { case WAIT_ABANDONED: @@ -479,7 +478,7 @@ THREAD_RETURN EmuThread(void *pArg) break; case WAIT_TIMEOUT: ERROR_LOG(CONSOLE, "%s", StopMessage(true, "CPU wait returned: WAIT_TIMEOUT").c_str()); - break; + break; case WAIT_FAILED: ERROR_LOG(CONSOLE, "%s", StopMessage(true, "CPU wait returned: WAIT_FAILED").c_str()); break; @@ -491,30 +490,29 @@ THREAD_RETURN EmuThread(void *pArg) // Returns after game exited cpuThread = NULL; } + + // Stop audio thread - Actually this does nothing on HLE plugin. + // But stops the DSP Interpreter on LLE plugin. + Plugins.GetDSP()->DSP_StopSoundStream(); // We must set up this flag before executing HW::Shutdown() g_bHwInit = false; - - // Stop audio thread. - Plugins.GetDSP()->DSP_StopSoundStream(); - - // For single core mode, video plugin is already shut down - // but doing it again doesn't hurt - Plugins.ShutdownVideoPlugin(); - - WARN_LOG(CONSOLE, "%s", StopMessage(false, "Shutting down plugins").c_str()); - Plugins.ShutdownPlugins(); - NOTICE_LOG(CONSOLE, "%s", StopMessage(false, "Plugins shutdown").c_str()); - NOTICE_LOG(CONSOLE, "%s", StopMessage(false, "Shutting down HW").c_str()); HW::Shutdown(); NOTICE_LOG(CONSOLE, "%s", StopMessage(false, "HW shutdown").c_str()); + WARN_LOG(CONSOLE, "%s", StopMessage(false, "Shutting down plugins").c_str()); + // In single core mode, this has already been called. + if (_CoreParameter.bCPUThread) + Plugins.ShutdownVideoPlugin(); + + Plugins.ShutdownPlugins(); + NOTICE_LOG(CONSOLE, "%s", StopMessage(false, "Plugins shutdown").c_str()); + NOTICE_LOG(CONSOLE, "%s", StopMessage(true, "Main thread stopped").c_str()); NOTICE_LOG(CONSOLE, "Stop [Main Thread]\t\t---- Shutdown complete ----"); cpuRunloopQuit.Shutdown(); - gpuRunloopQuit.Shutdown(); g_bStopping = false; return 0; } diff --git a/Source/Core/DolphinWX/Src/FrameTools.cpp b/Source/Core/DolphinWX/Src/FrameTools.cpp index 08173cbb70..deff0c298c 100644 --- a/Source/Core/DolphinWX/Src/FrameTools.cpp +++ b/Source/Core/DolphinWX/Src/FrameTools.cpp @@ -654,11 +654,6 @@ void CFrame::OnScreenshot(wxCommandEvent& WXUNUSED (event)) // Stop the emulation void CFrame::DoStop() { - // Rerecording - #ifdef RERECORDING - Core::RerecordingStop(); - #endif - if (Core::GetState() != Core::CORE_UNINITIALIZED) { // Ask for confirmation in case the user accidently clicked Stop / Escape @@ -674,6 +669,9 @@ void CFrame::DoStop() Core::Stop(); UpdateGUI(); + + // Clean framerate indications from the status bar. + m_pStatusBar->SetStatusText(wxT(" "), 0); } } diff --git a/Source/Core/DolphinWX/Src/Main.cpp b/Source/Core/DolphinWX/Src/Main.cpp index 66ceb92b5f..6ed104891d 100644 --- a/Source/Core/DolphinWX/Src/Main.cpp +++ b/Source/Core/DolphinWX/Src/Main.cpp @@ -661,11 +661,7 @@ void Host_SetWiiMoteConnectionState(int _State) case 2: event.SetString(wxString::FromAscii("Wiimote Connected")); break; } // Update field 1 or 2 - #ifdef RERECORDING - event.SetInt(2); - #else - event.SetInt(1); - #endif + event.SetInt(1); main_frame->AddPendingEvent(event); } diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/main.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/main.cpp index 0a1dc4d508..edc9aee5b6 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/main.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/main.cpp @@ -176,26 +176,24 @@ void DllConfig(HWND _hParent) g_Config.GameIniLoad(globals->game_ini); if (!m_ConfigFrame) - m_ConfigFrame = new DSPConfigDialogHLE(GetParentedWxWindow(_hParent)); - else if (!m_ConfigFrame->GetParent()->IsShown()) - m_ConfigFrame->Close(true); - - m_ConfigFrame->ClearBackends(); - - // add backends - std::vector backends = AudioCommon::GetSoundBackends(); - - for (std::vector::const_iterator iter = backends.begin(); - iter != backends.end(); ++iter) { - m_ConfigFrame->AddBackend((*iter).c_str()); - } + m_ConfigFrame = new DSPConfigDialogHLE(GetParentedWxWindow(_hParent)); - // Only allow one open at a time - if (!m_ConfigFrame->IsShown()) + // add backends + std::vector backends = AudioCommon::GetSoundBackends(); + + for (std::vector::const_iterator iter = backends.begin(); + iter != backends.end(); ++iter) + { + m_ConfigFrame->AddBackend((*iter).c_str()); + } + + // Only allow one open at a time m_ConfigFrame->ShowModal(); - else - m_ConfigFrame->Hide(); + + delete m_ConfigFrame; + m_ConfigFrame = 0; + } #endif } @@ -358,5 +356,5 @@ void DSP_SendAIBuffer(unsigned int address, unsigned int num_samples) void DSP_ClearAudioBuffer() { if (soundStream) - soundStream->Clear(*g_dspInitialize.pEmulatorState); + soundStream->Clear(!!*g_dspInitialize.pEmulatorState); } diff --git a/Source/Plugins/Plugin_DSP_LLE/Src/main.cpp b/Source/Plugins/Plugin_DSP_LLE/Src/main.cpp index 982fed7deb..e6b62c46a3 100644 --- a/Source/Plugins/Plugin_DSP_LLE/Src/main.cpp +++ b/Source/Plugins/Plugin_DSP_LLE/Src/main.cpp @@ -142,24 +142,24 @@ void DllConfig(HWND _hParent) { #if defined(HAVE_WX) && HAVE_WX if (!m_ConfigFrame) + { m_ConfigFrame = new DSPConfigDialogLLE(GetParentedWxWindow(_hParent)); - else if (!m_ConfigFrame->GetParent()->IsShown()) - m_ConfigFrame->Close(true); - m_ConfigFrame->ClearBackends(); - // add backends - std::vector backends = AudioCommon::GetSoundBackends(); + // add backends + std::vector backends = AudioCommon::GetSoundBackends(); - for (std::vector::const_iterator iter = backends.begin(); - iter != backends.end(); ++iter) { - m_ConfigFrame->AddBackend((*iter).c_str()); - } + for (std::vector::const_iterator iter = backends.begin(); + iter != backends.end(); ++iter) + { + m_ConfigFrame->AddBackend((*iter).c_str()); + } - // Only allow one open at a time - if (!m_ConfigFrame->IsShown()) + // Only allow one open at a time m_ConfigFrame->ShowModal(); - else - m_ConfigFrame->Hide(); + + delete m_ConfigFrame; + m_ConfigFrame = 0; + } #endif } diff --git a/Source/Plugins/Plugin_VideoDX9/Src/EmuWindow.cpp b/Source/Plugins/Plugin_VideoDX9/Src/EmuWindow.cpp index 76c22340f9..cc90c93d6e 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/EmuWindow.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/EmuWindow.cpp @@ -115,8 +115,12 @@ LRESULT CALLBACK WndProc( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam ) case WM_CLOSE: // When the user closes the window, we post an event to the main window to call Stop() // Which then handles all the necessary steps to Shutdown the core + the plugins - PostMessage( m_hMain, WM_USER, WM_USER_STOP, 0 ); - return 0; + if (m_hParent == NULL) + { + PostMessage( m_hMain, WM_USER, WM_USER_STOP, 0 ); + return 0; + } + break; case WM_USER: // if (wParam == TOGGLE_FULLSCREEN) @@ -170,6 +174,7 @@ HWND OpenWindow(HWND parent, HINSTANCE hInstance, int width, int height, const T else { m_hMain = parent; + m_hParent = NULL; DWORD style = g_Config.bFullscreen ? WS_POPUP : WS_OVERLAPPEDWINDOW; @@ -208,8 +213,11 @@ HWND Create(HWND hParent, HINSTANCE hInstance, const TCHAR *title) void Close() { - DestroyWindow(m_hWnd); - UnregisterClass(m_szClassName, m_hInstance); + if (m_hWnd && !g_Config.RenderToMainframe) + { + DestroyWindow(m_hWnd); + UnregisterClass(m_szClassName, m_hInstance); + } } void SetSize(int width, int height) diff --git a/Source/Plugins/Plugin_VideoDX9/Src/main.cpp b/Source/Plugins/Plugin_VideoDX9/Src/main.cpp index f9d85fb11d..bb7721a3c7 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/main.cpp @@ -68,7 +68,9 @@ PLUGIN_GLOBALS* globals = NULL; bool s_initialized; static u32 s_efbAccessRequested = FALSE; +static u32 s_FifoShuttingDown = FALSE; static bool s_swapRequested = false; + static volatile struct { u32 xfbAddr; @@ -261,6 +263,10 @@ void Initialize(void *init) void Video_Prepare() { + // Better be safe... + s_efbAccessRequested = FALSE; + s_FifoShuttingDown = FALSE; + Renderer::Init(); TextureCache::Init(); BPInit(); @@ -279,6 +285,7 @@ void Video_Prepare() void Shutdown() { s_efbAccessRequested = FALSE; + s_FifoShuttingDown = FALSE; Fifo_Shutdown(); VertexManager::Shutdown(); @@ -311,6 +318,8 @@ void Video_EnterLoop() void Video_ExitLoop() { Fifo_ExitLoop(); + + s_FifoShuttingDown = TRUE; } void Video_SetRendering(bool bEnabled) { @@ -451,7 +460,7 @@ u32 Video_AccessEFB(EFBAccessType type, u32 x, u32 y) if (g_VideoInitialize.bOnThread) { - while (Common::AtomicLoadAcquire(s_efbAccessRequested) && s_initialized) + while (Common::AtomicLoadAcquire(s_efbAccessRequested) && !s_FifoShuttingDown) Common::YieldCPU(); } else diff --git a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp index 2db8ea7d7e..2c19b8dfc9 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp @@ -107,6 +107,7 @@ static bool s_PluginInitialized = false; static u32 s_swapRequested = FALSE; static u32 s_efbAccessRequested = FALSE; +static u32 s_FifoShuttingDown = FALSE; static bool ForceSwap = true; bool IsD3D() @@ -295,8 +296,9 @@ void DllConfig(HWND _hParent) g_Config.UpdateProjectionHack(); UpdateActiveConfig(); #if defined(HAVE_WX) && HAVE_WX -// Prevent user to show more than 1 config window at same time - if (allowConfigShow) { + // Prevent user to show more than 1 config window at same time + if (allowConfigShow) + { m_ConfigFrame = new GFXConfigDialogOGL(GetParentedWxWindow(_hParent)); #if defined(_WIN32) @@ -307,15 +309,18 @@ void DllConfig(HWND _hParent) CocaAddResolutions(); #endif - // CreateGUIControls() will crash because the array is empty. - if (m_ConfigFrame->arrayStringFor_FullscreenCB.size() == 0) { - m_ConfigFrame->AddFSReso(""); - m_ConfigFrame->AddWindowReso(""); - } - - allowConfigShow = false; - m_ConfigFrame->CreateGUIControls(); - allowConfigShow = m_ConfigFrame->ShowModal() == 1 ? true : false; + // CreateGUIControls() will crash because the array is empty. + if (m_ConfigFrame->arrayStringFor_FullscreenCB.size() == 0) { + m_ConfigFrame->AddFSReso(""); + m_ConfigFrame->AddWindowReso(""); + } + + allowConfigShow = false; + m_ConfigFrame->CreateGUIControls(); + allowConfigShow = m_ConfigFrame->ShowModal() == 1 ? true : false; + + delete m_ConfigFrame; + m_ConfigFrame = 0; } #endif } @@ -382,6 +387,10 @@ void Video_Prepare(void) exit(1); } + s_swapRequested = FALSE; + s_efbAccessRequested = FALSE; + s_FifoShuttingDown = FALSE; + CommandProcessor::Init(); PixelEngine::Init(); @@ -400,8 +409,6 @@ void Video_Prepare(void) VertexLoaderManager::Init(); TextureConverter::Init(); DLCache::Init(); - s_swapRequested = FALSE; - s_efbAccessRequested = FALSE; s_PluginInitialized = true; INFO_LOG(VIDEO, "Video plugin initialized."); @@ -414,6 +421,7 @@ void Shutdown(void) s_efbAccessRequested = FALSE; s_swapRequested = FALSE; + s_FifoShuttingDown = FALSE; DLCache::Shutdown(); Fifo_Shutdown(); @@ -443,6 +451,8 @@ void Video_EnterLoop() void Video_ExitLoop() { Fifo_ExitLoop(); + + s_FifoShuttingDown = TRUE; } // Screenshot and screen message @@ -517,7 +527,7 @@ void Video_BeginField(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) // Make sure previous swap request has made it to the screen if (g_VideoInitialize.bOnThread) { - while (Common::AtomicLoadAcquire(s_swapRequested) && s_PluginInitialized) + while (Common::AtomicLoadAcquire(s_swapRequested) && !s_FifoShuttingDown) Common::YieldCPU(); } else @@ -570,7 +580,7 @@ u32 Video_AccessEFB(EFBAccessType type, u32 x, u32 y) if (g_VideoInitialize.bOnThread) { - while (Common::AtomicLoadAcquire(s_efbAccessRequested) && s_PluginInitialized) + while (Common::AtomicLoadAcquire(s_efbAccessRequested) && !s_FifoShuttingDown) Common::YieldCPU(); } else