diff options
| author | 2019-06-29 01:44:07 -0400 | |
|---|---|---|
| committer | 2019-10-04 18:52:50 -0400 | |
| commit | 38fc995f6cc2c2af29abc976ddb45b72873b2cc4 (patch) | |
| tree | a73839d510c79a5e296e54a6768868f788abd45d /src | |
| parent | shader_ir: Declare Manager and pass it to appropiate programs. (diff) | |
| download | yuzu-38fc995f6cc2c2af29abc976ddb45b72873b2cc4.tar.gz yuzu-38fc995f6cc2c2af29abc976ddb45b72873b2cc4.tar.xz yuzu-38fc995f6cc2c2af29abc976ddb45b72873b2cc4.zip | |
gl_shader_decompiler: Implement AST decompiling
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 271 | ||||
| -rw-r--r-- | src/video_core/shader/ast.cpp | 10 | ||||
| -rw-r--r-- | src/video_core/shader/ast.h | 18 | ||||
| -rw-r--r-- | src/video_core/shader/control_flow.cpp | 2 | ||||
| -rw-r--r-- | src/video_core/shader/control_flow.h | 2 | ||||
| -rw-r--r-- | src/video_core/shader/decode.cpp | 70 | ||||
| -rw-r--r-- | src/video_core/shader/decode/other.cpp | 8 | ||||
| -rw-r--r-- | src/video_core/shader/expr.cpp | 7 | ||||
| -rw-r--r-- | src/video_core/shader/expr.h | 2 | ||||
| -rw-r--r-- | src/video_core/shader/shader_ir.cpp | 6 | ||||
| -rw-r--r-- | src/video_core/shader/shader_ir.h | 25 |
11 files changed, 358 insertions, 63 deletions
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 @@ | |||
| 20 | #include "video_core/renderer_opengl/gl_rasterizer.h" | 20 | #include "video_core/renderer_opengl/gl_rasterizer.h" |
| 21 | #include "video_core/renderer_opengl/gl_shader_decompiler.h" | 21 | #include "video_core/renderer_opengl/gl_shader_decompiler.h" |
| 22 | #include "video_core/shader/node.h" | 22 | #include "video_core/shader/node.h" |
| 23 | #include "video_core/shader/ast.h" | ||
| 23 | #include "video_core/shader/shader_ir.h" | 24 | #include "video_core/shader/shader_ir.h" |
| 24 | 25 | ||
| 25 | namespace OpenGL::GLShader { | 26 | namespace OpenGL::GLShader { |
| @@ -334,43 +335,26 @@ constexpr bool IsVertexShader(ProgramType stage) { | |||
| 334 | return stage == ProgramType::VertexA || stage == ProgramType::VertexB; | 335 | return stage == ProgramType::VertexA || stage == ProgramType::VertexB; |
| 335 | } | 336 | } |
| 336 | 337 | ||
| 338 | class ASTDecompiler; | ||
| 339 | class ExprDecompiler; | ||
| 340 | |||
| 337 | class GLSLDecompiler final { | 341 | class GLSLDecompiler final { |
| 338 | public: | 342 | public: |
| 339 | explicit GLSLDecompiler(const Device& device, const ShaderIR& ir, ProgramType stage, | 343 | explicit GLSLDecompiler(const Device& device, const ShaderIR& ir, ProgramType stage, |
| 340 | std::string suffix) | 344 | std::string suffix) |
| 341 | : device{device}, ir{ir}, stage{stage}, suffix{suffix}, header{ir.GetHeader()} {} | 345 | : device{device}, ir{ir}, stage{stage}, suffix{suffix}, header{ir.GetHeader()} {} |
| 342 | 346 | ||
| 343 | void Decompile() { | 347 | void DecompileBranchMode() { |
| 344 | DeclareVertex(); | ||
| 345 | DeclareGeometry(); | ||
| 346 | DeclareRegisters(); | ||
| 347 | DeclarePredicates(); | ||
| 348 | DeclareLocalMemory(); | ||
| 349 | DeclareSharedMemory(); | ||
| 350 | DeclareInternalFlags(); | ||
| 351 | DeclareInputAttributes(); | ||
| 352 | DeclareOutputAttributes(); | ||
| 353 | DeclareConstantBuffers(); | ||
| 354 | DeclareGlobalMemory(); | ||
| 355 | DeclareSamplers(); | ||
| 356 | DeclarePhysicalAttributeReader(); | ||
| 357 | DeclareImages(); | ||
| 358 | |||
| 359 | code.AddLine("void execute_{}() {{", suffix); | ||
| 360 | ++code.scope; | ||
| 361 | |||
| 362 | // VM's program counter | 348 | // VM's program counter |
| 363 | const auto first_address = ir.GetBasicBlocks().begin()->first; | 349 | const auto first_address = ir.GetBasicBlocks().begin()->first; |
| 364 | code.AddLine("uint jmp_to = {}U;", first_address); | 350 | code.AddLine("uint jmp_to = {}U;", first_address); |
| 365 | 351 | ||
| 366 | // TODO(Subv): Figure out the actual depth of the flow stack, for now it seems | 352 | // TODO(Subv): Figure out the actual depth of the flow stack, for now it seems |
| 367 | // unlikely that shaders will use 20 nested SSYs and PBKs. | 353 | // unlikely that shaders will use 20 nested SSYs and PBKs. |
| 368 | if (!ir.IsFlowStackDisabled()) { | 354 | constexpr u32 FLOW_STACK_SIZE = 20; |
| 369 | constexpr u32 FLOW_STACK_SIZE = 20; | 355 | for (const auto stack : std::array{MetaStackClass::Ssy, MetaStackClass::Pbk}) { |
| 370 | for (const auto stack : std::array{MetaStackClass::Ssy, MetaStackClass::Pbk}) { | 356 | code.AddLine("uint {}[{}];", FlowStackName(stack), FLOW_STACK_SIZE); |
| 371 | code.AddLine("uint {}[{}];", FlowStackName(stack), FLOW_STACK_SIZE); | 357 | code.AddLine("uint {} = 0u;", FlowStackTopName(stack)); |
| 372 | code.AddLine("uint {} = 0U;", FlowStackTopName(stack)); | ||
| 373 | } | ||
| 374 | } | 358 | } |
| 375 | 359 | ||
| 376 | code.AddLine("while (true) {{"); | 360 | code.AddLine("while (true) {{"); |
| @@ -392,10 +376,37 @@ public: | |||
| 392 | code.AddLine("default: return;"); | 376 | code.AddLine("default: return;"); |
| 393 | code.AddLine("}}"); | 377 | code.AddLine("}}"); |
| 394 | 378 | ||
| 395 | for (std::size_t i = 0; i < 2; ++i) { | 379 | --code.scope; |
| 396 | --code.scope; | 380 | code.AddLine("}}"); |
| 397 | code.AddLine("}}"); | 381 | } |
| 382 | |||
| 383 | void DecompileAST(); | ||
| 384 | |||
| 385 | void Decompile() { | ||
| 386 | DeclareVertex(); | ||
| 387 | DeclareGeometry(); | ||
| 388 | DeclareRegisters(); | ||
| 389 | DeclarePredicates(); | ||
| 390 | DeclareLocalMemory(); | ||
| 391 | DeclareInternalFlags(); | ||
| 392 | DeclareInputAttributes(); | ||
| 393 | DeclareOutputAttributes(); | ||
| 394 | DeclareConstantBuffers(); | ||
| 395 | DeclareGlobalMemory(); | ||
| 396 | DeclareSamplers(); | ||
| 397 | DeclarePhysicalAttributeReader(); | ||
| 398 | |||
| 399 | code.AddLine("void execute_{}() {{", suffix); | ||
| 400 | ++code.scope; | ||
| 401 | |||
| 402 | if (ir.IsDecompiled()) { | ||
| 403 | DecompileAST(); | ||
| 404 | } else { | ||
| 405 | DecompileBranchMode(); | ||
| 398 | } | 406 | } |
| 407 | |||
| 408 | --code.scope; | ||
| 409 | code.AddLine("}}"); | ||
| 399 | } | 410 | } |
| 400 | 411 | ||
| 401 | std::string GetResult() { | 412 | std::string GetResult() { |
| @@ -424,6 +435,9 @@ public: | |||
| 424 | } | 435 | } |
| 425 | 436 | ||
| 426 | private: | 437 | private: |
| 438 | friend class ASTDecompiler; | ||
| 439 | friend class ExprDecompiler; | ||
| 440 | |||
| 427 | void DeclareVertex() { | 441 | void DeclareVertex() { |
| 428 | if (!IsVertexShader(stage)) | 442 | if (!IsVertexShader(stage)) |
| 429 | return; | 443 | return; |
| @@ -1821,7 +1835,7 @@ private: | |||
| 1821 | return {}; | 1835 | return {}; |
| 1822 | } | 1836 | } |
| 1823 | 1837 | ||
| 1824 | Expression Exit(Operation operation) { | 1838 | Expression WriteExit() { |
| 1825 | if (stage != ProgramType::Fragment) { | 1839 | if (stage != ProgramType::Fragment) { |
| 1826 | code.AddLine("return;"); | 1840 | code.AddLine("return;"); |
| 1827 | return {}; | 1841 | return {}; |
| @@ -1861,6 +1875,10 @@ private: | |||
| 1861 | return {}; | 1875 | return {}; |
| 1862 | } | 1876 | } |
| 1863 | 1877 | ||
| 1878 | Expression Exit(Operation operation) { | ||
| 1879 | return WriteExit(); | ||
| 1880 | } | ||
| 1881 | |||
| 1864 | Expression Discard(Operation operation) { | 1882 | Expression Discard(Operation operation) { |
| 1865 | // Enclose "discard" in a conditional, so that GLSL compilation does not complain | 1883 | // Enclose "discard" in a conditional, so that GLSL compilation does not complain |
| 1866 | // about unexecuted instructions that may follow this. | 1884 | // about unexecuted instructions that may follow this. |
| @@ -2253,6 +2271,201 @@ private: | |||
| 2253 | ShaderWriter code; | 2271 | ShaderWriter code; |
| 2254 | }; | 2272 | }; |
| 2255 | 2273 | ||
| 2274 | const std::string flow_var = "flow_var_"; | ||
| 2275 | |||
| 2276 | class ExprDecompiler { | ||
| 2277 | public: | ||
| 2278 | ExprDecompiler(GLSLDecompiler& decomp) : decomp{decomp} {} | ||
| 2279 | |||
| 2280 | void operator()(VideoCommon::Shader::ExprAnd& expr) { | ||
| 2281 | inner += "( "; | ||
| 2282 | std::visit(*this, *expr.operand1); | ||
| 2283 | inner += " && "; | ||
| 2284 | std::visit(*this, *expr.operand2); | ||
| 2285 | inner += ')'; | ||
| 2286 | } | ||
| 2287 | |||
| 2288 | void operator()(VideoCommon::Shader::ExprOr& expr) { | ||
| 2289 | inner += "( "; | ||
| 2290 | std::visit(*this, *expr.operand1); | ||
| 2291 | inner += " || "; | ||
| 2292 | std::visit(*this, *expr.operand2); | ||
| 2293 | inner += ')'; | ||
| 2294 | } | ||
| 2295 | |||
| 2296 | void operator()(VideoCommon::Shader::ExprNot& expr) { | ||
| 2297 | inner += '!'; | ||
| 2298 | std::visit(*this, *expr.operand1); | ||
| 2299 | } | ||
| 2300 | |||
| 2301 | void operator()(VideoCommon::Shader::ExprPredicate& expr) { | ||
| 2302 | auto pred = static_cast<Tegra::Shader::Pred>(expr.predicate); | ||
| 2303 | inner += decomp.GetPredicate(pred); | ||
| 2304 | } | ||
| 2305 | |||
| 2306 | void operator()(VideoCommon::Shader::ExprCondCode& expr) { | ||
| 2307 | Node cc = decomp.ir.GetConditionCode(expr.cc); | ||
| 2308 | std::string target; | ||
| 2309 | |||
| 2310 | if (const auto pred = std::get_if<PredicateNode>(&*cc)) { | ||
| 2311 | const auto index = pred->GetIndex(); | ||
| 2312 | switch (index) { | ||
| 2313 | case Tegra::Shader::Pred::NeverExecute: | ||
| 2314 | target = "false"; | ||
| 2315 | case Tegra::Shader::Pred::UnusedIndex: | ||
| 2316 | target = "true"; | ||
| 2317 | default: | ||
| 2318 | target = decomp.GetPredicate(index); | ||
| 2319 | } | ||
| 2320 | } else if (const auto flag = std::get_if<InternalFlagNode>(&*cc)) { | ||
| 2321 | target = decomp.GetInternalFlag(flag->GetFlag()); | ||
| 2322 | } | ||
| 2323 | inner += target; | ||
| 2324 | } | ||
| 2325 | |||
| 2326 | void operator()(VideoCommon::Shader::ExprVar& expr) { | ||
| 2327 | inner += flow_var + std::to_string(expr.var_index); | ||
| 2328 | } | ||
| 2329 | |||
| 2330 | void operator()(VideoCommon::Shader::ExprBoolean& expr) { | ||
| 2331 | inner += expr.value ? "true" : "false"; | ||
| 2332 | } | ||
| 2333 | |||
| 2334 | std::string& GetResult() { | ||
| 2335 | return inner; | ||
| 2336 | } | ||
| 2337 | |||
| 2338 | private: | ||
| 2339 | std::string inner{}; | ||
| 2340 | GLSLDecompiler& decomp; | ||
| 2341 | }; | ||
| 2342 | |||
| 2343 | class ASTDecompiler { | ||
| 2344 | public: | ||
| 2345 | ASTDecompiler(GLSLDecompiler& decomp) : decomp{decomp} {} | ||
| 2346 | |||
| 2347 | void operator()(VideoCommon::Shader::ASTProgram& ast) { | ||
| 2348 | ASTNode current = ast.nodes.GetFirst(); | ||
| 2349 | while (current) { | ||
| 2350 | Visit(current); | ||
| 2351 | current = current->GetNext(); | ||
| 2352 | } | ||
| 2353 | } | ||
| 2354 | |||
| 2355 | void operator()(VideoCommon::Shader::ASTIfThen& ast) { | ||
| 2356 | ExprDecompiler expr_parser{decomp}; | ||
| 2357 | std::visit(expr_parser, *ast.condition); | ||
| 2358 | decomp.code.AddLine("if ({}) {{", expr_parser.GetResult()); | ||
| 2359 | decomp.code.scope++; | ||
| 2360 | ASTNode current = ast.nodes.GetFirst(); | ||
| 2361 | while (current) { | ||
| 2362 | Visit(current); | ||
| 2363 | current = current->GetNext(); | ||
| 2364 | } | ||
| 2365 | decomp.code.scope--; | ||
| 2366 | decomp.code.AddLine("}}"); | ||
| 2367 | } | ||
| 2368 | |||
| 2369 | void operator()(VideoCommon::Shader::ASTIfElse& ast) { | ||
| 2370 | decomp.code.AddLine("else {{"); | ||
| 2371 | decomp.code.scope++; | ||
| 2372 | ASTNode current = ast.nodes.GetFirst(); | ||
| 2373 | while (current) { | ||
| 2374 | Visit(current); | ||
| 2375 | current = current->GetNext(); | ||
| 2376 | } | ||
| 2377 | decomp.code.scope--; | ||
| 2378 | decomp.code.AddLine("}}"); | ||
| 2379 | } | ||
| 2380 | |||
| 2381 | void operator()(VideoCommon::Shader::ASTBlockEncoded& ast) { | ||
| 2382 | UNREACHABLE(); | ||
| 2383 | } | ||
| 2384 | |||
| 2385 | void operator()(VideoCommon::Shader::ASTBlockDecoded& ast) { | ||
| 2386 | decomp.VisitBlock(ast.nodes); | ||
| 2387 | } | ||
| 2388 | |||
| 2389 | void operator()(VideoCommon::Shader::ASTVarSet& ast) { | ||
| 2390 | ExprDecompiler expr_parser{decomp}; | ||
| 2391 | std::visit(expr_parser, *ast.condition); | ||
| 2392 | decomp.code.AddLine("{}{} = {};", flow_var, ast.index, expr_parser.GetResult()); | ||
| 2393 | } | ||
| 2394 | |||
| 2395 | void operator()(VideoCommon::Shader::ASTLabel& ast) { | ||
| 2396 | decomp.code.AddLine("// Label_{}:", ast.index); | ||
| 2397 | } | ||
| 2398 | |||
| 2399 | void operator()(VideoCommon::Shader::ASTGoto& ast) { | ||
| 2400 | UNREACHABLE(); | ||
| 2401 | } | ||
| 2402 | |||
| 2403 | void operator()(VideoCommon::Shader::ASTDoWhile& ast) { | ||
| 2404 | ExprDecompiler expr_parser{decomp}; | ||
| 2405 | std::visit(expr_parser, *ast.condition); | ||
| 2406 | decomp.code.AddLine("do {{"); | ||
| 2407 | decomp.code.scope++; | ||
| 2408 | ASTNode current = ast.nodes.GetFirst(); | ||
| 2409 | while (current) { | ||
| 2410 | Visit(current); | ||
| 2411 | current = current->GetNext(); | ||
| 2412 | } | ||
| 2413 | decomp.code.scope--; | ||
| 2414 | decomp.code.AddLine("}} while({});", expr_parser.GetResult()); | ||
| 2415 | } | ||
| 2416 | |||
| 2417 | void operator()(VideoCommon::Shader::ASTReturn& ast) { | ||
| 2418 | bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition); | ||
| 2419 | if (!is_true) { | ||
| 2420 | ExprDecompiler expr_parser{decomp}; | ||
| 2421 | std::visit(expr_parser, *ast.condition); | ||
| 2422 | decomp.code.AddLine("if ({}) {{", expr_parser.GetResult()); | ||
| 2423 | decomp.code.scope++; | ||
| 2424 | } | ||
| 2425 | if (ast.kills) { | ||
| 2426 | decomp.code.AddLine("discard;"); | ||
| 2427 | } else { | ||
| 2428 | decomp.WriteExit(); | ||
| 2429 | } | ||
| 2430 | if (!is_true) { | ||
| 2431 | decomp.code.scope--; | ||
| 2432 | decomp.code.AddLine("}}"); | ||
| 2433 | } | ||
| 2434 | } | ||
| 2435 | |||
| 2436 | void operator()(VideoCommon::Shader::ASTBreak& ast) { | ||
| 2437 | bool is_true = VideoCommon::Shader::ExprIsTrue(ast.condition); | ||
| 2438 | if (!is_true) { | ||
| 2439 | ExprDecompiler expr_parser{decomp}; | ||
| 2440 | std::visit(expr_parser, *ast.condition); | ||
| 2441 | decomp.code.AddLine("if ({}) {{", expr_parser.GetResult()); | ||
| 2442 | decomp.code.scope++; | ||
| 2443 | } | ||
| 2444 | decomp.code.AddLine("break;"); | ||
| 2445 | if (!is_true) { | ||
| 2446 | decomp.code.scope--; | ||
| 2447 | decomp.code.AddLine("}}"); | ||
| 2448 | } | ||
| 2449 | } | ||
| 2450 | |||
| 2451 | void Visit(VideoCommon::Shader::ASTNode& node) { | ||
| 2452 | std::visit(*this, *node->GetInnerData()); | ||
| 2453 | } | ||
| 2454 | |||
| 2455 | private: | ||
| 2456 | GLSLDecompiler& decomp; | ||
| 2457 | }; | ||
| 2458 | |||
| 2459 | void GLSLDecompiler::DecompileAST() { | ||
| 2460 | u32 num_flow_variables = ir.GetASTNumVariables(); | ||
| 2461 | for (u32 i = 0; i < num_flow_variables; i++) { | ||
| 2462 | code.AddLine("bool {}{} = false;", flow_var, i); | ||
| 2463 | } | ||
| 2464 | ASTDecompiler decompiler{*this}; | ||
| 2465 | VideoCommon::Shader::ASTNode program = ir.GetASTProgram(); | ||
| 2466 | decompiler.Visit(program); | ||
| 2467 | } | ||
| 2468 | |||
| 2256 | } // Anonymous namespace | 2469 | } // Anonymous namespace |
| 2257 | 2470 | ||
| 2258 | std::string GetCommonDeclarations() { | 2471 | std::string GetCommonDeclarations() { |
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() { | |||
| 372 | void ASTManager::Init() { | 372 | void 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 | ||
| 378 | ASTManager::ASTManager(ASTManager&& other) | 378 | ASTManager::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 | ||
| 144 | using TransformCallback = std::function<NodeBlock(u32 start, u32 end)>; | ||
| 145 | |||
| 146 | class ASTBase { | 144 | class ASTBase { |
| 147 | public: | 145 | public: |
| 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 | |||
| 322 | private: | 320 | private: |
| 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 | ||
| 76 | std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, u32 program_size, | 76 | std::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 | ||
| 38 | class ASTDecoder { | ||
| 39 | public: | ||
| 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 | |||
| 97 | private: | ||
| 98 | ShaderIR& ir; | ||
| 99 | }; | ||
| 100 | |||
| 38 | void ShaderIR::Decode() { | 101 | void 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 | ||
| 75 | bool 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 | ||
| 116 | Expr MakeExprOr(Expr first, Expr second); | 116 | Expr MakeExprOr(Expr first, Expr second); |
| 117 | 117 | ||
| 118 | bool 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 | ||
| 140 | Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) { | 140 | Node 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 | ||
| 370 | Node ShaderIR::GetConditionCode(Tegra::Shader::ConditionCode cc) { | 370 | Node 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 | ||
| 21 | namespace VideoCommon::Shader { | 21 | namespace 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 | |||
| 152 | private: | 163 | private: |
| 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{}; |