summaryrefslogtreecommitdiff
path: root/src/video_core/shader
diff options
context:
space:
mode:
authorGravatar Fernando Sahmkow2019-06-29 01:44:07 -0400
committerGravatar FernandoS272019-10-04 18:52:50 -0400
commit38fc995f6cc2c2af29abc976ddb45b72873b2cc4 (patch)
treea73839d510c79a5e296e54a6768868f788abd45d /src/video_core/shader
parentshader_ir: Declare Manager and pass it to appropiate programs. (diff)
downloadyuzu-38fc995f6cc2c2af29abc976ddb45b72873b2cc4.tar.gz
yuzu-38fc995f6cc2c2af29abc976ddb45b72873b2cc4.tar.xz
yuzu-38fc995f6cc2c2af29abc976ddb45b72873b2cc4.zip
gl_shader_decompiler: Implement AST decompiling
Diffstat (limited to 'src/video_core/shader')
-rw-r--r--src/video_core/shader/ast.cpp10
-rw-r--r--src/video_core/shader/ast.h18
-rw-r--r--src/video_core/shader/control_flow.cpp2
-rw-r--r--src/video_core/shader/control_flow.h2
-rw-r--r--src/video_core/shader/decode.cpp70
-rw-r--r--src/video_core/shader/decode/other.cpp8
-rw-r--r--src/video_core/shader/expr.cpp7
-rw-r--r--src/video_core/shader/expr.h2
-rw-r--r--src/video_core/shader/shader_ir.cpp6
-rw-r--r--src/video_core/shader/shader_ir.h25
10 files changed, 116 insertions, 34 deletions
diff --git a/src/video_core/shader/ast.cpp b/src/video_core/shader/ast.cpp
index 0bf289f98..68a96cc79 100644
--- a/src/video_core/shader/ast.cpp
+++ b/src/video_core/shader/ast.cpp
@@ -372,13 +372,13 @@ ASTManager::~ASTManager() {
372void ASTManager::Init() { 372void ASTManager::Init() {
373 main_node = ASTBase::Make<ASTProgram>(ASTNode{}); 373 main_node = ASTBase::Make<ASTProgram>(ASTNode{});
374 program = std::get_if<ASTProgram>(main_node->GetInnerData()); 374 program = std::get_if<ASTProgram>(main_node->GetInnerData());
375 true_condition = MakeExpr<ExprBoolean>(true); 375 false_condition = MakeExpr<ExprBoolean>(false);
376} 376}
377 377
378ASTManager::ASTManager(ASTManager&& other) 378ASTManager::ASTManager(ASTManager&& other)
379 : labels_map(std::move(other.labels_map)), labels_count{other.labels_count}, 379 : labels_map(std::move(other.labels_map)), labels_count{other.labels_count},
380 gotos(std::move(other.gotos)), labels(std::move(other.labels)), variables{other.variables}, 380 gotos(std::move(other.gotos)), labels(std::move(other.labels)), variables{other.variables},
381 program{other.program}, main_node{other.main_node}, true_condition{other.true_condition} { 381 program{other.program}, main_node{other.main_node}, false_condition{other.false_condition} {
382 other.main_node.reset(); 382 other.main_node.reset();
383} 383}
384 384
@@ -390,7 +390,7 @@ ASTManager& ASTManager::operator=(ASTManager&& other) {
390 variables = other.variables; 390 variables = other.variables;
391 program = other.program; 391 program = other.program;
392 main_node = other.main_node; 392 main_node = other.main_node;
393 true_condition = other.true_condition; 393 false_condition = other.false_condition;
394 394
395 other.main_node.reset(); 395 other.main_node.reset();
396 return *this; 396 return *this;
@@ -594,7 +594,7 @@ void ASTManager::MoveOutward(ASTNode goto_node) {
594 u32 var_index = NewVariable(); 594 u32 var_index = NewVariable();
595 Expr var_condition = MakeExpr<ExprVar>(var_index); 595 Expr var_condition = MakeExpr<ExprVar>(var_index);
596 ASTNode var_node = ASTBase::Make<ASTVarSet>(parent, var_index, condition); 596 ASTNode var_node = ASTBase::Make<ASTVarSet>(parent, var_index, condition);
597 ASTNode var_node_init = ASTBase::Make<ASTVarSet>(parent, var_index, true_condition); 597 ASTNode var_node_init = ASTBase::Make<ASTVarSet>(parent, var_index, false_condition);
598 zipper2.InsertBefore(var_node_init, parent); 598 zipper2.InsertBefore(var_node_init, parent);
599 zipper.InsertAfter(var_node, prev); 599 zipper.InsertAfter(var_node, prev);
600 goto_node->SetGotoCondition(var_condition); 600 goto_node->SetGotoCondition(var_condition);
@@ -605,7 +605,7 @@ void ASTManager::MoveOutward(ASTNode goto_node) {
605 u32 var_index = NewVariable(); 605 u32 var_index = NewVariable();
606 Expr var_condition = MakeExpr<ExprVar>(var_index); 606 Expr var_condition = MakeExpr<ExprVar>(var_index);
607 ASTNode var_node = ASTBase::Make<ASTVarSet>(parent, var_index, condition); 607 ASTNode var_node = ASTBase::Make<ASTVarSet>(parent, var_index, condition);
608 ASTNode var_node_init = ASTBase::Make<ASTVarSet>(parent, var_index, true_condition); 608 ASTNode var_node_init = ASTBase::Make<ASTVarSet>(parent, var_index, false_condition);
609 if (is_if) { 609 if (is_if) {
610 zipper2.InsertBefore(var_node_init, parent); 610 zipper2.InsertBefore(var_node_init, parent);
611 } else { 611 } else {
diff --git a/src/video_core/shader/ast.h b/src/video_core/shader/ast.h
index 958989bcd..06ab20cc5 100644
--- a/src/video_core/shader/ast.h
+++ b/src/video_core/shader/ast.h
@@ -141,8 +141,6 @@ public:
141 Expr condition; 141 Expr condition;
142}; 142};
143 143
144using TransformCallback = std::function<NodeBlock(u32 start, u32 end)>;
145
146class ASTBase { 144class ASTBase {
147public: 145public:
148 explicit ASTBase(ASTNode parent, ASTData data) : parent{parent}, data{data} {} 146 explicit ASTBase(ASTNode parent, ASTData data) : parent{parent}, data{data} {}
@@ -233,11 +231,7 @@ public:
233 return std::holds_alternative<ASTBlockEncoded>(data); 231 return std::holds_alternative<ASTBlockEncoded>(data);
234 } 232 }
235 233
236 void TransformBlockEncoded(TransformCallback& callback) { 234 void TransformBlockEncoded(NodeBlock& nodes) {
237 auto block = std::get_if<ASTBlockEncoded>(&data);
238 const u32 start = block->start;
239 const u32 end = block->end;
240 NodeBlock nodes = callback(start, end);
241 data = ASTBlockDecoded(nodes); 235 data = ASTBlockDecoded(nodes);
242 } 236 }
243 237
@@ -309,16 +303,20 @@ public:
309 303
310 void SanityCheck(); 304 void SanityCheck();
311 305
312 bool IsFullyDecompiled() { 306 bool IsFullyDecompiled() const {
313 return gotos.size() == 0; 307 return gotos.size() == 0;
314 } 308 }
315 309
316 ASTNode GetProgram() { 310 ASTNode GetProgram() const {
317 return main_node; 311 return main_node;
318 } 312 }
319 313
320 void Clear(); 314 void Clear();
321 315
316 u32 GetVariables() const {
317 return variables;
318 }
319
322private: 320private:
323 bool IndirectlyRelated(ASTNode first, ASTNode second); 321 bool IndirectlyRelated(ASTNode first, ASTNode second);
324 322
@@ -343,7 +341,7 @@ private:
343 u32 variables{}; 341 u32 variables{};
344 ASTProgram* program{}; 342 ASTProgram* program{};
345 ASTNode main_node{}; 343 ASTNode main_node{};
346 Expr true_condition{}; 344 Expr false_condition{};
347}; 345};
348 346
349} // namespace VideoCommon::Shader 347} // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp
index deb3d3ebd..a29922815 100644
--- a/src/video_core/shader/control_flow.cpp
+++ b/src/video_core/shader/control_flow.cpp
@@ -425,7 +425,7 @@ void InsertBranch(ASTManager& mm, const BlockBranchInfo& branch) {
425 } 425 }
426 if (cond.predicate != Pred::UnusedIndex) { 426 if (cond.predicate != Pred::UnusedIndex) {
427 u32 pred = static_cast<u32>(cond.predicate); 427 u32 pred = static_cast<u32>(cond.predicate);
428 bool negate; 428 bool negate = false;
429 if (pred > 7) { 429 if (pred > 7) {
430 negate = true; 430 negate = true;
431 pred -= 8; 431 pred -= 8;
diff --git a/src/video_core/shader/control_flow.h b/src/video_core/shader/control_flow.h
index 2805d975c..347a35dcf 100644
--- a/src/video_core/shader/control_flow.h
+++ b/src/video_core/shader/control_flow.h
@@ -74,6 +74,6 @@ struct ShaderCharacteristics {
74}; 74};
75 75
76std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, u32 program_size, 76std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, u32 program_size,
77 u32 start_address, ASTManager& manager); 77 u32 start_address, ASTManager& manager);
78 78
79} // namespace VideoCommon::Shader 79} // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/decode.cpp b/src/video_core/shader/decode.cpp
index 381e87415..e7e0903f6 100644
--- a/src/video_core/shader/decode.cpp
+++ b/src/video_core/shader/decode.cpp
@@ -35,10 +35,73 @@ constexpr bool IsSchedInstruction(u32 offset, u32 main_offset) {
35 35
36} // namespace 36} // namespace
37 37
38class ASTDecoder {
39public:
40 ASTDecoder(ShaderIR& ir) : ir(ir) {}
41
42 void operator()(ASTProgram& ast) {
43 ASTNode current = ast.nodes.GetFirst();
44 while (current) {
45 Visit(current);
46 current = current->GetNext();
47 }
48 }
49
50 void operator()(ASTIfThen& ast) {
51 ASTNode current = ast.nodes.GetFirst();
52 while (current) {
53 Visit(current);
54 current = current->GetNext();
55 }
56 }
57
58 void operator()(ASTIfElse& ast) {
59 ASTNode current = ast.nodes.GetFirst();
60 while (current) {
61 Visit(current);
62 current = current->GetNext();
63 }
64 }
65
66 void operator()(ASTBlockEncoded& ast) {}
67
68 void operator()(ASTBlockDecoded& ast) {}
69
70 void operator()(ASTVarSet& ast) {}
71
72 void operator()(ASTLabel& ast) {}
73
74 void operator()(ASTGoto& ast) {}
75
76 void operator()(ASTDoWhile& ast) {
77 ASTNode current = ast.nodes.GetFirst();
78 while (current) {
79 Visit(current);
80 current = current->GetNext();
81 }
82 }
83
84 void operator()(ASTReturn& ast) {}
85
86 void operator()(ASTBreak& ast) {}
87
88 void Visit(ASTNode& node) {
89 std::visit(*this, *node->GetInnerData());
90 if (node->IsBlockEncoded()) {
91 auto block = std::get_if<ASTBlockEncoded>(node->GetInnerData());
92 NodeBlock bb = ir.DecodeRange(block->start, block->end);
93 node->TransformBlockEncoded(bb);
94 }
95 }
96
97private:
98 ShaderIR& ir;
99};
100
38void ShaderIR::Decode() { 101void ShaderIR::Decode() {
39 std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header)); 102 std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header));
40 103
41 disable_flow_stack = false; 104 decompiled = false;
42 const auto info = 105 const auto info =
43 ScanFlow(program_code, program_size, main_offset, program_manager); 106 ScanFlow(program_code, program_size, main_offset, program_manager);
44 if (info) { 107 if (info) {
@@ -46,7 +109,10 @@ void ShaderIR::Decode() {
46 coverage_begin = shader_info.start; 109 coverage_begin = shader_info.start;
47 coverage_end = shader_info.end; 110 coverage_end = shader_info.end;
48 if (shader_info.decompiled) { 111 if (shader_info.decompiled) {
49 disable_flow_stack = true; 112 decompiled = true;
113 ASTDecoder decoder{*this};
114 ASTNode program = GetASTProgram();
115 decoder.Visit(program);
50 return; 116 return;
51 } 117 }
52 LOG_WARNING(HW_GPU, "Flow Stack Removing Failed! Falling back to old method"); 118 LOG_WARNING(HW_GPU, "Flow Stack Removing Failed! Falling back to old method");
diff --git a/src/video_core/shader/decode/other.cpp b/src/video_core/shader/decode/other.cpp
index d46e0f823..6f678003c 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) {
157 UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0, 157 UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0,
158 "Constant buffer flow is not supported"); 158 "Constant buffer flow is not supported");
159 159
160 if (disable_flow_stack) { 160 if (decompiled) {
161 break; 161 break;
162 } 162 }
163 163
@@ -171,7 +171,7 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
171 UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0, 171 UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0,
172 "Constant buffer PBK is not supported"); 172 "Constant buffer PBK is not supported");
173 173
174 if (disable_flow_stack) { 174 if (decompiled) {
175 break; 175 break;
176 } 176 }
177 177
@@ -186,7 +186,7 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
186 UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, "SYNC condition code used: {}", 186 UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, "SYNC condition code used: {}",
187 static_cast<u32>(cc)); 187 static_cast<u32>(cc));
188 188
189 if (disable_flow_stack) { 189 if (decompiled) {
190 break; 190 break;
191 } 191 }
192 192
@@ -198,7 +198,7 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
198 const Tegra::Shader::ConditionCode cc = instr.flow_condition_code; 198 const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
199 UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, "BRK condition code used: {}", 199 UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, "BRK condition code used: {}",
200 static_cast<u32>(cc)); 200 static_cast<u32>(cc));
201 if (disable_flow_stack) { 201 if (decompiled) {
202 break; 202 break;
203 } 203 }
204 204
diff --git a/src/video_core/shader/expr.cpp b/src/video_core/shader/expr.cpp
index ebce6339b..ca633ffb1 100644
--- a/src/video_core/shader/expr.cpp
+++ b/src/video_core/shader/expr.cpp
@@ -72,4 +72,11 @@ bool ExprAreOpposite(Expr first, Expr second) {
72 return false; 72 return false;
73} 73}
74 74
75bool ExprIsTrue(Expr first) {
76 if (ExprIsBoolean(first)) {
77 return ExprBooleanGet(first);
78 }
79 return false;
80}
81
75} // namespace VideoCommon::Shader 82} // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/expr.h b/src/video_core/shader/expr.h
index f012f6fcf..b954cffb0 100644
--- a/src/video_core/shader/expr.h
+++ b/src/video_core/shader/expr.h
@@ -115,4 +115,6 @@ Expr MakeExprAnd(Expr first, Expr second);
115 115
116Expr MakeExprOr(Expr first, Expr second); 116Expr MakeExprOr(Expr first, Expr second);
117 117
118bool ExprIsTrue(Expr first);
119
118} // namespace VideoCommon::Shader 120} // namespace VideoCommon::Shader
diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp
index c79f80e04..004b1e16f 100644
--- a/src/video_core/shader/shader_ir.cpp
+++ b/src/video_core/shader/shader_ir.cpp
@@ -137,7 +137,7 @@ Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buff
137 return MakeNode<AbufNode>(index, static_cast<u32>(element), std::move(buffer)); 137 return MakeNode<AbufNode>(index, static_cast<u32>(element), std::move(buffer));
138} 138}
139 139
140Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) { 140Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) const {
141 const Node node = MakeNode<InternalFlagNode>(flag); 141 const Node node = MakeNode<InternalFlagNode>(flag);
142 if (negated) { 142 if (negated) {
143 return Operation(OperationCode::LogicalNegate, node); 143 return Operation(OperationCode::LogicalNegate, node);
@@ -367,13 +367,13 @@ OperationCode ShaderIR::GetPredicateCombiner(PredOperation operation) {
367 return op->second; 367 return op->second;
368} 368}
369 369
370Node ShaderIR::GetConditionCode(Tegra::Shader::ConditionCode cc) { 370Node ShaderIR::GetConditionCode(Tegra::Shader::ConditionCode cc) const {
371 switch (cc) { 371 switch (cc) {
372 case Tegra::Shader::ConditionCode::NEU: 372 case Tegra::Shader::ConditionCode::NEU:
373 return GetInternalFlag(InternalFlag::Zero, true); 373 return GetInternalFlag(InternalFlag::Zero, true);
374 default: 374 default:
375 UNIMPLEMENTED_MSG("Unimplemented condition code: {}", static_cast<u32>(cc)); 375 UNIMPLEMENTED_MSG("Unimplemented condition code: {}", static_cast<u32>(cc));
376 return GetPredicate(static_cast<u64>(Pred::NeverExecute)); 376 return MakeNode<PredicateNode>(Pred::NeverExecute, false);
377 } 377 }
378} 378}
379 379
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h
index a91cd7d67..48c7b722e 100644
--- a/src/video_core/shader/shader_ir.h
+++ b/src/video_core/shader/shader_ir.h
@@ -15,8 +15,8 @@
15#include "video_core/engines/maxwell_3d.h" 15#include "video_core/engines/maxwell_3d.h"
16#include "video_core/engines/shader_bytecode.h" 16#include "video_core/engines/shader_bytecode.h"
17#include "video_core/engines/shader_header.h" 17#include "video_core/engines/shader_header.h"
18#include "video_core/shader/node.h"
19#include "video_core/shader/ast.h" 18#include "video_core/shader/ast.h"
19#include "video_core/shader/node.h"
20 20
21namespace VideoCommon::Shader { 21namespace VideoCommon::Shader {
22 22
@@ -141,15 +141,27 @@ public:
141 return header; 141 return header;
142 } 142 }
143 143
144 bool IsFlowStackDisabled() const { 144 bool IsDecompiled() const {
145 return disable_flow_stack; 145 return decompiled;
146 }
147
148 ASTNode GetASTProgram() const {
149 return program_manager.GetProgram();
150 }
151
152 u32 GetASTNumVariables() const {
153 return program_manager.GetVariables();
146 } 154 }
147 155
148 u32 ConvertAddressToNvidiaSpace(const u32 address) const { 156 u32 ConvertAddressToNvidiaSpace(const u32 address) const {
149 return (address - main_offset) * sizeof(Tegra::Shader::Instruction); 157 return (address - main_offset) * sizeof(Tegra::Shader::Instruction);
150 } 158 }
151 159
160 /// Returns a condition code evaluated from internal flags
161 Node GetConditionCode(Tegra::Shader::ConditionCode cc) const;
162
152private: 163private:
164 friend class ASTDecoder;
153 void Decode(); 165 void Decode();
154 166
155 NodeBlock DecodeRange(u32 begin, u32 end); 167 NodeBlock DecodeRange(u32 begin, u32 end);
@@ -214,7 +226,7 @@ private:
214 /// Generates a node representing an output attribute. Keeps track of used attributes. 226 /// Generates a node representing an output attribute. Keeps track of used attributes.
215 Node GetOutputAttribute(Tegra::Shader::Attribute::Index index, u64 element, Node buffer); 227 Node GetOutputAttribute(Tegra::Shader::Attribute::Index index, u64 element, Node buffer);
216 /// Generates a node representing an internal flag 228 /// Generates a node representing an internal flag
217 Node GetInternalFlag(InternalFlag flag, bool negated = false); 229 Node GetInternalFlag(InternalFlag flag, bool negated = false) const;
218 /// Generates a node representing a local memory address 230 /// Generates a node representing a local memory address
219 Node GetLocalMemory(Node address); 231 Node GetLocalMemory(Node address);
220 /// Generates a node representing a shared memory address 232 /// Generates a node representing a shared memory address
@@ -272,9 +284,6 @@ private:
272 /// Returns a predicate combiner operation 284 /// Returns a predicate combiner operation
273 OperationCode GetPredicateCombiner(Tegra::Shader::PredOperation operation); 285 OperationCode GetPredicateCombiner(Tegra::Shader::PredOperation operation);
274 286
275 /// Returns a condition code evaluated from internal flags
276 Node GetConditionCode(Tegra::Shader::ConditionCode cc);
277
278 /// Accesses a texture sampler 287 /// Accesses a texture sampler
279 const Sampler& GetSampler(const Tegra::Shader::Sampler& sampler, 288 const Sampler& GetSampler(const Tegra::Shader::Sampler& sampler,
280 Tegra::Shader::TextureType type, bool is_array, bool is_shadow); 289 Tegra::Shader::TextureType type, bool is_array, bool is_shadow);
@@ -358,7 +367,7 @@ private:
358 const ProgramCode& program_code; 367 const ProgramCode& program_code;
359 const u32 main_offset; 368 const u32 main_offset;
360 const std::size_t program_size; 369 const std::size_t program_size;
361 bool disable_flow_stack{}; 370 bool decompiled{};
362 371
363 u32 coverage_begin{}; 372 u32 coverage_begin{};
364 u32 coverage_end{}; 373 u32 coverage_end{};