diff options
Diffstat (limited to 'src/yuzu/main.cpp')
-rw-r--r-- | src/yuzu/main.cpp | 474 |
1 files changed, 289 insertions, 185 deletions
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 9844e4764..432379705 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -16,7 +16,7 @@ #include "applets/software_keyboard.h" #include "applets/web_browser.h" #include "configuration/configure_input.h" -#include "configuration/configure_per_general.h" +#include "configuration/configure_per_game.h" #include "core/file_sys/vfs.h" #include "core/file_sys/vfs_real.h" #include "core/frontend/applets/general_frontend.h" @@ -107,6 +107,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "yuzu/game_list.h" #include "yuzu/game_list_p.h" #include "yuzu/hotkeys.h" +#include "yuzu/install_dialog.h" #include "yuzu/loading_screen.h" #include "yuzu/main.h" #include "yuzu/uisettings.h" @@ -534,15 +535,15 @@ void GMainWindow::InitializeWidgets() { if (emulation_running) { return; } - bool is_async = - !Settings::values.use_asynchronous_gpu_emulation || Settings::values.use_multi_core; - Settings::values.use_asynchronous_gpu_emulation = is_async; - async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation); + bool is_async = !Settings::values.use_asynchronous_gpu_emulation.GetValue() || + Settings::values.use_multi_core.GetValue(); + Settings::values.use_asynchronous_gpu_emulation.SetValue(is_async); + async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue()); Settings::Apply(); }); async_status_button->setText(tr("ASYNC")); async_status_button->setCheckable(true); - async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation); + async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue()); // Setup Multicore button multicore_status_button = new QPushButton(); @@ -552,17 +553,17 @@ void GMainWindow::InitializeWidgets() { if (emulation_running) { return; } - Settings::values.use_multi_core = !Settings::values.use_multi_core; - bool is_async = - Settings::values.use_asynchronous_gpu_emulation || Settings::values.use_multi_core; - Settings::values.use_asynchronous_gpu_emulation = is_async; - async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation); - multicore_status_button->setChecked(Settings::values.use_multi_core); + Settings::values.use_multi_core.SetValue(!Settings::values.use_multi_core.GetValue()); + bool is_async = Settings::values.use_asynchronous_gpu_emulation.GetValue() || + Settings::values.use_multi_core.GetValue(); + Settings::values.use_asynchronous_gpu_emulation.SetValue(is_async); + async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue()); + multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue()); Settings::Apply(); }); multicore_status_button->setText(tr("MULTICORE")); multicore_status_button->setCheckable(true); - multicore_status_button->setChecked(Settings::values.use_multi_core); + multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue()); statusBar()->insertPermanentWidget(0, multicore_status_button); statusBar()->insertPermanentWidget(0, async_status_button); @@ -581,16 +582,16 @@ void GMainWindow::InitializeWidgets() { renderer_status_button->setCheckable(false); renderer_status_button->setDisabled(true); #else - renderer_status_button->setChecked(Settings::values.renderer_backend == + renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() == Settings::RendererBackend::Vulkan); connect(renderer_status_button, &QPushButton::clicked, [=] { if (emulation_running) { return; } if (renderer_status_button->isChecked()) { - Settings::values.renderer_backend = Settings::RendererBackend::Vulkan; + Settings::values.renderer_backend.SetValue(Settings::RendererBackend::Vulkan); } else { - Settings::values.renderer_backend = Settings::RendererBackend::OpenGL; + Settings::values.renderer_backend.SetValue(Settings::RendererBackend::OpenGL); } Settings::Apply(); @@ -727,21 +728,24 @@ void GMainWindow::InitializeHotkeys() { }); connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Toggle Speed Limit"), this), &QShortcut::activated, this, [&] { - Settings::values.use_frame_limit = !Settings::values.use_frame_limit; + Settings::values.use_frame_limit.SetValue( + !Settings::values.use_frame_limit.GetValue()); UpdateStatusBar(); }); constexpr u16 SPEED_LIMIT_STEP = 5; connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Increase Speed Limit"), this), &QShortcut::activated, this, [&] { - if (Settings::values.frame_limit < 9999 - SPEED_LIMIT_STEP) { - Settings::values.frame_limit += SPEED_LIMIT_STEP; + if (Settings::values.frame_limit.GetValue() < 9999 - SPEED_LIMIT_STEP) { + Settings::values.frame_limit.SetValue(SPEED_LIMIT_STEP + + Settings::values.frame_limit.GetValue()); UpdateStatusBar(); } }); connect(hotkey_registry.GetHotkey(main_window, QStringLiteral("Decrease Speed Limit"), this), &QShortcut::activated, this, [&] { - if (Settings::values.frame_limit > SPEED_LIMIT_STEP) { - Settings::values.frame_limit -= SPEED_LIMIT_STEP; + if (Settings::values.frame_limit.GetValue() > SPEED_LIMIT_STEP) { + Settings::values.frame_limit.SetValue(Settings::values.frame_limit.GetValue() - + SPEED_LIMIT_STEP); UpdateStatusBar(); } }); @@ -844,6 +848,9 @@ void GMainWindow::ConnectWidgetEvents() { connect(game_list, &GameList::OpenPerGameGeneralRequested, this, &GMainWindow::OnGameListOpenPerGameProperties); + connect(this, &GMainWindow::UpdateInstallProgress, this, + &GMainWindow::IncrementInstallProgress); + connect(this, &GMainWindow::EmulationStarting, render_window, &GRenderWindow::OnEmulationStarting); connect(this, &GMainWindow::EmulationStopping, render_window, @@ -1039,6 +1046,17 @@ void GMainWindow::BootGame(const QString& filename) { LOG_INFO(Frontend, "yuzu starting..."); StoreRecentFile(filename); // Put the filename on top of the list + u64 title_id{0}; + + const auto v_file = Core::GetGameFileFromPath(vfs, filename.toUtf8().constData()); + const auto loader = Loader::GetLoader(v_file); + if (!(loader == nullptr || loader->ReadProgramId(title_id) != Loader::ResultStatus::Success)) { + // Load per game settings + Config per_game_config(fmt::format("{:016X}.ini", title_id), false); + } + + Settings::LogSettings(); + if (UISettings::values.select_user_on_boot) { SelectAndSetCurrentUser(); } @@ -1063,6 +1081,7 @@ void GMainWindow::BootGame(const QString& filename) { &LoadingScreen::OnLoadProgress, Qt::QueuedConnection); // Update the GUI + UpdateStatusButtons(); if (ui.action_Single_Window_Mode->isChecked()) { game_list->hide(); game_list_placeholder->hide(); @@ -1078,8 +1097,6 @@ void GMainWindow::BootGame(const QString& filename) { ui.centralwidget->setMouseTracking(true); } - const u64 title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); - std::string title_name; std::string title_version; const auto res = Core::System::GetInstance().GetGameName(title_name); @@ -1521,7 +1538,7 @@ void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) { return; } - ConfigurePerGameGeneral dialog(this, title_id); + ConfigurePerGame dialog(this, title_id); dialog.LoadFromFile(v_file); auto result = dialog.exec(); if (result == QDialog::Accepted) { @@ -1532,7 +1549,14 @@ void GMainWindow::OnGameListOpenPerGameProperties(const std::string& file) { game_list->PopulateAsync(UISettings::values.game_dirs); } - config->Save(); + // Do not cause the global config to write local settings into the config file + Settings::RestoreGlobalState(); + + if (!Core::System::GetInstance().IsPoweredOn()) { + config->Save(); + } + } else { + Settings::RestoreGlobalState(); } } @@ -1573,187 +1597,255 @@ void GMainWindow::OnMenuLoadFolder() { } } +void GMainWindow::IncrementInstallProgress() { + install_progress->setValue(install_progress->value() + 1); +} + void GMainWindow::OnMenuInstallToNAND() { const QString file_filter = tr("Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive " - "(*.nca);;Nintendo Submissions Package (*.nsp);;NX Cartridge " + "(*.nca);;Nintendo Submission Package (*.nsp);;NX Cartridge " "Image (*.xci)"); - QString filename = QFileDialog::getOpenFileName(this, tr("Install File"), - UISettings::values.roms_path, file_filter); - if (filename.isEmpty()) { + QStringList filenames = QFileDialog::getOpenFileNames( + this, tr("Install Files"), UISettings::values.roms_path, file_filter); + + if (filenames.isEmpty()) { + return; + } + + InstallDialog installDialog(this, filenames); + if (installDialog.exec() == QDialog::Rejected) { + return; + } + + const QStringList files = installDialog.GetFiles(); + + if (files.isEmpty()) { + return; + } + + int remaining = filenames.size(); + + // This would only overflow above 2^43 bytes (8.796 TB) + int total_size = 0; + for (const QString& file : files) { + total_size += static_cast<int>(QFile(file).size() / 0x1000); + } + if (total_size < 0) { + LOG_CRITICAL(Frontend, "Attempting to install too many files, aborting."); return; } + QStringList new_files{}; // Newly installed files that do not yet exist in the NAND + QStringList overwritten_files{}; // Files that overwrote those existing in the NAND + QStringList failed_files{}; // Files that failed to install due to errors + + ui.action_Install_File_NAND->setEnabled(false); + + install_progress = new QProgressDialog(QStringLiteral(""), tr("Cancel"), 0, total_size, this); + install_progress->setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint & + ~Qt::WindowMaximizeButtonHint); + install_progress->setAttribute(Qt::WA_DeleteOnClose, true); + install_progress->setFixedWidth(installDialog.GetMinimumWidth() + 40); + install_progress->show(); + + for (const QString& file : files) { + install_progress->setWindowTitle(tr("%n file(s) remaining", "", remaining)); + install_progress->setLabelText( + tr("Installing file \"%1\"...").arg(QFileInfo(file).fileName())); + + QFuture<InstallResult> future; + InstallResult result; + + if (file.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) || + file.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { + + future = QtConcurrent::run([this, &file] { return InstallNSPXCI(file); }); + + while (!future.isFinished()) { + QCoreApplication::processEvents(); + } + + result = future.result(); + + } else { + result = InstallNCA(file); + } + + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + + switch (result) { + case InstallResult::Success: + new_files.append(QFileInfo(file).fileName()); + break; + case InstallResult::Overwrite: + overwritten_files.append(QFileInfo(file).fileName()); + break; + case InstallResult::Failure: + failed_files.append(QFileInfo(file).fileName()); + break; + } + + --remaining; + } + + install_progress->close(); + + const QString install_results = + (new_files.isEmpty() ? QStringLiteral("") + : tr("%n file(s) were newly installed\n", "", new_files.size())) + + (overwritten_files.isEmpty() + ? QStringLiteral("") + : tr("%n file(s) were overwritten\n", "", overwritten_files.size())) + + (failed_files.isEmpty() ? QStringLiteral("") + : tr("%n file(s) failed to install\n", "", failed_files.size())); + + QMessageBox::information(this, tr("Install Results"), install_results); + game_list->PopulateAsync(UISettings::values.game_dirs); + FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP + + "game_list"); + ui.action_Install_File_NAND->setEnabled(true); +} + +InstallResult GMainWindow::InstallNSPXCI(const QString& filename) { const auto qt_raw_copy = [this](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest, std::size_t block_size) { - if (src == nullptr || dest == nullptr) + if (src == nullptr || dest == nullptr) { return false; - if (!dest->Resize(src->GetSize())) + } + if (!dest->Resize(src->GetSize())) { return false; + } std::array<u8, 0x1000> buffer{}; - const int progress_maximum = static_cast<int>(src->GetSize() / buffer.size()); - - QProgressDialog progress( - tr("Installing file \"%1\"...").arg(QString::fromStdString(src->GetName())), - tr("Cancel"), 0, progress_maximum, this); - progress.setWindowModality(Qt::WindowModal); for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { - if (progress.wasCanceled()) { + if (install_progress->wasCanceled()) { dest->Resize(0); return false; } - const int progress_value = static_cast<int>(i / buffer.size()); - progress.setValue(progress_value); + emit UpdateInstallProgress(); const auto read = src->Read(buffer.data(), buffer.size(), i); dest->Write(buffer.data(), read, i); } - return true; }; - const auto success = [this]() { - QMessageBox::information(this, tr("Successfully Installed"), - tr("The file was successfully installed.")); - game_list->PopulateAsync(UISettings::values.game_dirs); - FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + - DIR_SEP + "game_list"); - }; - - const auto failed = [this]() { - QMessageBox::warning( - this, tr("Failed to Install"), - tr("There was an error while attempting to install the provided file. It " - "could have an incorrect format or be missing metadata. Please " - "double-check your file and try again.")); - }; - - const auto overwrite = [this]() { - return QMessageBox::question(this, tr("Failed to Install"), - tr("The file you are attempting to install already exists " - "in the cache. Would you like to overwrite it?")) == - QMessageBox::Yes; - }; - - if (filename.endsWith(QStringLiteral("xci"), Qt::CaseInsensitive) || - filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { - std::shared_ptr<FileSys::NSP> nsp; - if (filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { - nsp = std::make_shared<FileSys::NSP>( - vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); - if (nsp->IsExtractedType()) - failed(); - } else { - const auto xci = std::make_shared<FileSys::XCI>( - vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); - nsp = xci->GetSecurePartitionNSP(); - } - - if (nsp->GetStatus() != Loader::ResultStatus::Success) { - failed(); - return; - } - const auto res = Core::System::GetInstance() - .GetFileSystemController() - .GetUserNANDContents() - ->InstallEntry(*nsp, false, qt_raw_copy); - if (res == FileSys::InstallResult::Success) { - success(); - } else { - if (res == FileSys::InstallResult::ErrorAlreadyExists) { - if (overwrite()) { - const auto res2 = Core::System::GetInstance() - .GetFileSystemController() - .GetUserNANDContents() - ->InstallEntry(*nsp, true, qt_raw_copy); - if (res2 == FileSys::InstallResult::Success) { - success(); - } else { - failed(); - } - } - } else { - failed(); - } + std::shared_ptr<FileSys::NSP> nsp; + if (filename.endsWith(QStringLiteral("nsp"), Qt::CaseInsensitive)) { + nsp = std::make_shared<FileSys::NSP>( + vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); + if (nsp->IsExtractedType()) { + return InstallResult::Failure; } } else { - const auto nca = std::make_shared<FileSys::NCA>( + const auto xci = std::make_shared<FileSys::XCI>( vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); - const auto id = nca->GetStatus(); + nsp = xci->GetSecurePartitionNSP(); + } - // Game updates necessary are missing base RomFS - if (id != Loader::ResultStatus::Success && - id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { - failed(); - return; - } + if (nsp->GetStatus() != Loader::ResultStatus::Success) { + return InstallResult::Failure; + } + const auto res = + Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->InstallEntry( + *nsp, true, qt_raw_copy); + if (res == FileSys::InstallResult::Success) { + return InstallResult::Success; + } else if (res == FileSys::InstallResult::ErrorAlreadyExists) { + return InstallResult::Overwrite; + } else { + return InstallResult::Failure; + } +} - const QStringList tt_options{tr("System Application"), - tr("System Archive"), - tr("System Application Update"), - tr("Firmware Package (Type A)"), - tr("Firmware Package (Type B)"), - tr("Game"), - tr("Game Update"), - tr("Game DLC"), - tr("Delta Title")}; - bool ok; - const auto item = QInputDialog::getItem( - this, tr("Select NCA Install Type..."), - tr("Please select the type of title you would like to install this NCA as:\n(In " - "most instances, the default 'Game' is fine.)"), - tt_options, 5, false, &ok); - - auto index = tt_options.indexOf(item); - if (!ok || index == -1) { - QMessageBox::warning(this, tr("Failed to Install"), - tr("The title type you selected for the NCA is invalid.")); - return; +InstallResult GMainWindow::InstallNCA(const QString& filename) { + const auto qt_raw_copy = [this](const FileSys::VirtualFile& src, + const FileSys::VirtualFile& dest, std::size_t block_size) { + if (src == nullptr || dest == nullptr) { + return false; } - - // If index is equal to or past Game, add the jump in TitleType. - if (index >= 5) { - index += static_cast<size_t>(FileSys::TitleType::Application) - - static_cast<size_t>(FileSys::TitleType::FirmwarePackageB); + if (!dest->Resize(src->GetSize())) { + return false; } - FileSys::InstallResult res; - if (index >= static_cast<s32>(FileSys::TitleType::Application)) { - res = Core::System::GetInstance() - .GetFileSystemController() - .GetUserNANDContents() - ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false, - qt_raw_copy); - } else { - res = Core::System::GetInstance() - .GetFileSystemController() - .GetSystemNANDContents() - ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false, - qt_raw_copy); - } + std::array<u8, 0x1000> buffer{}; - if (res == FileSys::InstallResult::Success) { - success(); - } else if (res == FileSys::InstallResult::ErrorAlreadyExists) { - if (overwrite()) { - const auto res2 = Core::System::GetInstance() - .GetFileSystemController() - .GetUserNANDContents() - ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), - true, qt_raw_copy); - if (res2 == FileSys::InstallResult::Success) { - success(); - } else { - failed(); - } + for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { + if (install_progress->wasCanceled()) { + dest->Resize(0); + return false; } - } else { - failed(); + + emit UpdateInstallProgress(); + + const auto read = src->Read(buffer.data(), buffer.size(), i); + dest->Write(buffer.data(), read, i); } + return true; + }; + + const auto nca = + std::make_shared<FileSys::NCA>(vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); + const auto id = nca->GetStatus(); + + // Game updates necessary are missing base RomFS + if (id != Loader::ResultStatus::Success && + id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { + return InstallResult::Failure; + } + + const QStringList tt_options{tr("System Application"), + tr("System Archive"), + tr("System Application Update"), + tr("Firmware Package (Type A)"), + tr("Firmware Package (Type B)"), + tr("Game"), + tr("Game Update"), + tr("Game DLC"), + tr("Delta Title")}; + bool ok; + const auto item = QInputDialog::getItem( + this, tr("Select NCA Install Type..."), + tr("Please select the type of title you would like to install this NCA as:\n(In " + "most instances, the default 'Game' is fine.)"), + tt_options, 5, false, &ok); + + auto index = tt_options.indexOf(item); + if (!ok || index == -1) { + QMessageBox::warning(this, tr("Failed to Install"), + tr("The title type you selected for the NCA is invalid.")); + return InstallResult::Failure; + } + + // If index is equal to or past Game, add the jump in TitleType. + if (index >= 5) { + index += static_cast<size_t>(FileSys::TitleType::Application) - + static_cast<size_t>(FileSys::TitleType::FirmwarePackageB); + } + + FileSys::InstallResult res; + if (index >= static_cast<s32>(FileSys::TitleType::Application)) { + res = Core::System::GetInstance() + .GetFileSystemController() + .GetUserNANDContents() + ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy); + } else { + res = Core::System::GetInstance() + .GetFileSystemController() + .GetSystemNANDContents() + ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy); + } + + if (res == FileSys::InstallResult::Success) { + return InstallResult::Success; + } else if (res == FileSys::InstallResult::ErrorAlreadyExists) { + return InstallResult::Overwrite; + } else { + return InstallResult::Failure; } } @@ -1819,6 +1911,9 @@ void GMainWindow::OnStopGame() { } ShutdownGame(); + + Settings::RestoreGlobalState(); + UpdateStatusButtons(); } void GMainWindow::OnLoadComplete() { @@ -1926,7 +2021,7 @@ void GMainWindow::ToggleWindowMode() { void GMainWindow::ResetWindowSize() { const auto aspect_ratio = Layout::EmulationAspectRatio( - static_cast<Layout::AspectRatio>(Settings::values.aspect_ratio), + static_cast<Layout::AspectRatio>(Settings::values.aspect_ratio.GetValue()), static_cast<float>(Layout::ScreenUndocked::Height) / Layout::ScreenUndocked::Width); if (!ui.action_Single_Window_Mode->isChecked()) { render_window->resize(Layout::ScreenUndocked::Height / aspect_ratio, @@ -1974,16 +2069,7 @@ void GMainWindow::OnConfigure() { ui.centralwidget->setMouseTracking(false); } - dock_status_button->setChecked(Settings::values.use_docked_mode); - multicore_status_button->setChecked(Settings::values.use_multi_core); - Settings::values.use_asynchronous_gpu_emulation = - Settings::values.use_asynchronous_gpu_emulation || Settings::values.use_multi_core; - async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation); - -#ifdef HAS_VULKAN - renderer_status_button->setChecked(Settings::values.renderer_backend == - Settings::RendererBackend::Vulkan); -#endif + UpdateStatusButtons(); } void GMainWindow::OnLoadAmiibo() { @@ -2097,21 +2183,34 @@ void GMainWindow::UpdateStatusBar() { auto results = Core::System::GetInstance().GetAndResetPerfStats(); - if (Settings::values.use_frame_limit) { + if (Settings::values.use_frame_limit.GetValue()) { emu_speed_label->setText(tr("Speed: %1% / %2%") .arg(results.emulation_speed * 100.0, 0, 'f', 0) - .arg(Settings::values.frame_limit)); + .arg(Settings::values.frame_limit.GetValue())); } else { emu_speed_label->setText(tr("Speed: %1%").arg(results.emulation_speed * 100.0, 0, 'f', 0)); } game_fps_label->setText(tr("Game: %1 FPS").arg(results.game_fps, 0, 'f', 0)); emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2)); - emu_speed_label->setVisible(!Settings::values.use_multi_core); + emu_speed_label->setVisible(!Settings::values.use_multi_core.GetValue()); game_fps_label->setVisible(true); emu_frametime_label->setVisible(true); } +void GMainWindow::UpdateStatusButtons() { + dock_status_button->setChecked(Settings::values.use_docked_mode); + multicore_status_button->setChecked(Settings::values.use_multi_core.GetValue()); + Settings::values.use_asynchronous_gpu_emulation.SetValue( + Settings::values.use_asynchronous_gpu_emulation.GetValue() || + Settings::values.use_multi_core.GetValue()); + async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation.GetValue()); +#ifdef HAS_VULKAN + renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() == + Settings::RendererBackend::Vulkan); +#endif +} + void GMainWindow::HideMouseCursor() { if (emu_thread == nullptr || UISettings::values.hide_mouse == false) { mouse_hide_timer.stop(); @@ -2195,6 +2294,9 @@ void GMainWindow::OnCoreError(Core::System::ResultStatus result, std::string det if (answer == QMessageBox::Yes) { if (emu_thread) { ShutdownGame(); + + Settings::RestoreGlobalState(); + UpdateStatusButtons(); } } else { // Only show the message if the game is still running. @@ -2357,9 +2459,13 @@ void GMainWindow::closeEvent(QCloseEvent* event) { hotkey_registry.SaveHotkeys(); // Shutdown session if the emu thread is active... - if (emu_thread != nullptr) + if (emu_thread != nullptr) { ShutdownGame(); + Settings::RestoreGlobalState(); + UpdateStatusButtons(); + } + render_window->close(); QWidget::closeEvent(event); @@ -2539,8 +2645,6 @@ int main(int argc, char* argv[]) { QObject::connect(&app, &QGuiApplication::applicationStateChanged, &main_window, &GMainWindow::OnAppFocusStateChanged); - Settings::LogSettings(); - int result = app.exec(); detached_tasks.WaitForAllTasks(); return result; |