mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	custom_tex_manager: Allow old hash in the dumper (#6832)
This commit is contained in:
		
							parent
							
								
									35e208b447
								
							
						
					
					
						commit
						baf3ea4beb
					
				
					 5 changed files with 73 additions and 44 deletions
				
			
		|  | @ -321,12 +321,12 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st | ||||||
|     cheat_engine = std::make_unique<Cheats::CheatEngine>(title_id, *this); |     cheat_engine = std::make_unique<Cheats::CheatEngine>(title_id, *this); | ||||||
|     perf_stats = std::make_unique<PerfStats>(title_id); |     perf_stats = std::make_unique<PerfStats>(title_id); | ||||||
| 
 | 
 | ||||||
|  |     if (Settings::values.dump_textures) { | ||||||
|  |         custom_tex_manager->PrepareDumping(title_id); | ||||||
|  |     } | ||||||
|     if (Settings::values.custom_textures) { |     if (Settings::values.custom_textures) { | ||||||
|         custom_tex_manager->FindCustomTextures(); |         custom_tex_manager->FindCustomTextures(); | ||||||
|     } |     } | ||||||
|     if (Settings::values.dump_textures) { |  | ||||||
|         custom_tex_manager->WriteConfig(); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     status = ResultStatus::Success; |     status = ResultStatus::Success; | ||||||
|     m_emu_window = &emu_window; |     m_emu_window = &emu_window; | ||||||
|  |  | ||||||
|  | @ -90,19 +90,12 @@ void CustomTexManager::FindCustomTextures() { | ||||||
|         CreateWorkers(); |         CreateWorkers(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const u64 program_id = system.Kernel().GetCurrentProcess()->codeset->program_id; |     const u64 title_id = system.Kernel().GetCurrentProcess()->codeset->program_id; | ||||||
|     const std::string load_path = |     const auto textures = GetTextures(title_id); | ||||||
|         fmt::format("{}textures/{:016X}/", GetUserPath(FileUtil::UserPath::LoadDir), program_id); |     if (!ReadConfig(title_id)) { | ||||||
| 
 |         use_new_hash = false; | ||||||
|     if (!FileUtil::Exists(load_path)) { |         skip_mipmap = true; | ||||||
|         FileUtil::CreateFullPath(load_path); |  | ||||||
|     } |     } | ||||||
|     ReadConfig(load_path); |  | ||||||
| 
 |  | ||||||
|     FileUtil::FSTEntry texture_dir; |  | ||||||
|     std::vector<FileUtil::FSTEntry> textures; |  | ||||||
|     FileUtil::ScanDirectoryTree(load_path, texture_dir, 64); |  | ||||||
|     FileUtil::GetAllFilesFromNestedEntries(texture_dir, textures); |  | ||||||
| 
 | 
 | ||||||
|     custom_textures.reserve(textures.size()); |     custom_textures.reserve(textures.size()); | ||||||
|     for (const FileUtil::FSTEntry& file : textures) { |     for (const FileUtil::FSTEntry& file : textures) { | ||||||
|  | @ -137,8 +130,8 @@ bool CustomTexManager::ParseFilename(const FileUtil::FSTEntry& file, CustomTextu | ||||||
|     if (file_format == CustomFileFormat::None) { |     if (file_format == CustomFileFormat::None) { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|     if (file_format == CustomFileFormat::DDS && refuse_dds) { |     if (file_format == CustomFileFormat::DDS && skip_mipmap) { | ||||||
|         LOG_ERROR(Render, "Legacy pack is attempting to use DDS textures, skipping!"); |         LOG_ERROR(Render, "Mipmap skip is incompatible with DDS textures, skipping!"); | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|     texture->file_format = file_format; |     texture->file_format = file_format; | ||||||
|  | @ -176,10 +169,14 @@ bool CustomTexManager::ParseFilename(const FileUtil::FSTEntry& file, CustomTextu | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void CustomTexManager::WriteConfig() { | void CustomTexManager::PrepareDumping(u64 title_id) { | ||||||
|     const u64 program_id = system.Kernel().GetCurrentProcess()->codeset->program_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 = |     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"; |     const std::string pack_config = dump_path + "pack.json"; | ||||||
|     if (FileUtil::Exists(pack_config)) { |     if (FileUtil::Exists(pack_config)) { | ||||||
|         return; |         return; | ||||||
|  | @ -307,18 +304,23 @@ bool CustomTexManager::Decode(Material* material, std::function<bool()>&& upload | ||||||
|     return false; |     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"; |     const std::string config_path = load_path + "pack.json"; | ||||||
|     FileUtil::IOFile config_file{config_path, "r"}; |     FileUtil::IOFile config_file{config_path, "r"}; | ||||||
|     if (!config_file.IsOpen()) { |     if (!config_file.IsOpen()) { | ||||||
|         LOG_INFO(Render, "Unable to find pack config file, using legacy defaults"); |         LOG_INFO(Render, "Unable to find pack config file, using legacy defaults"); | ||||||
|         refuse_dds = true; |         return false; | ||||||
|         return; |  | ||||||
|     } |     } | ||||||
|     std::string config(config_file.GetSize(), '\0'); |     std::string config(config_file.GetSize(), '\0'); | ||||||
|     const std::size_t read_size = config_file.ReadBytes(config.data(), config.size()); |     const std::size_t read_size = config_file.ReadBytes(config.data(), config.size()); | ||||||
|     if (!read_size) { |     if (!read_size) { | ||||||
|         return; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     nlohmann::json json = nlohmann::json::parse(config, nullptr, false, true); |     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<bool>(); |     skip_mipmap = options["skip_mipmap"].get<bool>(); | ||||||
|     flip_png_files = options["flip_png_files"].get<bool>(); |     flip_png_files = options["flip_png_files"].get<bool>(); | ||||||
|     use_new_hash = options["use_new_hash"].get<bool>(); |     use_new_hash = options["use_new_hash"].get<bool>(); | ||||||
|     refuse_dds = skip_mipmap || !use_new_hash; | 
 | ||||||
|  |     if (options_only) { | ||||||
|  |         return true; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     const auto& textures = json["textures"]; |     const auto& textures = json["textures"]; | ||||||
|     for (const auto& material : textures.items()) { |     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()); |             LOG_ERROR(Render, "Material with key {} is invalid", material.key()); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::vector<FileUtil::FSTEntry> 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<FileUtil::FSTEntry> textures; | ||||||
|  |     FileUtil::ScanDirectoryTree(load_path, texture_dir, 64); | ||||||
|  |     FileUtil::GetAllFilesFromNestedEntries(texture_dir, textures); | ||||||
|  |     return textures; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void CustomTexManager::CreateWorkers() { | void CustomTexManager::CreateWorkers() { | ||||||
|  |  | ||||||
|  | @ -40,8 +40,11 @@ public: | ||||||
|     /// Searches the load directory assigned to program_id for any custom textures and loads them
 |     /// Searches the load directory assigned to program_id for any custom textures and loads them
 | ||||||
|     void FindCustomTextures(); |     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.
 |     /// 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
 |     /// Preloads all registered custom textures
 | ||||||
|     void PreloadTextures(const std::atomic_bool& stop_run, |     void PreloadTextures(const std::atomic_bool& stop_run, | ||||||
|  | @ -70,8 +73,8 @@ private: | ||||||
|     /// Parses the custom texture filename (hash, material type, etc).
 |     /// Parses the custom texture filename (hash, material type, etc).
 | ||||||
|     bool ParseFilename(const FileUtil::FSTEntry& file, CustomTexture* texture); |     bool ParseFilename(const FileUtil::FSTEntry& file, CustomTexture* texture); | ||||||
| 
 | 
 | ||||||
|     /// Reads the pack configuration file
 |     /// Returns a vector of all custom texture files.
 | ||||||
|     void ReadConfig(const std::string& load_path); |     std::vector<FileUtil::FSTEntry> GetTextures(u64 title_id); | ||||||
| 
 | 
 | ||||||
|     /// Creates the thread workers.
 |     /// Creates the thread workers.
 | ||||||
|     void CreateWorkers(); |     void CreateWorkers(); | ||||||
|  | @ -87,10 +90,9 @@ private: | ||||||
|     std::unique_ptr<Common::ThreadWorker> workers; |     std::unique_ptr<Common::ThreadWorker> workers; | ||||||
|     bool textures_loaded{false}; |     bool textures_loaded{false}; | ||||||
|     bool async_custom_loading{true}; |     bool async_custom_loading{true}; | ||||||
|     bool skip_mipmap{true}; |     bool skip_mipmap{false}; | ||||||
|     bool flip_png_files{true}; |     bool flip_png_files{true}; | ||||||
|     bool use_new_hash{false}; |     bool use_new_hash{true}; | ||||||
|     bool refuse_dds{false}; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace VideoCore
 | } // namespace VideoCore
 | ||||||
|  |  | ||||||
|  | @ -993,7 +993,7 @@ void RasterizerCache<T>::UploadSurface(Surface& surface, SurfaceInterval interva | ||||||
|                   runtime.NeedsConversion(surface.pixel_format)); |                   runtime.NeedsConversion(surface.pixel_format)); | ||||||
| 
 | 
 | ||||||
|     if (dump_textures && False(surface.flags & SurfaceFlagBits::Custom)) { |     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); |         const u32 level = surface.LevelOf(load_info.addr); | ||||||
|         custom_tex_manager.DumpTexture(load_info, level, upload_data, hash); |         custom_tex_manager.DumpTexture(load_info, level, upload_data, hash); | ||||||
|     } |     } | ||||||
|  | @ -1007,6 +1007,20 @@ void RasterizerCache<T>::UploadSurface(Surface& surface, SurfaceInterval interva | ||||||
|     surface.Upload(upload, staging); |     surface.Upload(upload, staging); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | template <class T> | ||||||
|  | u64 RasterizerCache<T>::ComputeHash(const SurfaceParams& load_info, std::span<u8> 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<u8>(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 <class T> | template <class T> | ||||||
| bool RasterizerCache<T>::UploadCustomSurface(SurfaceId surface_id, SurfaceInterval interval) { | bool RasterizerCache<T>::UploadCustomSurface(SurfaceId surface_id, SurfaceInterval interval) { | ||||||
|     MICROPROFILE_SCOPE(RasterizerCache_UploadSurface); |     MICROPROFILE_SCOPE(RasterizerCache_UploadSurface); | ||||||
|  | @ -1021,18 +1035,7 @@ bool RasterizerCache<T>::UploadCustomSurface(SurfaceId surface_id, SurfaceInterv | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const auto upload_data = source_ptr.GetWriteBytes(load_info.end - load_info.addr); |     const auto upload_data = source_ptr.GetWriteBytes(load_info.end - load_info.addr); | ||||||
|     const u64 hash = [&] { |     const u64 hash = ComputeHash(load_info, upload_data); | ||||||
|         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<u8>(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 u32 level = surface.LevelOf(load_info.addr); |     const u32 level = surface.LevelOf(load_info.addr); | ||||||
|     Material* material = custom_tex_manager.GetMaterial(hash); |     Material* material = custom_tex_manager.GetMaterial(hash); | ||||||
|  |  | ||||||
|  | @ -7,6 +7,7 @@ | ||||||
| #include <functional> | #include <functional> | ||||||
| #include <list> | #include <list> | ||||||
| #include <optional> | #include <optional> | ||||||
|  | #include <span> | ||||||
| #include <unordered_map> | #include <unordered_map> | ||||||
| #include <vector> | #include <vector> | ||||||
| #include <boost/icl/interval_map.hpp> | #include <boost/icl/interval_map.hpp> | ||||||
|  | @ -167,6 +168,9 @@ private: | ||||||
|     /// Transfers ownership of a memory region from src_surface to dest_surface
 |     /// Transfers ownership of a memory region from src_surface to dest_surface
 | ||||||
|     void DuplicateSurface(SurfaceId src_id, SurfaceId dst_id); |     void DuplicateSurface(SurfaceId src_id, SurfaceId dst_id); | ||||||
| 
 | 
 | ||||||
|  |     /// Computes the hash of the provided texture data.
 | ||||||
|  |     u64 ComputeHash(const SurfaceParams& load_info, std::span<u8> upload_data); | ||||||
|  | 
 | ||||||
|     /// Update surface's texture for given region when necessary
 |     /// Update surface's texture for given region when necessary
 | ||||||
|     void ValidateSurface(SurfaceId surface, PAddr addr, u32 size); |     void ValidateSurface(SurfaceId surface, PAddr addr, u32 size); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue