From baf3ea4beb9f4701b0c501914ca2601a2eb7f3fb Mon Sep 17 00:00:00 2001 From: GPUCode <47210458+GPUCode@users.noreply.github.com> Date: Tue, 1 Aug 2023 20:38:51 +0300 Subject: [PATCH] custom_tex_manager: Allow old hash in the dumper (#6832) --- src/core/core.cpp | 6 +- .../custom_textures/custom_tex_manager.cpp | 64 ++++++++++++------- .../custom_textures/custom_tex_manager.h | 14 ++-- .../rasterizer_cache/rasterizer_cache.h | 29 +++++---- .../rasterizer_cache/rasterizer_cache_base.h | 4 ++ 5 files changed, 73 insertions(+), 44 deletions(-) diff --git a/src/core/core.cpp b/src/core/core.cpp index a8f651723c..ac1ce52340 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -321,12 +321,12 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st cheat_engine = std::make_unique(title_id, *this); perf_stats = std::make_unique(title_id); + if (Settings::values.dump_textures) { + custom_tex_manager->PrepareDumping(title_id); + } if (Settings::values.custom_textures) { custom_tex_manager->FindCustomTextures(); } - if (Settings::values.dump_textures) { - custom_tex_manager->WriteConfig(); - } status = ResultStatus::Success; m_emu_window = &emu_window; diff --git a/src/video_core/custom_textures/custom_tex_manager.cpp b/src/video_core/custom_textures/custom_tex_manager.cpp index 3cbd7dae68..b8bb214389 100644 --- a/src/video_core/custom_textures/custom_tex_manager.cpp +++ b/src/video_core/custom_textures/custom_tex_manager.cpp @@ -90,19 +90,12 @@ void CustomTexManager::FindCustomTextures() { CreateWorkers(); } - const u64 program_id = system.Kernel().GetCurrentProcess()->codeset->program_id; - const std::string load_path = - fmt::format("{}textures/{:016X}/", GetUserPath(FileUtil::UserPath::LoadDir), program_id); - - if (!FileUtil::Exists(load_path)) { - FileUtil::CreateFullPath(load_path); + const u64 title_id = system.Kernel().GetCurrentProcess()->codeset->program_id; + const auto textures = GetTextures(title_id); + if (!ReadConfig(title_id)) { + use_new_hash = false; + skip_mipmap = true; } - ReadConfig(load_path); - - FileUtil::FSTEntry texture_dir; - std::vector textures; - FileUtil::ScanDirectoryTree(load_path, texture_dir, 64); - FileUtil::GetAllFilesFromNestedEntries(texture_dir, textures); custom_textures.reserve(textures.size()); for (const FileUtil::FSTEntry& file : textures) { @@ -137,8 +130,8 @@ bool CustomTexManager::ParseFilename(const FileUtil::FSTEntry& file, CustomTextu if (file_format == CustomFileFormat::None) { return false; } - if (file_format == CustomFileFormat::DDS && refuse_dds) { - LOG_ERROR(Render, "Legacy pack is attempting to use DDS textures, skipping!"); + if (file_format == CustomFileFormat::DDS && skip_mipmap) { + LOG_ERROR(Render, "Mipmap skip is incompatible with DDS textures, skipping!"); return false; } texture->file_format = file_format; @@ -176,10 +169,14 @@ bool CustomTexManager::ParseFilename(const FileUtil::FSTEntry& file, CustomTextu return true; } -void CustomTexManager::WriteConfig() { - const u64 program_id = system.Kernel().GetCurrentProcess()->codeset->program_id; +void CustomTexManager::PrepareDumping(u64 title_id) { + // If a pack exists in the load folder that uses the old hash + // dump textures using the old hash. + ReadConfig(title_id, true); + + // Write template config file const std::string dump_path = - fmt::format("{}textures/{:016X}/", GetUserPath(FileUtil::UserPath::DumpDir), program_id); + fmt::format("{}textures/{:016X}/", GetUserPath(FileUtil::UserPath::DumpDir), title_id); const std::string pack_config = dump_path + "pack.json"; if (FileUtil::Exists(pack_config)) { return; @@ -307,18 +304,23 @@ bool CustomTexManager::Decode(Material* material, std::function&& upload return false; } -void CustomTexManager::ReadConfig(const std::string& load_path) { +bool CustomTexManager::ReadConfig(u64 title_id, bool options_only) { + const std::string load_path = + fmt::format("{}textures/{:016X}/", GetUserPath(FileUtil::UserPath::LoadDir), title_id); + if (!FileUtil::Exists(load_path)) { + FileUtil::CreateFullPath(load_path); + } + const std::string config_path = load_path + "pack.json"; FileUtil::IOFile config_file{config_path, "r"}; if (!config_file.IsOpen()) { LOG_INFO(Render, "Unable to find pack config file, using legacy defaults"); - refuse_dds = true; - return; + return false; } std::string config(config_file.GetSize(), '\0'); const std::size_t read_size = config_file.ReadBytes(config.data(), config.size()); if (!read_size) { - return; + return false; } nlohmann::json json = nlohmann::json::parse(config, nullptr, false, true); @@ -327,7 +329,10 @@ void CustomTexManager::ReadConfig(const std::string& load_path) { skip_mipmap = options["skip_mipmap"].get(); flip_png_files = options["flip_png_files"].get(); use_new_hash = options["use_new_hash"].get(); - refuse_dds = skip_mipmap || !use_new_hash; + + if (options_only) { + return true; + } const auto& textures = json["textures"]; for (const auto& material : textures.items()) { @@ -355,6 +360,21 @@ void CustomTexManager::ReadConfig(const std::string& load_path) { LOG_ERROR(Render, "Material with key {} is invalid", material.key()); } } + return true; +} + +std::vector CustomTexManager::GetTextures(u64 title_id) { + const std::string load_path = + fmt::format("{}textures/{:016X}/", GetUserPath(FileUtil::UserPath::LoadDir), title_id); + if (!FileUtil::Exists(load_path)) { + FileUtil::CreateFullPath(load_path); + } + + FileUtil::FSTEntry texture_dir; + std::vector textures; + FileUtil::ScanDirectoryTree(load_path, texture_dir, 64); + FileUtil::GetAllFilesFromNestedEntries(texture_dir, textures); + return textures; } void CustomTexManager::CreateWorkers() { diff --git a/src/video_core/custom_textures/custom_tex_manager.h b/src/video_core/custom_textures/custom_tex_manager.h index 1e7a0d4d8c..ba8a6b5dde 100644 --- a/src/video_core/custom_textures/custom_tex_manager.h +++ b/src/video_core/custom_textures/custom_tex_manager.h @@ -40,8 +40,11 @@ public: /// Searches the load directory assigned to program_id for any custom textures and loads them void FindCustomTextures(); + /// Reads the pack configuration file + bool ReadConfig(u64 title_id, bool options_only = false); + /// Saves the pack configuration file template to the dump directory if it doesn't exist. - void WriteConfig(); + void PrepareDumping(u64 title_id); /// Preloads all registered custom textures void PreloadTextures(const std::atomic_bool& stop_run, @@ -70,8 +73,8 @@ private: /// Parses the custom texture filename (hash, material type, etc). bool ParseFilename(const FileUtil::FSTEntry& file, CustomTexture* texture); - /// Reads the pack configuration file - void ReadConfig(const std::string& load_path); + /// Returns a vector of all custom texture files. + std::vector GetTextures(u64 title_id); /// Creates the thread workers. void CreateWorkers(); @@ -87,10 +90,9 @@ private: std::unique_ptr workers; bool textures_loaded{false}; bool async_custom_loading{true}; - bool skip_mipmap{true}; + bool skip_mipmap{false}; bool flip_png_files{true}; - bool use_new_hash{false}; - bool refuse_dds{false}; + bool use_new_hash{true}; }; } // namespace VideoCore diff --git a/src/video_core/rasterizer_cache/rasterizer_cache.h b/src/video_core/rasterizer_cache/rasterizer_cache.h index 8eda922753..82de7c9bff 100644 --- a/src/video_core/rasterizer_cache/rasterizer_cache.h +++ b/src/video_core/rasterizer_cache/rasterizer_cache.h @@ -993,7 +993,7 @@ void RasterizerCache::UploadSurface(Surface& surface, SurfaceInterval interva runtime.NeedsConversion(surface.pixel_format)); if (dump_textures && False(surface.flags & SurfaceFlagBits::Custom)) { - const u64 hash = Common::ComputeHash64(upload_data.data(), upload_data.size()); + const u64 hash = ComputeHash(load_info, upload_data); const u32 level = surface.LevelOf(load_info.addr); custom_tex_manager.DumpTexture(load_info, level, upload_data, hash); } @@ -1007,6 +1007,20 @@ void RasterizerCache::UploadSurface(Surface& surface, SurfaceInterval interva surface.Upload(upload, staging); } +template +u64 RasterizerCache::ComputeHash(const SurfaceParams& load_info, std::span upload_data) { + if (!custom_tex_manager.UseNewHash()) { + const u32 width = load_info.width; + const u32 height = load_info.height; + const u32 bpp = GetFormatBytesPerPixel(load_info.pixel_format); + auto decoded = std::vector(width * height * bpp); + DecodeTexture(load_info, load_info.addr, load_info.end, upload_data, decoded, false); + return Common::ComputeHash64(decoded.data(), decoded.size()); + } else { + return Common::ComputeHash64(upload_data.data(), upload_data.size()); + } +} + template bool RasterizerCache::UploadCustomSurface(SurfaceId surface_id, SurfaceInterval interval) { MICROPROFILE_SCOPE(RasterizerCache_UploadSurface); @@ -1021,18 +1035,7 @@ bool RasterizerCache::UploadCustomSurface(SurfaceId surface_id, SurfaceInterv } const auto upload_data = source_ptr.GetWriteBytes(load_info.end - load_info.addr); - const u64 hash = [&] { - if (!custom_tex_manager.UseNewHash()) { - const u32 width = load_info.width; - const u32 height = load_info.height; - const u32 bpp = surface.GetInternalBytesPerPixel(); - auto decoded = std::vector(width * height * bpp); - DecodeTexture(load_info, load_info.addr, load_info.end, upload_data, decoded, false); - return Common::ComputeHash64(decoded.data(), decoded.size()); - } else { - return Common::ComputeHash64(upload_data.data(), upload_data.size()); - } - }(); + const u64 hash = ComputeHash(load_info, upload_data); const u32 level = surface.LevelOf(load_info.addr); Material* material = custom_tex_manager.GetMaterial(hash); diff --git a/src/video_core/rasterizer_cache/rasterizer_cache_base.h b/src/video_core/rasterizer_cache/rasterizer_cache_base.h index acb8f52ab5..daed5f2532 100644 --- a/src/video_core/rasterizer_cache/rasterizer_cache_base.h +++ b/src/video_core/rasterizer_cache/rasterizer_cache_base.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -167,6 +168,9 @@ private: /// Transfers ownership of a memory region from src_surface to dest_surface void DuplicateSurface(SurfaceId src_id, SurfaceId dst_id); + /// Computes the hash of the provided texture data. + u64 ComputeHash(const SurfaceParams& load_info, std::span upload_data); + /// Update surface's texture for given region when necessary void ValidateSurface(SurfaceId surface, PAddr addr, u32 size);