summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar ReinUsesLisp2020-04-01 21:37:32 -0300
committerGravatar ReinUsesLisp2020-04-01 21:48:55 -0300
commit2339fe199f3b08faa33b15048aa7158a2e0eff00 (patch)
tree28e28e8c22dfb27609f1926ea538a64dd4a6463f /src
parentMerge pull request #3591 from ReinUsesLisp/vk-wrapper-part2 (diff)
downloadyuzu-2339fe199f3b08faa33b15048aa7158a2e0eff00.tar.gz
yuzu-2339fe199f3b08faa33b15048aa7158a2e0eff00.tar.xz
yuzu-2339fe199f3b08faa33b15048aa7158a2e0eff00.zip
shader_decompiler: Remove FragCoord.w hack and change IPA implementation
Credits go to gdkchan and Ryujinx. The pull request used for this can be found here: https://github.com/Ryujinx/Ryujinx/pull/1082 yuzu was already using the header for interpolation, but it was missing the FragCoord.w multiplication described in the linked pull request. This commit finally removes the FragCoord.w == 1.0f hack from the shader decompiler. While we are at it, this commit renames some enumerations to match Nvidia's documentation (linked below) and fixes component declaration order in the shader program header (z and w were swapped). https://github.com/NVIDIA/open-gpu-doc/blob/master/Shader-Program-Header/Shader-Program-Header.html
Diffstat (limited to 'src')
-rw-r--r--src/video_core/engines/shader_header.h55
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp34
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp17
-rw-r--r--src/video_core/shader/decode/other.cpp36
4 files changed, 74 insertions, 68 deletions
diff --git a/src/video_core/engines/shader_header.h b/src/video_core/engines/shader_header.h
index bc80661d8..72e2a33d5 100644
--- a/src/video_core/engines/shader_header.h
+++ b/src/video_core/engines/shader_header.h
@@ -4,6 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
8#include <optional>
9
7#include "common/bit_field.h" 10#include "common/bit_field.h"
8#include "common/common_funcs.h" 11#include "common/common_funcs.h"
9#include "common/common_types.h" 12#include "common/common_types.h"
@@ -16,7 +19,7 @@ enum class OutputTopology : u32 {
16 TriangleStrip = 7, 19 TriangleStrip = 7,
17}; 20};
18 21
19enum class AttributeUse : u8 { 22enum class PixelImap : u8 {
20 Unused = 0, 23 Unused = 0,
21 Constant = 1, 24 Constant = 1,
22 Perspective = 2, 25 Perspective = 2,
@@ -24,7 +27,7 @@ enum class AttributeUse : u8 {
24}; 27};
25 28
26// Documentation in: 29// Documentation in:
27// http://download.nvidia.com/open-gpu-doc/Shader-Program-Header/1/Shader-Program-Header.html#ImapTexture 30// http://download.nvidia.com/open-gpu-doc/Shader-Program-Header/1/Shader-Program-Header.html
28struct Header { 31struct Header {
29 union { 32 union {
30 BitField<0, 5, u32> sph_type; 33 BitField<0, 5, u32> sph_type;
@@ -59,8 +62,8 @@ struct Header {
59 union { 62 union {
60 BitField<0, 12, u32> max_output_vertices; 63 BitField<0, 12, u32> max_output_vertices;
61 BitField<12, 8, u32> store_req_start; // NOTE: not used by geometry shaders. 64 BitField<12, 8, u32> store_req_start; // NOTE: not used by geometry shaders.
62 BitField<24, 4, u32> reserved; 65 BitField<20, 4, u32> reserved;
63 BitField<12, 8, u32> store_req_end; // NOTE: not used by geometry shaders. 66 BitField<24, 8, u32> store_req_end; // NOTE: not used by geometry shaders.
64 } common4{}; 67 } common4{};
65 68
66 union { 69 union {
@@ -93,17 +96,20 @@ struct Header {
93 struct { 96 struct {
94 INSERT_UNION_PADDING_BYTES(3); // ImapSystemValuesA 97 INSERT_UNION_PADDING_BYTES(3); // ImapSystemValuesA
95 INSERT_UNION_PADDING_BYTES(1); // ImapSystemValuesB 98 INSERT_UNION_PADDING_BYTES(1); // ImapSystemValuesB
99
96 union { 100 union {
97 BitField<0, 2, AttributeUse> x; 101 BitField<0, 2, PixelImap> x;
98 BitField<2, 2, AttributeUse> y; 102 BitField<2, 2, PixelImap> y;
99 BitField<4, 2, AttributeUse> w; 103 BitField<4, 2, PixelImap> z;
100 BitField<6, 2, AttributeUse> z; 104 BitField<6, 2, PixelImap> w;
101 u8 raw; 105 u8 raw;
102 } imap_generic_vector[32]; 106 } imap_generic_vector[32];
107
103 INSERT_UNION_PADDING_BYTES(2); // ImapColor 108 INSERT_UNION_PADDING_BYTES(2); // ImapColor
104 INSERT_UNION_PADDING_BYTES(2); // ImapSystemValuesC 109 INSERT_UNION_PADDING_BYTES(2); // ImapSystemValuesC
105 INSERT_UNION_PADDING_BYTES(10); // ImapFixedFncTexture[10] 110 INSERT_UNION_PADDING_BYTES(10); // ImapFixedFncTexture[10]
106 INSERT_UNION_PADDING_BYTES(2); // ImapReserved 111 INSERT_UNION_PADDING_BYTES(2); // ImapReserved
112
107 struct { 113 struct {
108 u32 target; 114 u32 target;
109 union { 115 union {
@@ -112,31 +118,30 @@ struct Header {
112 BitField<2, 30, u32> reserved; 118 BitField<2, 30, u32> reserved;
113 }; 119 };
114 } omap; 120 } omap;
121
115 bool IsColorComponentOutputEnabled(u32 render_target, u32 component) const { 122 bool IsColorComponentOutputEnabled(u32 render_target, u32 component) const {
116 const u32 bit = render_target * 4 + component; 123 const u32 bit = render_target * 4 + component;
117 return omap.target & (1 << bit); 124 return omap.target & (1 << bit);
118 } 125 }
119 AttributeUse GetAttributeIndexUse(u32 attribute, u32 index) const { 126
120 return static_cast<AttributeUse>( 127 PixelImap GetPixelImap(u32 attribute) const {
121 (imap_generic_vector[attribute].raw >> (index * 2)) & 0x03); 128 const auto get_index = [this, attribute](u32 index) {
122 } 129 return static_cast<PixelImap>(
123 AttributeUse GetAttributeUse(u32 attribute) const { 130 (imap_generic_vector[attribute].raw >> (index * 2)) & 3);
124 AttributeUse result = AttributeUse::Unused; 131 };
125 for (u32 i = 0; i < 4; i++) { 132
126 const auto index = GetAttributeIndexUse(attribute, i); 133 std::optional<PixelImap> result;
127 if (index == AttributeUse::Unused) { 134 for (u32 component = 0; component < 4; ++component) {
128 continue; 135 const PixelImap index = get_index(component);
129 } 136 if (index == PixelImap::Unused) {
130 if (result == AttributeUse::Unused || result == index) {
131 result = index;
132 continue; 137 continue;
133 } 138 }
134 LOG_CRITICAL(HW_GPU, "Generic Attribute Conflict in Interpolation Mode"); 139 if (result && result != index) {
135 if (index == AttributeUse::Perspective) { 140 LOG_CRITICAL(HW_GPU, "Generic attribute conflict in interpolation mode");
136 result = index;
137 } 141 }
142 result = index;
138 } 143 }
139 return result; 144 return result.value_or(PixelImap::Unused);
140 } 145 }
141 } ps; 146 } ps;
142 147
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index c7d24cf14..160ae4340 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -31,11 +31,11 @@ namespace {
31 31
32using Tegra::Engines::ShaderType; 32using Tegra::Engines::ShaderType;
33using Tegra::Shader::Attribute; 33using Tegra::Shader::Attribute;
34using Tegra::Shader::AttributeUse;
35using Tegra::Shader::Header; 34using Tegra::Shader::Header;
36using Tegra::Shader::IpaInterpMode; 35using Tegra::Shader::IpaInterpMode;
37using Tegra::Shader::IpaMode; 36using Tegra::Shader::IpaMode;
38using Tegra::Shader::IpaSampleMode; 37using Tegra::Shader::IpaSampleMode;
38using Tegra::Shader::PixelImap;
39using Tegra::Shader::Register; 39using Tegra::Shader::Register;
40using VideoCommon::Shader::BuildTransformFeedback; 40using VideoCommon::Shader::BuildTransformFeedback;
41using VideoCommon::Shader::Registry; 41using VideoCommon::Shader::Registry;
@@ -702,20 +702,19 @@ private:
702 code.AddNewLine(); 702 code.AddNewLine();
703 } 703 }
704 704
705 std::string GetInputFlags(AttributeUse attribute) { 705 const char* GetInputFlags(PixelImap attribute) {
706 switch (attribute) { 706 switch (attribute) {
707 case AttributeUse::Perspective: 707 case PixelImap::Perspective:
708 // Default, Smooth 708 return "smooth";
709 return {}; 709 case PixelImap::Constant:
710 case AttributeUse::Constant: 710 return "flat";
711 return "flat "; 711 case PixelImap::ScreenLinear:
712 case AttributeUse::ScreenLinear: 712 return "noperspective";
713 return "noperspective "; 713 case PixelImap::Unused:
714 default: 714 break;
715 case AttributeUse::Unused:
716 UNIMPLEMENTED_MSG("Unknown attribute usage index={}", static_cast<u32>(attribute));
717 return {};
718 } 715 }
716 UNIMPLEMENTED_MSG("Unknown attribute usage index={}", static_cast<int>(attribute));
717 return {};
719 } 718 }
720 719
721 void DeclareInputAttributes() { 720 void DeclareInputAttributes() {
@@ -749,8 +748,8 @@ private:
749 748
750 std::string suffix; 749 std::string suffix;
751 if (stage == ShaderType::Fragment) { 750 if (stage == ShaderType::Fragment) {
752 const auto input_mode{header.ps.GetAttributeUse(location)}; 751 const auto input_mode{header.ps.GetPixelImap(location)};
753 if (skip_unused && input_mode == AttributeUse::Unused) { 752 if (input_mode == PixelImap::Unused) {
754 return; 753 return;
755 } 754 }
756 suffix = GetInputFlags(input_mode); 755 suffix = GetInputFlags(input_mode);
@@ -927,7 +926,7 @@ private:
927 const u32 address{generic_base + index * generic_stride + element * element_stride}; 926 const u32 address{generic_base + index * generic_stride + element * element_stride};
928 927
929 const bool declared = stage != ShaderType::Fragment || 928 const bool declared = stage != ShaderType::Fragment ||
930 header.ps.GetAttributeUse(index) != AttributeUse::Unused; 929 header.ps.GetPixelImap(index) != PixelImap::Unused;
931 const std::string value = 930 const std::string value =
932 declared ? ReadAttribute(attribute, element).AsFloat() : "0.0f"; 931 declared ? ReadAttribute(attribute, element).AsFloat() : "0.0f";
933 code.AddLine("case 0x{:X}U: return {};", address, value); 932 code.AddLine("case 0x{:X}U: return {};", address, value);
@@ -1142,8 +1141,7 @@ private:
1142 GetSwizzle(element)), 1141 GetSwizzle(element)),
1143 Type::Float}; 1142 Type::Float};
1144 case ShaderType::Fragment: 1143 case ShaderType::Fragment:
1145 return {element == 3 ? "1.0f" : ("gl_FragCoord"s + GetSwizzle(element)), 1144 return {"gl_FragCoord"s + GetSwizzle(element), Type::Float};
1146 Type::Float};
1147 default: 1145 default:
1148 UNREACHABLE(); 1146 UNREACHABLE();
1149 } 1147 }
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
index d67f08cf9..b9f9e2714 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -35,7 +35,7 @@ namespace {
35using Sirit::Id; 35using Sirit::Id;
36using Tegra::Engines::ShaderType; 36using Tegra::Engines::ShaderType;
37using Tegra::Shader::Attribute; 37using Tegra::Shader::Attribute;
38using Tegra::Shader::AttributeUse; 38using Tegra::Shader::PixelImap;
39using Tegra::Shader::Register; 39using Tegra::Shader::Register;
40using namespace VideoCommon::Shader; 40using namespace VideoCommon::Shader;
41 41
@@ -752,16 +752,16 @@ private:
752 if (stage != ShaderType::Fragment) { 752 if (stage != ShaderType::Fragment) {
753 continue; 753 continue;
754 } 754 }
755 switch (header.ps.GetAttributeUse(location)) { 755 switch (header.ps.GetPixelImap(location)) {
756 case AttributeUse::Constant: 756 case PixelImap::Constant:
757 Decorate(id, spv::Decoration::Flat); 757 Decorate(id, spv::Decoration::Flat);
758 break; 758 break;
759 case AttributeUse::ScreenLinear: 759 case PixelImap::Perspective:
760 Decorate(id, spv::Decoration::NoPerspective);
761 break;
762 case AttributeUse::Perspective:
763 // Default 760 // Default
764 break; 761 break;
762 case PixelImap::ScreenLinear:
763 Decorate(id, spv::Decoration::NoPerspective);
764 break;
765 default: 765 default:
766 UNREACHABLE_MSG("Unused attribute being fetched"); 766 UNREACHABLE_MSG("Unused attribute being fetched");
767 } 767 }
@@ -1145,9 +1145,6 @@ private:
1145 switch (attribute) { 1145 switch (attribute) {
1146 case Attribute::Index::Position: { 1146 case Attribute::Index::Position: {
1147 if (stage == ShaderType::Fragment) { 1147 if (stage == ShaderType::Fragment) {
1148 if (element == 3) {
1149 return {Constant(t_float, 1.0f), Type::Float};
1150 }
1151 return {OpLoad(t_float, AccessElement(t_in_float, frag_coord, element)), 1148 return {OpLoad(t_float, AccessElement(t_in_float, frag_coord, element)),
1152 Type::Float}; 1149 Type::Float};
1153 } 1150 }
diff --git a/src/video_core/shader/decode/other.cpp b/src/video_core/shader/decode/other.cpp
index 4944e9d69..e6edec459 100644
--- a/src/video_core/shader/decode/other.cpp
+++ b/src/video_core/shader/decode/other.cpp
@@ -11,12 +11,17 @@
11 11
12namespace VideoCommon::Shader { 12namespace VideoCommon::Shader {
13 13
14using std::move;
14using Tegra::Shader::ConditionCode; 15using Tegra::Shader::ConditionCode;
15using Tegra::Shader::Instruction; 16using Tegra::Shader::Instruction;
17using Tegra::Shader::IpaInterpMode;
16using Tegra::Shader::OpCode; 18using Tegra::Shader::OpCode;
19using Tegra::Shader::PixelImap;
17using Tegra::Shader::Register; 20using Tegra::Shader::Register;
18using Tegra::Shader::SystemVariable; 21using Tegra::Shader::SystemVariable;
19 22
23using Index = Tegra::Shader::Attribute::Index;
24
20u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { 25u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
21 const Instruction instr = {program_code[pc]}; 26 const Instruction instr = {program_code[pc]};
22 const auto opcode = OpCode::Decode(instr); 27 const auto opcode = OpCode::Decode(instr);
@@ -213,27 +218,28 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
213 } 218 }
214 case OpCode::Id::IPA: { 219 case OpCode::Id::IPA: {
215 const bool is_physical = instr.ipa.idx && instr.gpr8.Value() != 0xff; 220 const bool is_physical = instr.ipa.idx && instr.gpr8.Value() != 0xff;
216
217 const auto attribute = instr.attribute.fmt28; 221 const auto attribute = instr.attribute.fmt28;
218 const Tegra::Shader::IpaMode input_mode{instr.ipa.interp_mode.Value(), 222 const Index index = attribute.index;
219 instr.ipa.sample_mode.Value()};
220 223
221 Node value = is_physical ? GetPhysicalInputAttribute(instr.gpr8) 224 Node value = is_physical ? GetPhysicalInputAttribute(instr.gpr8)
222 : GetInputAttribute(attribute.index, attribute.element); 225 : GetInputAttribute(index, attribute.element);
223 const Tegra::Shader::Attribute::Index index = attribute.index.Value(); 226
224 const bool is_generic = index >= Tegra::Shader::Attribute::Index::Attribute_0 && 227 // Code taken from Ryujinx.
225 index <= Tegra::Shader::Attribute::Index::Attribute_31; 228 if (index >= Index::Attribute_0 && index <= Index::Attribute_31) {
226 if (is_generic || is_physical) { 229 const u32 location = static_cast<u32>(index) - static_cast<u32>(Index::Attribute_0);
227 // TODO(Blinkhawk): There are cases where a perspective attribute use PASS. 230 if (header.ps.GetPixelImap(location) == PixelImap::Perspective) {
228 // In theory by setting them as perspective, OpenGL does the perspective correction. 231 Node position_w = GetInputAttribute(Index::Position, 3);
229 // A way must figured to reverse the last step of it. 232 value = Operation(OperationCode::FMul, move(value), move(position_w));
230 if (input_mode.interpolation_mode == Tegra::Shader::IpaInterpMode::Multiply) {
231 value = Operation(OperationCode::FMul, PRECISE, value, GetRegister(instr.gpr20));
232 } 233 }
233 } 234 }
234 value = GetSaturatedFloat(value, instr.ipa.saturate);
235 235
236 SetRegister(bb, instr.gpr0, value); 236 if (instr.ipa.interp_mode == IpaInterpMode::Multiply) {
237 value = Operation(OperationCode::FMul, move(value), GetRegister(instr.gpr20));
238 }
239
240 value = GetSaturatedFloat(move(value), instr.ipa.saturate);
241
242 SetRegister(bb, instr.gpr0, move(value));
237 break; 243 break;
238 } 244 }
239 case OpCode::Id::OUT_R: { 245 case OpCode::Id::OUT_R: {