diff options
| author | 2020-04-01 21:37:32 -0300 | |
|---|---|---|
| committer | 2020-04-01 21:48:55 -0300 | |
| commit | 2339fe199f3b08faa33b15048aa7158a2e0eff00 (patch) | |
| tree | 28e28e8c22dfb27609f1926ea538a64dd4a6463f /src/video_core/shader | |
| parent | Merge pull request #3591 from ReinUsesLisp/vk-wrapper-part2 (diff) | |
| download | yuzu-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/video_core/shader')
| -rw-r--r-- | src/video_core/shader/decode/other.cpp | 36 |
1 files changed, 21 insertions, 15 deletions
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: { |