From 72deb773fdcc59b1df9752de4e846422b7bb5280 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 16 Apr 2020 01:34:45 -0300 Subject: shader_ir: Turn classes into data structures --- src/video_core/shader/decode.cpp | 18 ++--- src/video_core/shader/decode/image.cpp | 18 ++--- src/video_core/shader/decode/texture.cpp | 99 ++++++++++++------------ src/video_core/shader/node.h | 129 ++++++------------------------- src/video_core/shader/shader_ir.h | 20 ++--- 5 files changed, 102 insertions(+), 182 deletions(-) (limited to 'src/video_core/shader') diff --git a/src/video_core/shader/decode.cpp b/src/video_core/shader/decode.cpp index 87ac9ac6c..8427837b7 100644 --- a/src/video_core/shader/decode.cpp +++ b/src/video_core/shader/decode.cpp @@ -42,11 +42,11 @@ void DeduceTextureHandlerSize(VideoCore::GuestDriverProfile& gpu_driver, u32 count{}; std::vector bound_offsets; for (const auto& sampler : used_samplers) { - if (sampler.IsBindless()) { + if (sampler.is_bindless) { continue; } ++count; - bound_offsets.emplace_back(sampler.GetOffset()); + bound_offsets.emplace_back(sampler.offset); } if (count > 1) { gpu_driver.DeduceTextureHandlerSize(std::move(bound_offsets)); @@ -56,14 +56,14 @@ void DeduceTextureHandlerSize(VideoCore::GuestDriverProfile& gpu_driver, std::optional TryDeduceSamplerSize(const Sampler& sampler_to_deduce, VideoCore::GuestDriverProfile& gpu_driver, const std::list& used_samplers) { - const u32 base_offset = sampler_to_deduce.GetOffset(); + const u32 base_offset = sampler_to_deduce.offset; u32 max_offset{std::numeric_limits::max()}; for (const auto& sampler : used_samplers) { - if (sampler.IsBindless()) { + if (sampler.is_bindless) { continue; } - if (sampler.GetOffset() > base_offset) { - max_offset = std::min(sampler.GetOffset(), max_offset); + if (sampler.offset > base_offset) { + max_offset = std::min(sampler.offset, max_offset); } } if (max_offset == std::numeric_limits::max()) { @@ -363,14 +363,14 @@ void ShaderIR::PostDecode() { return; } for (auto& sampler : used_samplers) { - if (!sampler.IsIndexed()) { + if (!sampler.is_indexed) { continue; } if (const auto size = TryDeduceSamplerSize(sampler, gpu_driver, used_samplers)) { - sampler.SetSize(*size); + sampler.size = *size; } else { LOG_CRITICAL(HW_GPU, "Failed to deduce size of indexed sampler"); - sampler.SetSize(1); + sampler.size = 1; } } } diff --git a/src/video_core/shader/decode/image.cpp b/src/video_core/shader/decode/image.cpp index 85ee9aa5e..60b6ad72a 100644 --- a/src/video_core/shader/decode/image.cpp +++ b/src/video_core/shader/decode/image.cpp @@ -485,11 +485,10 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) { Image& ShaderIR::GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type) { const auto offset = static_cast(image.index.Value()); - const auto it = - std::find_if(std::begin(used_images), std::end(used_images), - [offset](const Image& entry) { return entry.GetOffset() == offset; }); + const auto it = std::find_if(std::begin(used_images), std::end(used_images), + [offset](const Image& entry) { return entry.offset == offset; }); if (it != std::end(used_images)) { - ASSERT(!it->IsBindless() && it->GetType() == it->GetType()); + ASSERT(!it->is_bindless && it->type == type); return *it; } @@ -505,13 +504,12 @@ Image& ShaderIR::GetBindlessImage(Tegra::Shader::Register reg, Tegra::Shader::Im const auto buffer = std::get<1>(result); const auto offset = std::get<2>(result); - const auto it = - std::find_if(std::begin(used_images), std::end(used_images), - [buffer = buffer, offset = offset](const Image& entry) { - return entry.GetBuffer() == buffer && entry.GetOffset() == offset; - }); + const auto it = std::find_if(std::begin(used_images), std::end(used_images), + [buffer, offset](const Image& entry) { + return entry.buffer == buffer && entry.offset == offset; + }); if (it != std::end(used_images)) { - ASSERT(it->IsBindless() && it->GetType() == it->GetType()); + ASSERT(it->is_bindless && it->type == type); return *it; } diff --git a/src/video_core/shader/decode/texture.cpp b/src/video_core/shader/decode/texture.cpp index e68f1d305..193368c29 100644 --- a/src/video_core/shader/decode/texture.cpp +++ b/src/video_core/shader/decode/texture.cpp @@ -140,14 +140,13 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { const Node component = Immediate(static_cast(instr.tld4s.component)); const SamplerInfo info{TextureType::Texture2D, false, is_depth_compare, false}; - const Sampler& sampler = *GetSampler(instr.sampler, info); + const std::optional sampler = GetSampler(instr.sampler, info); Node4 values; for (u32 element = 0; element < values.size(); ++element) { - auto coords_copy = coords; - MetaTexture meta{sampler, {}, depth_compare, aoffi, {}, {}, - {}, {}, component, element, {}}; - values[element] = Operation(OperationCode::TextureGather, meta, std::move(coords_copy)); + MetaTexture meta{*sampler, {}, depth_compare, aoffi, {}, {}, + {}, {}, component, element, {}}; + values[element] = Operation(OperationCode::TextureGather, meta, coords); } if (instr.tld4s.fp16_flag) { @@ -170,13 +169,15 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { const auto texture_type = instr.txd.texture_type.Value(); const auto coord_count = GetCoordCount(texture_type); Node index_var{}; - const Sampler* sampler = + const std::optional sampler = is_bindless ? GetBindlessSampler(base_reg, index_var, {{texture_type, is_array, false, false}}) : GetSampler(instr.sampler, {{texture_type, is_array, false, false}}); Node4 values; - if (sampler == nullptr) { - std::generate(values.begin(), values.end(), [] { return Immediate(0); }); + if (!sampler) { + for (u32 element = 0; element < values.size(); ++element) { + values[element] = Immediate(0); + } WriteTexInstructionFloat(bb, instr, values); break; } @@ -218,10 +219,10 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { // Sadly, not all texture instructions specify the type of texture their sampler // uses. This must be fixed at a later instance. Node index_var{}; - const Sampler* sampler = + const std::optional sampler = is_bindless ? GetBindlessSampler(instr.gpr8, index_var) : GetSampler(instr.sampler); - if (sampler == nullptr) { + if (!sampler) { u32 indexer = 0; for (u32 element = 0; element < 4; ++element) { if (!instr.txq.IsComponentEnabled(element)) { @@ -269,10 +270,10 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { auto texture_type = instr.tmml.texture_type.Value(); Node index_var{}; - const Sampler* sampler = + const std::optional sampler = is_bindless ? GetBindlessSampler(instr.gpr20, index_var) : GetSampler(instr.sampler); - if (sampler == nullptr) { + if (!sampler) { u32 indexer = 0; for (u32 element = 0; element < 2; ++element) { if (!instr.tmml.IsComponentEnabled(element)) { @@ -368,35 +369,34 @@ ShaderIR::SamplerInfo ShaderIR::GetSamplerInfo(std::optional sample sampler->is_buffer != 0}; } -const Sampler* ShaderIR::GetSampler(const Tegra::Shader::Sampler& sampler, - std::optional sampler_info) { +std::optional ShaderIR::GetSampler(const Tegra::Shader::Sampler& sampler, + std::optional sampler_info) { const auto offset = static_cast(sampler.index.Value()); const auto info = GetSamplerInfo(sampler_info, offset); // If this sampler has already been used, return the existing mapping. - const auto it = - std::find_if(used_samplers.begin(), used_samplers.end(), - [offset](const Sampler& entry) { return entry.GetOffset() == offset; }); + const auto it = std::find_if(used_samplers.begin(), used_samplers.end(), + [offset](const Sampler& entry) { return entry.offset == offset; }); if (it != used_samplers.end()) { - ASSERT(!it->IsBindless() && it->GetType() == info.type && it->IsArray() == info.is_array && - it->IsShadow() == info.is_shadow && it->IsBuffer() == info.is_buffer); - return &*it; + ASSERT(!it->is_bindless && it->type == info.type && it->is_array == info.is_array && + it->is_shadow == info.is_shadow && it->is_buffer == info.is_buffer); + return *it; } // Otherwise create a new mapping for this sampler const auto next_index = static_cast(used_samplers.size()); - return &used_samplers.emplace_back(next_index, offset, info.type, info.is_array, info.is_shadow, - info.is_buffer, false); + return used_samplers.emplace_back(next_index, offset, info.type, info.is_array, info.is_shadow, + info.is_buffer, false); } -const Sampler* ShaderIR::GetBindlessSampler(Tegra::Shader::Register reg, Node& index_var, - std::optional sampler_info) { +std::optional ShaderIR::GetBindlessSampler(Tegra::Shader::Register reg, Node& index_var, + std::optional sampler_info) { const Node sampler_register = GetRegister(reg); const auto [base_node, tracked_sampler_info] = TrackBindlessSampler(sampler_register, global_code, static_cast(global_code.size())); ASSERT(base_node != nullptr); if (base_node == nullptr) { - return nullptr; + return std::nullopt; } if (const auto bindless_sampler_info = @@ -406,23 +406,22 @@ const Sampler* ShaderIR::GetBindlessSampler(Tegra::Shader::Register reg, Node& i const auto info = GetSamplerInfo(sampler_info, offset, buffer); // If this sampler has already been used, return the existing mapping. - const auto it = - std::find_if(used_samplers.begin(), used_samplers.end(), - [buffer = buffer, offset = offset](const Sampler& entry) { - return entry.GetBuffer() == buffer && entry.GetOffset() == offset; - }); + const auto it = std::find_if(used_samplers.begin(), used_samplers.end(), + [buffer = buffer, offset = offset](const Sampler& entry) { + return entry.buffer == buffer && entry.offset == offset; + }); if (it != used_samplers.end()) { - ASSERT(it->IsBindless() && it->GetType() == info.type && - it->IsArray() == info.is_array && it->IsShadow() == info.is_shadow); - return &*it; + ASSERT(it->is_bindless && it->type == info.type && it->is_array == info.is_array && + it->is_shadow == info.is_shadow); + return *it; } // Otherwise create a new mapping for this sampler const auto next_index = static_cast(used_samplers.size()); - return &used_samplers.emplace_back(next_index, offset, buffer, info.type, info.is_array, - info.is_shadow, info.is_buffer, false); - } else if (const auto array_sampler_info = - std::get_if(&*tracked_sampler_info)) { + return used_samplers.emplace_back(next_index, offset, buffer, info.type, info.is_array, + info.is_shadow, info.is_buffer, false); + } + if (const auto array_sampler_info = std::get_if(&*tracked_sampler_info)) { const u32 base_offset = array_sampler_info->GetBaseOffset() / 4; index_var = GetCustomVariable(array_sampler_info->GetIndexVar()); const auto info = GetSamplerInfo(sampler_info, base_offset); @@ -430,21 +429,21 @@ const Sampler* ShaderIR::GetBindlessSampler(Tegra::Shader::Register reg, Node& i // If this sampler has already been used, return the existing mapping. const auto it = std::find_if( used_samplers.begin(), used_samplers.end(), - [base_offset](const Sampler& entry) { return entry.GetOffset() == base_offset; }); + [base_offset](const Sampler& entry) { return entry.offset == base_offset; }); if (it != used_samplers.end()) { - ASSERT(!it->IsBindless() && it->GetType() == info.type && - it->IsArray() == info.is_array && it->IsShadow() == info.is_shadow && - it->IsBuffer() == info.is_buffer && it->IsIndexed()); - return &*it; + ASSERT(!it->is_bindless && it->type == info.type && it->is_array == info.is_array && + it->is_shadow == info.is_shadow && it->is_buffer == info.is_buffer && + it->is_indexed); + return *it; } uses_indexed_samplers = true; // Otherwise create a new mapping for this sampler const auto next_index = static_cast(used_samplers.size()); - return &used_samplers.emplace_back(next_index, base_offset, info.type, info.is_array, - info.is_shadow, info.is_buffer, true); + return used_samplers.emplace_back(next_index, base_offset, info.type, info.is_array, + info.is_shadow, info.is_buffer, true); } - return nullptr; + return std::nullopt; } void ShaderIR::WriteTexInstructionFloat(NodeBlock& bb, Instruction instr, const Node4& components) { @@ -531,7 +530,8 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type, const SamplerInfo info{texture_type, is_array, is_shadow, false}; Node index_var; - const Sampler* sampler = is_bindless ? GetBindlessSampler(*bindless_reg, index_var, info) + std::optional sampler = is_bindless + ? GetBindlessSampler(*bindless_reg, index_var, info) : GetSampler(instr.sampler, info); if (!sampler) { return {Immediate(0), Immediate(0), Immediate(0), Immediate(0)}; @@ -685,10 +685,11 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de const SamplerInfo info{texture_type, is_array, depth_compare, false}; Node index_var{}; - const Sampler* sampler = is_bindless ? GetBindlessSampler(parameter_register++, index_var, info) - : GetSampler(instr.sampler, info); + const std::optional sampler = + is_bindless ? GetBindlessSampler(parameter_register++, index_var, info) + : GetSampler(instr.sampler, info); Node4 values; - if (sampler == nullptr) { + if (!sampler) { for (u32 element = 0; element < values.size(); ++element) { values[element] = Immediate(0); } diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h index 3eee961f5..d0656b581 100644 --- a/src/video_core/shader/node.h +++ b/src/video_core/shader/node.h @@ -265,76 +265,30 @@ class ArraySamplerNode; using TrackSamplerData = std::variant; using TrackSampler = std::shared_ptr; -class Sampler { -public: - /// This constructor is for bound samplers +struct Sampler { + /// Bound samplers constructor constexpr explicit Sampler(u32 index, u32 offset, Tegra::Shader::TextureType type, bool is_array, bool is_shadow, bool is_buffer, bool is_indexed) : index{index}, offset{offset}, type{type}, is_array{is_array}, is_shadow{is_shadow}, is_buffer{is_buffer}, is_indexed{is_indexed} {} - /// This constructor is for bindless samplers + /// Bindless samplers constructor constexpr explicit Sampler(u32 index, u32 offset, u32 buffer, Tegra::Shader::TextureType type, bool is_array, bool is_shadow, bool is_buffer, bool is_indexed) : index{index}, offset{offset}, buffer{buffer}, type{type}, is_array{is_array}, is_shadow{is_shadow}, is_buffer{is_buffer}, is_bindless{true}, is_indexed{is_indexed} {} - constexpr u32 GetIndex() const { - return index; - } - - constexpr u32 GetOffset() const { - return offset; - } - - constexpr u32 GetBuffer() const { - return buffer; - } - - constexpr Tegra::Shader::TextureType GetType() const { - return type; - } - - constexpr bool IsArray() const { - return is_array; - } - - constexpr bool IsShadow() const { - return is_shadow; - } - - constexpr bool IsBuffer() const { - return is_buffer; - } - - constexpr bool IsBindless() const { - return is_bindless; - } - - constexpr bool IsIndexed() const { - return is_indexed; - } - - constexpr u32 Size() const { - return size; - } - - constexpr void SetSize(u32 new_size) { - size = new_size; - } - -private: - u32 index{}; ///< Emulated index given for the this sampler. - u32 offset{}; ///< Offset in the const buffer from where the sampler is being read. - u32 buffer{}; ///< Buffer where the bindless sampler is being read (unused on bound samplers). - u32 size{1}; ///< Size of the sampler. + u32 index = 0; ///< Emulated index given for the this sampler. + u32 offset = 0; ///< Offset in the const buffer from where the sampler is being read. + u32 buffer = 0; ///< Buffer where the bindless sampler is being read (unused on bound samplers). + u32 size = 1; ///< Size of the sampler. Tegra::Shader::TextureType type{}; ///< The type used to sample this texture (Texture2D, etc) - bool is_array{}; ///< Whether the texture is being sampled as an array texture or not. - bool is_shadow{}; ///< Whether the texture is being sampled as a depth texture or not. - bool is_buffer{}; ///< Whether the texture is a texture buffer without sampler. - bool is_bindless{}; ///< Whether this sampler belongs to a bindless texture or not. - bool is_indexed{}; ///< Whether this sampler is an indexed array of textures. + bool is_array = false; ///< Whether the texture is being sampled as an array texture or not. + bool is_shadow = false; ///< Whether the texture is being sampled as a depth texture or not. + bool is_buffer = false; ///< Whether the texture is a texture buffer without sampler. + bool is_bindless = false; ///< Whether this sampler belongs to a bindless texture or not. + bool is_indexed = false; ///< Whether this sampler is an indexed array of textures. }; /// Represents a tracked bindless sampler into a direct const buffer @@ -379,13 +333,13 @@ private: u32 offset; }; -class Image final { +struct Image { public: - /// This constructor is for bound images + /// Bound images constructor constexpr explicit Image(u32 index, u32 offset, Tegra::Shader::ImageType type) : index{index}, offset{offset}, type{type} {} - /// This constructor is for bindless samplers + /// Bindless samplers constructor constexpr explicit Image(u32 index, u32 offset, u32 buffer, Tegra::Shader::ImageType type) : index{index}, offset{offset}, buffer{buffer}, type{type}, is_bindless{true} {} @@ -403,53 +357,20 @@ public: is_atomic = true; } - constexpr u32 GetIndex() const { - return index; - } - - constexpr u32 GetOffset() const { - return offset; - } - - constexpr u32 GetBuffer() const { - return buffer; - } - - constexpr Tegra::Shader::ImageType GetType() const { - return type; - } - - constexpr bool IsBindless() const { - return is_bindless; - } - - constexpr bool IsWritten() const { - return is_written; - } - - constexpr bool IsRead() const { - return is_read; - } - - constexpr bool IsAtomic() const { - return is_atomic; - } - -private: - u32 index{}; - u32 offset{}; - u32 buffer{}; + u32 index = 0; + u32 offset = 0; + u32 buffer = 0; Tegra::Shader::ImageType type{}; - bool is_bindless{}; - bool is_written{}; - bool is_read{}; - bool is_atomic{}; + bool is_bindless = false; + bool is_written = false; + bool is_read = false; + bool is_atomic = false; }; struct GlobalMemoryBase { - u32 cbuf_index{}; - u32 cbuf_offset{}; + u32 cbuf_index = 0; + u32 cbuf_offset = 0; bool operator<(const GlobalMemoryBase& rhs) const { return std::tie(cbuf_index, cbuf_offset) < std::tie(rhs.cbuf_index, rhs.cbuf_offset); @@ -463,7 +384,7 @@ struct MetaArithmetic { /// Parameters describing a texture sampler struct MetaTexture { - const Sampler& sampler; + Sampler sampler; Node array; Node depth_compare; std::vector aoffi; diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index c6e7bdf50..ae5e414cb 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h @@ -29,12 +29,11 @@ using ProgramCode = std::vector; constexpr u32 MAX_PROGRAM_LENGTH = 0x1000; -class ConstBuffer { -public: - explicit ConstBuffer(u32 max_offset, bool is_indirect) +struct ConstBuffer { + constexpr explicit ConstBuffer(u32 max_offset, bool is_indirect) : max_offset{max_offset}, is_indirect{is_indirect} {} - ConstBuffer() = default; + constexpr ConstBuffer() = default; void MarkAsUsed(u64 offset) { max_offset = std::max(max_offset, static_cast(offset)); @@ -57,8 +56,8 @@ public: } private: - u32 max_offset{}; - bool is_indirect{}; + u32 max_offset = 0; + bool is_indirect = false; }; struct GlobalMemoryUsage { @@ -332,12 +331,13 @@ private: std::optional buffer = std::nullopt); /// Accesses a texture sampler - const Sampler* GetSampler(const Tegra::Shader::Sampler& sampler, - std::optional sampler_info = std::nullopt); + std::optional GetSampler(const Tegra::Shader::Sampler& sampler, + std::optional sampler_info = std::nullopt); /// Accesses a texture sampler for a bindless texture. - const Sampler* GetBindlessSampler(Tegra::Shader::Register reg, Node& index_var, - std::optional sampler_info = std::nullopt); + std::optional GetBindlessSampler( + Tegra::Shader::Register reg, Node& index_var, + std::optional sampler_info = std::nullopt); /// Accesses an image. Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type); -- cgit v1.2.3 From 4fb921ff6bd6f9596c7e7cd9524932f2a44e9490 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Thu, 16 Apr 2020 02:07:42 -0300 Subject: shader/texture: Support multiple unknown sampler properties This allows deducing some properties from the texture instruction before asking the runtime. By doing this we can handle type mismatches in some instructions from the renderer instead of the shader decoder. Fixes texelFetch issues with games using 2D texture instructions on a 1D sampler. --- src/video_core/shader/decode/texture.cpp | 125 ++++++++++++++++++------------- src/video_core/shader/shader_ir.h | 24 +++--- 2 files changed, 87 insertions(+), 62 deletions(-) (limited to 'src/video_core/shader') diff --git a/src/video_core/shader/decode/texture.cpp b/src/video_core/shader/decode/texture.cpp index 193368c29..8f0bb996e 100644 --- a/src/video_core/shader/decode/texture.cpp +++ b/src/video_core/shader/decode/texture.cpp @@ -139,7 +139,8 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { } const Node component = Immediate(static_cast(instr.tld4s.component)); - const SamplerInfo info{TextureType::Texture2D, false, is_depth_compare, false}; + SamplerInfo info; + info.is_shadow = is_depth_compare; const std::optional sampler = GetSampler(instr.sampler, info); Node4 values; @@ -164,20 +165,20 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { "AOFFI is not implemented"); const bool is_array = instr.txd.is_array != 0; - u64 base_reg = instr.gpr8.Value(); const auto derivate_reg = instr.gpr20.Value(); const auto texture_type = instr.txd.texture_type.Value(); const auto coord_count = GetCoordCount(texture_type); - Node index_var{}; - const std::optional sampler = - is_bindless - ? GetBindlessSampler(base_reg, index_var, {{texture_type, is_array, false, false}}) - : GetSampler(instr.sampler, {{texture_type, is_array, false, false}}); + u64 base_reg = instr.gpr8.Value(); + Node index_var; + SamplerInfo info; + info.type = texture_type; + info.is_array = is_array; + const std::optional sampler = is_bindless + ? GetBindlessSampler(base_reg, info, index_var) + : GetSampler(instr.sampler, info); Node4 values; if (!sampler) { - for (u32 element = 0; element < values.size(); ++element) { - values[element] = Immediate(0); - } + std::generate(values.begin(), values.end(), [this] { return Immediate(0); }); WriteTexInstructionFloat(bb, instr, values); break; } @@ -215,12 +216,10 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { is_bindless = true; [[fallthrough]]; case OpCode::Id::TXQ: { - // TODO: The new commits on the texture refactor, change the way samplers work. - // Sadly, not all texture instructions specify the type of texture their sampler - // uses. This must be fixed at a later instance. - Node index_var{}; - const std::optional sampler = - is_bindless ? GetBindlessSampler(instr.gpr8, index_var) : GetSampler(instr.sampler); + Node index_var; + const std::optional sampler = is_bindless + ? GetBindlessSampler(instr.gpr8, {}, index_var) + : GetSampler(instr.sampler, {}); if (!sampler) { u32 indexer = 0; @@ -268,10 +267,15 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { UNIMPLEMENTED_IF_MSG(instr.tmml.UsesMiscMode(Tegra::Shader::TextureMiscMode::NDV), "NDV is not implemented"); - auto texture_type = instr.tmml.texture_type.Value(); - Node index_var{}; + const auto texture_type = instr.tmml.texture_type.Value(); + const bool is_array = instr.tmml.array != 0; + SamplerInfo info; + info.type = texture_type; + info.is_array = is_array; + Node index_var; const std::optional sampler = - is_bindless ? GetBindlessSampler(instr.gpr20, index_var) : GetSampler(instr.sampler); + is_bindless ? GetBindlessSampler(instr.gpr20, info, index_var) + : GetSampler(instr.sampler, info); if (!sampler) { u32 indexer = 0; @@ -300,12 +304,11 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { coords.push_back(GetRegister(instr.gpr8.Value() + 1)); break; default: - UNIMPLEMENTED_MSG("Unhandled texture type {}", static_cast(texture_type)); + UNIMPLEMENTED_MSG("Unhandled texture type {}", static_cast(texture_type)); // Fallback to interpreting as a 2D texture for now coords.push_back(GetRegister(instr.gpr8.Value() + 0)); coords.push_back(GetRegister(instr.gpr8.Value() + 1)); - texture_type = TextureType::Texture2D; } u32 indexer = 0; for (u32 element = 0; element < 2; ++element) { @@ -354,23 +357,30 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) { return pc; } -ShaderIR::SamplerInfo ShaderIR::GetSamplerInfo(std::optional sampler_info, u32 offset, +ShaderIR::SamplerInfo ShaderIR::GetSamplerInfo(SamplerInfo info, u32 offset, std::optional buffer) { - if (sampler_info) { - return *sampler_info; + if (info.IsComplete()) { + return info; } const auto sampler = buffer ? registry.ObtainBindlessSampler(*buffer, offset) : registry.ObtainBoundSampler(offset); if (!sampler) { LOG_WARNING(HW_GPU, "Unknown sampler info"); - return SamplerInfo{TextureType::Texture2D, false, false, false}; - } - return SamplerInfo{sampler->texture_type, sampler->is_array != 0, sampler->is_shadow != 0, - sampler->is_buffer != 0}; + info.type = info.type.value_or(Tegra::Shader::TextureType::Texture2D); + info.is_array = info.is_array.value_or(false); + info.is_shadow = info.is_shadow.value_or(false); + info.is_buffer = info.is_buffer.value_or(false); + return info; + } + info.type = info.type.value_or(sampler->texture_type); + info.is_array = info.is_array.value_or(sampler->is_array != 0); + info.is_shadow = info.is_shadow.value_or(sampler->is_shadow != 0); + info.is_buffer = info.is_buffer.value_or(sampler->is_buffer != 0); + return info; } -std::optional ShaderIR::GetSampler(const Tegra::Shader::Sampler& sampler, - std::optional sampler_info) { +std::optional ShaderIR::GetSampler(Tegra::Shader::Sampler sampler, + SamplerInfo sampler_info) { const auto offset = static_cast(sampler.index.Value()); const auto info = GetSamplerInfo(sampler_info, offset); @@ -385,12 +395,12 @@ std::optional ShaderIR::GetSampler(const Tegra::Shader::Sampler& sample // Otherwise create a new mapping for this sampler const auto next_index = static_cast(used_samplers.size()); - return used_samplers.emplace_back(next_index, offset, info.type, info.is_array, info.is_shadow, - info.is_buffer, false); + return used_samplers.emplace_back(next_index, offset, *info.type, *info.is_array, + *info.is_shadow, *info.is_buffer, false); } -std::optional ShaderIR::GetBindlessSampler(Tegra::Shader::Register reg, Node& index_var, - std::optional sampler_info) { +std::optional ShaderIR::GetBindlessSampler(Tegra::Shader::Register reg, SamplerInfo info, + Node& index_var) { const Node sampler_register = GetRegister(reg); const auto [base_node, tracked_sampler_info] = TrackBindlessSampler(sampler_register, global_code, static_cast(global_code.size())); @@ -403,7 +413,7 @@ std::optional ShaderIR::GetBindlessSampler(Tegra::Shader::Register reg, std::get_if(&*tracked_sampler_info)) { const u32 buffer = bindless_sampler_info->GetIndex(); const u32 offset = bindless_sampler_info->GetOffset(); - const auto info = GetSamplerInfo(sampler_info, offset, buffer); + info = GetSamplerInfo(info, offset, buffer); // If this sampler has already been used, return the existing mapping. const auto it = std::find_if(used_samplers.begin(), used_samplers.end(), @@ -418,13 +428,13 @@ std::optional ShaderIR::GetBindlessSampler(Tegra::Shader::Register reg, // Otherwise create a new mapping for this sampler const auto next_index = static_cast(used_samplers.size()); - return used_samplers.emplace_back(next_index, offset, buffer, info.type, info.is_array, - info.is_shadow, info.is_buffer, false); + return used_samplers.emplace_back(next_index, offset, buffer, *info.type, *info.is_array, + *info.is_shadow, *info.is_buffer, false); } if (const auto array_sampler_info = std::get_if(&*tracked_sampler_info)) { const u32 base_offset = array_sampler_info->GetBaseOffset() / 4; index_var = GetCustomVariable(array_sampler_info->GetIndexVar()); - const auto info = GetSamplerInfo(sampler_info, base_offset); + info = GetSamplerInfo(info, base_offset); // If this sampler has already been used, return the existing mapping. const auto it = std::find_if( @@ -440,8 +450,8 @@ std::optional ShaderIR::GetBindlessSampler(Tegra::Shader::Register reg, uses_indexed_samplers = true; // Otherwise create a new mapping for this sampler const auto next_index = static_cast(used_samplers.size()); - return used_samplers.emplace_back(next_index, base_offset, info.type, info.is_array, - info.is_shadow, info.is_buffer, true); + return used_samplers.emplace_back(next_index, base_offset, *info.type, *info.is_array, + *info.is_shadow, *info.is_buffer, true); } return std::nullopt; } @@ -528,11 +538,16 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type, ASSERT_MSG(texture_type != TextureType::Texture3D || !is_array || !is_shadow, "Illegal texture type"); - const SamplerInfo info{texture_type, is_array, is_shadow, false}; + SamplerInfo info; + info.type = texture_type; + info.is_array = is_array; + info.is_shadow = is_shadow; + info.is_buffer = false; + Node index_var; - std::optional sampler = is_bindless - ? GetBindlessSampler(*bindless_reg, index_var, info) - : GetSampler(instr.sampler, info); + const std::optional sampler = is_bindless + ? GetBindlessSampler(*bindless_reg, info, index_var) + : GetSampler(instr.sampler, info); if (!sampler) { return {Immediate(0), Immediate(0), Immediate(0), Immediate(0)}; } @@ -683,10 +698,14 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de u64 parameter_register = instr.gpr20.Value(); - const SamplerInfo info{texture_type, is_array, depth_compare, false}; - Node index_var{}; + SamplerInfo info; + info.type = texture_type; + info.is_array = is_array; + info.is_shadow = depth_compare; + + Node index_var; const std::optional sampler = - is_bindless ? GetBindlessSampler(parameter_register++, index_var, info) + is_bindless ? GetBindlessSampler(parameter_register++, info, index_var) : GetSampler(instr.sampler, info); Node4 values; if (!sampler) { @@ -744,12 +763,12 @@ Node4 ShaderIR::GetTldCode(Tegra::Shader::Instruction instr) { // const Node aoffi_register{is_aoffi ? GetRegister(gpr20_cursor++) : nullptr}; // const Node multisample{is_multisample ? GetRegister(gpr20_cursor++) : nullptr}; - const auto& sampler = *GetSampler(instr.sampler); + const std::optional sampler = GetSampler(instr.sampler, {}); Node4 values; for (u32 element = 0; element < values.size(); ++element) { auto coords_copy = coords; - MetaTexture meta{sampler, array_register, {}, {}, {}, {}, {}, lod, {}, element, {}}; + MetaTexture meta{*sampler, array_register, {}, {}, {}, {}, {}, lod, {}, element, {}}; values[element] = Operation(OperationCode::TexelFetch, meta, std::move(coords_copy)); } @@ -757,7 +776,11 @@ Node4 ShaderIR::GetTldCode(Tegra::Shader::Instruction instr) { } Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is_array) { - const Sampler& sampler = *GetSampler(instr.sampler); + SamplerInfo info; + info.type = texture_type; + info.is_array = is_array; + info.is_shadow = false; + const std::optional sampler = GetSampler(instr.sampler, info); const std::size_t type_coord_count = GetCoordCount(texture_type); const bool lod_enabled = instr.tlds.GetTextureProcessMode() == TextureProcessMode::LL; @@ -785,7 +808,7 @@ Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is Node4 values; for (u32 element = 0; element < values.size(); ++element) { auto coords_copy = coords; - MetaTexture meta{sampler, array, {}, {}, {}, {}, {}, lod, {}, element, {}}; + MetaTexture meta{*sampler, array, {}, {}, {}, {}, {}, lod, {}, element, {}}; values[element] = Operation(OperationCode::TexelFetch, meta, std::move(coords_copy)); } return values; diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index ae5e414cb..748d73087 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h @@ -191,10 +191,14 @@ private: friend class ASTDecoder; struct SamplerInfo { - Tegra::Shader::TextureType type; - bool is_array; - bool is_shadow; - bool is_buffer; + std::optional type; + std::optional is_array; + std::optional is_shadow; + std::optional is_buffer; + + constexpr bool IsComplete() const noexcept { + return type && is_array && is_shadow && is_buffer; + } }; void Decode(); @@ -327,17 +331,15 @@ private: OperationCode GetPredicateCombiner(Tegra::Shader::PredOperation operation); /// Queries the missing sampler info from the execution context. - SamplerInfo GetSamplerInfo(std::optional sampler_info, u32 offset, + SamplerInfo GetSamplerInfo(SamplerInfo info, u32 offset, std::optional buffer = std::nullopt); - /// Accesses a texture sampler - std::optional GetSampler(const Tegra::Shader::Sampler& sampler, - std::optional sampler_info = std::nullopt); + /// Accesses a texture sampler. + std::optional GetSampler(Tegra::Shader::Sampler sampler, SamplerInfo info); /// Accesses a texture sampler for a bindless texture. - std::optional GetBindlessSampler( - Tegra::Shader::Register reg, Node& index_var, - std::optional sampler_info = std::nullopt); + std::optional GetBindlessSampler(Tegra::Shader::Register reg, SamplerInfo info, + Node& index_var); /// Accesses an image. Image& GetImage(Tegra::Shader::Image image, Tegra::Shader::ImageType type); -- cgit v1.2.3