Core: Make EmuThread spawn a GPU thread and become the CPU thread in dual-core mode.

This commit is contained in:
Jordan Woyak 2025-03-12 14:42:20 -05:00
parent de997d616f
commit 33deb7673d
4 changed files with 25 additions and 78 deletions

View file

@ -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<StateChangedCallbackFunc> s_on_state_changed_callbacks;
static std::thread s_cpu_thread;
static bool s_is_throttler_temp_disabled = false;
static std::atomic<double> 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<std::string>& 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<std::string>& sa
static void FifoPlayerThread(Core::System& system, const std::optional<std::string>& 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<BootParameters> 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<BootParameters> boot
system.GetPowerPC().SetMode(PowerPC::CoreMode::Interpreter);
// Determine the CPU thread function
void (*cpuThreadFunc)(Core::System & system, const std::optional<std::string>& savestate_path,
bool delete_savestate);
if (std::holds_alternative<BootParameters::DFF>(boot->parameters))
cpuThreadFunc = FifoPlayerThread;
else
cpuThreadFunc = CpuThread;
const auto cpu_thread_func =
std::holds_alternative<BootParameters::DFF>(boot->parameters) ? FifoPlayerThread : CpuThread;
std::optional<DiscIO::Riivolution::SavegameRedirect> savegame_redirect = std::nullopt;
if (system.IsWii())
@ -657,37 +631,36 @@ static void EmuThread(Core::System& system, std::unique_ptr<BootParameters> 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 ..."));

View file

@ -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<std::mutex> 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)

View file

@ -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;
};

View file

@ -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()