diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/engines/shader_header.h | 55 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 34 | ||||
| -rw-r--r-- | src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | 17 | ||||
| -rw-r--r-- | src/video_core/shader/decode/other.cpp | 36 |
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 | ||
| 19 | enum class AttributeUse : u8 { | 22 | enum 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 |
| 28 | struct Header { | 31 | struct 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 | ||
| 32 | using Tegra::Engines::ShaderType; | 32 | using Tegra::Engines::ShaderType; |
| 33 | using Tegra::Shader::Attribute; | 33 | using Tegra::Shader::Attribute; |
| 34 | using Tegra::Shader::AttributeUse; | ||
| 35 | using Tegra::Shader::Header; | 34 | using Tegra::Shader::Header; |
| 36 | using Tegra::Shader::IpaInterpMode; | 35 | using Tegra::Shader::IpaInterpMode; |
| 37 | using Tegra::Shader::IpaMode; | 36 | using Tegra::Shader::IpaMode; |
| 38 | using Tegra::Shader::IpaSampleMode; | 37 | using Tegra::Shader::IpaSampleMode; |
| 38 | using Tegra::Shader::PixelImap; | ||
| 39 | using Tegra::Shader::Register; | 39 | using Tegra::Shader::Register; |
| 40 | using VideoCommon::Shader::BuildTransformFeedback; | 40 | using VideoCommon::Shader::BuildTransformFeedback; |
| 41 | using VideoCommon::Shader::Registry; | 41 | using 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 { | |||
| 35 | using Sirit::Id; | 35 | using Sirit::Id; |
| 36 | using Tegra::Engines::ShaderType; | 36 | using Tegra::Engines::ShaderType; |
| 37 | using Tegra::Shader::Attribute; | 37 | using Tegra::Shader::Attribute; |
| 38 | using Tegra::Shader::AttributeUse; | 38 | using Tegra::Shader::PixelImap; |
| 39 | using Tegra::Shader::Register; | 39 | using Tegra::Shader::Register; |
| 40 | using namespace VideoCommon::Shader; | 40 | using 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 | ||
| 12 | namespace VideoCommon::Shader { | 12 | namespace VideoCommon::Shader { |
| 13 | 13 | ||
| 14 | using std::move; | ||
| 14 | using Tegra::Shader::ConditionCode; | 15 | using Tegra::Shader::ConditionCode; |
| 15 | using Tegra::Shader::Instruction; | 16 | using Tegra::Shader::Instruction; |
| 17 | using Tegra::Shader::IpaInterpMode; | ||
| 16 | using Tegra::Shader::OpCode; | 18 | using Tegra::Shader::OpCode; |
| 19 | using Tegra::Shader::PixelImap; | ||
| 17 | using Tegra::Shader::Register; | 20 | using Tegra::Shader::Register; |
| 18 | using Tegra::Shader::SystemVariable; | 21 | using Tegra::Shader::SystemVariable; |
| 19 | 22 | ||
| 23 | using Index = Tegra::Shader::Attribute::Index; | ||
| 24 | |||
| 20 | u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { | 25 | u32 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: { |