diff options
| author | 2018-08-19 17:01:48 -0400 | |
|---|---|---|
| committer | 2018-08-19 17:01:48 -0400 | |
| commit | 51ddb130c59e2d574a478f43c254292cd63df6b1 (patch) | |
| tree | 0c9a6ea9a983186401f81c1d53b4a541143d17d4 /src | |
| parent | Merge pull request #1105 from Subv/convert_neg (diff) | |
| parent | Shaders: Corrected the 'abs' and 'neg' bit usage in the float arithmetic inst... (diff) | |
| download | yuzu-51ddb130c59e2d574a478f43c254292cd63df6b1.tar.gz yuzu-51ddb130c59e2d574a478f43c254292cd63df6b1.tar.xz yuzu-51ddb130c59e2d574a478f43c254292cd63df6b1.zip | |
Merge pull request #1089 from Subv/neg_bits
Shaders: Corrected the 'abs' and 'neg' bit usage in the float arithmetic instructions.
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 096de9632..9413a81fb 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -293,6 +293,10 @@ union Instruction { | |||
| 293 | } alu; | 293 | } alu; |
| 294 | 294 | ||
| 295 | union { | 295 | union { |
| 296 | BitField<48, 1, u64> negate_b; | ||
| 297 | } fmul; | ||
| 298 | |||
| 299 | union { | ||
| 296 | BitField<48, 1, u64> is_signed; | 300 | BitField<48, 1, u64> is_signed; |
| 297 | } shift; | 301 | } shift; |
| 298 | 302 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 44c6120b8..57cf9f213 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -747,6 +747,30 @@ private: | |||
| 747 | return op->second; | 747 | return op->second; |
| 748 | } | 748 | } |
| 749 | 749 | ||
| 750 | /** | ||
| 751 | * Transforms the input string GLSL operand into one that applies the abs() function and negates | ||
| 752 | * the output if necessary. When both abs and neg are true, the negation will be applied after | ||
| 753 | * taking the absolute value. | ||
| 754 | * @param operand The input operand to take the abs() of, negate, or both. | ||
| 755 | * @param abs Whether to apply the abs() function to the input operand. | ||
| 756 | * @param neg Whether to negate the input operand. | ||
| 757 | * @returns String corresponding to the operand after being transformed by the abs() and | ||
| 758 | * negation operations. | ||
| 759 | */ | ||
| 760 | static std::string GetOperandAbsNeg(const std::string& operand, bool abs, bool neg) { | ||
| 761 | std::string result = operand; | ||
| 762 | |||
| 763 | if (abs) { | ||
| 764 | result = "abs(" + result + ')'; | ||
| 765 | } | ||
| 766 | |||
| 767 | if (neg) { | ||
| 768 | result = "-(" + result + ')'; | ||
| 769 | } | ||
| 770 | |||
| 771 | return result; | ||
| 772 | } | ||
| 773 | |||
| 750 | /* | 774 | /* |
| 751 | * Returns whether the instruction at the specified offset is a 'sched' instruction. | 775 | * Returns whether the instruction at the specified offset is a 'sched' instruction. |
| 752 | * Sched instructions always appear before a sequence of 3 instructions. | 776 | * Sched instructions always appear before a sequence of 3 instructions. |
| @@ -913,13 +937,6 @@ private: | |||
| 913 | switch (opcode->GetType()) { | 937 | switch (opcode->GetType()) { |
| 914 | case OpCode::Type::Arithmetic: { | 938 | case OpCode::Type::Arithmetic: { |
| 915 | std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); | 939 | std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); |
| 916 | if (instr.alu.abs_a) { | ||
| 917 | op_a = "abs(" + op_a + ')'; | ||
| 918 | } | ||
| 919 | |||
| 920 | if (instr.alu.negate_a) { | ||
| 921 | op_a = "-(" + op_a + ')'; | ||
| 922 | } | ||
| 923 | 940 | ||
| 924 | std::string op_b; | 941 | std::string op_b; |
| 925 | 942 | ||
| @@ -934,17 +951,10 @@ private: | |||
| 934 | } | 951 | } |
| 935 | } | 952 | } |
| 936 | 953 | ||
| 937 | if (instr.alu.abs_b) { | ||
| 938 | op_b = "abs(" + op_b + ')'; | ||
| 939 | } | ||
| 940 | |||
| 941 | if (instr.alu.negate_b) { | ||
| 942 | op_b = "-(" + op_b + ')'; | ||
| 943 | } | ||
| 944 | |||
| 945 | switch (opcode->GetId()) { | 954 | switch (opcode->GetId()) { |
| 946 | case OpCode::Id::MOV_C: | 955 | case OpCode::Id::MOV_C: |
| 947 | case OpCode::Id::MOV_R: { | 956 | case OpCode::Id::MOV_R: { |
| 957 | // MOV does not have neither 'abs' nor 'neg' bits. | ||
| 948 | regs.SetRegisterToFloat(instr.gpr0, 0, op_b, 1, 1); | 958 | regs.SetRegisterToFloat(instr.gpr0, 0, op_b, 1, 1); |
| 949 | break; | 959 | break; |
| 950 | } | 960 | } |
| @@ -952,6 +962,8 @@ private: | |||
| 952 | case OpCode::Id::FMUL_C: | 962 | case OpCode::Id::FMUL_C: |
| 953 | case OpCode::Id::FMUL_R: | 963 | case OpCode::Id::FMUL_R: |
| 954 | case OpCode::Id::FMUL_IMM: { | 964 | case OpCode::Id::FMUL_IMM: { |
| 965 | // FMUL does not have 'abs' bits and only the second operand has a 'neg' bit. | ||
| 966 | op_b = GetOperandAbsNeg(op_b, false, instr.fmul.negate_b); | ||
| 955 | regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1, | 967 | regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1, |
| 956 | instr.alu.saturate_d); | 968 | instr.alu.saturate_d); |
| 957 | break; | 969 | break; |
| @@ -959,11 +971,14 @@ private: | |||
| 959 | case OpCode::Id::FADD_C: | 971 | case OpCode::Id::FADD_C: |
| 960 | case OpCode::Id::FADD_R: | 972 | case OpCode::Id::FADD_R: |
| 961 | case OpCode::Id::FADD_IMM: { | 973 | case OpCode::Id::FADD_IMM: { |
| 974 | op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a); | ||
| 975 | op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b); | ||
| 962 | regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, | 976 | regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, |
| 963 | instr.alu.saturate_d); | 977 | instr.alu.saturate_d); |
| 964 | break; | 978 | break; |
| 965 | } | 979 | } |
| 966 | case OpCode::Id::MUFU: { | 980 | case OpCode::Id::MUFU: { |
| 981 | op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a); | ||
| 967 | switch (instr.sub_op) { | 982 | switch (instr.sub_op) { |
| 968 | case SubOp::Cos: | 983 | case SubOp::Cos: |
| 969 | regs.SetRegisterToFloat(instr.gpr0, 0, "cos(" + op_a + ')', 1, 1, | 984 | regs.SetRegisterToFloat(instr.gpr0, 0, "cos(" + op_a + ')', 1, 1, |
| @@ -1003,6 +1018,9 @@ private: | |||
| 1003 | case OpCode::Id::FMNMX_C: | 1018 | case OpCode::Id::FMNMX_C: |
| 1004 | case OpCode::Id::FMNMX_R: | 1019 | case OpCode::Id::FMNMX_R: |
| 1005 | case OpCode::Id::FMNMX_IMM: { | 1020 | case OpCode::Id::FMNMX_IMM: { |
| 1021 | op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a); | ||
| 1022 | op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b); | ||
| 1023 | |||
| 1006 | std::string condition = | 1024 | std::string condition = |
| 1007 | GetPredicateCondition(instr.alu.fmnmx.pred, instr.alu.fmnmx.negate_pred != 0); | 1025 | GetPredicateCondition(instr.alu.fmnmx.pred, instr.alu.fmnmx.negate_pred != 0); |
| 1008 | std::string parameters = op_a + ',' + op_b; | 1026 | std::string parameters = op_a + ',' + op_b; |
| @@ -1016,7 +1034,7 @@ private: | |||
| 1016 | case OpCode::Id::RRO_R: | 1034 | case OpCode::Id::RRO_R: |
| 1017 | case OpCode::Id::RRO_IMM: { | 1035 | case OpCode::Id::RRO_IMM: { |
| 1018 | // Currently RRO is only implemented as a register move. | 1036 | // Currently RRO is only implemented as a register move. |
| 1019 | // Usage of `abs_b` and `negate_b` here should also be correct. | 1037 | op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b); |
| 1020 | regs.SetRegisterToFloat(instr.gpr0, 0, op_b, 1, 1); | 1038 | regs.SetRegisterToFloat(instr.gpr0, 0, op_b, 1, 1); |
| 1021 | LOG_WARNING(HW_GPU, "RRO instruction is incomplete"); | 1039 | LOG_WARNING(HW_GPU, "RRO instruction is incomplete"); |
| 1022 | break; | 1040 | break; |