diff options
| author | 2019-05-19 14:02:58 -0400 | |
|---|---|---|
| committer | 2019-05-19 14:02:58 -0400 | |
| commit | d49efbfb4aa4e935f6c753871d6af6534701f542 (patch) | |
| tree | 79608391a32719a0be20c898fc79aba93f9f1d48 /src | |
| parent | Merge pull request #2410 from lioncash/affinity (diff) | |
| parent | shader_ir/other: Implement IPA.IDX (diff) | |
| download | yuzu-d49efbfb4aa4e935f6c753871d6af6534701f542.tar.gz yuzu-d49efbfb4aa4e935f6c753871d6af6534701f542.tar.xz yuzu-d49efbfb4aa4e935f6c753871d6af6534701f542.zip | |
Merge pull request #2441 from ReinUsesLisp/al2p
shader: Implement AL2P and ALD.PHYS
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/engines/maxwell_3d.h | 1 | ||||
| -rw-r--r-- | src/video_core/engines/shader_bytecode.h | 22 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_device.cpp | 9 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_device.h | 14 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 313 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | 7 | ||||
| -rw-r--r-- | src/video_core/shader/decode/memory.cpp | 30 | ||||
| -rw-r--r-- | src/video_core/shader/decode/other.cpp | 13 | ||||
| -rw-r--r-- | src/video_core/shader/shader_ir.cpp | 13 | ||||
| -rw-r--r-- | src/video_core/shader/shader_ir.h | 45 |
10 files changed, 310 insertions, 157 deletions
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 48e4fec33..f342c78e6 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -59,6 +59,7 @@ public: | |||
| 59 | static constexpr std::size_t NumCBData = 16; | 59 | static constexpr std::size_t NumCBData = 16; |
| 60 | static constexpr std::size_t NumVertexArrays = 32; | 60 | static constexpr std::size_t NumVertexArrays = 32; |
| 61 | static constexpr std::size_t NumVertexAttributes = 32; | 61 | static constexpr std::size_t NumVertexAttributes = 32; |
| 62 | static constexpr std::size_t NumVaryings = 31; | ||
| 62 | static constexpr std::size_t NumTextureSamplers = 32; | 63 | static constexpr std::size_t NumTextureSamplers = 32; |
| 63 | static constexpr std::size_t NumClipDistances = 8; | 64 | static constexpr std::size_t NumClipDistances = 8; |
| 64 | static constexpr std::size_t MaxShaderProgram = 6; | 65 | static constexpr std::size_t MaxShaderProgram = 6; |
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index e5b4eadea..7bbc556da 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -98,6 +98,10 @@ union Attribute { | |||
| 98 | BitField<22, 2, u64> element; | 98 | BitField<22, 2, u64> element; |
| 99 | BitField<24, 6, Index> index; | 99 | BitField<24, 6, Index> index; |
| 100 | BitField<47, 3, AttributeSize> size; | 100 | BitField<47, 3, AttributeSize> size; |
| 101 | |||
| 102 | bool IsPhysical() const { | ||
| 103 | return element == 0 && static_cast<u64>(index.Value()) == 0; | ||
| 104 | } | ||
| 101 | } fmt20; | 105 | } fmt20; |
| 102 | 106 | ||
| 103 | union { | 107 | union { |
| @@ -499,6 +503,11 @@ enum class SystemVariable : u64 { | |||
| 499 | CircularQueueEntryAddressHigh = 0x63, | 503 | CircularQueueEntryAddressHigh = 0x63, |
| 500 | }; | 504 | }; |
| 501 | 505 | ||
| 506 | enum class PhysicalAttributeDirection : u64 { | ||
| 507 | Input = 0, | ||
| 508 | Output = 1, | ||
| 509 | }; | ||
| 510 | |||
| 502 | union Instruction { | 511 | union Instruction { |
| 503 | Instruction& operator=(const Instruction& instr) { | 512 | Instruction& operator=(const Instruction& instr) { |
| 504 | value = instr.value; | 513 | value = instr.value; |
| @@ -587,6 +596,7 @@ union Instruction { | |||
| 587 | } alu; | 596 | } alu; |
| 588 | 597 | ||
| 589 | union { | 598 | union { |
| 599 | BitField<38, 1, u64> idx; | ||
| 590 | BitField<51, 1, u64> saturate; | 600 | BitField<51, 1, u64> saturate; |
| 591 | BitField<52, 2, IpaSampleMode> sample_mode; | 601 | BitField<52, 2, IpaSampleMode> sample_mode; |
| 592 | BitField<54, 2, IpaInterpMode> interp_mode; | 602 | BitField<54, 2, IpaInterpMode> interp_mode; |
| @@ -812,6 +822,12 @@ union Instruction { | |||
| 812 | } stg; | 822 | } stg; |
| 813 | 823 | ||
| 814 | union { | 824 | union { |
| 825 | BitField<32, 1, PhysicalAttributeDirection> direction; | ||
| 826 | BitField<47, 3, AttributeSize> size; | ||
| 827 | BitField<20, 11, u64> address; | ||
| 828 | } al2p; | ||
| 829 | |||
| 830 | union { | ||
| 815 | BitField<0, 3, u64> pred0; | 831 | BitField<0, 3, u64> pred0; |
| 816 | BitField<3, 3, u64> pred3; | 832 | BitField<3, 3, u64> pred3; |
| 817 | BitField<7, 1, u64> abs_a; | 833 | BitField<7, 1, u64> abs_a; |
| @@ -1374,8 +1390,9 @@ public: | |||
| 1374 | ST_A, | 1390 | ST_A, |
| 1375 | ST_L, | 1391 | ST_L, |
| 1376 | ST_S, | 1392 | ST_S, |
| 1377 | LDG, // Load from global memory | 1393 | LDG, // Load from global memory |
| 1378 | STG, // Store in global memory | 1394 | STG, // Store in global memory |
| 1395 | AL2P, // Transforms attribute memory into physical memory | ||
| 1379 | TEX, | 1396 | TEX, |
| 1380 | TEX_B, // Texture Load Bindless | 1397 | TEX_B, // Texture Load Bindless |
| 1381 | TXQ, // Texture Query | 1398 | TXQ, // Texture Query |
| @@ -1646,6 +1663,7 @@ private: | |||
| 1646 | INST("1110111101010---", Id::ST_L, Type::Memory, "ST_L"), | 1663 | INST("1110111101010---", Id::ST_L, Type::Memory, "ST_L"), |
| 1647 | INST("1110111011010---", Id::LDG, Type::Memory, "LDG"), | 1664 | INST("1110111011010---", Id::LDG, Type::Memory, "LDG"), |
| 1648 | INST("1110111011011---", Id::STG, Type::Memory, "STG"), | 1665 | INST("1110111011011---", Id::STG, Type::Memory, "STG"), |
| 1666 | INST("1110111110100---", Id::AL2P, Type::Memory, "AL2P"), | ||
| 1649 | INST("110000----111---", Id::TEX, Type::Texture, "TEX"), | 1667 | INST("110000----111---", Id::TEX, Type::Texture, "TEX"), |
| 1650 | INST("1101111010111---", Id::TEX_B, Type::Texture, "TEX_B"), | 1668 | INST("1101111010111---", Id::TEX_B, Type::Texture, "TEX_B"), |
| 1651 | INST("1101111101001---", Id::TXQ, Type::Texture, "TXQ"), | 1669 | INST("1101111101001---", Id::TXQ, Type::Texture, "TXQ"), |
diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index b6d9e0ddb..38497678a 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp | |||
| @@ -21,9 +21,18 @@ T GetInteger(GLenum pname) { | |||
| 21 | 21 | ||
| 22 | Device::Device() { | 22 | Device::Device() { |
| 23 | uniform_buffer_alignment = GetInteger<std::size_t>(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT); | 23 | uniform_buffer_alignment = GetInteger<std::size_t>(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT); |
| 24 | max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS); | ||
| 25 | max_varyings = GetInteger<u32>(GL_MAX_VARYING_VECTORS); | ||
| 24 | has_variable_aoffi = TestVariableAoffi(); | 26 | has_variable_aoffi = TestVariableAoffi(); |
| 25 | } | 27 | } |
| 26 | 28 | ||
| 29 | Device::Device(std::nullptr_t) { | ||
| 30 | uniform_buffer_alignment = 0; | ||
| 31 | max_vertex_attributes = 16; | ||
| 32 | max_varyings = 15; | ||
| 33 | has_variable_aoffi = true; | ||
| 34 | } | ||
| 35 | |||
| 27 | bool Device::TestVariableAoffi() { | 36 | bool Device::TestVariableAoffi() { |
| 28 | const GLchar* AOFFI_TEST = R"(#version 430 core | 37 | const GLchar* AOFFI_TEST = R"(#version 430 core |
| 29 | uniform sampler2D tex; | 38 | uniform sampler2D tex; |
diff --git a/src/video_core/renderer_opengl/gl_device.h b/src/video_core/renderer_opengl/gl_device.h index 78ff5ee58..de8490682 100644 --- a/src/video_core/renderer_opengl/gl_device.h +++ b/src/video_core/renderer_opengl/gl_device.h | |||
| @@ -5,17 +5,27 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstddef> | 7 | #include <cstddef> |
| 8 | #include "common/common_types.h" | ||
| 8 | 9 | ||
| 9 | namespace OpenGL { | 10 | namespace OpenGL { |
| 10 | 11 | ||
| 11 | class Device { | 12 | class Device { |
| 12 | public: | 13 | public: |
| 13 | Device(); | 14 | explicit Device(); |
| 15 | explicit Device(std::nullptr_t); | ||
| 14 | 16 | ||
| 15 | std::size_t GetUniformBufferAlignment() const { | 17 | std::size_t GetUniformBufferAlignment() const { |
| 16 | return uniform_buffer_alignment; | 18 | return uniform_buffer_alignment; |
| 17 | } | 19 | } |
| 18 | 20 | ||
| 21 | u32 GetMaxVertexAttributes() const { | ||
| 22 | return max_vertex_attributes; | ||
| 23 | } | ||
| 24 | |||
| 25 | u32 GetMaxVaryings() const { | ||
| 26 | return max_varyings; | ||
| 27 | } | ||
| 28 | |||
| 19 | bool HasVariableAoffi() const { | 29 | bool HasVariableAoffi() const { |
| 20 | return has_variable_aoffi; | 30 | return has_variable_aoffi; |
| 21 | } | 31 | } |
| @@ -24,6 +34,8 @@ private: | |||
| 24 | static bool TestVariableAoffi(); | 34 | static bool TestVariableAoffi(); |
| 25 | 35 | ||
| 26 | std::size_t uniform_buffer_alignment{}; | 36 | std::size_t uniform_buffer_alignment{}; |
| 37 | u32 max_vertex_attributes{}; | ||
| 38 | u32 max_varyings{}; | ||
| 27 | bool has_variable_aoffi{}; | 39 | bool has_variable_aoffi{}; |
| 28 | }; | 40 | }; |
| 29 | 41 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 1a62795e1..4bff54a59 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -134,6 +134,19 @@ bool IsPrecise(Node node) { | |||
| 134 | return false; | 134 | return false; |
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | constexpr bool IsGenericAttribute(Attribute::Index index) { | ||
| 138 | return index >= Attribute::Index::Attribute_0 && index <= Attribute::Index::Attribute_31; | ||
| 139 | } | ||
| 140 | |||
| 141 | constexpr Attribute::Index ToGenericAttribute(u32 value) { | ||
| 142 | return static_cast<Attribute::Index>(value + static_cast<u32>(Attribute::Index::Attribute_0)); | ||
| 143 | } | ||
| 144 | |||
| 145 | u32 GetGenericAttributeIndex(Attribute::Index index) { | ||
| 146 | ASSERT(IsGenericAttribute(index)); | ||
| 147 | return static_cast<u32>(index) - static_cast<u32>(Attribute::Index::Attribute_0); | ||
| 148 | } | ||
| 149 | |||
| 137 | class GLSLDecompiler final { | 150 | class GLSLDecompiler final { |
| 138 | public: | 151 | public: |
| 139 | explicit GLSLDecompiler(const Device& device, const ShaderIR& ir, ShaderStage stage, | 152 | explicit GLSLDecompiler(const Device& device, const ShaderIR& ir, ShaderStage stage, |
| @@ -152,6 +165,7 @@ public: | |||
| 152 | DeclareConstantBuffers(); | 165 | DeclareConstantBuffers(); |
| 153 | DeclareGlobalMemory(); | 166 | DeclareGlobalMemory(); |
| 154 | DeclareSamplers(); | 167 | DeclareSamplers(); |
| 168 | DeclarePhysicalAttributeReader(); | ||
| 155 | 169 | ||
| 156 | code.AddLine("void execute_" + suffix + "() {"); | 170 | code.AddLine("void execute_" + suffix + "() {"); |
| 157 | ++code.scope; | 171 | ++code.scope; |
| @@ -296,76 +310,95 @@ private: | |||
| 296 | } | 310 | } |
| 297 | 311 | ||
| 298 | std::string GetInputFlags(AttributeUse attribute) { | 312 | std::string GetInputFlags(AttributeUse attribute) { |
| 299 | std::string out; | ||
| 300 | |||
| 301 | switch (attribute) { | 313 | switch (attribute) { |
| 302 | case AttributeUse::Constant: | ||
| 303 | out += "flat "; | ||
| 304 | break; | ||
| 305 | case AttributeUse::ScreenLinear: | ||
| 306 | out += "noperspective "; | ||
| 307 | break; | ||
| 308 | case AttributeUse::Perspective: | 314 | case AttributeUse::Perspective: |
| 309 | // Default, Smooth | 315 | // Default, Smooth |
| 310 | break; | 316 | return {}; |
| 317 | case AttributeUse::Constant: | ||
| 318 | return "flat "; | ||
| 319 | case AttributeUse::ScreenLinear: | ||
| 320 | return "noperspective "; | ||
| 311 | default: | 321 | default: |
| 312 | LOG_CRITICAL(HW_GPU, "Unused attribute being fetched"); | 322 | case AttributeUse::Unused: |
| 313 | UNREACHABLE(); | 323 | UNREACHABLE_MSG("Unused attribute being fetched"); |
| 324 | return {}; | ||
| 325 | UNIMPLEMENTED_MSG("Unknown attribute usage index={}", static_cast<u32>(attribute)); | ||
| 326 | return {}; | ||
| 314 | } | 327 | } |
| 315 | return out; | ||
| 316 | } | 328 | } |
| 317 | 329 | ||
| 318 | void DeclareInputAttributes() { | 330 | void DeclareInputAttributes() { |
| 319 | const auto& attributes = ir.GetInputAttributes(); | 331 | if (ir.HasPhysicalAttributes()) { |
| 320 | for (const auto element : attributes) { | 332 | const u32 num_inputs{GetNumPhysicalInputAttributes()}; |
| 321 | const Attribute::Index index = element.first; | 333 | for (u32 i = 0; i < num_inputs; ++i) { |
| 322 | if (index < Attribute::Index::Attribute_0 || index > Attribute::Index::Attribute_31) { | 334 | DeclareInputAttribute(ToGenericAttribute(i), true); |
| 323 | // Skip when it's not a generic attribute | ||
| 324 | continue; | ||
| 325 | } | ||
| 326 | |||
| 327 | // TODO(bunnei): Use proper number of elements for these | ||
| 328 | u32 idx = static_cast<u32>(index) - static_cast<u32>(Attribute::Index::Attribute_0); | ||
| 329 | if (stage != ShaderStage::Vertex) { | ||
| 330 | // If inputs are varyings, add an offset | ||
| 331 | idx += GENERIC_VARYING_START_LOCATION; | ||
| 332 | } | 335 | } |
| 336 | code.AddNewLine(); | ||
| 337 | return; | ||
| 338 | } | ||
| 333 | 339 | ||
| 334 | std::string attr = GetInputAttribute(index); | 340 | const auto& attributes = ir.GetInputAttributes(); |
| 335 | if (stage == ShaderStage::Geometry) { | 341 | for (const auto index : attributes) { |
| 336 | attr = "gs_" + attr + "[]"; | 342 | if (IsGenericAttribute(index)) { |
| 337 | } | 343 | DeclareInputAttribute(index, false); |
| 338 | std::string suffix; | ||
| 339 | if (stage == ShaderStage::Fragment) { | ||
| 340 | const auto input_mode = | ||
| 341 | header.ps.GetAttributeUse(idx - GENERIC_VARYING_START_LOCATION); | ||
| 342 | suffix = GetInputFlags(input_mode); | ||
| 343 | } | 344 | } |
| 344 | code.AddLine("layout (location = " + std::to_string(idx) + ") " + suffix + "in vec4 " + | ||
| 345 | attr + ';'); | ||
| 346 | } | 345 | } |
| 347 | if (!attributes.empty()) | 346 | if (!attributes.empty()) |
| 348 | code.AddNewLine(); | 347 | code.AddNewLine(); |
| 349 | } | 348 | } |
| 350 | 349 | ||
| 350 | void DeclareInputAttribute(Attribute::Index index, bool skip_unused) { | ||
| 351 | const u32 generic_index{GetGenericAttributeIndex(index)}; | ||
| 352 | |||
| 353 | std::string name{GetInputAttribute(index)}; | ||
| 354 | if (stage == ShaderStage::Geometry) { | ||
| 355 | name = "gs_" + name + "[]"; | ||
| 356 | } | ||
| 357 | |||
| 358 | std::string suffix; | ||
| 359 | if (stage == ShaderStage::Fragment) { | ||
| 360 | const auto input_mode{header.ps.GetAttributeUse(generic_index)}; | ||
| 361 | if (skip_unused && input_mode == AttributeUse::Unused) { | ||
| 362 | return; | ||
| 363 | } | ||
| 364 | suffix = GetInputFlags(input_mode); | ||
| 365 | } | ||
| 366 | |||
| 367 | u32 location = generic_index; | ||
| 368 | if (stage != ShaderStage::Vertex) { | ||
| 369 | // If inputs are varyings, add an offset | ||
| 370 | location += GENERIC_VARYING_START_LOCATION; | ||
| 371 | } | ||
| 372 | |||
| 373 | code.AddLine("layout (location = " + std::to_string(location) + ") " + suffix + "in vec4 " + | ||
| 374 | name + ';'); | ||
| 375 | } | ||
| 376 | |||
| 351 | void DeclareOutputAttributes() { | 377 | void DeclareOutputAttributes() { |
| 378 | if (ir.HasPhysicalAttributes() && stage != ShaderStage::Fragment) { | ||
| 379 | for (u32 i = 0; i < GetNumPhysicalVaryings(); ++i) { | ||
| 380 | DeclareOutputAttribute(ToGenericAttribute(i)); | ||
| 381 | } | ||
| 382 | code.AddNewLine(); | ||
| 383 | return; | ||
| 384 | } | ||
| 385 | |||
| 352 | const auto& attributes = ir.GetOutputAttributes(); | 386 | const auto& attributes = ir.GetOutputAttributes(); |
| 353 | for (const auto index : attributes) { | 387 | for (const auto index : attributes) { |
| 354 | if (index < Attribute::Index::Attribute_0 || index > Attribute::Index::Attribute_31) { | 388 | if (IsGenericAttribute(index)) { |
| 355 | // Skip when it's not a generic attribute | 389 | DeclareOutputAttribute(index); |
| 356 | continue; | ||
| 357 | } | 390 | } |
| 358 | // TODO(bunnei): Use proper number of elements for these | ||
| 359 | const auto idx = static_cast<u32>(index) - | ||
| 360 | static_cast<u32>(Attribute::Index::Attribute_0) + | ||
| 361 | GENERIC_VARYING_START_LOCATION; | ||
| 362 | code.AddLine("layout (location = " + std::to_string(idx) + ") out vec4 " + | ||
| 363 | GetOutputAttribute(index) + ';'); | ||
| 364 | } | 391 | } |
| 365 | if (!attributes.empty()) | 392 | if (!attributes.empty()) |
| 366 | code.AddNewLine(); | 393 | code.AddNewLine(); |
| 367 | } | 394 | } |
| 368 | 395 | ||
| 396 | void DeclareOutputAttribute(Attribute::Index index) { | ||
| 397 | const u32 location{GetGenericAttributeIndex(index) + GENERIC_VARYING_START_LOCATION}; | ||
| 398 | code.AddLine("layout (location = " + std::to_string(location) + ") out vec4 " + | ||
| 399 | GetOutputAttribute(index) + ';'); | ||
| 400 | } | ||
| 401 | |||
| 369 | void DeclareConstantBuffers() { | 402 | void DeclareConstantBuffers() { |
| 370 | for (const auto& entry : ir.GetConstantBuffers()) { | 403 | for (const auto& entry : ir.GetConstantBuffers()) { |
| 371 | const auto [index, size] = entry; | 404 | const auto [index, size] = entry; |
| @@ -429,6 +462,39 @@ private: | |||
| 429 | code.AddNewLine(); | 462 | code.AddNewLine(); |
| 430 | } | 463 | } |
| 431 | 464 | ||
| 465 | void DeclarePhysicalAttributeReader() { | ||
| 466 | if (!ir.HasPhysicalAttributes()) { | ||
| 467 | return; | ||
| 468 | } | ||
| 469 | code.AddLine("float readPhysicalAttribute(uint physical_address) {"); | ||
| 470 | ++code.scope; | ||
| 471 | code.AddLine("switch (physical_address) {"); | ||
| 472 | |||
| 473 | // Just declare generic attributes for now. | ||
| 474 | const auto num_attributes{static_cast<u32>(GetNumPhysicalInputAttributes())}; | ||
| 475 | for (u32 index = 0; index < num_attributes; ++index) { | ||
| 476 | const auto attribute{ToGenericAttribute(index)}; | ||
| 477 | for (u32 element = 0; element < 4; ++element) { | ||
| 478 | constexpr u32 generic_base{0x80}; | ||
| 479 | constexpr u32 generic_stride{16}; | ||
| 480 | constexpr u32 element_stride{4}; | ||
| 481 | const u32 address{generic_base + index * generic_stride + element * element_stride}; | ||
| 482 | |||
| 483 | const bool declared{stage != ShaderStage::Fragment || | ||
| 484 | header.ps.GetAttributeUse(index) != AttributeUse::Unused}; | ||
| 485 | const std::string value{declared ? ReadAttribute(attribute, element) : "0"}; | ||
| 486 | code.AddLine(fmt::format("case 0x{:x}: return {};", address, value)); | ||
| 487 | } | ||
| 488 | } | ||
| 489 | |||
| 490 | code.AddLine("default: return 0;"); | ||
| 491 | |||
| 492 | code.AddLine('}'); | ||
| 493 | --code.scope; | ||
| 494 | code.AddLine('}'); | ||
| 495 | code.AddNewLine(); | ||
| 496 | } | ||
| 497 | |||
| 432 | void VisitBlock(const NodeBlock& bb) { | 498 | void VisitBlock(const NodeBlock& bb) { |
| 433 | for (const Node node : bb) { | 499 | for (const Node node : bb) { |
| 434 | if (const std::string expr = Visit(node); !expr.empty()) { | 500 | if (const std::string expr = Visit(node); !expr.empty()) { |
| @@ -483,70 +549,12 @@ private: | |||
| 483 | return value; | 549 | return value; |
| 484 | 550 | ||
| 485 | } else if (const auto abuf = std::get_if<AbufNode>(node)) { | 551 | } else if (const auto abuf = std::get_if<AbufNode>(node)) { |
| 486 | const auto attribute = abuf->GetIndex(); | 552 | UNIMPLEMENTED_IF_MSG(abuf->IsPhysicalBuffer() && stage == ShaderStage::Geometry, |
| 487 | const auto element = abuf->GetElement(); | 553 | "Physical attributes in geometry shaders are not implemented"); |
| 488 | 554 | if (abuf->IsPhysicalBuffer()) { | |
| 489 | const auto GeometryPass = [&](const std::string& name) { | 555 | return "readPhysicalAttribute(ftou(" + Visit(abuf->GetPhysicalAddress()) + "))"; |
| 490 | if (stage == ShaderStage::Geometry && abuf->GetBuffer()) { | ||
| 491 | // TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games | ||
| 492 | // set an 0x80000000 index for those and the shader fails to build. Find out why | ||
| 493 | // this happens and what's its intent. | ||
| 494 | return "gs_" + name + "[ftou(" + Visit(abuf->GetBuffer()) + | ||
| 495 | ") % MAX_VERTEX_INPUT]"; | ||
| 496 | } | ||
| 497 | return name; | ||
| 498 | }; | ||
| 499 | |||
| 500 | switch (attribute) { | ||
| 501 | case Attribute::Index::Position: | ||
| 502 | if (stage != ShaderStage::Fragment) { | ||
| 503 | return GeometryPass("position") + GetSwizzle(element); | ||
| 504 | } else { | ||
| 505 | return element == 3 ? "1.0f" : "gl_FragCoord" + GetSwizzle(element); | ||
| 506 | } | ||
| 507 | case Attribute::Index::PointCoord: | ||
| 508 | switch (element) { | ||
| 509 | case 0: | ||
| 510 | return "gl_PointCoord.x"; | ||
| 511 | case 1: | ||
| 512 | return "gl_PointCoord.y"; | ||
| 513 | case 2: | ||
| 514 | case 3: | ||
| 515 | return "0"; | ||
| 516 | } | ||
| 517 | UNREACHABLE(); | ||
| 518 | return "0"; | ||
| 519 | case Attribute::Index::TessCoordInstanceIDVertexID: | ||
| 520 | // TODO(Subv): Find out what the values are for the first two elements when inside a | ||
| 521 | // vertex shader, and what's the value of the fourth element when inside a Tess Eval | ||
| 522 | // shader. | ||
| 523 | ASSERT(stage == ShaderStage::Vertex); | ||
| 524 | switch (element) { | ||
| 525 | case 2: | ||
| 526 | // Config pack's first value is instance_id. | ||
| 527 | return "uintBitsToFloat(config_pack[0])"; | ||
| 528 | case 3: | ||
| 529 | return "uintBitsToFloat(gl_VertexID)"; | ||
| 530 | } | ||
| 531 | UNIMPLEMENTED_MSG("Unmanaged TessCoordInstanceIDVertexID element={}", element); | ||
| 532 | return "0"; | ||
| 533 | case Attribute::Index::FrontFacing: | ||
| 534 | // TODO(Subv): Find out what the values are for the other elements. | ||
| 535 | ASSERT(stage == ShaderStage::Fragment); | ||
| 536 | switch (element) { | ||
| 537 | case 3: | ||
| 538 | return "itof(gl_FrontFacing ? -1 : 0)"; | ||
| 539 | } | ||
| 540 | UNIMPLEMENTED_MSG("Unmanaged FrontFacing element={}", element); | ||
| 541 | return "0"; | ||
| 542 | default: | ||
| 543 | if (attribute >= Attribute::Index::Attribute_0 && | ||
| 544 | attribute <= Attribute::Index::Attribute_31) { | ||
| 545 | return GeometryPass(GetInputAttribute(attribute)) + GetSwizzle(element); | ||
| 546 | } | ||
| 547 | break; | ||
| 548 | } | 556 | } |
| 549 | UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute)); | 557 | return ReadAttribute(abuf->GetIndex(), abuf->GetElement(), abuf->GetBuffer()); |
| 550 | 558 | ||
| 551 | } else if (const auto cbuf = std::get_if<CbufNode>(node)) { | 559 | } else if (const auto cbuf = std::get_if<CbufNode>(node)) { |
| 552 | const Node offset = cbuf->GetOffset(); | 560 | const Node offset = cbuf->GetOffset(); |
| @@ -598,6 +606,69 @@ private: | |||
| 598 | return {}; | 606 | return {}; |
| 599 | } | 607 | } |
| 600 | 608 | ||
| 609 | std::string ReadAttribute(Attribute::Index attribute, u32 element, Node buffer = {}) { | ||
| 610 | const auto GeometryPass = [&](std::string name) { | ||
| 611 | if (stage == ShaderStage::Geometry && buffer) { | ||
| 612 | // TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games | ||
| 613 | // set an 0x80000000 index for those and the shader fails to build. Find out why | ||
| 614 | // this happens and what's its intent. | ||
| 615 | return "gs_" + std::move(name) + "[ftou(" + Visit(buffer) + ") % MAX_VERTEX_INPUT]"; | ||
| 616 | } | ||
| 617 | return name; | ||
| 618 | }; | ||
| 619 | |||
| 620 | switch (attribute) { | ||
| 621 | case Attribute::Index::Position: | ||
| 622 | if (stage != ShaderStage::Fragment) { | ||
| 623 | return GeometryPass("position") + GetSwizzle(element); | ||
| 624 | } else { | ||
| 625 | return element == 3 ? "1.0f" : "gl_FragCoord" + GetSwizzle(element); | ||
| 626 | } | ||
| 627 | case Attribute::Index::PointCoord: | ||
| 628 | switch (element) { | ||
| 629 | case 0: | ||
| 630 | return "gl_PointCoord.x"; | ||
| 631 | case 1: | ||
| 632 | return "gl_PointCoord.y"; | ||
| 633 | case 2: | ||
| 634 | case 3: | ||
| 635 | return "0"; | ||
| 636 | } | ||
| 637 | UNREACHABLE(); | ||
| 638 | return "0"; | ||
| 639 | case Attribute::Index::TessCoordInstanceIDVertexID: | ||
| 640 | // TODO(Subv): Find out what the values are for the first two elements when inside a | ||
| 641 | // vertex shader, and what's the value of the fourth element when inside a Tess Eval | ||
| 642 | // shader. | ||
| 643 | ASSERT(stage == ShaderStage::Vertex); | ||
| 644 | switch (element) { | ||
| 645 | case 2: | ||
| 646 | // Config pack's first value is instance_id. | ||
| 647 | return "uintBitsToFloat(config_pack[0])"; | ||
| 648 | case 3: | ||
| 649 | return "uintBitsToFloat(gl_VertexID)"; | ||
| 650 | } | ||
| 651 | UNIMPLEMENTED_MSG("Unmanaged TessCoordInstanceIDVertexID element={}", element); | ||
| 652 | return "0"; | ||
| 653 | case Attribute::Index::FrontFacing: | ||
| 654 | // TODO(Subv): Find out what the values are for the other elements. | ||
| 655 | ASSERT(stage == ShaderStage::Fragment); | ||
| 656 | switch (element) { | ||
| 657 | case 3: | ||
| 658 | return "itof(gl_FrontFacing ? -1 : 0)"; | ||
| 659 | } | ||
| 660 | UNIMPLEMENTED_MSG("Unmanaged FrontFacing element={}", element); | ||
| 661 | return "0"; | ||
| 662 | default: | ||
| 663 | if (IsGenericAttribute(attribute)) { | ||
| 664 | return GeometryPass(GetInputAttribute(attribute)) + GetSwizzle(element); | ||
| 665 | } | ||
| 666 | break; | ||
| 667 | } | ||
| 668 | UNIMPLEMENTED_MSG("Unhandled input attribute: {}", static_cast<u32>(attribute)); | ||
| 669 | return "0"; | ||
| 670 | } | ||
| 671 | |||
| 601 | std::string ApplyPrecise(Operation operation, const std::string& value) { | 672 | std::string ApplyPrecise(Operation operation, const std::string& value) { |
| 602 | if (!IsPrecise(operation)) { | 673 | if (!IsPrecise(operation)) { |
| 603 | return value; | 674 | return value; |
| @@ -833,6 +904,8 @@ private: | |||
| 833 | target = GetRegister(gpr->GetIndex()); | 904 | target = GetRegister(gpr->GetIndex()); |
| 834 | 905 | ||
| 835 | } else if (const auto abuf = std::get_if<AbufNode>(dest)) { | 906 | } else if (const auto abuf = std::get_if<AbufNode>(dest)) { |
| 907 | UNIMPLEMENTED_IF(abuf->IsPhysicalBuffer()); | ||
| 908 | |||
| 836 | target = [&]() -> std::string { | 909 | target = [&]() -> std::string { |
| 837 | switch (const auto attribute = abuf->GetIndex(); abuf->GetIndex()) { | 910 | switch (const auto attribute = abuf->GetIndex(); abuf->GetIndex()) { |
| 838 | case Attribute::Index::Position: | 911 | case Attribute::Index::Position: |
| @@ -844,8 +917,7 @@ private: | |||
| 844 | case Attribute::Index::ClipDistances4567: | 917 | case Attribute::Index::ClipDistances4567: |
| 845 | return "gl_ClipDistance[" + std::to_string(abuf->GetElement() + 4) + ']'; | 918 | return "gl_ClipDistance[" + std::to_string(abuf->GetElement() + 4) + ']'; |
| 846 | default: | 919 | default: |
| 847 | if (attribute >= Attribute::Index::Attribute_0 && | 920 | if (IsGenericAttribute(attribute)) { |
| 848 | attribute <= Attribute::Index::Attribute_31) { | ||
| 849 | return GetOutputAttribute(attribute) + GetSwizzle(abuf->GetElement()); | 921 | return GetOutputAttribute(attribute) + GetSwizzle(abuf->GetElement()); |
| 850 | } | 922 | } |
| 851 | UNIMPLEMENTED_MSG("Unhandled output attribute: {}", | 923 | UNIMPLEMENTED_MSG("Unhandled output attribute: {}", |
| @@ -1591,15 +1663,11 @@ private: | |||
| 1591 | } | 1663 | } |
| 1592 | 1664 | ||
| 1593 | std::string GetInputAttribute(Attribute::Index attribute) const { | 1665 | std::string GetInputAttribute(Attribute::Index attribute) const { |
| 1594 | const auto index{static_cast<u32>(attribute) - | 1666 | return GetDeclarationWithSuffix(GetGenericAttributeIndex(attribute), "input_attr"); |
| 1595 | static_cast<u32>(Attribute::Index::Attribute_0)}; | ||
| 1596 | return GetDeclarationWithSuffix(index, "input_attr"); | ||
| 1597 | } | 1667 | } |
| 1598 | 1668 | ||
| 1599 | std::string GetOutputAttribute(Attribute::Index attribute) const { | 1669 | std::string GetOutputAttribute(Attribute::Index attribute) const { |
| 1600 | const auto index{static_cast<u32>(attribute) - | 1670 | return GetDeclarationWithSuffix(GetGenericAttributeIndex(attribute), "output_attr"); |
| 1601 | static_cast<u32>(Attribute::Index::Attribute_0)}; | ||
| 1602 | return GetDeclarationWithSuffix(index, "output_attr"); | ||
| 1603 | } | 1671 | } |
| 1604 | 1672 | ||
| 1605 | std::string GetConstBuffer(u32 index) const { | 1673 | std::string GetConstBuffer(u32 index) const { |
| @@ -1640,6 +1708,19 @@ private: | |||
| 1640 | return name + '_' + std::to_string(index) + '_' + suffix; | 1708 | return name + '_' + std::to_string(index) + '_' + suffix; |
| 1641 | } | 1709 | } |
| 1642 | 1710 | ||
| 1711 | u32 GetNumPhysicalInputAttributes() const { | ||
| 1712 | return stage == ShaderStage::Vertex ? GetNumPhysicalAttributes() : GetNumPhysicalVaryings(); | ||
| 1713 | } | ||
| 1714 | |||
| 1715 | u32 GetNumPhysicalAttributes() const { | ||
| 1716 | return std::min<u32>(device.GetMaxVertexAttributes(), Maxwell::NumVertexAttributes); | ||
| 1717 | } | ||
| 1718 | |||
| 1719 | u32 GetNumPhysicalVaryings() const { | ||
| 1720 | return std::min<u32>(device.GetMaxVaryings() - GENERIC_VARYING_START_LOCATION, | ||
| 1721 | Maxwell::NumVaryings); | ||
| 1722 | } | ||
| 1723 | |||
| 1643 | const Device& device; | 1724 | const Device& device; |
| 1644 | const ShaderIR& ir; | 1725 | const ShaderIR& ir; |
| 1645 | const ShaderStage stage; | 1726 | const ShaderStage stage; |
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index a11000f6b..b61a6d170 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | |||
| @@ -194,8 +194,8 @@ public: | |||
| 194 | for (const auto& sampler : ir.GetSamplers()) { | 194 | for (const auto& sampler : ir.GetSamplers()) { |
| 195 | entries.samplers.emplace_back(sampler); | 195 | entries.samplers.emplace_back(sampler); |
| 196 | } | 196 | } |
| 197 | for (const auto& attr : ir.GetInputAttributes()) { | 197 | for (const auto& attribute : ir.GetInputAttributes()) { |
| 198 | entries.attributes.insert(GetGenericAttributeLocation(attr.first)); | 198 | entries.attributes.insert(GetGenericAttributeLocation(attribute)); |
| 199 | } | 199 | } |
| 200 | entries.clip_distances = ir.GetClipDistances(); | 200 | entries.clip_distances = ir.GetClipDistances(); |
| 201 | entries.shader_length = ir.GetLength(); | 201 | entries.shader_length = ir.GetLength(); |
| @@ -321,8 +321,7 @@ private: | |||
| 321 | } | 321 | } |
| 322 | 322 | ||
| 323 | void DeclareInputAttributes() { | 323 | void DeclareInputAttributes() { |
| 324 | for (const auto element : ir.GetInputAttributes()) { | 324 | for (const auto index : ir.GetInputAttributes()) { |
| 325 | const Attribute::Index index = element.first; | ||
| 326 | if (!IsGenericAttribute(index)) { | 325 | if (!IsGenericAttribute(index)) { |
| 327 | continue; | 326 | continue; |
| 328 | } | 327 | } |
diff --git a/src/video_core/shader/decode/memory.cpp b/src/video_core/shader/decode/memory.cpp index ea1092db1..6a992c543 100644 --- a/src/video_core/shader/decode/memory.cpp +++ b/src/video_core/shader/decode/memory.cpp | |||
| @@ -12,6 +12,8 @@ | |||
| 12 | #include "video_core/engines/shader_bytecode.h" | 12 | #include "video_core/engines/shader_bytecode.h" |
| 13 | #include "video_core/shader/shader_ir.h" | 13 | #include "video_core/shader/shader_ir.h" |
| 14 | 14 | ||
| 15 | #pragma optimize("", off) | ||
| 16 | |||
| 15 | namespace VideoCommon::Shader { | 17 | namespace VideoCommon::Shader { |
| 16 | 18 | ||
| 17 | using Tegra::Shader::Attribute; | 19 | using Tegra::Shader::Attribute; |
| @@ -47,17 +49,20 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | |||
| 47 | "Indirect attribute loads are not supported"); | 49 | "Indirect attribute loads are not supported"); |
| 48 | UNIMPLEMENTED_IF_MSG((instr.attribute.fmt20.immediate.Value() % sizeof(u32)) != 0, | 50 | UNIMPLEMENTED_IF_MSG((instr.attribute.fmt20.immediate.Value() % sizeof(u32)) != 0, |
| 49 | "Unaligned attribute loads are not supported"); | 51 | "Unaligned attribute loads are not supported"); |
| 52 | UNIMPLEMENTED_IF_MSG(instr.attribute.fmt20.IsPhysical() && | ||
| 53 | instr.attribute.fmt20.size != Tegra::Shader::AttributeSize::Word, | ||
| 54 | "Non-32 bits PHYS reads are not implemented"); | ||
| 50 | 55 | ||
| 51 | Tegra::Shader::IpaMode input_mode{Tegra::Shader::IpaInterpMode::Pass, | 56 | const Node buffer{GetRegister(instr.gpr39)}; |
| 52 | Tegra::Shader::IpaSampleMode::Default}; | ||
| 53 | 57 | ||
| 54 | u64 next_element = instr.attribute.fmt20.element; | 58 | u64 next_element = instr.attribute.fmt20.element; |
| 55 | auto next_index = static_cast<u64>(instr.attribute.fmt20.index.Value()); | 59 | auto next_index = static_cast<u64>(instr.attribute.fmt20.index.Value()); |
| 56 | 60 | ||
| 57 | const auto LoadNextElement = [&](u32 reg_offset) { | 61 | const auto LoadNextElement = [&](u32 reg_offset) { |
| 58 | const Node buffer = GetRegister(instr.gpr39); | 62 | const Node attribute{instr.attribute.fmt20.IsPhysical() |
| 59 | const Node attribute = GetInputAttribute(static_cast<Attribute::Index>(next_index), | 63 | ? GetPhysicalInputAttribute(instr.gpr8, buffer) |
| 60 | next_element, input_mode, buffer); | 64 | : GetInputAttribute(static_cast<Attribute::Index>(next_index), |
| 65 | next_element, buffer)}; | ||
| 61 | 66 | ||
| 62 | SetRegister(bb, instr.gpr0.Value() + reg_offset, attribute); | 67 | SetRegister(bb, instr.gpr0.Value() + reg_offset, attribute); |
| 63 | 68 | ||
| @@ -239,6 +244,21 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | |||
| 239 | } | 244 | } |
| 240 | break; | 245 | break; |
| 241 | } | 246 | } |
| 247 | case OpCode::Id::AL2P: { | ||
| 248 | // Ignore al2p.direction since we don't care about it. | ||
| 249 | |||
| 250 | // Calculate emulation fake physical address. | ||
| 251 | const Node fixed_address{Immediate(static_cast<u32>(instr.al2p.address))}; | ||
| 252 | const Node reg{GetRegister(instr.gpr8)}; | ||
| 253 | const Node fake_address{Operation(OperationCode::IAdd, NO_PRECISE, reg, fixed_address)}; | ||
| 254 | |||
| 255 | // Set the fake address to target register. | ||
| 256 | SetRegister(bb, instr.gpr0, fake_address); | ||
| 257 | |||
| 258 | // Signal the shader IR to declare all possible attributes and varyings | ||
| 259 | uses_physical_attributes = true; | ||
| 260 | break; | ||
| 261 | } | ||
| 242 | default: | 262 | default: |
| 243 | UNIMPLEMENTED_MSG("Unhandled memory instruction: {}", opcode->get().GetName()); | 263 | UNIMPLEMENTED_MSG("Unhandled memory instruction: {}", opcode->get().GetName()); |
| 244 | } | 264 | } |
diff --git a/src/video_core/shader/decode/other.cpp b/src/video_core/shader/decode/other.cpp index d750a2936..fa17c45b5 100644 --- a/src/video_core/shader/decode/other.cpp +++ b/src/video_core/shader/decode/other.cpp | |||
| @@ -130,15 +130,18 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { | |||
| 130 | break; | 130 | break; |
| 131 | } | 131 | } |
| 132 | case OpCode::Id::IPA: { | 132 | case OpCode::Id::IPA: { |
| 133 | const auto& attribute = instr.attribute.fmt28; | 133 | const bool is_physical = instr.ipa.idx && instr.gpr8.Value() != 0xff; |
| 134 | |||
| 135 | const auto attribute = instr.attribute.fmt28; | ||
| 134 | const Tegra::Shader::IpaMode input_mode{instr.ipa.interp_mode.Value(), | 136 | const Tegra::Shader::IpaMode input_mode{instr.ipa.interp_mode.Value(), |
| 135 | instr.ipa.sample_mode.Value()}; | 137 | instr.ipa.sample_mode.Value()}; |
| 136 | 138 | ||
| 137 | const Node attr = GetInputAttribute(attribute.index, attribute.element, input_mode); | 139 | Node value = is_physical ? GetPhysicalInputAttribute(instr.gpr8) |
| 138 | Node value = attr; | 140 | : GetInputAttribute(attribute.index, attribute.element); |
| 139 | const Tegra::Shader::Attribute::Index index = attribute.index.Value(); | 141 | const Tegra::Shader::Attribute::Index index = attribute.index.Value(); |
| 140 | if (index >= Tegra::Shader::Attribute::Index::Attribute_0 && | 142 | const bool is_generic = index >= Tegra::Shader::Attribute::Index::Attribute_0 && |
| 141 | index <= Tegra::Shader::Attribute::Index::Attribute_31) { | 143 | index <= Tegra::Shader::Attribute::Index::Attribute_31; |
| 144 | if (is_generic || is_physical) { | ||
| 142 | // TODO(Blinkhawk): There are cases where a perspective attribute use PASS. | 145 | // TODO(Blinkhawk): There are cases where a perspective attribute use PASS. |
| 143 | // In theory by setting them as perspective, OpenGL does the perspective correction. | 146 | // In theory by setting them as perspective, OpenGL does the perspective correction. |
| 144 | // A way must figured to reverse the last step of it. | 147 | // A way must figured to reverse the last step of it. |
diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp index 196235e5d..153ad1fd0 100644 --- a/src/video_core/shader/shader_ir.cpp +++ b/src/video_core/shader/shader_ir.cpp | |||
| @@ -96,13 +96,14 @@ Node ShaderIR::GetPredicate(bool immediate) { | |||
| 96 | return GetPredicate(static_cast<u64>(immediate ? Pred::UnusedIndex : Pred::NeverExecute)); | 96 | return GetPredicate(static_cast<u64>(immediate ? Pred::UnusedIndex : Pred::NeverExecute)); |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | Node ShaderIR::GetInputAttribute(Attribute::Index index, u64 element, | 99 | Node ShaderIR::GetInputAttribute(Attribute::Index index, u64 element, Node buffer) { |
| 100 | const Tegra::Shader::IpaMode& input_mode, Node buffer) { | 100 | used_input_attributes.emplace(index); |
| 101 | const auto [entry, is_new] = | 101 | return StoreNode(AbufNode(index, static_cast<u32>(element), buffer)); |
| 102 | used_input_attributes.emplace(std::make_pair(index, std::set<Tegra::Shader::IpaMode>{})); | 102 | } |
| 103 | entry->second.insert(input_mode); | ||
| 104 | 103 | ||
| 105 | return StoreNode(AbufNode(index, static_cast<u32>(element), input_mode, buffer)); | 104 | Node ShaderIR::GetPhysicalInputAttribute(Tegra::Shader::Register physical_address, Node buffer) { |
| 105 | uses_physical_attributes = true; | ||
| 106 | return StoreNode(AbufNode(GetRegister(physical_address), buffer)); | ||
| 106 | } | 107 | } |
| 107 | 108 | ||
| 108 | Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buffer) { | 109 | Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buffer) { |
diff --git a/src/video_core/shader/shader_ir.h b/src/video_core/shader/shader_ir.h index e4253fdb3..0bf124252 100644 --- a/src/video_core/shader/shader_ir.h +++ b/src/video_core/shader/shader_ir.h | |||
| @@ -456,17 +456,14 @@ private: | |||
| 456 | /// Attribute buffer memory (known as attributes or varyings in GLSL terms) | 456 | /// Attribute buffer memory (known as attributes or varyings in GLSL terms) |
| 457 | class AbufNode final { | 457 | class AbufNode final { |
| 458 | public: | 458 | public: |
| 459 | explicit constexpr AbufNode(Tegra::Shader::Attribute::Index index, u32 element, | 459 | // Initialize for standard attributes (index is explicit). |
| 460 | const Tegra::Shader::IpaMode& input_mode, Node buffer = {}) | ||
| 461 | : input_mode{input_mode}, buffer{buffer}, index{index}, element{element} {} | ||
| 462 | |||
| 463 | explicit constexpr AbufNode(Tegra::Shader::Attribute::Index index, u32 element, | 460 | explicit constexpr AbufNode(Tegra::Shader::Attribute::Index index, u32 element, |
| 464 | Node buffer = {}) | 461 | Node buffer = {}) |
| 465 | : input_mode{}, buffer{buffer}, index{index}, element{element} {} | 462 | : buffer{buffer}, index{index}, element{element} {} |
| 466 | 463 | ||
| 467 | Tegra::Shader::IpaMode GetInputMode() const { | 464 | // Initialize for physical attributes (index is a variable value). |
| 468 | return input_mode; | 465 | explicit constexpr AbufNode(Node physical_address, Node buffer = {}) |
| 469 | } | 466 | : physical_address{physical_address}, buffer{buffer} {} |
| 470 | 467 | ||
| 471 | Tegra::Shader::Attribute::Index GetIndex() const { | 468 | Tegra::Shader::Attribute::Index GetIndex() const { |
| 472 | return index; | 469 | return index; |
| @@ -480,11 +477,19 @@ public: | |||
| 480 | return buffer; | 477 | return buffer; |
| 481 | } | 478 | } |
| 482 | 479 | ||
| 480 | bool IsPhysicalBuffer() const { | ||
| 481 | return physical_address != nullptr; | ||
| 482 | } | ||
| 483 | |||
| 484 | Node GetPhysicalAddress() const { | ||
| 485 | return physical_address; | ||
| 486 | } | ||
| 487 | |||
| 483 | private: | 488 | private: |
| 484 | const Tegra::Shader::IpaMode input_mode; | 489 | Node physical_address{}; |
| 485 | const Node buffer; | 490 | Node buffer{}; |
| 486 | const Tegra::Shader::Attribute::Index index; | 491 | Tegra::Shader::Attribute::Index index{}; |
| 487 | const u32 element; | 492 | u32 element{}; |
| 488 | }; | 493 | }; |
| 489 | 494 | ||
| 490 | /// Constant buffer node, usually mapped to uniform buffers in GLSL | 495 | /// Constant buffer node, usually mapped to uniform buffers in GLSL |
| @@ -573,8 +578,7 @@ public: | |||
| 573 | return used_predicates; | 578 | return used_predicates; |
| 574 | } | 579 | } |
| 575 | 580 | ||
| 576 | const std::map<Tegra::Shader::Attribute::Index, std::set<Tegra::Shader::IpaMode>>& | 581 | const std::set<Tegra::Shader::Attribute::Index>& GetInputAttributes() const { |
| 577 | GetInputAttributes() const { | ||
| 578 | return used_input_attributes; | 582 | return used_input_attributes; |
| 579 | } | 583 | } |
| 580 | 584 | ||
| @@ -603,6 +607,10 @@ public: | |||
| 603 | return static_cast<std::size_t>(coverage_end * sizeof(u64)); | 607 | return static_cast<std::size_t>(coverage_end * sizeof(u64)); |
| 604 | } | 608 | } |
| 605 | 609 | ||
| 610 | bool HasPhysicalAttributes() const { | ||
| 611 | return uses_physical_attributes; | ||
| 612 | } | ||
| 613 | |||
| 606 | const Tegra::Shader::Header& GetHeader() const { | 614 | const Tegra::Shader::Header& GetHeader() const { |
| 607 | return header; | 615 | return header; |
| 608 | } | 616 | } |
| @@ -684,8 +692,9 @@ private: | |||
| 684 | /// Generates a predicate node for an immediate true or false value | 692 | /// Generates a predicate node for an immediate true or false value |
| 685 | Node GetPredicate(bool immediate); | 693 | Node GetPredicate(bool immediate); |
| 686 | /// Generates a node representing an input attribute. Keeps track of used attributes. | 694 | /// Generates a node representing an input attribute. Keeps track of used attributes. |
| 687 | Node GetInputAttribute(Tegra::Shader::Attribute::Index index, u64 element, | 695 | Node GetInputAttribute(Tegra::Shader::Attribute::Index index, u64 element, Node buffer = {}); |
| 688 | const Tegra::Shader::IpaMode& input_mode, Node buffer = {}); | 696 | /// Generates a node representing a physical input attribute. |
| 697 | Node GetPhysicalInputAttribute(Tegra::Shader::Register physical_address, Node buffer = {}); | ||
| 689 | /// Generates a node representing an output attribute. Keeps track of used attributes. | 698 | /// Generates a node representing an output attribute. Keeps track of used attributes. |
| 690 | Node GetOutputAttribute(Tegra::Shader::Attribute::Index index, u64 element, Node buffer); | 699 | Node GetOutputAttribute(Tegra::Shader::Attribute::Index index, u64 element, Node buffer); |
| 691 | /// Generates a node representing an internal flag | 700 | /// Generates a node representing an internal flag |
| @@ -859,13 +868,13 @@ private: | |||
| 859 | 868 | ||
| 860 | std::set<u32> used_registers; | 869 | std::set<u32> used_registers; |
| 861 | std::set<Tegra::Shader::Pred> used_predicates; | 870 | std::set<Tegra::Shader::Pred> used_predicates; |
| 862 | std::map<Tegra::Shader::Attribute::Index, std::set<Tegra::Shader::IpaMode>> | 871 | std::set<Tegra::Shader::Attribute::Index> used_input_attributes; |
| 863 | used_input_attributes; | ||
| 864 | std::set<Tegra::Shader::Attribute::Index> used_output_attributes; | 872 | std::set<Tegra::Shader::Attribute::Index> used_output_attributes; |
| 865 | std::map<u32, ConstBuffer> used_cbufs; | 873 | std::map<u32, ConstBuffer> used_cbufs; |
| 866 | std::set<Sampler> used_samplers; | 874 | std::set<Sampler> used_samplers; |
| 867 | std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{}; | 875 | std::array<bool, Tegra::Engines::Maxwell3D::Regs::NumClipDistances> used_clip_distances{}; |
| 868 | std::map<GlobalMemoryBase, GlobalMemoryUsage> used_global_memory; | 876 | std::map<GlobalMemoryBase, GlobalMemoryUsage> used_global_memory; |
| 877 | bool uses_physical_attributes{}; // Shader uses AL2P or physical attribute read/writes | ||
| 869 | 878 | ||
| 870 | Tegra::Shader::Header header; | 879 | Tegra::Shader::Header header; |
| 871 | }; | 880 | }; |