diff options
| author | 2018-08-16 09:05:16 -0500 | |
|---|---|---|
| committer | 2018-08-18 10:22:42 -0500 | |
| commit | 2e95ba2e9c67d16456fb9f700cfe3da837e16a73 (patch) | |
| tree | 83c1c00e9a39179dd72db272c9d49bbe7cdfa5a9 /src | |
| parent | Merge pull request #1075 from lioncash/include (diff) | |
| download | yuzu-2e95ba2e9c67d16456fb9f700cfe3da837e16a73.tar.gz yuzu-2e95ba2e9c67d16456fb9f700cfe3da837e16a73.tar.xz yuzu-2e95ba2e9c67d16456fb9f700cfe3da837e16a73.zip | |
Shaders: Corrected the 'abs' and 'neg' bit usage in the float arithmetic instructions.
We should definitely audit our shader generator for more errors like this.
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/engines/shader_bytecode.h | 4 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 50 |
2 files changed, 38 insertions, 16 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 2526ebf28..f438fa809 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -283,6 +283,10 @@ union Instruction { | |||
| 283 | } alu; | 283 | } alu; |
| 284 | 284 | ||
| 285 | union { | 285 | union { |
| 286 | BitField<48, 1, u64> negate_b; | ||
| 287 | } fmul; | ||
| 288 | |||
| 289 | union { | ||
| 286 | BitField<48, 1, u64> is_signed; | 290 | BitField<48, 1, u64> is_signed; |
| 287 | } shift; | 291 | } shift; |
| 288 | 292 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index e0dfdbb9f..e899237e5 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -741,6 +741,30 @@ private: | |||
| 741 | return op->second; | 741 | return op->second; |
| 742 | } | 742 | } |
| 743 | 743 | ||
| 744 | /** | ||
| 745 | * Transforms the input string GLSL operand into one that applies the abs() function and negates | ||
| 746 | * the output if necessary. When both abs and neg are true, the negation will be applied after | ||
| 747 | * taking the absolute value. | ||
| 748 | * @param operand The input operand to take the abs() of, negate, or both. | ||
| 749 | * @param abs Whether to apply the abs() function to the input operand. | ||
| 750 | * @param neg Whether to negate the input operand. | ||
| 751 | * @returns String corresponding to the operand after being transformed by the abs() and | ||
| 752 | * negation operations. | ||
| 753 | */ | ||
| 754 | static std::string GetOperandAbsNeg(const std::string& operand, bool abs, bool neg) { | ||
| 755 | std::string result = operand; | ||
| 756 | |||
| 757 | if (abs) { | ||
| 758 | result = "abs(" + result + ')'; | ||
| 759 | } | ||
| 760 | |||
| 761 | if (neg) { | ||
| 762 | result = "-(" + result + ')'; | ||
| 763 | } | ||
| 764 | |||
| 765 | return result; | ||
| 766 | } | ||
| 767 | |||
| 744 | /* | 768 | /* |
| 745 | * Returns whether the instruction at the specified offset is a 'sched' instruction. | 769 | * Returns whether the instruction at the specified offset is a 'sched' instruction. |
| 746 | * Sched instructions always appear before a sequence of 3 instructions. | 770 | * Sched instructions always appear before a sequence of 3 instructions. |
| @@ -857,13 +881,6 @@ private: | |||
| 857 | switch (opcode->GetType()) { | 881 | switch (opcode->GetType()) { |
| 858 | case OpCode::Type::Arithmetic: { | 882 | case OpCode::Type::Arithmetic: { |
| 859 | std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); | 883 | std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); |
| 860 | if (instr.alu.abs_a) { | ||
| 861 | op_a = "abs(" + op_a + ')'; | ||
| 862 | } | ||
| 863 | |||
| 864 | if (instr.alu.negate_a) { | ||
| 865 | op_a = "-(" + op_a + ')'; | ||
| 866 | } | ||
| 867 | 884 | ||
| 868 | std::string op_b; | 885 | std::string op_b; |
| 869 | 886 | ||
| @@ -878,17 +895,10 @@ private: | |||
| 878 | } | 895 | } |
| 879 | } | 896 | } |
| 880 | 897 | ||
| 881 | if (instr.alu.abs_b) { | ||
| 882 | op_b = "abs(" + op_b + ')'; | ||
| 883 | } | ||
| 884 | |||
| 885 | if (instr.alu.negate_b) { | ||
| 886 | op_b = "-(" + op_b + ')'; | ||
| 887 | } | ||
| 888 | |||
| 889 | switch (opcode->GetId()) { | 898 | switch (opcode->GetId()) { |
| 890 | case OpCode::Id::MOV_C: | 899 | case OpCode::Id::MOV_C: |
| 891 | case OpCode::Id::MOV_R: { | 900 | case OpCode::Id::MOV_R: { |
| 901 | // MOV does not have neither 'abs' nor 'neg' bits. | ||
| 892 | regs.SetRegisterToFloat(instr.gpr0, 0, op_b, 1, 1); | 902 | regs.SetRegisterToFloat(instr.gpr0, 0, op_b, 1, 1); |
| 893 | break; | 903 | break; |
| 894 | } | 904 | } |
| @@ -896,6 +906,8 @@ private: | |||
| 896 | case OpCode::Id::FMUL_C: | 906 | case OpCode::Id::FMUL_C: |
| 897 | case OpCode::Id::FMUL_R: | 907 | case OpCode::Id::FMUL_R: |
| 898 | case OpCode::Id::FMUL_IMM: { | 908 | case OpCode::Id::FMUL_IMM: { |
| 909 | // FMUL does not have 'abs' bits and only the second operand has a 'neg' bit. | ||
| 910 | op_b = GetOperandAbsNeg(op_b, false, instr.fmul.negate_b); | ||
| 899 | regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1, | 911 | regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1, |
| 900 | instr.alu.saturate_d); | 912 | instr.alu.saturate_d); |
| 901 | break; | 913 | break; |
| @@ -903,11 +915,14 @@ private: | |||
| 903 | case OpCode::Id::FADD_C: | 915 | case OpCode::Id::FADD_C: |
| 904 | case OpCode::Id::FADD_R: | 916 | case OpCode::Id::FADD_R: |
| 905 | case OpCode::Id::FADD_IMM: { | 917 | case OpCode::Id::FADD_IMM: { |
| 918 | op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a); | ||
| 919 | op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b); | ||
| 906 | regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, | 920 | regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, |
| 907 | instr.alu.saturate_d); | 921 | instr.alu.saturate_d); |
| 908 | break; | 922 | break; |
| 909 | } | 923 | } |
| 910 | case OpCode::Id::MUFU: { | 924 | case OpCode::Id::MUFU: { |
| 925 | op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a); | ||
| 911 | switch (instr.sub_op) { | 926 | switch (instr.sub_op) { |
| 912 | case SubOp::Cos: | 927 | case SubOp::Cos: |
| 913 | regs.SetRegisterToFloat(instr.gpr0, 0, "cos(" + op_a + ')', 1, 1, | 928 | regs.SetRegisterToFloat(instr.gpr0, 0, "cos(" + op_a + ')', 1, 1, |
| @@ -947,6 +962,9 @@ private: | |||
| 947 | case OpCode::Id::FMNMX_C: | 962 | case OpCode::Id::FMNMX_C: |
| 948 | case OpCode::Id::FMNMX_R: | 963 | case OpCode::Id::FMNMX_R: |
| 949 | case OpCode::Id::FMNMX_IMM: { | 964 | case OpCode::Id::FMNMX_IMM: { |
| 965 | op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a); | ||
| 966 | op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b); | ||
| 967 | |||
| 950 | std::string condition = | 968 | std::string condition = |
| 951 | GetPredicateCondition(instr.alu.fmnmx.pred, instr.alu.fmnmx.negate_pred != 0); | 969 | GetPredicateCondition(instr.alu.fmnmx.pred, instr.alu.fmnmx.negate_pred != 0); |
| 952 | std::string parameters = op_a + ',' + op_b; | 970 | std::string parameters = op_a + ',' + op_b; |
| @@ -960,7 +978,7 @@ private: | |||
| 960 | case OpCode::Id::RRO_R: | 978 | case OpCode::Id::RRO_R: |
| 961 | case OpCode::Id::RRO_IMM: { | 979 | case OpCode::Id::RRO_IMM: { |
| 962 | // Currently RRO is only implemented as a register move. | 980 | // Currently RRO is only implemented as a register move. |
| 963 | // Usage of `abs_b` and `negate_b` here should also be correct. | 981 | op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b); |
| 964 | regs.SetRegisterToFloat(instr.gpr0, 0, op_b, 1, 1); | 982 | regs.SetRegisterToFloat(instr.gpr0, 0, op_b, 1, 1); |
| 965 | LOG_WARNING(HW_GPU, "RRO instruction is incomplete"); | 983 | LOG_WARNING(HW_GPU, "RRO instruction is incomplete"); |
| 966 | break; | 984 | break; |