diff --git a/README.md b/README.md index aeb118912..7fb8b281c 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 1832. +This is the source code for early-access 1833. ## Legal Notice diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp index 1952c88ef..ccd5ca6cc 100755 --- a/src/audio_core/audio_renderer.cpp +++ b/src/audio_core/audio_renderer.cpp @@ -69,7 +69,7 @@ namespace { } // namespace namespace AudioCore { -constexpr s32 NUM_BUFFERS = 4; +constexpr s32 NUM_BUFFERS = 2; AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& memory_, AudioCommon::AudioRendererParameter params, diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 53b8b7ca0..13d294ad8 100755 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -345,8 +345,10 @@ std::vector PatchManager::CreateCheatList( static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type, const Service::FileSystem::FileSystemController& fs_controller) { const auto load_dir = fs_controller.GetModificationLoadRoot(title_id); + const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id); if ((type != ContentRecordType::Program && type != ContentRecordType::Data) || - load_dir == nullptr || load_dir->GetSize() <= 0) { + ((load_dir == nullptr || load_dir->GetSize() <= 0) && + (sdmc_load_dir == nullptr || sdmc_load_dir->GetSize() <= 0))) { return; } @@ -356,7 +358,10 @@ static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType t } const auto& disabled = Settings::values.disabled_addons[title_id]; - auto patch_dirs = load_dir->GetSubdirectories(); + std::vector patch_dirs = load_dir->GetSubdirectories(); + if (std::find(disabled.cbegin(), disabled.cend(), "SDMC") == disabled.cend()) { + patch_dirs.push_back(sdmc_load_dir); + } std::sort(patch_dirs.begin(), patch_dirs.end(), [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); }); @@ -524,6 +529,15 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u } } + // SDMC mod directory (RomFS LayeredFS) + const auto sdmc_mod_dir = fs_controller.GetSDMCModificationLoadRoot(title_id); + if (sdmc_mod_dir != nullptr && sdmc_mod_dir->GetSize() > 0 && + IsDirValidAndNonEmpty(FindSubdirectoryCaseless(sdmc_mod_dir, "romfs"))) { + const auto mod_disabled = + std::find(disabled.begin(), disabled.end(), "SDMC") != disabled.end(); + out.insert_or_assign(mod_disabled ? "[D] SDMC" : "SDMC", "LayeredFS"); + } + // DLC const auto dlc_entries = content_provider.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data); diff --git a/src/core/file_sys/sdmc_factory.cpp b/src/core/file_sys/sdmc_factory.cpp index cb56d8f2d..e5c72cd4d 100755 --- a/src/core/file_sys/sdmc_factory.cpp +++ b/src/core/file_sys/sdmc_factory.cpp @@ -12,23 +12,32 @@ namespace FileSys { constexpr u64 SDMC_TOTAL_SIZE = 0x10000000000; // 1 TiB -SDMCFactory::SDMCFactory(VirtualDir dir_) - : dir(std::move(dir_)), contents(std::make_unique( - GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/registered"), - [](const VirtualFile& file, const NcaID& id) { - return NAX{file, id}.GetDecrypted(); - })), +SDMCFactory::SDMCFactory(VirtualDir sd_dir_, VirtualDir sd_mod_dir_) + : sd_dir(std::move(sd_dir_)), sd_mod_dir(std::move(sd_mod_dir_)), + contents(std::make_unique( + GetOrCreateDirectoryRelative(sd_dir, "/Nintendo/Contents/registered"), + [](const VirtualFile& file, const NcaID& id) { + return NAX{file, id}.GetDecrypted(); + })), placeholder(std::make_unique( - GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/placehld"))) {} + GetOrCreateDirectoryRelative(sd_dir, "/Nintendo/Contents/placehld"))) {} SDMCFactory::~SDMCFactory() = default; ResultVal SDMCFactory::Open() const { - return MakeResult(dir); + return MakeResult(sd_dir); +} + +VirtualDir SDMCFactory::GetSDMCModificationLoadRoot(u64 title_id) const { + // LayeredFS doesn't work on updates and title id-less homebrew + if (title_id == 0 || (title_id & 0xFFF) == 0x800) { + return nullptr; + } + return GetOrCreateDirectoryRelative(sd_mod_dir, fmt::format("/{:016X}", title_id)); } VirtualDir SDMCFactory::GetSDMCContentDirectory() const { - return GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents"); + return GetOrCreateDirectoryRelative(sd_dir, "/Nintendo/Contents"); } RegisteredCache* SDMCFactory::GetSDMCContents() const { @@ -40,11 +49,11 @@ PlaceholderCache* SDMCFactory::GetSDMCPlaceholder() const { } VirtualDir SDMCFactory::GetImageDirectory() const { - return GetOrCreateDirectoryRelative(dir, "/Nintendo/Album"); + return GetOrCreateDirectoryRelative(sd_dir, "/Nintendo/Album"); } u64 SDMCFactory::GetSDMCFreeSpace() const { - return GetSDMCTotalSpace() - dir->GetSize(); + return GetSDMCTotalSpace() - sd_dir->GetSize(); } u64 SDMCFactory::GetSDMCTotalSpace() const { diff --git a/src/core/file_sys/sdmc_factory.h b/src/core/file_sys/sdmc_factory.h index 2bb92ba93..3a3d11f3a 100755 --- a/src/core/file_sys/sdmc_factory.h +++ b/src/core/file_sys/sdmc_factory.h @@ -16,11 +16,12 @@ class PlaceholderCache; /// File system interface to the SDCard archive class SDMCFactory { public: - explicit SDMCFactory(VirtualDir dir); + explicit SDMCFactory(VirtualDir sd_dir_, VirtualDir sd_mod_dir_); ~SDMCFactory(); ResultVal Open() const; + VirtualDir GetSDMCModificationLoadRoot(u64 title_id) const; VirtualDir GetSDMCContentDirectory() const; RegisteredCache* GetSDMCContents() const; @@ -32,7 +33,8 @@ public: u64 GetSDMCTotalSpace() const; private: - VirtualDir dir; + VirtualDir sd_dir; + VirtualDir sd_mod_dir; std::unique_ptr contents; std::unique_ptr placeholder; diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index feb5150e1..7583d68b2 100755 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -96,7 +96,7 @@ private: void RequestUpdateImpl(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_Audio, "(STUBBED) called"); - std::vector output_params(ctx.GetWriteBufferSize()); + std::vector output_params(ctx.GetWriteBufferSize(), 0); auto result = renderer->UpdateAudioRenderer(ctx.ReadBuffer(), output_params); if (result.IsSuccess()) { diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 3c16fe6c7..4a9b13e45 100755 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -703,6 +703,16 @@ FileSys::VirtualDir FileSystemController::GetModificationLoadRoot(u64 title_id) return bis_factory->GetModificationLoadRoot(title_id); } +FileSys::VirtualDir FileSystemController::GetSDMCModificationLoadRoot(u64 title_id) const { + LOG_TRACE(Service_FS, "Opening SDMC mod load root for tid={:016X}", title_id); + + if (sdmc_factory == nullptr) { + return nullptr; + } + + return sdmc_factory->GetSDMCModificationLoadRoot(title_id); +} + FileSys::VirtualDir FileSystemController::GetModificationDumpRoot(u64 title_id) const { LOG_TRACE(Service_FS, "Opening mod dump root for tid={:016X}", title_id); @@ -733,20 +743,23 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove } using YuzuPath = Common::FS::YuzuPath; + const auto sdmc_dir_path = Common::FS::GetYuzuPath(YuzuPath::SDMCDir); + const auto sdmc_load_dir_path = sdmc_dir_path / "atmosphere/contents"; const auto rw_mode = FileSys::Mode::ReadWrite; auto nand_directory = vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::NANDDir), rw_mode); - auto sd_directory = - vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::SDMCDir), rw_mode); + auto sd_directory = vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_dir_path), rw_mode); auto load_directory = vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::LoadDir), FileSys::Mode::Read); + auto sd_load_directory = + vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_load_dir_path), FileSys::Mode::Read); auto dump_directory = vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::DumpDir), rw_mode); if (bis_factory == nullptr) { - bis_factory = - std::make_unique(nand_directory, load_directory, dump_directory); + bis_factory = std::make_unique( + nand_directory, std::move(load_directory), std::move(dump_directory)); system.RegisterContentProvider(FileSys::ContentProviderUnionSlot::SysNAND, bis_factory->GetSystemNANDContents()); system.RegisterContentProvider(FileSys::ContentProviderUnionSlot::UserNAND, @@ -759,7 +772,8 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove } if (sdmc_factory == nullptr) { - sdmc_factory = std::make_unique(std::move(sd_directory)); + sdmc_factory = std::make_unique(std::move(sd_directory), + std::move(sd_load_directory)); system.RegisterContentProvider(FileSys::ContentProviderUnionSlot::SDMC, sdmc_factory->GetSDMCContents()); } diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index b6b1b9220..d387af3cb 100755 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -115,6 +115,7 @@ public: FileSys::VirtualDir GetContentDirectory(ContentStorageId id) const; FileSys::VirtualDir GetImageDirectory(ImageDirectoryId id) const; + FileSys::VirtualDir GetSDMCModificationLoadRoot(u64 title_id) const; FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) const; FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) const; diff --git a/src/video_core/textures/astc.cpp b/src/video_core/textures/astc.cpp index e2eb9eaf1..c066d8cbf 100755 --- a/src/video_core/textures/astc.cpp +++ b/src/video_core/textures/astc.cpp @@ -1578,7 +1578,7 @@ void Decompress(std::span data, uint32_t width, uint32_t height, const u32 y = stride.index * block_height; const u32 depth_offset = stride.z * height * width * 4; for (u32 x_index = 0; x_index < cols; ++x_index) { - const u32 block_index = stride.index * cols + x_index; + const u32 block_index = (stride.z * rows * cols) + (stride.index * cols) + x_index; const u32 x = x_index * block_width; const std::span blockPtr{data.subspan(block_index * 16, 16)}; @@ -1614,7 +1614,7 @@ void Decompress(std::span data, uint32_t width, uint32_t height, // for (u32 y_index = 0; y_index < rows; ++y_index) { // const u32 y = y_index * block_height; // for (u32 x_index = 0; x_index < cols; ++x_index) { - // const u32 block_index = y_index * cols + x_index; + // const u32 block_index = (z * rows * cols) + (y_index * cols) + x_index; // const u32 x = x_index * block_width; // const std::span blockPtr{data.subspan(block_index * 16, 16)}; diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index da956c99b..e44907be8 100755 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -521,7 +521,9 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri QAction* remove_custom_config = remove_menu->addAction(tr("Remove Custom Configuration")); remove_menu->addSeparator(); QAction* remove_all_content = remove_menu->addAction(tr("Remove All Installed Contents")); - QAction* dump_romfs = context_menu.addAction(tr("Dump RomFS")); + QMenu* dump_romfs_menu = context_menu.addMenu(tr("Dump RomFS")); + QAction* dump_romfs = dump_romfs_menu->addAction(tr("Dump RomFS")); + QAction* dump_romfs_sdmc = dump_romfs_menu->addAction(tr("Dump RomFS to SDMC")); QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard")); QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("Navigate to GameDB entry")); context_menu.addSeparator(); @@ -570,8 +572,12 @@ void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, const std::stri connect(remove_custom_config, &QAction::triggered, [this, program_id, path]() { emit RemoveFileRequested(program_id, GameListRemoveTarget::CustomConfiguration, path); }); - connect(dump_romfs, &QAction::triggered, - [this, program_id, path]() { emit DumpRomFSRequested(program_id, path); }); + connect(dump_romfs, &QAction::triggered, [this, program_id, path]() { + emit DumpRomFSRequested(program_id, path, DumpRomFSTarget::Normal); + }); + connect(dump_romfs_sdmc, &QAction::triggered, [this, program_id, path]() { + emit DumpRomFSRequested(program_id, path, DumpRomFSTarget::SDMC); + }); connect(copy_tid, &QAction::triggered, [this, program_id]() { emit CopyTIDRequested(program_id); }); connect(navigate_to_gamedb_entry, &QAction::triggered, [this, program_id]() { diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index b630e34ff..50402da51 100755 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h @@ -45,6 +45,11 @@ enum class GameListRemoveTarget { CustomConfiguration, }; +enum class DumpRomFSTarget { + Normal, + SDMC, +}; + enum class InstalledEntryType { Game, Update, @@ -92,7 +97,7 @@ signals: void RemoveInstalledEntryRequested(u64 program_id, InstalledEntryType type); void RemoveFileRequested(u64 program_id, GameListRemoveTarget target, const std::string& game_path); - void DumpRomFSRequested(u64 program_id, const std::string& game_path); + void DumpRomFSRequested(u64 program_id, const std::string& game_path, DumpRomFSTarget target); void CopyTIDRequested(u64 program_id); void NavigateToGamedbEntryRequested(u64 program_id, const CompatibilityList& compatibility_list); diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 9d0a1ab64..08eb3722d 100755 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1423,6 +1423,9 @@ void GMainWindow::BootGame(const QString& filename, std::size_t program_index, S title_name = Common::FS::PathToUTF8String( std::filesystem::path{filename.toStdU16String()}.filename()); } + const bool is_64bit = system.Kernel().CurrentProcess()->Is64BitProcess(); + const auto instruction_set_suffix = is_64bit ? " (64-bit)" : " (32-bit)"; + title_name += instruction_set_suffix; LOG_INFO(Frontend, "Booting game: {:016X} | {} | {}", title_id, title_name, title_version); const auto gpu_vendor = system.GPU().Renderer().GetDeviceVendor(); UpdateWindowTitle(title_name, title_version, gpu_vendor); @@ -1879,7 +1882,8 @@ void GMainWindow::RemoveCustomConfiguration(u64 program_id, const std::string& g } } -void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path) { +void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path, + DumpRomFSTarget target) { const auto failed = [this] { QMessageBox::warning(this, tr("RomFS Extraction Failed!"), tr("There was an error copying the RomFS files or the user " @@ -1907,7 +1911,10 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa return; } - const auto dump_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir); + const auto dump_dir = + target == DumpRomFSTarget::Normal + ? Common::FS::GetYuzuPath(Common::FS::YuzuPath::DumpDir) + : Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir) / "atmosphere" / "contents"; const auto romfs_dir = fmt::format("{:016X}/romfs", *romfs_title_id); const auto path = Common::FS::PathToUTF8String(dump_dir / romfs_dir); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 5c199155a..45c8310e1 100755 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -34,6 +34,7 @@ class QProgressDialog; class WaitTreeWidget; enum class GameListOpenTarget; enum class GameListRemoveTarget; +enum class DumpRomFSTarget; enum class InstalledEntryType; class GameListPlaceholder; @@ -244,7 +245,7 @@ private slots: void OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type); void OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target, const std::string& game_path); - void OnGameListDumpRomFS(u64 program_id, const std::string& game_path); + void OnGameListDumpRomFS(u64 program_id, const std::string& game_path, DumpRomFSTarget target); void OnGameListCopyTID(u64 program_id); void OnGameListNavigateToGamedbEntry(u64 program_id, const CompatibilityList& compatibility_list);