mirror of
				https://git.tardis.systems/mirrors/yuzu
				synced 2025-10-31 02:34:11 +01:00 
			
		
		
		
	Shader_Ir: Refactor Decompilation process and allow multiple decompilation modes.
This commit is contained in:
		
							parent
							
								
									38fc995f6c
								
							
						
					
					
						commit
						47e4f6a52c
					
				| @ -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" | ||||
|  | ||||
| @ -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" | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -352,10 +352,12 @@ 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; | ||||
|         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) {{"); | ||||
|         ++code.scope; | ||||
|  | ||||
| @ -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; | ||||
| 
 | ||||
|  | ||||
| @ -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++; | ||||
|     } | ||||
|     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); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
|  | ||||
| @ -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 { | ||||
|         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<u32, u32> labels_map{}; | ||||
|     u32 labels_count{}; | ||||
|     std::vector<ASTNode> labels{}; | ||||
|  | ||||
							
								
								
									
										26
									
								
								src/video_core/shader/compiler_settings.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/video_core/shader/compiler_settings.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -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
 | ||||
							
								
								
									
										25
									
								
								src/video_core/shader/compiler_settings.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/video_core/shader/compiler_settings.h
									
									
									
									
									
										Normal file
									
								
							| @ -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
 | ||||
| @ -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<BlockInfo> block_info{}; | ||||
| @ -71,7 +71,7 @@ struct CFGRebuildState { | ||||
|     std::unordered_map<u32, BlockStack> 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<ShaderCharacteristics> 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<ShaderCharacteristics>(); | ||||
|     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); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     bool use_flow_stack = true; | ||||
| 
 | ||||
|     bool decompiled = false; | ||||
| 
 | ||||
|     if (settings.depth != CompileDepth::FlowStack) { | ||||
|         // Decompile Stacks
 | ||||
|         state.queries.push_back(Query{state.start, {}, {}}); | ||||
|     bool decompiled = true; | ||||
|         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) { | ||||
|             if (settings.depth == CompileDepth::FullDecompile) { | ||||
|                 LOG_CRITICAL(HW_GPU, "Failed to remove all the gotos!:"); | ||||
|             state.manager.ShowCurrentState("Of Shader"); | ||||
|             state.manager.Clear(); | ||||
|         } | ||||
|             } 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<ShaderCharacteristics>(); | ||||
|     result_out->decompiled = decompiled; | ||||
|             result_out->start = start_address; | ||||
|     if (decompiled) { | ||||
|             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); | ||||
|         } | ||||
|     } | ||||
|     result_out->start = start_address; | ||||
|     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<ShaderCharacteristics> 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()) { | ||||
|  | ||||
| @ -9,8 +9,9 @@ | ||||
| #include <set> | ||||
| 
 | ||||
| #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<ShaderBlock> blocks{}; | ||||
|     bool decompiled{}; | ||||
|     std::set<u32> labels{}; | ||||
|     u32 start{}; | ||||
|     u32 end{}; | ||||
|     ASTManager manager{true}; | ||||
|     CompilerSettings settings{}; | ||||
| }; | ||||
| 
 | ||||
| std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, u32 program_size, | ||||
|                                                 u32 start_address, ASTManager& manager); | ||||
|                                                 u32 start_address, | ||||
|                                                 const CompilerSettings& settings); | ||||
| 
 | ||||
| } // namespace VideoCommon::Shader
 | ||||
|  | ||||
| @ -102,36 +102,72 @@ 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; | ||||
|     auto info = ScanFlow(program_code, program_size, main_offset, settings); | ||||
|     auto& shader_info = *info; | ||||
|     coverage_begin = shader_info.start; | ||||
|     coverage_end = shader_info.end; | ||||
|         if (shader_info.decompiled) { | ||||
|     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)}); | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
|     case CompileDepth::NoFlowStack: { | ||||
|         disable_flow_stack = true; | ||||
|         const auto insert_block = [this](NodeBlock& nodes, u32 label) { | ||||
|             if (label == static_cast<u32>(exit_branch)) { | ||||
|                 return; | ||||
|             } | ||||
|             basic_blocks.insert({label, nodes}); | ||||
|         }; | ||||
|         const auto& blocks = shader_info.blocks; | ||||
|         NodeBlock current_block; | ||||
|         u32 current_label = static_cast<u32>(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); | ||||
|             return; | ||||
|         break; | ||||
|     } | ||||
|         LOG_WARNING(HW_GPU, "Flow Stack Removing Failed! Falling back to old method"); | ||||
|         // we can't decompile it, fallback to standard method
 | ||||
|         for (const auto& block : shader_info.blocks) { | ||||
|             basic_blocks.insert({block.start, DecodeRange(block.start, block.end + 1)}); | ||||
|         } | ||||
|         return; | ||||
|     } | ||||
|     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.
 | ||||
|     default: | ||||
|         LOG_CRITICAL(HW_GPU, "Unknown decompilation mode!"); | ||||
|         [[fallthrough]]; | ||||
|     case CompileDepth::BruteForce: { | ||||
|         coverage_begin = main_offset; | ||||
|         const u32 shader_end = static_cast<u32>(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; | ||||
|     } | ||||
|     } | ||||
|     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)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| NodeBlock ShaderIR::DecodeRange(u32 begin, u32 end) { | ||||
|  | ||||
| @ -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<u32>(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<u32>(cc)); | ||||
|         if (decompiled) { | ||||
|         if (disable_flow_stack) { | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|  | ||||
| @ -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(); | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -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<u32, NodeBlock>& 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<u32, NodeBlock> basic_blocks; | ||||
|     NodeBlock global_code; | ||||
|     ASTManager program_manager; | ||||
|     CompilerSettings settings{}; | ||||
| 
 | ||||
|     std::set<u32> used_registers; | ||||
|     std::set<Tegra::Shader::Pred> used_predicates; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user