From 56edbff4d764c9d29cfaef2fc99d018936af86df Mon Sep 17 00:00:00 2001 From: Zephyron Date: Fri, 2 Jan 2026 17:51:38 +1000 Subject: [PATCH] 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 Signed-off-by: Zephyron --- src/video_core/shader_environment.cpp | 117 ++++++++++++++++++++++++++ src/video_core/shader_environment.h | 9 ++ 2 files changed, 126 insertions(+) diff --git a/src/video_core/shader_environment.cpp b/src/video_core/shader_environment.cpp index 4aea915a9..3f0e3a948 100644 --- a/src/video_core/shader_environment.cpp +++ b/src/video_core/shader_environment.cpp @@ -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 +#include #include #include #include @@ -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(CachedSizeBytes())}; const u64 num_texture_types{static_cast(texture_types.size())}; const u64 num_texture_pixel_formats{static_cast(texture_pixel_formats.size())}; + const u64 num_texture_component_types{static_cast(texture_component_types.size())}; const u64 num_cbuf_values{static_cast(cbuf_values.size())}; const u64 num_cbuf_replacement_values{static_cast(cbuf_replacements.size())}; @@ -205,6 +260,8 @@ void GenericEnvironment::Serialize(std::ofstream& file) const { .write(reinterpret_cast(&num_texture_types), sizeof(num_texture_types)) .write(reinterpret_cast(&num_texture_pixel_formats), sizeof(num_texture_pixel_formats)) + .write(reinterpret_cast(&num_texture_component_types), + sizeof(num_texture_component_types)) .write(reinterpret_cast(&num_cbuf_values), sizeof(num_cbuf_values)) .write(reinterpret_cast(&num_cbuf_replacement_values), sizeof(num_cbuf_replacement_values)) @@ -221,6 +278,10 @@ void GenericEnvironment::Serialize(std::ofstream& file) const { file.write(reinterpret_cast(&key), sizeof(key)) .write(reinterpret_cast(&type), sizeof(type)); } + for (const auto& [key, component] : texture_component_types) { + file.write(reinterpret_cast(&key), sizeof(key)) + .write(reinterpret_cast(&component), sizeof(component)); + } for (const auto& [key, format] : texture_pixel_formats) { file.write(reinterpret_cast(&key), sizeof(key)) .write(reinterpret_cast(&format), sizeof(format)); @@ -405,12 +466,31 @@ std::optional 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(&code_size), sizeof(code_size)) .read(reinterpret_cast(&num_texture_types), sizeof(num_texture_types)) .read(reinterpret_cast(&num_texture_pixel_formats), sizeof(num_texture_pixel_formats)) + .read(reinterpret_cast(&num_texture_component_types), + sizeof(num_texture_component_types)) .read(reinterpret_cast(&num_cbuf_values), sizeof(num_cbuf_values)) .read(reinterpret_cast(&num_cbuf_replacement_values), sizeof(num_cbuf_replacement_values)) @@ -517,6 +618,13 @@ void FileEnvironment::Deserialize(std::ifstream& file) { .read(reinterpret_cast(&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(&key), sizeof(key)) + .read(reinterpret_cast(&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()) { diff --git a/src/video_core/shader_environment.h b/src/video_core/shader_environment.h index 6b372e336..9c276b2c8 100644 --- a/src/video_core/shader_environment.h +++ b/src/video_core/shader_environment.h @@ -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 code; std::unordered_map texture_types; + std::unordered_map texture_component_types; std::unordered_map texture_pixel_formats; std::unordered_map cbuf_values; std::unordered_map 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 code; std::unordered_map texture_types; + std::unordered_map texture_component_types; std::unordered_map texture_pixel_formats; std::unordered_map cbuf_values; std::unordered_map cbuf_replacements;