mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	Merge pull request #2558 from ReinUsesLisp/shader-nodes
shader: Move Node declarations out of the shader IR header
This commit is contained in:
		
						commit
						cd2d9628c9
					
				| @ -82,6 +82,9 @@ set(HASH_FILES | ||||
|     "${VIDEO_CORE}/shader/decode/video.cpp" | ||||
|     "${VIDEO_CORE}/shader/decode/xmad.cpp" | ||||
|     "${VIDEO_CORE}/shader/decode.cpp" | ||||
|     "${VIDEO_CORE}/shader/node.h" | ||||
|     "${VIDEO_CORE}/shader/node_helper.cpp" | ||||
|     "${VIDEO_CORE}/shader/node_helper.h" | ||||
|     "${VIDEO_CORE}/shader/shader_ir.cpp" | ||||
|     "${VIDEO_CORE}/shader/shader_ir.h" | ||||
|     "${VIDEO_CORE}/shader/track.cpp" | ||||
|  | ||||
| @ -56,6 +56,9 @@ add_custom_command(OUTPUT scm_rev.cpp | ||||
|       "${VIDEO_CORE}/shader/decode/video.cpp" | ||||
|       "${VIDEO_CORE}/shader/decode/xmad.cpp" | ||||
|       "${VIDEO_CORE}/shader/decode.cpp" | ||||
|       "${VIDEO_CORE}/shader/node.h" | ||||
|       "${VIDEO_CORE}/shader/node_helper.cpp" | ||||
|       "${VIDEO_CORE}/shader/node_helper.h" | ||||
|       "${VIDEO_CORE}/shader/shader_ir.cpp" | ||||
|       "${VIDEO_CORE}/shader/shader_ir.h" | ||||
|       "${VIDEO_CORE}/shader/track.cpp" | ||||
|  | ||||
| @ -104,6 +104,7 @@ add_library(video_core STATIC | ||||
|     shader/decode.cpp | ||||
|     shader/node_helper.cpp | ||||
|     shader/node_helper.h | ||||
|     shader/node.h | ||||
|     shader/shader_ir.cpp | ||||
|     shader/shader_ir.h | ||||
|     shader/track.cpp | ||||
|  | ||||
							
								
								
									
										514
									
								
								src/video_core/shader/node.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										514
									
								
								src/video_core/shader/node.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,514 @@ | ||||
| // Copyright 2019 yuzu Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <array> | ||||
| #include <cstddef> | ||||
| #include <memory> | ||||
| #include <string> | ||||
| #include <tuple> | ||||
| #include <utility> | ||||
| #include <variant> | ||||
| #include <vector> | ||||
| 
 | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
| 
 | ||||
| enum class OperationCode { | ||||
|     Assign, /// (float& dest, float src) -> void
 | ||||
| 
 | ||||
|     Select, /// (MetaArithmetic, bool pred, float a, float b) -> float
 | ||||
| 
 | ||||
|     FAdd,          /// (MetaArithmetic, float a, float b) -> float
 | ||||
|     FMul,          /// (MetaArithmetic, float a, float b) -> float
 | ||||
|     FDiv,          /// (MetaArithmetic, float a, float b) -> float
 | ||||
|     FFma,          /// (MetaArithmetic, float a, float b, float c) -> float
 | ||||
|     FNegate,       /// (MetaArithmetic, float a) -> float
 | ||||
|     FAbsolute,     /// (MetaArithmetic, float a) -> float
 | ||||
|     FClamp,        /// (MetaArithmetic, float value, float min, float max) -> float
 | ||||
|     FMin,          /// (MetaArithmetic, float a, float b) -> float
 | ||||
|     FMax,          /// (MetaArithmetic, float a, float b) -> float
 | ||||
|     FCos,          /// (MetaArithmetic, float a) -> float
 | ||||
|     FSin,          /// (MetaArithmetic, float a) -> float
 | ||||
|     FExp2,         /// (MetaArithmetic, float a) -> float
 | ||||
|     FLog2,         /// (MetaArithmetic, float a) -> float
 | ||||
|     FInverseSqrt,  /// (MetaArithmetic, float a) -> float
 | ||||
|     FSqrt,         /// (MetaArithmetic, float a) -> float
 | ||||
|     FRoundEven,    /// (MetaArithmetic, float a) -> float
 | ||||
|     FFloor,        /// (MetaArithmetic, float a) -> float
 | ||||
|     FCeil,         /// (MetaArithmetic, float a) -> float
 | ||||
|     FTrunc,        /// (MetaArithmetic, float a) -> float
 | ||||
|     FCastInteger,  /// (MetaArithmetic, int a) -> float
 | ||||
|     FCastUInteger, /// (MetaArithmetic, uint a) -> float
 | ||||
| 
 | ||||
|     IAdd,                  /// (MetaArithmetic, int a, int b) -> int
 | ||||
|     IMul,                  /// (MetaArithmetic, int a, int b) -> int
 | ||||
|     IDiv,                  /// (MetaArithmetic, int a, int b) -> int
 | ||||
|     INegate,               /// (MetaArithmetic, int a) -> int
 | ||||
|     IAbsolute,             /// (MetaArithmetic, int a) -> int
 | ||||
|     IMin,                  /// (MetaArithmetic, int a, int b) -> int
 | ||||
|     IMax,                  /// (MetaArithmetic, int a, int b) -> int
 | ||||
|     ICastFloat,            /// (MetaArithmetic, float a) -> int
 | ||||
|     ICastUnsigned,         /// (MetaArithmetic, uint a) -> int
 | ||||
|     ILogicalShiftLeft,     /// (MetaArithmetic, int a, uint b) -> int
 | ||||
|     ILogicalShiftRight,    /// (MetaArithmetic, int a, uint b) -> int
 | ||||
|     IArithmeticShiftRight, /// (MetaArithmetic, int a, uint b) -> int
 | ||||
|     IBitwiseAnd,           /// (MetaArithmetic, int a, int b) -> int
 | ||||
|     IBitwiseOr,            /// (MetaArithmetic, int a, int b) -> int
 | ||||
|     IBitwiseXor,           /// (MetaArithmetic, int a, int b) -> int
 | ||||
|     IBitwiseNot,           /// (MetaArithmetic, int a) -> int
 | ||||
|     IBitfieldInsert,       /// (MetaArithmetic, int base, int insert, int offset, int bits) -> int
 | ||||
|     IBitfieldExtract,      /// (MetaArithmetic, int value, int offset, int offset) -> int
 | ||||
|     IBitCount,             /// (MetaArithmetic, int) -> int
 | ||||
| 
 | ||||
|     UAdd,                  /// (MetaArithmetic, uint a, uint b) -> uint
 | ||||
|     UMul,                  /// (MetaArithmetic, uint a, uint b) -> uint
 | ||||
|     UDiv,                  /// (MetaArithmetic, uint a, uint b) -> uint
 | ||||
|     UMin,                  /// (MetaArithmetic, uint a, uint b) -> uint
 | ||||
|     UMax,                  /// (MetaArithmetic, uint a, uint b) -> uint
 | ||||
|     UCastFloat,            /// (MetaArithmetic, float a) -> uint
 | ||||
|     UCastSigned,           /// (MetaArithmetic, int a) -> uint
 | ||||
|     ULogicalShiftLeft,     /// (MetaArithmetic, uint a, uint b) -> uint
 | ||||
|     ULogicalShiftRight,    /// (MetaArithmetic, uint a, uint b) -> uint
 | ||||
|     UArithmeticShiftRight, /// (MetaArithmetic, uint a, uint b) -> uint
 | ||||
|     UBitwiseAnd,           /// (MetaArithmetic, uint a, uint b) -> uint
 | ||||
|     UBitwiseOr,            /// (MetaArithmetic, uint a, uint b) -> uint
 | ||||
|     UBitwiseXor,           /// (MetaArithmetic, uint a, uint b) -> uint
 | ||||
|     UBitwiseNot,           /// (MetaArithmetic, uint a) -> uint
 | ||||
|     UBitfieldInsert,  /// (MetaArithmetic, uint base, uint insert, int offset, int bits) -> uint
 | ||||
|     UBitfieldExtract, /// (MetaArithmetic, uint value, int offset, int offset) -> uint
 | ||||
|     UBitCount,        /// (MetaArithmetic, uint) -> uint
 | ||||
| 
 | ||||
|     HAdd,      /// (MetaArithmetic, f16vec2 a, f16vec2 b) -> f16vec2
 | ||||
|     HMul,      /// (MetaArithmetic, f16vec2 a, f16vec2 b) -> f16vec2
 | ||||
|     HFma,      /// (MetaArithmetic, f16vec2 a, f16vec2 b, f16vec2 c) -> f16vec2
 | ||||
|     HAbsolute, /// (f16vec2 a) -> f16vec2
 | ||||
|     HNegate,   /// (f16vec2 a, bool first, bool second) -> f16vec2
 | ||||
|     HClamp,    /// (f16vec2 src, float min, float max) -> f16vec2
 | ||||
|     HUnpack,   /// (Tegra::Shader::HalfType, T value) -> f16vec2
 | ||||
|     HMergeF32, /// (f16vec2 src) -> float
 | ||||
|     HMergeH0,  /// (f16vec2 dest, f16vec2 src) -> f16vec2
 | ||||
|     HMergeH1,  /// (f16vec2 dest, f16vec2 src) -> f16vec2
 | ||||
|     HPack2,    /// (float a, float b) -> f16vec2
 | ||||
| 
 | ||||
|     LogicalAssign, /// (bool& dst, bool src) -> void
 | ||||
|     LogicalAnd,    /// (bool a, bool b) -> bool
 | ||||
|     LogicalOr,     /// (bool a, bool b) -> bool
 | ||||
|     LogicalXor,    /// (bool a, bool b) -> bool
 | ||||
|     LogicalNegate, /// (bool a) -> bool
 | ||||
|     LogicalPick2,  /// (bool2 pair, uint index) -> bool
 | ||||
|     LogicalAll2,   /// (bool2 a) -> bool
 | ||||
|     LogicalAny2,   /// (bool2 a) -> bool
 | ||||
| 
 | ||||
|     LogicalFLessThan,     /// (float a, float b) -> bool
 | ||||
|     LogicalFEqual,        /// (float a, float b) -> bool
 | ||||
|     LogicalFLessEqual,    /// (float a, float b) -> bool
 | ||||
|     LogicalFGreaterThan,  /// (float a, float b) -> bool
 | ||||
|     LogicalFNotEqual,     /// (float a, float b) -> bool
 | ||||
|     LogicalFGreaterEqual, /// (float a, float b) -> bool
 | ||||
|     LogicalFIsNan,        /// (float a) -> bool
 | ||||
| 
 | ||||
|     LogicalILessThan,     /// (int a, int b) -> bool
 | ||||
|     LogicalIEqual,        /// (int a, int b) -> bool
 | ||||
|     LogicalILessEqual,    /// (int a, int b) -> bool
 | ||||
|     LogicalIGreaterThan,  /// (int a, int b) -> bool
 | ||||
|     LogicalINotEqual,     /// (int a, int b) -> bool
 | ||||
|     LogicalIGreaterEqual, /// (int a, int b) -> bool
 | ||||
| 
 | ||||
|     LogicalULessThan,     /// (uint a, uint b) -> bool
 | ||||
|     LogicalUEqual,        /// (uint a, uint b) -> bool
 | ||||
|     LogicalULessEqual,    /// (uint a, uint b) -> bool
 | ||||
|     LogicalUGreaterThan,  /// (uint a, uint b) -> bool
 | ||||
|     LogicalUNotEqual,     /// (uint a, uint b) -> bool
 | ||||
|     LogicalUGreaterEqual, /// (uint a, uint b) -> bool
 | ||||
| 
 | ||||
|     Logical2HLessThan,            /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
|     Logical2HEqual,               /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
|     Logical2HLessEqual,           /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
|     Logical2HGreaterThan,         /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
|     Logical2HNotEqual,            /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
|     Logical2HGreaterEqual,        /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
|     Logical2HLessThanWithNan,     /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
|     Logical2HEqualWithNan,        /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
|     Logical2HLessEqualWithNan,    /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
|     Logical2HGreaterThanWithNan,  /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
|     Logical2HNotEqualWithNan,     /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
|     Logical2HGreaterEqualWithNan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
| 
 | ||||
|     Texture,                /// (MetaTexture, float[N] coords) -> float4
 | ||||
|     TextureLod,             /// (MetaTexture, float[N] coords) -> float4
 | ||||
|     TextureGather,          /// (MetaTexture, float[N] coords) -> float4
 | ||||
|     TextureQueryDimensions, /// (MetaTexture, float a) -> float4
 | ||||
|     TextureQueryLod,        /// (MetaTexture, float[N] coords) -> float4
 | ||||
|     TexelFetch,             /// (MetaTexture, int[N], int) -> float4
 | ||||
| 
 | ||||
|     Branch,        /// (uint branch_target) -> void
 | ||||
|     PushFlowStack, /// (uint branch_target) -> void
 | ||||
|     PopFlowStack,  /// () -> void
 | ||||
|     Exit,          /// () -> void
 | ||||
|     Discard,       /// () -> void
 | ||||
| 
 | ||||
|     EmitVertex,   /// () -> void
 | ||||
|     EndPrimitive, /// () -> void
 | ||||
| 
 | ||||
|     YNegate,            /// () -> float
 | ||||
|     LocalInvocationIdX, /// () -> uint
 | ||||
|     LocalInvocationIdY, /// () -> uint
 | ||||
|     LocalInvocationIdZ, /// () -> uint
 | ||||
|     WorkGroupIdX,       /// () -> uint
 | ||||
|     WorkGroupIdY,       /// () -> uint
 | ||||
|     WorkGroupIdZ,       /// () -> uint
 | ||||
| 
 | ||||
|     Amount, | ||||
| }; | ||||
| 
 | ||||
| enum class InternalFlag { | ||||
|     Zero = 0, | ||||
|     Sign = 1, | ||||
|     Carry = 2, | ||||
|     Overflow = 3, | ||||
|     Amount = 4, | ||||
| }; | ||||
| 
 | ||||
| class OperationNode; | ||||
| class ConditionalNode; | ||||
| class GprNode; | ||||
| class ImmediateNode; | ||||
| class InternalFlagNode; | ||||
| class PredicateNode; | ||||
| class AbufNode; | ||||
| class CbufNode; | ||||
| class LmemNode; | ||||
| class GmemNode; | ||||
| class CommentNode; | ||||
| 
 | ||||
| using NodeData = | ||||
|     std::variant<OperationNode, ConditionalNode, GprNode, ImmediateNode, InternalFlagNode, | ||||
|                  PredicateNode, AbufNode, CbufNode, LmemNode, GmemNode, CommentNode>; | ||||
| using Node = std::shared_ptr<NodeData>; | ||||
| using Node4 = std::array<Node, 4>; | ||||
| using NodeBlock = std::vector<Node>; | ||||
| 
 | ||||
| class Sampler { | ||||
| public: | ||||
|     /// This constructor is for bound samplers
 | ||||
|     explicit Sampler(std::size_t offset, std::size_t index, Tegra::Shader::TextureType type, | ||||
|                      bool is_array, bool is_shadow) | ||||
|         : offset{offset}, index{index}, type{type}, is_array{is_array}, is_shadow{is_shadow}, | ||||
|           is_bindless{false} {} | ||||
| 
 | ||||
|     /// This constructor is for bindless samplers
 | ||||
|     explicit Sampler(u32 cbuf_index, u32 cbuf_offset, std::size_t index, | ||||
|                      Tegra::Shader::TextureType type, bool is_array, bool is_shadow) | ||||
|         : offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type}, | ||||
|           is_array{is_array}, is_shadow{is_shadow}, is_bindless{true} {} | ||||
| 
 | ||||
|     /// This constructor is for serialization/deserialization
 | ||||
|     explicit Sampler(std::size_t offset, std::size_t index, Tegra::Shader::TextureType type, | ||||
|                      bool is_array, bool is_shadow, bool is_bindless) | ||||
|         : offset{offset}, index{index}, type{type}, is_array{is_array}, is_shadow{is_shadow}, | ||||
|           is_bindless{is_bindless} {} | ||||
| 
 | ||||
|     std::size_t GetOffset() const { | ||||
|         return offset; | ||||
|     } | ||||
| 
 | ||||
|     std::size_t GetIndex() const { | ||||
|         return index; | ||||
|     } | ||||
| 
 | ||||
|     Tegra::Shader::TextureType GetType() const { | ||||
|         return type; | ||||
|     } | ||||
| 
 | ||||
|     bool IsArray() const { | ||||
|         return is_array; | ||||
|     } | ||||
| 
 | ||||
|     bool IsShadow() const { | ||||
|         return is_shadow; | ||||
|     } | ||||
| 
 | ||||
|     bool IsBindless() const { | ||||
|         return is_bindless; | ||||
|     } | ||||
| 
 | ||||
|     std::pair<u32, u32> GetBindlessCBuf() const { | ||||
|         return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)}; | ||||
|     } | ||||
| 
 | ||||
|     bool operator<(const Sampler& rhs) const { | ||||
|         return std::tie(index, offset, type, is_array, is_shadow, is_bindless) < | ||||
|                std::tie(rhs.index, rhs.offset, rhs.type, rhs.is_array, rhs.is_shadow, | ||||
|                         rhs.is_bindless); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     /// Offset in TSC memory from which to read the sampler object, as specified by the sampling
 | ||||
|     /// instruction.
 | ||||
|     std::size_t offset{}; | ||||
|     std::size_t index{}; ///< Value used to index into the generated GLSL sampler array.
 | ||||
|     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_bindless{}; ///< Whether this sampler belongs to a bindless texture or not.
 | ||||
| }; | ||||
| 
 | ||||
| struct GlobalMemoryBase { | ||||
|     u32 cbuf_index{}; | ||||
|     u32 cbuf_offset{}; | ||||
| 
 | ||||
|     bool operator<(const GlobalMemoryBase& rhs) const { | ||||
|         return std::tie(cbuf_index, cbuf_offset) < std::tie(rhs.cbuf_index, rhs.cbuf_offset); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| /// Parameters describing an arithmetic operation
 | ||||
| struct MetaArithmetic { | ||||
|     bool precise{}; ///< Whether the operation can be constraint or not
 | ||||
| }; | ||||
| 
 | ||||
| /// Parameters describing a texture sampler
 | ||||
| struct MetaTexture { | ||||
|     const Sampler& sampler; | ||||
|     Node array; | ||||
|     Node depth_compare; | ||||
|     std::vector<Node> aoffi; | ||||
|     Node bias; | ||||
|     Node lod; | ||||
|     Node component{}; | ||||
|     u32 element{}; | ||||
| }; | ||||
| 
 | ||||
| /// Parameters that modify an operation but are not part of any particular operand
 | ||||
| using Meta = std::variant<MetaArithmetic, MetaTexture, Tegra::Shader::HalfType>; | ||||
| 
 | ||||
| /// Holds any kind of operation that can be done in the IR
 | ||||
| class OperationNode final { | ||||
| public: | ||||
|     explicit OperationNode(OperationCode code) : OperationNode(code, Meta{}) {} | ||||
| 
 | ||||
|     explicit OperationNode(OperationCode code, Meta meta) | ||||
|         : OperationNode(code, meta, std::vector<Node>{}) {} | ||||
| 
 | ||||
|     explicit OperationNode(OperationCode code, std::vector<Node> operands) | ||||
|         : OperationNode(code, Meta{}, std::move(operands)) {} | ||||
| 
 | ||||
|     explicit OperationNode(OperationCode code, Meta meta, std::vector<Node> operands) | ||||
|         : code{code}, meta{std::move(meta)}, operands{std::move(operands)} {} | ||||
| 
 | ||||
|     template <typename... Args> | ||||
|     explicit OperationNode(OperationCode code, Meta meta, Args&&... operands) | ||||
|         : code{code}, meta{std::move(meta)}, operands{operands...} {} | ||||
| 
 | ||||
|     OperationCode GetCode() const { | ||||
|         return code; | ||||
|     } | ||||
| 
 | ||||
|     const Meta& GetMeta() const { | ||||
|         return meta; | ||||
|     } | ||||
| 
 | ||||
|     std::size_t GetOperandsCount() const { | ||||
|         return operands.size(); | ||||
|     } | ||||
| 
 | ||||
|     const Node& operator[](std::size_t operand_index) const { | ||||
|         return operands.at(operand_index); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     OperationCode code{}; | ||||
|     Meta meta{}; | ||||
|     std::vector<Node> operands; | ||||
| }; | ||||
| 
 | ||||
| /// Encloses inside any kind of node that returns a boolean conditionally-executed code
 | ||||
| class ConditionalNode final { | ||||
| public: | ||||
|     explicit ConditionalNode(Node condition, std::vector<Node>&& code) | ||||
|         : condition{std::move(condition)}, code{std::move(code)} {} | ||||
| 
 | ||||
|     const Node& GetCondition() const { | ||||
|         return condition; | ||||
|     } | ||||
| 
 | ||||
|     const std::vector<Node>& GetCode() const { | ||||
|         return code; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     Node condition;         ///< Condition to be satisfied
 | ||||
|     std::vector<Node> code; ///< Code to execute
 | ||||
| }; | ||||
| 
 | ||||
| /// A general purpose register
 | ||||
| class GprNode final { | ||||
| public: | ||||
|     explicit constexpr GprNode(Tegra::Shader::Register index) : index{index} {} | ||||
| 
 | ||||
|     u32 GetIndex() const { | ||||
|         return static_cast<u32>(index); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     Tegra::Shader::Register index{}; | ||||
| }; | ||||
| 
 | ||||
| /// A 32-bits value that represents an immediate value
 | ||||
| class ImmediateNode final { | ||||
| public: | ||||
|     explicit constexpr ImmediateNode(u32 value) : value{value} {} | ||||
| 
 | ||||
|     u32 GetValue() const { | ||||
|         return value; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     u32 value{}; | ||||
| }; | ||||
| 
 | ||||
| /// One of Maxwell's internal flags
 | ||||
| class InternalFlagNode final { | ||||
| public: | ||||
|     explicit constexpr InternalFlagNode(InternalFlag flag) : flag{flag} {} | ||||
| 
 | ||||
|     InternalFlag GetFlag() const { | ||||
|         return flag; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     InternalFlag flag{}; | ||||
| }; | ||||
| 
 | ||||
| /// A predicate register, it can be negated without additional nodes
 | ||||
| class PredicateNode final { | ||||
| public: | ||||
|     explicit constexpr PredicateNode(Tegra::Shader::Pred index, bool negated) | ||||
|         : index{index}, negated{negated} {} | ||||
| 
 | ||||
|     Tegra::Shader::Pred GetIndex() const { | ||||
|         return index; | ||||
|     } | ||||
| 
 | ||||
|     bool IsNegated() const { | ||||
|         return negated; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     Tegra::Shader::Pred index{}; | ||||
|     bool negated{}; | ||||
| }; | ||||
| 
 | ||||
| /// Attribute buffer memory (known as attributes or varyings in GLSL terms)
 | ||||
| class AbufNode final { | ||||
| public: | ||||
|     // Initialize for standard attributes (index is explicit).
 | ||||
|     explicit AbufNode(Tegra::Shader::Attribute::Index index, u32 element, Node buffer = {}) | ||||
|         : buffer{std::move(buffer)}, index{index}, element{element} {} | ||||
| 
 | ||||
|     // Initialize for physical attributes (index is a variable value).
 | ||||
|     explicit AbufNode(Node physical_address, Node buffer = {}) | ||||
|         : physical_address{std::move(physical_address)}, buffer{std::move(buffer)} {} | ||||
| 
 | ||||
|     Tegra::Shader::Attribute::Index GetIndex() const { | ||||
|         return index; | ||||
|     } | ||||
| 
 | ||||
|     u32 GetElement() const { | ||||
|         return element; | ||||
|     } | ||||
| 
 | ||||
|     const Node& GetBuffer() const { | ||||
|         return buffer; | ||||
|     } | ||||
| 
 | ||||
|     bool IsPhysicalBuffer() const { | ||||
|         return static_cast<bool>(physical_address); | ||||
|     } | ||||
| 
 | ||||
|     const Node& GetPhysicalAddress() const { | ||||
|         return physical_address; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     Node physical_address; | ||||
|     Node buffer; | ||||
|     Tegra::Shader::Attribute::Index index{}; | ||||
|     u32 element{}; | ||||
| }; | ||||
| 
 | ||||
| /// Constant buffer node, usually mapped to uniform buffers in GLSL
 | ||||
| class CbufNode final { | ||||
| public: | ||||
|     explicit CbufNode(u32 index, Node offset) : index{index}, offset{std::move(offset)} {} | ||||
| 
 | ||||
|     u32 GetIndex() const { | ||||
|         return index; | ||||
|     } | ||||
| 
 | ||||
|     const Node& GetOffset() const { | ||||
|         return offset; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     u32 index{}; | ||||
|     Node offset; | ||||
| }; | ||||
| 
 | ||||
| /// Local memory node
 | ||||
| class LmemNode final { | ||||
| public: | ||||
|     explicit LmemNode(Node address) : address{std::move(address)} {} | ||||
| 
 | ||||
|     const Node& GetAddress() const { | ||||
|         return address; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     Node address; | ||||
| }; | ||||
| 
 | ||||
| /// Global memory node
 | ||||
| class GmemNode final { | ||||
| public: | ||||
|     explicit GmemNode(Node real_address, Node base_address, const GlobalMemoryBase& descriptor) | ||||
|         : real_address{std::move(real_address)}, base_address{std::move(base_address)}, | ||||
|           descriptor{descriptor} {} | ||||
| 
 | ||||
|     const Node& GetRealAddress() const { | ||||
|         return real_address; | ||||
|     } | ||||
| 
 | ||||
|     const Node& GetBaseAddress() const { | ||||
|         return base_address; | ||||
|     } | ||||
| 
 | ||||
|     const GlobalMemoryBase& GetDescriptor() const { | ||||
|         return descriptor; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     Node real_address; | ||||
|     Node base_address; | ||||
|     GlobalMemoryBase descriptor; | ||||
| }; | ||||
| 
 | ||||
| /// Commentary, can be dropped
 | ||||
| class CommentNode final { | ||||
| public: | ||||
|     explicit CommentNode(std::string text) : text{std::move(text)} {} | ||||
| 
 | ||||
|     const std::string& GetText() const { | ||||
|         return text; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     std::string text; | ||||
| }; | ||||
| 
 | ||||
| } // namespace VideoCommon::Shader
 | ||||
| @ -12,10 +12,15 @@ | ||||
| #include <vector> | ||||
| 
 | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| #include "video_core/shader/node.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
| 
 | ||||
| /// This arithmetic operation cannot be constraint
 | ||||
| inline constexpr MetaArithmetic PRECISE = {true}; | ||||
| /// This arithmetic operation can be optimized away
 | ||||
| inline constexpr MetaArithmetic NO_PRECISE = {false}; | ||||
| 
 | ||||
| /// Creates a conditional node
 | ||||
| Node Conditional(Node condition, std::vector<Node> code); | ||||
| 
 | ||||
|  | ||||
| @ -18,188 +18,14 @@ | ||||
| #include "video_core/engines/maxwell_3d.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/engines/shader_header.h" | ||||
| #include "video_core/shader/node.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
| 
 | ||||
| class OperationNode; | ||||
| class ConditionalNode; | ||||
| class GprNode; | ||||
| class ImmediateNode; | ||||
| class InternalFlagNode; | ||||
| class PredicateNode; | ||||
| class AbufNode; ///< Attribute buffer
 | ||||
| class CbufNode; ///< Constant buffer
 | ||||
| class LmemNode; ///< Local memory
 | ||||
| class GmemNode; ///< Global memory
 | ||||
| class CommentNode; | ||||
| 
 | ||||
| using ProgramCode = std::vector<u64>; | ||||
| 
 | ||||
| using NodeData = | ||||
|     std::variant<OperationNode, ConditionalNode, GprNode, ImmediateNode, InternalFlagNode, | ||||
|                  PredicateNode, AbufNode, CbufNode, LmemNode, GmemNode, CommentNode>; | ||||
| using Node = std::shared_ptr<NodeData>; | ||||
| using Node4 = std::array<Node, 4>; | ||||
| using NodeBlock = std::vector<Node>; | ||||
| 
 | ||||
| constexpr u32 MAX_PROGRAM_LENGTH = 0x1000; | ||||
| 
 | ||||
| enum class OperationCode { | ||||
|     Assign, /// (float& dest, float src) -> void
 | ||||
| 
 | ||||
|     Select, /// (MetaArithmetic, bool pred, float a, float b) -> float
 | ||||
| 
 | ||||
|     FAdd,          /// (MetaArithmetic, float a, float b) -> float
 | ||||
|     FMul,          /// (MetaArithmetic, float a, float b) -> float
 | ||||
|     FDiv,          /// (MetaArithmetic, float a, float b) -> float
 | ||||
|     FFma,          /// (MetaArithmetic, float a, float b, float c) -> float
 | ||||
|     FNegate,       /// (MetaArithmetic, float a) -> float
 | ||||
|     FAbsolute,     /// (MetaArithmetic, float a) -> float
 | ||||
|     FClamp,        /// (MetaArithmetic, float value, float min, float max) -> float
 | ||||
|     FMin,          /// (MetaArithmetic, float a, float b) -> float
 | ||||
|     FMax,          /// (MetaArithmetic, float a, float b) -> float
 | ||||
|     FCos,          /// (MetaArithmetic, float a) -> float
 | ||||
|     FSin,          /// (MetaArithmetic, float a) -> float
 | ||||
|     FExp2,         /// (MetaArithmetic, float a) -> float
 | ||||
|     FLog2,         /// (MetaArithmetic, float a) -> float
 | ||||
|     FInverseSqrt,  /// (MetaArithmetic, float a) -> float
 | ||||
|     FSqrt,         /// (MetaArithmetic, float a) -> float
 | ||||
|     FRoundEven,    /// (MetaArithmetic, float a) -> float
 | ||||
|     FFloor,        /// (MetaArithmetic, float a) -> float
 | ||||
|     FCeil,         /// (MetaArithmetic, float a) -> float
 | ||||
|     FTrunc,        /// (MetaArithmetic, float a) -> float
 | ||||
|     FCastInteger,  /// (MetaArithmetic, int a) -> float
 | ||||
|     FCastUInteger, /// (MetaArithmetic, uint a) -> float
 | ||||
| 
 | ||||
|     IAdd,                  /// (MetaArithmetic, int a, int b) -> int
 | ||||
|     IMul,                  /// (MetaArithmetic, int a, int b) -> int
 | ||||
|     IDiv,                  /// (MetaArithmetic, int a, int b) -> int
 | ||||
|     INegate,               /// (MetaArithmetic, int a) -> int
 | ||||
|     IAbsolute,             /// (MetaArithmetic, int a) -> int
 | ||||
|     IMin,                  /// (MetaArithmetic, int a, int b) -> int
 | ||||
|     IMax,                  /// (MetaArithmetic, int a, int b) -> int
 | ||||
|     ICastFloat,            /// (MetaArithmetic, float a) -> int
 | ||||
|     ICastUnsigned,         /// (MetaArithmetic, uint a) -> int
 | ||||
|     ILogicalShiftLeft,     /// (MetaArithmetic, int a, uint b) -> int
 | ||||
|     ILogicalShiftRight,    /// (MetaArithmetic, int a, uint b) -> int
 | ||||
|     IArithmeticShiftRight, /// (MetaArithmetic, int a, uint b) -> int
 | ||||
|     IBitwiseAnd,           /// (MetaArithmetic, int a, int b) -> int
 | ||||
|     IBitwiseOr,            /// (MetaArithmetic, int a, int b) -> int
 | ||||
|     IBitwiseXor,           /// (MetaArithmetic, int a, int b) -> int
 | ||||
|     IBitwiseNot,           /// (MetaArithmetic, int a) -> int
 | ||||
|     IBitfieldInsert,       /// (MetaArithmetic, int base, int insert, int offset, int bits) -> int
 | ||||
|     IBitfieldExtract,      /// (MetaArithmetic, int value, int offset, int offset) -> int
 | ||||
|     IBitCount,             /// (MetaArithmetic, int) -> int
 | ||||
| 
 | ||||
|     UAdd,                  /// (MetaArithmetic, uint a, uint b) -> uint
 | ||||
|     UMul,                  /// (MetaArithmetic, uint a, uint b) -> uint
 | ||||
|     UDiv,                  /// (MetaArithmetic, uint a, uint b) -> uint
 | ||||
|     UMin,                  /// (MetaArithmetic, uint a, uint b) -> uint
 | ||||
|     UMax,                  /// (MetaArithmetic, uint a, uint b) -> uint
 | ||||
|     UCastFloat,            /// (MetaArithmetic, float a) -> uint
 | ||||
|     UCastSigned,           /// (MetaArithmetic, int a) -> uint
 | ||||
|     ULogicalShiftLeft,     /// (MetaArithmetic, uint a, uint b) -> uint
 | ||||
|     ULogicalShiftRight,    /// (MetaArithmetic, uint a, uint b) -> uint
 | ||||
|     UArithmeticShiftRight, /// (MetaArithmetic, uint a, uint b) -> uint
 | ||||
|     UBitwiseAnd,           /// (MetaArithmetic, uint a, uint b) -> uint
 | ||||
|     UBitwiseOr,            /// (MetaArithmetic, uint a, uint b) -> uint
 | ||||
|     UBitwiseXor,           /// (MetaArithmetic, uint a, uint b) -> uint
 | ||||
|     UBitwiseNot,           /// (MetaArithmetic, uint a) -> uint
 | ||||
|     UBitfieldInsert,  /// (MetaArithmetic, uint base, uint insert, int offset, int bits) -> uint
 | ||||
|     UBitfieldExtract, /// (MetaArithmetic, uint value, int offset, int offset) -> uint
 | ||||
|     UBitCount,        /// (MetaArithmetic, uint) -> uint
 | ||||
| 
 | ||||
|     HAdd,      /// (MetaArithmetic, f16vec2 a, f16vec2 b) -> f16vec2
 | ||||
|     HMul,      /// (MetaArithmetic, f16vec2 a, f16vec2 b) -> f16vec2
 | ||||
|     HFma,      /// (MetaArithmetic, f16vec2 a, f16vec2 b, f16vec2 c) -> f16vec2
 | ||||
|     HAbsolute, /// (f16vec2 a) -> f16vec2
 | ||||
|     HNegate,   /// (f16vec2 a, bool first, bool second) -> f16vec2
 | ||||
|     HClamp,    /// (f16vec2 src, float min, float max) -> f16vec2
 | ||||
|     HUnpack,   /// (Tegra::Shader::HalfType, T value) -> f16vec2
 | ||||
|     HMergeF32, /// (f16vec2 src) -> float
 | ||||
|     HMergeH0,  /// (f16vec2 dest, f16vec2 src) -> f16vec2
 | ||||
|     HMergeH1,  /// (f16vec2 dest, f16vec2 src) -> f16vec2
 | ||||
|     HPack2,    /// (float a, float b) -> f16vec2
 | ||||
| 
 | ||||
|     LogicalAssign, /// (bool& dst, bool src) -> void
 | ||||
|     LogicalAnd,    /// (bool a, bool b) -> bool
 | ||||
|     LogicalOr,     /// (bool a, bool b) -> bool
 | ||||
|     LogicalXor,    /// (bool a, bool b) -> bool
 | ||||
|     LogicalNegate, /// (bool a) -> bool
 | ||||
|     LogicalPick2,  /// (bool2 pair, uint index) -> bool
 | ||||
|     LogicalAll2,   /// (bool2 a) -> bool
 | ||||
|     LogicalAny2,   /// (bool2 a) -> bool
 | ||||
| 
 | ||||
|     LogicalFLessThan,     /// (float a, float b) -> bool
 | ||||
|     LogicalFEqual,        /// (float a, float b) -> bool
 | ||||
|     LogicalFLessEqual,    /// (float a, float b) -> bool
 | ||||
|     LogicalFGreaterThan,  /// (float a, float b) -> bool
 | ||||
|     LogicalFNotEqual,     /// (float a, float b) -> bool
 | ||||
|     LogicalFGreaterEqual, /// (float a, float b) -> bool
 | ||||
|     LogicalFIsNan,        /// (float a) -> bool
 | ||||
| 
 | ||||
|     LogicalILessThan,     /// (int a, int b) -> bool
 | ||||
|     LogicalIEqual,        /// (int a, int b) -> bool
 | ||||
|     LogicalILessEqual,    /// (int a, int b) -> bool
 | ||||
|     LogicalIGreaterThan,  /// (int a, int b) -> bool
 | ||||
|     LogicalINotEqual,     /// (int a, int b) -> bool
 | ||||
|     LogicalIGreaterEqual, /// (int a, int b) -> bool
 | ||||
| 
 | ||||
|     LogicalULessThan,     /// (uint a, uint b) -> bool
 | ||||
|     LogicalUEqual,        /// (uint a, uint b) -> bool
 | ||||
|     LogicalULessEqual,    /// (uint a, uint b) -> bool
 | ||||
|     LogicalUGreaterThan,  /// (uint a, uint b) -> bool
 | ||||
|     LogicalUNotEqual,     /// (uint a, uint b) -> bool
 | ||||
|     LogicalUGreaterEqual, /// (uint a, uint b) -> bool
 | ||||
| 
 | ||||
|     Logical2HLessThan,            /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
|     Logical2HEqual,               /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
|     Logical2HLessEqual,           /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
|     Logical2HGreaterThan,         /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
|     Logical2HNotEqual,            /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
|     Logical2HGreaterEqual,        /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
|     Logical2HLessThanWithNan,     /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
|     Logical2HEqualWithNan,        /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
|     Logical2HLessEqualWithNan,    /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
|     Logical2HGreaterThanWithNan,  /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
|     Logical2HNotEqualWithNan,     /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
|     Logical2HGreaterEqualWithNan, /// (MetaHalfArithmetic, f16vec2 a, f16vec2) -> bool2
 | ||||
| 
 | ||||
|     Texture,                /// (MetaTexture, float[N] coords) -> float4
 | ||||
|     TextureLod,             /// (MetaTexture, float[N] coords) -> float4
 | ||||
|     TextureGather,          /// (MetaTexture, float[N] coords) -> float4
 | ||||
|     TextureQueryDimensions, /// (MetaTexture, float a) -> float4
 | ||||
|     TextureQueryLod,        /// (MetaTexture, float[N] coords) -> float4
 | ||||
|     TexelFetch,             /// (MetaTexture, int[N], int) -> float4
 | ||||
| 
 | ||||
|     Branch,        /// (uint branch_target) -> void
 | ||||
|     PushFlowStack, /// (uint branch_target) -> void
 | ||||
|     PopFlowStack,  /// () -> void
 | ||||
|     Exit,          /// () -> void
 | ||||
|     Discard,       /// () -> void
 | ||||
| 
 | ||||
|     EmitVertex,   /// () -> void
 | ||||
|     EndPrimitive, /// () -> void
 | ||||
| 
 | ||||
|     YNegate,            /// () -> float
 | ||||
|     LocalInvocationIdX, /// () -> uint
 | ||||
|     LocalInvocationIdY, /// () -> uint
 | ||||
|     LocalInvocationIdZ, /// () -> uint
 | ||||
|     WorkGroupIdX,       /// () -> uint
 | ||||
|     WorkGroupIdY,       /// () -> uint
 | ||||
|     WorkGroupIdZ,       /// () -> uint
 | ||||
| 
 | ||||
|     Amount, | ||||
| }; | ||||
| 
 | ||||
| enum class InternalFlag { | ||||
|     Zero = 0, | ||||
|     Sign = 1, | ||||
|     Carry = 2, | ||||
|     Overflow = 3, | ||||
|     Amount = 4, | ||||
| }; | ||||
| 
 | ||||
| /// Describes the behaviour of code path of a given entry point and a return point.
 | ||||
| enum class ExitMethod { | ||||
|     Undetermined, ///< Internal value. Only occur when analyzing JMP loop.
 | ||||
| @ -208,71 +34,6 @@ enum class ExitMethod { | ||||
|     AlwaysEnd,    ///< All code paths reach a END instruction.
 | ||||
| }; | ||||
| 
 | ||||
| class Sampler { | ||||
| public: | ||||
|     // Use this constructor for bounded Samplers
 | ||||
|     explicit Sampler(std::size_t offset, std::size_t index, Tegra::Shader::TextureType type, | ||||
|                      bool is_array, bool is_shadow) | ||||
|         : offset{offset}, index{index}, type{type}, is_array{is_array}, is_shadow{is_shadow}, | ||||
|           is_bindless{false} {} | ||||
| 
 | ||||
|     // Use this constructor for bindless Samplers
 | ||||
|     explicit Sampler(u32 cbuf_index, u32 cbuf_offset, std::size_t index, | ||||
|                      Tegra::Shader::TextureType type, bool is_array, bool is_shadow) | ||||
|         : offset{(static_cast<u64>(cbuf_index) << 32) | cbuf_offset}, index{index}, type{type}, | ||||
|           is_array{is_array}, is_shadow{is_shadow}, is_bindless{true} {} | ||||
| 
 | ||||
|     // Use this only for serialization/deserialization
 | ||||
|     explicit Sampler(std::size_t offset, std::size_t index, Tegra::Shader::TextureType type, | ||||
|                      bool is_array, bool is_shadow, bool is_bindless) | ||||
|         : offset{offset}, index{index}, type{type}, is_array{is_array}, is_shadow{is_shadow}, | ||||
|           is_bindless{is_bindless} {} | ||||
| 
 | ||||
|     std::size_t GetOffset() const { | ||||
|         return offset; | ||||
|     } | ||||
| 
 | ||||
|     std::size_t GetIndex() const { | ||||
|         return index; | ||||
|     } | ||||
| 
 | ||||
|     Tegra::Shader::TextureType GetType() const { | ||||
|         return type; | ||||
|     } | ||||
| 
 | ||||
|     bool IsArray() const { | ||||
|         return is_array; | ||||
|     } | ||||
| 
 | ||||
|     bool IsShadow() const { | ||||
|         return is_shadow; | ||||
|     } | ||||
| 
 | ||||
|     bool IsBindless() const { | ||||
|         return is_bindless; | ||||
|     } | ||||
| 
 | ||||
|     std::pair<u32, u32> GetBindlessCBuf() const { | ||||
|         return {static_cast<u32>(offset >> 32), static_cast<u32>(offset)}; | ||||
|     } | ||||
| 
 | ||||
|     bool operator<(const Sampler& rhs) const { | ||||
|         return std::tie(index, offset, type, is_array, is_shadow, is_bindless) < | ||||
|                std::tie(rhs.index, rhs.offset, rhs.type, rhs.is_array, rhs.is_shadow, | ||||
|                         rhs.is_bindless); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     /// Offset in TSC memory from which to read the sampler object, as specified by the sampling
 | ||||
|     /// instruction.
 | ||||
|     std::size_t offset{}; | ||||
|     std::size_t index{}; ///< Value used to index into the generated GLSL sampler array.
 | ||||
|     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_bindless{}; ///< Whether this sampler belongs to a bindless texture or not.
 | ||||
| }; | ||||
| 
 | ||||
| class ConstBuffer { | ||||
| public: | ||||
|     explicit ConstBuffer(u32 max_offset, bool is_indirect) | ||||
| @ -305,263 +66,11 @@ private: | ||||
|     bool is_indirect{}; | ||||
| }; | ||||
| 
 | ||||
| struct GlobalMemoryBase { | ||||
|     u32 cbuf_index{}; | ||||
|     u32 cbuf_offset{}; | ||||
| 
 | ||||
|     bool operator<(const GlobalMemoryBase& rhs) const { | ||||
|         return std::tie(cbuf_index, cbuf_offset) < std::tie(rhs.cbuf_index, rhs.cbuf_offset); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| struct GlobalMemoryUsage { | ||||
|     bool is_read{}; | ||||
|     bool is_written{}; | ||||
| }; | ||||
| 
 | ||||
| struct MetaArithmetic { | ||||
|     bool precise{}; | ||||
| }; | ||||
| 
 | ||||
| struct MetaTexture { | ||||
|     const Sampler& sampler; | ||||
|     Node array{}; | ||||
|     Node depth_compare{}; | ||||
|     std::vector<Node> aoffi; | ||||
|     Node bias{}; | ||||
|     Node lod{}; | ||||
|     Node component{}; | ||||
|     u32 element{}; | ||||
| }; | ||||
| 
 | ||||
| constexpr MetaArithmetic PRECISE = {true}; | ||||
| constexpr MetaArithmetic NO_PRECISE = {false}; | ||||
| 
 | ||||
| using Meta = std::variant<MetaArithmetic, MetaTexture, Tegra::Shader::HalfType>; | ||||
| 
 | ||||
| /// Holds any kind of operation that can be done in the IR
 | ||||
| class OperationNode final { | ||||
| public: | ||||
|     explicit OperationNode(OperationCode code) : OperationNode(code, Meta{}) {} | ||||
| 
 | ||||
|     explicit OperationNode(OperationCode code, Meta meta) | ||||
|         : OperationNode(code, meta, std::vector<Node>{}) {} | ||||
| 
 | ||||
|     explicit OperationNode(OperationCode code, std::vector<Node> operands) | ||||
|         : OperationNode(code, Meta{}, std::move(operands)) {} | ||||
| 
 | ||||
|     explicit OperationNode(OperationCode code, Meta meta, std::vector<Node> operands) | ||||
|         : code{code}, meta{std::move(meta)}, operands{std::move(operands)} {} | ||||
| 
 | ||||
|     template <typename... Args> | ||||
|     explicit OperationNode(OperationCode code, Meta meta, Args&&... operands) | ||||
|         : code{code}, meta{std::move(meta)}, operands{operands...} {} | ||||
| 
 | ||||
|     OperationCode GetCode() const { | ||||
|         return code; | ||||
|     } | ||||
| 
 | ||||
|     const Meta& GetMeta() const { | ||||
|         return meta; | ||||
|     } | ||||
| 
 | ||||
|     std::size_t GetOperandsCount() const { | ||||
|         return operands.size(); | ||||
|     } | ||||
| 
 | ||||
|     const Node& operator[](std::size_t operand_index) const { | ||||
|         return operands.at(operand_index); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     OperationCode code{}; | ||||
|     Meta meta{}; | ||||
|     std::vector<Node> operands; | ||||
| }; | ||||
| 
 | ||||
| /// Encloses inside any kind of node that returns a boolean conditionally-executed code
 | ||||
| class ConditionalNode final { | ||||
| public: | ||||
|     explicit ConditionalNode(Node condition, std::vector<Node>&& code) | ||||
|         : condition{condition}, code{std::move(code)} {} | ||||
| 
 | ||||
|     Node GetCondition() const { | ||||
|         return condition; | ||||
|     } | ||||
| 
 | ||||
|     const std::vector<Node>& GetCode() const { | ||||
|         return code; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     const Node condition;   ///< Condition to be satisfied
 | ||||
|     std::vector<Node> code; ///< Code to execute
 | ||||
| }; | ||||
| 
 | ||||
| /// A general purpose register
 | ||||
| class GprNode final { | ||||
| public: | ||||
|     explicit constexpr GprNode(Tegra::Shader::Register index) : index{index} {} | ||||
| 
 | ||||
|     u32 GetIndex() const { | ||||
|         return static_cast<u32>(index); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     const Tegra::Shader::Register index; | ||||
| }; | ||||
| 
 | ||||
| /// A 32-bits value that represents an immediate value
 | ||||
| class ImmediateNode final { | ||||
| public: | ||||
|     explicit constexpr ImmediateNode(u32 value) : value{value} {} | ||||
| 
 | ||||
|     u32 GetValue() const { | ||||
|         return value; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     const u32 value; | ||||
| }; | ||||
| 
 | ||||
| /// One of Maxwell's internal flags
 | ||||
| class InternalFlagNode final { | ||||
| public: | ||||
|     explicit constexpr InternalFlagNode(InternalFlag flag) : flag{flag} {} | ||||
| 
 | ||||
|     InternalFlag GetFlag() const { | ||||
|         return flag; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     const InternalFlag flag; | ||||
| }; | ||||
| 
 | ||||
| /// A predicate register, it can be negated without additional nodes
 | ||||
| class PredicateNode final { | ||||
| public: | ||||
|     explicit constexpr PredicateNode(Tegra::Shader::Pred index, bool negated) | ||||
|         : index{index}, negated{negated} {} | ||||
| 
 | ||||
|     Tegra::Shader::Pred GetIndex() const { | ||||
|         return index; | ||||
|     } | ||||
| 
 | ||||
|     bool IsNegated() const { | ||||
|         return negated; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     const Tegra::Shader::Pred index; | ||||
|     const bool negated; | ||||
| }; | ||||
| 
 | ||||
| /// Attribute buffer memory (known as attributes or varyings in GLSL terms)
 | ||||
| class AbufNode final { | ||||
| public: | ||||
|     // Initialize for standard attributes (index is explicit).
 | ||||
|     explicit AbufNode(Tegra::Shader::Attribute::Index index, u32 element, Node buffer = {}) | ||||
|         : buffer{std::move(buffer)}, index{index}, element{element} {} | ||||
| 
 | ||||
|     // Initialize for physical attributes (index is a variable value).
 | ||||
|     explicit AbufNode(Node physical_address, Node buffer = {}) | ||||
|         : physical_address{physical_address}, buffer{std::move(buffer)} {} | ||||
| 
 | ||||
|     Tegra::Shader::Attribute::Index GetIndex() const { | ||||
|         return index; | ||||
|     } | ||||
| 
 | ||||
|     u32 GetElement() const { | ||||
|         return element; | ||||
|     } | ||||
| 
 | ||||
|     Node GetBuffer() const { | ||||
|         return buffer; | ||||
|     } | ||||
| 
 | ||||
|     bool IsPhysicalBuffer() const { | ||||
|         return static_cast<bool>(physical_address); | ||||
|     } | ||||
| 
 | ||||
|     const Node& GetPhysicalAddress() const { | ||||
|         return physical_address; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     Node physical_address; | ||||
|     Node buffer; | ||||
|     Tegra::Shader::Attribute::Index index{}; | ||||
|     u32 element{}; | ||||
| }; | ||||
| 
 | ||||
| /// Constant buffer node, usually mapped to uniform buffers in GLSL
 | ||||
| class CbufNode final { | ||||
| public: | ||||
|     explicit CbufNode(u32 index, Node offset) : index{index}, offset{offset} {} | ||||
| 
 | ||||
|     u32 GetIndex() const { | ||||
|         return index; | ||||
|     } | ||||
| 
 | ||||
|     Node GetOffset() const { | ||||
|         return offset; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     const u32 index; | ||||
|     const Node offset; | ||||
| }; | ||||
| 
 | ||||
| /// Local memory node
 | ||||
| class LmemNode final { | ||||
| public: | ||||
|     explicit LmemNode(Node address) : address{address} {} | ||||
| 
 | ||||
|     Node GetAddress() const { | ||||
|         return address; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     const Node address; | ||||
| }; | ||||
| 
 | ||||
| /// Global memory node
 | ||||
| class GmemNode final { | ||||
| public: | ||||
|     explicit GmemNode(Node real_address, Node base_address, const GlobalMemoryBase& descriptor) | ||||
|         : real_address{real_address}, base_address{base_address}, descriptor{descriptor} {} | ||||
| 
 | ||||
|     Node GetRealAddress() const { | ||||
|         return real_address; | ||||
|     } | ||||
| 
 | ||||
|     Node GetBaseAddress() const { | ||||
|         return base_address; | ||||
|     } | ||||
| 
 | ||||
|     const GlobalMemoryBase& GetDescriptor() const { | ||||
|         return descriptor; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     const Node real_address; | ||||
|     const Node base_address; | ||||
|     const GlobalMemoryBase descriptor; | ||||
| }; | ||||
| 
 | ||||
| /// Commentary, can be dropped
 | ||||
| class CommentNode final { | ||||
| public: | ||||
|     explicit CommentNode(std::string text) : text{std::move(text)} {} | ||||
| 
 | ||||
|     const std::string& GetText() const { | ||||
|         return text; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     std::string text; | ||||
| }; | ||||
| 
 | ||||
| class ShaderIR final { | ||||
| public: | ||||
|     explicit ShaderIR(const ProgramCode& program_code, u32 main_offset); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 bunnei
						bunnei