mirror of
https://git.citron-emu.org/citron/emulator
synced 2026-01-30 22:43:28 +00:00
feat(video-core): add texture component type caching and serialization
Implement texture component type conversion and caching in shader environments, with full serialization support for shader cache. - Add ConvertSamplerComponentType using std::bitset for component tracking - Implement ReadTextureComponentType for Graphics/Compute/File environments - Add texture_component_types cache to all environment classes - Update Serialize/Deserialize to include component types - Cache component types alongside texture types for performance Co-Authored-By: ForrestMarkX <forrestmarkx@outlook.com> Signed-off-by: Zephyron <zephyron@citron-emu.org>
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <bitset>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
@@ -68,6 +70,58 @@ static Shader::TexturePixelFormat ConvertTexturePixelFormat(const Tegra::Texture
|
||||
entry.a_type, entry.srgb_conversion));
|
||||
}
|
||||
|
||||
static Shader::SamplerComponentType ConvertSamplerComponentType(
|
||||
const Tegra::Texture::TICEntry& entry) {
|
||||
const auto pixel_format = PixelFormatFromTextureInfo(entry.format, entry.r_type, entry.g_type,
|
||||
entry.b_type, entry.a_type,
|
||||
entry.srgb_conversion);
|
||||
const auto surface_type = VideoCore::Surface::GetFormatType(pixel_format);
|
||||
if (entry.depth_texture != 0 || surface_type == VideoCore::Surface::SurfaceType::Depth) {
|
||||
return Shader::SamplerComponentType::Depth;
|
||||
}
|
||||
if (surface_type == VideoCore::Surface::SurfaceType::Stencil) {
|
||||
return Shader::SamplerComponentType::Stencil;
|
||||
}
|
||||
if (surface_type == VideoCore::Surface::SurfaceType::DepthStencil) {
|
||||
return entry.depth_texture != 0 ? Shader::SamplerComponentType::Depth
|
||||
: Shader::SamplerComponentType::Stencil;
|
||||
}
|
||||
|
||||
// Use std::bitset for cleaner tracking of component types
|
||||
std::bitset<2> component_flags{}; // [0]=has_signed, [1]=has_unsigned
|
||||
const auto accumulate = [&component_flags](const Tegra::Texture::ComponentType component) {
|
||||
switch (component) {
|
||||
case Tegra::Texture::ComponentType::SINT:
|
||||
component_flags.set(0);
|
||||
break;
|
||||
case Tegra::Texture::ComponentType::UINT:
|
||||
component_flags.set(1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
accumulate(entry.r_type);
|
||||
accumulate(entry.g_type);
|
||||
accumulate(entry.b_type);
|
||||
accumulate(entry.a_type);
|
||||
|
||||
if (component_flags[0] && !component_flags[1]) {
|
||||
return Shader::SamplerComponentType::Sint;
|
||||
}
|
||||
if (component_flags[1] && !component_flags[0]) {
|
||||
return Shader::SamplerComponentType::Uint;
|
||||
}
|
||||
if (component_flags[0]) {
|
||||
return Shader::SamplerComponentType::Sint;
|
||||
}
|
||||
if (component_flags[1]) {
|
||||
return Shader::SamplerComponentType::Uint;
|
||||
}
|
||||
return Shader::SamplerComponentType::Float;
|
||||
}
|
||||
|
||||
static std::string_view StageToPrefix(Shader::Stage stage) {
|
||||
switch (stage) {
|
||||
case Shader::Stage::VertexB:
|
||||
@@ -198,6 +252,7 @@ void GenericEnvironment::Serialize(std::ofstream& file) const {
|
||||
const u64 code_size{static_cast<u64>(CachedSizeBytes())};
|
||||
const u64 num_texture_types{static_cast<u64>(texture_types.size())};
|
||||
const u64 num_texture_pixel_formats{static_cast<u64>(texture_pixel_formats.size())};
|
||||
const u64 num_texture_component_types{static_cast<u64>(texture_component_types.size())};
|
||||
const u64 num_cbuf_values{static_cast<u64>(cbuf_values.size())};
|
||||
const u64 num_cbuf_replacement_values{static_cast<u64>(cbuf_replacements.size())};
|
||||
|
||||
@@ -205,6 +260,8 @@ void GenericEnvironment::Serialize(std::ofstream& file) const {
|
||||
.write(reinterpret_cast<const char*>(&num_texture_types), sizeof(num_texture_types))
|
||||
.write(reinterpret_cast<const char*>(&num_texture_pixel_formats),
|
||||
sizeof(num_texture_pixel_formats))
|
||||
.write(reinterpret_cast<const char*>(&num_texture_component_types),
|
||||
sizeof(num_texture_component_types))
|
||||
.write(reinterpret_cast<const char*>(&num_cbuf_values), sizeof(num_cbuf_values))
|
||||
.write(reinterpret_cast<const char*>(&num_cbuf_replacement_values),
|
||||
sizeof(num_cbuf_replacement_values))
|
||||
@@ -221,6 +278,10 @@ void GenericEnvironment::Serialize(std::ofstream& file) const {
|
||||
file.write(reinterpret_cast<const char*>(&key), sizeof(key))
|
||||
.write(reinterpret_cast<const char*>(&type), sizeof(type));
|
||||
}
|
||||
for (const auto& [key, component] : texture_component_types) {
|
||||
file.write(reinterpret_cast<const char*>(&key), sizeof(key))
|
||||
.write(reinterpret_cast<const char*>(&component), sizeof(component));
|
||||
}
|
||||
for (const auto& [key, format] : texture_pixel_formats) {
|
||||
file.write(reinterpret_cast<const char*>(&key), sizeof(key))
|
||||
.write(reinterpret_cast<const char*>(&format), sizeof(format));
|
||||
@@ -405,12 +466,31 @@ std::optional<Shader::ReplaceConstant> GraphicsEnvironment::GetReplaceConstBuffe
|
||||
}
|
||||
|
||||
Shader::TextureType GraphicsEnvironment::ReadTextureType(u32 handle) {
|
||||
const auto it{texture_types.find(handle)};
|
||||
if (it != texture_types.end()) {
|
||||
return it->second;
|
||||
}
|
||||
const auto& regs{maxwell3d->regs};
|
||||
const bool via_header_index{regs.sampler_binding == Maxwell::SamplerBinding::ViaHeaderBinding};
|
||||
auto entry =
|
||||
ReadTextureInfo(regs.tex_header.Address(), regs.tex_header.limit, via_header_index, handle);
|
||||
const Shader::TextureType result{ConvertTextureType(entry)};
|
||||
texture_types.emplace(handle, result);
|
||||
texture_component_types.emplace(handle, ConvertSamplerComponentType(entry));
|
||||
return result;
|
||||
}
|
||||
|
||||
Shader::SamplerComponentType GraphicsEnvironment::ReadTextureComponentType(u32 handle) {
|
||||
const auto it{texture_component_types.find(handle)};
|
||||
if (it != texture_component_types.end()) {
|
||||
return it->second;
|
||||
}
|
||||
const auto& regs{maxwell3d->regs};
|
||||
const bool via_header_index{regs.sampler_binding == Maxwell::SamplerBinding::ViaHeaderBinding};
|
||||
auto entry =
|
||||
ReadTextureInfo(regs.tex_header.Address(), regs.tex_header.limit, via_header_index, handle);
|
||||
const Shader::SamplerComponentType result{ConvertSamplerComponentType(entry)};
|
||||
texture_component_types.emplace(handle, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -462,11 +542,29 @@ u32 ComputeEnvironment::ReadCbufValue(u32 cbuf_index, u32 cbuf_offset) {
|
||||
}
|
||||
|
||||
Shader::TextureType ComputeEnvironment::ReadTextureType(u32 handle) {
|
||||
const auto it{texture_types.find(handle)};
|
||||
if (it != texture_types.end()) {
|
||||
return it->second;
|
||||
}
|
||||
const auto& regs{kepler_compute->regs};
|
||||
const auto& qmd{kepler_compute->launch_description};
|
||||
auto entry = ReadTextureInfo(regs.tic.Address(), regs.tic.limit, qmd.linked_tsc != 0, handle);
|
||||
const Shader::TextureType result{ConvertTextureType(entry)};
|
||||
texture_types.emplace(handle, result);
|
||||
texture_component_types.emplace(handle, ConvertSamplerComponentType(entry));
|
||||
return result;
|
||||
}
|
||||
|
||||
Shader::SamplerComponentType ComputeEnvironment::ReadTextureComponentType(u32 handle) {
|
||||
const auto it{texture_component_types.find(handle)};
|
||||
if (it != texture_component_types.end()) {
|
||||
return it->second;
|
||||
}
|
||||
const auto& regs{kepler_compute->regs};
|
||||
const auto& qmd{kepler_compute->launch_description};
|
||||
auto entry = ReadTextureInfo(regs.tic.Address(), regs.tic.limit, qmd.linked_tsc != 0, handle);
|
||||
const Shader::SamplerComponentType result{ConvertSamplerComponentType(entry)};
|
||||
texture_component_types.emplace(handle, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -492,12 +590,15 @@ void FileEnvironment::Deserialize(std::ifstream& file) {
|
||||
u64 code_size{};
|
||||
u64 num_texture_types{};
|
||||
u64 num_texture_pixel_formats{};
|
||||
u64 num_texture_component_types{};
|
||||
u64 num_cbuf_values{};
|
||||
u64 num_cbuf_replacement_values{};
|
||||
file.read(reinterpret_cast<char*>(&code_size), sizeof(code_size))
|
||||
.read(reinterpret_cast<char*>(&num_texture_types), sizeof(num_texture_types))
|
||||
.read(reinterpret_cast<char*>(&num_texture_pixel_formats),
|
||||
sizeof(num_texture_pixel_formats))
|
||||
.read(reinterpret_cast<char*>(&num_texture_component_types),
|
||||
sizeof(num_texture_component_types))
|
||||
.read(reinterpret_cast<char*>(&num_cbuf_values), sizeof(num_cbuf_values))
|
||||
.read(reinterpret_cast<char*>(&num_cbuf_replacement_values),
|
||||
sizeof(num_cbuf_replacement_values))
|
||||
@@ -517,6 +618,13 @@ void FileEnvironment::Deserialize(std::ifstream& file) {
|
||||
.read(reinterpret_cast<char*>(&type), sizeof(type));
|
||||
texture_types.emplace(key, type);
|
||||
}
|
||||
for (size_t i = 0; i < num_texture_component_types; ++i) {
|
||||
u32 key;
|
||||
Shader::SamplerComponentType component;
|
||||
file.read(reinterpret_cast<char*>(&key), sizeof(key))
|
||||
.read(reinterpret_cast<char*>(&component), sizeof(component));
|
||||
texture_component_types.emplace(key, component);
|
||||
}
|
||||
for (size_t i = 0; i < num_texture_pixel_formats; ++i) {
|
||||
u32 key;
|
||||
Shader::TexturePixelFormat format;
|
||||
@@ -579,6 +687,15 @@ Shader::TextureType FileEnvironment::ReadTextureType(u32 handle) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
Shader::SamplerComponentType FileEnvironment::ReadTextureComponentType(u32 handle) {
|
||||
const auto it{texture_component_types.find(handle)};
|
||||
if (it == texture_component_types.end()) {
|
||||
LOG_WARNING(Render_Vulkan, "Texture component descriptor {:08x} not found", handle);
|
||||
return Shader::SamplerComponentType::Float;
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
Shader::TexturePixelFormat FileEnvironment::ReadTexturePixelFormat(u32 handle) {
|
||||
const auto it{texture_pixel_formats.find(handle)};
|
||||
if (it == texture_pixel_formats.end()) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 citron Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
@@ -77,6 +78,7 @@ protected:
|
||||
|
||||
std::vector<u64> code;
|
||||
std::unordered_map<u32, Shader::TextureType> texture_types;
|
||||
std::unordered_map<u32, Shader::SamplerComponentType> texture_component_types;
|
||||
std::unordered_map<u32, Shader::TexturePixelFormat> texture_pixel_formats;
|
||||
std::unordered_map<u64, u32> cbuf_values;
|
||||
std::unordered_map<u64, Shader::ReplaceConstant> cbuf_replacements;
|
||||
@@ -113,6 +115,8 @@ public:
|
||||
|
||||
Shader::TextureType ReadTextureType(u32 handle) override;
|
||||
|
||||
Shader::SamplerComponentType ReadTextureComponentType(u32 handle) override;
|
||||
|
||||
Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override;
|
||||
|
||||
bool IsTexturePixelFormatInteger(u32 handle) override;
|
||||
@@ -139,6 +143,8 @@ public:
|
||||
|
||||
Shader::TextureType ReadTextureType(u32 handle) override;
|
||||
|
||||
Shader::SamplerComponentType ReadTextureComponentType(u32 handle) override;
|
||||
|
||||
Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override;
|
||||
|
||||
bool IsTexturePixelFormatInteger(u32 handle) override;
|
||||
@@ -173,6 +179,8 @@ public:
|
||||
|
||||
[[nodiscard]] Shader::TextureType ReadTextureType(u32 handle) override;
|
||||
|
||||
[[nodiscard]] Shader::SamplerComponentType ReadTextureComponentType(u32 handle) override;
|
||||
|
||||
[[nodiscard]] Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override;
|
||||
|
||||
[[nodiscard]] bool IsTexturePixelFormatInteger(u32 handle) override;
|
||||
@@ -199,6 +207,7 @@ public:
|
||||
private:
|
||||
std::vector<u64> code;
|
||||
std::unordered_map<u32, Shader::TextureType> texture_types;
|
||||
std::unordered_map<u32, Shader::SamplerComponentType> texture_component_types;
|
||||
std::unordered_map<u32, Shader::TexturePixelFormat> texture_pixel_formats;
|
||||
std::unordered_map<u64, u32> cbuf_values;
|
||||
std::unordered_map<u64, Shader::ReplaceConstant> cbuf_replacements;
|
||||
|
||||
Reference in New Issue
Block a user