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