mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-11-04 00:49:02 -06:00 
			
		
		
		
	EmuThread: refactor
This commit is contained in:
		@@ -183,26 +183,20 @@ struct System::Impl {
 | 
			
		||||
        Initialize(system);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SystemResultStatus Run() {
 | 
			
		||||
    void Run() {
 | 
			
		||||
        std::unique_lock<std::mutex> 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<std::mutex> 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 {
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
 
 | 
			
		||||
@@ -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<bool> 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);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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.<br/><br/>For more information on dumping these files, please see the "
 | 
			
		||||
           "following wiki page: <a "
 | 
			
		||||
           "href='https://yuzu-emu.org/wiki/"
 | 
			
		||||
           "dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System "
 | 
			
		||||
           "Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>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: "
 | 
			
		||||
               "<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How "
 | 
			
		||||
               "to "
 | 
			
		||||
               "Upload the Log File</a>.<br/><br/>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(
 | 
			
		||||
 
 | 
			
		||||
@@ -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();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user