summaryrefslogtreecommitdiff
path: root/src/yuzu/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/yuzu/main.cpp')
-rw-r--r--src/yuzu/main.cpp138
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);