diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/core.cpp | 18 | ||||
| -rw-r--r-- | src/core/core.h | 4 | ||||
| -rw-r--r-- | src/yuzu/bootmanager.cpp | 82 | ||||
| -rw-r--r-- | src/yuzu/bootmanager.h | 51 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 82 | ||||
| -rw-r--r-- | src/yuzu/main.h | 1 |
6 files changed, 65 insertions, 173 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 { | |||
| 183 | Initialize(system); | 183 | Initialize(system); |
| 184 | } | 184 | } |
| 185 | 185 | ||
| 186 | SystemResultStatus Run() { | 186 | void Run() { |
| 187 | std::unique_lock<std::mutex> lk(suspend_guard); | 187 | std::unique_lock<std::mutex> lk(suspend_guard); |
| 188 | status = SystemResultStatus::Success; | ||
| 189 | 188 | ||
| 190 | kernel.Suspend(false); | 189 | kernel.Suspend(false); |
| 191 | core_timing.SyncPause(false); | 190 | core_timing.SyncPause(false); |
| 192 | is_paused.store(false, std::memory_order_relaxed); | 191 | is_paused.store(false, std::memory_order_relaxed); |
| 193 | |||
| 194 | return status; | ||
| 195 | } | 192 | } |
| 196 | 193 | ||
| 197 | SystemResultStatus Pause() { | 194 | void Pause() { |
| 198 | std::unique_lock<std::mutex> lk(suspend_guard); | 195 | std::unique_lock<std::mutex> lk(suspend_guard); |
| 199 | status = SystemResultStatus::Success; | ||
| 200 | 196 | ||
| 201 | core_timing.SyncPause(true); | 197 | core_timing.SyncPause(true); |
| 202 | kernel.Suspend(true); | 198 | kernel.Suspend(true); |
| 203 | is_paused.store(true, std::memory_order_relaxed); | 199 | is_paused.store(true, std::memory_order_relaxed); |
| 204 | |||
| 205 | return status; | ||
| 206 | } | 200 | } |
| 207 | 201 | ||
| 208 | bool IsPaused() const { | 202 | bool IsPaused() const { |
| @@ -553,12 +547,12 @@ void System::Initialize() { | |||
| 553 | impl->Initialize(*this); | 547 | impl->Initialize(*this); |
| 554 | } | 548 | } |
| 555 | 549 | ||
| 556 | SystemResultStatus System::Run() { | 550 | void System::Run() { |
| 557 | return impl->Run(); | 551 | impl->Run(); |
| 558 | } | 552 | } |
| 559 | 553 | ||
| 560 | SystemResultStatus System::Pause() { | 554 | void System::Pause() { |
| 561 | return impl->Pause(); | 555 | impl->Pause(); |
| 562 | } | 556 | } |
| 563 | 557 | ||
| 564 | bool System::IsPaused() const { | 558 | 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: | |||
| 152 | * Run the OS and Application | 152 | * Run the OS and Application |
| 153 | * This function will start emulation and run the relevant devices | 153 | * This function will start emulation and run the relevant devices |
| 154 | */ | 154 | */ |
| 155 | [[nodiscard]] SystemResultStatus Run(); | 155 | void Run(); |
| 156 | 156 | ||
| 157 | /** | 157 | /** |
| 158 | * Pause the OS and Application | 158 | * Pause the OS and Application |
| 159 | * This function will pause emulation and stop the relevant devices | 159 | * This function will pause emulation and stop the relevant devices |
| 160 | */ | 160 | */ |
| 161 | [[nodiscard]] SystemResultStatus Pause(); | 161 | void Pause(); |
| 162 | 162 | ||
| 163 | /// Check if the core is currently paused. | 163 | /// Check if the core is currently paused. |
| 164 | [[nodiscard]] bool IsPaused() const; | 164 | [[nodiscard]] bool IsPaused() const; |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 1368b20d5..13782869d 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -46,30 +46,28 @@ | |||
| 46 | 46 | ||
| 47 | static Core::Frontend::WindowSystemType GetWindowSystemType(); | 47 | static Core::Frontend::WindowSystemType GetWindowSystemType(); |
| 48 | 48 | ||
| 49 | EmuThread::EmuThread(Core::System& system_) : system{system_} {} | 49 | EmuThread::EmuThread(Core::System& system) : m_system{system} {} |
| 50 | 50 | ||
| 51 | EmuThread::~EmuThread() = default; | 51 | EmuThread::~EmuThread() = default; |
| 52 | 52 | ||
| 53 | void EmuThread::run() { | 53 | void EmuThread::run() { |
| 54 | std::string name = "EmuControlThread"; | 54 | const char* name = "EmuControlThread"; |
| 55 | MicroProfileOnThreadCreate(name.c_str()); | 55 | MicroProfileOnThreadCreate(name); |
| 56 | Common::SetCurrentThreadName(name.c_str()); | 56 | Common::SetCurrentThreadName(name); |
| 57 | 57 | ||
| 58 | auto& gpu = system.GPU(); | 58 | auto& gpu = m_system.GPU(); |
| 59 | auto stop_token = stop_source.get_token(); | 59 | auto stop_token = m_stop_source.get_token(); |
| 60 | bool debugger_should_start = system.DebuggerEnabled(); | ||
| 61 | 60 | ||
| 62 | system.RegisterHostThread(); | 61 | m_system.RegisterHostThread(); |
| 63 | 62 | ||
| 64 | // Main process has been loaded. Make the context current to this thread and begin GPU and CPU | 63 | // Main process has been loaded. Make the context current to this thread and begin GPU and CPU |
| 65 | // execution. | 64 | // execution. |
| 66 | gpu.ObtainContext(); | 65 | gpu.ObtainContext(); |
| 67 | 66 | ||
| 68 | emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); | 67 | emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); |
| 69 | |||
| 70 | if (Settings::values.use_disk_shader_cache.GetValue()) { | 68 | if (Settings::values.use_disk_shader_cache.GetValue()) { |
| 71 | system.Renderer().ReadRasterizer()->LoadDiskResources( | 69 | m_system.Renderer().ReadRasterizer()->LoadDiskResources( |
| 72 | system.GetCurrentProcessProgramID(), stop_token, | 70 | m_system.GetCurrentProcessProgramID(), stop_token, |
| 73 | [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) { | 71 | [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) { |
| 74 | emit LoadProgress(stage, value, total); | 72 | emit LoadProgress(stage, value, total); |
| 75 | }); | 73 | }); |
| @@ -79,57 +77,35 @@ void EmuThread::run() { | |||
| 79 | gpu.ReleaseContext(); | 77 | gpu.ReleaseContext(); |
| 80 | gpu.Start(); | 78 | gpu.Start(); |
| 81 | 79 | ||
| 82 | system.GetCpuManager().OnGpuReady(); | 80 | m_system.GetCpuManager().OnGpuReady(); |
| 81 | m_system.RegisterExitCallback([this] { m_stop_source.request_stop(); }); | ||
| 83 | 82 | ||
| 84 | system.RegisterExitCallback([this]() { | 83 | if (m_system.DebuggerEnabled()) { |
| 85 | stop_source.request_stop(); | 84 | m_system.InitializeDebugger(); |
| 86 | SetRunning(false); | 85 | } |
| 87 | }); | ||
| 88 | 86 | ||
| 89 | // Holds whether the cpu was running during the last iteration, | ||
| 90 | // so that the DebugModeLeft signal can be emitted before the | ||
| 91 | // next execution step | ||
| 92 | bool was_active = false; | ||
| 93 | while (!stop_token.stop_requested()) { | 87 | while (!stop_token.stop_requested()) { |
| 94 | if (running) { | 88 | std::unique_lock lk{m_should_run_mutex}; |
| 95 | if (was_active) { | 89 | if (m_should_run) { |
| 96 | emit DebugModeLeft(); | 90 | m_system.Run(); |
| 97 | } | 91 | m_is_running.store(true); |
| 92 | m_is_running.notify_all(); | ||
| 98 | 93 | ||
| 99 | running_guard = true; | 94 | Common::CondvarWait(m_should_run_cv, lk, stop_token, [&] { return !m_should_run; }); |
| 100 | Core::SystemResultStatus result = system.Run(); | ||
| 101 | if (result != Core::SystemResultStatus::Success) { | ||
| 102 | running_guard = false; | ||
| 103 | this->SetRunning(false); | ||
| 104 | emit ErrorThrown(result, system.GetStatusDetails()); | ||
| 105 | } | ||
| 106 | |||
| 107 | if (debugger_should_start) { | ||
| 108 | system.InitializeDebugger(); | ||
| 109 | debugger_should_start = false; | ||
| 110 | } | ||
| 111 | |||
| 112 | running_wait.Wait(); | ||
| 113 | result = system.Pause(); | ||
| 114 | if (result != Core::SystemResultStatus::Success) { | ||
| 115 | running_guard = false; | ||
| 116 | this->SetRunning(false); | ||
| 117 | emit ErrorThrown(result, system.GetStatusDetails()); | ||
| 118 | } | ||
| 119 | running_guard = false; | ||
| 120 | |||
| 121 | if (!stop_token.stop_requested()) { | ||
| 122 | was_active = true; | ||
| 123 | emit DebugModeEntered(); | ||
| 124 | } | ||
| 125 | } else { | 95 | } else { |
| 126 | std::unique_lock lock{running_mutex}; | 96 | m_system.Pause(); |
| 127 | Common::CondvarWait(running_cv, lock, stop_token, [&] { return IsRunning(); }); | 97 | m_is_running.store(false); |
| 98 | m_is_running.notify_all(); | ||
| 99 | |||
| 100 | emit DebugModeEntered(); | ||
| 101 | Common::CondvarWait(m_should_run_cv, lk, stop_token, [&] { return m_should_run; }); | ||
| 102 | emit DebugModeLeft(); | ||
| 128 | } | 103 | } |
| 129 | } | 104 | } |
| 130 | 105 | ||
| 131 | // Shutdown the main emulated process | 106 | // Shutdown the main emulated process |
| 132 | system.ShutdownMainProcess(); | 107 | m_system.DetachDebugger(); |
| 108 | m_system.ShutdownMainProcess(); | ||
| 133 | 109 | ||
| 134 | #if MICROPROFILE_ENABLED | 110 | #if MICROPROFILE_ENABLED |
| 135 | MicroProfileOnThreadExit(); | 111 | MicroProfileOnThreadExit(); |
diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index b24141fd9..1c2e76369 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h | |||
| @@ -47,7 +47,7 @@ class EmuThread final : public QThread { | |||
| 47 | Q_OBJECT | 47 | Q_OBJECT |
| 48 | 48 | ||
| 49 | public: | 49 | public: |
| 50 | explicit EmuThread(Core::System& system_); | 50 | explicit EmuThread(Core::System& system); |
| 51 | ~EmuThread() override; | 51 | ~EmuThread() override; |
| 52 | 52 | ||
| 53 | /** | 53 | /** |
| @@ -57,30 +57,30 @@ public: | |||
| 57 | void run() override; | 57 | void run() override; |
| 58 | 58 | ||
| 59 | /** | 59 | /** |
| 60 | * Sets whether the emulation thread is running or not | 60 | * Sets whether the emulation thread should run or not |
| 61 | * @param running_ Boolean value, set the emulation thread to running if true | 61 | * @param should_run Boolean value, set the emulation thread to running if true |
| 62 | * @note This function is thread-safe | ||
| 63 | */ | 62 | */ |
| 64 | void SetRunning(bool running_) { | 63 | void SetRunning(bool should_run) { |
| 65 | std::unique_lock lock{running_mutex}; | 64 | // TODO: Prevent other threads from modifying the state until we finish. |
| 66 | running = running_; | 65 | { |
| 67 | lock.unlock(); | 66 | // Notify the running thread to change state. |
| 68 | running_cv.notify_all(); | 67 | std::unique_lock run_lk{m_should_run_mutex}; |
| 69 | if (!running) { | 68 | m_should_run = should_run; |
| 70 | running_wait.Set(); | 69 | m_should_run_cv.notify_one(); |
| 71 | /// Wait until effectively paused | 70 | } |
| 72 | while (running_guard) | 71 | |
| 73 | ; | 72 | // Wait until paused, if pausing. |
| 73 | if (!should_run) { | ||
| 74 | m_is_running.wait(true); | ||
| 74 | } | 75 | } |
| 75 | } | 76 | } |
| 76 | 77 | ||
| 77 | /** | 78 | /** |
| 78 | * Check if the emulation thread is running or not | 79 | * Check if the emulation thread is running or not |
| 79 | * @return True if the emulation thread is running, otherwise false | 80 | * @return True if the emulation thread is running, otherwise false |
| 80 | * @note This function is thread-safe | ||
| 81 | */ | 81 | */ |
| 82 | bool IsRunning() const { | 82 | bool IsRunning() const { |
| 83 | return running; | 83 | return m_is_running.load(); |
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | /** | 86 | /** |
| @@ -88,18 +88,17 @@ public: | |||
| 88 | */ | 88 | */ |
| 89 | void ForceStop() { | 89 | void ForceStop() { |
| 90 | LOG_WARNING(Frontend, "Force stopping EmuThread"); | 90 | LOG_WARNING(Frontend, "Force stopping EmuThread"); |
| 91 | stop_source.request_stop(); | 91 | m_stop_source.request_stop(); |
| 92 | SetRunning(false); | ||
| 93 | } | 92 | } |
| 94 | 93 | ||
| 95 | private: | 94 | private: |
| 96 | bool running = false; | 95 | Core::System& m_system; |
| 97 | std::stop_source stop_source; | 96 | |
| 98 | std::mutex running_mutex; | 97 | std::stop_source m_stop_source; |
| 99 | std::condition_variable_any running_cv; | 98 | std::mutex m_should_run_mutex; |
| 100 | Common::Event running_wait{}; | 99 | std::condition_variable_any m_should_run_cv; |
| 101 | std::atomic_bool running_guard{false}; | 100 | std::atomic<bool> m_is_running{false}; |
| 102 | Core::System& system; | 101 | bool m_should_run{true}; |
| 103 | 102 | ||
| 104 | signals: | 103 | signals: |
| 105 | /** | 104 | /** |
| @@ -120,8 +119,6 @@ signals: | |||
| 120 | */ | 119 | */ |
| 121 | void DebugModeLeft(); | 120 | void DebugModeLeft(); |
| 122 | 121 | ||
| 123 | void ErrorThrown(Core::SystemResultStatus, std::string); | ||
| 124 | |||
| 125 | void LoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total); | 122 | void LoadProgress(VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total); |
| 126 | }; | 123 | }; |
| 127 | 124 | ||
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index fe140dce0..820f60e61 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -1498,7 +1498,7 @@ void GMainWindow::SetupSigInterrupts() { | |||
| 1498 | 1498 | ||
| 1499 | void GMainWindow::HandleSigInterrupt(int sig) { | 1499 | void GMainWindow::HandleSigInterrupt(int sig) { |
| 1500 | if (sig == SIGINT) { | 1500 | if (sig == SIGINT) { |
| 1501 | exit(1); | 1501 | _exit(1); |
| 1502 | } | 1502 | } |
| 1503 | 1503 | ||
| 1504 | // Calling into Qt directly from a signal handler is not safe, | 1504 | // Calling into Qt directly from a signal handler is not safe, |
| @@ -1794,15 +1794,16 @@ void GMainWindow::ShutdownGame() { | |||
| 1794 | Settings::values.use_speed_limit.SetValue(true); | 1794 | Settings::values.use_speed_limit.SetValue(true); |
| 1795 | 1795 | ||
| 1796 | system->SetShuttingDown(true); | 1796 | system->SetShuttingDown(true); |
| 1797 | system->DetachDebugger(); | ||
| 1798 | discord_rpc->Pause(); | 1797 | discord_rpc->Pause(); |
| 1799 | 1798 | ||
| 1800 | RequestGameExit(); | 1799 | RequestGameExit(); |
| 1800 | emu_thread->disconnect(); | ||
| 1801 | emu_thread->SetRunning(true); | ||
| 1801 | 1802 | ||
| 1802 | emit EmulationStopping(); | 1803 | emit EmulationStopping(); |
| 1803 | 1804 | ||
| 1804 | // Wait for emulation thread to complete and delete it | 1805 | // Wait for emulation thread to complete and delete it |
| 1805 | if (!emu_thread->wait(5000)) { | 1806 | if (system->DebuggerEnabled() || !emu_thread->wait(5000)) { |
| 1806 | emu_thread->ForceStop(); | 1807 | emu_thread->ForceStop(); |
| 1807 | emu_thread->wait(); | 1808 | emu_thread->wait(); |
| 1808 | } | 1809 | } |
| @@ -2919,8 +2920,6 @@ void GMainWindow::OnStartGame() { | |||
| 2919 | 2920 | ||
| 2920 | emu_thread->SetRunning(true); | 2921 | emu_thread->SetRunning(true); |
| 2921 | 2922 | ||
| 2922 | connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError); | ||
| 2923 | |||
| 2924 | UpdateMenuState(); | 2923 | UpdateMenuState(); |
| 2925 | OnTasStateChanged(); | 2924 | OnTasStateChanged(); |
| 2926 | 2925 | ||
| @@ -3904,79 +3903,6 @@ void GMainWindow::OnMouseActivity() { | |||
| 3904 | mouse_center_timer.stop(); | 3903 | mouse_center_timer.stop(); |
| 3905 | } | 3904 | } |
| 3906 | 3905 | ||
| 3907 | void GMainWindow::OnCoreError(Core::SystemResultStatus result, std::string details) { | ||
| 3908 | QMessageBox::StandardButton answer; | ||
| 3909 | QString status_message; | ||
| 3910 | const QString common_message = | ||
| 3911 | tr("The game you are trying to load requires additional files from your Switch to be " | ||
| 3912 | "dumped " | ||
| 3913 | "before playing.<br/><br/>For more information on dumping these files, please see the " | ||
| 3914 | "following wiki page: <a " | ||
| 3915 | "href='https://yuzu-emu.org/wiki/" | ||
| 3916 | "dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System " | ||
| 3917 | "Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to " | ||
| 3918 | "quit " | ||
| 3919 | "back to the game list? Continuing emulation may result in crashes, corrupted save " | ||
| 3920 | "data, or other bugs."); | ||
| 3921 | switch (result) { | ||
| 3922 | case Core::SystemResultStatus::ErrorSystemFiles: { | ||
| 3923 | QString message; | ||
| 3924 | if (details.empty()) { | ||
| 3925 | message = | ||
| 3926 | tr("yuzu was unable to locate a Switch system archive. %1").arg(common_message); | ||
| 3927 | } else { | ||
| 3928 | message = tr("yuzu was unable to locate a Switch system archive: %1. %2") | ||
| 3929 | .arg(QString::fromStdString(details), common_message); | ||
| 3930 | } | ||
| 3931 | |||
| 3932 | answer = QMessageBox::question(this, tr("System Archive Not Found"), message, | ||
| 3933 | QMessageBox::Yes | QMessageBox::No, QMessageBox::No); | ||
| 3934 | status_message = tr("System Archive Missing"); | ||
| 3935 | break; | ||
| 3936 | } | ||
| 3937 | |||
| 3938 | case Core::SystemResultStatus::ErrorSharedFont: { | ||
| 3939 | const QString message = | ||
| 3940 | tr("yuzu was unable to locate the Switch shared fonts. %1").arg(common_message); | ||
| 3941 | answer = QMessageBox::question(this, tr("Shared Fonts Not Found"), message, | ||
| 3942 | QMessageBox::Yes | QMessageBox::No, QMessageBox::No); | ||
| 3943 | status_message = tr("Shared Font Missing"); | ||
| 3944 | break; | ||
| 3945 | } | ||
| 3946 | |||
| 3947 | default: | ||
| 3948 | answer = QMessageBox::question( | ||
| 3949 | this, tr("Fatal Error"), | ||
| 3950 | tr("yuzu has encountered a fatal error, please see the log for more details. " | ||
| 3951 | "For more information on accessing the log, please see the following page: " | ||
| 3952 | "<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How " | ||
| 3953 | "to " | ||
| 3954 | "Upload the Log File</a>.<br/><br/>Would you like to quit back to the game " | ||
| 3955 | "list? " | ||
| 3956 | "Continuing emulation may result in crashes, corrupted save data, or other " | ||
| 3957 | "bugs."), | ||
| 3958 | QMessageBox::Yes | QMessageBox::No, QMessageBox::No); | ||
| 3959 | status_message = tr("Fatal Error encountered"); | ||
| 3960 | break; | ||
| 3961 | } | ||
| 3962 | |||
| 3963 | if (answer == QMessageBox::Yes) { | ||
| 3964 | if (emu_thread) { | ||
| 3965 | ShutdownGame(); | ||
| 3966 | |||
| 3967 | Settings::RestoreGlobalState(system->IsPoweredOn()); | ||
| 3968 | system->HIDCore().ReloadInputDevices(); | ||
| 3969 | UpdateStatusButtons(); | ||
| 3970 | } | ||
| 3971 | } else { | ||
| 3972 | // Only show the message if the game is still running. | ||
| 3973 | if (emu_thread) { | ||
| 3974 | emu_thread->SetRunning(true); | ||
| 3975 | message_label->setText(status_message); | ||
| 3976 | } | ||
| 3977 | } | ||
| 3978 | } | ||
| 3979 | |||
| 3980 | void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { | 3906 | void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { |
| 3981 | if (behavior == ReinitializeKeyBehavior::Warning) { | 3907 | if (behavior == ReinitializeKeyBehavior::Warning) { |
| 3982 | const auto res = QMessageBox::information( | 3908 | 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: | |||
| 332 | void ResetWindowSize900(); | 332 | void ResetWindowSize900(); |
| 333 | void ResetWindowSize1080(); | 333 | void ResetWindowSize1080(); |
| 334 | void OnCaptureScreenshot(); | 334 | void OnCaptureScreenshot(); |
| 335 | void OnCoreError(Core::SystemResultStatus, std::string); | ||
| 336 | void OnReinitializeKeys(ReinitializeKeyBehavior behavior); | 335 | void OnReinitializeKeys(ReinitializeKeyBehavior behavior); |
| 337 | void OnLanguageChanged(const QString& locale); | 336 | void OnLanguageChanged(const QString& locale); |
| 338 | void OnMouseActivity(); | 337 | void OnMouseActivity(); |