From f5668cdb25fee554d20d4fb979f8357b6f29ce09 Mon Sep 17 00:00:00 2001 From: GPUCode Date: Mon, 1 May 2023 14:08:01 +0300 Subject: [PATCH] custom_tex_manager: Allow multiple hash mappings per texture --- .../custom_textures/custom_tex_manager.cpp | 57 ++++++++++--------- .../custom_textures/custom_tex_manager.h | 2 +- src/video_core/custom_textures/material.cpp | 11 ++-- src/video_core/custom_textures/material.h | 7 ++- .../rasterizer_cache/rasterizer_cache.h | 3 + .../renderer_opengl/gl_texture_runtime.cpp | 2 +- .../renderer_opengl/gl_texture_runtime.h | 2 +- 7 files changed, 47 insertions(+), 37 deletions(-) diff --git a/src/video_core/custom_textures/custom_tex_manager.cpp b/src/video_core/custom_textures/custom_tex_manager.cpp index 381cb180e..f7d884a1d 100644 --- a/src/video_core/custom_textures/custom_tex_manager.cpp +++ b/src/video_core/custom_textures/custom_tex_manager.cpp @@ -112,11 +112,14 @@ void CustomTexManager::FindCustomTextures() { if (!ParseFilename(file, texture)) { continue; } - auto& material = material_map[texture->hash]; - if (!material) { - material = std::make_unique(); + for (const u64 hash : texture->hashes) { + auto& material = material_map[hash]; + if (!material) { + material = std::make_unique(); + } + material->hash = hash; + material->AddMapTexture(texture); } - material->AddMapTexture(texture); } textures_loaded = true; } @@ -146,21 +149,25 @@ bool CustomTexManager::ParseFilename(const FileUtil::FSTEntry& file, CustomTextu parts.pop_back(); } - // First check if the path is mapped directly to a hash - // before trying to parse the texture filename. + // First look if this file is mapped to any number of hashes. + std::vector& hashes = texture->hashes; const auto it = path_to_hash_map.find(file.virtualName); if (it != path_to_hash_map.end()) { - texture->hash = it->second; - } else { - u32 width; - u32 height; - u32 format; - unsigned long long hash{}; - if (std::sscanf(parts.back().c_str(), "tex1_%ux%u_%llX_%u", &width, &height, &hash, - &format) != 4) { - return false; - } - texture->hash = hash; + hashes = it->second; + } + + // It's also possible for pack creators to retain the default texture name + // still map the texture to another hash. Support that as well. + u32 width; + u32 height; + u32 format; + unsigned long long hash{}; + const bool is_parsed = std::sscanf(parts.back().c_str(), "tex1_%ux%u_%llX_%u", &width, &height, + &hash, &format) == 4; + const bool is_mapped = + !hashes.empty() && std::find(hashes.begin(), hashes.end(), hash) != hashes.end(); + if (is_parsed && !is_mapped) { + hashes.push_back(hash); } texture->path = file.physicalName; @@ -182,9 +189,9 @@ void CustomTexManager::WriteConfig() { json["description"] = "A graphics pack"; auto& options = json["options"]; - options["skip_mipmap"] = skip_mipmap; - options["flip_png_files"] = flip_png_files; - options["use_new_hash"] = use_new_hash; + options["skip_mipmap"] = false; + options["flip_png_files"] = true; + options["use_new_hash"] = true; FileUtil::IOFile file{pack_config, "w"}; const std::string output = json.dump(4); @@ -303,7 +310,7 @@ void CustomTexManager::ReadConfig(const std::string& load_path) { return; } - nlohmann::json json = nlohmann::json::parse(config); + nlohmann::json json = nlohmann::json::parse(config, nullptr, false, true); const auto& options = json["options"]; skip_mipmap = options["skip_mipmap"].get(); @@ -322,13 +329,7 @@ void CustomTexManager::ReadConfig(const std::string& load_path) { const auto parse = [&](const std::string& file) { const std::string filename{FileUtil::GetFilename(file)}; auto [it, new_hash] = path_to_hash_map.try_emplace(filename); - if (!new_hash) { - LOG_ERROR(Render, - "File {} with key {} already exists and is mapped to {:#016X}, skipping", - file, material.key(), path_to_hash_map[filename]); - return; - } - it->second = hash; + it->second.push_back(hash); }; const auto value = material.value(); if (value.is_string()) { diff --git a/src/video_core/custom_textures/custom_tex_manager.h b/src/video_core/custom_textures/custom_tex_manager.h index caee66a1f..27a24b28f 100644 --- a/src/video_core/custom_textures/custom_tex_manager.h +++ b/src/video_core/custom_textures/custom_tex_manager.h @@ -79,7 +79,7 @@ private: Frontend::ImageInterface& image_interface; std::unordered_set dumped_textures; std::unordered_map> material_map; - std::unordered_map path_to_hash_map; + std::unordered_map> path_to_hash_map; std::vector> custom_textures; std::list async_uploads; std::unique_ptr workers; diff --git a/src/video_core/custom_textures/material.cpp b/src/video_core/custom_textures/material.cpp index 9d76c20e7..d7bee5da4 100644 --- a/src/video_core/custom_textures/material.cpp +++ b/src/video_core/custom_textures/material.cpp @@ -55,6 +55,11 @@ CustomTexture::CustomTexture(Frontend::ImageInterface& image_interface_) CustomTexture::~CustomTexture() = default; void CustomTexture::LoadFromDisk(bool flip_png) { + std::scoped_lock lock{decode_mutex}; + if (IsLoaded()) { + return; + } + FileUtil::IOFile file{path, "rb"}; std::vector input(file.GetSize()); if (file.ReadBytes(input.data(), input.size()) != input.size()) { @@ -71,7 +76,6 @@ void CustomTexture::LoadFromDisk(bool flip_png) { break; default: LOG_ERROR(Render, "Unknown file format {}", file_format); - return; } } @@ -102,8 +106,7 @@ void Material::LoadFromDisk(bool flip_png) noexcept { } texture->LoadFromDisk(flip_png); size += texture->data.size(); - LOG_DEBUG(Render, "Loading {} map {} with hash {:#016X}", MapTypeName(texture->type), - texture->path, texture->hash); + LOG_DEBUG(Render, "Loading {} map {}", MapTypeName(texture->type), texture->path); } if (!textures[0]) { LOG_ERROR(Render, "Unable to create material without color texture!"); @@ -121,7 +124,7 @@ void Material::LoadFromDisk(bool flip_png) noexcept { LOG_ERROR(Render, "{} map {} of material with hash {:#016X} has dimentions {}x{} " "which do not match the color texture dimentions {}x{}", - MapTypeName(texture->type), texture->path, texture->hash, texture->width, + MapTypeName(texture->type), texture->path, hash, texture->width, texture->height, width, height); state = DecodeState::Failed; return; diff --git a/src/video_core/custom_textures/material.h b/src/video_core/custom_textures/material.h index 6c43695d0..69d6a838c 100644 --- a/src/video_core/custom_textures/material.h +++ b/src/video_core/custom_textures/material.h @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -39,7 +40,7 @@ public: void LoadFromDisk(bool flip_png); [[nodiscard]] bool IsParsed() const noexcept { - return file_format != CustomFileFormat::None && hash != 0; + return file_format != CustomFileFormat::None && !hashes.empty(); } [[nodiscard]] bool IsLoaded() const noexcept { @@ -56,7 +57,8 @@ public: std::string path; u32 width; u32 height; - u64 hash; + std::vector hashes; + std::mutex decode_mutex; CustomPixelFormat format; CustomFileFormat file_format; std::vector data; @@ -67,6 +69,7 @@ struct Material { u32 width; u32 height; u64 size; + u64 hash; CustomPixelFormat format; std::array textures; std::atomic state{}; diff --git a/src/video_core/rasterizer_cache/rasterizer_cache.h b/src/video_core/rasterizer_cache/rasterizer_cache.h index c37aac79d..316678bdf 100644 --- a/src/video_core/rasterizer_cache/rasterizer_cache.h +++ b/src/video_core/rasterizer_cache/rasterizer_cache.h @@ -2,12 +2,15 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#pragma once + #include #include #include #include "common/alignment.h" #include "common/logging/log.h" #include "common/microprofile.h" +#include "common/settings.h" #include "core/memory.h" #include "video_core/custom_textures/custom_tex_manager.h" #include "video_core/rasterizer_cache/rasterizer_cache_base.h" diff --git a/src/video_core/renderer_opengl/gl_texture_runtime.cpp b/src/video_core/renderer_opengl/gl_texture_runtime.cpp index f69528854..fe2c19070 100644 --- a/src/video_core/renderer_opengl/gl_texture_runtime.cpp +++ b/src/video_core/renderer_opengl/gl_texture_runtime.cpp @@ -674,7 +674,7 @@ Framebuffer::Framebuffer(TextureRuntime& runtime, const Surface* color, u32 colo Framebuffer::~Framebuffer() = default; -Sampler::Sampler(TextureRuntime& runtime, VideoCore::SamplerParams params) { +Sampler::Sampler(TextureRuntime&, VideoCore::SamplerParams params) { const GLenum mag_filter = PicaToGL::TextureMagFilterMode(params.mag_filter); const GLenum min_filter = PicaToGL::TextureMinFilterMode(params.min_filter, params.mip_filter); const GLenum wrap_s = PicaToGL::WrapMode(params.wrap_s); diff --git a/src/video_core/renderer_opengl/gl_texture_runtime.h b/src/video_core/renderer_opengl/gl_texture_runtime.h index bfe78e2b9..aab561f8a 100644 --- a/src/video_core/renderer_opengl/gl_texture_runtime.h +++ b/src/video_core/renderer_opengl/gl_texture_runtime.h @@ -213,7 +213,7 @@ private: class Sampler { public: - explicit Sampler(TextureRuntime& runtime, VideoCore::SamplerParams params); + explicit Sampler(TextureRuntime&, VideoCore::SamplerParams params); ~Sampler(); Sampler(const Sampler&) = delete;