diff options
Diffstat (limited to 'src/yuzu/main.cpp')
-rw-r--r-- | src/yuzu/main.cpp | 138 |
1 files changed, 110 insertions, 28 deletions
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index e11ba7854..45bb1d1d1 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -12,12 +12,14 @@ #define QT_NO_OPENGL #include <QDesktopWidget> +#include <QDialogButtonBox> #include <QFileDialog> #include <QMessageBox> #include <QtGui> #include <QtWidgets> #include <fmt/format.h> #include "common/common_paths.h" +#include "common/file_util.h" #include "common/logging/backend.h" #include "common/logging/filter.h" #include "common/logging/log.h" @@ -29,9 +31,14 @@ #include "core/core.h" #include "core/crypto/key_manager.h" #include "core/file_sys/card_image.h" +#include "core/file_sys/content_archive.h" +#include "core/file_sys/control_metadata.h" +#include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" #include "core/file_sys/savedata_factory.h" +#include "core/file_sys/submission_package.h" #include "core/file_sys/vfs_real.h" +#include "core/hle/kernel/process.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/loader/loader.h" #include "core/perf_stats.h" @@ -40,6 +47,7 @@ #include "video_core/debug_utils/debug_utils.h" #include "yuzu/about_dialog.h" #include "yuzu/bootmanager.h" +#include "yuzu/compatibility_list.h" #include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_dialog.h" #include "yuzu/debugger/console.h" @@ -73,6 +81,7 @@ __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; */ enum class CalloutFlag : uint32_t { Telemetry = 0x1, + DRDDeprecation = 0x2, }; static void ShowCalloutMessage(const QString& message, CalloutFlag flag) { @@ -128,11 +137,11 @@ GMainWindow::GMainWindow() ConnectMenuEvents(); ConnectWidgetEvents(); - LOG_INFO(Frontend, "yuzu Version: {} | {}-{}", Common::g_build_name, Common::g_scm_branch, + LOG_INFO(Frontend, "yuzu Version: {} | {}-{}", Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc); setWindowTitle(QString("yuzu %1| %2-%3") - .arg(Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc)); + .arg(Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc)); show(); // Necessary to load titles from nand in gamelist. @@ -372,6 +381,10 @@ void GMainWindow::ConnectMenuEvents() { &GMainWindow::OnMenuInstallToNAND); connect(ui.action_Select_Game_List_Root, &QAction::triggered, this, &GMainWindow::OnMenuSelectGameListRoot); + connect(ui.action_Select_NAND_Directory, &QAction::triggered, this, + [this] { OnMenuSelectEmulatedDirectory(EmulatedDirectoryTarget::NAND); }); + connect(ui.action_Select_SDMC_Directory, &QAction::triggered, this, + [this] { OnMenuSelectEmulatedDirectory(EmulatedDirectoryTarget::SDMC); }); connect(ui.action_Exit, &QAction::triggered, this, &QMainWindow::close); // Emulation @@ -419,7 +432,7 @@ void GMainWindow::OnDisplayTitleBars(bool show) { } } -bool GMainWindow::SupportsRequiredGLExtensions() { +QStringList GMainWindow::GetUnsupportedGLExtensions() { QStringList unsupported_ext; if (!GLAD_GL_ARB_program_interface_query) @@ -432,6 +445,12 @@ bool GMainWindow::SupportsRequiredGLExtensions() { unsupported_ext.append("ARB_vertex_type_10f_11f_11f_rev"); if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) unsupported_ext.append("ARB_texture_mirror_clamp_to_edge"); + if (!GLAD_GL_ARB_base_instance) + unsupported_ext.append("ARB_base_instance"); + if (!GLAD_GL_ARB_texture_storage) + unsupported_ext.append("ARB_texture_storage"); + if (!GLAD_GL_ARB_multi_bind) + unsupported_ext.append("ARB_multi_bind"); // Extensions required to support some texture formats. if (!GLAD_GL_EXT_texture_compression_s3tc) @@ -446,7 +465,7 @@ bool GMainWindow::SupportsRequiredGLExtensions() { for (const QString& ext : unsupported_ext) LOG_CRITICAL(Frontend, "Unsupported GL extension: {}", ext.toStdString()); - return unsupported_ext.empty(); + return unsupported_ext; } bool GMainWindow::LoadROM(const QString& filename) { @@ -464,11 +483,13 @@ bool GMainWindow::LoadROM(const QString& filename) { return false; } - if (!SupportsRequiredGLExtensions()) { - QMessageBox::critical( - this, tr("Error while initializing OpenGL Core!"), - tr("Your GPU may not support one or more required OpenGL extensions. Please " - "ensure you have the latest graphics driver. See the log for more details.")); + QStringList unsupported_gl_extensions = GetUnsupportedGLExtensions(); + if (!unsupported_gl_extensions.empty()) { + QMessageBox::critical(this, tr("Error while initializing OpenGL Core!"), + tr("Your GPU may not support one or more required OpenGL" + "extensions. Please ensure you have the latest graphics " + "driver.<br><br>Unsupported extensions:<br>") + + unsupported_gl_extensions.join("<br>")); return false; } @@ -479,6 +500,23 @@ bool GMainWindow::LoadROM(const QString& filename) { const Core::System::ResultStatus result{system.Load(*render_window, filename.toStdString())}; + const auto drd_callout = + (UISettings::values.callout_flags & static_cast<u32>(CalloutFlag::DRDDeprecation)) == 0; + + if (result == Core::System::ResultStatus::Success && + system.GetAppLoader().GetFileType() == Loader::FileType::DeconstructedRomDirectory && + drd_callout) { + UISettings::values.callout_flags |= static_cast<u32>(CalloutFlag::DRDDeprecation); + QMessageBox::warning( + this, tr("Warning Outdated Game Format"), + tr("You are using the deconstructed ROM directory format for this game, which is an " + "outdated format that has been superseded by others such as NCA, NAX, XCI, or " + "NSP. Deconstructed ROM directories lack icons, metadata, and update " + "support.<br><br>For an explanation of the various Switch formats yuzu supports, <a " + "href='https://yuzu-emu.org/wiki/overview-of-switch-game-formats'>check out our " + "wiki</a>. This message will not be shown again.")); + } + render_window->DoneCurrent(); if (result != Core::System::ResultStatus::Success) { @@ -563,11 +601,19 @@ void GMainWindow::BootGame(const QString& filename) { std::string title_name; const auto res = Core::System::GetInstance().GetGameName(title_name); - if (res != Loader::ResultStatus::Success) - title_name = FileUtil::GetFilename(filename.toStdString()); + if (res != Loader::ResultStatus::Success) { + const u64 program_id = Core::System::GetInstance().CurrentProcess()->program_id; + + const auto [nacp, icon_file] = FileSys::PatchManager(program_id).GetControlMetadata(); + if (nacp != nullptr) + title_name = nacp->GetApplicationName(); + + if (title_name.empty()) + title_name = FileUtil::GetFilename(filename.toStdString()); + } setWindowTitle(QString("yuzu %1| %4 | %2-%3") - .arg(Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc, + .arg(Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc, QString::fromStdString(title_name))); render_window->show(); @@ -602,7 +648,7 @@ void GMainWindow::ShutdownGame() { game_list->show(); game_list->setFilterFocus(); setWindowTitle(QString("yuzu %1| %2-%3") - .arg(Common::g_build_name, Common::g_scm_branch, Common::g_scm_desc)); + .arg(Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc)); // Disable status bar updates status_bar_update_timer.stop(); @@ -684,14 +730,11 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); } -void GMainWindow::OnGameListNavigateToGamedbEntry( - u64 program_id, - std::unordered_map<std::string, std::pair<QString, QString>>& compatibility_list) { - - auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); +void GMainWindow::OnGameListNavigateToGamedbEntry(u64 program_id, + const CompatibilityList& compatibility_list) { + const auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); QString directory; - if (it != compatibility_list.end()) directory = it->second.second; @@ -737,7 +780,8 @@ void GMainWindow::OnMenuLoadFolder() { void GMainWindow::OnMenuInstallToNAND() { const QString file_filter = - tr("Installable Switch File (*.nca *.xci);;Nintendo Content Archive (*.nca);;NX Cartridge " + tr("Installable Switch File (*.nca *.nsp *.xci);;Nintendo Content Archive " + "(*.nca);;Nintendo Submissions Package (*.nsp);;NX Cartridge " "Image (*.xci)"); QString filename = QFileDialog::getOpenFileName(this, tr("Install File"), UISettings::values.roms_path, file_filter); @@ -760,7 +804,7 @@ void GMainWindow::OnMenuInstallToNAND() { tr("Cancel"), 0, progress_maximum, this); progress.setWindowModality(Qt::WindowModal); - for (size_t i = 0; i < src->GetSize(); i += buffer.size()) { + for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) { if (progress.wasCanceled()) { dest->Resize(0); return false; @@ -797,22 +841,34 @@ void GMainWindow::OnMenuInstallToNAND() { QMessageBox::Yes; }; - if (filename.endsWith("xci", Qt::CaseInsensitive)) { - const auto xci = std::make_shared<FileSys::XCI>( - vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); - if (xci->GetStatus() != Loader::ResultStatus::Success) { + if (filename.endsWith("xci", Qt::CaseInsensitive) || + filename.endsWith("nsp", Qt::CaseInsensitive)) { + + std::shared_ptr<FileSys::NSP> nsp; + if (filename.endsWith("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 = - Service::FileSystem::GetUserNANDContents()->InstallEntry(xci, false, qt_raw_copy); + Service::FileSystem::GetUserNANDContents()->InstallEntry(nsp, false, qt_raw_copy); if (res == FileSys::InstallResult::Success) { success(); } else { if (res == FileSys::InstallResult::ErrorAlreadyExists) { if (overwrite()) { const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry( - xci, true, qt_raw_copy); + nsp, true, qt_raw_copy); if (res2 == FileSys::InstallResult::Success) { success(); } else { @@ -826,7 +882,11 @@ void GMainWindow::OnMenuInstallToNAND() { } else { const auto nca = std::make_shared<FileSys::NCA>( vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); - if (nca->GetStatus() != Loader::ResultStatus::Success) { + const auto id = nca->GetStatus(); + + // Game updates necessary are missing base RomFS + if (id != Loader::ResultStatus::Success && + id != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { failed(); return; } @@ -885,6 +945,28 @@ void GMainWindow::OnMenuSelectGameListRoot() { } } +void GMainWindow::OnMenuSelectEmulatedDirectory(EmulatedDirectoryTarget target) { + const auto res = QMessageBox::information( + this, tr("Changing Emulated Directory"), + tr("You are about to change the emulated %1 directory of the system. Please note " + "that this does not also move the contents of the previous directory to the " + "new one and you will have to do that yourself.") + .arg(target == EmulatedDirectoryTarget::SDMC ? tr("SD card") : tr("NAND")), + QMessageBox::StandardButtons{QMessageBox::Ok, QMessageBox::Cancel}); + + if (res == QMessageBox::Cancel) + return; + + QString dir_path = QFileDialog::getExistingDirectory(this, tr("Select Directory")); + if (!dir_path.isEmpty()) { + FileUtil::GetUserPath(target == EmulatedDirectoryTarget::SDMC ? FileUtil::UserPath::SDMCDir + : FileUtil::UserPath::NANDDir, + dir_path.toStdString()); + Service::FileSystem::CreateFactories(vfs); + game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan); + } +} + void GMainWindow::OnMenuRecentFile() { QAction* action = qobject_cast<QAction*>(sender()); assert(action); |