custom_tex_manager: Allow multiple hash mappings per texture
This commit is contained in:
@@ -112,11 +112,14 @@ void CustomTexManager::FindCustomTextures() {
|
||||
if (!ParseFilename(file, texture)) {
|
||||
continue;
|
||||
}
|
||||
auto& material = material_map[texture->hash];
|
||||
if (!material) {
|
||||
material = std::make_unique<Material>();
|
||||
for (const u64 hash : texture->hashes) {
|
||||
auto& material = material_map[hash];
|
||||
if (!material) {
|
||||
material = std::make_unique<Material>();
|
||||
}
|
||||
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<u64>& 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<bool>();
|
||||
@@ -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()) {
|
||||
|
@@ -79,7 +79,7 @@ private:
|
||||
Frontend::ImageInterface& image_interface;
|
||||
std::unordered_set<u64> dumped_textures;
|
||||
std::unordered_map<u64, std::unique_ptr<Material>> material_map;
|
||||
std::unordered_map<std::string, u64> path_to_hash_map;
|
||||
std::unordered_map<std::string, std::vector<u64>> path_to_hash_map;
|
||||
std::vector<std::unique_ptr<CustomTexture>> custom_textures;
|
||||
std::list<AsyncUpload> async_uploads;
|
||||
std::unique_ptr<Common::ThreadWorker> workers;
|
||||
|
@@ -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<u8> 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;
|
||||
|
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -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<u64> hashes;
|
||||
std::mutex decode_mutex;
|
||||
CustomPixelFormat format;
|
||||
CustomFileFormat file_format;
|
||||
std::vector<u8> data;
|
||||
@@ -67,6 +69,7 @@ struct Material {
|
||||
u32 width;
|
||||
u32 height;
|
||||
u64 size;
|
||||
u64 hash;
|
||||
CustomPixelFormat format;
|
||||
std::array<CustomTexture*, MAX_MAPS> textures;
|
||||
std::atomic<DecodeState> state{};
|
||||
|
@@ -2,12 +2,15 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#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"
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user