custom_tex_manager: Allow old hash in the dumper (#6832)

This commit is contained in:
GPUCode 2023-08-01 20:38:51 +03:00 committed by GitHub
parent 35e208b447
commit baf3ea4beb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 73 additions and 44 deletions

View File

@ -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;

View File

@ -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() {

View File

@ -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

View File

@ -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);

View File

@ -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);