diff options
| author | 2019-04-30 19:36:18 -0300 | |
|---|---|---|
| committer | 2019-05-02 21:46:25 -0300 | |
| commit | c6f9e651b21aca5ec5afef1f217b39a3b85518b9 (patch) | |
| tree | 53a0bddbb9bc78f3c26fb91ed64fab8cb008f87b /src/video_core | |
| parent | shader_ir/memory: Implement physical input attributes (diff) | |
| download | yuzu-c6f9e651b21aca5ec5afef1f217b39a3b85518b9.tar.gz yuzu-c6f9e651b21aca5ec5afef1f217b39a3b85518b9.tar.xz yuzu-c6f9e651b21aca5ec5afef1f217b39a3b85518b9.zip | |
gl_shader_decompiler: Implement GLSL physical attributes
Diffstat (limited to 'src/video_core')
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 165 | ||||
| -rw-r--r-- | src/video_core/shader/shader_ir.h | 2 |
2 files changed, 101 insertions, 66 deletions
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 1ad33107d..47bfa5538 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -165,6 +165,7 @@ public: | |||
| 165 | DeclareConstantBuffers(); | 165 | DeclareConstantBuffers(); |
| 166 | DeclareGlobalMemory(); | 166 | DeclareGlobalMemory(); |
| 167 | DeclareSamplers(); | 167 | DeclareSamplers(); |
| 168 | DeclarePhysicalAttributeReader(); | ||
| 168 | 169 | ||
| 169 | code.AddLine("void execute_" + suffix + "() {"); | 170 | code.AddLine("void execute_" + suffix + "() {"); |
| 170 | ++code.scope; | 171 | ++code.scope; |
| @@ -330,8 +331,7 @@ private: | |||
| 330 | 331 | ||
| 331 | void DeclareInputAttributes() { | 332 | void DeclareInputAttributes() { |
| 332 | if (ir.HasPhysicalAttributes()) { | 333 | if (ir.HasPhysicalAttributes()) { |
| 333 | const u32 num_inputs{stage == ShaderStage::Vertex ? GetNumPhysicalAttributes() | 334 | const u32 num_inputs{GetNumPhysicalInputAttributes()}; |
| 334 | : GetNumPhysicalVaryings()}; | ||
| 335 | for (u32 i = 0; i < num_inputs; ++i) { | 335 | for (u32 i = 0; i < num_inputs; ++i) { |
| 336 | DeclareInputAttribute(ToGenericAttribute(i)); | 336 | DeclareInputAttribute(ToGenericAttribute(i)); |
| 337 | } | 337 | } |
| @@ -374,7 +374,7 @@ private: | |||
| 374 | } | 374 | } |
| 375 | 375 | ||
| 376 | void DeclareOutputAttributes() { | 376 | void DeclareOutputAttributes() { |
| 377 | if (ir.HasPhysicalAttributes()) { | 377 | if (ir.HasPhysicalAttributes() && stage != ShaderStage::Fragment) { |
| 378 | for (u32 i = 0; i < GetNumPhysicalVaryings(); ++i) { | 378 | for (u32 i = 0; i < GetNumPhysicalVaryings(); ++i) { |
| 379 | DeclareOutputAttribute(ToGenericAttribute(i)); | 379 | DeclareOutputAttribute(ToGenericAttribute(i)); |
| 380 | } | 380 | } |
| @@ -461,6 +461,31 @@ private: | |||
| 461 | code.AddNewLine(); | 461 | code.AddNewLine(); |
| 462 | } | 462 | } |
| 463 | 463 | ||
| 464 | void DeclarePhysicalAttributeReader() { | ||
| 465 | if (!ir.HasPhysicalAttributes()) { | ||
| 466 | return; | ||
| 467 | } | ||
| 468 | code.AddLine("float readPhysicalAttribute(uint physical_address) {"); | ||
| 469 | ++code.scope; | ||
| 470 | code.AddLine("switch (physical_address) {"); | ||
| 471 | |||
| 472 | // Just declare generic attributes for now. | ||
| 473 | const auto num_attributes{static_cast<u32>(GetNumPhysicalAttributes())}; | ||
| 474 | for (u32 index = 0; index < num_attributes; ++index) { | ||
| 475 | for (u32 element = 0; element < 4; ++element) { | ||
| 476 | code.AddLine(fmt::format("case 0x{:x}: return {};", 0x80 + index * 16 + element * 4, | ||
| 477 | ReadAttribute(ToGenericAttribute(index), element))); | ||
| 478 | } | ||
| 479 | } | ||
| 480 | |||
| 481 | code.AddLine("default: return 0;"); | ||
| 482 | |||
| 483 | code.AddLine('}'); | ||
| 484 | --code.scope; | ||
| 485 | code.AddLine('}'); | ||
| 486 | code.AddNewLine(); | ||
| 487 | } | ||
| 488 | |||
| 464 | void VisitBlock(const NodeBlock& bb) { | 489 | void VisitBlock(const NodeBlock& bb) { |
| 465 | for (const Node node : bb) { | 490 | for (const Node node : bb) { |
| 466 | if (const std::string expr = Visit(node); !expr.empty()) { | 491 | if (const std::string expr = Visit(node); !expr.empty()) { |
| @@ -515,69 +540,12 @@ private: | |||
| 515 | return value; | 540 | return value; |
| 516 | 541 | ||
| 517 | } else if (const auto abuf = std::get_if<AbufNode>(node)) { | 542 | } else if (const auto abuf = std::get_if<AbufNode>(node)) { |
| 518 | const auto attribute = abuf->GetIndex(); | 543 | UNIMPLEMENTED_IF_MSG(abuf->IsPhysicalBuffer() && stage == ShaderStage::Geometry, |
| 519 | const auto element = abuf->GetElement(); | 544 | "Physical attributes in geometry shaders are not implemented"); |
| 520 | 545 | if (abuf->IsPhysicalBuffer()) { | |
| 521 | const auto GeometryPass = [&](const std::string& name) { | 546 | return "readPhysicalAttribute(ftou(" + Visit(abuf->GetPhysicalAddress()) + "))"; |
| 522 | if (stage == ShaderStage::Geometry && abuf->GetBuffer()) { | ||
| 523 | // TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games | ||
| 524 | // set an 0x80000000 index for those and the shader fails to build. Find out why | ||
| 525 | // this happens and what's its intent. | ||
| 526 | return "gs_" + name + "[ftou(" + Visit(abuf->GetBuffer()) + | ||
| 527 | ") % MAX_VERTEX_INPUT]"; | ||
| 528 | } | ||
| 529 | return name; | ||
| 530 | }; | ||
| 531 | |||
| 532 | switch (attribute) { | ||
| 533 | case Attribute::Index::Position: | ||
| 534 | if (stage != ShaderStage::Fragment) { | ||
| 535 | return GeometryPass("position") + GetSwizzle(element); | ||
| 536 | } else { | ||
| 537 | return element == 3 ? "1.0f" : "gl_FragCoord" + GetSwizzle(element); | ||
| 538 | } | ||
| 539 | case Attribute::Index::PointCoord: | ||
| 540 | switch (element) { | ||
| 541 | case 0: | ||
| 542 | return "gl_PointCoord.x"; | ||
| 543 | case 1: | ||
| 544 | return "gl_PointCoord.y"; | ||
| 545 | case 2: | ||
| 546 | case 3: | ||
| 547 | return "0"; | ||
| 548 | } | ||
| 549 | UNREACHABLE(); | ||
| 550 | return "0"; | ||
| 551 | case Attribute::Index::TessCoordInstanceIDVertexID: | ||
| 552 | // TODO(Subv): Find out what the values are for the first two elements when inside a | ||
| 553 | // vertex shader, and what's the value of the fourth element when inside a Tess Eval | ||
| 554 | // shader. | ||
| 555 | ASSERT(stage == ShaderStage::Vertex); | ||
| 556 | switch (element) { | ||
| 557 | case 2: | ||
| 558 | // Config pack's first value is instance_id. | ||
| 559 | return "uintBitsToFloat(config_pack[0])"; | ||
| 560 | case 3: | ||
| 561 | return "uintBitsToFloat(gl_VertexID)"; | ||
| 562 | } | ||
| 563 | UNIMPLEMENTED_MSG("Unmanaged TessCoordInstanceIDVertexID element={}", element); | ||
| 564 | return "0"; | ||
| 565 | case Attribute::Index::FrontFacing: | ||
| 566 | // TODO(Subv): Find out what the values are for the other elements. | ||
| 567 | ASSERT(stage == ShaderStage::Fragment); | ||
| 568 | switch (element) { | ||
| 569 | case 3: | ||
| 570 | return "itof(gl_FrontFacing ? -1 : 0)"; | ||
| 571 | } | ||
| 572 | UNIMPLEMENTED_MSG("Unmanaged FrontFacing element={}", element); | ||
| 573 | return "0"; | ||
| 574 | default: | ||
| 575 | if (IsGenericAttribute(attribute)) { | ||
| 576 | return GeometryPass(GetInputAttribute(attribute)) + GetSwizzle(element); | ||
| 577 | } | ||
| 578 | break; | ||
| 579 | } | 547 | } |
| 580 | UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute)); | 548 | return ReadAttribute(abuf->GetIndex(), abuf->GetElement(), abuf->GetBuffer()); |
| 581 | 549 | ||
| 582 | } else if (const auto cbuf = std::get_if<CbufNode>(node)) { | 550 | } else if (const auto cbuf = std::get_if<CbufNode>(node)) { |
| 583 | const Node offset = cbuf->GetOffset(); | 551 | const Node offset = cbuf->GetOffset(); |
| @@ -629,6 +597,69 @@ private: | |||
| 629 | return {}; | 597 | return {}; |
| 630 | } | 598 | } |
| 631 | 599 | ||
| 600 | std::string ReadAttribute(Attribute::Index attribute, u32 element, Node buffer = {}) { | ||
| 601 | const auto GeometryPass = [&](std::string name) { | ||
| 602 | if (stage == ShaderStage::Geometry && buffer) { | ||
| 603 | // TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games | ||
| 604 | // set an 0x80000000 index for those and the shader fails to build. Find out why | ||
| 605 | // this happens and what's its intent. | ||
| 606 | return "gs_" + std::move(name) + "[ftou(" + Visit(buffer) + ") % MAX_VERTEX_INPUT]"; | ||
| 607 | } | ||
| 608 | return name; | ||
| 609 | }; | ||
| 610 | |||
| 611 | switch (attribute) { | ||
| 612 | case Attribute::Index::Position: | ||
| 613 | if (stage != ShaderStage::Fragment) { | ||
| 614 | return GeometryPass("position") + GetSwizzle(element); | ||
| 615 | } else { | ||
| 616 | return element == 3 ? "1.0f" : "gl_FragCoord" + GetSwizzle(element); | ||
| 617 | } | ||
| 618 | case Attribute::Index::PointCoord: | ||
| 619 | switch (element) { | ||
| 620 | case 0: | ||
| 621 | return "gl_PointCoord.x"; | ||
| 622 | case 1: | ||
| 623 | return "gl_PointCoord.y"; | ||
| 624 | case 2: | ||
| 625 | case 3: | ||
| 626 | return "0"; | ||
| 627 | } | ||
| 628 | UNREACHABLE(); | ||
| 629 | return "0"; | ||
| 630 | case Attribute::Index::TessCoordInstanceIDVertexID: | ||
| 631 | // TODO(Subv): Find out what the values are for the first two elements when inside a | ||
| 632 | // vertex shader, and what's the value of the fourth element when inside a Tess Eval | ||
| 633 | // shader. | ||
| 634 | ASSERT(stage == ShaderStage::Vertex); | ||
| 635 | switch (element) { | ||
| 636 | case 2: | ||
| 637 | // Config pack's first value is instance_id. | ||
| 638 | return "uintBitsToFloat(config_pack[0])"; | ||
| 639 | case 3: | ||
| 640 | return "uintBitsToFloat(gl_VertexID)"; | ||
| 641 | } | ||
| 642 | UNIMPLEMENTED_MSG("Unmanaged TessCoordInstanceIDVertexID element={}", element); | ||
| 643 | return "0"; | ||
| 644 | case Attribute::Index::FrontFacing: | ||
| 645 | // TODO(Subv): Find out what the values are for the other elements. | ||
| 646 | ASSERT(stage == ShaderStage::Fragment); | ||
| 647 | switch (element) { | ||
| 648 | case 3: | ||
| 649 | return "itof(gl_FrontFacing ? -1 : 0)"; | ||
| 650 | } | ||
| 651 | UNIMPLEMENTED_MSG("Unmanaged FrontFacing element={}", element); | ||
| 652 | return "0"; | ||
| 653 | default: | ||
| 654 | if (IsGenericAttribute(attribute)) { | ||
| 655 | return GeometryPass(GetInputAttribute(attribute)) + GetSwizzle(element); | ||
| 656 | } | ||
| 657 | break; | ||
| 658 | } | ||
| 659 | UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute)); | ||
| 660 | return "0"; | ||
| 661 | } | ||
| 662 | |||
| 632 | std::string ApplyPrecise(Operation operation, const std::string& value) { | 663 | std::string ApplyPrecise(Operation operation, const std::string& value) { |
| 633 | if (!IsPrecise(operation)) { | 664 | if (!IsPrecise(operation)) { |
| 634 | return value; | 665 | return value; |
| @@ -1677,6 +1708,10 @@ private: | |||
| 1677 | return name + '_' + std::to_string(index) + '_' + suffix; | 1708 | return name + '_' + std::to_string(index) + '_' + suffix; |
| 1678 | } | 1709 | } |
| 1679 | 1710 | ||
| 1711 | u32 GetNumPhysicalInputAttributes() const { | ||
| 1712 | return stage == ShaderStage::Vertex ? GetNumPhysicalAttributes() : GetNumPhysicalVaryings(); | ||
| 1713 | } | ||
| 1714 | |||
| 1680 | u32 GetNumPhysicalAttributes() const { | 1715 | u32 GetNumPhysicalAttributes() const { |
| 1681 | return std::min<u32>(device.GetMaxVertexAttributes(), Maxwell::NumVertexAttributes); | 1716 | return std::min<u32>(device.GetMaxVertexAttributes(), Maxwell::NumVertexAttributes); |
| 1682 | } | 1717 | } |
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index 3a1164d4f..a4bb0c41c 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h | |||
| @@ -885,7 +885,7 @@ private: | |||
| 885 | std::set<Sampler> used_samplers; | 885 | std::set<Sampler> used_samplers; |
| 886 | std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{}; | 886 | std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{}; |
| 887 | std::map<GlobalMemoryBase, GlobalMemoryUsage> used_global_memory; | 887 | std::map<GlobalMemoryBase, GlobalMemoryUsage> used_global_memory; |
| 888 | bool use_physical_attributes = true; // Shader uses AL2P | 888 | bool use_physical_attributes{}; // Shader uses AL2P or physical attribute read/writes |
| 889 | 889 | ||
| 890 | Tegra::Shader::Header header; | 890 | Tegra::Shader::Header header; |
| 891 | }; | 891 | }; |