mirror of
				https://git.tardis.systems/mirrors/yuzu
				synced 2025-10-31 02:34:11 +01:00 
			
		
		
		
	gl_shader_decompiler: Implement AST decompiling
This commit is contained in:
		
							parent
							
								
									6fdd501113
								
							
						
					
					
						commit
						38fc995f6c
					
				| @ -20,6 +20,7 @@ | ||||
| #include "video_core/renderer_opengl/gl_rasterizer.h" | ||||
| #include "video_core/renderer_opengl/gl_shader_decompiler.h" | ||||
| #include "video_core/shader/node.h" | ||||
| #include "video_core/shader/ast.h" | ||||
| #include "video_core/shader/shader_ir.h" | ||||
| 
 | ||||
| namespace OpenGL::GLShader { | ||||
| @ -334,43 +335,26 @@ constexpr bool IsVertexShader(ProgramType stage) { | ||||
|     return stage == ProgramType::VertexA || stage == ProgramType::VertexB; | ||||
| } | ||||
| 
 | ||||
| class ASTDecompiler; | ||||
| class ExprDecompiler; | ||||
| 
 | ||||
| class GLSLDecompiler final { | ||||
| public: | ||||
|     explicit GLSLDecompiler(const Device& device, const ShaderIR& ir, ProgramType stage, | ||||
|                             std::string suffix) | ||||
|         : device{device}, ir{ir}, stage{stage}, suffix{suffix}, header{ir.GetHeader()} {} | ||||
| 
 | ||||
|     void Decompile() { | ||||
|         DeclareVertex(); | ||||
|         DeclareGeometry(); | ||||
|         DeclareRegisters(); | ||||
|         DeclarePredicates(); | ||||
|         DeclareLocalMemory(); | ||||
|         DeclareSharedMemory(); | ||||
|         DeclareInternalFlags(); | ||||
|         DeclareInputAttributes(); | ||||
|         DeclareOutputAttributes(); | ||||
|         DeclareConstantBuffers(); | ||||
|         DeclareGlobalMemory(); | ||||
|         DeclareSamplers(); | ||||
|         DeclarePhysicalAttributeReader(); | ||||
|         DeclareImages(); | ||||
| 
 | ||||
|         code.AddLine("void execute_{}() {{", suffix); | ||||
|         ++code.scope; | ||||
| 
 | ||||
|     void DecompileBranchMode() { | ||||
|         // VM's program counter
 | ||||
|         const auto first_address = ir.GetBasicBlocks().begin()->first; | ||||
|         code.AddLine("uint jmp_to = {}U;", first_address); | ||||
| 
 | ||||
|         // TODO(Subv): Figure out the actual depth of the flow stack, for now it seems
 | ||||
|         // unlikely that shaders will use 20 nested SSYs and PBKs.
 | ||||
|         if (!ir.IsFlowStackDisabled()) { | ||||
|         constexpr u32 FLOW_STACK_SIZE = 20; | ||||
|         for (const auto stack : std::array{MetaStackClass::Ssy, MetaStackClass::Pbk}) { | ||||
|             code.AddLine("uint {}[{}];", FlowStackName(stack), FLOW_STACK_SIZE); | ||||
|                 code.AddLine("uint {} = 0U;", FlowStackTopName(stack)); | ||||
|             } | ||||
|             code.AddLine("uint {} = 0u;", FlowStackTopName(stack)); | ||||
|         } | ||||
| 
 | ||||
|         code.AddLine("while (true) {{"); | ||||
| @ -392,10 +376,37 @@ public: | ||||
|         code.AddLine("default: return;"); | ||||
|         code.AddLine("}}"); | ||||
| 
 | ||||
|         for (std::size_t i = 0; i < 2; ++i) { | ||||
|         --code.scope; | ||||
|         code.AddLine("}}"); | ||||
|     } | ||||
| 
 | ||||
|     void DecompileAST(); | ||||
| 
 | ||||
|     void Decompile() { | ||||
|         DeclareVertex(); | ||||
|         DeclareGeometry(); | ||||
|         DeclareRegisters(); | ||||
|         DeclarePredicates(); | ||||
|         DeclareLocalMemory(); | ||||
|         DeclareInternalFlags(); | ||||
|         DeclareInputAttributes(); | ||||
|         DeclareOutputAttributes(); | ||||
|         DeclareConstantBuffers(); | ||||
|         DeclareGlobalMemory(); | ||||
|         DeclareSamplers(); | ||||
|         DeclarePhysicalAttributeReader(); | ||||
| 
 | ||||
|         code.AddLine("void execute_{}() {{", suffix); | ||||
|         ++code.scope; | ||||
| 
 | ||||
|         if (ir.IsDecompiled()) { | ||||
|             DecompileAST(); | ||||
|         } else { | ||||
|             DecompileBranchMode(); | ||||
|         } | ||||
| 
 | ||||
|         --code.scope; | ||||
|         code.AddLine("}}"); | ||||
|     } | ||||
| 
 | ||||
|     std::string GetResult() { | ||||
| @ -424,6 +435,9 @@ public: | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     friend class ASTDecompiler; | ||||
|     friend class ExprDecompiler; | ||||
| 
 | ||||
|     void DeclareVertex() { | ||||
|         if (!IsVertexShader(stage)) | ||||
|             return; | ||||
| @ -1821,7 +1835,7 @@ private: | ||||
|         return {}; | ||||
|     } | ||||
| 
 | ||||
|     Expression Exit(Operation operation) { | ||||
|     Expression WriteExit() { | ||||
|         if (stage != ProgramType::Fragment) { | ||||
|             code.AddLine("return;"); | ||||
|             return {}; | ||||
| @ -1861,6 +1875,10 @@ private: | ||||
|         return {}; | ||||
|     } | ||||
| 
 | ||||
|     Expression Exit(Operation operation) { | ||||
|         return WriteExit(); | ||||
|     } | ||||
| 
 | ||||
|     Expression Discard(Operation operation) { | ||||
|         // Enclose "discard" in a conditional, so that GLSL compilation does not complain
 | ||||
|         // about unexecuted instructions that may follow this.
 | ||||
| @ -2253,6 +2271,201 @@ private: | ||||
|     ShaderWriter code; | ||||
| }; | ||||
| 
 | ||||
| const std::string flow_var = "flow_var_"; | ||||
| 
 | ||||
| class ExprDecompiler { | ||||
| public: | ||||
|     ExprDecompiler(GLSLDecompiler& decomp) : decomp{decomp} {} | ||||
| 
 | ||||
|     void operator()(VideoCommon::Shader::ExprAnd& expr) { | ||||
|         inner += "( "; | ||||
|         std::visit(*this, *expr.operand1); | ||||
|         inner += " && "; | ||||
|         std::visit(*this, *expr.operand2); | ||||
|         inner += ')'; | ||||
|     } | ||||
| 
 | ||||
|     void operator()(VideoCommon::Shader::ExprOr& expr) { | ||||
|         inner += "( "; | ||||
|         std::visit(*this, *expr.operand1); | ||||
|         inner += " || "; | ||||
|         std::visit(*this, *expr.operand2); | ||||
|         inner += ')'; | ||||
|     } | ||||
| 
 | ||||
|     void operator()(VideoCommon::Shader::ExprNot& expr) { | ||||
|         inner += '!'; | ||||
|         std::visit(*this, *expr.operand1); | ||||
|     } | ||||
| 
 | ||||
|     void operator()(VideoCommon::Shader::ExprPredicate& expr) { | ||||
|         auto pred = static_cast<Tegra::Shader::Pred>(expr.predicate); | ||||
|         inner += decomp.GetPredicate(pred); | ||||
|     } | ||||
| 
 | ||||
|     void operator()(VideoCommon::Shader::ExprCondCode& expr) { | ||||
|         Node cc = decomp.ir.GetConditionCode(expr.cc); | ||||
|         std::string target; | ||||
| 
 | ||||
|         if (const auto pred = std::get_if<PredicateNode>(&*cc)) { | ||||
|             const auto index = pred->GetIndex(); | ||||
|             switch (index) { | ||||
|             case Tegra::Shader::Pred::NeverExecute: | ||||
|                 target = "false"; | ||||
|             case Tegra::Shader::Pred::UnusedIndex: | ||||
|                 target = "true"; | ||||
|             default: | ||||
|                 target = decomp.GetPredicate(index); | ||||
|             } | ||||
|         } else if (const auto flag = std::get_if<InternalFlagNode>(&*cc)) { | ||||
|             target = decomp.GetInternalFlag(flag->GetFlag()); | ||||
|         } | ||||
|         inner += target; | ||||
|     } | ||||
| 
 | ||||
|     void operator()(VideoCommon::Shader::ExprVar& expr) { | ||||
|         inner += flow_var + std::to_string(expr.var_index); | ||||
|     } | ||||
| 
 | ||||
|     void operator()(VideoCommon::Shader::ExprBoolean& expr) { | ||||
|         inner += expr.value ? "true" : "false"; | ||||
|     } | ||||
| 
 | ||||
|     std::string& GetResult() { | ||||
|         return inner; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     std::string inner{}; | ||||
|     GLSLDecompiler& decomp; | ||||
| }; | ||||
| 
 | ||||
| class ASTDecompiler { | ||||
| public: | ||||
|     ASTDecompiler(GLSLDecompiler& decomp) : decomp{decomp} {} | ||||
| 
 | ||||
|     void operator()(VideoCommon::Shader::ASTProgram& ast) { | ||||
|         ASTNode current = ast.nodes.GetFirst(); | ||||
|         while (current) { | ||||
|             Visit(current); | ||||
|             current = current->GetNext(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void operator()(VideoCommon::Shader::ASTIfThen& ast) { | ||||
|         ExprDecompiler expr_parser{decomp}; | ||||
|         std::visit(expr_parser, *ast.condition); | ||||
|         decomp.code.AddLine("if ({}) {{", expr_parser.GetResult()); | ||||
|         decomp.code.scope++; | ||||
|         ASTNode current = ast.nodes.GetFirst(); | ||||
|         while (current) { | ||||
|             Visit(current); | ||||
|             current = current->GetNext(); | ||||
|         } | ||||
|         decomp.code.scope--; | ||||
|         decomp.code.AddLine("}}"); | ||||
|     } | ||||
| 
 | ||||
|     void operator()(VideoCommon::Shader::ASTIfElse& ast) { | ||||
|         decomp.code.AddLine("else {{"); | ||||
|         decomp.code.scope++; | ||||
|         ASTNode current = ast.nodes.GetFirst(); | ||||
|         while (current) { | ||||
|             Visit(current); | ||||
|             current = current->GetNext(); | ||||
|         } | ||||
|         decomp.code.scope--; | ||||
|         decomp.code.AddLine("}}"); | ||||
|     } | ||||
| 
 | ||||
|     void operator()(VideoCommon::Shader::ASTBlockEncoded& ast) { | ||||
|         UNREACHABLE(); | ||||
|     } | ||||
| 
 | ||||
|     void operator()(VideoCommon::Shader::ASTBlockDecoded& ast) { | ||||
|         decomp.VisitBlock(ast.nodes); | ||||
|     } | ||||
| 
 | ||||
|     void operator()(VideoCommon::Shader::ASTVarSet& ast) { | ||||
|         ExprDecompiler expr_parser{decomp}; | ||||
|         std::visit(expr_parser, *ast.condition); | ||||
|         decomp.code.AddLine("{}{} = {};", flow_var, ast.index, expr_parser.GetResult()); | ||||
|     } | ||||
| 
 | ||||
|     void operator()(VideoCommon::Shader::ASTLabel& ast) { | ||||
|         decomp.code.AddLine("// Label_{}:", ast.index); | ||||
|     } | ||||
| 
 | ||||
|     void operator()(VideoCommon::Shader::ASTGoto& ast) { | ||||
|         UNREACHABLE(); | ||||
|     } | ||||
| 
 | ||||
|     void operator()(VideoCommon::Shader::ASTDoWhile& ast) { | ||||
|         ExprDecompiler expr_parser{decomp}; | ||||
|         std::visit(expr_parser, *ast.condition); | ||||
|         decomp.code.AddLine("do {{"); | ||||
|         decomp.code.scope++; | ||||
|         ASTNode current = ast.nodes.GetFirst(); | ||||
|         while (current) { | ||||
|             Visit(current); | ||||
|             current = current->GetNext(); | ||||
|         } | ||||
|         decomp.code.scope--; | ||||
|         decomp.code.AddLine("}} while({});", expr_parser.GetResult()); | ||||
|     } | ||||
| 
 | ||||
|     void operator()(VideoCommon::Shader::ASTReturn& ast) { | ||||
|         bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition); | ||||
|         if (!is_true) { | ||||
|             ExprDecompiler expr_parser{decomp}; | ||||
|             std::visit(expr_parser, *ast.condition); | ||||
|             decomp.code.AddLine("if ({}) {{", expr_parser.GetResult()); | ||||
|             decomp.code.scope++; | ||||
|         } | ||||
|         if (ast.kills) { | ||||
|             decomp.code.AddLine("discard;"); | ||||
|         } else { | ||||
|             decomp.WriteExit(); | ||||
|         } | ||||
|         if (!is_true) { | ||||
|             decomp.code.scope--; | ||||
|             decomp.code.AddLine("}}"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void operator()(VideoCommon::Shader::ASTBreak& ast) { | ||||
|         bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition); | ||||
|         if (!is_true) { | ||||
|             ExprDecompiler expr_parser{decomp}; | ||||
|             std::visit(expr_parser, *ast.condition); | ||||
|             decomp.code.AddLine("if ({}) {{", expr_parser.GetResult()); | ||||
|             decomp.code.scope++; | ||||
|         } | ||||
|         decomp.code.AddLine("break;"); | ||||
|         if (!is_true) { | ||||
|             decomp.code.scope--; | ||||
|             decomp.code.AddLine("}}"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void Visit(VideoCommon::Shader::ASTNode& node) { | ||||
|         std::visit(*this, *node->GetInnerData()); | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     GLSLDecompiler& decomp; | ||||
| }; | ||||
| 
 | ||||
| void GLSLDecompiler::DecompileAST() { | ||||
|     u32 num_flow_variables = ir.GetASTNumVariables(); | ||||
|     for (u32 i = 0; i < num_flow_variables; i++) { | ||||
|         code.AddLine("bool {}{} = false;", flow_var, i); | ||||
|     } | ||||
|     ASTDecompiler decompiler{*this}; | ||||
|     VideoCommon::Shader::ASTNode program = ir.GetASTProgram(); | ||||
|     decompiler.Visit(program); | ||||
| } | ||||
| 
 | ||||
| } // Anonymous namespace
 | ||||
| 
 | ||||
| std::string GetCommonDeclarations() { | ||||
|  | ||||
| @ -372,13 +372,13 @@ ASTManager::~ASTManager() { | ||||
| void ASTManager::Init() { | ||||
|     main_node = ASTBase::Make<ASTProgram>(ASTNode{}); | ||||
|     program = std::get_if<ASTProgram>(main_node->GetInnerData()); | ||||
|     true_condition = MakeExpr<ExprBoolean>(true); | ||||
|     false_condition = MakeExpr<ExprBoolean>(false); | ||||
| } | ||||
| 
 | ||||
| ASTManager::ASTManager(ASTManager&& other) | ||||
|     : labels_map(std::move(other.labels_map)), labels_count{other.labels_count}, | ||||
|       gotos(std::move(other.gotos)), labels(std::move(other.labels)), variables{other.variables}, | ||||
|       program{other.program}, main_node{other.main_node}, true_condition{other.true_condition} { | ||||
|       program{other.program}, main_node{other.main_node}, false_condition{other.false_condition} { | ||||
|     other.main_node.reset(); | ||||
| } | ||||
| 
 | ||||
| @ -390,7 +390,7 @@ ASTManager& ASTManager::operator=(ASTManager&& other) { | ||||
|     variables = other.variables; | ||||
|     program = other.program; | ||||
|     main_node = other.main_node; | ||||
|     true_condition = other.true_condition; | ||||
|     false_condition = other.false_condition; | ||||
| 
 | ||||
|     other.main_node.reset(); | ||||
|     return *this; | ||||
| @ -594,7 +594,7 @@ void ASTManager::MoveOutward(ASTNode goto_node) { | ||||
|         u32 var_index = NewVariable(); | ||||
|         Expr var_condition = MakeExpr<ExprVar>(var_index); | ||||
|         ASTNode var_node = ASTBase::Make<ASTVarSet>(parent, var_index, condition); | ||||
|         ASTNode var_node_init = ASTBase::Make<ASTVarSet>(parent, var_index, true_condition); | ||||
|         ASTNode var_node_init = ASTBase::Make<ASTVarSet>(parent, var_index, false_condition); | ||||
|         zipper2.InsertBefore(var_node_init, parent); | ||||
|         zipper.InsertAfter(var_node, prev); | ||||
|         goto_node->SetGotoCondition(var_condition); | ||||
| @ -605,7 +605,7 @@ void ASTManager::MoveOutward(ASTNode goto_node) { | ||||
|             u32 var_index = NewVariable(); | ||||
|             Expr var_condition = MakeExpr<ExprVar>(var_index); | ||||
|             ASTNode var_node = ASTBase::Make<ASTVarSet>(parent, var_index, condition); | ||||
|             ASTNode var_node_init = ASTBase::Make<ASTVarSet>(parent, var_index, true_condition); | ||||
|             ASTNode var_node_init = ASTBase::Make<ASTVarSet>(parent, var_index, false_condition); | ||||
|             if (is_if) { | ||||
|                 zipper2.InsertBefore(var_node_init, parent); | ||||
|             } else { | ||||
|  | ||||
| @ -141,8 +141,6 @@ public: | ||||
|     Expr condition; | ||||
| }; | ||||
| 
 | ||||
| using TransformCallback = std::function<NodeBlock(u32 start, u32 end)>; | ||||
| 
 | ||||
| class ASTBase { | ||||
| public: | ||||
|     explicit ASTBase(ASTNode parent, ASTData data) : parent{parent}, data{data} {} | ||||
| @ -233,11 +231,7 @@ public: | ||||
|         return std::holds_alternative<ASTBlockEncoded>(data); | ||||
|     } | ||||
| 
 | ||||
|     void TransformBlockEncoded(TransformCallback& callback) { | ||||
|         auto block = std::get_if<ASTBlockEncoded>(&data); | ||||
|         const u32 start = block->start; | ||||
|         const u32 end = block->end; | ||||
|         NodeBlock nodes = callback(start, end); | ||||
|     void TransformBlockEncoded(NodeBlock& nodes) { | ||||
|         data = ASTBlockDecoded(nodes); | ||||
|     } | ||||
| 
 | ||||
| @ -309,16 +303,20 @@ public: | ||||
| 
 | ||||
|     void SanityCheck(); | ||||
| 
 | ||||
|     bool IsFullyDecompiled() { | ||||
|     bool IsFullyDecompiled() const { | ||||
|         return gotos.size() == 0; | ||||
|     } | ||||
| 
 | ||||
|     ASTNode GetProgram() { | ||||
|     ASTNode GetProgram() const { | ||||
|         return main_node; | ||||
|     } | ||||
| 
 | ||||
|     void Clear(); | ||||
| 
 | ||||
|     u32 GetVariables() const { | ||||
|         return variables; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     bool IndirectlyRelated(ASTNode first, ASTNode second); | ||||
| 
 | ||||
| @ -343,7 +341,7 @@ private: | ||||
|     u32 variables{}; | ||||
|     ASTProgram* program{}; | ||||
|     ASTNode main_node{}; | ||||
|     Expr true_condition{}; | ||||
|     Expr false_condition{}; | ||||
| }; | ||||
| 
 | ||||
| } // namespace VideoCommon::Shader
 | ||||
|  | ||||
| @ -425,7 +425,7 @@ void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch) { | ||||
|         } | ||||
|         if (cond.predicate != Pred::UnusedIndex) { | ||||
|             u32 pred = static_cast<u32>(cond.predicate); | ||||
|             bool negate; | ||||
|             bool negate = false; | ||||
|             if (pred > 7) { | ||||
|                 negate = true; | ||||
|                 pred -= 8; | ||||
|  | ||||
| @ -35,10 +35,73 @@ constexpr bool IsSchedInstruction(u32 offset, u32 main_offset) { | ||||
| 
 | ||||
| } // namespace
 | ||||
| 
 | ||||
| class ASTDecoder { | ||||
| public: | ||||
|     ASTDecoder(ShaderIR& ir) : ir(ir) {} | ||||
| 
 | ||||
|     void operator()(ASTProgram& ast) { | ||||
|         ASTNode current = ast.nodes.GetFirst(); | ||||
|         while (current) { | ||||
|             Visit(current); | ||||
|             current = current->GetNext(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void operator()(ASTIfThen& ast) { | ||||
|         ASTNode current = ast.nodes.GetFirst(); | ||||
|         while (current) { | ||||
|             Visit(current); | ||||
|             current = current->GetNext(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void operator()(ASTIfElse& ast) { | ||||
|         ASTNode current = ast.nodes.GetFirst(); | ||||
|         while (current) { | ||||
|             Visit(current); | ||||
|             current = current->GetNext(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void operator()(ASTBlockEncoded& ast) {} | ||||
| 
 | ||||
|     void operator()(ASTBlockDecoded& ast) {} | ||||
| 
 | ||||
|     void operator()(ASTVarSet& ast) {} | ||||
| 
 | ||||
|     void operator()(ASTLabel& ast) {} | ||||
| 
 | ||||
|     void operator()(ASTGoto& ast) {} | ||||
| 
 | ||||
|     void operator()(ASTDoWhile& ast) { | ||||
|         ASTNode current = ast.nodes.GetFirst(); | ||||
|         while (current) { | ||||
|             Visit(current); | ||||
|             current = current->GetNext(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void operator()(ASTReturn& ast) {} | ||||
| 
 | ||||
|     void operator()(ASTBreak& ast) {} | ||||
| 
 | ||||
|     void Visit(ASTNode& node) { | ||||
|         std::visit(*this, *node->GetInnerData()); | ||||
|         if (node->IsBlockEncoded()) { | ||||
|             auto block = std::get_if<ASTBlockEncoded>(node->GetInnerData()); | ||||
|             NodeBlock bb = ir.DecodeRange(block->start, block->end); | ||||
|             node->TransformBlockEncoded(bb); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     ShaderIR& ir; | ||||
| }; | ||||
| 
 | ||||
| void ShaderIR::Decode() { | ||||
|     std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header)); | ||||
| 
 | ||||
|     disable_flow_stack = false; | ||||
|     decompiled = false; | ||||
|     const auto info = | ||||
|         ScanFlow(program_code, program_size, main_offset, program_manager); | ||||
|     if (info) { | ||||
| @ -46,7 +109,10 @@ void ShaderIR::Decode() { | ||||
|         coverage_begin = shader_info.start; | ||||
|         coverage_end = shader_info.end; | ||||
|         if (shader_info.decompiled) { | ||||
|             disable_flow_stack = true; | ||||
|             decompiled = true; | ||||
|             ASTDecoder decoder{*this}; | ||||
|             ASTNode program = GetASTProgram(); | ||||
|             decoder.Visit(program); | ||||
|             return; | ||||
|         } | ||||
|         LOG_WARNING(HW_GPU, "Flow Stack Removing Failed! Falling back to old method"); | ||||
|  | ||||
| @ -157,7 +157,7 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { | ||||
|         UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0, | ||||
|                              "Constant buffer flow is not supported"); | ||||
| 
 | ||||
|         if (disable_flow_stack) { | ||||
|         if (decompiled) { | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
| @ -171,7 +171,7 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { | ||||
|         UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0, | ||||
|                              "Constant buffer PBK is not supported"); | ||||
| 
 | ||||
|         if (disable_flow_stack) { | ||||
|         if (decompiled) { | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
| @ -186,7 +186,7 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { | ||||
|         UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, "SYNC condition code used: {}", | ||||
|                              static_cast<u32>(cc)); | ||||
| 
 | ||||
|         if (disable_flow_stack) { | ||||
|         if (decompiled) { | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
| @ -198,7 +198,7 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { | ||||
|         const Tegra::Shader::ConditionCode cc = instr.flow_condition_code; | ||||
|         UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, "BRK condition code used: {}", | ||||
|                              static_cast<u32>(cc)); | ||||
|         if (disable_flow_stack) { | ||||
|         if (decompiled) { | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|  | ||||
| @ -72,4 +72,11 @@ bool ExprAreOpposite(Expr first, Expr second) { | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| bool ExprIsTrue(Expr first) { | ||||
|     if (ExprIsBoolean(first)) { | ||||
|         return ExprBooleanGet(first); | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| } // namespace VideoCommon::Shader
 | ||||
|  | ||||
| @ -115,4 +115,6 @@ Expr MakeExprAnd(Expr first, Expr second); | ||||
| 
 | ||||
| Expr MakeExprOr(Expr first, Expr second); | ||||
| 
 | ||||
| bool ExprIsTrue(Expr first); | ||||
| 
 | ||||
| } // namespace VideoCommon::Shader
 | ||||
|  | ||||
| @ -137,7 +137,7 @@ Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buff | ||||
|     return MakeNode<AbufNode>(index, static_cast<u32>(element), std::move(buffer)); | ||||
| } | ||||
| 
 | ||||
| Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) { | ||||
| Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) const { | ||||
|     const Node node = MakeNode<InternalFlagNode>(flag); | ||||
|     if (negated) { | ||||
|         return Operation(OperationCode::LogicalNegate, node); | ||||
| @ -367,13 +367,13 @@ OperationCode ShaderIR::GetPredicateCombiner(PredOperation operation) { | ||||
|     return op->second; | ||||
| } | ||||
| 
 | ||||
| Node ShaderIR::GetConditionCode(Tegra::Shader::ConditionCode cc) { | ||||
| Node ShaderIR::GetConditionCode(Tegra::Shader::ConditionCode cc) const { | ||||
|     switch (cc) { | ||||
|     case Tegra::Shader::ConditionCode::NEU: | ||||
|         return GetInternalFlag(InternalFlag::Zero, true); | ||||
|     default: | ||||
|         UNIMPLEMENTED_MSG("Unimplemented condition code: {}", static_cast<u32>(cc)); | ||||
|         return GetPredicate(static_cast<u64>(Pred::NeverExecute)); | ||||
|         return MakeNode<PredicateNode>(Pred::NeverExecute, false); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -15,8 +15,8 @@ | ||||
| #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" | ||||
| #include "video_core/shader/ast.h" | ||||
| #include "video_core/shader/node.h" | ||||
| 
 | ||||
| namespace VideoCommon::Shader { | ||||
| 
 | ||||
| @ -141,15 +141,27 @@ public: | ||||
|         return header; | ||||
|     } | ||||
| 
 | ||||
|     bool IsFlowStackDisabled() const { | ||||
|         return disable_flow_stack; | ||||
|     bool IsDecompiled() const { | ||||
|         return decompiled; | ||||
|     } | ||||
| 
 | ||||
|     ASTNode GetASTProgram() const { | ||||
|         return program_manager.GetProgram(); | ||||
|     } | ||||
| 
 | ||||
|     u32 GetASTNumVariables() const { | ||||
|         return program_manager.GetVariables(); | ||||
|     } | ||||
| 
 | ||||
|     u32 ConvertAddressToNvidiaSpace(const u32 address) const { | ||||
|         return (address - main_offset) * sizeof(Tegra::Shader::Instruction); | ||||
|     } | ||||
| 
 | ||||
|     /// Returns a condition code evaluated from internal flags
 | ||||
|     Node GetConditionCode(Tegra::Shader::ConditionCode cc) const; | ||||
| 
 | ||||
| private: | ||||
|     friend class ASTDecoder; | ||||
|     void Decode(); | ||||
| 
 | ||||
|     NodeBlock DecodeRange(u32 begin, u32 end); | ||||
| @ -214,7 +226,7 @@ private: | ||||
|     /// Generates a node representing an output attribute. Keeps track of used attributes.
 | ||||
|     Node GetOutputAttribute(Tegra::Shader::Attribute::Index index, u64 element, Node buffer); | ||||
|     /// Generates a node representing an internal flag
 | ||||
|     Node GetInternalFlag(InternalFlag flag, bool negated = false); | ||||
|     Node GetInternalFlag(InternalFlag flag, bool negated = false) const; | ||||
|     /// Generates a node representing a local memory address
 | ||||
|     Node GetLocalMemory(Node address); | ||||
|     /// Generates a node representing a shared memory address
 | ||||
| @ -272,9 +284,6 @@ private: | ||||
|     /// Returns a predicate combiner operation
 | ||||
|     OperationCode GetPredicateCombiner(Tegra::Shader::PredOperation operation); | ||||
| 
 | ||||
|     /// Returns a condition code evaluated from internal flags
 | ||||
|     Node GetConditionCode(Tegra::Shader::ConditionCode cc); | ||||
| 
 | ||||
|     /// Accesses a texture sampler
 | ||||
|     const Sampler& GetSampler(const Tegra::Shader::Sampler& sampler, | ||||
|                               Tegra::Shader::TextureType type, bool is_array, bool is_shadow); | ||||
| @ -358,7 +367,7 @@ private: | ||||
|     const ProgramCode& program_code; | ||||
|     const u32 main_offset; | ||||
|     const std::size_t program_size; | ||||
|     bool disable_flow_stack{}; | ||||
|     bool decompiled{}; | ||||
| 
 | ||||
|     u32 coverage_begin{}; | ||||
|     u32 coverage_end{}; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user