From 33deb7673d7c5e519f9214adfcce5400f39a71b5 Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Wed, 12 Mar 2025 14:42:20 -0500 Subject: [PATCH] Core: Make EmuThread spawn a GPU thread and become the CPU thread in dual-core mode. --- Source/Core/Core/Core.cpp | 77 ++++++++--------------- Source/Core/VideoCommon/AsyncRequests.cpp | 18 ------ Source/Core/VideoCommon/AsyncRequests.h | 2 - Source/Core/VideoCommon/Fifo.cpp | 6 -- 4 files changed, 25 insertions(+), 78 deletions(-) diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index 7226c1ed06..9e0a5c5805 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -29,21 +29,17 @@ #include "Common/FPURoundMode.h" #include "Common/FatFsUtil.h" #include "Common/FileUtil.h" -#include "Common/Flag.h" #include "Common/Logging/Log.h" -#include "Common/MemoryUtil.h" #include "Common/MsgHandler.h" #include "Common/ScopeGuard.h" #include "Common/StringUtil.h" #include "Common/Thread.h" -#include "Common/Timer.h" #include "Common/Version.h" #include "Core/AchievementManager.h" #include "Core/Boot/Boot.h" #include "Core/BootManager.h" #include "Core/CPUThreadConfigCallback.h" -#include "Core/Config/AchievementSettings.h" #include "Core/Config/MainSettings.h" #include "Core/ConfigManager.h" #include "Core/CoreTiming.h" @@ -92,7 +88,6 @@ #include "VideoCommon/FrameDumper.h" #include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/PerformanceMetrics.h" -#include "VideoCommon/Present.h" #include "VideoCommon/VideoBackendBase.h" #include "VideoCommon/VideoEvents.h" @@ -104,7 +99,6 @@ static bool s_wants_determinism; static std::thread s_emu_thread; static std::vector s_on_state_changed_callbacks; -static std::thread s_cpu_thread; static bool s_is_throttler_temp_disabled = false; static std::atomic s_last_actual_emulation_speed{1.0}; static bool s_frame_step = false; @@ -308,16 +302,6 @@ void Stop(Core::System& system) // - Hammertime! INFO_LOG_FMT(CONSOLE, "{}", StopMessage(true, "Stop CPU")); system.GetCPU().Stop(); - if (system.IsDualCoreMode()) - { - // FIFO processing should now exit so that EmuThread() - // will continue concurrently with the rest of the commands - // in this function. We no longer rely on Postmessage. - INFO_LOG_FMT(CONSOLE, "{}", StopMessage(true, "Wait for Video Loop to exit ...")); - - system.GetFifo().ExitGpuLoop(); - } - s_last_actual_emulation_speed = 1.0; } @@ -369,8 +353,6 @@ static void CPUSetInitialExecutionState(bool force_paused = false) static void CpuThread(Core::System& system, const std::optional& savestate_path, bool delete_savestate) { - DeclareAsCPUThread(); - if (system.IsDualCoreMode()) Common::SetCurrentThreadName("CPU thread"); else @@ -448,8 +430,6 @@ static void CpuThread(Core::System& system, const std::optional& sa static void FifoPlayerThread(Core::System& system, const std::optional& savestate_path, bool delete_savestate) { - DeclareAsCPUThread(); - if (system.IsDualCoreMode()) Common::SetCurrentThreadName("FIFO player thread"); else @@ -496,11 +476,9 @@ static void EmuThread(Core::System& system, std::unique_ptr boot }}; Common::SetCurrentThreadName("Emuthread - Starting"); - - DeclareAsGPUThread(); - - // For a time this acts as the CPU thread... + // This thread will become the CPU thread (in both single and dual-core mode). DeclareAsCPUThread(); + s_frame_step = false; // If settings have changed since the previous run, notify callbacks. @@ -612,12 +590,8 @@ static void EmuThread(Core::System& system, std::unique_ptr boot system.GetPowerPC().SetMode(PowerPC::CoreMode::Interpreter); // Determine the CPU thread function - void (*cpuThreadFunc)(Core::System & system, const std::optional& savestate_path, - bool delete_savestate); - if (std::holds_alternative(boot->parameters)) - cpuThreadFunc = FifoPlayerThread; - else - cpuThreadFunc = CpuThread; + const auto cpu_thread_func = + std::holds_alternative(boot->parameters) ? FifoPlayerThread : CpuThread; std::optional savegame_redirect = std::nullopt; if (system.IsWii()) @@ -657,37 +631,36 @@ static void EmuThread(Core::System& system, std::unique_ptr boot UpdateTitle(system); - // ENTER THE VIDEO THREAD LOOP + AsyncRequests::GetInstance()->SetPassthrough(!system.IsDualCoreMode()); + if (system.IsDualCoreMode()) { - // This thread, after creating the EmuWindow, spawns a CPU - // thread, and then takes over and becomes the video thread - Common::SetCurrentThreadName("Video thread"); - UndeclareAsCPUThread(); - Common::FPU::LoadDefaultSIMDState(); + // Spawn a GPU thread. + auto gpu_thread = std::thread([&] { + Common::SetCurrentThreadName("Video thread"); + Common::FPU::LoadDefaultSIMDState(); + DeclareAsGPUThread(); - // Spawn the CPU thread. The CPU thread will signal the event that boot is complete. - s_cpu_thread = - std::thread(cpuThreadFunc, std::ref(system), std::ref(savestate_path), delete_savestate); + system.GetFifo().RunGpuLoop(); - // become the GPU thread - system.GetFifo().RunGpuLoop(); + INFO_LOG_FMT(CONSOLE, "{}", StopMessage(false, "Video Loop Ended")); + }); - // We have now exited the Video Loop - INFO_LOG_FMT(CONSOLE, "{}", StopMessage(false, "Video Loop Ended")); + // Become the CPU thread. + cpu_thread_func(system, savestate_path, delete_savestate); - // Join with the CPU thread. - s_cpu_thread.join(); - INFO_LOG_FMT(CONSOLE, "{}", StopMessage(true, "CPU thread stopped.")); + INFO_LOG_FMT(CONSOLE, "{}", StopMessage(true, "Wait for Video Loop to exit ...")); - // Redeclare this thread as the CPU thread, so that the code running in the scope guards doesn't - // think we're doing anything unsafe by doing stuff that could race with the CPU thread. - DeclareAsCPUThread(); + // Join with the GPU thread. + system.GetFifo().ExitGpuLoop(); + gpu_thread.join(); + + INFO_LOG_FMT(CONSOLE, "{}", StopMessage(true, "GPU thread stopped.")); } - else // SingleCore mode + else { - // Become the CPU thread - cpuThreadFunc(system, savestate_path, delete_savestate); + // Become the CPU thread. + cpu_thread_func(system, savestate_path, delete_savestate); } INFO_LOG_FMT(CONSOLE, "{}", StopMessage(true, "Stopping GDB ...")); diff --git a/Source/Core/VideoCommon/AsyncRequests.cpp b/Source/Core/VideoCommon/AsyncRequests.cpp index 0bb916d9b6..d986bb08f1 100644 --- a/Source/Core/VideoCommon/AsyncRequests.cpp +++ b/Source/Core/VideoCommon/AsyncRequests.cpp @@ -61,9 +61,6 @@ void AsyncRequests::PushEvent(const AsyncRequests::Event& event, bool blocking) m_empty.Clear(); m_wake_me_up_again |= blocking; - if (!m_enable) - return; - m_queue.push(event); auto& system = Core::System::GetInstance(); @@ -80,21 +77,6 @@ void AsyncRequests::WaitForEmptyQueue() m_cond.wait(lock, [this] { return m_queue.empty(); }); } -void AsyncRequests::SetEnable(bool enable) -{ - std::unique_lock lock(m_mutex); - m_enable = enable; - - if (!enable) - { - // flush the queue on disabling - while (!m_queue.empty()) - m_queue.pop(); - if (m_wake_me_up_again) - m_cond.notify_all(); - } -} - void AsyncRequests::HandleEvent(const AsyncRequests::Event& e) { switch (e.type) diff --git a/Source/Core/VideoCommon/AsyncRequests.h b/Source/Core/VideoCommon/AsyncRequests.h index 1df6d91f0a..7fca6dace8 100644 --- a/Source/Core/VideoCommon/AsyncRequests.h +++ b/Source/Core/VideoCommon/AsyncRequests.h @@ -86,7 +86,6 @@ public: } void PushEvent(const Event& event, bool blocking = false); void WaitForEmptyQueue(); - void SetEnable(bool enable); void SetPassthrough(bool enable); static AsyncRequests* GetInstance() { return &s_singleton; } @@ -103,6 +102,5 @@ private: std::condition_variable m_cond; bool m_wake_me_up_again = false; - bool m_enable = false; bool m_passthrough = true; }; diff --git a/Source/Core/VideoCommon/Fifo.cpp b/Source/Core/VideoCommon/Fifo.cpp index 513b655408..0e7bb4c341 100644 --- a/Source/Core/VideoCommon/Fifo.cpp +++ b/Source/Core/VideoCommon/Fifo.cpp @@ -287,9 +287,6 @@ void FifoManager::ResetVideoBuffer() // Purpose: Keep the Core HW updated about the CPU-GPU distance void FifoManager::RunGpuLoop() { - AsyncRequests::GetInstance()->SetEnable(true); - AsyncRequests::GetInstance()->SetPassthrough(false); - m_gpu_mainloop.Run( [this] { // Run events from the CPU thread. @@ -391,9 +388,6 @@ void FifoManager::RunGpuLoop() } }, 100); - - AsyncRequests::GetInstance()->SetEnable(false); - AsyncRequests::GetInstance()->SetPassthrough(true); } void FifoManager::FlushGpu()