summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/core.cpp18
-rw-r--r--src/core/core.h4
-rw-r--r--src/yuzu/bootmanager.cpp82
-rw-r--r--src/yuzu/bootmanager.h51
-rw-r--r--src/yuzu/main.cpp80
-rw-r--r--src/yuzu/main.h1
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 {
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
556SystemResultStatus System::Run() { 550void System::Run() {
557 return impl->Run(); 551 impl->Run();
558} 552}
559 553
560SystemResultStatus System::Pause() { 554void System::Pause() {
561 return impl->Pause(); 555 impl->Pause();
562} 556}
563 557
564bool System::IsPaused() const { 558bool 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 682b37f47..40b3d91fc 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -46,30 +46,28 @@
46 46
47static Core::Frontend::WindowSystemType GetWindowSystemType(); 47static Core::Frontend::WindowSystemType GetWindowSystemType();
48 48
49EmuThread::EmuThread(Core::System& system_) : system{system_} {} 49EmuThread::EmuThread(Core::System& system) : m_system{system} {}
50 50
51EmuThread::~EmuThread() = default; 51EmuThread::~EmuThread() = default;
52 52
53void EmuThread::run() { 53void 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 5bbcf61f7..52867d628 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
49public: 49public:
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
95private: 94private:
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
104signals: 103signals:
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 2e6c2311a..c5285ffc9 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -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 }
@@ -2916,8 +2917,6 @@ void GMainWindow::OnStartGame() {
2916 2917
2917 emu_thread->SetRunning(true); 2918 emu_thread->SetRunning(true);
2918 2919
2919 connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError);
2920
2921 UpdateMenuState(); 2920 UpdateMenuState();
2922 OnTasStateChanged(); 2921 OnTasStateChanged();
2923 2922
@@ -3901,79 +3900,6 @@ void GMainWindow::OnMouseActivity() {
3901 mouse_center_timer.stop(); 3900 mouse_center_timer.stop();
3902} 3901}
3903 3902
3904void GMainWindow::OnCoreError(Core::SystemResultStatus result, std::string details) {
3905 QMessageBox::StandardButton answer;
3906 QString status_message;
3907 const QString common_message =
3908 tr("The game you are trying to load requires additional files from your Switch to be "
3909 "dumped "
3910 "before playing.<br/><br/>For more information on dumping these files, please see the "
3911 "following wiki page: <a "
3912 "href='https://yuzu-emu.org/wiki/"
3913 "dumping-system-archives-and-the-shared-fonts-from-a-switch-console/'>Dumping System "
3914 "Archives and the Shared Fonts from a Switch Console</a>.<br/><br/>Would you like to "
3915 "quit "
3916 "back to the game list? Continuing emulation may result in crashes, corrupted save "
3917 "data, or other bugs.");
3918 switch (result) {
3919 case Core::SystemResultStatus::ErrorSystemFiles: {
3920 QString message;
3921 if (details.empty()) {
3922 message =
3923 tr("yuzu was unable to locate a Switch system archive. %1").arg(common_message);
3924 } else {
3925 message = tr("yuzu was unable to locate a Switch system archive: %1. %2")
3926 .arg(QString::fromStdString(details), common_message);
3927 }
3928
3929 answer = QMessageBox::question(this, tr("System Archive Not Found"), message,
3930 QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
3931 status_message = tr("System Archive Missing");
3932 break;
3933 }
3934
3935 case Core::SystemResultStatus::ErrorSharedFont: {
3936 const QString message =
3937 tr("yuzu was unable to locate the Switch shared fonts. %1").arg(common_message);
3938 answer = QMessageBox::question(this, tr("Shared Fonts Not Found"), message,
3939 QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
3940 status_message = tr("Shared Font Missing");
3941 break;
3942 }
3943
3944 default:
3945 answer = QMessageBox::question(
3946 this, tr("Fatal Error"),
3947 tr("yuzu has encountered a fatal error, please see the log for more details. "
3948 "For more information on accessing the log, please see the following page: "
3949 "<a href='https://community.citra-emu.org/t/how-to-upload-the-log-file/296'>How "
3950 "to "
3951 "Upload the Log File</a>.<br/><br/>Would you like to quit back to the game "
3952 "list? "
3953 "Continuing emulation may result in crashes, corrupted save data, or other "
3954 "bugs."),
3955 QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
3956 status_message = tr("Fatal Error encountered");
3957 break;
3958 }
3959
3960 if (answer == QMessageBox::Yes) {
3961 if (emu_thread) {
3962 ShutdownGame();
3963
3964 Settings::RestoreGlobalState(system->IsPoweredOn());
3965 system->HIDCore().ReloadInputDevices();
3966 UpdateStatusButtons();
3967 }
3968 } else {
3969 // Only show the message if the game is still running.
3970 if (emu_thread) {
3971 emu_thread->SetRunning(true);
3972 message_label->setText(status_message);
3973 }
3974 }
3975}
3976
3977void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { 3903void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
3978 if (behavior == ReinitializeKeyBehavior::Warning) { 3904 if (behavior == ReinitializeKeyBehavior::Warning) {
3979 const auto res = QMessageBox::information( 3905 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();