mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	core: Consolidate top-level system state into a singleton.
This commit is contained in:
		
							parent
							
								
									81e22ae8c7
								
							
						
					
					
						commit
						198b6c9bdd
					
				
					 8 changed files with 167 additions and 106 deletions
				
			
		|  | @ -64,7 +64,7 @@ int main(int argc, char** argv) { | |||
|         return -1; | ||||
|     } | ||||
| #endif | ||||
|     std::string boot_filename; | ||||
|     std::string filepath; | ||||
| 
 | ||||
|     static struct option long_options[] = { | ||||
|         {"gdbport", required_argument, 0, 'g'}, | ||||
|  | @ -97,9 +97,9 @@ int main(int argc, char** argv) { | |||
|             } | ||||
|         } else { | ||||
| #ifdef _WIN32 | ||||
|             boot_filename = Common::UTF16ToUTF8(argv_w[optind]); | ||||
|             filepath = Common::UTF16ToUTF8(argv_w[optind]); | ||||
| #else | ||||
|             boot_filename = argv[optind]; | ||||
|             filepath = argv[optind]; | ||||
| #endif | ||||
|             optind++; | ||||
|         } | ||||
|  | @ -115,7 +115,7 @@ int main(int argc, char** argv) { | |||
|     MicroProfileOnThreadCreate("EmuThread"); | ||||
|     SCOPE_EXIT({ MicroProfileShutdown(); }); | ||||
| 
 | ||||
|     if (boot_filename.empty()) { | ||||
|     if (filepath.empty()) { | ||||
|         LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified"); | ||||
|         return -1; | ||||
|     } | ||||
|  | @ -127,27 +127,20 @@ int main(int argc, char** argv) { | |||
|     Settings::values.use_gdbstub = use_gdbstub; | ||||
|     Settings::Apply(); | ||||
| 
 | ||||
|     std::unique_ptr<EmuWindow_SDL2> emu_window = std::make_unique<EmuWindow_SDL2>(); | ||||
|     std::unique_ptr<EmuWindow_SDL2> emu_window{ std::make_unique<EmuWindow_SDL2>() }; | ||||
| 
 | ||||
|     std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(boot_filename); | ||||
|     if (!loader) { | ||||
|         LOG_CRITICAL(Frontend, "Failed to obtain loader for %s!", boot_filename.c_str()); | ||||
|     Core::System& system{ Core::System::GetInstance() }; | ||||
| 
 | ||||
|     SCOPE_EXIT({ system.Shutdown(); }); | ||||
| 
 | ||||
|     const Core::System::ResultStatus load_result{ system.Load(emu_window.get(), filepath) }; | ||||
| 
 | ||||
|     switch (load_result) { | ||||
|     case Core::System::ResultStatus::ErrorGetLoader: | ||||
|         LOG_CRITICAL(Frontend, "Failed to obtain loader for %s!", filepath.c_str()); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     boost::optional<u32> system_mode = loader->LoadKernelSystemMode(); | ||||
| 
 | ||||
|     if (!system_mode) { | ||||
|         LOG_CRITICAL(Frontend, "Failed to load ROM (Could not determine system mode)!"); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     System::Init(emu_window.get(), system_mode.get()); | ||||
|     SCOPE_EXIT({ System::Shutdown(); }); | ||||
| 
 | ||||
|     Loader::ResultStatus load_result = loader->Load(); | ||||
|     if (Loader::ResultStatus::Success != load_result) { | ||||
|         LOG_CRITICAL(Frontend, "Failed to load ROM (Error %i)!", load_result); | ||||
|     case Core::System::ResultStatus::ErrorLoader: | ||||
|         LOG_CRITICAL(Frontend, "Failed to load ROM!"); | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -60,7 +60,7 @@ void EmuThread::run() { | |||
|     } | ||||
| 
 | ||||
|     // Shutdown the core emulation
 | ||||
|     System::Shutdown(); | ||||
|     Core::System::GetInstance().Shutdown(); | ||||
| 
 | ||||
| #if MICROPROFILE_ENABLED | ||||
|     MicroProfileOnThreadExit(); | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent) | |||
|     ui->setupUi(this); | ||||
|     this->setConfiguration(); | ||||
| 
 | ||||
|     ui->toggle_cpu_jit->setEnabled(!System::IsPoweredOn()); | ||||
|     ui->toggle_cpu_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn()); | ||||
| } | ||||
| 
 | ||||
| ConfigureGeneral::~ConfigureGeneral() {} | ||||
|  |  | |||
|  | @ -13,7 +13,7 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent) | |||
|     ui->setupUi(this); | ||||
|     this->setConfiguration(); | ||||
| 
 | ||||
|     ui->toggle_vsync->setEnabled(!System::IsPoweredOn()); | ||||
|     ui->toggle_vsync->setEnabled(!Core::System::GetInstance().IsPoweredOn()); | ||||
| } | ||||
| 
 | ||||
| ConfigureGraphics::~ConfigureGraphics() {} | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui:: | |||
| ConfigureSystem::~ConfigureSystem() {} | ||||
| 
 | ||||
| void ConfigureSystem::setConfiguration() { | ||||
|     enabled = !System::IsPoweredOn(); | ||||
|     enabled = !Core::System::GetInstance().IsPoweredOn(); | ||||
| 
 | ||||
|     if (!enabled) { | ||||
|         ReadSystemSettings(); | ||||
|  |  | |||
|  | @ -274,7 +274,7 @@ void GMainWindow::OnDisplayTitleBars(bool show) { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| bool GMainWindow::InitializeSystem(u32 system_mode) { | ||||
| bool GMainWindow::LoadROM(const std::string& filename) { | ||||
|     // Shutdown previous session if the emu thread is still active...
 | ||||
|     if (emu_thread != nullptr) | ||||
|         ShutdownGame(); | ||||
|  | @ -284,79 +284,50 @@ bool GMainWindow::InitializeSystem(u32 system_mode) { | |||
| 
 | ||||
|     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 " | ||||
|                                  "have the latest graphics driver.")); | ||||
|             tr("Failed to initialize the video core!\n\n" | ||||
|                 "Please ensure that your GPU supports OpenGL 3.3 and that you " | ||||
|                 "have the latest graphics driver.")); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     // Initialize the core emulation
 | ||||
|     System::Result system_result = System::Init(render_window, system_mode); | ||||
|     if (System::Result::Success != system_result) { | ||||
|         switch (system_result) { | ||||
|         case System::Result::ErrorInitVideoCore: | ||||
|             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 " | ||||
|                                      "have the latest graphics driver.")); | ||||
|             break; | ||||
|     Core::System& system{ Core::System::GetInstance() }; | ||||
| 
 | ||||
|         default: | ||||
|             QMessageBox::critical(this, tr("Error while starting Citra!"), | ||||
|                                   tr("Unknown error (please check the log)!")); | ||||
|             break; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| bool GMainWindow::LoadROM(const std::string& filename) { | ||||
|     std::unique_ptr<Loader::AppLoader> app_loader = Loader::GetLoader(filename); | ||||
|     if (!app_loader) { | ||||
|         LOG_CRITICAL(Frontend, "Failed to obtain loader for %s!", filename.c_str()); | ||||
|         QMessageBox::critical(this, tr("Error while loading ROM!"), | ||||
|                               tr("The ROM format is not supported.")); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     boost::optional<u32> system_mode = app_loader->LoadKernelSystemMode(); | ||||
|     if (!system_mode) { | ||||
|         LOG_CRITICAL(Frontend, "Failed to load ROM!"); | ||||
|         QMessageBox::critical(this, tr("Error while loading ROM!"), | ||||
|                               tr("Could not determine the system mode.")); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     if (!InitializeSystem(system_mode.get())) | ||||
|         return false; | ||||
| 
 | ||||
|     Loader::ResultStatus result = app_loader->Load(); | ||||
|     if (Loader::ResultStatus::Success != result) { | ||||
|         System::Shutdown(); | ||||
|         LOG_CRITICAL(Frontend, "Failed to load ROM!"); | ||||
|     const Core::System::ResultStatus result{ system.Load(render_window, filename) }; | ||||
| 
 | ||||
|     if (result != Core::System::ResultStatus::Success) { | ||||
|         switch (result) { | ||||
|         case Loader::ResultStatus::ErrorEncrypted: { | ||||
|         case Core::System::ResultStatus::ErrorGetLoader: | ||||
|             LOG_CRITICAL(Frontend, "Failed to obtain loader for %s!", filename.c_str()); | ||||
|             QMessageBox::critical(this, tr("Error while loading ROM!"), | ||||
|                 tr("The ROM format is not supported.")); | ||||
|             break; | ||||
| 
 | ||||
|         case Core::System::ResultStatus::ErrorSystemMode: | ||||
|             LOG_CRITICAL(Frontend, "Failed to load ROM!"); | ||||
|             QMessageBox::critical(this, tr("Error while loading ROM!"), | ||||
|                 tr("Could not determine the system mode.")); | ||||
|             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( | ||||
|                 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>")); | ||||
|                     "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(); | ||||
|             break; | ||||
|         } | ||||
|         case Loader::ResultStatus::ErrorInvalidFormat: | ||||
|         case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat: | ||||
|             QMessageBox::critical(this, tr("Error while loading ROM!"), | ||||
|                                   tr("The ROM format is not supported.")); | ||||
|                 tr("The ROM format is not supported.")); | ||||
|             break; | ||||
|         case Loader::ResultStatus::Error: | ||||
| 
 | ||||
|         default: | ||||
|             QMessageBox::critical(this, tr("Error while loading ROM!"), tr("Unknown error!")); | ||||
|  |  | |||
|  | @ -13,33 +13,30 @@ | |||
| #include "core/system.h" | ||||
| #include "video_core/video_core.h" | ||||
| 
 | ||||
| namespace System { | ||||
| namespace Core { | ||||
| 
 | ||||
| static bool is_powered_on{false}; | ||||
| /*static*/ System System::s_instance; | ||||
| 
 | ||||
| Result Init(EmuWindow* emu_window, u32 system_mode) { | ||||
| System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { | ||||
|     Core::Init(); | ||||
|     CoreTiming::Init(); | ||||
|     Memory::Init(); | ||||
|     HW::Init(); | ||||
|     Kernel::Init(system_mode); | ||||
|     HLE::Init(); | ||||
|     if (!VideoCore::Init(emu_window)) { | ||||
|         return Result::ErrorInitVideoCore; | ||||
|     } | ||||
|     AudioCore::Init(); | ||||
|     GDBStub::Init(); | ||||
| 
 | ||||
|     if (!VideoCore::Init(emu_window)) { | ||||
|         return ResultStatus::ErrorVideoCore; | ||||
|     } | ||||
| 
 | ||||
|     is_powered_on = true; | ||||
| 
 | ||||
|     return Result::Success; | ||||
|     return ResultStatus::Success; | ||||
| } | ||||
| 
 | ||||
| bool IsPoweredOn() { | ||||
|     return is_powered_on; | ||||
| } | ||||
| 
 | ||||
| void Shutdown() { | ||||
| void System::Shutdown() { | ||||
|     GDBStub::Shutdown(); | ||||
|     AudioCore::Shutdown(); | ||||
|     VideoCore::Shutdown(); | ||||
|  | @ -52,4 +49,42 @@ void Shutdown() { | |||
|     is_powered_on = false; | ||||
| } | ||||
| 
 | ||||
| } // namespace
 | ||||
| System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& filepath) { | ||||
|     state.app_loader = Loader::GetLoader(filepath); | ||||
| 
 | ||||
|     if (!state.app_loader) { | ||||
|         LOG_CRITICAL(Frontend, "Failed to obtain loader for %s!", filepath.c_str()); | ||||
|         return ResultStatus::ErrorGetLoader; | ||||
|     } | ||||
| 
 | ||||
|     boost::optional<u32> system_mode{ state.app_loader->LoadKernelSystemMode() }; | ||||
|     if (!system_mode) { | ||||
|         LOG_CRITICAL(Frontend, "Failed to determine system mode!"); | ||||
|         return ResultStatus::ErrorSystemMode; | ||||
|     } | ||||
| 
 | ||||
|     ResultStatus init_result{ Init(emu_window, system_mode.get()) }; | ||||
|     if (init_result != ResultStatus::Success) { | ||||
|         LOG_CRITICAL(Frontend, "Failed to initialize system (Error %i)!", init_result); | ||||
|         System::Shutdown(); | ||||
|         return init_result; | ||||
|     } | ||||
| 
 | ||||
|     const Loader::ResultStatus load_result{ state.app_loader->Load() }; | ||||
|     if (Loader::ResultStatus::Success != load_result) { | ||||
|         LOG_CRITICAL(Frontend, "Failed to load ROM (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::ErrorLoader; | ||||
|         } | ||||
|     } | ||||
|     return ResultStatus::Success; | ||||
| } | ||||
| 
 | ||||
| } // namespace Core
 | ||||
|  |  | |||
|  | @ -4,18 +4,80 @@ | |||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <string> | ||||
| 
 | ||||
| #include "core/loader/loader.h" | ||||
| 
 | ||||
| class EmuWindow; | ||||
| 
 | ||||
| namespace System { | ||||
| namespace Core { | ||||
| 
 | ||||
| enum class Result { | ||||
|     Success,            ///< Everything is fine
 | ||||
|     Error,              ///< Something went wrong (no module specified)
 | ||||
|     ErrorInitCore,      ///< Something went wrong during core init
 | ||||
|     ErrorInitVideoCore, ///< Something went wrong during video core init
 | ||||
| class System { | ||||
| public: | ||||
|     struct State { | ||||
|         std::unique_ptr<Loader::AppLoader> app_loader; | ||||
|     }; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Gets the instance of the System singleton class. | ||||
|      * @returns Reference to the instance of the System singleton class. | ||||
|      */ | ||||
|     static System& GetInstance() { | ||||
|         return s_instance; | ||||
|     } | ||||
| 
 | ||||
|     /// Enumeration representing the return values of the System Initialize and Load process.
 | ||||
|     enum class ResultStatus : u32 { | ||||
|         Success, ///< Succeeded
 | ||||
|         ErrorGetLoader, ///< Error finding the correct application loader
 | ||||
|         ErrorSystemMode, ///< Error determining the system mode
 | ||||
|         ErrorLoader, ///< Error loading the specified application
 | ||||
|         ErrorLoader_ErrorEncrypted, ///< Error loading the specified application due to encryption
 | ||||
|         ErrorLoader_ErrorInvalidFormat, ///< Error loading the specified application due to an invalid format
 | ||||
|         ErrorVideoCore, ///< Error in the video core
 | ||||
|     }; | ||||
| 
 | ||||
|     /**
 | ||||
|      * Initialize the emulated system. | ||||
|      * @param emu_window Pointer to the host-system window used for video output and keyboard input. | ||||
|      * @param system_mode The system mode. | ||||
|      * @returns ResultStatus code, indicating if the operation succeeded. | ||||
|      */ | ||||
|     ResultStatus Init(EmuWindow* emu_window, u32 system_mode); | ||||
| 
 | ||||
|     /// Shutdown the emulated system.
 | ||||
|     void Shutdown(); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Load an executable application. | ||||
|      * @param emu_window Pointer to the host-system window used for video output and keyboard input. | ||||
|      * @param filepath String path to the executable application to load on the host file system. | ||||
|      * @returns ResultStatus code, indicating if the operation succeeded. | ||||
|      */ | ||||
|     ResultStatus Load(EmuWindow* emu_window, const std::string& filepath); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Indicates if the emulated system is powered on (all subsystems initialized and able to run an | ||||
|      * application). | ||||
|      * @returns True if the emulated system is powered on, otherwise false. | ||||
|      */ | ||||
|     bool IsPoweredOn() const { | ||||
|         return is_powered_on; | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|      * Gets the internal state of the emulated system. | ||||
|      * @returns The internal state of the emulated system | ||||
|      */ | ||||
|     State& GetState() { | ||||
|         return state; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     bool is_powered_on{}; | ||||
|     State state; | ||||
| 
 | ||||
|     static System s_instance; | ||||
| }; | ||||
| 
 | ||||
| Result Init(EmuWindow* emu_window, u32 system_mode); | ||||
| bool IsPoweredOn(); | ||||
| void Shutdown(); | ||||
| } | ||||
| } // namespace Core
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue