From d3123079e887710580b622b444a642ae298ddec0 Mon Sep 17 00:00:00 2001 From: Liam Date: Sat, 17 Dec 2022 14:34:03 -0500 Subject: [PATCH] EmuThread: refactor --- src/core/core.cpp | 18 +++------ src/core/core.h | 4 +- src/yuzu/bootmanager.cpp | 82 ++++++++++++++-------------------------- src/yuzu/bootmanager.h | 51 ++++++++++++------------- src/yuzu/main.cpp | 80 ++------------------------------------- src/yuzu/main.h | 1 - 6 files changed, 64 insertions(+), 172 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index a738f221f..47292cd78 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -183,26 +183,20 @@ struct System::Impl { Initialize(system); } - SystemResultStatus Run() { + void Run() { std::unique_lock lk(suspend_guard); - status = SystemResultStatus::Success; kernel.Suspend(false); core_timing.SyncPause(false); is_paused.store(false, std::memory_order_relaxed); - - return status; } - SystemResultStatus Pause() { + void Pause() { std::unique_lock lk(suspend_guard); - status = SystemResultStatus::Success; core_timing.SyncPause(true); kernel.Suspend(true); is_paused.store(true, std::memory_order_relaxed); - - return status; } bool IsPaused() const { @@ -553,12 +547,12 @@ void System::Initialize() { impl->Initialize(*this); } -SystemResultStatus System::Run() { - return impl->Run(); +void System::Run() { + impl->Run(); } -SystemResultStatus System::Pause() { - return impl->Pause(); +void System::Pause() { + impl->Pause(); } bool System::IsPaused() const { diff --git a/src/core/core.h b/src/core/core.h index 4ebedffd9..fb5cda2f5 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -152,13 +152,13 @@ public: * Run the OS and Application * This function will start emulation and run the relevant devices */ - [[nodiscard]] SystemResultStatus Run(); + void Run(); /** * Pause the OS and Application * This function will pause emulation and stop the relevant devices */ - [[nodiscard]] SystemResultStatus Pause(); + void Pause(); /// Check if the core is currently paused. [[nodiscard]] bool IsPaused() const; diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 682b37f47..40b3d91fc 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -46,30 +46,28 @@ static Core::Frontend::WindowSystemType GetWindowSystemType(); -EmuThread::EmuThread(Core::System& system_) : system{system_} {} +EmuThread::EmuThread(Core::System& system) : m_system{system} {} EmuThread::~EmuThread() = default; void EmuThread::run() { - std::string name = "EmuControlThread"; - MicroProfileOnThreadCreate(name.c_str()); - Common::SetCurrentThreadName(name.c_str()); + const char* name = "EmuControlThread"; + MicroProfileOnThreadCreate(name); + Common::SetCurrentThreadName(name); - auto& gpu = system.GPU(); - auto stop_token = stop_source.get_token(); - bool debugger_should_start = system.DebuggerEnabled(); + auto& gpu = m_system.GPU(); + auto stop_token = m_stop_source.get_token(); - system.RegisterHostThread(); + m_system.RegisterHostThread(); // Main process has been loaded. Make the context current to this thread and begin GPU and CPU // execution. gpu.ObtainContext(); emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); - if (Settings::values.use_disk_shader_cache.GetValue()) { - system.Renderer().ReadRasterizer()->LoadDiskResources( - system.GetCurrentProcessProgramID(), stop_token, + m_system.Renderer().ReadRasterizer()->LoadDiskResources( + m_system.GetCurrentProcessProgramID(), stop_token, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) { emit LoadProgress(stage, value, total); }); @@ -79,57 +77,35 @@ void EmuThread::run() { gpu.ReleaseContext(); gpu.Start(); - system.GetCpuManager().OnGpuReady(); + m_system.GetCpuManager().OnGpuReady(); + m_system.RegisterExitCallback([this] { m_stop_source.request_stop(); }); - system.RegisterExitCallback([this]() { - stop_source.request_stop(); - SetRunning(false); - }); + if (m_system.DebuggerEnabled()) { + m_system.InitializeDebugger(); + } - // Holds whether the cpu was running during the last iteration, - // so that the DebugModeLeft signal can be emitted before the - // next execution step - bool was_active = false; while (!stop_token.stop_requested()) { - if (running) { - if (was_active) { - emit DebugModeLeft(); - } + std::unique_lock lk{m_should_run_mutex}; + if (m_should_run) { + m_system.Run(); + m_is_running.store(true); + m_is_running.notify_all(); - running_guard = true; - Core::SystemResultStatus result = system.Run(); - if (result != Core::SystemResultStatus::Success) { - running_guard = false; - this->SetRunning(false); - emit ErrorThrown(result, system.GetStatusDetails()); - } - - if (debugger_should_start) { - system.InitializeDebugger(); - debugger_should_start = false; - } - - running_wait.Wait(); - result = system.Pause(); - if (result != Core::SystemResultStatus::Success) { - running_guard = false; - this->SetRunning(false); - emit ErrorThrown(result, system.GetStatusDetails()); - } - running_guard = false; - - if (!stop_token.stop_requested()) { - was_active = true; - emit DebugModeEntered(); - } + Common::CondvarWait(m_should_run_cv, lk, stop_token, [&] { return !m_should_run; }); } else { - std::unique_lock lock{running_mutex}; - Common::CondvarWait(running_cv, lock, stop_token, [&] { return IsRunning(); }); + m_system.Pause(); + m_is_running.store(false); + m_is_running.notify_all(); + + emit DebugModeEntered(); + Common::CondvarWait(m_should_run_cv, lk, stop_token, [&] { return m_should_run; }); + emit DebugModeLeft(); } } // Shutdown the main emulated process - system.ShutdownMainProcess(); + m_system.DetachDebugger(); + m_system.ShutdownMainProcess(); #if MICROPROFILE_ENABLED MicroProfileOnThreadExit(); diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 5bbcf61f7..52867d628 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -47,7 +47,7 @@ class EmuThread final : public QThread { Q_OBJECT public: - explicit EmuThread(Core::System& system_); + explicit EmuThread(Core::System& system); ~EmuThread() override; /** @@ -57,30 +57,30 @@ public: void run() override; /** - * Sets whether the emulation thread is running or not - * @param running_ Boolean value, set the emulation thread to running if true - * @note This function is thread-safe + * Sets whether the emulation thread should run or not + * @param should_run Boolean value, set the emulation thread to running if true */ - void SetRunning(bool running_) { - std::unique_lock lock{running_mutex}; - running = running_; - lock.unlock(); - running_cv.notify_all(); - if (!running) { - running_wait.Set(); - /// Wait until effectively paused - while (running_guard) - ; + void SetRunning(bool should_run) { + // TODO: Prevent other threads from modifying the state until we finish. + { + // Notify the running thread to change state. + std::unique_lock run_lk{m_should_run_mutex}; + m_should_run = should_run; + m_should_run_cv.notify_one(); + } + + // Wait until paused, if pausing. + if (!should_run) { + m_is_running.wait(true); } } /** * Check if the emulation thread is running or not * @return True if the emulation thread is running, otherwise false - * @note This function is thread-safe */ bool IsRunning() const { - return running; + return m_is_running.load(); } /** @@ -88,18 +88,17 @@ public: */ void ForceStop() { LOG_WARNING(Frontend, "Force stopping EmuThread"); - stop_source.request_stop(); - SetRunning(false); + m_stop_source.request_stop(); } private: - bool running = false; - std::stop_source stop_source; - std::mutex running_mutex; - std::condition_variable_any running_cv; - Common::Event running_wait{}; - std::atomic_bool running_guard{false}; - Core::System& system; + Core::System& m_system; + + std::stop_source m_stop_source; + std::mutex m_should_run_mutex; + std::condition_variable_any m_should_run_cv; + std::atomic m_is_running{false}; + bool m_should_run{true}; signals: /** @@ -120,8 +119,6 @@ signals: */ void DebugModeLeft(); - void ErrorThrown(Core::SystemResultStatus, std::string); - void LoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total); }; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 2e6c2311a..c5285ffc9 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1794,15 +1794,16 @@ void GMainWindow::ShutdownGame() { Settings::values.use_speed_limit.SetValue(true); system->SetShuttingDown(true); - system->DetachDebugger(); discord_rpc->Pause(); RequestGameExit(); + emu_thread->disconnect(); + emu_thread->SetRunning(true); emit EmulationStopping(); // Wait for emulation thread to complete and delete it - if (!emu_thread->wait(5000)) { + if (system->DebuggerEnabled() || !emu_thread->wait(5000)) { emu_thread->ForceStop(); emu_thread->wait(); } @@ -2916,8 +2917,6 @@ void GMainWindow::OnStartGame() { emu_thread->SetRunning(true); - connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError); - UpdateMenuState(); OnTasStateChanged(); @@ -3901,79 +3900,6 @@ void GMainWindow::OnMouseActivity() { mouse_center_timer.stop(); } -void GMainWindow::OnCoreError(Core::SystemResultStatus result, std::string details) { - QMessageBox::StandardButton answer; - QString status_message; - const QString common_message = - tr("The game you are trying to load requires additional files from your Switch to be " - "dumped " - "before playing.

For more information on dumping these files, please see the " - "following wiki page: Dumping System " - "Archives and the Shared Fonts from a Switch Console.

Would you like to " - "quit " - "back to the game list? Continuing emulation may result in crashes, corrupted save " - "data, or other bugs."); - switch (result) { - case Core::SystemResultStatus::ErrorSystemFiles: { - QString message; - if (details.empty()) { - message = - tr("yuzu was unable to locate a Switch system archive. %1").arg(common_message); - } else { - message = tr("yuzu was unable to locate a Switch system archive: %1. %2") - .arg(QString::fromStdString(details), common_message); - } - - answer = QMessageBox::question(this, tr("System Archive Not Found"), message, - QMessageBox::Yes | QMessageBox::No, QMessageBox::No); - status_message = tr("System Archive Missing"); - break; - } - - case Core::SystemResultStatus::ErrorSharedFont: { - const QString message = - tr("yuzu was unable to locate the Switch shared fonts. %1").arg(common_message); - answer = QMessageBox::question(this, tr("Shared Fonts Not Found"), message, - QMessageBox::Yes | QMessageBox::No, QMessageBox::No); - status_message = tr("Shared Font Missing"); - break; - } - - default: - answer = QMessageBox::question( - this, tr("Fatal Error"), - tr("yuzu has encountered a fatal error, please see the log for more details. " - "For more information on accessing the log, please see the following page: " - "How " - "to " - "Upload the Log File.

Would you like to quit back to the game " - "list? " - "Continuing emulation may result in crashes, corrupted save data, or other " - "bugs."), - QMessageBox::Yes | QMessageBox::No, QMessageBox::No); - status_message = tr("Fatal Error encountered"); - break; - } - - if (answer == QMessageBox::Yes) { - if (emu_thread) { - ShutdownGame(); - - Settings::RestoreGlobalState(system->IsPoweredOn()); - system->HIDCore().ReloadInputDevices(); - UpdateStatusButtons(); - } - } else { - // Only show the message if the game is still running. - if (emu_thread) { - emu_thread->SetRunning(true); - message_label->setText(status_message); - } - } -} - void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { if (behavior == ReinitializeKeyBehavior::Warning) { const auto res = QMessageBox::information( diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 1047ba276..5b84c7a00 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -332,7 +332,6 @@ private slots: void ResetWindowSize900(); void ResetWindowSize1080(); void OnCaptureScreenshot(); - void OnCoreError(Core::SystemResultStatus, std::string); void OnReinitializeKeys(ReinitializeKeyBehavior behavior); void OnLanguageChanged(const QString& locale); void OnMouseActivity();