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
This commit is contained in:
parent
baf91c920c
commit
2339fe199f
4 changed files with 74 additions and 68 deletions
|
@ -11,12 +11,17 @@
|
|||
|
||||
namespace VideoCommon::Shader {
|
||||
|
||||
using std::move;
|
||||
using Tegra::Shader::ConditionCode;
|
||||
using Tegra::Shader::Instruction;
|
||||
using Tegra::Shader::IpaInterpMode;
|
||||
using Tegra::Shader::OpCode;
|
||||
using Tegra::Shader::PixelImap;
|
||||
using Tegra::Shader::Register;
|
||||
using Tegra::Shader::SystemVariable;
|
||||
|
||||
using Index = Tegra::Shader::Attribute::Index;
|
||||
|
||||
u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
|
||||
const Instruction instr = {program_code[pc]};
|
||||
const auto opcode = OpCode::Decode(instr);
|
||||
|
@ -213,27 +218,28 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
|
|||
}
|
||||
case OpCode::Id::IPA: {
|
||||
const bool is_physical = instr.ipa.idx && instr.gpr8.Value() != 0xff;
|
||||
|
||||
const auto attribute = instr.attribute.fmt28;
|
||||
const Tegra::Shader::IpaMode input_mode{instr.ipa.interp_mode.Value(),
|
||||
instr.ipa.sample_mode.Value()};
|
||||
const Index index = attribute.index;
|
||||
|
||||
Node value = is_physical ? GetPhysicalInputAttribute(instr.gpr8)
|
||||
: GetInputAttribute(attribute.index, attribute.element);
|
||||
const Tegra::Shader::Attribute::Index index = attribute.index.Value();
|
||||
const bool is_generic = index >= Tegra::Shader::Attribute::Index::Attribute_0 &&
|
||||
index <= Tegra::Shader::Attribute::Index::Attribute_31;
|
||||
if (is_generic || is_physical) {
|
||||
// TODO(Blinkhawk): There are cases where a perspective attribute use PASS.
|
||||
// In theory by setting them as perspective, OpenGL does the perspective correction.
|
||||
// A way must figured to reverse the last step of it.
|
||||
if (input_mode.interpolation_mode == Tegra::Shader::IpaInterpMode::Multiply) {
|
||||
value = Operation(OperationCode::FMul, PRECISE, value, GetRegister(instr.gpr20));
|
||||
: GetInputAttribute(index, attribute.element);
|
||||
|
||||
// Code taken from Ryujinx.
|
||||
if (index >= Index::Attribute_0 && index <= Index::Attribute_31) {
|
||||
const u32 location = static_cast<u32>(index) - static_cast<u32>(Index::Attribute_0);
|
||||
if (header.ps.GetPixelImap(location) == PixelImap::Perspective) {
|
||||
Node position_w = GetInputAttribute(Index::Position, 3);
|
||||
value = Operation(OperationCode::FMul, move(value), move(position_w));
|
||||
}
|
||||
}
|
||||
value = GetSaturatedFloat(value, instr.ipa.saturate);
|
||||
|
||||
SetRegister(bb, instr.gpr0, value);
|
||||
if (instr.ipa.interp_mode == IpaInterpMode::Multiply) {
|
||||
value = Operation(OperationCode::FMul, move(value), GetRegister(instr.gpr20));
|
||||
}
|
||||
|
||||
value = GetSaturatedFloat(move(value), instr.ipa.saturate);
|
||||
|
||||
SetRegister(bb, instr.gpr0, move(value));
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::OUT_R: {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue