citra/src/video_core/custom_textures/material.cpp

155 lines
4.7 KiB
C++
Raw Normal View History

Custom textures rewrite (#6452) * common: Add thread pool from yuzu * Is really useful for asynchronous operations like shader compilation and custom textures, will be used in following PRs * core: Improve ImageInterface * Provide a default implementation so frontends don't have to duplicate code registering the lodepng version * Add a dds version too which we will use in the next commit * rasterizer_cache: Rewrite custom textures * There's just too much to talk about here, look at the PR description for more details * rasterizer_cache: Implement basic pack configuration file * custom_tex_manager: Flip dumped textures * custom_tex_manager: Optimize custom texture hashing * If no convertions are needed then we can hash the decoded data directly removing the needed for duplicate decode * custom_tex_manager: Implement asynchronous texture loading * The file loading and decoding is offloaded into worker threads, while the upload itself still occurs in the main thread to avoid having to manage shared contexts * Address review comments * custom_tex_manager: Introduce custom material support * video_core: Move custom textures to separate directory * Also split the files to make the code cleaner * gl_texture_runtime: Generate mipmaps for material * custom_tex_manager: Prevent memory overflow when preloading * externals: Add dds-ktx as submodule * string_util: Return vector from SplitString * No code benefits from passing it as an argument * custom_textures: Use json config file * gl_rasterizer: Only bind material for unit 0 * Address review comments
2023-04-27 06:38:28 +02:00
// Copyright 2023 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/texture.h"
#include "core/frontend/image_interface.h"
#include "video_core/custom_textures/material.h"
namespace VideoCore {
namespace {
CustomPixelFormat ToCustomPixelFormat(ddsktx_format format) {
switch (format) {
case DDSKTX_FORMAT_RGBA8:
return CustomPixelFormat::RGBA8;
case DDSKTX_FORMAT_BC1:
return CustomPixelFormat::BC1;
case DDSKTX_FORMAT_BC3:
return CustomPixelFormat::BC3;
case DDSKTX_FORMAT_BC5:
return CustomPixelFormat::BC5;
case DDSKTX_FORMAT_BC7:
return CustomPixelFormat::BC7;
case DDSKTX_FORMAT_ASTC4x4:
return CustomPixelFormat::ASTC4;
case DDSKTX_FORMAT_ASTC6x6:
return CustomPixelFormat::ASTC6;
case DDSKTX_FORMAT_ASTC8x6:
return CustomPixelFormat::ASTC8;
default:
LOG_ERROR(Common, "Unknown dds/ktx pixel format {}", format);
return CustomPixelFormat::RGBA8;
}
}
std::string_view MapTypeName(MapType type) {
switch (type) {
case MapType::Color:
return "Color";
case MapType::Normal:
return "Normal";
default:
return "Invalid";
}
}
} // Anonymous namespace
CustomTexture::CustomTexture(Frontend::ImageInterface& image_interface_)
: image_interface{image_interface_} {}
CustomTexture::~CustomTexture() = default;
void CustomTexture::LoadFromDisk(bool flip_png) {
std::scoped_lock lock{decode_mutex};
if (IsLoaded()) {
return;
}
Custom textures rewrite (#6452) * common: Add thread pool from yuzu * Is really useful for asynchronous operations like shader compilation and custom textures, will be used in following PRs * core: Improve ImageInterface * Provide a default implementation so frontends don't have to duplicate code registering the lodepng version * Add a dds version too which we will use in the next commit * rasterizer_cache: Rewrite custom textures * There's just too much to talk about here, look at the PR description for more details * rasterizer_cache: Implement basic pack configuration file * custom_tex_manager: Flip dumped textures * custom_tex_manager: Optimize custom texture hashing * If no convertions are needed then we can hash the decoded data directly removing the needed for duplicate decode * custom_tex_manager: Implement asynchronous texture loading * The file loading and decoding is offloaded into worker threads, while the upload itself still occurs in the main thread to avoid having to manage shared contexts * Address review comments * custom_tex_manager: Introduce custom material support * video_core: Move custom textures to separate directory * Also split the files to make the code cleaner * gl_texture_runtime: Generate mipmaps for material * custom_tex_manager: Prevent memory overflow when preloading * externals: Add dds-ktx as submodule * string_util: Return vector from SplitString * No code benefits from passing it as an argument * custom_textures: Use json config file * gl_rasterizer: Only bind material for unit 0 * Address review comments
2023-04-27 06:38:28 +02:00
FileUtil::IOFile file{path, "rb"};
std::vector<u8> input(file.GetSize());
if (file.ReadBytes(input.data(), input.size()) != input.size()) {
LOG_CRITICAL(Render, "Failed to open custom texture: {}", path);
return;
}
switch (file_format) {
case CustomFileFormat::PNG:
LoadPNG(input, flip_png);
break;
case CustomFileFormat::DDS:
case CustomFileFormat::KTX:
LoadDDS(input);
break;
default:
LOG_ERROR(Render, "Unknown file format {}", file_format);
}
}
void CustomTexture::LoadPNG(std::span<const u8> input, bool flip_png) {
if (!image_interface.DecodePNG(data, width, height, input)) {
LOG_ERROR(Render, "Failed to decode png: {}", path);
return;
}
if (flip_png) {
Common::FlipRGBA8Texture(data, width, height);
}
format = CustomPixelFormat::RGBA8;
}
void CustomTexture::LoadDDS(std::span<const u8> input) {
ddsktx_format dds_format{};
image_interface.DecodeDDS(data, width, height, dds_format, input);
format = ToCustomPixelFormat(dds_format);
}
void Material::LoadFromDisk(bool flip_png) noexcept {
if (IsDecoded()) {
return;
}
for (CustomTexture* const texture : textures) {
if (!texture || texture->IsLoaded()) {
continue;
}
texture->LoadFromDisk(flip_png);
size += texture->data.size();
LOG_DEBUG(Render, "Loading {} map {}", MapTypeName(texture->type), texture->path);
Custom textures rewrite (#6452) * common: Add thread pool from yuzu * Is really useful for asynchronous operations like shader compilation and custom textures, will be used in following PRs * core: Improve ImageInterface * Provide a default implementation so frontends don't have to duplicate code registering the lodepng version * Add a dds version too which we will use in the next commit * rasterizer_cache: Rewrite custom textures * There's just too much to talk about here, look at the PR description for more details * rasterizer_cache: Implement basic pack configuration file * custom_tex_manager: Flip dumped textures * custom_tex_manager: Optimize custom texture hashing * If no convertions are needed then we can hash the decoded data directly removing the needed for duplicate decode * custom_tex_manager: Implement asynchronous texture loading * The file loading and decoding is offloaded into worker threads, while the upload itself still occurs in the main thread to avoid having to manage shared contexts * Address review comments * custom_tex_manager: Introduce custom material support * video_core: Move custom textures to separate directory * Also split the files to make the code cleaner * gl_texture_runtime: Generate mipmaps for material * custom_tex_manager: Prevent memory overflow when preloading * externals: Add dds-ktx as submodule * string_util: Return vector from SplitString * No code benefits from passing it as an argument * custom_textures: Use json config file * gl_rasterizer: Only bind material for unit 0 * Address review comments
2023-04-27 06:38:28 +02:00
}
if (!textures[0]) {
LOG_ERROR(Render, "Unable to create material without color texture!");
state = DecodeState::Failed;
return;
}
width = textures[0]->width;
height = textures[0]->height;
format = textures[0]->format;
for (const CustomTexture* texture : textures) {
if (!texture) {
continue;
}
if (texture->width != width || texture->height != height) {
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, hash, texture->width,
Custom textures rewrite (#6452) * common: Add thread pool from yuzu * Is really useful for asynchronous operations like shader compilation and custom textures, will be used in following PRs * core: Improve ImageInterface * Provide a default implementation so frontends don't have to duplicate code registering the lodepng version * Add a dds version too which we will use in the next commit * rasterizer_cache: Rewrite custom textures * There's just too much to talk about here, look at the PR description for more details * rasterizer_cache: Implement basic pack configuration file * custom_tex_manager: Flip dumped textures * custom_tex_manager: Optimize custom texture hashing * If no convertions are needed then we can hash the decoded data directly removing the needed for duplicate decode * custom_tex_manager: Implement asynchronous texture loading * The file loading and decoding is offloaded into worker threads, while the upload itself still occurs in the main thread to avoid having to manage shared contexts * Address review comments * custom_tex_manager: Introduce custom material support * video_core: Move custom textures to separate directory * Also split the files to make the code cleaner * gl_texture_runtime: Generate mipmaps for material * custom_tex_manager: Prevent memory overflow when preloading * externals: Add dds-ktx as submodule * string_util: Return vector from SplitString * No code benefits from passing it as an argument * custom_textures: Use json config file * gl_rasterizer: Only bind material for unit 0 * Address review comments
2023-04-27 06:38:28 +02:00
texture->height, width, height);
state = DecodeState::Failed;
return;
}
if (texture->format != format) {
LOG_ERROR(
Render, "{} map {} is stored with {} format which does not match color format {}",
MapTypeName(texture->type), texture->path,
CustomPixelFormatAsString(texture->format), CustomPixelFormatAsString(format));
state = DecodeState::Failed;
return;
}
}
state = DecodeState::Decoded;
}
void Material::AddMapTexture(CustomTexture* texture) noexcept {
const std::size_t index = static_cast<std::size_t>(texture->type);
if (textures[index]) {
LOG_ERROR(Render, "Textures {} and {} are assigned to the same material, ignoring!",
textures[index]->path, texture->path);
return;
}
textures[index] = texture;
}
} // namespace VideoCore