mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Added system for handling core errors in citra-qt.
This commit is contained in:
		
							parent
							
								
									e523c76cc8
								
							
						
					
					
						commit
						1ecb322daa
					
				
					 9 changed files with 121 additions and 26 deletions
				
			
		|  | @ -37,7 +37,11 @@ void EmuThread::run() { | |||
|             if (!was_active) | ||||
|                 emit DebugModeLeft(); | ||||
| 
 | ||||
|             Core::System::GetInstance().RunLoop(); | ||||
|             Core::System::ResultStatus result = Core::System::GetInstance().RunLoop(); | ||||
|             if (result != Core::System::ResultStatus::Success) { | ||||
|                 emit ErrorThrown(result); | ||||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|             was_active = running || exec_step; | ||||
|             if (!was_active && !stop_run) | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ | |||
| #include <QGLWidget> | ||||
| #include <QThread> | ||||
| #include "common/thread.h" | ||||
| #include "core/core.h" | ||||
| #include "core/frontend/emu_window.h" | ||||
| #include "core/frontend/motion_emu.h" | ||||
| 
 | ||||
|  | @ -97,6 +98,8 @@ signals: | |||
|      * Qt::BlockingQueuedConnection (additionally block source thread until slot returns) | ||||
|      */ | ||||
|     void DebugModeLeft(); | ||||
| 
 | ||||
|     void ErrorThrown(Core::System::ResultStatus); | ||||
| }; | ||||
| 
 | ||||
| class GRenderWindow : public QWidget, public EmuWindow { | ||||
|  |  | |||
|  | @ -301,8 +301,7 @@ bool GMainWindow::LoadROM(const QString& filename) { | |||
| 
 | ||||
|     if (!gladLoadGL()) { | ||||
|         QMessageBox::critical(this, tr("Error while starting Citra!"), | ||||
|                               tr("Failed to initialize the video core!\n\n" | ||||
|                                  "Please ensure that your GPU supports OpenGL 3.3 and that you " | ||||
|                               tr("Your GPU may not support OpenGL 3.3, or you do not" | ||||
|                                  "have the latest graphics driver.")); | ||||
|         return false; | ||||
|     } | ||||
|  | @ -327,18 +326,17 @@ bool GMainWindow::LoadROM(const QString& filename) { | |||
|             break; | ||||
| 
 | ||||
|         case Core::System::ResultStatus::ErrorLoader_ErrorEncrypted: { | ||||
|             // Build the MessageBox ourselves to have clickable link
 | ||||
|             QMessageBox popup_error; | ||||
|             popup_error.setTextFormat(Qt::RichText); | ||||
|             popup_error.setWindowTitle(tr("Error while loading ROM!")); | ||||
|             popup_error.setText( | ||||
|             QMessageBox::critical( | ||||
|                 this, tr("Error while loading ROM!"), | ||||
|                 tr("The game that you are trying to load must be decrypted before being used with " | ||||
|                    "Citra.<br/><br/>" | ||||
|                    "For more information on dumping and decrypting games, please see: <a " | ||||
|                    "href='https://citra-emu.org/wiki/Dumping-Game-Cartridges'>https://" | ||||
|                    "citra-emu.org/wiki/Dumping-Game-Cartridges</a>")); | ||||
|             popup_error.setIcon(QMessageBox::Critical); | ||||
|             popup_error.exec(); | ||||
|                    "For more information on dumping and decrypting games, please see the following " | ||||
|                    "wiki pages: <ul>" | ||||
|                    "<li><a href='https://citra-emu.org/wiki/Dumping-Game-Cartridges/'>Dumping Game " | ||||
|                    "Cartridges</a></li>" | ||||
|                    "<li><a href='https://citra-emu.org/wiki/Dumping-Installed-Titles/'>Dumping " | ||||
|                    "Installed Titles</a></li>" | ||||
|                    "</ul>")); | ||||
|             break; | ||||
|         } | ||||
|         case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat: | ||||
|  | @ -346,8 +344,16 @@ bool GMainWindow::LoadROM(const QString& filename) { | |||
|                                   tr("The ROM format is not supported.")); | ||||
|             break; | ||||
| 
 | ||||
|         case Core::System::ResultStatus::ErrorOpenGL: | ||||
|             QMessageBox::critical(this, tr("Error while loading OpenGL!"), | ||||
|                                   tr("Your GPU may not support OpenGL 3.3, or you do not " | ||||
|                                      "have the latest graphics driver.")); | ||||
|             break; | ||||
| 
 | ||||
|         default: | ||||
|             QMessageBox::critical(this, tr("Error while loading ROM!"), tr("Unknown error!")); | ||||
|             QMessageBox::critical( | ||||
|                 this, tr("Error while loading ROM!"), | ||||
|                 tr("An unknown error occured. Please see the log for more details.")); | ||||
|             break; | ||||
|         } | ||||
|         return false; | ||||
|  | @ -530,6 +536,9 @@ void GMainWindow::OnMenuRecentFile() { | |||
| 
 | ||||
| void GMainWindow::OnStartGame() { | ||||
|     emu_thread->SetRunning(true); | ||||
|     qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus"); | ||||
|     connect(emu_thread.get(), SIGNAL(ErrorThrown(Core::System::ResultStatus)), this, | ||||
|             SLOT(OnCoreError(Core::System::ResultStatus))); | ||||
| 
 | ||||
|     ui.action_Start->setEnabled(false); | ||||
|     ui.action_Start->setText(tr("Continue")); | ||||
|  | @ -622,14 +631,57 @@ void GMainWindow::UpdateStatusBar() { | |||
|     emu_frametime_label->setVisible(true); | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::OnCoreError(Core::System::ResultStatus result) { | ||||
|     // Waiting for the dialog to be closed before shutting down causes a segfault, maybe because of
 | ||||
|     // the profiler
 | ||||
|     ShutdownGame(); | ||||
|     switch (result) { | ||||
|     case Core::System::ResultStatus::ErrorSystemFiles: | ||||
|         QMessageBox::critical( | ||||
|             this, "System Archive Not Found", | ||||
|             "Citra was unable to locate the 3DS system archive.<br/><br/>" | ||||
|             "The game you are trying to load requires additional files from your 3DS to be dumped " | ||||
|             "before playing.<br/><br/>" | ||||
|             "For more information on dumping these files, please see the following wiki page: " | ||||
|             "<a " | ||||
|             "href='https://citra-emu.org/wiki/" | ||||
|             "Dumping-System-Archives-and-the-Shared-Fonts-from-a-3DS-Console/'>Dumping System " | ||||
|             "Archives and the Shared Fonts from a 3DS Console</a>" | ||||
|             "."); | ||||
|         break; | ||||
| 
 | ||||
|     case Core::System::ResultStatus::ErrorSharedFont: | ||||
|         QMessageBox::critical( | ||||
|             this, "Shared Fonts Not Found", | ||||
|             "Citra was unable to locate the 3DS shared fonts.<br/><br/>" | ||||
|             "The game you are trying to load requires additional files from your 3DS to be dumped " | ||||
|             "before playing.<br/><br/>" | ||||
|             "For more information on dumping these files, please see the following wiki page: " | ||||
|             "<a " | ||||
|             "href='https://citra-emu.org/wiki/" | ||||
|             "Dumping-System-Archives-and-the-Shared-Fonts-from-a-3DS-Console/'>Dumping System " | ||||
|             "Archives and the Shared Fonts from a 3DS Console</a>" | ||||
|             "."); | ||||
|         break; | ||||
| 
 | ||||
|     case Core::System::ResultStatus::ErrorUnknown: | ||||
|         QMessageBox::critical( | ||||
|             this, "Fatal Error", | ||||
|             "Citra has encountered a fatal error, please see the log for more details."); | ||||
|         break; | ||||
| 
 | ||||
|     default: | ||||
|         break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool GMainWindow::ConfirmClose() { | ||||
|     if (emu_thread == nullptr || !UISettings::values.confirm_before_closing) | ||||
|         return true; | ||||
| 
 | ||||
|     auto answer = | ||||
|         QMessageBox::question(this, tr("Citra"), tr("Are you sure you want to close Citra?"), | ||||
|                               QMessageBox::Yes | QMessageBox::No, QMessageBox::No); | ||||
|     return answer != QMessageBox::No; | ||||
|     return QMessageBox::question(this, tr("Citra"), tr("Are you sure you want to close Citra?"), | ||||
|                                  QMessageBox::Yes | QMessageBox::No, | ||||
|                                  QMessageBox::No) != QMessageBox::No; | ||||
| } | ||||
| 
 | ||||
| void GMainWindow::closeEvent(QCloseEvent* event) { | ||||
|  |  | |||
|  | @ -125,6 +125,7 @@ private slots: | |||
|     void OnDisplayTitleBars(bool); | ||||
|     void ToggleWindowMode(); | ||||
|     void OnCreateGraphicsSurfaceViewer(); | ||||
|     void OnCoreError(Core::System::ResultStatus); | ||||
| 
 | ||||
| private: | ||||
|     void UpdateStatusBar(); | ||||
|  |  | |||
|  | @ -59,7 +59,7 @@ System::ResultStatus System::RunLoop(int tight_loop) { | |||
|     HW::Update(); | ||||
|     Reschedule(); | ||||
| 
 | ||||
|     return ResultStatus::Success; | ||||
|     return GetStatus(); | ||||
| } | ||||
| 
 | ||||
| System::ResultStatus System::SingleStep() { | ||||
|  | @ -73,11 +73,21 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file | |||
|         LOG_CRITICAL(Core, "Failed to obtain loader for %s!", filepath.c_str()); | ||||
|         return ResultStatus::ErrorGetLoader; | ||||
|     } | ||||
|     boost::optional<u32> system_mode = boost::none; | ||||
| 
 | ||||
|     boost::optional<u32> system_mode{app_loader->LoadKernelSystemMode()}; | ||||
|     Loader::ResultStatus load_result{app_loader->LoadKernelSystemMode(system_mode)}; | ||||
|     if (!system_mode) { | ||||
|         LOG_CRITICAL(Core, "Failed to determine system mode!"); | ||||
|         return ResultStatus::ErrorSystemMode; | ||||
|         LOG_CRITICAL(Core, "Failed to determine system mode (Error %i)!", load_result); | ||||
|         System::Shutdown(); | ||||
| 
 | ||||
|         switch (load_result) { | ||||
|         case Loader::ResultStatus::ErrorEncrypted: | ||||
|             return ResultStatus::ErrorLoader_ErrorEncrypted; | ||||
|         case Loader::ResultStatus::ErrorInvalidFormat: | ||||
|             return ResultStatus::ErrorLoader_ErrorInvalidFormat; | ||||
|         default: | ||||
|             return ResultStatus::ErrorSystemMode; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     ResultStatus init_result{Init(emu_window, system_mode.get())}; | ||||
|  | @ -87,7 +97,7 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file | |||
|         return init_result; | ||||
|     } | ||||
| 
 | ||||
|     const Loader::ResultStatus load_result{app_loader->Load()}; | ||||
|     load_result = app_loader->Load(); | ||||
|     if (Loader::ResultStatus::Success != load_result) { | ||||
|         LOG_CRITICAL(Core, "Failed to load ROM (Error %i)!", load_result); | ||||
|         System::Shutdown(); | ||||
|  | @ -101,6 +111,8 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file | |||
|             return ResultStatus::ErrorLoader; | ||||
|         } | ||||
|     } | ||||
|     // this->status will be used for errors while actually running the game
 | ||||
|     status = ResultStatus::Success; | ||||
|     return ResultStatus::Success; | ||||
| } | ||||
| 
 | ||||
|  | @ -142,7 +154,7 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { | |||
|     GDBStub::Init(); | ||||
| 
 | ||||
|     if (!VideoCore::Init(emu_window)) { | ||||
|         return ResultStatus::ErrorVideoCore; | ||||
|         return ResultStatus::ErrorOpenGL; | ||||
|     } | ||||
| 
 | ||||
|     LOG_DEBUG(Core, "Initialized OK"); | ||||
|  |  | |||
|  | @ -40,7 +40,11 @@ public: | |||
|         ErrorLoader_ErrorEncrypted, ///< Error loading the specified application due to encryption
 | ||||
|         ErrorLoader_ErrorInvalidFormat, ///< Error loading the specified application due to an
 | ||||
|                                         /// invalid format
 | ||||
|         ErrorSystemFiles,               ///< Error in finding system files
 | ||||
|         ErrorSharedFont,                ///< Error in finding shared font
 | ||||
|         ErrorVideoCore,                 ///< Error in the video core
 | ||||
|         ErrorOpenGL,                    ///< Error when initializing OpenGL
 | ||||
|         ErrorUnknown                    ///< Any other error
 | ||||
|     }; | ||||
| 
 | ||||
|     /**
 | ||||
|  | @ -105,6 +109,14 @@ public: | |||
|     PerfStats perf_stats; | ||||
|     FrameLimiter frame_limiter; | ||||
| 
 | ||||
|     ResultStatus GetStatus() { | ||||
|         return status; | ||||
|     } | ||||
| 
 | ||||
|     void SetStatus(ResultStatus newStatus) { | ||||
|         status = newStatus; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     /**
 | ||||
|      * Initialize the emulated system. | ||||
|  | @ -130,6 +142,7 @@ private: | |||
|     std::unique_ptr<Core::TelemetrySession> telemetry_session; | ||||
| 
 | ||||
|     static System s_instance; | ||||
|     ResultStatus status; | ||||
| }; | ||||
| 
 | ||||
| inline ARM_Interface& CPU() { | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ | |||
| #include "common/common_paths.h" | ||||
| #include "common/file_util.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "core/core.h" | ||||
| #include "core/hle/applets/applet.h" | ||||
| #include "core/hle/kernel/event.h" | ||||
| #include "core/hle/kernel/mutex.h" | ||||
|  | @ -74,6 +75,7 @@ void GetSharedFont(Service::Interface* self) { | |||
|         LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds"); | ||||
|         rb.Push<u32>(-1); // TODO: Find the right error code
 | ||||
|         rb.Skip(1 + 2, true); | ||||
|         Core::System::GetInstance().SetStatus(Core::System::ResultStatus::ErrorSharedFont); | ||||
|         return; | ||||
|     } | ||||
| 
 | ||||
|  | @ -279,8 +281,9 @@ void CancelParameter(Service::Interface* self) { | |||
|     rb.Push(RESULT_SUCCESS); // No error
 | ||||
|     rb.Push(true);           // Set to Success
 | ||||
| 
 | ||||
|     LOG_WARNING(Service_APT, "(STUBBED) called check_sender=0x%08X, sender_appid=0x%08X, " | ||||
|                              "check_receiver=0x%08X, receiver_appid=0x%08X", | ||||
|     LOG_WARNING(Service_APT, | ||||
|                 "(STUBBED) called check_sender=0x%08X, sender_appid=0x%08X, " | ||||
|                 "check_receiver=0x%08X, receiver_appid=0x%08X", | ||||
|                 check_sender, sender_appid, check_receiver, receiver_appid); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ | |||
| #include "common/bit_field.h" | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "core/core.h" | ||||
| #include "core/hle/result.h" | ||||
| #include "core/hle/service/err_f.h" | ||||
| 
 | ||||
|  | @ -172,6 +173,7 @@ static void ThrowFatalError(Interface* self) { | |||
|     const ErrInfo* errinfo = reinterpret_cast<ErrInfo*>(&cmd_buff[1]); | ||||
|     LOG_CRITICAL(Service_ERR, "Fatal error type: %s", | ||||
|                  GetErrType(errinfo->errinfo_common.specifier).c_str()); | ||||
|     Core::System::GetInstance().SetStatus(Core::System::ResultStatus::ErrorUnknown); | ||||
| 
 | ||||
|     // Generic Info
 | ||||
|     LogGenericInfo(errinfo->errinfo_common); | ||||
|  |  | |||
|  | @ -8,6 +8,7 @@ | |||
| #include "common/logging/log.h" | ||||
| #include "common/scope_exit.h" | ||||
| #include "common/string_util.h" | ||||
| #include "core/core.h" | ||||
| #include "core/file_sys/errors.h" | ||||
| #include "core/hle/kernel/client_session.h" | ||||
| #include "core/hle/result.h" | ||||
|  | @ -132,6 +133,10 @@ static void OpenFileDirectly(Service::Interface* self) { | |||
|         LOG_ERROR(Service_FS, | ||||
|                   "failed to get a handle for archive archive_id=0x%08X archive_path=%s", | ||||
|                   static_cast<u32>(archive_id), archive_path.DebugStr().c_str()); | ||||
|         if (static_cast<u32>(archive_id) == 0x2345678A) { | ||||
|             Core::System::GetInstance().SetStatus(Core::System::ResultStatus::ErrorSystemFiles); | ||||
|             return; | ||||
|         } | ||||
|         cmd_buff[1] = archive_handle.Code().raw; | ||||
|         cmd_buff[3] = 0; | ||||
|         return; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue