From 9e88f03e7591bd3b91d7af9b9995a727c0b92ac9 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sat, 28 Jul 2018 12:32:16 -0400 Subject: Avoid parsing RomFS to directory in NCA --- src/yuzu/CMakeLists.txt | 3 + src/yuzu/configuration/config.cpp | 14 +++ src/yuzu/configuration/configure.ui | 11 +++ src/yuzu/configuration/configure_dialog.cpp | 1 + src/yuzu/configuration/configure_gamelist.cpp | 61 +++++++++++++ src/yuzu/configuration/configure_gamelist.h | 28 ++++++ src/yuzu/configuration/configure_gamelist.ui | 126 ++++++++++++++++++++++++++ src/yuzu/game_list.cpp | 77 ++++++++++++++-- src/yuzu/game_list_p.h | 38 +++++++- src/yuzu/main.cpp | 1 + src/yuzu/ui_settings.h | 6 ++ 11 files changed, 353 insertions(+), 13 deletions(-) create mode 100644 src/yuzu/configuration/configure_gamelist.cpp create mode 100644 src/yuzu/configuration/configure_gamelist.h create mode 100644 src/yuzu/configuration/configure_gamelist.ui (limited to 'src/yuzu') diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 475556806..46ed232d8 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -17,6 +17,8 @@ add_executable(yuzu configuration/configure_debug.h configuration/configure_dialog.cpp configuration/configure_dialog.h + configuration/configure_gamelist.cpp + configuration/configure_gamelist.h configuration/configure_general.cpp configuration/configure_general.h configuration/configure_graphics.cpp @@ -59,6 +61,7 @@ set(UIS configuration/configure.ui configuration/configure_audio.ui configuration/configure_debug.ui + configuration/configure_gamelist.ui configuration/configure_general.ui configuration/configure_graphics.ui configuration/configure_input.ui diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index bf469ee73..0bd46dbac 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -122,6 +122,13 @@ void Config::ReadValues() { qt_config->beginGroup("UI"); UISettings::values.theme = qt_config->value("theme", UISettings::themes[0].second).toString(); + qt_config->beginGroup("UIGameList"); + UISettings::values.show_unknown = qt_config->value("show_unknown", true).toBool(); + UISettings::values.icon_size = qt_config->value("icon_size", 48).toUInt(); + UISettings::values.row_1_text_id = qt_config->value("row_1_text_id", 0).toUInt(); + UISettings::values.row_2_text_id = qt_config->value("row_2_text_id", 3).toUInt(); + qt_config->endGroup(); + qt_config->beginGroup("UILayout"); UISettings::values.geometry = qt_config->value("geometry").toByteArray(); UISettings::values.state = qt_config->value("state").toByteArray(); @@ -234,6 +241,13 @@ void Config::SaveValues() { qt_config->beginGroup("UI"); qt_config->setValue("theme", UISettings::values.theme); + qt_config->beginGroup("UIGameList"); + qt_config->setValue("show_unknown", UISettings::values.show_unknown); + qt_config->setValue("icon_size", UISettings::values.icon_size); + qt_config->setValue("row_1_text_id", UISettings::values.row_1_text_id); + qt_config->setValue("row_2_text_id", UISettings::values.row_2_text_id); + qt_config->endGroup(); + qt_config->beginGroup("UILayout"); qt_config->setValue("geometry", UISettings::values.geometry); qt_config->setValue("state", UISettings::values.state); diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui index c8e0b88af..20f120134 100644 --- a/src/yuzu/configuration/configure.ui +++ b/src/yuzu/configuration/configure.ui @@ -24,6 +24,11 @@ General + + + Game List + + System @@ -67,6 +72,12 @@
configuration/configure_general.h
1 + + ConfigureGameList + QWidget +
configuration/configure_gamelist.h
+ 1 +
ConfigureSystem QWidget diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 1ca7e876c..d04aa4e31 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -18,6 +18,7 @@ void ConfigureDialog::setConfiguration() {} void ConfigureDialog::applyConfiguration() { ui->generalTab->applyConfiguration(); + ui->gameListTab->applyConfiguration(); ui->systemTab->applyConfiguration(); ui->inputTab->applyConfiguration(); ui->graphicsTab->applyConfiguration(); diff --git a/src/yuzu/configuration/configure_gamelist.cpp b/src/yuzu/configuration/configure_gamelist.cpp new file mode 100644 index 000000000..072b3f96f --- /dev/null +++ b/src/yuzu/configuration/configure_gamelist.cpp @@ -0,0 +1,61 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/core.h" +#include "core/settings.h" +#include "ui_configure_gamelist.h" +#include "ui_settings.h" +#include "yuzu/configuration/configure_gamelist.h" + +ConfigureGameList::ConfigureGameList(QWidget* parent) + : QWidget(parent), ui(new Ui::ConfigureGameList) { + ui->setupUi(this); + + static std::vector> default_icon_sizes{ + std::make_pair(0, "None"), std::make_pair(24, "Small"), + std::make_pair(48, "Standard"), std::make_pair(96, "Large"), + std::make_pair(256, "Full Size"), + }; + + for (const auto& size : default_icon_sizes) { + ui->icon_size_combobox->addItem(QString::fromStdString(size.second + " (" + + std::to_string(size.first) + "x" + + std::to_string(size.first) + ")"), + size.first); + } + + static std::vector row_text_names{ + "Filename", + "Filetype", + "Title ID", + "Title Name", + }; + + for (size_t i = 0; i < row_text_names.size(); ++i) { + ui->row_1_text_combobox->addItem(QString::fromStdString(row_text_names[i]), i); + ui->row_2_text_combobox->addItem(QString::fromStdString(row_text_names[i]), i); + } + + this->setConfiguration(); +} + +ConfigureGameList::~ConfigureGameList() {} + +void ConfigureGameList::setConfiguration() { + ui->show_unknown->setChecked(UISettings::values.show_unknown); + ui->icon_size_combobox->setCurrentIndex( + ui->icon_size_combobox->findData(UISettings::values.icon_size)); + ui->row_1_text_combobox->setCurrentIndex( + ui->row_1_text_combobox->findData(UISettings::values.row_1_text_id)); + ui->row_2_text_combobox->setCurrentIndex( + ui->row_2_text_combobox->findData(UISettings::values.row_2_text_id)); +} + +void ConfigureGameList::applyConfiguration() { + UISettings::values.show_unknown = ui->show_unknown->isChecked(); + UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt(); + UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt(); + UISettings::values.row_2_text_id = ui->row_2_text_combobox->currentData().toUInt(); + Settings::Apply(); +} diff --git a/src/yuzu/configuration/configure_gamelist.h b/src/yuzu/configuration/configure_gamelist.h new file mode 100644 index 000000000..94fba6373 --- /dev/null +++ b/src/yuzu/configuration/configure_gamelist.h @@ -0,0 +1,28 @@ +// Copyright 2016 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +namespace Ui { +class ConfigureGameList; +} + +class ConfigureGameList : public QWidget { + Q_OBJECT + +public: + explicit ConfigureGameList(QWidget* parent = nullptr); + ~ConfigureGameList(); + + void applyConfiguration(); + +private: + void setConfiguration(); + +private: + std::unique_ptr ui; +}; diff --git a/src/yuzu/configuration/configure_gamelist.ui b/src/yuzu/configuration/configure_gamelist.ui new file mode 100644 index 000000000..7471fdb60 --- /dev/null +++ b/src/yuzu/configuration/configure_gamelist.ui @@ -0,0 +1,126 @@ + + + ConfigureGameList + + + + 0 + 0 + 300 + 377 + + + + Form + + + + + + + + General + + + + + + + + Show files with type 'Unknown' + + + + + + + + + + + + Icon Size + + + + + + + + + + Icon Size: + + + + + + + + + + + + + + + + + Row Text + + + + + + + + + + Row 1 Text: + + + + + + + + + + + + + + Row 2 Text: + + + + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 24f38a3c7..893c5f693 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -12,6 +12,8 @@ #include "common/common_paths.h" #include "common/logging/log.h" #include "common/string_util.h" +#include "core/file_sys/content_archive.h" +#include "core/file_sys/control_metadata.h" #include "core/file_sys/vfs_real.h" #include "core/loader/loader.h" #include "game_list.h" @@ -398,8 +400,32 @@ void GameList::RefreshGameDirectory() { } void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) { - const auto callback = [this, recursion](u64* num_entries_out, const std::string& directory, - const std::string& virtual_name) -> bool { + boost::container::flat_map> nca_control_map; + + const auto nca_control_callback = + [this, &nca_control_map](u64* num_entries_out, const std::string& directory, + const std::string& virtual_name) -> bool { + std::string physical_name = directory + DIR_SEP + virtual_name; + + if (stop_processing) + return false; // Breaks the callback loop. + + bool is_dir = FileUtil::IsDirectory(physical_name); + QFileInfo file_info(physical_name.c_str()); + if (!is_dir && file_info.suffix().toStdString() == "nca") { + auto nca = std::make_shared( + std::make_shared(physical_name)); + if (nca->GetType() == FileSys::NCAContentType::Control) + nca_control_map.insert_or_assign(nca->GetTitleId(), nca); + } + return true; + }; + + FileUtil::ForeachDirectoryEntry(nullptr, dir_path, nca_control_callback); + + const auto callback = [this, recursion, + &nca_control_map](u64* num_entries_out, const std::string& directory, + const std::string& virtual_name) -> bool { std::string physical_name = directory + DIR_SEP + virtual_name; if (stop_processing) @@ -410,17 +436,50 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) { std::unique_ptr loader = Loader::GetLoader(std::make_shared(physical_name)); - if (!loader) + if (!loader || ((loader->GetFileType() == Loader::FileType::Unknown || + loader->GetFileType() == Loader::FileType::Error) && + !UISettings::values.show_unknown)) return true; - std::vector smdh; - loader->ReadIcon(smdh); - - u64 program_id = 0; - loader->ReadProgramId(program_id); + std::vector icon; + const auto res1 = loader->ReadIcon(icon); + + u64 program_id; + const auto res2 = loader->ReadProgramId(program_id); + + std::string name = " "; + const auto res3 = loader->ReadTitle(name); + + if ((res1 == Loader::ResultStatus::ErrorNotUsed || + res1 == Loader::ResultStatus::ErrorNotImplemented) && + (res3 == Loader::ResultStatus::ErrorNotUsed || + res3 == Loader::ResultStatus::ErrorNotImplemented) && + res2 == Loader::ResultStatus::Success) { + // Use from metadata pool. + if (nca_control_map.find(program_id) != nca_control_map.end()) { + const auto nca = nca_control_map[program_id]; + auto control_dir = nca->GetSection(0); + + auto nacp_file = control_dir->GetFile("control.nacp"); + FileSys::NACP nacp(nacp_file); + name = nacp.GetApplicationName(); + + FileSys::VirtualFile icon_file = nullptr; + for (const auto& language : FileSys::LANGUAGE_NAMES) { + icon_file = control_dir->GetFile("icon_" + language + ".dat"); + if (icon_file != nullptr) { + icon = icon_file->ReadAllBytes(); + break; + } + } + } + } emit EntryReady({ - new GameListItemPath(FormatGameName(physical_name), smdh, program_id), + new GameListItemPath( + FormatGameName(physical_name), icon, QString::fromStdString(name), + QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())), + program_id), new GameListItem( QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))), new GameListItemSize(FileUtil::GetSize(physical_name)), diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index aa69a098f..a22025e67 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h @@ -11,6 +11,7 @@ #include #include #include "common/string_util.h" +#include "ui_settings.h" #include "yuzu/util/util.h" /** @@ -18,8 +19,7 @@ * @param large If true, returns large icon (48x48), otherwise returns small icon (24x24) * @return QPixmap default icon */ -static QPixmap GetDefaultIcon(bool large) { - int size = large ? 48 : 24; +static QPixmap GetDefaultIcon(u32 size) { QPixmap icon(size, size); icon.fill(Qt::transparent); return icon; @@ -44,11 +44,25 @@ public: static const int FullPathRole = Qt::UserRole + 1; static const int TitleRole = Qt::UserRole + 2; static const int ProgramIdRole = Qt::UserRole + 3; + static const int FileTypeRole = Qt::UserRole + 4; GameListItemPath() = default; - GameListItemPath(const QString& game_path, const std::vector& smdh_data, u64 program_id) { + GameListItemPath(const QString& game_path, const std::vector& picture_data, + const QString& game_name, const QString& game_type, u64 program_id) + : GameListItem() { setData(game_path, FullPathRole); + setData(game_name, TitleRole); setData(qulonglong(program_id), ProgramIdRole); + setData(game_type, FileTypeRole); + + QPixmap picture; + u32 size = UISettings::values.icon_size; + if (!picture.loadFromData(picture_data.data(), picture_data.size())) + picture = GetDefaultIcon(size); + + picture = picture.scaled(size, size); + + setData(picture, Qt::DecorationRole); } QVariant data(int role) const override { @@ -57,7 +71,23 @@ public: Common::SplitPath(data(FullPathRole).toString().toStdString(), nullptr, &filename, nullptr); QString title = data(TitleRole).toString(); - return QString::fromStdString(filename) + (title.isEmpty() ? "" : "\n " + title); + + std::vector row_data{ + QString::fromStdString(filename), + data(FileTypeRole).toString(), + QString::fromStdString(fmt::format("0x{:016X}", data(ProgramIdRole).toULongLong())), + data(TitleRole).toString(), + }; + + auto row1 = row_data.at(UISettings::values.row_1_text_id); + auto row2 = row_data.at(UISettings::values.row_2_text_id); + + if (row1.isEmpty() || row1 == row2) + return row2; + if (row2.isEmpty()) + return row1; + + return row1 + "\n " + row2; } else { return GameListItem::data(role); } diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index dd71bd763..3cba6f403 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -764,6 +764,7 @@ void GMainWindow::OnConfigure() { configureDialog.applyConfiguration(); if (UISettings::values.theme != old_theme) UpdateUITheme(); + game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan); config->Save(); } } diff --git a/src/yuzu/ui_settings.h b/src/yuzu/ui_settings.h index 2286c2559..051494bc5 100644 --- a/src/yuzu/ui_settings.h +++ b/src/yuzu/ui_settings.h @@ -54,6 +54,12 @@ struct Values { // logging bool show_console; + + // Game List + bool show_unknown; + uint32_t icon_size; + uint8_t row_1_text_id; + uint8_t row_2_text_id; }; extern Values values; -- cgit v1.2.3 From 5927cf0e177d1804bcc0d9f95aa3fe1c4d0f6201 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sat, 28 Jul 2018 12:35:02 -0400 Subject: Use const where applicable --- src/core/file_sys/control_metadata.h | 2 +- src/core/loader/deconstructed_rom_directory.cpp | 2 +- src/yuzu/configuration/configure_gamelist.cpp | 8 ++++---- src/yuzu/game_list.cpp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src/yuzu') diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index 9fc02612a..6582cc240 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h @@ -62,7 +62,7 @@ enum class Language : u8 { Chinese = 14, }; -static std::array LANGUAGE_NAMES = { +static constexpr std::array LANGUAGE_NAMES = { "AmericanEnglish", "BritishEnglish", "Japanese", "French", "German", "LatinAmericanSpanish", "Spanish", "Italian", "Dutch", diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index cc88a44b6..4a028250b 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -25,7 +25,7 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys // Icon FileSys::VirtualFile icon_file = nullptr; for (const auto& language : FileSys::LANGUAGE_NAMES) { - icon_file = dir->GetFile("icon_" + language + ".dat"); + icon_file = dir->GetFile("icon_" + std::string(language) + ".dat"); if (icon_file != nullptr) { icon_data = icon_file->ReadAllBytes(); break; diff --git a/src/yuzu/configuration/configure_gamelist.cpp b/src/yuzu/configuration/configure_gamelist.cpp index 072b3f96f..c81e716f9 100644 --- a/src/yuzu/configuration/configure_gamelist.cpp +++ b/src/yuzu/configuration/configure_gamelist.cpp @@ -12,9 +12,9 @@ ConfigureGameList::ConfigureGameList(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureGameList) { ui->setupUi(this); - static std::vector> default_icon_sizes{ - std::make_pair(0, "None"), std::make_pair(24, "Small"), - std::make_pair(48, "Standard"), std::make_pair(96, "Large"), + static const std::vector> default_icon_sizes{ + std::make_pair(0, "None"), std::make_pair(32, "Small"), + std::make_pair(64, "Standard"), std::make_pair(128, "Large"), std::make_pair(256, "Full Size"), }; @@ -25,7 +25,7 @@ ConfigureGameList::ConfigureGameList(QWidget* parent) size.first); } - static std::vector row_text_names{ + static const std::vector row_text_names{ "Filename", "Filetype", "Title ID", diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 893c5f693..481d91be5 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -466,7 +466,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign FileSys::VirtualFile icon_file = nullptr; for (const auto& language : FileSys::LANGUAGE_NAMES) { - icon_file = control_dir->GetFile("icon_" + language + ".dat"); + icon_file = control_dir->GetFile("icon_" + std::string(language) + ".dat"); if (icon_file != nullptr) { icon = icon_file->ReadAllBytes(); break; -- cgit v1.2.3 From 91cfe70301bec23099ae27ad70e3da525a573cfe Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Mon, 6 Aug 2018 23:13:37 -0400 Subject: loader: Add icon and title support to XCI --- src/core/file_sys/card_image.cpp | 1 + src/core/file_sys/content_archive.cpp | 4 ++++ src/core/file_sys/content_archive.h | 1 + src/core/loader/nca.h | 2 -- src/core/loader/xci.cpp | 33 ++++++++++++++++++++++++++++++++- src/core/loader/xci.h | 5 +++++ src/yuzu/game_list.cpp | 5 +++-- 7 files changed, 46 insertions(+), 5 deletions(-) (limited to 'src/yuzu') diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp index 395eea8ae..e897d9913 100644 --- a/src/core/file_sys/card_image.cpp +++ b/src/core/file_sys/card_image.cpp @@ -5,6 +5,7 @@ #include #include #include +#include "common/logging/log.h" #include "core/file_sys/card_image.h" #include "core/file_sys/partition_filesystem.h" #include "core/file_sys/vfs_offset.h" diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index 79e70f6ef..8cd1f5e6a 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp @@ -140,6 +140,10 @@ VirtualFile NCA::Decrypt(NCASectionHeader header, VirtualFile in, u64 starting_o } NCA::NCA(VirtualFile file_) : file(std::move(file_)) { + if (file == nullptr) { + status = Loader::ResultStatus::ErrorInvalidFormat; + return; + } if (sizeof(NCAHeader) != file->ReadObject(&header)) LOG_ERROR(Loader, "File reader errored out during header read."); diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h index 6492163b5..a984a4d36 100644 --- a/src/core/file_sys/content_archive.h +++ b/src/core/file_sys/content_archive.h @@ -12,6 +12,7 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "common/swap.h" +#include "control_metadata.h" #include "core/crypto/key_manager.h" #include "core/file_sys/partition_filesystem.h" #include "core/loader/loader.h" diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h index 443bc1202..7f7d8ea0b 100644 --- a/src/core/loader/nca.h +++ b/src/core/loader/nca.h @@ -35,8 +35,6 @@ public: ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; ResultStatus ReadProgramId(u64& out_program_id) override; - ResultStatus ReadProgramId(u64& out_program_id) override; - ~AppLoader_NCA(); private: diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index eb4dee2c2..d3fe24419 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp @@ -26,7 +26,25 @@ namespace Loader { AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file) : AppLoader(file), xci(std::make_unique(file)), nca_loader(std::make_unique( - xci->GetNCAFileByType(FileSys::NCAContentType::Program))) {} + xci->GetNCAFileByType(FileSys::NCAContentType::Program))) { + if (xci->GetStatus() != ResultStatus::Success) + return; + const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control); + if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) + return; + const auto romfs = FileSys::ExtractRomFS(control_nca->GetRomFS()); + if (romfs == nullptr) + return; + for (const auto& language : FileSys::LANGUAGE_NAMES) { + icon_file = romfs->GetFile("icon_" + std::string(language) + ".dat"); + if (icon_file != nullptr) + break; + } + const auto nacp_raw = romfs->GetFile("control.nacp"); + if (nacp_raw == nullptr) + return; + nacp_file = std::make_shared(nacp_raw); +} AppLoader_XCI::~AppLoader_XCI() = default; @@ -71,4 +89,17 @@ ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) { return nca_loader->ReadProgramId(out_program_id); } +ResultStatus AppLoader_XCI::ReadIcon(std::vector& buffer) { + if (icon_file == nullptr) + return ResultStatus::ErrorInvalidFormat; + buffer = icon_file->ReadAllBytes(); + return ResultStatus::Success; +} + +ResultStatus AppLoader_XCI::ReadTitle(std::string& title) { + if (nacp_file == nullptr) + return ResultStatus::ErrorInvalidFormat; + title = nacp_file->GetApplicationName(); + return ResultStatus::Success; +} } // namespace Loader diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h index 0dbcfbdf8..973833050 100644 --- a/src/core/loader/xci.h +++ b/src/core/loader/xci.h @@ -33,12 +33,17 @@ public: ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; ResultStatus ReadProgramId(u64& out_program_id) override; + ResultStatus ReadIcon(std::vector& buffer) override; + ResultStatus ReadTitle(std::string& title) override; private: FileSys::ProgramMetadata metadata; std::unique_ptr xci; std::unique_ptr nca_loader; + + FileSys::VirtualFile icon_file; + std::shared_ptr nacp_file; }; } // namespace Loader diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 481d91be5..5f47f5a2b 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include "common/common_paths.h" #include "common/logging/log.h" #include "common/string_util.h" @@ -458,9 +459,9 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign // Use from metadata pool. if (nca_control_map.find(program_id) != nca_control_map.end()) { const auto nca = nca_control_map[program_id]; - auto control_dir = nca->GetSection(0); + const auto control_dir = nca->GetSubdirectories()[0]; - auto nacp_file = control_dir->GetFile("control.nacp"); + const auto nacp_file = control_dir->GetFile("control.nacp"); FileSys::NACP nacp(nacp_file); name = nacp.GetApplicationName(); -- cgit v1.2.3 From 1abfd4166ee25354dd1b85b87fa7038fff420257 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Tue, 7 Aug 2018 17:10:10 -0400 Subject: configure_gamelist: Use explicit QVariant constructor --- src/yuzu/configuration/configure_gamelist.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/yuzu') diff --git a/src/yuzu/configuration/configure_gamelist.cpp b/src/yuzu/configuration/configure_gamelist.cpp index c81e716f9..1ae3423cf 100644 --- a/src/yuzu/configuration/configure_gamelist.cpp +++ b/src/yuzu/configuration/configure_gamelist.cpp @@ -33,8 +33,10 @@ ConfigureGameList::ConfigureGameList(QWidget* parent) }; for (size_t i = 0; i < row_text_names.size(); ++i) { - ui->row_1_text_combobox->addItem(QString::fromStdString(row_text_names[i]), i); - ui->row_2_text_combobox->addItem(QString::fromStdString(row_text_names[i]), i); + ui->row_1_text_combobox->addItem(QString::fromStdString(row_text_names[i]), + QVariant::fromValue(i)); + ui->row_2_text_combobox->addItem(QString::fromStdString(row_text_names[i]), + QVariant::fromValue(i)); } this->setConfiguration(); -- cgit v1.2.3 From 4b471f0554146463f3b82eed14ff3922a5584e9f Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 3 Aug 2018 11:51:48 -0400 Subject: core: Port core to VfsFilesystem for file access --- src/core/core.cpp | 8 ++++++-- src/core/core.h | 12 ++++++++++++ src/core/hle/service/filesystem/filesystem.cpp | 14 +++++++------- src/core/hle/service/filesystem/filesystem.h | 2 +- src/core/hle/service/service.cpp | 4 ++-- src/core/hle/service/service.h | 7 ++++++- src/yuzu/game_list.cpp | 7 ++++--- src/yuzu/game_list.h | 3 ++- src/yuzu/game_list_p.h | 3 ++- src/yuzu/main.cpp | 10 ++++++---- src/yuzu/main.h | 3 +++ src/yuzu_cmd/yuzu.cpp | 1 + 12 files changed, 52 insertions(+), 22 deletions(-) (limited to 'src/yuzu') diff --git a/src/core/core.cpp b/src/core/core.cpp index 085ba68d0..69c45c026 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -89,7 +89,7 @@ System::ResultStatus System::SingleStep() { } System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& filepath) { - app_loader = Loader::GetLoader(std::make_shared(filepath)); + app_loader = Loader::GetLoader(virtual_filesystem->OpenFile(filepath, FileSys::Mode::Read)); if (!app_loader) { LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); @@ -174,6 +174,10 @@ System::ResultStatus System::Init(EmuWindow& emu_window) { CoreTiming::Init(); + // Create a default fs if one doesn't already exist. + if (virtual_filesystem == nullptr) + virtual_filesystem = std::make_shared(); + current_process = Kernel::Process::Create("main"); cpu_barrier = std::make_shared(); @@ -186,7 +190,7 @@ System::ResultStatus System::Init(EmuWindow& emu_window) { service_manager = std::make_shared(); Kernel::Init(); - Service::Init(service_manager); + Service::Init(service_manager, virtual_filesystem); GDBStub::Init(); renderer = VideoCore::CreateRenderer(emu_window); diff --git a/src/core/core.h b/src/core/core.h index c8ca4b247..7cf7ea4e1 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -17,6 +17,8 @@ #include "core/memory.h" #include "core/perf_stats.h" #include "core/telemetry_session.h" +#include "file_sys/vfs_real.h" +#include "hle/service/filesystem/filesystem.h" #include "video_core/debug_utils/debug_utils.h" #include "video_core/gpu.h" @@ -211,6 +213,14 @@ public: return debug_context; } + void SetFilesystem(FileSys::VirtualFilesystem vfs) { + virtual_filesystem = std::move(vfs); + } + + FileSys::VirtualFilesystem GetFilesystem() const { + return virtual_filesystem; + } + private: System(); @@ -225,6 +235,8 @@ private: */ ResultStatus Init(EmuWindow& emu_window); + /// RealVfsFilesystem instance + FileSys::VirtualFilesystem virtual_filesystem; /// AppLoader used to load the current executing application std::unique_ptr app_loader; std::unique_ptr renderer; diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 9b87e3484..5e416cde2 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -281,15 +281,15 @@ ResultVal OpenSDMC() { return sdmc_factory->Open(); } -void RegisterFileSystems() { +void RegisterFileSystems(const FileSys::VirtualFilesystem& vfs) { romfs_factory = nullptr; save_data_factory = nullptr; sdmc_factory = nullptr; - auto nand_directory = std::make_shared( - FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), FileSys::Mode::ReadWrite); - auto sd_directory = std::make_shared( - FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), FileSys::Mode::ReadWrite); + auto nand_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), + FileSys::Mode::ReadWrite); + auto sd_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), + FileSys::Mode::ReadWrite); auto savedata = std::make_unique(std::move(nand_directory)); save_data_factory = std::move(savedata); @@ -298,8 +298,8 @@ void RegisterFileSystems() { sdmc_factory = std::move(sdcard); } -void InstallInterfaces(SM::ServiceManager& service_manager) { - RegisterFileSystems(); +void InstallInterfaces(SM::ServiceManager& service_manager, const FileSys::VirtualFilesystem& vfs) { + RegisterFileSystems(vfs); std::make_shared()->InstallAsService(service_manager); std::make_shared()->InstallAsService(service_manager); std::make_shared()->InstallAsService(service_manager); diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index d4483daa5..462c13f20 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -36,7 +36,7 @@ ResultVal OpenSDMC(); // ResultVal> OpenBIS(); /// Registers all Filesystem services with the specified service manager. -void InstallInterfaces(SM::ServiceManager& service_manager); +void InstallInterfaces(SM::ServiceManager& service_manager, const FileSys::VirtualFilesystem& vfs); // A class that wraps a VfsDirectory with methods that return ResultVal and ResultCode instead of // pointers and booleans. This makes using a VfsDirectory with switch services much easier and diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 6f286ea74..11951adaf 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -198,7 +198,7 @@ void AddNamedPort(std::string name, SharedPtr port) { } /// Initialize ServiceManager -void Init(std::shared_ptr& sm) { +void Init(std::shared_ptr& sm, const FileSys::VirtualFilesystem& rfs) { // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it // here and pass it into the respective InstallInterfaces functions. auto nv_flinger = std::make_shared(); @@ -221,7 +221,7 @@ void Init(std::shared_ptr& sm) { EUPLD::InstallInterfaces(*sm); Fatal::InstallInterfaces(*sm); FGM::InstallInterfaces(*sm); - FileSystem::InstallInterfaces(*sm); + FileSystem::InstallInterfaces(*sm, rfs); Friend::InstallInterfaces(*sm); GRC::InstallInterfaces(*sm); HID::InstallInterfaces(*sm); diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 046c5e18d..8a294c0f2 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -22,6 +22,10 @@ class ServerSession; class HLERequestContext; } // namespace Kernel +namespace FileSys { +struct VfsFilesystem; +} + namespace Service { namespace SM { @@ -177,7 +181,8 @@ private: }; /// Initialize ServiceManager -void Init(std::shared_ptr& sm); +void Init(std::shared_ptr& sm, + const std::shared_ptr& vfs); /// Shutdown ServiceManager void Shutdown(); diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 5f47f5a2b..e150a0684 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -197,7 +197,8 @@ void GameList::onFilterCloseClicked() { main_window->filterBarSetChecked(false); } -GameList::GameList(GMainWindow* parent) : QWidget{parent} { +GameList::GameList(FileSys::VirtualFilesystem vfs, GMainWindow* parent) + : QWidget{parent}, vfs(std::move(vfs)) { watcher = new QFileSystemWatcher(this); connect(watcher, &QFileSystemWatcher::directoryChanged, this, &GameList::RefreshGameDirectory); @@ -341,7 +342,7 @@ void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) { emit ShouldCancelWorker(); - GameListWorker* worker = new GameListWorker(dir_path, deep_scan); + GameListWorker* worker = new GameListWorker(vfs, dir_path, deep_scan); connect(worker, &GameListWorker::EntryReady, this, &GameList::AddEntry, Qt::QueuedConnection); connect(worker, &GameListWorker::Finished, this, &GameList::DonePopulating, @@ -436,7 +437,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign if (!is_dir && (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) { std::unique_ptr loader = - Loader::GetLoader(std::make_shared(physical_name)); + Loader::GetLoader(vfs->OpenFile(physical_name, FileSys::Mode::Read)); if (!loader || ((loader->GetFileType() == Loader::FileType::Unknown || loader->GetFileType() == Loader::FileType::Error) && !UISettings::values.show_unknown)) diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 3bc14f07f..afe624b32 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h @@ -59,7 +59,7 @@ public: QToolButton* button_filter_close = nullptr; }; - explicit GameList(GMainWindow* parent = nullptr); + explicit GameList(FileSys::VirtualFilesystem vfs, GMainWindow* parent = nullptr); ~GameList() override; void clearFilter(); @@ -90,6 +90,7 @@ private: void PopupContextMenu(const QPoint& menu_location); void RefreshGameDirectory(); + FileSys::VirtualFilesystem vfs; SearchField* search_field; GMainWindow* main_window = nullptr; QVBoxLayout* layout = nullptr; diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index a22025e67..49a3f6181 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h @@ -139,7 +139,7 @@ class GameListWorker : public QObject, public QRunnable { Q_OBJECT public: - GameListWorker(QString dir_path, bool deep_scan) + GameListWorker(FileSys::VirtualFilesystem vfs, QString dir_path, bool deep_scan) : dir_path(std::move(dir_path)), deep_scan(deep_scan) {} public slots: @@ -163,6 +163,7 @@ signals: void Finished(QStringList watch_list); private: + FileSys::VirtualFilesystem vfs; QStringList watch_list; QString dir_path; bool deep_scan; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index a6241e63e..f7812a392 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -24,6 +24,7 @@ #include "common/string_util.h" #include "core/core.h" #include "core/crypto/key_manager.h" +#include "core/file_sys/vfs_real.h" #include "core/gdbstub/gdbstub.h" #include "core/loader/loader.h" #include "core/settings.h" @@ -81,9 +82,9 @@ static void ShowCalloutMessage(const QString& message, CalloutFlag flag) { void GMainWindow::ShowCallouts() {} -const int GMainWindow::max_recent_files_item; - -GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) { +GMainWindow::GMainWindow() + : config(new Config()), emu_thread(nullptr), + vfs(std::make_shared()) { debug_context = Tegra::DebugContext::Construct(); @@ -132,7 +133,7 @@ void GMainWindow::InitializeWidgets() { render_window = new GRenderWindow(this, emu_thread.get()); render_window->hide(); - game_list = new GameList(this); + game_list = new GameList(vfs, this); ui.horizontalLayout->addWidget(game_list); // Create status bar @@ -406,6 +407,7 @@ bool GMainWindow::LoadROM(const QString& filename) { } Core::System& system{Core::System::GetInstance()}; + system.SetFilesystem(vfs); system.SetGPUDebugContext(debug_context); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 6e335b8f8..74487c58c 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -161,6 +161,9 @@ private: bool emulation_running = false; std::unique_ptr emu_thread; + // FS + FileSys::VirtualFilesystem vfs; + // Debugger panes ProfilerWidget* profilerWidget; MicroProfileDialog* microProfileDialog; diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index d637dbd0c..0605c92e3 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -161,6 +161,7 @@ int main(int argc, char** argv) { } Core::System& system{Core::System::GetInstance()}; + system.SetFilesystem(std::make_shared()); SCOPE_EXIT({ system.Shutdown(); }); -- cgit v1.2.3 From 2b6128fe0b8788318a4bbe1fc55ea14aed2981e4 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Mon, 6 Aug 2018 23:21:37 -0400 Subject: file_util: Use enum instead of bool for specifing path behavior --- src/common/file_util.cpp | 8 ++++---- src/common/file_util.h | 7 +++++-- src/core/file_sys/vfs_real.cpp | 44 ++++++++++++++++++++++++++---------------- src/yuzu/game_list_p.h | 2 +- 4 files changed, 37 insertions(+), 24 deletions(-) (limited to 'src/yuzu') diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index 190cac6d9..3ce590062 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp @@ -884,12 +884,12 @@ std::string_view RemoveTrailingSlash(std::string_view path) { return path; } -std::string SanitizePath(std::string_view path_, bool with_platform_slashes) { +std::string SanitizePath(std::string_view path_, DirectorySeparator directory_separator) { std::string path(path_); - char type1 = '\\'; - char type2 = '/'; + char type1 = directory_separator == DirectorySeparator::BackwardSlash ? '/' : '\\'; + char type2 = directory_separator == DirectorySeparator::BackwardSlash ? '\\' : '/'; - if (with_platform_slashes) { + if (directory_separator == DirectorySeparator::PlatformDefault) { #ifdef _WIN32 type1 = '/'; type2 = '\\'; diff --git a/src/common/file_util.h b/src/common/file_util.h index ca63d7466..2711872ae 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h @@ -182,9 +182,12 @@ std::vector SliceVector(const std::vector& vector, size_t first, size_t la return std::vector(vector.begin() + first, vector.begin() + first + last); } +enum class DirectorySeparator { ForwardSlash, BackwardSlash, PlatformDefault }; + // Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\' -// if windows and with_platform_slashes is true. -std::string SanitizePath(std::string_view path, bool with_platform_slashes = false); +// depending if directory_separator is BackwardSlash or PlatformDefault and running on windows +std::string SanitizePath(std::string_view path, + DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash); // simple wrapper for cstdlib file functions to // hopefully will make error checking easier diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index 21ea35aaf..1b5919737 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp @@ -53,7 +53,7 @@ bool RealVfsFilesystem::IsWritable() const { } VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const { - const auto path = FileUtil::SanitizePath(path_, true); + const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); if (!FileUtil::Exists(path)) return VfsEntryType::None; if (FileUtil::IsDirectory(path)) @@ -63,7 +63,7 @@ VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const { } VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { - const auto path = FileUtil::SanitizePath(path_, true); + const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); if (cache.find(path) != cache.end()) { auto weak = cache[path]; if (!weak.expired()) { @@ -82,15 +82,17 @@ VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { } VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) { - const auto path = FileUtil::SanitizePath(path_, true); + const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); if (!FileUtil::Exists(path) && !FileUtil::CreateEmptyFile(path)) return nullptr; return OpenFile(path, perms); } VirtualFile RealVfsFilesystem::CopyFile(std::string_view old_path_, std::string_view new_path_) { - const auto old_path = FileUtil::SanitizePath(old_path_, true); - const auto new_path = FileUtil::SanitizePath(new_path_, true); + const auto old_path = + FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault); + const auto new_path = + FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault); if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || FileUtil::IsDirectory(old_path) || !FileUtil::Copy(old_path, new_path)) @@ -99,8 +101,10 @@ VirtualFile RealVfsFilesystem::CopyFile(std::string_view old_path_, std::string_ } VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) { - const auto old_path = FileUtil::SanitizePath(old_path_, true); - const auto new_path = FileUtil::SanitizePath(new_path_, true); + const auto old_path = + FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault); + const auto new_path = + FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault); if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path)) @@ -119,7 +123,7 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_ } bool RealVfsFilesystem::DeleteFile(std::string_view path_) { - const auto path = FileUtil::SanitizePath(path_, true); + const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); if (cache.find(path) != cache.end()) { if (!cache[path].expired()) cache[path].lock()->Close(); @@ -129,13 +133,13 @@ bool RealVfsFilesystem::DeleteFile(std::string_view path_) { } VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) { - const auto path = FileUtil::SanitizePath(path_, true); + const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); // Cannot use make_shared as RealVfsDirectory constructor is private return std::shared_ptr(new RealVfsDirectory(*this, path, perms)); } VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) { - const auto path = FileUtil::SanitizePath(path_, true); + const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); if (!FileUtil::Exists(path) && !FileUtil::CreateDir(path)) return nullptr; // Cannot use make_shared as RealVfsDirectory constructor is private @@ -144,8 +148,10 @@ VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms VirtualDir RealVfsFilesystem::CopyDirectory(std::string_view old_path_, std::string_view new_path_) { - const auto old_path = FileUtil::SanitizePath(old_path_, true); - const auto new_path = FileUtil::SanitizePath(new_path_, true); + const auto old_path = + FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault); + const auto new_path = + FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault); if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || !FileUtil::IsDirectory(old_path)) return nullptr; @@ -155,8 +161,10 @@ VirtualDir RealVfsFilesystem::CopyDirectory(std::string_view old_path_, VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_, std::string_view new_path_) { - const auto old_path = FileUtil::SanitizePath(old_path_, true); - const auto new_path = FileUtil::SanitizePath(new_path_, true); + const auto old_path = + FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault); + const auto new_path = + FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault); if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path)) return nullptr; @@ -164,9 +172,11 @@ VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_, for (auto& kv : cache) { // Path in cache starts with old_path if (kv.first.rfind(old_path, 0) == 0) { - const auto file_old_path = FileUtil::SanitizePath(kv.first, true); + const auto file_old_path = + FileUtil::SanitizePath(kv.first, FileUtil::DirectorySeparator::PlatformDefault); const auto file_new_path = - FileUtil::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()), true); + FileUtil::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()), + FileUtil::DirectorySeparator::PlatformDefault); auto cached = cache[file_old_path]; if (!cached.expired()) { auto file = cached.lock(); @@ -181,7 +191,7 @@ VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_, } bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) { - const auto path = FileUtil::SanitizePath(path_, true); + const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); for (auto& kv : cache) { // Path in cache starts with old_path if (kv.first.rfind(path, 0) == 0) { diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index 49a3f6181..114a0fc7f 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h @@ -140,7 +140,7 @@ class GameListWorker : public QObject, public QRunnable { public: GameListWorker(FileSys::VirtualFilesystem vfs, QString dir_path, bool deep_scan) - : dir_path(std::move(dir_path)), deep_scan(deep_scan) {} + : vfs(std::move(vfs)), dir_path(std::move(dir_path)), deep_scan(deep_scan) {} public slots: /// Starts the processing of directory tree information. -- cgit v1.2.3 From 94cf327e776eff934052847346d8415d584b369b Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Wed, 8 Aug 2018 14:34:06 -0400 Subject: vfs: Fix typo in VfsFilesystem docs --- src/core/file_sys/vfs.h | 2 +- src/yuzu/game_list.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'src/yuzu') diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h index 9c7ef93b8..bf16e7286 100644 --- a/src/core/file_sys/vfs.h +++ b/src/core/file_sys/vfs.h @@ -31,7 +31,7 @@ enum class VfsEntryType { Directory, }; -// A class represnting an abstract filesystem. A default implementation given the root VirtualDir is +// A class representing an abstract filesystem. A default implementation given the root VirtualDir is // provided for convenience, but if the Vfs implementation has any additional state or // functionality, they will need to override. struct VfsFilesystem : NonCopyable { diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index e150a0684..1c738d2a4 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -15,6 +15,7 @@ #include "common/string_util.h" #include "core/file_sys/content_archive.h" #include "core/file_sys/control_metadata.h" +#include "core/file_sys/romfs.h" #include "core/file_sys/vfs_real.h" #include "core/loader/loader.h" #include "game_list.h" @@ -415,8 +416,8 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign bool is_dir = FileUtil::IsDirectory(physical_name); QFileInfo file_info(physical_name.c_str()); if (!is_dir && file_info.suffix().toStdString() == "nca") { - auto nca = std::make_shared( - std::make_shared(physical_name)); + auto nca = + std::make_shared(vfs->OpenFile(physical_name, FileSys::Mode::Read)); if (nca->GetType() == FileSys::NCAContentType::Control) nca_control_map.insert_or_assign(nca->GetTitleId(), nca); } @@ -460,7 +461,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign // Use from metadata pool. if (nca_control_map.find(program_id) != nca_control_map.end()) { const auto nca = nca_control_map[program_id]; - const auto control_dir = nca->GetSubdirectories()[0]; + const auto control_dir = FileSys::ExtractRomFS(nca->GetRomFS()); const auto nacp_file = control_dir->GetFile("control.nacp"); FileSys::NACP nacp(nacp_file); -- cgit v1.2.3 From 668458525ede125509ee27388221247b639f4676 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Wed, 8 Aug 2018 21:44:59 -0400 Subject: vfs: Fix documentation --- src/core/file_sys/vfs.h | 4 ++-- src/yuzu/main.cpp | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src/yuzu') diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h index bf16e7286..141a053ce 100644 --- a/src/core/file_sys/vfs.h +++ b/src/core/file_sys/vfs.h @@ -31,8 +31,8 @@ enum class VfsEntryType { Directory, }; -// A class representing an abstract filesystem. A default implementation given the root VirtualDir is -// provided for convenience, but if the Vfs implementation has any additional state or +// A class representing an abstract filesystem. A default implementation given the root VirtualDir +// is provided for convenience, but if the Vfs implementation has any additional state or // functionality, they will need to override. struct VfsFilesystem : NonCopyable { VfsFilesystem(VirtualDir root); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index f7812a392..67e3c6549 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -82,6 +82,8 @@ static void ShowCalloutMessage(const QString& message, CalloutFlag flag) { void GMainWindow::ShowCallouts() {} +const int GMainWindow::max_recent_files_item; + GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr), vfs(std::make_shared()) { -- cgit v1.2.3 From 3a67876252d616e1221e1a83b2dbe387993ad124 Mon Sep 17 00:00:00 2001 From: bunnei Date: Thu, 9 Aug 2018 20:17:48 -0400 Subject: textures: Refactor out for Texture/Depth FormatFromPixelFormat. --- .../renderer_opengl/gl_rasterizer_cache.cpp | 31 +++++--- .../renderer_opengl/gl_rasterizer_cache.h | 86 ---------------------- src/video_core/textures/decoders.cpp | 85 +-------------------- src/video_core/textures/decoders.h | 4 +- src/yuzu/debugger/graphics/graphics_surface.cpp | 6 +- 5 files changed, 31 insertions(+), 181 deletions(-) (limited to 'src/yuzu') diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 114d35ce6..885403cd0 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -183,6 +183,21 @@ MathUtil::Rectangle SurfaceParams::GetRect() const { return {0, actual_height, width, 0}; } +/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN +static bool IsFormatBCn(PixelFormat format) { + switch (format) { + case PixelFormat::DXT1: + case PixelFormat::DXT23: + case PixelFormat::DXT45: + case PixelFormat::DXN1: + case PixelFormat::DXN2SNORM: + case PixelFormat::DXN2UNORM: + case PixelFormat::BC7U: + return true; + } + return false; +} + template void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector& gl_buffer, Tegra::GPUVAddr addr) { @@ -191,16 +206,12 @@ void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector& gl_bu const auto& gpu = Core::System::GetInstance().GPU(); if (morton_to_gl) { - std::vector data; - if (SurfaceParams::GetFormatType(format) == SurfaceType::ColorTexture) { - data = Tegra::Texture::UnswizzleTexture( - *gpu.memory_manager->GpuToCpuAddress(addr), - SurfaceParams::TextureFormatFromPixelFormat(format), stride, height, block_height); - } else { - data = Tegra::Texture::UnswizzleDepthTexture( - *gpu.memory_manager->GpuToCpuAddress(addr), - SurfaceParams::DepthFormatFromPixelFormat(format), stride, height, block_height); - } + // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual + // pixel values. + const u32 tile_size{IsFormatBCn(format) ? 4U : 1U}; + const std::vector data = + Tegra::Texture::UnswizzleTexture(*gpu.memory_manager->GpuToCpuAddress(addr), tile_size, + bytes_per_pixel, stride, height, block_height); const size_t size_to_copy{std::min(gl_buffer.size(), data.size())}; gl_buffer.assign(data.begin(), data.begin() + size_to_copy); } else { diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 26e2ee203..36213c403 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -348,92 +348,6 @@ struct SurfaceParams { } } - static Tegra::Texture::TextureFormat TextureFormatFromPixelFormat(PixelFormat format) { - // TODO(Subv): Properly implement this - switch (format) { - case PixelFormat::ABGR8: - case PixelFormat::SRGBA8: - return Tegra::Texture::TextureFormat::A8R8G8B8; - case PixelFormat::B5G6R5: - return Tegra::Texture::TextureFormat::B5G6R5; - case PixelFormat::A2B10G10R10: - return Tegra::Texture::TextureFormat::A2B10G10R10; - case PixelFormat::A1B5G5R5: - return Tegra::Texture::TextureFormat::A1B5G5R5; - case PixelFormat::R8: - return Tegra::Texture::TextureFormat::R8; - case PixelFormat::G8R8: - return Tegra::Texture::TextureFormat::G8R8; - case PixelFormat::RGBA16F: - return Tegra::Texture::TextureFormat::R16_G16_B16_A16; - case PixelFormat::R11FG11FB10F: - return Tegra::Texture::TextureFormat::BF10GF11RF11; - case PixelFormat::RGBA32UI: - return Tegra::Texture::TextureFormat::R32_G32_B32_A32; - case PixelFormat::DXT1: - return Tegra::Texture::TextureFormat::DXT1; - case PixelFormat::DXT23: - return Tegra::Texture::TextureFormat::DXT23; - case PixelFormat::DXT45: - return Tegra::Texture::TextureFormat::DXT45; - case PixelFormat::DXN1: - return Tegra::Texture::TextureFormat::DXN1; - case PixelFormat::DXN2UNORM: - case PixelFormat::DXN2SNORM: - return Tegra::Texture::TextureFormat::DXN2; - case PixelFormat::BC7U: - return Tegra::Texture::TextureFormat::BC7U; - case PixelFormat::ASTC_2D_4X4: - return Tegra::Texture::TextureFormat::ASTC_2D_4X4; - case PixelFormat::BGRA8: - // TODO(bunnei): This is fine for unswizzling (since we just need the right component - // sizes), but could be a bug if we used this function in different ways. - return Tegra::Texture::TextureFormat::A8R8G8B8; - case PixelFormat::RGBA32F: - return Tegra::Texture::TextureFormat::R32_G32_B32_A32; - case PixelFormat::RGB32F: - return Tegra::Texture::TextureFormat::R32_G32_B32; - case PixelFormat::RG32F: - return Tegra::Texture::TextureFormat::R32_G32; - case PixelFormat::R32F: - return Tegra::Texture::TextureFormat::R32; - case PixelFormat::R16F: - case PixelFormat::R16UNORM: - return Tegra::Texture::TextureFormat::R16; - case PixelFormat::Z32F: - return Tegra::Texture::TextureFormat::ZF32; - case PixelFormat::Z24S8: - return Tegra::Texture::TextureFormat::Z24S8; - case PixelFormat::RG16F: - case PixelFormat::RG16: - case PixelFormat::RG16UI: - case PixelFormat::RG16I: - case PixelFormat::RG16S: - return Tegra::Texture::TextureFormat::R16_G16; - default: - LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast(format)); - UNREACHABLE(); - } - } - - static Tegra::DepthFormat DepthFormatFromPixelFormat(PixelFormat format) { - switch (format) { - case PixelFormat::S8Z24: - return Tegra::DepthFormat::S8_Z24_UNORM; - case PixelFormat::Z24S8: - return Tegra::DepthFormat::Z24_S8_UNORM; - case PixelFormat::Z32F: - return Tegra::DepthFormat::Z32_FLOAT; - case PixelFormat::Z16: - return Tegra::DepthFormat::Z16_UNORM; - case PixelFormat::Z32FS8: - return Tegra::DepthFormat::Z32_S8_X24_FLOAT; - default: - LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast(format)); - UNREACHABLE(); - } - } - static ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type) { // TODO(Subv): Implement more component types switch (type) { diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index 7ea66584c..70746a34e 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp @@ -86,88 +86,11 @@ u32 BytesPerPixel(TextureFormat format) { } } -static u32 DepthBytesPerPixel(DepthFormat format) { - switch (format) { - case DepthFormat::Z16_UNORM: - return 2; - case DepthFormat::S8_Z24_UNORM: - case DepthFormat::Z24_S8_UNORM: - case DepthFormat::Z32_FLOAT: - return 4; - case DepthFormat::Z32_S8_X24_FLOAT: - return 8; - default: - UNIMPLEMENTED_MSG("Format not implemented"); - break; - } -} - -std::vector UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height, - u32 block_height) { - u8* data = Memory::GetPointer(address); - u32 bytes_per_pixel = BytesPerPixel(format); - - std::vector unswizzled_data(width * height * bytes_per_pixel); - - switch (format) { - case TextureFormat::DXT1: - case TextureFormat::DXT23: - case TextureFormat::DXT45: - case TextureFormat::DXN1: - case TextureFormat::DXN2: - case TextureFormat::BC7U: - // In the DXT and DXN formats, each 4x4 tile is swizzled instead of just individual pixel - // values. - CopySwizzledData(width / 4, height / 4, bytes_per_pixel, bytes_per_pixel, data, - unswizzled_data.data(), true, block_height); - break; - case TextureFormat::A8R8G8B8: - case TextureFormat::A2B10G10R10: - case TextureFormat::A1B5G5R5: - case TextureFormat::B5G6R5: - case TextureFormat::R8: - case TextureFormat::G8R8: - case TextureFormat::R16_G16_B16_A16: - case TextureFormat::R32_G32_B32_A32: - case TextureFormat::R32_G32: - case TextureFormat::R32: - case TextureFormat::R16: - case TextureFormat::R16_G16: - case TextureFormat::BF10GF11RF11: - case TextureFormat::ASTC_2D_4X4: - case TextureFormat::R32_G32_B32: - CopySwizzledData(width, height, bytes_per_pixel, bytes_per_pixel, data, - unswizzled_data.data(), true, block_height); - break; - default: - UNIMPLEMENTED_MSG("Format not implemented"); - break; - } - - return unswizzled_data; -} - -std::vector UnswizzleDepthTexture(VAddr address, DepthFormat format, u32 width, u32 height, - u32 block_height) { - u8* data = Memory::GetPointer(address); - u32 bytes_per_pixel = DepthBytesPerPixel(format); - +std::vector UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width, + u32 height, u32 block_height) { std::vector unswizzled_data(width * height * bytes_per_pixel); - - switch (format) { - case DepthFormat::Z16_UNORM: - case DepthFormat::S8_Z24_UNORM: - case DepthFormat::Z24_S8_UNORM: - case DepthFormat::Z32_FLOAT: - case DepthFormat::Z32_S8_X24_FLOAT: - CopySwizzledData(width, height, bytes_per_pixel, bytes_per_pixel, data, - unswizzled_data.data(), true, block_height); - break; - default: - UNIMPLEMENTED_MSG("Format not implemented"); - break; - } - + CopySwizzledData(width / tile_size, height / tile_size, bytes_per_pixel, bytes_per_pixel, + Memory::GetPointer(address), unswizzled_data.data(), true, block_height); return unswizzled_data; } diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h index 73a4924d1..1f7b731be 100644 --- a/src/video_core/textures/decoders.h +++ b/src/video_core/textures/decoders.h @@ -13,8 +13,8 @@ namespace Tegra::Texture { /** * Unswizzles a swizzled texture without changing its format. */ -std::vector UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height, - u32 block_height = TICEntry::DefaultBlockHeight); +std::vector UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width, + u32 height, u32 block_height = TICEntry::DefaultBlockHeight); /** * Unswizzles a swizzled depth texture without changing its format. diff --git a/src/yuzu/debugger/graphics/graphics_surface.cpp b/src/yuzu/debugger/graphics/graphics_surface.cpp index 3f7103ab9..e037223c2 100644 --- a/src/yuzu/debugger/graphics/graphics_surface.cpp +++ b/src/yuzu/debugger/graphics/graphics_surface.cpp @@ -383,8 +383,10 @@ void GraphicsSurfaceWidget::OnUpdate() { QImage decoded_image(surface_width, surface_height, QImage::Format_ARGB32); boost::optional address = gpu.memory_manager->GpuToCpuAddress(surface_address); - auto unswizzled_data = - Tegra::Texture::UnswizzleTexture(*address, surface_format, surface_width, surface_height); + // TODO(bunnei): Will not work with BCn formats that swizzle 4x4 tiles. + // Needs to be fixed if we plan to use this feature more, otherwise we may remove it. + auto unswizzled_data = Tegra::Texture::UnswizzleTexture( + *address, 1, Tegra::Texture::BytesPerPixel(surface_format), surface_width, surface_height); auto texture_data = Tegra::Texture::DecodeTexture(unswizzled_data, surface_format, surface_width, surface_height); -- cgit v1.2.3