diff options
| author | 2018-06-17 17:44:38 -0400 | |
|---|---|---|
| committer | 2018-06-17 17:44:38 -0400 | |
| commit | f9af74201c1c210f48eb03a1aaaccef766ba998f (patch) | |
| tree | 196b3267a4521b1bd0fb103e6e20854705499b35 /src/video_core | |
| parent | Merge pull request #565 from bunnei/shader_conversions (diff) | |
| parent | gl_shader_decompiler: Implement LOP instructions. (diff) | |
| download | yuzu-f9af74201c1c210f48eb03a1aaaccef766ba998f.tar.gz yuzu-f9af74201c1c210f48eb03a1aaaccef766ba998f.tar.xz yuzu-f9af74201c1c210f48eb03a1aaaccef766ba998f.zip | |
Merge pull request #568 from bunnei/lop
gl_shader_decompiler: Implement LOP instructions.
Diffstat (limited to 'src/video_core')
| -rw-r--r-- | src/video_core/engines/shader_bytecode.h | 19 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 128 |
2 files changed, 84 insertions, 63 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index ceef8087c..cefd57f4c 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -230,10 +230,18 @@ union Instruction { | |||
| 230 | } fmnmx; | 230 | } fmnmx; |
| 231 | 231 | ||
| 232 | union { | 232 | union { |
| 233 | BitField<39, 1, u64> invert_a; | ||
| 234 | BitField<40, 1, u64> invert_b; | ||
| 235 | BitField<41, 2, LogicOperation> operation; | ||
| 236 | BitField<44, 2, u64> unk44; | ||
| 237 | BitField<48, 3, Pred> pred48; | ||
| 238 | } lop; | ||
| 239 | |||
| 240 | union { | ||
| 233 | BitField<53, 2, LogicOperation> operation; | 241 | BitField<53, 2, LogicOperation> operation; |
| 234 | BitField<55, 1, u64> invert_a; | 242 | BitField<55, 1, u64> invert_a; |
| 235 | BitField<56, 1, u64> invert_b; | 243 | BitField<56, 1, u64> invert_b; |
| 236 | } lop; | 244 | } lop32i; |
| 237 | 245 | ||
| 238 | float GetImm20_19() const { | 246 | float GetImm20_19() const { |
| 239 | float result{}; | 247 | float result{}; |
| @@ -476,6 +484,9 @@ public: | |||
| 476 | I2I_C, | 484 | I2I_C, |
| 477 | I2I_R, | 485 | I2I_R, |
| 478 | I2I_IMM, | 486 | I2I_IMM, |
| 487 | LOP_C, | ||
| 488 | LOP_R, | ||
| 489 | LOP_IMM, | ||
| 479 | LOP32I, | 490 | LOP32I, |
| 480 | MOV_C, | 491 | MOV_C, |
| 481 | MOV_R, | 492 | MOV_R, |
| @@ -518,7 +529,6 @@ public: | |||
| 518 | ArithmeticInteger, | 529 | ArithmeticInteger, |
| 519 | ArithmeticIntegerImmediate, | 530 | ArithmeticIntegerImmediate, |
| 520 | Bfe, | 531 | Bfe, |
| 521 | Logic, | ||
| 522 | Shift, | 532 | Shift, |
| 523 | Ffma, | 533 | Ffma, |
| 524 | Flow, | 534 | Flow, |
| @@ -676,7 +686,10 @@ private: | |||
| 676 | INST("0100110000000---", Id::BFE_C, Type::Bfe, "BFE_C"), | 686 | INST("0100110000000---", Id::BFE_C, Type::Bfe, "BFE_C"), |
| 677 | INST("0101110000000---", Id::BFE_R, Type::Bfe, "BFE_R"), | 687 | INST("0101110000000---", Id::BFE_R, Type::Bfe, "BFE_R"), |
| 678 | INST("0011100-00000---", Id::BFE_IMM, Type::Bfe, "BFE_IMM"), | 688 | INST("0011100-00000---", Id::BFE_IMM, Type::Bfe, "BFE_IMM"), |
| 679 | INST("000001----------", Id::LOP32I, Type::Logic, "LOP32I"), | 689 | INST("0100110001000---", Id::LOP_C, Type::ArithmeticInteger, "LOP_C"), |
| 690 | INST("0101110001000---", Id::LOP_R, Type::ArithmeticInteger, "LOP_R"), | ||
| 691 | INST("0011100001000---", Id::LOP_IMM, Type::ArithmeticInteger, "LOP_IMM"), | ||
| 692 | INST("000001----------", Id::LOP32I, Type::ArithmeticIntegerImmediate, "LOP32I"), | ||
| 680 | INST("0100110001001---", Id::SHL_C, Type::Shift, "SHL_C"), | 693 | INST("0100110001001---", Id::SHL_C, Type::Shift, "SHL_C"), |
| 681 | INST("0101110001001---", Id::SHL_R, Type::Shift, "SHL_R"), | 694 | INST("0101110001001---", Id::SHL_R, Type::Shift, "SHL_R"), |
| 682 | INST("0011100-01001---", Id::SHL_IMM, Type::Shift, "SHL_IMM"), | 695 | INST("0011100-01001---", Id::SHL_IMM, Type::Shift, "SHL_IMM"), |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index af68c3bda..6ec0a0742 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -16,6 +16,7 @@ namespace Decompiler { | |||
| 16 | 16 | ||
| 17 | using Tegra::Shader::Attribute; | 17 | using Tegra::Shader::Attribute; |
| 18 | using Tegra::Shader::Instruction; | 18 | using Tegra::Shader::Instruction; |
| 19 | using Tegra::Shader::LogicOperation; | ||
| 19 | using Tegra::Shader::OpCode; | 20 | using Tegra::Shader::OpCode; |
| 20 | using Tegra::Shader::Register; | 21 | using Tegra::Shader::Register; |
| 21 | using Tegra::Shader::Sampler; | 22 | using Tegra::Shader::Sampler; |
| @@ -759,6 +760,31 @@ private: | |||
| 759 | return (absolute_offset % SchedPeriod) == 0; | 760 | return (absolute_offset % SchedPeriod) == 0; |
| 760 | } | 761 | } |
| 761 | 762 | ||
| 763 | void WriteLogicOperation(Register dest, LogicOperation logic_op, const std::string& op_a, | ||
| 764 | const std::string& op_b) { | ||
| 765 | switch (logic_op) { | ||
| 766 | case LogicOperation::And: { | ||
| 767 | regs.SetRegisterToInteger(dest, true, 0, '(' + op_a + " & " + op_b + ')', 1, 1); | ||
| 768 | break; | ||
| 769 | } | ||
| 770 | case LogicOperation::Or: { | ||
| 771 | regs.SetRegisterToInteger(dest, true, 0, '(' + op_a + " | " + op_b + ')', 1, 1); | ||
| 772 | break; | ||
| 773 | } | ||
| 774 | case LogicOperation::Xor: { | ||
| 775 | regs.SetRegisterToInteger(dest, true, 0, '(' + op_a + " ^ " + op_b + ')', 1, 1); | ||
| 776 | break; | ||
| 777 | } | ||
| 778 | case LogicOperation::PassB: { | ||
| 779 | regs.SetRegisterToInteger(dest, true, 0, op_b, 1, 1); | ||
| 780 | break; | ||
| 781 | } | ||
| 782 | default: | ||
| 783 | NGLOG_CRITICAL(HW_GPU, "Unimplemented logic operation: {}", static_cast<u32>(logic_op)); | ||
| 784 | UNREACHABLE(); | ||
| 785 | } | ||
| 786 | } | ||
| 787 | |||
| 762 | /** | 788 | /** |
| 763 | * Compiles a single instruction from Tegra to GLSL. | 789 | * Compiles a single instruction from Tegra to GLSL. |
| 764 | * @param offset the offset of the Tegra shader instruction. | 790 | * @param offset the offset of the Tegra shader instruction. |
| @@ -942,55 +968,6 @@ private: | |||
| 942 | 968 | ||
| 943 | break; | 969 | break; |
| 944 | } | 970 | } |
| 945 | case OpCode::Type::Logic: { | ||
| 946 | std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, true); | ||
| 947 | |||
| 948 | if (instr.alu.lop.invert_a) | ||
| 949 | op_a = "~(" + op_a + ')'; | ||
| 950 | |||
| 951 | switch (opcode->GetId()) { | ||
| 952 | case OpCode::Id::LOP32I: { | ||
| 953 | u32 imm = static_cast<u32>(instr.alu.imm20_32.Value()); | ||
| 954 | |||
| 955 | if (instr.alu.lop.invert_b) | ||
| 956 | imm = ~imm; | ||
| 957 | |||
| 958 | std::string op_b = std::to_string(imm); | ||
| 959 | |||
| 960 | switch (instr.alu.lop.operation) { | ||
| 961 | case Tegra::Shader::LogicOperation::And: { | ||
| 962 | regs.SetRegisterToInteger(instr.gpr0, true, 0, '(' + op_a + " & " + op_b + ')', | ||
| 963 | 1, 1); | ||
| 964 | break; | ||
| 965 | } | ||
| 966 | case Tegra::Shader::LogicOperation::Or: { | ||
| 967 | regs.SetRegisterToInteger(instr.gpr0, true, 0, '(' + op_a + " | " + op_b + ')', | ||
| 968 | 1, 1); | ||
| 969 | break; | ||
| 970 | } | ||
| 971 | case Tegra::Shader::LogicOperation::Xor: { | ||
| 972 | regs.SetRegisterToInteger(instr.gpr0, true, 0, '(' + op_a + " ^ " + op_b + ')', | ||
| 973 | 1, 1); | ||
| 974 | break; | ||
| 975 | } | ||
| 976 | case Tegra::Shader::LogicOperation::PassB: { | ||
| 977 | regs.SetRegisterToInteger(instr.gpr0, true, 0, op_b, 1, 1); | ||
| 978 | break; | ||
| 979 | } | ||
| 980 | default: | ||
| 981 | NGLOG_CRITICAL(HW_GPU, "Unimplemented lop32i operation: {}", | ||
| 982 | static_cast<u32>(instr.alu.lop.operation.Value())); | ||
| 983 | UNREACHABLE(); | ||
| 984 | } | ||
| 985 | break; | ||
| 986 | } | ||
| 987 | default: { | ||
| 988 | NGLOG_CRITICAL(HW_GPU, "Unhandled logic instruction: {}", opcode->GetName()); | ||
| 989 | UNREACHABLE(); | ||
| 990 | } | ||
| 991 | } | ||
| 992 | break; | ||
| 993 | } | ||
| 994 | 971 | ||
| 995 | case OpCode::Type::Shift: { | 972 | case OpCode::Type::Shift: { |
| 996 | std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, true); | 973 | std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, true); |
| @@ -1036,17 +1013,26 @@ private: | |||
| 1036 | 1013 | ||
| 1037 | case OpCode::Type::ArithmeticIntegerImmediate: { | 1014 | case OpCode::Type::ArithmeticIntegerImmediate: { |
| 1038 | std::string op_a = regs.GetRegisterAsInteger(instr.gpr8); | 1015 | std::string op_a = regs.GetRegisterAsInteger(instr.gpr8); |
| 1039 | 1016 | std::string op_b = std::to_string(instr.alu.imm20_32.Value()); | |
| 1040 | if (instr.iadd32i.negate_a) | ||
| 1041 | op_a = '-' + op_a; | ||
| 1042 | |||
| 1043 | std::string op_b = '(' + std::to_string(instr.alu.imm20_32.Value()) + ')'; | ||
| 1044 | 1017 | ||
| 1045 | switch (opcode->GetId()) { | 1018 | switch (opcode->GetId()) { |
| 1046 | case OpCode::Id::IADD32I: | 1019 | case OpCode::Id::IADD32I: |
| 1020 | if (instr.iadd32i.negate_a) | ||
| 1021 | op_a = "-(" + op_a + ')'; | ||
| 1022 | |||
| 1047 | regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1, | 1023 | regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1, |
| 1048 | instr.iadd32i.saturate != 0); | 1024 | instr.iadd32i.saturate != 0); |
| 1049 | break; | 1025 | break; |
| 1026 | case OpCode::Id::LOP32I: { | ||
| 1027 | if (instr.alu.lop32i.invert_a) | ||
| 1028 | op_a = "~(" + op_a + ')'; | ||
| 1029 | |||
| 1030 | if (instr.alu.lop32i.invert_b) | ||
| 1031 | op_b = "~(" + op_b + ')'; | ||
| 1032 | |||
| 1033 | WriteLogicOperation(instr.gpr0, instr.alu.lop32i.operation, op_a, op_b); | ||
| 1034 | break; | ||
| 1035 | } | ||
| 1050 | default: { | 1036 | default: { |
| 1051 | NGLOG_CRITICAL(HW_GPU, "Unhandled ArithmeticIntegerImmediate instruction: {}", | 1037 | NGLOG_CRITICAL(HW_GPU, "Unhandled ArithmeticIntegerImmediate instruction: {}", |
| 1052 | opcode->GetName()); | 1038 | opcode->GetName()); |
| @@ -1057,12 +1043,7 @@ private: | |||
| 1057 | } | 1043 | } |
| 1058 | case OpCode::Type::ArithmeticInteger: { | 1044 | case OpCode::Type::ArithmeticInteger: { |
| 1059 | std::string op_a = regs.GetRegisterAsInteger(instr.gpr8); | 1045 | std::string op_a = regs.GetRegisterAsInteger(instr.gpr8); |
| 1060 | 1046 | std::string op_b; | |
| 1061 | if (instr.alu_integer.negate_a) | ||
| 1062 | op_a = '-' + op_a; | ||
| 1063 | |||
| 1064 | std::string op_b = instr.alu_integer.negate_b ? "-" : ""; | ||
| 1065 | |||
| 1066 | if (instr.is_b_imm) { | 1047 | if (instr.is_b_imm) { |
| 1067 | op_b += '(' + std::to_string(instr.alu.GetSignedImm20_20()) + ')'; | 1048 | op_b += '(' + std::to_string(instr.alu.GetSignedImm20_20()) + ')'; |
| 1068 | } else { | 1049 | } else { |
| @@ -1078,6 +1059,12 @@ private: | |||
| 1078 | case OpCode::Id::IADD_C: | 1059 | case OpCode::Id::IADD_C: |
| 1079 | case OpCode::Id::IADD_R: | 1060 | case OpCode::Id::IADD_R: |
| 1080 | case OpCode::Id::IADD_IMM: { | 1061 | case OpCode::Id::IADD_IMM: { |
| 1062 | if (instr.alu_integer.negate_a) | ||
| 1063 | op_a = "-(" + op_a + ')'; | ||
| 1064 | |||
| 1065 | if (instr.alu_integer.negate_b) | ||
| 1066 | op_b = "-(" + op_b + ')'; | ||
| 1067 | |||
| 1081 | regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1, | 1068 | regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1, |
| 1082 | instr.alu.saturate_d); | 1069 | instr.alu.saturate_d); |
| 1083 | break; | 1070 | break; |
| @@ -1085,12 +1072,33 @@ private: | |||
| 1085 | case OpCode::Id::ISCADD_C: | 1072 | case OpCode::Id::ISCADD_C: |
| 1086 | case OpCode::Id::ISCADD_R: | 1073 | case OpCode::Id::ISCADD_R: |
| 1087 | case OpCode::Id::ISCADD_IMM: { | 1074 | case OpCode::Id::ISCADD_IMM: { |
| 1075 | if (instr.alu_integer.negate_a) | ||
| 1076 | op_a = "-(" + op_a + ')'; | ||
| 1077 | |||
| 1078 | if (instr.alu_integer.negate_b) | ||
| 1079 | op_b = "-(" + op_b + ')'; | ||
| 1080 | |||
| 1088 | std::string shift = std::to_string(instr.alu_integer.shift_amount.Value()); | 1081 | std::string shift = std::to_string(instr.alu_integer.shift_amount.Value()); |
| 1089 | 1082 | ||
| 1090 | regs.SetRegisterToInteger(instr.gpr0, true, 0, | 1083 | regs.SetRegisterToInteger(instr.gpr0, true, 0, |
| 1091 | "((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1); | 1084 | "((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1); |
| 1092 | break; | 1085 | break; |
| 1093 | } | 1086 | } |
| 1087 | case OpCode::Id::LOP_C: | ||
| 1088 | case OpCode::Id::LOP_R: | ||
| 1089 | case OpCode::Id::LOP_IMM: { | ||
| 1090 | ASSERT_MSG(!instr.alu.lop.unk44, "Unimplemented"); | ||
| 1091 | ASSERT_MSG(instr.alu.lop.pred48 == Pred::UnusedIndex, "Unimplemented"); | ||
| 1092 | |||
| 1093 | if (instr.alu.lop.invert_a) | ||
| 1094 | op_a = "~(" + op_a + ')'; | ||
| 1095 | |||
| 1096 | if (instr.alu.lop.invert_b) | ||
| 1097 | op_b = "~(" + op_b + ')'; | ||
| 1098 | |||
| 1099 | WriteLogicOperation(instr.gpr0, instr.alu.lop.operation, op_a, op_b); | ||
| 1100 | break; | ||
| 1101 | } | ||
| 1094 | default: { | 1102 | default: { |
| 1095 | NGLOG_CRITICAL(HW_GPU, "Unhandled ArithmeticInteger instruction: {}", | 1103 | NGLOG_CRITICAL(HW_GPU, "Unhandled ArithmeticInteger instruction: {}", |
| 1096 | opcode->GetName()); | 1104 | opcode->GetName()); |