mirror of
				https://git.suyu.dev/suyu/suyu.git
				synced 2025-10-31 23:06:43 +08:00 
			
		
		
		
	Merge pull request #2552 from ReinUsesLisp/shader-shared-ptr
shader: Use shared_ptr to store nodes and move initialization to file
This commit is contained in:
		
						commit
						04ac7a637a
					
				| @ -102,6 +102,8 @@ add_library(video_core STATIC | ||||
|     shader/decode/xmad.cpp | ||||
|     shader/decode/other.cpp | ||||
|     shader/decode.cpp | ||||
|     shader/node_helper.cpp | ||||
|     shader/node_helper.h | ||||
|     shader/shader_ir.cpp | ||||
|     shader/shader_ir.h | ||||
|     shader/track.cpp | ||||
|  | ||||
| @ -123,8 +123,8 @@ bool IsPrecise(Operation operand) { | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| bool IsPrecise(Node node) { | ||||
|     if (const auto operation = std::get_if<OperationNode>(node)) { | ||||
| bool IsPrecise(const Node& node) { | ||||
|     if (const auto operation = std::get_if<OperationNode>(&*node)) { | ||||
|         return IsPrecise(*operation); | ||||
|     } | ||||
|     return false; | ||||
| @ -497,15 +497,15 @@ private: | ||||
|     } | ||||
| 
 | ||||
|     void VisitBlock(const NodeBlock& bb) { | ||||
|         for (const Node node : bb) { | ||||
|         for (const auto& node : bb) { | ||||
|             if (const std::string expr = Visit(node); !expr.empty()) { | ||||
|                 code.AddLine(expr); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     std::string Visit(Node node) { | ||||
|         if (const auto operation = std::get_if<OperationNode>(node)) { | ||||
|     std::string Visit(const Node& node) { | ||||
|         if (const auto operation = std::get_if<OperationNode>(&*node)) { | ||||
|             const auto operation_index = static_cast<std::size_t>(operation->GetCode()); | ||||
|             if (operation_index >= operation_decompilers.size()) { | ||||
|                 UNREACHABLE_MSG("Out of bounds operation: {}", operation_index); | ||||
| @ -519,7 +519,7 @@ private: | ||||
|             return (this->*decompiler)(*operation); | ||||
|         } | ||||
| 
 | ||||
|         if (const auto gpr = std::get_if<GprNode>(node)) { | ||||
|         if (const auto gpr = std::get_if<GprNode>(&*node)) { | ||||
|             const u32 index = gpr->GetIndex(); | ||||
|             if (index == Register::ZeroIndex) { | ||||
|                 return "0"; | ||||
| @ -527,7 +527,7 @@ private: | ||||
|             return GetRegister(index); | ||||
|         } | ||||
| 
 | ||||
|         if (const auto immediate = std::get_if<ImmediateNode>(node)) { | ||||
|         if (const auto immediate = std::get_if<ImmediateNode>(&*node)) { | ||||
|             const u32 value = immediate->GetValue(); | ||||
|             if (value < 10) { | ||||
|                 // For eyecandy avoid using hex numbers on single digits
 | ||||
| @ -536,7 +536,7 @@ private: | ||||
|             return fmt::format("utof(0x{:x}u)", immediate->GetValue()); | ||||
|         } | ||||
| 
 | ||||
|         if (const auto predicate = std::get_if<PredicateNode>(node)) { | ||||
|         if (const auto predicate = std::get_if<PredicateNode>(&*node)) { | ||||
|             const auto value = [&]() -> std::string { | ||||
|                 switch (const auto index = predicate->GetIndex(); index) { | ||||
|                 case Tegra::Shader::Pred::UnusedIndex: | ||||
| @ -553,7 +553,7 @@ private: | ||||
|             return value; | ||||
|         } | ||||
| 
 | ||||
|         if (const auto abuf = std::get_if<AbufNode>(node)) { | ||||
|         if (const auto abuf = std::get_if<AbufNode>(&*node)) { | ||||
|             UNIMPLEMENTED_IF_MSG(abuf->IsPhysicalBuffer() && stage == ShaderStage::Geometry, | ||||
|                                  "Physical attributes in geometry shaders are not implemented"); | ||||
|             if (abuf->IsPhysicalBuffer()) { | ||||
| @ -563,9 +563,9 @@ private: | ||||
|             return ReadAttribute(abuf->GetIndex(), abuf->GetElement(), abuf->GetBuffer()); | ||||
|         } | ||||
| 
 | ||||
|         if (const auto cbuf = std::get_if<CbufNode>(node)) { | ||||
|         if (const auto cbuf = std::get_if<CbufNode>(&*node)) { | ||||
|             const Node offset = cbuf->GetOffset(); | ||||
|             if (const auto immediate = std::get_if<ImmediateNode>(offset)) { | ||||
|             if (const auto immediate = std::get_if<ImmediateNode>(&*offset)) { | ||||
|                 // Direct access
 | ||||
|                 const u32 offset_imm = immediate->GetValue(); | ||||
|                 ASSERT_MSG(offset_imm % 4 == 0, "Unaligned cbuf direct access"); | ||||
| @ -601,22 +601,22 @@ private: | ||||
|             UNREACHABLE_MSG("Unmanaged offset node type"); | ||||
|         } | ||||
| 
 | ||||
|         if (const auto gmem = std::get_if<GmemNode>(node)) { | ||||
|         if (const auto gmem = std::get_if<GmemNode>(&*node)) { | ||||
|             const std::string real = Visit(gmem->GetRealAddress()); | ||||
|             const std::string base = Visit(gmem->GetBaseAddress()); | ||||
|             const std::string final_offset = fmt::format("(ftou({}) - ftou({})) / 4", real, base); | ||||
|             return fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset); | ||||
|         } | ||||
| 
 | ||||
|         if (const auto lmem = std::get_if<LmemNode>(node)) { | ||||
|         if (const auto lmem = std::get_if<LmemNode>(&*node)) { | ||||
|             return fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress())); | ||||
|         } | ||||
| 
 | ||||
|         if (const auto internal_flag = std::get_if<InternalFlagNode>(node)) { | ||||
|         if (const auto internal_flag = std::get_if<InternalFlagNode>(&*node)) { | ||||
|             return GetInternalFlag(internal_flag->GetFlag()); | ||||
|         } | ||||
| 
 | ||||
|         if (const auto conditional = std::get_if<ConditionalNode>(node)) { | ||||
|         if (const auto conditional = std::get_if<ConditionalNode>(&*node)) { | ||||
|             // It's invalid to call conditional on nested nodes, use an operation instead
 | ||||
|             code.AddLine("if ({}) {{", Visit(conditional->GetCondition())); | ||||
|             ++code.scope; | ||||
| @ -628,7 +628,7 @@ private: | ||||
|             return {}; | ||||
|         } | ||||
| 
 | ||||
|         if (const auto comment = std::get_if<CommentNode>(node)) { | ||||
|         if (const auto comment = std::get_if<CommentNode>(&*node)) { | ||||
|             return "// " + comment->GetText(); | ||||
|         } | ||||
| 
 | ||||
| @ -636,7 +636,7 @@ private: | ||||
|         return {}; | ||||
|     } | ||||
| 
 | ||||
|     std::string ReadAttribute(Attribute::Index attribute, u32 element, Node buffer = {}) { | ||||
|     std::string ReadAttribute(Attribute::Index attribute, u32 element, const Node& buffer = {}) { | ||||
|         const auto GeometryPass = [&](std::string_view name) { | ||||
|             if (stage == ShaderStage::Geometry && buffer) { | ||||
|                 // TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games
 | ||||
| @ -872,7 +872,7 @@ private: | ||||
|         std::string expr = ", "; | ||||
|         switch (type) { | ||||
|         case Type::Int: | ||||
|             if (const auto immediate = std::get_if<ImmediateNode>(operand)) { | ||||
|             if (const auto immediate = std::get_if<ImmediateNode>(&*operand)) { | ||||
|                 // Inline the string as an immediate integer in GLSL (some extra arguments are
 | ||||
|                 // required to be constant)
 | ||||
|                 expr += std::to_string(static_cast<s32>(immediate->GetValue())); | ||||
| @ -904,7 +904,7 @@ private: | ||||
| 
 | ||||
|         for (std::size_t index = 0; index < aoffi.size(); ++index) { | ||||
|             const auto operand{aoffi.at(index)}; | ||||
|             if (const auto immediate = std::get_if<ImmediateNode>(operand)) { | ||||
|             if (const auto immediate = std::get_if<ImmediateNode>(&*operand)) { | ||||
|                 // Inline the string as an immediate integer in GLSL (AOFFI arguments are required
 | ||||
|                 // to be constant by the standard).
 | ||||
|                 expr += std::to_string(static_cast<s32>(immediate->GetValue())); | ||||
| @ -925,17 +925,17 @@ private: | ||||
|     } | ||||
| 
 | ||||
|     std::string Assign(Operation operation) { | ||||
|         const Node dest = operation[0]; | ||||
|         const Node src = operation[1]; | ||||
|         const Node& dest = operation[0]; | ||||
|         const Node& src = operation[1]; | ||||
| 
 | ||||
|         std::string target; | ||||
|         if (const auto gpr = std::get_if<GprNode>(dest)) { | ||||
|         if (const auto gpr = std::get_if<GprNode>(&*dest)) { | ||||
|             if (gpr->GetIndex() == Register::ZeroIndex) { | ||||
|                 // Writing to Register::ZeroIndex is a no op
 | ||||
|                 return {}; | ||||
|             } | ||||
|             target = GetRegister(gpr->GetIndex()); | ||||
|         } else if (const auto abuf = std::get_if<AbufNode>(dest)) { | ||||
|         } else if (const auto abuf = std::get_if<AbufNode>(&*dest)) { | ||||
|             UNIMPLEMENTED_IF(abuf->IsPhysicalBuffer()); | ||||
| 
 | ||||
|             target = [&]() -> std::string { | ||||
| @ -957,9 +957,9 @@ private: | ||||
|                     return "0"; | ||||
|                 } | ||||
|             }(); | ||||
|         } else if (const auto lmem = std::get_if<LmemNode>(dest)) { | ||||
|         } else if (const auto lmem = std::get_if<LmemNode>(&*dest)) { | ||||
|             target = fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress())); | ||||
|         } else if (const auto gmem = std::get_if<GmemNode>(dest)) { | ||||
|         } else if (const auto gmem = std::get_if<GmemNode>(&*dest)) { | ||||
|             const std::string real = Visit(gmem->GetRealAddress()); | ||||
|             const std::string base = Visit(gmem->GetBaseAddress()); | ||||
|             const std::string final_offset = fmt::format("(ftou({}) - ftou({})) / 4", real, base); | ||||
| @ -1236,12 +1236,12 @@ private: | ||||
|     } | ||||
| 
 | ||||
|     std::string LogicalAssign(Operation operation) { | ||||
|         const Node dest = operation[0]; | ||||
|         const Node src = operation[1]; | ||||
|         const Node& dest = operation[0]; | ||||
|         const Node& src = operation[1]; | ||||
| 
 | ||||
|         std::string target; | ||||
| 
 | ||||
|         if (const auto pred = std::get_if<PredicateNode>(dest)) { | ||||
|         if (const auto pred = std::get_if<PredicateNode>(&*dest)) { | ||||
|             ASSERT_MSG(!pred->IsNegated(), "Negating logical assignment"); | ||||
| 
 | ||||
|             const auto index = pred->GetIndex(); | ||||
| @ -1252,7 +1252,7 @@ private: | ||||
|                 return {}; | ||||
|             } | ||||
|             target = GetPredicate(index); | ||||
|         } else if (const auto flag = std::get_if<InternalFlagNode>(dest)) { | ||||
|         } else if (const auto flag = std::get_if<InternalFlagNode>(&*dest)) { | ||||
|             target = GetInternalFlag(flag->GetFlag()); | ||||
|         } | ||||
| 
 | ||||
| @ -1429,7 +1429,7 @@ private: | ||||
|     } | ||||
| 
 | ||||
|     std::string Branch(Operation operation) { | ||||
|         const auto target = std::get_if<ImmediateNode>(operation[0]); | ||||
|         const auto target = std::get_if<ImmediateNode>(&*operation[0]); | ||||
|         UNIMPLEMENTED_IF(!target); | ||||
| 
 | ||||
|         code.AddLine("jmp_to = 0x{:x}u;", target->GetValue()); | ||||
| @ -1438,7 +1438,7 @@ private: | ||||
|     } | ||||
| 
 | ||||
|     std::string PushFlowStack(Operation operation) { | ||||
|         const auto target = std::get_if<ImmediateNode>(operation[0]); | ||||
|         const auto target = std::get_if<ImmediateNode>(&*operation[0]); | ||||
|         UNIMPLEMENTED_IF(!target); | ||||
| 
 | ||||
|         code.AddLine("flow_stack[flow_stack_top++] = 0x{:x}u;", target->GetValue()); | ||||
|  | ||||
| @ -481,13 +481,13 @@ private: | ||||
|     } | ||||
| 
 | ||||
|     void VisitBasicBlock(const NodeBlock& bb) { | ||||
|         for (const Node node : bb) { | ||||
|         for (const auto& node : bb) { | ||||
|             static_cast<void>(Visit(node)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     Id Visit(Node node) { | ||||
|         if (const auto operation = std::get_if<OperationNode>(node)) { | ||||
|     Id Visit(const Node& node) { | ||||
|         if (const auto operation = std::get_if<OperationNode>(&*node)) { | ||||
|             const auto operation_index = static_cast<std::size_t>(operation->GetCode()); | ||||
|             const auto decompiler = operation_decompilers[operation_index]; | ||||
|             if (decompiler == nullptr) { | ||||
| @ -495,17 +495,17 @@ private: | ||||
|             } | ||||
|             return (this->*decompiler)(*operation); | ||||
| 
 | ||||
|         } else if (const auto gpr = std::get_if<GprNode>(node)) { | ||||
|         } else if (const auto gpr = std::get_if<GprNode>(&*node)) { | ||||
|             const u32 index = gpr->GetIndex(); | ||||
|             if (index == Register::ZeroIndex) { | ||||
|                 return Constant(t_float, 0.0f); | ||||
|             } | ||||
|             return Emit(OpLoad(t_float, registers.at(index))); | ||||
| 
 | ||||
|         } else if (const auto immediate = std::get_if<ImmediateNode>(node)) { | ||||
|         } else if (const auto immediate = std::get_if<ImmediateNode>(&*node)) { | ||||
|             return BitcastTo<Type::Float>(Constant(t_uint, immediate->GetValue())); | ||||
| 
 | ||||
|         } else if (const auto predicate = std::get_if<PredicateNode>(node)) { | ||||
|         } else if (const auto predicate = std::get_if<PredicateNode>(&*node)) { | ||||
|             const auto value = [&]() -> Id { | ||||
|                 switch (const auto index = predicate->GetIndex(); index) { | ||||
|                 case Tegra::Shader::Pred::UnusedIndex: | ||||
| @ -521,7 +521,7 @@ private: | ||||
|             } | ||||
|             return value; | ||||
| 
 | ||||
|         } else if (const auto abuf = std::get_if<AbufNode>(node)) { | ||||
|         } else if (const auto abuf = std::get_if<AbufNode>(&*node)) { | ||||
|             const auto attribute = abuf->GetIndex(); | ||||
|             const auto element = abuf->GetElement(); | ||||
| 
 | ||||
| @ -571,8 +571,8 @@ private: | ||||
|             } | ||||
|             UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute)); | ||||
| 
 | ||||
|         } else if (const auto cbuf = std::get_if<CbufNode>(node)) { | ||||
|             const Node offset = cbuf->GetOffset(); | ||||
|         } else if (const auto cbuf = std::get_if<CbufNode>(&*node)) { | ||||
|             const Node& offset = cbuf->GetOffset(); | ||||
|             const Id buffer_id = constant_buffers.at(cbuf->GetIndex()); | ||||
| 
 | ||||
|             Id pointer{}; | ||||
| @ -584,7 +584,7 @@ private: | ||||
|             } else { | ||||
|                 Id buffer_index{}; | ||||
|                 Id buffer_element{}; | ||||
|                 if (const auto immediate = std::get_if<ImmediateNode>(offset)) { | ||||
|                 if (const auto immediate = std::get_if<ImmediateNode>(&*offset)) { | ||||
|                     // Direct access
 | ||||
|                     const u32 offset_imm = immediate->GetValue(); | ||||
|                     ASSERT(offset_imm % 4 == 0); | ||||
| @ -606,7 +606,7 @@ private: | ||||
|             } | ||||
|             return Emit(OpLoad(t_float, pointer)); | ||||
| 
 | ||||
|         } else if (const auto gmem = std::get_if<GmemNode>(node)) { | ||||
|         } else if (const auto gmem = std::get_if<GmemNode>(&*node)) { | ||||
|             const Id gmem_buffer = global_buffers.at(gmem->GetDescriptor()); | ||||
|             const Id real = BitcastTo<Type::Uint>(Visit(gmem->GetRealAddress())); | ||||
|             const Id base = BitcastTo<Type::Uint>(Visit(gmem->GetBaseAddress())); | ||||
| @ -616,7 +616,7 @@ private: | ||||
|             return Emit(OpLoad(t_float, Emit(OpAccessChain(t_gmem_float, gmem_buffer, | ||||
|                                                            Constant(t_uint, 0u), offset)))); | ||||
| 
 | ||||
|         } else if (const auto conditional = std::get_if<ConditionalNode>(node)) { | ||||
|         } else if (const auto conditional = std::get_if<ConditionalNode>(&*node)) { | ||||
|             // It's invalid to call conditional on nested nodes, use an operation instead
 | ||||
|             const Id true_label = OpLabel(); | ||||
|             const Id skip_label = OpLabel(); | ||||
| @ -631,7 +631,7 @@ private: | ||||
|             Emit(skip_label); | ||||
|             return {}; | ||||
| 
 | ||||
|         } else if (const auto comment = std::get_if<CommentNode>(node)) { | ||||
|         } else if (const auto comment = std::get_if<CommentNode>(&*node)) { | ||||
|             Name(Emit(OpUndef(t_void)), comment->GetText()); | ||||
|             return {}; | ||||
|         } | ||||
| @ -699,18 +699,18 @@ private: | ||||
|     } | ||||
| 
 | ||||
|     Id Assign(Operation operation) { | ||||
|         const Node dest = operation[0]; | ||||
|         const Node src = operation[1]; | ||||
|         const Node& dest = operation[0]; | ||||
|         const Node& src = operation[1]; | ||||
| 
 | ||||
|         Id target{}; | ||||
|         if (const auto gpr = std::get_if<GprNode>(dest)) { | ||||
|         if (const auto gpr = std::get_if<GprNode>(&*dest)) { | ||||
|             if (gpr->GetIndex() == Register::ZeroIndex) { | ||||
|                 // Writing to Register::ZeroIndex is a no op
 | ||||
|                 return {}; | ||||
|             } | ||||
|             target = registers.at(gpr->GetIndex()); | ||||
| 
 | ||||
|         } else if (const auto abuf = std::get_if<AbufNode>(dest)) { | ||||
|         } else if (const auto abuf = std::get_if<AbufNode>(&*dest)) { | ||||
|             target = [&]() -> Id { | ||||
|                 switch (const auto attribute = abuf->GetIndex(); attribute) { | ||||
|                 case Attribute::Index::Position: | ||||
| @ -735,7 +735,7 @@ private: | ||||
|                 } | ||||
|             }(); | ||||
| 
 | ||||
|         } else if (const auto lmem = std::get_if<LmemNode>(dest)) { | ||||
|         } else if (const auto lmem = std::get_if<LmemNode>(&*dest)) { | ||||
|             Id address = BitcastTo<Type::Uint>(Visit(lmem->GetAddress())); | ||||
|             address = Emit(OpUDiv(t_uint, address, Constant(t_uint, 4))); | ||||
|             target = Emit(OpAccessChain(t_prv_float, local_memory, {address})); | ||||
| @ -781,11 +781,11 @@ private: | ||||
|     } | ||||
| 
 | ||||
|     Id LogicalAssign(Operation operation) { | ||||
|         const Node dest = operation[0]; | ||||
|         const Node src = operation[1]; | ||||
|         const Node& dest = operation[0]; | ||||
|         const Node& src = operation[1]; | ||||
| 
 | ||||
|         Id target{}; | ||||
|         if (const auto pred = std::get_if<PredicateNode>(dest)) { | ||||
|         if (const auto pred = std::get_if<PredicateNode>(&*dest)) { | ||||
|             ASSERT_MSG(!pred->IsNegated(), "Negating logical assignment"); | ||||
| 
 | ||||
|             const auto index = pred->GetIndex(); | ||||
| @ -797,7 +797,7 @@ private: | ||||
|             } | ||||
|             target = predicates.at(index); | ||||
| 
 | ||||
|         } else if (const auto flag = std::get_if<InternalFlagNode>(dest)) { | ||||
|         } else if (const auto flag = std::get_if<InternalFlagNode>(&*dest)) { | ||||
|             target = internal_flags.at(static_cast<u32>(flag->GetFlag())); | ||||
|         } | ||||
| 
 | ||||
| @ -883,7 +883,7 @@ private: | ||||
|         } else { | ||||
|             u32 component_value = 0; | ||||
|             if (meta->component) { | ||||
|                 const auto component = std::get_if<ImmediateNode>(meta->component); | ||||
|                 const auto component = std::get_if<ImmediateNode>(&*meta->component); | ||||
|                 ASSERT_MSG(component, "Component is not an immediate value"); | ||||
|                 component_value = component->GetValue(); | ||||
|             } | ||||
| @ -940,7 +940,7 @@ private: | ||||
|     } | ||||
| 
 | ||||
|     Id Branch(Operation operation) { | ||||
|         const auto target = std::get_if<ImmediateNode>(operation[0]); | ||||
|         const auto target = std::get_if<ImmediateNode>(&*operation[0]); | ||||
|         UNIMPLEMENTED_IF(!target); | ||||
| 
 | ||||
|         Emit(OpStore(jmp_to, Constant(t_uint, target->GetValue()))); | ||||
| @ -949,7 +949,7 @@ private: | ||||
|     } | ||||
| 
 | ||||
|     Id PushFlowStack(Operation operation) { | ||||
|         const auto target = std::get_if<ImmediateNode>(operation[0]); | ||||
|         const auto target = std::get_if<ImmediateNode>(&*operation[0]); | ||||
|         ASSERT(target); | ||||
| 
 | ||||
|         const Id current = Emit(OpLoad(t_uint, flow_stack_top)); | ||||
|  | ||||
| @ -11,6 +11,7 @@ | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/engines/shader_header.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -6,6 +6,7 @@ | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -6,6 +6,7 @@ | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -6,6 +6,7 @@ | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -8,6 +8,7 @@ | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -7,6 +7,7 @@ | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -4,6 +4,7 @@ | ||||
| 
 | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -10,6 +10,7 @@ | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
| @ -169,7 +170,7 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | ||||
|             const Node it_offset = Immediate(i * 4); | ||||
|             const Node real_address = | ||||
|                 Operation(OperationCode::UAdd, NO_PRECISE, real_address_base, it_offset); | ||||
|             const Node gmem = StoreNode(GmemNode(real_address, base_address, descriptor)); | ||||
|             const Node gmem = MakeNode<GmemNode>(real_address, base_address, descriptor); | ||||
| 
 | ||||
|             SetTemporal(bb, i, gmem); | ||||
|         } | ||||
| @ -262,7 +263,7 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | ||||
|             const Node it_offset = Immediate(i * 4); | ||||
|             const Node real_address = | ||||
|                 Operation(OperationCode::UAdd, NO_PRECISE, real_address_base, it_offset); | ||||
|             const Node gmem = StoreNode(GmemNode(real_address, base_address, descriptor)); | ||||
|             const Node gmem = MakeNode<GmemNode>(real_address, base_address, descriptor); | ||||
| 
 | ||||
|             bb.push_back(Operation(OperationCode::Assign, gmem, GetTemporal(i + 1))); | ||||
|         } | ||||
| @ -298,9 +299,9 @@ std::tuple<Node, Node, GlobalMemoryBase> ShaderIR::TrackAndGetGlobalMemory(NodeB | ||||
| 
 | ||||
|     const Node base_address{ | ||||
|         TrackCbuf(addr_register, global_code, static_cast<s64>(global_code.size()))}; | ||||
|     const auto cbuf = std::get_if<CbufNode>(base_address); | ||||
|     const auto cbuf = std::get_if<CbufNode>(&*base_address); | ||||
|     ASSERT(cbuf != nullptr); | ||||
|     const auto cbuf_offset_imm = std::get_if<ImmediateNode>(cbuf->GetOffset()); | ||||
|     const auto cbuf_offset_imm = std::get_if<ImmediateNode>(&*cbuf->GetOffset()); | ||||
|     ASSERT(cbuf_offset_imm != nullptr); | ||||
|     const auto cbuf_offset = cbuf_offset_imm->GetValue(); | ||||
| 
 | ||||
|  | ||||
| @ -6,6 +6,7 @@ | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -11,6 +11,7 @@ | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
| @ -291,8 +292,8 @@ const Sampler& ShaderIR::GetBindlessSampler(const Tegra::Shader::Register& reg, | ||||
|     const Node sampler_register = GetRegister(reg); | ||||
|     const Node base_sampler = | ||||
|         TrackCbuf(sampler_register, global_code, static_cast<s64>(global_code.size())); | ||||
|     const auto cbuf = std::get_if<CbufNode>(base_sampler); | ||||
|     const auto cbuf_offset_imm = std::get_if<ImmediateNode>(cbuf->GetOffset()); | ||||
|     const auto cbuf = std::get_if<CbufNode>(&*base_sampler); | ||||
|     const auto cbuf_offset_imm = std::get_if<ImmediateNode>(&*cbuf->GetOffset()); | ||||
|     ASSERT(cbuf_offset_imm != nullptr); | ||||
|     const auto cbuf_offset = cbuf_offset_imm->GetValue(); | ||||
|     const auto cbuf_index = cbuf->GetIndex(); | ||||
| @ -388,8 +389,8 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type, | ||||
|                                Node array, Node depth_compare, u32 bias_offset, | ||||
|                                std::vector<Node> aoffi, | ||||
|                                std::optional<Tegra::Shader::Register> bindless_reg) { | ||||
|     const bool is_array = array; | ||||
|     const bool is_shadow = depth_compare; | ||||
|     const auto is_array = static_cast<bool>(array); | ||||
|     const auto is_shadow = static_cast<bool>(depth_compare); | ||||
|     const bool is_bindless = bindless_reg.has_value(); | ||||
| 
 | ||||
|     UNIMPLEMENTED_IF_MSG((texture_type == TextureType::Texture3D && (is_array || is_shadow)) || | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
| @ -5,6 +5,7 @@ | ||||
| #include "common/assert.h" | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
|  | ||||
							
								
								
									
										99
									
								
								src/video_core/shader/node_helper.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/video_core/shader/node_helper.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,99 @@ | ||||
| // Copyright 2019 yuzu Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <cstring> | ||||
| #include <vector> | ||||
| 
 | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
| 
 | ||||
| Node Conditional(Node condition, std::vector<Node> code) { | ||||
|     return MakeNode<ConditionalNode>(condition, std::move(code)); | ||||
| } | ||||
| 
 | ||||
| Node Comment(std::string text) { | ||||
|     return MakeNode<CommentNode>(std::move(text)); | ||||
| } | ||||
| 
 | ||||
| Node Immediate(u32 value) { | ||||
|     return MakeNode<ImmediateNode>(value); | ||||
| } | ||||
| 
 | ||||
| Node Immediate(s32 value) { | ||||
|     return Immediate(static_cast<u32>(value)); | ||||
| } | ||||
| 
 | ||||
| Node Immediate(f32 value) { | ||||
|     u32 integral; | ||||
|     std::memcpy(&integral, &value, sizeof(u32)); | ||||
|     return Immediate(integral); | ||||
| } | ||||
| 
 | ||||
| OperationCode SignedToUnsignedCode(OperationCode operation_code, bool is_signed) { | ||||
|     if (is_signed) { | ||||
|         return operation_code; | ||||
|     } | ||||
|     switch (operation_code) { | ||||
|     case OperationCode::FCastInteger: | ||||
|         return OperationCode::FCastUInteger; | ||||
|     case OperationCode::IAdd: | ||||
|         return OperationCode::UAdd; | ||||
|     case OperationCode::IMul: | ||||
|         return OperationCode::UMul; | ||||
|     case OperationCode::IDiv: | ||||
|         return OperationCode::UDiv; | ||||
|     case OperationCode::IMin: | ||||
|         return OperationCode::UMin; | ||||
|     case OperationCode::IMax: | ||||
|         return OperationCode::UMax; | ||||
|     case OperationCode::ICastFloat: | ||||
|         return OperationCode::UCastFloat; | ||||
|     case OperationCode::ICastUnsigned: | ||||
|         return OperationCode::UCastSigned; | ||||
|     case OperationCode::ILogicalShiftLeft: | ||||
|         return OperationCode::ULogicalShiftLeft; | ||||
|     case OperationCode::ILogicalShiftRight: | ||||
|         return OperationCode::ULogicalShiftRight; | ||||
|     case OperationCode::IArithmeticShiftRight: | ||||
|         return OperationCode::UArithmeticShiftRight; | ||||
|     case OperationCode::IBitwiseAnd: | ||||
|         return OperationCode::UBitwiseAnd; | ||||
|     case OperationCode::IBitwiseOr: | ||||
|         return OperationCode::UBitwiseOr; | ||||
|     case OperationCode::IBitwiseXor: | ||||
|         return OperationCode::UBitwiseXor; | ||||
|     case OperationCode::IBitwiseNot: | ||||
|         return OperationCode::UBitwiseNot; | ||||
|     case OperationCode::IBitfieldInsert: | ||||
|         return OperationCode::UBitfieldInsert; | ||||
|     case OperationCode::IBitCount: | ||||
|         return OperationCode::UBitCount; | ||||
|     case OperationCode::LogicalILessThan: | ||||
|         return OperationCode::LogicalULessThan; | ||||
|     case OperationCode::LogicalIEqual: | ||||
|         return OperationCode::LogicalUEqual; | ||||
|     case OperationCode::LogicalILessEqual: | ||||
|         return OperationCode::LogicalULessEqual; | ||||
|     case OperationCode::LogicalIGreaterThan: | ||||
|         return OperationCode::LogicalUGreaterThan; | ||||
|     case OperationCode::LogicalINotEqual: | ||||
|         return OperationCode::LogicalUNotEqual; | ||||
|     case OperationCode::LogicalIGreaterEqual: | ||||
|         return OperationCode::LogicalUGreaterEqual; | ||||
|     case OperationCode::INegate: | ||||
|         UNREACHABLE_MSG("Can't negate an unsigned integer"); | ||||
|         return {}; | ||||
|     case OperationCode::IAbsolute: | ||||
|         UNREACHABLE_MSG("Can't apply absolute to an unsigned integer"); | ||||
|         return {}; | ||||
|     default: | ||||
|         UNREACHABLE_MSG("Unknown signed operation with code={}", static_cast<u32>(operation_code)); | ||||
|         return {}; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| } // namespace VideoCommon::Shader
 | ||||
							
								
								
									
										60
									
								
								src/video_core/shader/node_helper.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								src/video_core/shader/node_helper.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,60 @@ | ||||
| // Copyright 2019 yuzu Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <memory> | ||||
| #include <string> | ||||
| #include <tuple> | ||||
| #include <type_traits> | ||||
| #include <utility> | ||||
| #include <vector> | ||||
| 
 | ||||
| #include "common/common_types.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
| 
 | ||||
| /// Creates a conditional node
 | ||||
| Node Conditional(Node condition, std::vector<Node> code); | ||||
| 
 | ||||
| /// Creates a commentary node
 | ||||
| Node Comment(std::string text); | ||||
| 
 | ||||
| /// Creates an u32 immediate
 | ||||
| Node Immediate(u32 value); | ||||
| 
 | ||||
| /// Creates a s32 immediate
 | ||||
| Node Immediate(s32 value); | ||||
| 
 | ||||
| /// Creates a f32 immediate
 | ||||
| Node Immediate(f32 value); | ||||
| 
 | ||||
| /// Converts an signed operation code to an unsigned operation code
 | ||||
| OperationCode SignedToUnsignedCode(OperationCode operation_code, bool is_signed); | ||||
| 
 | ||||
| template <typename T, typename... Args> | ||||
| Node MakeNode(Args&&... args) { | ||||
|     static_assert(std::is_convertible_v<T, NodeData>); | ||||
|     return std::make_shared<NodeData>(T(std::forward<Args>(args)...)); | ||||
| } | ||||
| 
 | ||||
| template <typename... Args> | ||||
| Node Operation(OperationCode code, Args&&... args) { | ||||
|     if constexpr (sizeof...(args) == 0) { | ||||
|         return MakeNode<OperationNode>(code); | ||||
|     } else if constexpr (std::is_convertible_v<std::tuple_element_t<0, std::tuple<Args...>>, | ||||
|                                                Meta>) { | ||||
|         return MakeNode<OperationNode>(code, std::forward<Args>(args)...); | ||||
|     } else { | ||||
|         return MakeNode<OperationNode>(code, Meta{}, std::forward<Args>(args)...); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| template <typename... Args> | ||||
| Node SignedOperation(OperationCode code, bool is_signed, Args&&... args) { | ||||
|     return Operation(SignedToUnsignedCode(code, is_signed), std::forward<Args>(args)...); | ||||
| } | ||||
| 
 | ||||
| } // namespace VideoCommon::Shader
 | ||||
| @ -9,6 +9,7 @@ | ||||
| #include "common/common_types.h" | ||||
| #include "common/logging/log.h" | ||||
| #include "video_core/engines/shader_bytecode.h" | ||||
| #include "video_core/shader/node_helper.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
| @ -28,30 +29,11 @@ ShaderIR::ShaderIR(const ProgramCode& program_code, u32 main_offset) | ||||
| 
 | ||||
| ShaderIR::~ShaderIR() = default; | ||||
| 
 | ||||
| Node ShaderIR::StoreNode(NodeData&& node_data) { | ||||
|     auto store = std::make_unique<NodeData>(node_data); | ||||
|     const Node node = store.get(); | ||||
|     stored_nodes.push_back(std::move(store)); | ||||
|     return node; | ||||
| } | ||||
| 
 | ||||
| Node ShaderIR::Conditional(Node condition, std::vector<Node>&& code) { | ||||
|     return StoreNode(ConditionalNode(condition, std::move(code))); | ||||
| } | ||||
| 
 | ||||
| Node ShaderIR::Comment(std::string text) { | ||||
|     return StoreNode(CommentNode(std::move(text))); | ||||
| } | ||||
| 
 | ||||
| Node ShaderIR::Immediate(u32 value) { | ||||
|     return StoreNode(ImmediateNode(value)); | ||||
| } | ||||
| 
 | ||||
| Node ShaderIR::GetRegister(Register reg) { | ||||
|     if (reg != Register::ZeroIndex) { | ||||
|         used_registers.insert(static_cast<u32>(reg)); | ||||
|     } | ||||
|     return StoreNode(GprNode(reg)); | ||||
|     return MakeNode<GprNode>(reg); | ||||
| } | ||||
| 
 | ||||
| Node ShaderIR::GetImmediate19(Instruction instr) { | ||||
| @ -69,7 +51,7 @@ Node ShaderIR::GetConstBuffer(u64 index_, u64 offset_) { | ||||
|     const auto [entry, is_new] = used_cbufs.try_emplace(index); | ||||
|     entry->second.MarkAsUsed(offset); | ||||
| 
 | ||||
|     return StoreNode(CbufNode(index, Immediate(offset))); | ||||
|     return MakeNode<CbufNode>(index, Immediate(offset)); | ||||
| } | ||||
| 
 | ||||
| Node ShaderIR::GetConstBufferIndirect(u64 index_, u64 offset_, Node node) { | ||||
| @ -80,7 +62,7 @@ Node ShaderIR::GetConstBufferIndirect(u64 index_, u64 offset_, Node node) { | ||||
|     entry->second.MarkAsUsedIndirect(); | ||||
| 
 | ||||
|     const Node final_offset = Operation(OperationCode::UAdd, NO_PRECISE, node, Immediate(offset)); | ||||
|     return StoreNode(CbufNode(index, final_offset)); | ||||
|     return MakeNode<CbufNode>(index, final_offset); | ||||
| } | ||||
| 
 | ||||
| Node ShaderIR::GetPredicate(u64 pred_, bool negated) { | ||||
| @ -89,7 +71,7 @@ Node ShaderIR::GetPredicate(u64 pred_, bool negated) { | ||||
|         used_predicates.insert(pred); | ||||
|     } | ||||
| 
 | ||||
|     return StoreNode(PredicateNode(pred, negated)); | ||||
|     return MakeNode<PredicateNode>(pred, negated); | ||||
| } | ||||
| 
 | ||||
| Node ShaderIR::GetPredicate(bool immediate) { | ||||
| @ -98,12 +80,12 @@ Node ShaderIR::GetPredicate(bool immediate) { | ||||
| 
 | ||||
| Node ShaderIR::GetInputAttribute(Attribute::Index index, u64 element, Node buffer) { | ||||
|     used_input_attributes.emplace(index); | ||||
|     return StoreNode(AbufNode(index, static_cast<u32>(element), buffer)); | ||||
|     return MakeNode<AbufNode>(index, static_cast<u32>(element), buffer); | ||||
| } | ||||
| 
 | ||||
| Node ShaderIR::GetPhysicalInputAttribute(Tegra::Shader::Register physical_address, Node buffer) { | ||||
|     uses_physical_attributes = true; | ||||
|     return StoreNode(AbufNode(GetRegister(physical_address), buffer)); | ||||
|     return MakeNode<AbufNode>(GetRegister(physical_address), buffer); | ||||
| } | ||||
| 
 | ||||
| Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buffer) { | ||||
| @ -115,11 +97,11 @@ Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buff | ||||
|     } | ||||
|     used_output_attributes.insert(index); | ||||
| 
 | ||||
|     return StoreNode(AbufNode(index, static_cast<u32>(element), buffer)); | ||||
|     return MakeNode<AbufNode>(index, static_cast<u32>(element), buffer); | ||||
| } | ||||
| 
 | ||||
| Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) { | ||||
|     const Node node = StoreNode(InternalFlagNode(flag)); | ||||
|     const Node node = MakeNode<InternalFlagNode>(flag); | ||||
|     if (negated) { | ||||
|         return Operation(OperationCode::LogicalNegate, node); | ||||
|     } | ||||
| @ -127,7 +109,7 @@ Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) { | ||||
| } | ||||
| 
 | ||||
| Node ShaderIR::GetLocalMemory(Node address) { | ||||
|     return StoreNode(LmemNode(address)); | ||||
|     return MakeNode<LmemNode>(address); | ||||
| } | ||||
| 
 | ||||
| Node ShaderIR::GetTemporal(u32 id) { | ||||
| @ -393,68 +375,4 @@ Node ShaderIR::BitfieldExtract(Node value, u32 offset, u32 bits) { | ||||
|                      Immediate(bits)); | ||||
| } | ||||
| 
 | ||||
| /*static*/ OperationCode ShaderIR::SignedToUnsignedCode(OperationCode operation_code, | ||||
|                                                         bool is_signed) { | ||||
|     if (is_signed) { | ||||
|         return operation_code; | ||||
|     } | ||||
|     switch (operation_code) { | ||||
|     case OperationCode::FCastInteger: | ||||
|         return OperationCode::FCastUInteger; | ||||
|     case OperationCode::IAdd: | ||||
|         return OperationCode::UAdd; | ||||
|     case OperationCode::IMul: | ||||
|         return OperationCode::UMul; | ||||
|     case OperationCode::IDiv: | ||||
|         return OperationCode::UDiv; | ||||
|     case OperationCode::IMin: | ||||
|         return OperationCode::UMin; | ||||
|     case OperationCode::IMax: | ||||
|         return OperationCode::UMax; | ||||
|     case OperationCode::ICastFloat: | ||||
|         return OperationCode::UCastFloat; | ||||
|     case OperationCode::ICastUnsigned: | ||||
|         return OperationCode::UCastSigned; | ||||
|     case OperationCode::ILogicalShiftLeft: | ||||
|         return OperationCode::ULogicalShiftLeft; | ||||
|     case OperationCode::ILogicalShiftRight: | ||||
|         return OperationCode::ULogicalShiftRight; | ||||
|     case OperationCode::IArithmeticShiftRight: | ||||
|         return OperationCode::UArithmeticShiftRight; | ||||
|     case OperationCode::IBitwiseAnd: | ||||
|         return OperationCode::UBitwiseAnd; | ||||
|     case OperationCode::IBitwiseOr: | ||||
|         return OperationCode::UBitwiseOr; | ||||
|     case OperationCode::IBitwiseXor: | ||||
|         return OperationCode::UBitwiseXor; | ||||
|     case OperationCode::IBitwiseNot: | ||||
|         return OperationCode::UBitwiseNot; | ||||
|     case OperationCode::IBitfieldInsert: | ||||
|         return OperationCode::UBitfieldInsert; | ||||
|     case OperationCode::IBitCount: | ||||
|         return OperationCode::UBitCount; | ||||
|     case OperationCode::LogicalILessThan: | ||||
|         return OperationCode::LogicalULessThan; | ||||
|     case OperationCode::LogicalIEqual: | ||||
|         return OperationCode::LogicalUEqual; | ||||
|     case OperationCode::LogicalILessEqual: | ||||
|         return OperationCode::LogicalULessEqual; | ||||
|     case OperationCode::LogicalIGreaterThan: | ||||
|         return OperationCode::LogicalUGreaterThan; | ||||
|     case OperationCode::LogicalINotEqual: | ||||
|         return OperationCode::LogicalUNotEqual; | ||||
|     case OperationCode::LogicalIGreaterEqual: | ||||
|         return OperationCode::LogicalUGreaterEqual; | ||||
|     case OperationCode::INegate: | ||||
|         UNREACHABLE_MSG("Can't negate an unsigned integer"); | ||||
|         return {}; | ||||
|     case OperationCode::IAbsolute: | ||||
|         UNREACHABLE_MSG("Can't apply absolute to an unsigned integer"); | ||||
|         return {}; | ||||
|     default: | ||||
|         UNREACHABLE_MSG("Unknown signed operation with code={}", static_cast<u32>(operation_code)); | ||||
|         return {}; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| } // namespace VideoCommon::Shader
 | ||||
|  | ||||
| @ -38,7 +38,7 @@ using ProgramCode = std::vector<u64>; | ||||
| using NodeData = | ||||
|     std::variant<OperationNode, ConditionalNode, GprNode, ImmediateNode, InternalFlagNode, | ||||
|                  PredicateNode, AbufNode, CbufNode, LmemNode, GmemNode, CommentNode>; | ||||
| using Node = const NodeData*; | ||||
| using Node = std::shared_ptr<NodeData>; | ||||
| using Node4 = std::array<Node, 4>; | ||||
| using NodeBlock = std::vector<Node>; | ||||
| 
 | ||||
| @ -342,23 +342,20 @@ 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) : code{code} {} | ||||
|     explicit OperationNode(OperationCode code) : OperationNode(code, Meta{}) {} | ||||
| 
 | ||||
|     explicit OperationNode(OperationCode code, Meta&& meta) : code{code}, meta{std::move(meta)} {} | ||||
|     explicit OperationNode(OperationCode code, Meta meta) | ||||
|         : OperationNode(code, meta, std::vector<Node>{}) {} | ||||
| 
 | ||||
|     template <typename... T> | ||||
|     explicit OperationNode(OperationCode code, const T*... operands) | ||||
|         : OperationNode(code, {}, operands...) {} | ||||
|     explicit OperationNode(OperationCode code, std::vector<Node> operands) | ||||
|         : OperationNode(code, Meta{}, std::move(operands)) {} | ||||
| 
 | ||||
|     template <typename... T> | ||||
|     explicit OperationNode(OperationCode code, Meta&& meta, const T*... operands_) | ||||
|         : code{code}, meta{std::move(meta)}, operands{operands_...} {} | ||||
|     explicit OperationNode(OperationCode code, Meta meta, std::vector<Node> operands) | ||||
|         : code{code}, meta{std::move(meta)}, operands{std::move(operands)} {} | ||||
| 
 | ||||
|     explicit OperationNode(OperationCode code, Meta&& meta, std::vector<Node>&& operands) | ||||
|         : code{code}, meta{meta}, operands{std::move(operands)} {} | ||||
| 
 | ||||
|     explicit OperationNode(OperationCode code, std::vector<Node>&& operands) | ||||
|         : code{code}, 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; | ||||
| @ -372,13 +369,13 @@ public: | ||||
|         return operands.size(); | ||||
|     } | ||||
| 
 | ||||
|     Node operator[](std::size_t operand_index) const { | ||||
|     const Node& operator[](std::size_t operand_index) const { | ||||
|         return operands.at(operand_index); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     const OperationCode code; | ||||
|     const Meta meta; | ||||
|     OperationCode code{}; | ||||
|     Meta meta{}; | ||||
|     std::vector<Node> operands; | ||||
| }; | ||||
| 
 | ||||
| @ -463,13 +460,12 @@ private: | ||||
| class AbufNode final { | ||||
| public: | ||||
|     // Initialize for standard attributes (index is explicit).
 | ||||
|     explicit constexpr AbufNode(Tegra::Shader::Attribute::Index index, u32 element, | ||||
|                                 Node buffer = {}) | ||||
|         : buffer{buffer}, index{index}, element{element} {} | ||||
|     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 constexpr AbufNode(Node physical_address, Node buffer = {}) | ||||
|         : physical_address{physical_address}, buffer{buffer} {} | ||||
|     explicit AbufNode(Node physical_address, Node buffer = {}) | ||||
|         : physical_address{physical_address}, buffer{std::move(buffer)} {} | ||||
| 
 | ||||
|     Tegra::Shader::Attribute::Index GetIndex() const { | ||||
|         return index; | ||||
| @ -484,16 +480,16 @@ public: | ||||
|     } | ||||
| 
 | ||||
|     bool IsPhysicalBuffer() const { | ||||
|         return physical_address != nullptr; | ||||
|         return static_cast<bool>(physical_address); | ||||
|     } | ||||
| 
 | ||||
|     Node GetPhysicalAddress() const { | ||||
|     const Node& GetPhysicalAddress() const { | ||||
|         return physical_address; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     Node physical_address{}; | ||||
|     Node buffer{}; | ||||
|     Node physical_address; | ||||
|     Node buffer; | ||||
|     Tegra::Shader::Attribute::Index index{}; | ||||
|     u32 element{}; | ||||
| }; | ||||
| @ -501,7 +497,7 @@ private: | ||||
| /// Constant buffer node, usually mapped to uniform buffers in GLSL
 | ||||
| class CbufNode final { | ||||
| public: | ||||
|     explicit constexpr CbufNode(u32 index, Node offset) : index{index}, offset{offset} {} | ||||
|     explicit CbufNode(u32 index, Node offset) : index{index}, offset{offset} {} | ||||
| 
 | ||||
|     u32 GetIndex() const { | ||||
|         return index; | ||||
| @ -519,7 +515,7 @@ private: | ||||
| /// Local memory node
 | ||||
| class LmemNode final { | ||||
| public: | ||||
|     explicit constexpr LmemNode(Node address) : address{address} {} | ||||
|     explicit LmemNode(Node address) : address{address} {} | ||||
| 
 | ||||
|     Node GetAddress() const { | ||||
|         return address; | ||||
| @ -532,8 +528,7 @@ private: | ||||
| /// Global memory node
 | ||||
| class GmemNode final { | ||||
| public: | ||||
|     explicit constexpr GmemNode(Node real_address, Node base_address, | ||||
|                                 const GlobalMemoryBase& descriptor) | ||||
|     explicit GmemNode(Node real_address, Node base_address, const GlobalMemoryBase& descriptor) | ||||
|         : real_address{real_address}, base_address{base_address}, descriptor{descriptor} {} | ||||
| 
 | ||||
|     Node GetRealAddress() const { | ||||
| @ -663,26 +658,6 @@ private: | ||||
|     u32 DecodeXmad(NodeBlock& bb, u32 pc); | ||||
|     u32 DecodeOther(NodeBlock& bb, u32 pc); | ||||
| 
 | ||||
|     /// Internalizes node's data and returns a managed pointer to a clone of that node
 | ||||
|     Node StoreNode(NodeData&& node_data); | ||||
| 
 | ||||
|     /// Creates a conditional node
 | ||||
|     Node Conditional(Node condition, std::vector<Node>&& code); | ||||
|     /// Creates a commentary
 | ||||
|     Node Comment(std::string text); | ||||
|     /// Creates an u32 immediate
 | ||||
|     Node Immediate(u32 value); | ||||
|     /// Creates a s32 immediate
 | ||||
|     Node Immediate(s32 value) { | ||||
|         return Immediate(static_cast<u32>(value)); | ||||
|     } | ||||
|     /// Creates a f32 immediate
 | ||||
|     Node Immediate(f32 value) { | ||||
|         u32 integral; | ||||
|         std::memcpy(&integral, &value, sizeof(u32)); | ||||
|         return Immediate(integral); | ||||
|     } | ||||
| 
 | ||||
|     /// Generates a node for a passed register.
 | ||||
|     Node GetRegister(Tegra::Shader::Register reg); | ||||
|     /// Generates a node representing a 19-bit immediate value
 | ||||
| @ -827,37 +802,6 @@ private: | ||||
|     std::tuple<Node, Node, GlobalMemoryBase> TrackAndGetGlobalMemory( | ||||
|         NodeBlock& bb, Tegra::Shader::Instruction instr, bool is_write); | ||||
| 
 | ||||
|     template <typename... T> | ||||
|     Node Operation(OperationCode code, const T*... operands) { | ||||
|         return StoreNode(OperationNode(code, operands...)); | ||||
|     } | ||||
| 
 | ||||
|     template <typename... T> | ||||
|     Node Operation(OperationCode code, Meta&& meta, const T*... operands) { | ||||
|         return StoreNode(OperationNode(code, std::move(meta), operands...)); | ||||
|     } | ||||
| 
 | ||||
|     Node Operation(OperationCode code, std::vector<Node>&& operands) { | ||||
|         return StoreNode(OperationNode(code, std::move(operands))); | ||||
|     } | ||||
| 
 | ||||
|     Node Operation(OperationCode code, Meta&& meta, std::vector<Node>&& operands) { | ||||
|         return StoreNode(OperationNode(code, std::move(meta), std::move(operands))); | ||||
|     } | ||||
| 
 | ||||
|     template <typename... T> | ||||
|     Node SignedOperation(OperationCode code, bool is_signed, const T*... operands) { | ||||
|         return StoreNode(OperationNode(SignedToUnsignedCode(code, is_signed), operands...)); | ||||
|     } | ||||
| 
 | ||||
|     template <typename... T> | ||||
|     Node SignedOperation(OperationCode code, bool is_signed, Meta&& meta, const T*... operands) { | ||||
|         return StoreNode( | ||||
|             OperationNode(SignedToUnsignedCode(code, is_signed), std::move(meta), operands...)); | ||||
|     } | ||||
| 
 | ||||
|     static OperationCode SignedToUnsignedCode(OperationCode operation_code, bool is_signed); | ||||
| 
 | ||||
|     const ProgramCode& program_code; | ||||
|     const u32 main_offset; | ||||
| 
 | ||||
| @ -868,8 +812,6 @@ private: | ||||
|     std::map<u32, NodeBlock> basic_blocks; | ||||
|     NodeBlock global_code; | ||||
| 
 | ||||
|     std::vector<std::unique_ptr<NodeData>> stored_nodes; | ||||
| 
 | ||||
|     std::set<u32> used_registers; | ||||
|     std::set<Tegra::Shader::Pred> used_predicates; | ||||
|     std::set<Tegra::Shader::Attribute::Index> used_input_attributes; | ||||
|  | ||||
| @ -16,12 +16,12 @@ std::pair<Node, s64> FindOperation(const NodeBlock& code, s64 cursor, | ||||
|                                    OperationCode operation_code) { | ||||
|     for (; cursor >= 0; --cursor) { | ||||
|         const Node node = code.at(cursor); | ||||
|         if (const auto operation = std::get_if<OperationNode>(node)) { | ||||
|         if (const auto operation = std::get_if<OperationNode>(&*node)) { | ||||
|             if (operation->GetCode() == operation_code) { | ||||
|                 return {node, cursor}; | ||||
|             } | ||||
|         } | ||||
|         if (const auto conditional = std::get_if<ConditionalNode>(node)) { | ||||
|         if (const auto conditional = std::get_if<ConditionalNode>(&*node)) { | ||||
|             const auto& conditional_code = conditional->GetCode(); | ||||
|             const auto [found, internal_cursor] = FindOperation( | ||||
|                 conditional_code, static_cast<s64>(conditional_code.size() - 1), operation_code); | ||||
| @ -35,11 +35,11 @@ std::pair<Node, s64> FindOperation(const NodeBlock& code, s64 cursor, | ||||
| } // namespace
 | ||||
| 
 | ||||
| Node ShaderIR::TrackCbuf(Node tracked, const NodeBlock& code, s64 cursor) const { | ||||
|     if (const auto cbuf = std::get_if<CbufNode>(tracked)) { | ||||
|     if (const auto cbuf = std::get_if<CbufNode>(&*tracked)) { | ||||
|         // Cbuf found, but it has to be immediate
 | ||||
|         return std::holds_alternative<ImmediateNode>(*cbuf->GetOffset()) ? tracked : nullptr; | ||||
|     } | ||||
|     if (const auto gpr = std::get_if<GprNode>(tracked)) { | ||||
|     if (const auto gpr = std::get_if<GprNode>(&*tracked)) { | ||||
|         if (gpr->GetIndex() == Tegra::Shader::Register::ZeroIndex) { | ||||
|             return nullptr; | ||||
|         } | ||||
| @ -51,7 +51,7 @@ Node ShaderIR::TrackCbuf(Node tracked, const NodeBlock& code, s64 cursor) const | ||||
|         } | ||||
|         return TrackCbuf(source, code, new_cursor); | ||||
|     } | ||||
|     if (const auto operation = std::get_if<OperationNode>(tracked)) { | ||||
|     if (const auto operation = std::get_if<OperationNode>(&*tracked)) { | ||||
|         for (std::size_t i = 0; i < operation->GetOperandsCount(); ++i) { | ||||
|             if (const auto found = TrackCbuf((*operation)[i], code, cursor)) { | ||||
|                 // Cbuf found in operand
 | ||||
| @ -60,7 +60,7 @@ Node ShaderIR::TrackCbuf(Node tracked, const NodeBlock& code, s64 cursor) const | ||||
|         } | ||||
|         return nullptr; | ||||
|     } | ||||
|     if (const auto conditional = std::get_if<ConditionalNode>(tracked)) { | ||||
|     if (const auto conditional = std::get_if<ConditionalNode>(&*tracked)) { | ||||
|         const auto& conditional_code = conditional->GetCode(); | ||||
|         return TrackCbuf(tracked, conditional_code, static_cast<s64>(conditional_code.size())); | ||||
|     } | ||||
| @ -75,7 +75,7 @@ std::optional<u32> ShaderIR::TrackImmediate(Node tracked, const NodeBlock& code, | ||||
|     if (!found) { | ||||
|         return {}; | ||||
|     } | ||||
|     if (const auto immediate = std::get_if<ImmediateNode>(found)) { | ||||
|     if (const auto immediate = std::get_if<ImmediateNode>(&*found)) { | ||||
|         return immediate->GetValue(); | ||||
|     } | ||||
|     return {}; | ||||
| @ -88,11 +88,11 @@ std::pair<Node, s64> ShaderIR::TrackRegister(const GprNode* tracked, const NodeB | ||||
|         if (!found_node) { | ||||
|             return {}; | ||||
|         } | ||||
|         const auto operation = std::get_if<OperationNode>(found_node); | ||||
|         const auto operation = std::get_if<OperationNode>(&*found_node); | ||||
|         ASSERT(operation); | ||||
| 
 | ||||
|         const auto& target = (*operation)[0]; | ||||
|         if (const auto gpr_target = std::get_if<GprNode>(target)) { | ||||
|         if (const auto gpr_target = std::get_if<GprNode>(&*target)) { | ||||
|             if (gpr_target->GetIndex() == tracked->GetIndex()) { | ||||
|                 return {(*operation)[1], new_cursor}; | ||||
|             } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user