static void FifoPlayerThread() { const SConfig& _CoreParameter = SConfig::GetInstance(); if (_CoreParameter.bCPUThread) { Common::SetCurrentThreadName("FIFO player thread"); } else { g_video_backend->Video_Prepare(); Common::SetCurrentThreadName("FIFO-GPU thread"); } s_is_started = true; DeclareAsCPUThread(); // Enter CPU run loop. When we leave it - we are done. if (FifoPlayer::GetInstance().Open(_CoreParameter.m_strFilename)) { FifoPlayer::GetInstance().Play(); FifoPlayer::GetInstance().Close(); } UndeclareAsCPUThread(); s_is_started = false; if (!_CoreParameter.bCPUThread) g_video_backend->Video_Cleanup(); return; }
// Create the CPU thread, which is a CPU + Video thread in Single Core mode. static void CpuThread() { DeclareAsCPUThread(); const SConfig& _CoreParameter = SConfig::GetInstance(); VideoBackendBase* video_backend = g_video_backend; if (_CoreParameter.bCPUThread) { Common::SetCurrentThreadName("CPU thread"); } else { Common::SetCurrentThreadName("CPU-GPU thread"); video_backend->Video_Prepare(); } if (_CoreParameter.bFastmem) EMM::InstallExceptionHandler(); // Let's run under memory watch if (!s_state_filename.empty()) State::LoadAs(s_state_filename); s_is_started = true; #ifdef USE_GDBSTUB #ifndef _WIN32 if (!_CoreParameter.gdb_socket.empty()) { gdb_init_local(_CoreParameter.gdb_socket.data()); gdb_break(); } else #endif if (_CoreParameter.iGDBPort > 0) { gdb_init(_CoreParameter.iGDBPort); // break at next instruction (the first instruction) gdb_break(); } #endif #ifdef USE_MEMORYWATCHER MemoryWatcher::Init(); #endif // Enter CPU run loop. When we leave it - we are done. CPU::Run(); s_is_started = false; if (!_CoreParameter.bCPUThread) video_backend->Video_Cleanup(); if (_CoreParameter.bFastmem) EMM::UninstallExceptionHandler(); return; }
static void FifoPlayerThread() { DeclareAsCPUThread(); const SConfig& _CoreParameter = SConfig::GetInstance(); if (_CoreParameter.bCPUThread) { Common::SetCurrentThreadName("FIFO player thread"); } else { g_video_backend->Video_Prepare(); Common::SetCurrentThreadName("FIFO-GPU thread"); } // Enter CPU run loop. When we leave it - we are done. if (FifoPlayer::GetInstance().Open(_CoreParameter.m_strFilename)) { if (auto cpu_core = FifoPlayer::GetInstance().GetCPUCore()) { PowerPC::InjectExternalCPUCore(cpu_core.get()); s_is_started = true; CPUSetInitialExecutionState(); CPU::Run(); s_is_started = false; PowerPC::InjectExternalCPUCore(nullptr); } FifoPlayer::GetInstance().Close(); } // If we did not enter the CPU Run Loop above then run a fake one instead. // We need to be IsRunningAndStarted() for DolphinWX to stop us. if (CPU::GetState() != CPU::CPU_POWERDOWN) { s_is_started = true; Host_Message(WM_USER_STOP); while (CPU::GetState() != CPU::CPU_POWERDOWN) { if (!_CoreParameter.bCPUThread) g_video_backend->PeekMessages(); std::this_thread::sleep_for(std::chrono::milliseconds(20)); } s_is_started = false; } if (!_CoreParameter.bCPUThread) g_video_backend->Video_Cleanup(); return; }
// Create the CPU thread, which is a CPU + Video thread in Single Core mode. static void CpuThread() { DeclareAsCPUThread(); const SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter; if (_CoreParameter.bCPUThread) { Common::SetCurrentThreadName("CPU thread"); } else { Common::SetCurrentThreadName("CPU-GPU thread"); g_video_backend->Video_Prepare(); } if (_CoreParameter.bFastmem) EMM::InstallExceptionHandler(); // Let's run under memory watch if (!s_state_filename.empty()) State::LoadAs(s_state_filename); s_is_started = true; #ifdef USE_GDBSTUB if (_CoreParameter.iGDBPort > 0) { gdb_init(_CoreParameter.iGDBPort); // break at next instruction (the first instruction) gdb_break(); } #endif // Enter CPU run loop. When we leave it - we are done. CCPU::Run(); s_is_started = false; if (!_CoreParameter.bCPUThread) g_video_backend->Video_Cleanup(); if (_CoreParameter.bFastmem) EMM::UninstallExceptionHandler(); return; }
// Initialize and create emulation thread // Call browser: Init():s_emu_thread(). // See the BootManager.cpp file description for a complete call schedule. void EmuThread() { const SCoreStartupParameter& core_parameter = SConfig::GetInstance().m_LocalCoreStartupParameter; Common::SetCurrentThreadName("Emuthread - Starting"); if (SConfig::GetInstance().m_OCEnable) DisplayMessage("WARNING: running at non-native CPU clock! Game may not be stable.", 8000); DisplayMessage(cpu_info.brand_string, 8000); DisplayMessage(cpu_info.Summarize(), 8000); DisplayMessage(core_parameter.m_strFilename, 3000); // For a time this acts as the CPU thread... DeclareAsCPUThread(); Movie::Init(); HW::Init(); if (!g_video_backend->Initialize(s_window_handle)) { PanicAlert("Failed to initialize video backend!"); Host_Message(WM_USER_STOP); return; } OSD::AddMessage("Dolphin " + g_video_backend->GetName() + " Video Backend.", 5000); if (cpu_info.HTT) SConfig::GetInstance().m_LocalCoreStartupParameter.bDSPThread = cpu_info.num_cores > 4; else SConfig::GetInstance().m_LocalCoreStartupParameter.bDSPThread = cpu_info.num_cores > 2; if (!DSP::GetDSPEmulator()->Initialize(core_parameter.bWii, core_parameter.bDSPThread)) { HW::Shutdown(); g_video_backend->Shutdown(); PanicAlert("Failed to initialize DSP emulator!"); Host_Message(WM_USER_STOP); return; } bool init_controllers = false; if (!g_controller_interface.IsInit()) { Pad::Initialize(s_window_handle); Keyboard::Initialize(s_window_handle); init_controllers = true; } else { // Update references in case controllers were refreshed Pad::LoadConfig(); Keyboard::LoadConfig(); } // Load and Init Wiimotes - only if we are booting in Wii mode if (core_parameter.bWii) { if (init_controllers) Wiimote::Initialize(s_window_handle, !s_state_filename.empty()); else Wiimote::LoadConfig(); // Activate Wiimotes which don't have source set to "None" for (unsigned int i = 0; i != MAX_BBMOTES; ++i) if (g_wiimote_sources[i]) GetUsbPointer()->AccessWiiMote(i | 0x100)->Activate(true); } AudioCommon::InitSoundStream(); // The hardware is initialized. s_hardware_initialized = true; // Boot to pause or not Core::SetState(core_parameter.bBootToPause ? Core::CORE_PAUSE : Core::CORE_RUN); // Load GCM/DOL/ELF whatever ... we boot with the interpreter core PowerPC::SetMode(PowerPC::MODE_INTERPRETER); CBoot::BootUp(); // Thread is no longer acting as CPU Thread UndeclareAsCPUThread(); // Setup our core, but can't use dynarec if we are compare server if (core_parameter.iCPUCore != PowerPC::CORE_INTERPRETER && (!core_parameter.bRunCompareServer || core_parameter.bRunCompareClient)) { PowerPC::SetMode(PowerPC::MODE_JIT); } else { PowerPC::SetMode(PowerPC::MODE_INTERPRETER); } // Update the window again because all stuff is initialized Host_UpdateDisasmDialog(); Host_UpdateMainFrame(); // Determine the CPU thread function void (*cpuThreadFunc)(void); if (core_parameter.m_BootType == SCoreStartupParameter::BOOT_DFF) cpuThreadFunc = FifoPlayerThread; else cpuThreadFunc = CpuThread; // ENTER THE VIDEO THREAD LOOP if (core_parameter.bCPUThread) { // This thread, after creating the EmuWindow, spawns a CPU // thread, and then takes over and becomes the video thread Common::SetCurrentThreadName("Video thread"); g_video_backend->Video_Prepare(); // Spawn the CPU thread s_cpu_thread = std::thread(cpuThreadFunc); // become the GPU thread g_video_backend->Video_EnterLoop(); // We have now exited the Video Loop INFO_LOG(CONSOLE, "%s", StopMessage(false, "Video Loop Ended").c_str()); } else // SingleCore mode { // The spawned CPU Thread also does the graphics. // The EmuThread is thus an idle thread, which sleeps while // waiting for the program to terminate. Without this extra // thread, the video backend window hangs in single core mode // because no one is pumping messages. Common::SetCurrentThreadName("Emuthread - Idle"); // Spawn the CPU+GPU thread s_cpu_thread = std::thread(cpuThreadFunc); while (PowerPC::GetState() != PowerPC::CPU_POWERDOWN) { g_video_backend->PeekMessages(); Common::SleepCurrentThread(20); } } INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping Emu thread ...").c_str()); // Wait for s_cpu_thread to exit INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping CPU-GPU thread ...").c_str()); #ifdef USE_GDBSTUB INFO_LOG(CONSOLE, "%s", StopMessage(true, "Stopping GDB ...").c_str()); gdb_deinit(); INFO_LOG(CONSOLE, "%s", StopMessage(true, "GDB stopped.").c_str()); #endif s_cpu_thread.join(); INFO_LOG(CONSOLE, "%s", StopMessage(true, "CPU thread stopped.").c_str()); if (core_parameter.bCPUThread) g_video_backend->Video_Cleanup(); VolumeHandler::EjectVolume(); FileMon::Close(); // Stop audio thread - Actually this does nothing when using HLE // emulation, but stops the DSP Interpreter when using LLE emulation. DSP::GetDSPEmulator()->DSP_StopSoundStream(); // We must set up this flag before executing HW::Shutdown() s_hardware_initialized = false; INFO_LOG(CONSOLE, "%s", StopMessage(false, "Shutting down HW").c_str()); HW::Shutdown(); INFO_LOG(CONSOLE, "%s", StopMessage(false, "HW shutdown").c_str()); if (init_controllers) { Wiimote::Shutdown(); Keyboard::Shutdown(); Pad::Shutdown(); init_controllers = false; } g_video_backend->Shutdown(); AudioCommon::ShutdownSoundStream(); INFO_LOG(CONSOLE, "%s", StopMessage(true, "Main Emu thread stopped").c_str()); // Clear on screen messages that haven't expired g_video_backend->Video_ClearMessages(); // Reload sysconf file in order to see changes committed during emulation if (core_parameter.bWii) SConfig::GetInstance().m_SYSCONF->Reload(); INFO_LOG(CONSOLE, "Stop [Video Thread]\t\t---- Shutdown complete ----"); Movie::Shutdown(); PatchEngine::Shutdown(); s_is_stopping = false; if (s_on_stopped_callback) s_on_stopped_callback(); }
// Create the CPU thread, which is a CPU + Video thread in Single Core mode. static void CpuThread() { DeclareAsCPUThread(); const SConfig& _CoreParameter = SConfig::GetInstance(); if (_CoreParameter.bCPUThread) { Common::SetCurrentThreadName("CPU thread"); } else { Common::SetCurrentThreadName("CPU-GPU thread"); g_video_backend->Video_Prepare(); } // This needs to be delayed until after the video backend is ready. DolphinAnalytics::Instance()->ReportGameStart(); if (_CoreParameter.bFastmem) EMM::InstallExceptionHandler(); // Let's run under memory watch if (!s_state_filename.empty()) { // Needs to PauseAndLock the Core // NOTE: EmuThread should have left us in CPU_STEPPING so nothing will happen // until after the job is serviced. QueueHostJob([] { // Recheck in case Movie cleared it since. if (!s_state_filename.empty()) State::LoadAs(s_state_filename); }); } s_is_started = true; CPUSetInitialExecutionState(); #ifdef USE_GDBSTUB #ifndef _WIN32 if (!_CoreParameter.gdb_socket.empty()) { gdb_init_local(_CoreParameter.gdb_socket.data()); gdb_break(); } else #endif if (_CoreParameter.iGDBPort > 0) { gdb_init(_CoreParameter.iGDBPort); // break at next instruction (the first instruction) gdb_break(); } #endif #ifdef USE_MEMORYWATCHER MemoryWatcher::Init(); #endif // Enter CPU run loop. When we leave it - we are done. CPU::Run(); s_is_started = false; if (!_CoreParameter.bCPUThread) g_video_backend->Video_Cleanup(); if (_CoreParameter.bFastmem) EMM::UninstallExceptionHandler(); return; }