summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2019-05-19 14:02:58 -0400
committerGravatar GitHub2019-05-19 14:02:58 -0400
commitd49efbfb4aa4e935f6c753871d6af6534701f542 (patch)
tree79608391a32719a0be20c898fc79aba93f9f1d48 /src
parentMerge pull request #2410 from lioncash/affinity (diff)
parentshader_ir/other: Implement IPA.IDX (diff)
downloadyuzu-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.h1
-rw-r--r--src/video_core/engines/shader_bytecode.h22
-rw-r--r--src/video_core/renderer_opengl/gl_device.cpp9
-rw-r--r--src/video_core/renderer_opengl/gl_device.h14
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp313
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp7
-rw-r--r--src/video_core/shader/decode/memory.cpp30
-rw-r--r--src/video_core/shader/decode/other.cpp13
-rw-r--r--src/video_core/shader/shader_ir.cpp13
-rw-r--r--src/video_core/shader/shader_ir.h45
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
506enum class PhysicalAttributeDirection : u64 {
507 Input = 0,
508 Output = 1,
509};
510
502union Instruction { 511union 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
22Device::Device() { 22Device::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
29Device::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
27bool Device::TestVariableAoffi() { 36bool Device::TestVariableAoffi() {
28 const GLchar* AOFFI_TEST = R"(#version 430 core 37 const GLchar* AOFFI_TEST = R"(#version 430 core
29uniform sampler2D tex; 38uniform 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
9namespace OpenGL { 10namespace OpenGL {
10 11
11class Device { 12class Device {
12public: 13public:
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
137constexpr bool IsGenericAttribute(Attribute::Index index) {
138 return index >= Attribute::Index::Attribute_0 && index <= Attribute::Index::Attribute_31;
139}
140
141constexpr Attribute::Index ToGenericAttribute(u32 value) {
142 return static_cast<Attribute::Index>(value + static_cast<u32>(Attribute::Index::Attribute_0));
143}
144
145u32 GetGenericAttributeIndex(Attribute::Index index) {
146 ASSERT(IsGenericAttribute(index));
147 return static_cast<u32>(index) - static_cast<u32>(Attribute::Index::Attribute_0);
148}
149
137class GLSLDecompiler final { 150class GLSLDecompiler final {
138public: 151public:
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
15namespace VideoCommon::Shader { 17namespace VideoCommon::Shader {
16 18
17using Tegra::Shader::Attribute; 19using 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
99Node ShaderIR::GetInputAttribute(Attribute::Index index, u64 element, 99Node 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)); 104Node 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
108Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buffer) { 109Node 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)
457class AbufNode final { 457class AbufNode final {
458public: 458public:
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
483private: 488private:
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};