From 38fc995f6cc2c2af29abc976ddb45b72873b2cc4 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 29 Jun 2019 01:44:07 -0400 Subject: gl_shader_decompiler: Implement AST decompiling --- .../renderer_opengl/gl_shader_decompiler.cpp | 271 ++++++++++++++++++--- 1 file changed, 242 insertions(+), 29 deletions(-) (limited to 'src/video_core/renderer_opengl') diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 8fa9e6534..2955c6abf 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -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)); - } + 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("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("}}"); + --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(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(&*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(&*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() { -- cgit v1.2.3 From 47e4f6a52c5eb34916e2c1f4c876e6e8624e3840 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 16 Aug 2019 16:25:02 -0400 Subject: Shader_Ir: Refactor Decompilation process and allow multiple decompilation modes. --- CMakeModules/GenerateSCMRev.cmake | 2 + src/common/CMakeLists.txt | 2 + src/video_core/CMakeLists.txt | 2 + .../renderer_opengl/gl_shader_decompiler.cpp | 8 +- src/video_core/renderer_opengl/gl_shader_gen.cpp | 25 ++++-- src/video_core/shader/ast.cpp | 98 ++++++++++++++++++++-- src/video_core/shader/ast.h | 20 ++++- src/video_core/shader/compiler_settings.cpp | 26 ++++++ src/video_core/shader/compiler_settings.h | 25 ++++++ src/video_core/shader/control_flow.cpp | 92 +++++++++++++------- src/video_core/shader/control_flow.h | 10 ++- src/video_core/shader/decode.cpp | 86 +++++++++++++------ src/video_core/shader/decode/other.cpp | 8 +- src/video_core/shader/shader_ir.cpp | 6 +- src/video_core/shader/shader_ir.h | 10 ++- 15 files changed, 338 insertions(+), 82 deletions(-) create mode 100644 src/video_core/shader/compiler_settings.cpp create mode 100644 src/video_core/shader/compiler_settings.h (limited to 'src/video_core/renderer_opengl') diff --git a/CMakeModules/GenerateSCMRev.cmake b/CMakeModules/GenerateSCMRev.cmake index d3ab22c08..09eabe2c7 100644 --- a/CMakeModules/GenerateSCMRev.cmake +++ b/CMakeModules/GenerateSCMRev.cmake @@ -87,6 +87,8 @@ set(HASH_FILES "${VIDEO_CORE}/shader/ast.h" "${VIDEO_CORE}/shader/control_flow.cpp" "${VIDEO_CORE}/shader/control_flow.h" + "${VIDEO_CORE}/shader/compiler_settings.cpp" + "${VIDEO_CORE}/shader/compiler_settings.h" "${VIDEO_CORE}/shader/decode.cpp" "${VIDEO_CORE}/shader/expr.cpp" "${VIDEO_CORE}/shader/expr.h" diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index afc5ff736..0ed96c0d4 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -64,6 +64,8 @@ add_custom_command(OUTPUT scm_rev.cpp "${VIDEO_CORE}/shader/ast.h" "${VIDEO_CORE}/shader/control_flow.cpp" "${VIDEO_CORE}/shader/control_flow.h" + "${VIDEO_CORE}/shader/compiler_settings.cpp" + "${VIDEO_CORE}/shader/compiler_settings.h" "${VIDEO_CORE}/shader/decode.cpp" "${VIDEO_CORE}/shader/expr.cpp" "${VIDEO_CORE}/shader/expr.h" diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 33fa88762..eaa694ff8 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -109,6 +109,8 @@ add_library(video_core STATIC shader/ast.h shader/control_flow.cpp shader/control_flow.h + shader/compiler_settings.cpp + shader/compiler_settings.h shader/decode.cpp shader/expr.cpp shader/expr.h diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 2955c6abf..b8c3442bc 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -352,9 +352,11 @@ public: // 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. 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)); + if (!ir.IsFlowStackDisabled()) { + 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("while (true) {{"); diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 3a8d9e1da..72a49ebdc 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -11,6 +11,8 @@ namespace OpenGL::GLShader { using Tegra::Engines::Maxwell3D; +using VideoCommon::Shader::CompileDepth; +using VideoCommon::Shader::CompilerSettings; using VideoCommon::Shader::ProgramCode; using VideoCommon::Shader::ShaderIR; @@ -31,13 +33,17 @@ layout (std140, binding = EMULATION_UBO_BINDING) uniform vs_config { )"; - const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET, setup.program.size_a); + CompilerSettings settings; + settings.depth = CompileDepth::NoFlowStack; + + const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET, setup.program.size_a, settings); const auto stage = setup.IsDualProgram() ? ProgramType::VertexA : ProgramType::VertexB; ProgramResult program = Decompile(device, program_ir, stage, "vertex"); out += program.first; if (setup.IsDualProgram()) { - const ShaderIR program_ir_b(setup.program.code_b, PROGRAM_OFFSET, setup.program.size_b); + const ShaderIR program_ir_b(setup.program.code_b, PROGRAM_OFFSET, setup.program.size_b, + settings); ProgramResult program_b = Decompile(device, program_ir_b, ProgramType::VertexB, "vertex_b"); out += program_b.first; } @@ -80,7 +86,10 @@ layout (std140, binding = EMULATION_UBO_BINDING) uniform gs_config { )"; - const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET, setup.program.size_a); + CompilerSettings settings; + settings.depth = CompileDepth::NoFlowStack; + + const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET, setup.program.size_a, settings); ProgramResult program = Decompile(device, program_ir, ProgramType::Geometry, "geometry"); out += program.first; @@ -114,7 +123,10 @@ layout (std140, binding = EMULATION_UBO_BINDING) uniform fs_config { }; )"; - const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET, setup.program.size_a); + CompilerSettings settings; + settings.depth = CompileDepth::NoFlowStack; + + const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET, setup.program.size_a, settings); ProgramResult program = Decompile(device, program_ir, ProgramType::Fragment, "fragment"); out += program.first; @@ -133,7 +145,10 @@ ProgramResult GenerateComputeShader(const Device& device, const ShaderSetup& set std::string out = "// Shader Unique Id: CS" + id + "\n\n"; out += GetCommonDeclarations(); - const ShaderIR program_ir(setup.program.code, COMPUTE_OFFSET, setup.program.size_a); + CompilerSettings settings; + settings.depth = CompileDepth::NoFlowStack; + + const ShaderIR program_ir(setup.program.code, COMPUTE_OFFSET, setup.program.size_a, settings); ProgramResult program = Decompile(device, program_ir, ProgramType::Compute, "compute"); out += program.first; diff --git a/src/video_core/shader/ast.cpp b/src/video_core/shader/ast.cpp index 68a96cc79..14c50e1c6 100644 --- a/src/video_core/shader/ast.cpp +++ b/src/video_core/shader/ast.cpp @@ -363,7 +363,7 @@ std::string ASTManager::Print() { return printer.GetResult(); } -ASTManager::ASTManager() = default; +ASTManager::ASTManager(bool full_decompile) : full_decompile{full_decompile} {}; ASTManager::~ASTManager() { Clear(); @@ -383,6 +383,7 @@ ASTManager::ASTManager(ASTManager&& other) } ASTManager& ASTManager::operator=(ASTManager&& other) { + full_decompile = other.full_decompile; labels_map = std::move(other.labels_map); labels_count = other.labels_count; gotos = std::move(other.gotos); @@ -434,6 +435,13 @@ void ASTManager::Decompile() { ASTNode goto_node = *it; u32 label_index = goto_node->GetGotoLabel(); ASTNode label = labels[label_index]; + if (!full_decompile) { + // We only decompile backward jumps + if (!IsBackwardsJump(goto_node, label)) { + it++; + continue; + } + } if (IndirectlyRelated(goto_node, label)) { while (!DirectlyRelated(goto_node, label)) { MoveOutward(goto_node); @@ -469,11 +477,91 @@ void ASTManager::Decompile() { } it++; } - for (ASTNode label : labels) { - auto& manager = label->GetManager(); - manager.Remove(label); + if (full_decompile) { + for (ASTNode label : labels) { + auto& manager = label->GetManager(); + manager.Remove(label); + } + labels.clear(); + } else { + auto it = labels.begin(); + while (it != labels.end()) { + bool can_remove = true; + ASTNode label = *it; + for (ASTNode goto_node : gotos) { + u32 label_index = goto_node->GetGotoLabel(); + ASTNode glabel = labels[label_index]; + if (glabel == label) { + can_remove = false; + break; + } + } + if (can_remove) { + auto& manager = label->GetManager(); + manager.Remove(label); + labels.erase(it); + } + } } - labels.clear(); +} + +bool ASTManager::IsBackwardsJump(ASTNode goto_node, ASTNode label_node) const { + u32 goto_level = goto_node->GetLevel(); + u32 label_level = label_node->GetLevel(); + while (goto_level > label_level) { + goto_level--; + goto_node = goto_node->GetParent(); + } + while (label_level > goto_level) { + label_level--; + label_node = label_node->GetParent(); + } + while (goto_node->GetParent() != label_node->GetParent()) { + goto_node = goto_node->GetParent(); + label_node = label_node->GetParent(); + } + ASTNode current = goto_node->GetPrevious(); + while (current) { + if (current == label_node) { + return true; + } + current = current->GetPrevious(); + } + return false; +} + +ASTNode CommonParent(ASTNode first, ASTNode second) { + if (first->GetParent() == second->GetParent()) { + return first->GetParent(); + } + u32 first_level = first->GetLevel(); + u32 second_level = second->GetLevel(); + u32 min_level; + u32 max_level; + ASTNode max; + ASTNode min; + if (first_level > second_level) { + min_level = second_level; + min = second; + max_level = first_level; + max = first; + } else { + min_level = first_level; + min = first; + max_level = second_level; + max = second; + } + + while (max_level > min_level) { + max_level--; + max = max->GetParent(); + } + + while (min->GetParent() != max->GetParent()) { + min = min->GetParent(); + max = max->GetParent(); + } + return min->GetParent(); } bool ASTManager::IndirectlyRelated(ASTNode first, ASTNode second) { diff --git a/src/video_core/shader/ast.h b/src/video_core/shader/ast.h index 06ab20cc5..849d0612c 100644 --- a/src/video_core/shader/ast.h +++ b/src/video_core/shader/ast.h @@ -274,7 +274,7 @@ private: class ASTManager final { public: - ASTManager(); + ASTManager(bool full_decompile); ~ASTManager(); ASTManager(const ASTManager& o) = delete; @@ -304,7 +304,18 @@ public: void SanityCheck(); bool IsFullyDecompiled() const { - return gotos.size() == 0; + if (full_decompile) { + return gotos.size() == 0; + } else { + for (ASTNode goto_node : gotos) { + u32 label_index = goto_node->GetGotoLabel(); + ASTNode glabel = labels[label_index]; + if (IsBackwardsJump(goto_node, glabel)) { + return false; + } + } + return true; + } } ASTNode GetProgram() const { @@ -318,6 +329,10 @@ public: } private: + bool IsBackwardsJump(ASTNode goto_node, ASTNode label_node) const; + + ASTNode CommonParent(ASTNode first, ASTNode second); + bool IndirectlyRelated(ASTNode first, ASTNode second); bool DirectlyRelated(ASTNode first, ASTNode second); @@ -334,6 +349,7 @@ private: return new_var; } + bool full_decompile{}; std::unordered_map labels_map{}; u32 labels_count{}; std::vector labels{}; diff --git a/src/video_core/shader/compiler_settings.cpp b/src/video_core/shader/compiler_settings.cpp new file mode 100644 index 000000000..cddcbd4f0 --- /dev/null +++ b/src/video_core/shader/compiler_settings.cpp @@ -0,0 +1,26 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "video_core/shader/compiler_settings.h" + +namespace VideoCommon::Shader { + +std::string CompileDepthAsString(const CompileDepth cd) { + switch (cd) { + case CompileDepth::BruteForce: + return "Brute Force Compile"; + case CompileDepth::FlowStack: + return "Simple Flow Stack Mode"; + case CompileDepth::NoFlowStack: + return "Remove Flow Stack"; + case CompileDepth::DecompileBackwards: + return "Decompile Backward Jumps"; + case CompileDepth::FullDecompile: + return "Full Decompilation"; + default: + return "Unknown Compiler Process"; + } +} + +} // namespace VideoCommon::Shader diff --git a/src/video_core/shader/compiler_settings.h b/src/video_core/shader/compiler_settings.h new file mode 100644 index 000000000..e1fb5bc3a --- /dev/null +++ b/src/video_core/shader/compiler_settings.h @@ -0,0 +1,25 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "video_core/engines/shader_bytecode.h" + +namespace VideoCommon::Shader { + +enum class CompileDepth : u32 { + BruteForce = 0, + FlowStack = 1, + NoFlowStack = 2, + DecompileBackwards = 3, + FullDecompile = 4, +}; + +std::string CompileDepthAsString(CompileDepth cd); + +struct CompilerSettings { + CompileDepth depth; +}; + +} // namespace VideoCommon::Shader diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp index a29922815..c4351969b 100644 --- a/src/video_core/shader/control_flow.cpp +++ b/src/video_core/shader/control_flow.cpp @@ -57,8 +57,8 @@ struct BlockInfo { struct CFGRebuildState { explicit CFGRebuildState(const ProgramCode& program_code, const std::size_t program_size, - const u32 start, ASTManager& manager) - : program_code{program_code}, program_size{program_size}, start{start}, manager{manager} {} + const u32 start) + : program_code{program_code}, program_size{program_size}, start{start} {} u32 start{}; std::vector block_info{}; @@ -71,7 +71,7 @@ struct CFGRebuildState { std::unordered_map stacks{}; const ProgramCode& program_code; const std::size_t program_size; - ASTManager& manager; + ASTManager* manager; }; enum class BlockCollision : u32 { None, Found, Inside }; @@ -456,67 +456,91 @@ void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch) { } void DecompileShader(CFGRebuildState& state) { - state.manager.Init(); + state.manager->Init(); for (auto label : state.labels) { - state.manager.DeclareLabel(label); + state.manager->DeclareLabel(label); } for (auto& block : state.block_info) { if (state.labels.count(block.start) != 0) { - state.manager.InsertLabel(block.start); + state.manager->InsertLabel(block.start); } u32 end = block.branch.ignore ? block.end + 1 : block.end; - state.manager.InsertBlock(block.start, end); + state.manager->InsertBlock(block.start, end); if (!block.branch.ignore) { - InsertBranch(state.manager, block.branch); + InsertBranch(*state.manager, block.branch); } } - // state.manager.ShowCurrentState("Before Decompiling"); - state.manager.Decompile(); - // state.manager.ShowCurrentState("After Decompiling"); + state.manager->Decompile(); } std::unique_ptr ScanFlow(const ProgramCode& program_code, u32 program_size, - u32 start_address, ASTManager& manager) { - CFGRebuildState state{program_code, program_size, start_address, manager}; + u32 start_address, + const CompilerSettings& settings) { + auto result_out = std::make_unique(); + if (settings.depth == CompileDepth::BruteForce) { + result_out->settings.depth = CompileDepth::BruteForce; + return std::move(result_out); + } + + CFGRebuildState state{program_code, program_size, start_address}; // Inspect Code and generate blocks state.labels.clear(); state.labels.emplace(start_address); state.inspect_queries.push_back(state.start); while (!state.inspect_queries.empty()) { if (!TryInspectAddress(state)) { - return {}; + result_out->settings.depth = CompileDepth::BruteForce; + return std::move(result_out); } } - // Decompile Stacks - state.queries.push_back(Query{state.start, {}, {}}); - bool decompiled = true; - while (!state.queries.empty()) { - if (!TryQuery(state)) { - decompiled = false; - break; + bool use_flow_stack = true; + + bool decompiled = false; + + if (settings.depth != CompileDepth::FlowStack) { + // Decompile Stacks + state.queries.push_back(Query{state.start, {}, {}}); + decompiled = true; + while (!state.queries.empty()) { + if (!TryQuery(state)) { + decompiled = false; + break; + } } } + use_flow_stack = !decompiled; + // Sort and organize results std::sort(state.block_info.begin(), state.block_info.end(), [](const BlockInfo& a, const BlockInfo& b) -> bool { return a.start < b.start; }); - if (decompiled) { + if (decompiled && settings.depth != CompileDepth::NoFlowStack) { + ASTManager manager{settings.depth != CompileDepth::DecompileBackwards}; + state.manager = &manager; DecompileShader(state); - decompiled = state.manager.IsFullyDecompiled(); + decompiled = state.manager->IsFullyDecompiled(); if (!decompiled) { - LOG_CRITICAL(HW_GPU, "Failed to remove all the gotos!:"); - state.manager.ShowCurrentState("Of Shader"); - state.manager.Clear(); + if (settings.depth == CompileDepth::FullDecompile) { + LOG_CRITICAL(HW_GPU, "Failed to remove all the gotos!:"); + } else { + LOG_CRITICAL(HW_GPU, "Failed to remove all backward gotos!:"); + } + state.manager->ShowCurrentState("Of Shader"); + state.manager->Clear(); + } else { + auto result_out = std::make_unique(); + result_out->start = start_address; + result_out->settings.depth = settings.depth; + result_out->manager = std::move(manager); + result_out->end = state.block_info.back().end + 1; + return std::move(result_out); } } - auto result_out = std::make_unique(); - result_out->decompiled = decompiled; result_out->start = start_address; - if (decompiled) { - result_out->end = state.block_info.back().end + 1; - return std::move(result_out); - } + result_out->settings.depth = + use_flow_stack ? CompileDepth::FlowStack : CompileDepth::NoFlowStack; + result_out->blocks.clear(); for (auto& block : state.block_info) { ShaderBlock new_block{}; new_block.start = block.start; @@ -530,6 +554,10 @@ std::unique_ptr ScanFlow(const ProgramCode& program_code, result_out->end = std::max(result_out->end, block.end); result_out->blocks.push_back(new_block); } + if (!use_flow_stack) { + result_out->labels = std::move(state.labels); + return std::move(result_out); + } auto back = result_out->blocks.begin(); auto next = std::next(back); while (next != result_out->blocks.end()) { diff --git a/src/video_core/shader/control_flow.h b/src/video_core/shader/control_flow.h index 347a35dcf..8d0d08422 100644 --- a/src/video_core/shader/control_flow.h +++ b/src/video_core/shader/control_flow.h @@ -9,8 +9,9 @@ #include #include "video_core/engines/shader_bytecode.h" -#include "video_core/shader/shader_ir.h" #include "video_core/shader/ast.h" +#include "video_core/shader/compiler_settings.h" +#include "video_core/shader/shader_ir.h" namespace VideoCommon::Shader { @@ -68,12 +69,15 @@ struct ShaderBlock { struct ShaderCharacteristics { std::list blocks{}; - bool decompiled{}; + std::set labels{}; u32 start{}; u32 end{}; + ASTManager manager{true}; + CompilerSettings settings{}; }; std::unique_ptr ScanFlow(const ProgramCode& program_code, u32 program_size, - u32 start_address, ASTManager& manager); + u32 start_address, + const CompilerSettings& settings); } // namespace VideoCommon::Shader diff --git a/src/video_core/shader/decode.cpp b/src/video_core/shader/decode.cpp index e7e0903f6..6d4359295 100644 --- a/src/video_core/shader/decode.cpp +++ b/src/video_core/shader/decode.cpp @@ -102,35 +102,71 @@ void ShaderIR::Decode() { std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header)); decompiled = false; - const auto info = - ScanFlow(program_code, program_size, main_offset, program_manager); - if (info) { - const auto& shader_info = *info; - coverage_begin = shader_info.start; - coverage_end = shader_info.end; - if (shader_info.decompiled) { - 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"); - // we can't decompile it, fallback to standard method + auto info = ScanFlow(program_code, program_size, main_offset, settings); + auto& shader_info = *info; + coverage_begin = shader_info.start; + coverage_end = shader_info.end; + switch (shader_info.settings.depth) { + case CompileDepth::FlowStack: { for (const auto& block : shader_info.blocks) { basic_blocks.insert({block.start, DecodeRange(block.start, block.end + 1)}); } - return; + break; + } + case CompileDepth::NoFlowStack: { + disable_flow_stack = true; + const auto insert_block = [this](NodeBlock& nodes, u32 label) { + if (label == static_cast(exit_branch)) { + return; + } + basic_blocks.insert({label, nodes}); + }; + const auto& blocks = shader_info.blocks; + NodeBlock current_block; + u32 current_label = static_cast(exit_branch); + for (auto& block : blocks) { + if (shader_info.labels.count(block.start) != 0) { + insert_block(current_block, current_label); + current_block.clear(); + current_label = block.start; + } + if (!block.ignore_branch) { + DecodeRangeInner(current_block, block.start, block.end); + InsertControlFlow(current_block, block); + } else { + DecodeRangeInner(current_block, block.start, block.end + 1); + } + } + insert_block(current_block, current_label); + break; + } + case CompileDepth::DecompileBackwards: + case CompileDepth::FullDecompile: { + program_manager = std::move(shader_info.manager); + disable_flow_stack = true; + decompiled = true; + ASTDecoder decoder{*this}; + ASTNode program = GetASTProgram(); + decoder.Visit(program); + break; + } + default: + LOG_CRITICAL(HW_GPU, "Unknown decompilation mode!"); + [[fallthrough]]; + case CompileDepth::BruteForce: { + coverage_begin = main_offset; + const u32 shader_end = static_cast(program_size / sizeof(u64)); + coverage_end = shader_end; + for (u32 label = main_offset; label < shader_end; label++) { + basic_blocks.insert({label, DecodeRange(label, label + 1)}); + } + break; + } } - LOG_WARNING(HW_GPU, "Flow Analysis Failed! Falling back to brute force compiling"); - - // Now we need to deal with an undecompilable shader. We need to brute force - // a shader that captures every position. - coverage_begin = main_offset; - const u32 shader_end = static_cast(program_size / sizeof(u64)); - coverage_end = shader_end; - for (u32 label = main_offset; label < shader_end; label++) { - basic_blocks.insert({label, DecodeRange(label, label + 1)}); + if (settings.depth != shader_info.settings.depth) { + LOG_WARNING( + HW_GPU, "Decompiling to this setting \"{}\" failed, downgrading to this setting \"{}\"", + CompileDepthAsString(settings.depth), CompileDepthAsString(shader_info.settings.depth)); } } diff --git a/src/video_core/shader/decode/other.cpp b/src/video_core/shader/decode/other.cpp index 6f678003c..d46e0f823 100644 --- a/src/video_core/shader/decode/other.cpp +++ b/src/video_core/shader/decode/other.cpp @@ -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 (decompiled) { + if (disable_flow_stack) { 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 (decompiled) { + if (disable_flow_stack) { 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(cc)); - if (decompiled) { + if (disable_flow_stack) { 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(cc)); - if (decompiled) { + if (disable_flow_stack) { break; } diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp index 004b1e16f..04e364634 100644 --- a/src/video_core/shader/shader_ir.cpp +++ b/src/video_core/shader/shader_ir.cpp @@ -22,8 +22,10 @@ using Tegra::Shader::PredCondition; using Tegra::Shader::PredOperation; using Tegra::Shader::Register; -ShaderIR::ShaderIR(const ProgramCode& program_code, u32 main_offset, const std::size_t size) - : program_code{program_code}, main_offset{main_offset}, program_size{size}, program_manager{} { +ShaderIR::ShaderIR(const ProgramCode& program_code, u32 main_offset, const std::size_t size, + CompilerSettings settings) + : program_code{program_code}, main_offset{main_offset}, program_size{size}, basic_blocks{}, + program_manager{true}, settings{settings} { Decode(); } diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index 48c7b722e..7a91c9bb6 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h @@ -16,6 +16,7 @@ #include "video_core/engines/shader_bytecode.h" #include "video_core/engines/shader_header.h" #include "video_core/shader/ast.h" +#include "video_core/shader/compiler_settings.h" #include "video_core/shader/node.h" namespace VideoCommon::Shader { @@ -65,7 +66,8 @@ struct GlobalMemoryUsage { class ShaderIR final { public: - explicit ShaderIR(const ProgramCode& program_code, u32 main_offset, std::size_t size); + explicit ShaderIR(const ProgramCode& program_code, u32 main_offset, std::size_t size, + CompilerSettings settings); ~ShaderIR(); const std::map& GetBasicBlocks() const { @@ -141,6 +143,10 @@ public: return header; } + bool IsFlowStackDisabled() const { + return disable_flow_stack; + } + bool IsDecompiled() const { return decompiled; } @@ -368,6 +374,7 @@ private: const u32 main_offset; const std::size_t program_size; bool decompiled{}; + bool disable_flow_stack{}; u32 coverage_begin{}; u32 coverage_end{}; @@ -375,6 +382,7 @@ private: std::map basic_blocks; NodeBlock global_code; ASTManager program_manager; + CompilerSettings settings{}; std::set used_registers; std::set used_predicates; -- cgit v1.2.3 From 189a50bc2addbf43824be396f205e900af7523b3 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 22 Sep 2019 12:33:13 -0400 Subject: gl_shader_decompiler: Refactor and address feedback. --- .../renderer_opengl/gl_shader_decompiler.cpp | 35 +++++++++++----------- 1 file changed, 18 insertions(+), 17 deletions(-) (limited to 'src/video_core/renderer_opengl') diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index b8c3442bc..572fae353 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -355,7 +355,7 @@ public: if (!ir.IsFlowStackDisabled()) { 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)); } } @@ -1837,10 +1837,9 @@ private: return {}; } - Expression WriteExit() { + void PreExit() { if (stage != ProgramType::Fragment) { - code.AddLine("return;"); - return {}; + return; } const auto& used_registers = ir.GetRegisters(); const auto SafeGetRegister = [&](u32 reg) -> Expression { @@ -1872,13 +1871,12 @@ private: // already contains one past the last color register. code.AddLine("gl_FragDepth = {};", SafeGetRegister(current_reg + 1).AsFloat()); } - - code.AddLine("return;"); - return {}; } Expression Exit(Operation operation) { - return WriteExit(); + PreExit(); + code.AddLine("return;"); + return {}; } Expression Discard(Operation operation) { @@ -2277,7 +2275,7 @@ const std::string flow_var = "flow_var_"; class ExprDecompiler { public: - ExprDecompiler(GLSLDecompiler& decomp) : decomp{decomp} {} + explicit ExprDecompiler(GLSLDecompiler& decomp) : decomp{decomp} {} void operator()(VideoCommon::Shader::ExprAnd& expr) { inner += "( "; @@ -2301,12 +2299,12 @@ public: } void operator()(VideoCommon::Shader::ExprPredicate& expr) { - auto pred = static_cast(expr.predicate); + const auto pred = static_cast(expr.predicate); inner += decomp.GetPredicate(pred); } void operator()(VideoCommon::Shader::ExprCondCode& expr) { - Node cc = decomp.ir.GetConditionCode(expr.cc); + const Node cc = decomp.ir.GetConditionCode(expr.cc); std::string target; if (const auto pred = std::get_if(&*cc)) { @@ -2321,6 +2319,8 @@ public: } } else if (const auto flag = std::get_if(&*cc)) { target = decomp.GetInternalFlag(flag->GetFlag()); + } else { + UNREACHABLE(); } inner += target; } @@ -2338,13 +2338,13 @@ public: } private: - std::string inner{}; + std::string inner; GLSLDecompiler& decomp; }; class ASTDecompiler { public: - ASTDecompiler(GLSLDecompiler& decomp) : decomp{decomp} {} + explicit ASTDecompiler(GLSLDecompiler& decomp) : decomp{decomp} {} void operator()(VideoCommon::Shader::ASTProgram& ast) { ASTNode current = ast.nodes.GetFirst(); @@ -2417,7 +2417,7 @@ public: } void operator()(VideoCommon::Shader::ASTReturn& ast) { - bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition); + const bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition); if (!is_true) { ExprDecompiler expr_parser{decomp}; std::visit(expr_parser, *ast.condition); @@ -2427,7 +2427,8 @@ public: if (ast.kills) { decomp.code.AddLine("discard;"); } else { - decomp.WriteExit(); + decomp.PreExit(); + decomp.code.AddLine("return;"); } if (!is_true) { decomp.code.scope--; @@ -2436,7 +2437,7 @@ public: } void operator()(VideoCommon::Shader::ASTBreak& ast) { - bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition); + const bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition); if (!is_true) { ExprDecompiler expr_parser{decomp}; std::visit(expr_parser, *ast.condition); @@ -2459,7 +2460,7 @@ private: }; void GLSLDecompiler::DecompileAST() { - u32 num_flow_variables = ir.GetASTNumVariables(); + const u32 num_flow_variables = ir.GetASTNumVariables(); for (u32 i = 0; i < num_flow_variables; i++) { code.AddLine("bool {}{} = false;", flow_var, i); } -- cgit v1.2.3 From 000ad558dd21a0f1f0be57ddbb59540956314896 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 24 Sep 2019 10:57:45 -0400 Subject: vk_shader_decompiler: Clean code and be const correct. --- src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 2 +- src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'src/video_core/renderer_opengl') diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 572fae353..bff1067a4 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -19,8 +19,8 @@ #include "video_core/renderer_opengl/gl_device.h" #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/node.h" #include "video_core/shader/shader_ir.h" namespace OpenGL::GLShader { diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 11effe4a1..4bc7da198 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp @@ -1659,12 +1659,12 @@ public: } void operator()(VideoCommon::Shader::ExprPredicate& expr) { - auto pred = static_cast(expr.predicate); + const auto pred = static_cast(expr.predicate); current_id = decomp.Emit(decomp.OpLoad(decomp.t_bool, decomp.predicates.at(pred))); } void operator()(VideoCommon::Shader::ExprCondCode& expr) { - Node cc = decomp.ir.GetConditionCode(expr.cc); + const Node cc = decomp.ir.GetConditionCode(expr.cc); Id target; if (const auto pred = std::get_if(&*cc)) { @@ -1785,8 +1785,7 @@ public: } void operator()(VideoCommon::Shader::ASTReturn& ast) { - bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition); - if (!is_true) { + if (!VideoCommon::Shader::ExprIsTrue(ast.condition)) { ExprDecompiler expr_parser{decomp}; const Id condition = expr_parser.Visit(ast.condition); const Id then_label = decomp.OpLabel(); @@ -1816,8 +1815,7 @@ public: } void operator()(VideoCommon::Shader::ASTBreak& ast) { - bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition); - if (!is_true) { + if (!VideoCommon::Shader::ExprIsTrue(ast.condition)) { ExprDecompiler expr_parser{decomp}; const Id condition = expr_parser.Visit(ast.condition); const Id then_label = decomp.OpLabel(); @@ -1846,7 +1844,7 @@ private: }; void SPIRVDecompiler::DecompileAST() { - u32 num_flow_variables = ir.GetASTNumVariables(); + const u32 num_flow_variables = ir.GetASTNumVariables(); for (u32 i = 0; i < num_flow_variables; i++) { const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false); Name(id, fmt::format("flow_var_{}", i)); -- cgit v1.2.3 From e6eae4b815bf4bc480d62677fdf9bdbf5d6cba82 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 4 Oct 2019 17:23:16 -0400 Subject: Shader_ir: Address feedback --- .../renderer_opengl/gl_shader_decompiler.cpp | 12 ++++-- src/video_core/renderer_opengl/gl_shader_gen.cpp | 13 +----- src/video_core/shader/ast.cpp | 48 ++++------------------ src/video_core/shader/ast.h | 12 +++--- src/video_core/shader/control_flow.cpp | 2 +- src/video_core/shader/decode.cpp | 2 +- 6 files changed, 24 insertions(+), 65 deletions(-) (limited to 'src/video_core/renderer_opengl') diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index bff1067a4..6a610a3bc 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp @@ -2271,7 +2271,11 @@ private: ShaderWriter code; }; -const std::string flow_var = "flow_var_"; +static constexpr std::string_view flow_var = "flow_var_"; + +std::string GetFlowVariable(u32 i) { + return fmt::format("{}{}", flow_var, i); +} class ExprDecompiler { public: @@ -2326,7 +2330,7 @@ public: } void operator()(VideoCommon::Shader::ExprVar& expr) { - inner += flow_var + std::to_string(expr.var_index); + inner += GetFlowVariable(expr.var_index); } void operator()(VideoCommon::Shader::ExprBoolean& expr) { @@ -2391,7 +2395,7 @@ public: 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()); + decomp.code.AddLine("{} = {};", GetFlowVariable(ast.index), expr_parser.GetResult()); } void operator()(VideoCommon::Shader::ASTLabel& ast) { @@ -2462,7 +2466,7 @@ private: void GLSLDecompiler::DecompileAST() { const u32 num_flow_variables = ir.GetASTNumVariables(); for (u32 i = 0; i < num_flow_variables; i++) { - code.AddLine("bool {}{} = false;", flow_var, i); + code.AddLine("bool {} = false;", GetFlowVariable(i)); } ASTDecompiler decompiler{*this}; VideoCommon::Shader::ASTNode program = ir.GetASTProgram(); diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 72a49ebdc..b5a43e79e 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -19,6 +19,8 @@ using VideoCommon::Shader::ShaderIR; static constexpr u32 PROGRAM_OFFSET = 10; static constexpr u32 COMPUTE_OFFSET = 0; +static constexpr CompilerSettings settings{CompileDepth::NoFlowStack, true}; + ProgramResult GenerateVertexShader(const Device& device, const ShaderSetup& setup) { const std::string id = fmt::format("{:016x}", setup.program.unique_identifier); @@ -33,9 +35,6 @@ layout (std140, binding = EMULATION_UBO_BINDING) uniform vs_config { )"; - CompilerSettings settings; - settings.depth = CompileDepth::NoFlowStack; - const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET, setup.program.size_a, settings); const auto stage = setup.IsDualProgram() ? ProgramType::VertexA : ProgramType::VertexB; ProgramResult program = Decompile(device, program_ir, stage, "vertex"); @@ -86,9 +85,6 @@ layout (std140, binding = EMULATION_UBO_BINDING) uniform gs_config { )"; - CompilerSettings settings; - settings.depth = CompileDepth::NoFlowStack; - const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET, setup.program.size_a, settings); ProgramResult program = Decompile(device, program_ir, ProgramType::Geometry, "geometry"); out += program.first; @@ -123,8 +119,6 @@ layout (std140, binding = EMULATION_UBO_BINDING) uniform fs_config { }; )"; - CompilerSettings settings; - settings.depth = CompileDepth::NoFlowStack; const ShaderIR program_ir(setup.program.code, PROGRAM_OFFSET, setup.program.size_a, settings); ProgramResult program = Decompile(device, program_ir, ProgramType::Fragment, "fragment"); @@ -145,9 +139,6 @@ ProgramResult GenerateComputeShader(const Device& device, const ShaderSetup& set std::string out = "// Shader Unique Id: CS" + id + "\n\n"; out += GetCommonDeclarations(); - CompilerSettings settings; - settings.depth = CompileDepth::NoFlowStack; - const ShaderIR program_ir(setup.program.code, COMPUTE_OFFSET, setup.program.size_a, settings); ProgramResult program = Decompile(device, program_ir, ProgramType::Compute, "compute"); out += program.first; diff --git a/src/video_core/shader/ast.cpp b/src/video_core/shader/ast.cpp index c4548f0bc..2eb065c3d 100644 --- a/src/video_core/shader/ast.cpp +++ b/src/video_core/shader/ast.cpp @@ -376,7 +376,7 @@ void ASTManager::Init() { false_condition = MakeExpr(false); } -ASTManager::ASTManager(ASTManager&& other) +ASTManager::ASTManager(ASTManager&& other) noexcept : 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}, false_condition{other.false_condition}, @@ -384,7 +384,7 @@ ASTManager::ASTManager(ASTManager&& other) other.main_node.reset(); } -ASTManager& ASTManager::operator=(ASTManager&& other) { +ASTManager& ASTManager::operator=(ASTManager&& other) noexcept { full_decompile = other.full_decompile; labels_map = std::move(other.labels_map); labels_count = other.labels_count; @@ -490,7 +490,7 @@ void ASTManager::Decompile() { it++; } if (full_decompile) { - for (const ASTNode label : labels) { + for (const ASTNode& label : labels) { auto& manager = label->GetManager(); manager.Remove(label); } @@ -500,12 +500,12 @@ void ASTManager::Decompile() { while (it != labels.end()) { bool can_remove = true; ASTNode label = *it; - for (const ASTNode goto_node : gotos) { + for (const ASTNode& goto_node : gotos) { const auto label_index = goto_node->GetGotoLabel(); if (!label_index) { return; } - ASTNode glabel = labels[*label_index]; + ASTNode& glabel = labels[*label_index]; if (glabel == label) { can_remove = false; break; @@ -543,40 +543,6 @@ bool ASTManager::IsBackwardsJump(ASTNode goto_node, ASTNode label_node) const { return false; } -ASTNode CommonParent(ASTNode first, ASTNode second) { - if (first->GetParent() == second->GetParent()) { - return first->GetParent(); - } - const u32 first_level = first->GetLevel(); - const u32 second_level = second->GetLevel(); - u32 min_level; - u32 max_level; - ASTNode max; - ASTNode min; - if (first_level > second_level) { - min_level = second_level; - min = second; - max_level = first_level; - max = first; - } else { - min_level = first_level; - min = first; - max_level = second_level; - max = second; - } - - while (max_level > min_level) { - max_level--; - max = max->GetParent(); - } - - while (min->GetParent() != max->GetParent()) { - min = min->GetParent(); - max = max->GetParent(); - } - return min->GetParent(); -} - bool ASTManager::IndirectlyRelated(ASTNode first, ASTNode second) { return !(first->GetParent() == second->GetParent() || DirectlyRelated(first, second)); } @@ -608,7 +574,7 @@ bool ASTManager::DirectlyRelated(ASTNode first, ASTNode second) { max = max->GetParent(); } - return (min->GetParent() == max->GetParent()); + return min->GetParent() == max->GetParent(); } void ASTManager::ShowCurrentState(std::string state) { @@ -617,7 +583,7 @@ void ASTManager::ShowCurrentState(std::string state) { } void ASTManager::SanityCheck() { - for (auto label : labels) { + for (auto& label : labels) { if (!label->GetParent()) { LOG_CRITICAL(HW_GPU, "Sanity Check Failed"); } diff --git a/src/video_core/shader/ast.h b/src/video_core/shader/ast.h index 8efd4c147..ba234138e 100644 --- a/src/video_core/shader/ast.h +++ b/src/video_core/shader/ast.h @@ -97,7 +97,7 @@ public: class ASTBlockDecoded { public: - explicit ASTBlockDecoded(NodeBlock& new_nodes) : nodes(std::move(new_nodes)) {} + explicit ASTBlockDecoded(NodeBlock&& new_nodes) : nodes(std::move(new_nodes)) {} NodeBlock nodes; }; @@ -255,8 +255,8 @@ public: return std::holds_alternative(data); } - void TransformBlockEncoded(NodeBlock& nodes) { - data = ASTBlockDecoded(nodes); + void TransformBlockEncoded(NodeBlock&& nodes) { + data = ASTBlockDecoded(std::move(nodes)); } bool IsLoop() const { @@ -304,8 +304,8 @@ public: ASTManager(const ASTManager& o) = delete; ASTManager& operator=(const ASTManager& other) = delete; - ASTManager(ASTManager&& other); - ASTManager& operator=(ASTManager&& other); + ASTManager(ASTManager&& other) noexcept; + ASTManager& operator=(ASTManager&& other) noexcept; void Init(); @@ -362,8 +362,6 @@ public: private: bool IsBackwardsJump(ASTNode goto_node, ASTNode label_node) const; - ASTNode CommonParent(ASTNode first, ASTNode second); - bool IndirectlyRelated(ASTNode first, ASTNode second); bool DirectlyRelated(ASTNode first, ASTNode second); diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp index c2fa734e7..3c3a41ba6 100644 --- a/src/video_core/shader/control_flow.cpp +++ b/src/video_core/shader/control_flow.cpp @@ -58,7 +58,7 @@ struct BlockInfo { struct CFGRebuildState { explicit CFGRebuildState(const ProgramCode& program_code, const std::size_t program_size, const u32 start) - : program_code{program_code}, program_size{program_size}, start{start} {} + : start{start}, program_code{program_code}, program_size{program_size} {} u32 start{}; std::vector block_info{}; diff --git a/src/video_core/shader/decode.cpp b/src/video_core/shader/decode.cpp index 6d4359295..2626b1616 100644 --- a/src/video_core/shader/decode.cpp +++ b/src/video_core/shader/decode.cpp @@ -90,7 +90,7 @@ public: if (node->IsBlockEncoded()) { auto block = std::get_if(node->GetInnerData()); NodeBlock bb = ir.DecodeRange(block->start, block->end); - node->TransformBlockEncoded(bb); + node->TransformBlockEncoded(std::move(bb)); } } -- cgit v1.2.3