diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/video_core/engines/shader_bytecode.h | 42 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_decompiler.cpp | 80 |
2 files changed, 107 insertions, 15 deletions
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 93654eb66..4eb507325 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -237,9 +237,22 @@ union Instruction { | |||
| 237 | std::memcpy(&result, &imm, sizeof(imm)); | 237 | std::memcpy(&result, &imm, sizeof(imm)); |
| 238 | return result; | 238 | return result; |
| 239 | } | 239 | } |
| 240 | |||
| 241 | s32 GetSignedImm20_20() const { | ||
| 242 | u32 immediate = static_cast<u32>(imm20_19 | (negate_imm << 19)); | ||
| 243 | // Sign extend the 20-bit value. | ||
| 244 | u32 mask = 1U << (20 - 1); | ||
| 245 | return static_cast<s32>((immediate ^ mask) - mask); | ||
| 246 | } | ||
| 240 | } alu; | 247 | } alu; |
| 241 | 248 | ||
| 242 | union { | 249 | union { |
| 250 | BitField<39, 5, u64> shift_amount; | ||
| 251 | BitField<48, 1, u64> negate_b; | ||
| 252 | BitField<49, 1, u64> negate_a; | ||
| 253 | } iscadd; | ||
| 254 | |||
| 255 | union { | ||
| 243 | BitField<48, 1, u64> negate_b; | 256 | BitField<48, 1, u64> negate_b; |
| 244 | BitField<49, 1, u64> negate_c; | 257 | BitField<49, 1, u64> negate_c; |
| 245 | } ffma; | 258 | } ffma; |
| @@ -328,15 +341,16 @@ union Instruction { | |||
| 328 | } texs; | 341 | } texs; |
| 329 | 342 | ||
| 330 | union { | 343 | union { |
| 331 | BitField<20, 5, u64> target; | 344 | BitField<20, 24, u64> target; |
| 332 | BitField<5, 1, u64> constant_buffer; | 345 | BitField<5, 1, u64> constant_buffer; |
| 333 | 346 | ||
| 334 | s32 GetBranchTarget() const { | 347 | s32 GetBranchTarget() const { |
| 335 | // Sign extend the branch target offset | 348 | // Sign extend the branch target offset |
| 336 | u32 mask = 1U << (5 - 1); | 349 | u32 mask = 1U << (24 - 1); |
| 337 | u32 value = static_cast<u32>(target); | 350 | u32 value = static_cast<u32>(target); |
| 338 | // The branch offset is relative to the next instruction, so add 1 to it. | 351 | // The branch offset is relative to the next instruction and is stored in bytes, so |
| 339 | return static_cast<s32>((value ^ mask) - mask) + 1; | 352 | // divide it by the size of an instruction and add 1 to it. |
| 353 | return static_cast<s32>((value ^ mask) - mask) / sizeof(Instruction) + 1; | ||
| 340 | } | 354 | } |
| 341 | } bra; | 355 | } bra; |
| 342 | 356 | ||
| @@ -378,6 +392,9 @@ public: | |||
| 378 | FMUL_R, | 392 | FMUL_R, |
| 379 | FMUL_IMM, | 393 | FMUL_IMM, |
| 380 | FMUL32_IMM, | 394 | FMUL32_IMM, |
| 395 | ISCADD_C, // Scale and Add | ||
| 396 | ISCADD_R, | ||
| 397 | ISCADD_IMM, | ||
| 381 | MUFU, // Multi-Function Operator | 398 | MUFU, // Multi-Function Operator |
| 382 | RRO_C, // Range Reduction Operator | 399 | RRO_C, // Range Reduction Operator |
| 383 | RRO_R, | 400 | RRO_R, |
| @@ -399,6 +416,9 @@ public: | |||
| 399 | MOV_R, | 416 | MOV_R, |
| 400 | MOV_IMM, | 417 | MOV_IMM, |
| 401 | MOV32_IMM, | 418 | MOV32_IMM, |
| 419 | SHL_C, | ||
| 420 | SHL_R, | ||
| 421 | SHL_IMM, | ||
| 402 | SHR_C, | 422 | SHR_C, |
| 403 | SHR_R, | 423 | SHR_R, |
| 404 | SHR_IMM, | 424 | SHR_IMM, |
| @@ -421,6 +441,8 @@ public: | |||
| 421 | Trivial, | 441 | Trivial, |
| 422 | Arithmetic, | 442 | Arithmetic, |
| 423 | Logic, | 443 | Logic, |
| 444 | Shift, | ||
| 445 | ScaledAdd, | ||
| 424 | Ffma, | 446 | Ffma, |
| 425 | Flow, | 447 | Flow, |
| 426 | Memory, | 448 | Memory, |
| @@ -544,6 +566,9 @@ private: | |||
| 544 | INST("0101110001101---", Id::FMUL_R, Type::Arithmetic, "FMUL_R"), | 566 | INST("0101110001101---", Id::FMUL_R, Type::Arithmetic, "FMUL_R"), |
| 545 | INST("0011100-01101---", Id::FMUL_IMM, Type::Arithmetic, "FMUL_IMM"), | 567 | INST("0011100-01101---", Id::FMUL_IMM, Type::Arithmetic, "FMUL_IMM"), |
| 546 | INST("00011110--------", Id::FMUL32_IMM, Type::Arithmetic, "FMUL32_IMM"), | 568 | INST("00011110--------", Id::FMUL32_IMM, Type::Arithmetic, "FMUL32_IMM"), |
| 569 | INST("0100110000011---", Id::ISCADD_C, Type::ScaledAdd, "ISCADD_C"), | ||
| 570 | INST("0101110000011---", Id::ISCADD_R, Type::ScaledAdd, "ISCADD_R"), | ||
| 571 | INST("0011100-00011---", Id::ISCADD_IMM, Type::ScaledAdd, "ISCADD_IMM"), | ||
| 547 | INST("0101000010000---", Id::MUFU, Type::Arithmetic, "MUFU"), | 572 | INST("0101000010000---", Id::MUFU, Type::Arithmetic, "MUFU"), |
| 548 | INST("0100110010010---", Id::RRO_C, Type::Arithmetic, "RRO_C"), | 573 | INST("0100110010010---", Id::RRO_C, Type::Arithmetic, "RRO_C"), |
| 549 | INST("0101110010010---", Id::RRO_R, Type::Arithmetic, "RRO_R"), | 574 | INST("0101110010010---", Id::RRO_R, Type::Arithmetic, "RRO_R"), |
| @@ -558,13 +583,16 @@ private: | |||
| 558 | INST("0101110010011---", Id::MOV_R, Type::Arithmetic, "MOV_R"), | 583 | INST("0101110010011---", Id::MOV_R, Type::Arithmetic, "MOV_R"), |
| 559 | INST("0011100-10011---", Id::MOV_IMM, Type::Arithmetic, "MOV_IMM"), | 584 | INST("0011100-10011---", Id::MOV_IMM, Type::Arithmetic, "MOV_IMM"), |
| 560 | INST("000000010000----", Id::MOV32_IMM, Type::Arithmetic, "MOV32_IMM"), | 585 | INST("000000010000----", Id::MOV32_IMM, Type::Arithmetic, "MOV32_IMM"), |
| 561 | INST("0100110000101---", Id::SHR_C, Type::Arithmetic, "SHR_C"), | ||
| 562 | INST("0101110000101---", Id::SHR_R, Type::Arithmetic, "SHR_R"), | ||
| 563 | INST("0011100-00101---", Id::SHR_IMM, Type::Arithmetic, "SHR_IMM"), | ||
| 564 | INST("0100110001100---", Id::FMNMX_C, Type::Arithmetic, "FMNMX_C"), | 586 | INST("0100110001100---", Id::FMNMX_C, Type::Arithmetic, "FMNMX_C"), |
| 565 | INST("0101110001100---", Id::FMNMX_R, Type::Arithmetic, "FMNMX_R"), | 587 | INST("0101110001100---", Id::FMNMX_R, Type::Arithmetic, "FMNMX_R"), |
| 566 | INST("0011100-01100---", Id::FMNMX_IMM, Type::Arithmetic, "FMNMX_IMM"), | 588 | INST("0011100-01100---", Id::FMNMX_IMM, Type::Arithmetic, "FMNMX_IMM"), |
| 567 | INST("000001----------", Id::LOP32I, Type::Logic, "LOP32I"), | 589 | INST("000001----------", Id::LOP32I, Type::Logic, "LOP32I"), |
| 590 | INST("0100110001001---", Id::SHL_C, Type::Shift, "SHL_C"), | ||
| 591 | INST("0101110001001---", Id::SHL_R, Type::Shift, "SHL_R"), | ||
| 592 | INST("0011100-01001---", Id::SHL_IMM, Type::Shift, "SHL_IMM"), | ||
| 593 | INST("0100110000101---", Id::SHR_C, Type::Shift, "SHR_C"), | ||
| 594 | INST("0101110000101---", Id::SHR_R, Type::Shift, "SHR_R"), | ||
| 595 | INST("0011100-00101---", Id::SHR_IMM, Type::Shift, "SHR_IMM"), | ||
| 568 | INST("0100110011100---", Id::I2I_C, Type::Conversion, "I2I_C"), | 596 | INST("0100110011100---", Id::I2I_C, Type::Conversion, "I2I_C"), |
| 569 | INST("0101110011100---", Id::I2I_R, Type::Conversion, "I2I_R"), | 597 | INST("0101110011100---", Id::I2I_R, Type::Conversion, "I2I_R"), |
| 570 | INST("01110001-1000---", Id::I2I_IMM, Type::Conversion, "I2I_IMM"), | 598 | INST("01110001-1000---", Id::I2I_IMM, Type::Conversion, "I2I_IMM"), |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 4b14bb47e..4a41e7798 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -115,7 +115,16 @@ private: | |||
| 115 | if (const auto opcode = OpCode::Decode(instr)) { | 115 | if (const auto opcode = OpCode::Decode(instr)) { |
| 116 | switch (opcode->GetId()) { | 116 | switch (opcode->GetId()) { |
| 117 | case OpCode::Id::EXIT: { | 117 | case OpCode::Id::EXIT: { |
| 118 | return exit_method = ExitMethod::AlwaysEnd; | 118 | // The EXIT instruction can be predicated, which means that the shader can |
| 119 | // conditionally end on this instruction. We have to consider the case where the | ||
| 120 | // condition is not met and check the exit method of that other basic block. | ||
| 121 | using Tegra::Shader::Pred; | ||
| 122 | if (instr.pred.pred_index == static_cast<u64>(Pred::UnusedIndex)) { | ||
| 123 | return exit_method = ExitMethod::AlwaysEnd; | ||
| 124 | } else { | ||
| 125 | ExitMethod not_met = Scan(offset + 1, end, labels); | ||
| 126 | return exit_method = ParallelExit(ExitMethod::AlwaysEnd, not_met); | ||
| 127 | } | ||
| 119 | } | 128 | } |
| 120 | case OpCode::Id::BRA: { | 129 | case OpCode::Id::BRA: { |
| 121 | u32 target = offset + instr.bra.GetBranchTarget(); | 130 | u32 target = offset + instr.bra.GetBranchTarget(); |
| @@ -645,9 +654,9 @@ private: | |||
| 645 | std::string GetPredicateComparison(Tegra::Shader::PredCondition condition) const { | 654 | std::string GetPredicateComparison(Tegra::Shader::PredCondition condition) const { |
| 646 | using Tegra::Shader::PredCondition; | 655 | using Tegra::Shader::PredCondition; |
| 647 | static const std::unordered_map<PredCondition, const char*> PredicateComparisonStrings = { | 656 | static const std::unordered_map<PredCondition, const char*> PredicateComparisonStrings = { |
| 648 | {PredCondition::LessThan, "<"}, {PredCondition::Equal, "=="}, | 657 | {PredCondition::LessThan, "<"}, {PredCondition::Equal, "=="}, |
| 649 | {PredCondition::LessEqual, "<="}, {PredCondition::GreaterThan, ">"}, | 658 | {PredCondition::LessEqual, "<="}, {PredCondition::GreaterThan, ">"}, |
| 650 | {PredCondition::GreaterEqual, ">="}, | 659 | {PredCondition::NotEqual, "!="}, {PredCondition::GreaterEqual, ">="}, |
| 651 | }; | 660 | }; |
| 652 | 661 | ||
| 653 | auto comparison = PredicateComparisonStrings.find(condition); | 662 | auto comparison = PredicateComparisonStrings.find(condition); |
| @@ -884,6 +893,59 @@ private: | |||
| 884 | } | 893 | } |
| 885 | break; | 894 | break; |
| 886 | } | 895 | } |
| 896 | |||
| 897 | case OpCode::Type::Shift: { | ||
| 898 | std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, false); | ||
| 899 | std::string op_b; | ||
| 900 | |||
| 901 | if (instr.is_b_imm) { | ||
| 902 | op_b += '(' + std::to_string(instr.alu.GetSignedImm20_20()) + ')'; | ||
| 903 | } else { | ||
| 904 | if (instr.is_b_gpr) { | ||
| 905 | op_b += regs.GetRegisterAsInteger(instr.gpr20); | ||
| 906 | } else { | ||
| 907 | op_b += regs.GetUniform(instr.uniform, GLSLRegister::Type::Integer); | ||
| 908 | } | ||
| 909 | } | ||
| 910 | |||
| 911 | switch (opcode->GetId()) { | ||
| 912 | case OpCode::Id::SHL_C: | ||
| 913 | case OpCode::Id::SHL_R: | ||
| 914 | case OpCode::Id::SHL_IMM: | ||
| 915 | regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1); | ||
| 916 | break; | ||
| 917 | default: { | ||
| 918 | NGLOG_CRITICAL(HW_GPU, "Unhandled shift instruction: {}", opcode->GetName()); | ||
| 919 | UNREACHABLE(); | ||
| 920 | } | ||
| 921 | } | ||
| 922 | break; | ||
| 923 | } | ||
| 924 | |||
| 925 | case OpCode::Type::ScaledAdd: { | ||
| 926 | std::string op_a = regs.GetRegisterAsInteger(instr.gpr8); | ||
| 927 | |||
| 928 | if (instr.iscadd.negate_a) | ||
| 929 | op_a = '-' + op_a; | ||
| 930 | |||
| 931 | std::string op_b = instr.iscadd.negate_b ? "-" : ""; | ||
| 932 | |||
| 933 | if (instr.is_b_imm) { | ||
| 934 | op_b += '(' + std::to_string(instr.alu.GetSignedImm20_20()) + ')'; | ||
| 935 | } else { | ||
| 936 | if (instr.is_b_gpr) { | ||
| 937 | op_b += regs.GetRegisterAsInteger(instr.gpr20); | ||
| 938 | } else { | ||
| 939 | op_b += regs.GetUniform(instr.uniform, GLSLRegister::Type::Integer); | ||
| 940 | } | ||
| 941 | } | ||
| 942 | |||
| 943 | std::string shift = std::to_string(instr.iscadd.shift_amount.Value()); | ||
| 944 | |||
| 945 | regs.SetRegisterToInteger(instr.gpr0, true, 0, | ||
| 946 | "((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1); | ||
| 947 | break; | ||
| 948 | } | ||
| 887 | case OpCode::Type::Ffma: { | 949 | case OpCode::Type::Ffma: { |
| 888 | std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); | 950 | std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); |
| 889 | std::string op_b = instr.ffma.negate_b ? "-" : ""; | 951 | std::string op_b = instr.ffma.negate_b ? "-" : ""; |
| @@ -1230,9 +1292,6 @@ private: | |||
| 1230 | default: { | 1292 | default: { |
| 1231 | switch (opcode->GetId()) { | 1293 | switch (opcode->GetId()) { |
| 1232 | case OpCode::Id::EXIT: { | 1294 | case OpCode::Id::EXIT: { |
| 1233 | ASSERT_MSG(instr.pred.pred_index == static_cast<u64>(Pred::UnusedIndex), | ||
| 1234 | "Predicated exits not implemented"); | ||
| 1235 | |||
| 1236 | // Final color output is currently hardcoded to GPR0-3 for fragment shaders | 1295 | // Final color output is currently hardcoded to GPR0-3 for fragment shaders |
| 1237 | if (stage == Maxwell3D::Regs::ShaderStage::Fragment) { | 1296 | if (stage == Maxwell3D::Regs::ShaderStage::Fragment) { |
| 1238 | shader.AddLine("color.r = " + regs.GetRegisterAsFloat(0) + ';'); | 1297 | shader.AddLine("color.r = " + regs.GetRegisterAsFloat(0) + ';'); |
| @@ -1242,7 +1301,12 @@ private: | |||
| 1242 | } | 1301 | } |
| 1243 | 1302 | ||
| 1244 | shader.AddLine("return true;"); | 1303 | shader.AddLine("return true;"); |
| 1245 | offset = PROGRAM_END - 1; | 1304 | if (instr.pred.pred_index == static_cast<u64>(Pred::UnusedIndex)) { |
| 1305 | // If this is an unconditional exit then just end processing here, otherwise we | ||
| 1306 | // have to account for the possibility of the condition not being met, so | ||
| 1307 | // continue processing the next instruction. | ||
| 1308 | offset = PROGRAM_END - 1; | ||
| 1309 | } | ||
| 1246 | break; | 1310 | break; |
| 1247 | } | 1311 | } |
| 1248 | case OpCode::Id::KIL: { | 1312 | case OpCode::Id::KIL: { |