From 9db5c9b6dc7b01a0a69179707823f27f42b9cdd9 Mon Sep 17 00:00:00 2001 From: Subv Date: Tue, 24 Feb 2015 18:02:40 -0500 Subject: [PATCH 1/3] Archives: Properly implemented the SystemSaveData archive. Ported to the new factory pattern we have for archives. --- src/core/file_sys/archive_systemsavedata.cpp | 33 ++++++---- src/core/file_sys/archive_systemsavedata.h | 14 ++--- src/core/hle/service/cfg/cfg.cpp | 64 ++++++++++++-------- src/core/hle/service/fs/archive.cpp | 4 ++ 4 files changed, 70 insertions(+), 45 deletions(-) diff --git a/src/core/file_sys/archive_systemsavedata.cpp b/src/core/file_sys/archive_systemsavedata.cpp index c2a5d641a..25c94cd26 100644 --- a/src/core/file_sys/archive_systemsavedata.cpp +++ b/src/core/file_sys/archive_systemsavedata.cpp @@ -6,9 +6,9 @@ #include "common/common_types.h" #include "common/file_util.h" +#include "common/make_unique.h" #include "core/file_sys/archive_systemsavedata.h" -#include "core/file_sys/disk_archive.h" #include "core/hle/service/fs/archive.h" #include "core/settings.h" @@ -17,9 +17,11 @@ namespace FileSys { -static std::string GetSystemSaveDataPath(const std::string& mount_point, u64 save_id) { - u32 save_high = static_cast((save_id >> 32) & 0xFFFFFFFF); - u32 save_low = static_cast(save_id & 0xFFFFFFFF); +static std::string GetSystemSaveDataPath(const std::string& mount_point, const Path& path) { + std::vector vec_data = path.AsBinary(); + const u32* data = reinterpret_cast(vec_data.data()); + u32 save_low = data[1]; + u32 save_high = data[0]; return Common::StringFromFormat("%s%08X/%08X/", mount_point.c_str(), save_low, save_high); } @@ -27,18 +29,25 @@ static std::string GetSystemSaveDataContainerPath(const std::string& mount_point return Common::StringFromFormat("%sdata/%s/sysdata/", mount_point.c_str(), SYSTEM_ID.c_str()); } -Archive_SystemSaveData::Archive_SystemSaveData(const std::string& mount_point, u64 save_id) - : DiskArchive(GetSystemSaveDataPath(GetSystemSaveDataContainerPath(mount_point), save_id)) { - LOG_INFO(Service_FS, "Directory %s set as SystemSaveData.", this->mount_point.c_str()); +ArchiveFactory_SystemSaveData::ArchiveFactory_SystemSaveData(const std::string& nand_path) + : base_path(GetSystemSaveDataContainerPath(nand_path)) { } -bool Archive_SystemSaveData::Initialize() { - if (!FileUtil::CreateFullPath(mount_point)) { - LOG_ERROR(Service_FS, "Unable to create SystemSaveData path."); - return false; +ResultVal> ArchiveFactory_SystemSaveData::Open(const Path& path) { + std::string fullpath = GetSystemSaveDataPath(base_path, path); + if (!FileUtil::Exists(fullpath)) { + // TODO(Subv): Check error code, this one is probably wrong + return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, + ErrorSummary::InvalidState, ErrorLevel::Status); } + auto archive = Common::make_unique(fullpath); + return MakeResult>(std::move(archive)); +} - return true; +ResultCode ArchiveFactory_SystemSaveData::Format(const Path& path) { + std::string fullpath = GetSystemSaveDataPath(base_path, path); + FileUtil::CreateFullPath(fullpath); + return RESULT_SUCCESS; } } // namespace FileSys diff --git a/src/core/file_sys/archive_systemsavedata.h b/src/core/file_sys/archive_systemsavedata.h index c8f5845ca..556a2a488 100644 --- a/src/core/file_sys/archive_systemsavedata.h +++ b/src/core/file_sys/archive_systemsavedata.h @@ -15,17 +15,17 @@ namespace FileSys { /// File system interface to the SystemSaveData archive -class Archive_SystemSaveData final : public DiskArchive { +class ArchiveFactory_SystemSaveData final : public ArchiveFactory { public: - Archive_SystemSaveData(const std::string& mount_point, u64 save_id); + ArchiveFactory_SystemSaveData(const std::string& mount_point); - /** - * Initialize the archive. - * @return true if it initialized successfully - */ - bool Initialize(); + ResultVal> Open(const Path& path) override; + ResultCode Format(const Path& path) override; std::string GetName() const override { return "SystemSaveData"; } + +private: + std::string base_path; }; } // namespace FileSys diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp index 1a2104b48..b7cdccb86 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp @@ -4,8 +4,8 @@ #include #include "common/make_unique.h" -#include "core/file_sys/archive_systemsavedata.h" #include "core/hle/service/cfg/cfg.h" +#include "core/hle/service/fs/archive.h" namespace Service { namespace CFG { @@ -36,7 +36,8 @@ const std::array STEREO_CAMERA_SETTINGS = { static const u32 CONFIG_SAVEFILE_SIZE = 0x8000; static std::array cfg_config_file_buffer; -static std::unique_ptr cfg_system_save_data; +static Service::FS::ArchiveHandle cfg_system_save_data_archive; +static const std::vector cfg_system_savedata_id = { 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x01, 0x00 }; ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, u8* output) { // Read the header @@ -97,19 +98,22 @@ ResultCode CreateConfigInfoBlk(u32 block_id, u16 size, u16 flags, const u8* data ResultCode DeleteConfigNANDSaveFile() { FileSys::Path path("config"); - if (cfg_system_save_data->DeleteFile(path)) - return RESULT_SUCCESS; - return ResultCode(-1); // TODO(Subv): Find the right error code + return Service::FS::DeleteFileFromArchive(cfg_system_save_data_archive, path); } ResultCode UpdateConfigNANDSavegame() { FileSys::Mode mode = {}; mode.write_flag = 1; mode.create_flag = 1; + FileSys::Path path("config"); - auto file = cfg_system_save_data->OpenFile(path, mode); - ASSERT_MSG(file != nullptr, "could not open file"); - file->Write(0, CONFIG_SAVEFILE_SIZE, 1, cfg_config_file_buffer.data()); + + auto config_result = Service::FS::OpenFileFromArchive(cfg_system_save_data_archive, path, mode); + ASSERT_MSG(config_result.Succeeded(), "could not open file"); + + auto config = config_result.MoveFrom(); + config->backend->Write(0, CONFIG_SAVEFILE_SIZE, 1, cfg_config_file_buffer.data()); + return RESULT_SUCCESS; } @@ -158,27 +162,33 @@ ResultCode FormatConfig() { } void CFGInit() { - // TODO(Subv): In the future we should use the FS service to query this archive, - // currently it is not possible because you can only have one open archive of the same type at any time - std::string nand_directory = FileUtil::GetUserPath(D_NAND_IDX); - cfg_system_save_data = Common::make_unique( - nand_directory, CFG_SAVE_ID); - if (!cfg_system_save_data->Initialize()) { - LOG_CRITICAL(Service_CFG, "Could not initialize SystemSaveData archive for the CFG:U service"); - return; + // Open the SystemSaveData archive 0x00010017 + FileSys::Path archive_path(cfg_system_savedata_id); + auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); + + // If the archive didn't exist, create the files inside + if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { + // Format the archive to create the directories + Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); + + // Open it again to get a valid archive now that the folder exists + archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); } - // TODO(Subv): All this code should be moved to cfg:i, - // it's only here because we do not currently emulate the lower level code that uses that service - // Try to open the file in read-only mode to check its existence - FileSys::Mode mode = {}; - mode.read_flag = 1; - FileSys::Path path("config"); - auto file = cfg_system_save_data->OpenFile(path, mode); + ASSERT_MSG(archive_result.Succeeded(), "Could not open the CFG SystemSaveData archive!"); - // Load the config if it already exists - if (file != nullptr) { - file->Read(0, CONFIG_SAVEFILE_SIZE, cfg_config_file_buffer.data()); + cfg_system_save_data_archive = *archive_result; + + FileSys::Path config_path("config"); + FileSys::Mode open_mode = {}; + open_mode.read_flag = 1; + + auto config_result = Service::FS::OpenFileFromArchive(*archive_result, config_path, open_mode); + + // Read the file if it already exists + if (config_result.Succeeded()) { + auto config = config_result.MoveFrom(); + config->backend->Read(0, CONFIG_SAVEFILE_SIZE, cfg_config_file_buffer.data()); return; } @@ -186,10 +196,12 @@ void CFGInit() { // TODO(Subv): Initialize this directly in the variable when MSVC supports char16_t string literals CONSOLE_USERNAME_BLOCK.ng_word = 0; CONSOLE_USERNAME_BLOCK.zero = 0; + // Copy string to buffer and pad with zeros at the end auto size = Common::UTF8ToUTF16(CONSOLE_USERNAME).copy(CONSOLE_USERNAME_BLOCK.username, 0x14); std::fill(std::begin(CONSOLE_USERNAME_BLOCK.username) + size, std::end(CONSOLE_USERNAME_BLOCK.username), 0); + FormatConfig(); } diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index a69c4f25b..c5020cb24 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -18,6 +18,7 @@ #include "core/file_sys/archive_savedata.h" #include "core/file_sys/archive_savedatacheck.h" #include "core/file_sys/archive_sdmc.h" +#include "core/file_sys/archive_systemsavedata.h" #include "core/file_sys/directory_backend.h" #include "core/hle/service/fs/archive.h" #include "core/hle/result.h" @@ -449,6 +450,9 @@ void ArchiveInit() { // Create the SaveDataCheck archive, basically a small variation of the RomFS archive auto savedatacheck_factory = Common::make_unique(nand_directory); RegisterArchiveType(std::move(savedatacheck_factory), ArchiveIdCode::SaveDataCheck); + + auto systemsavedata_factory = Common::make_unique(nand_directory); + RegisterArchiveType(std::move(systemsavedata_factory), ArchiveIdCode::SystemSaveData); } /// Shutdown archives From 3c50da6fc058ff144fb9d7329dd71dbf9b436ae3 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Wed, 25 Feb 2015 22:16:01 -0300 Subject: [PATCH 2/3] Video core: Fix pixelation/blockiness in textures. This was caused during morton decoding by me not masking the bits of each coordinate before merging them, so the bits from x could set bits in y if it was >255. --- src/video_core/debug_utils/debug_utils.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp index 0beb72e6b..795449423 100644 --- a/src/video_core/debug_utils/debug_utils.cpp +++ b/src/video_core/debug_utils/debug_utils.cpp @@ -333,9 +333,9 @@ const Math::Vec4 LookupTexture(const u8* source, int x, int y, const Texture // Interleave the lower 3 bits of each coordinate to get the intra-block offsets, which are // arranged in a Z-order curve. More details on the bit manipulation at: // https://fgiesen.wordpress.com/2009/12/13/decoding-morton-codes/ - unsigned int i = (x | (y << 8)) & 0x0707; // ---- -210 - i = (i ^ (i << 2)) & 0x1313; // ---2 --10 - i = (i ^ (i << 1)) & 0x1515; // ---2 -1-0 + unsigned int i = (x & 7) | ((y & 7) << 8); // ---- -210 + i = (i ^ (i << 2)) & 0x1313; // ---2 --10 + i = (i ^ (i << 1)) & 0x1515; // ---2 -1-0 i = (i | (i >> 7)) & 0x3F; if (info.format != Regs::TextureFormat::ETC1 && From ea3c99f3a2422c98f383df0881348b1b4a3c91d2 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Wed, 25 Feb 2015 23:05:14 -0300 Subject: [PATCH 3/3] Video core: Fix A4 texture decoding It was trying to take the LSB from `coarse_x`, which would always be 0 and thus would always return the same texel from each byte. To add insult to the injury, the conditional was actually the wrong way around too. Fixes blocky text in OoT. --- src/video_core/debug_utils/debug_utils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp index 795449423..f436aa541 100644 --- a/src/video_core/debug_utils/debug_utils.cpp +++ b/src/video_core/debug_utils/debug_utils.cpp @@ -436,9 +436,9 @@ const Math::Vec4 LookupTexture(const u8* source, int x, int y, const Texture case Regs::TextureFormat::A4: { - const u8* source_ptr = source + offset / 2 + i / 2; + const u8* source_ptr = source + (offset + i) / 2; - u8 a = (coarse_x % 2) ? ((*source_ptr)&0xF) : (((*source_ptr) & 0xF0) >> 4); + u8 a = (i % 2) ? ((*source_ptr & 0xF0) >> 4) : (*source_ptr & 0xF); a = Color::Convert4To8(a); if (disable_alpha) {