xmad.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // Copyright 2018 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "common/assert.h"
  5. #include "common/common_types.h"
  6. #include "video_core/engines/shader_bytecode.h"
  7. #include "video_core/shader/node_helper.h"
  8. #include "video_core/shader/shader_ir.h"
  9. namespace VideoCommon::Shader {
  10. using Tegra::Shader::Instruction;
  11. using Tegra::Shader::OpCode;
  12. u32 ShaderIR::DecodeXmad(NodeBlock& bb, u32 pc) {
  13. const Instruction instr = {program_code[pc]};
  14. const auto opcode = OpCode::Decode(instr);
  15. UNIMPLEMENTED_IF(instr.xmad.sign_a);
  16. UNIMPLEMENTED_IF(instr.xmad.sign_b);
  17. UNIMPLEMENTED_IF_MSG(instr.generates_cc,
  18. "Condition codes generation in XMAD is not implemented");
  19. Node op_a = GetRegister(instr.gpr8);
  20. // TODO(bunnei): Needs to be fixed once op_a or op_b is signed
  21. UNIMPLEMENTED_IF(instr.xmad.sign_a != instr.xmad.sign_b);
  22. const bool is_signed_a = instr.xmad.sign_a == 1;
  23. const bool is_signed_b = instr.xmad.sign_b == 1;
  24. const bool is_signed_c = is_signed_a;
  25. auto [is_merge, is_psl, is_high_b, mode, op_b,
  26. op_c] = [&]() -> std::tuple<bool, bool, bool, Tegra::Shader::XmadMode, Node, Node> {
  27. switch (opcode->get().GetId()) {
  28. case OpCode::Id::XMAD_CR:
  29. return {instr.xmad.merge_56,
  30. instr.xmad.product_shift_left_second,
  31. instr.xmad.high_b,
  32. instr.xmad.mode_cbf,
  33. GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset()),
  34. GetRegister(instr.gpr39)};
  35. case OpCode::Id::XMAD_RR:
  36. return {instr.xmad.merge_37, instr.xmad.product_shift_left, instr.xmad.high_b_rr,
  37. instr.xmad.mode, GetRegister(instr.gpr20), GetRegister(instr.gpr39)};
  38. case OpCode::Id::XMAD_RC:
  39. return {false,
  40. false,
  41. instr.xmad.high_b,
  42. instr.xmad.mode_cbf,
  43. GetRegister(instr.gpr39),
  44. GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset())};
  45. case OpCode::Id::XMAD_IMM:
  46. return {instr.xmad.merge_37,
  47. instr.xmad.product_shift_left,
  48. false,
  49. instr.xmad.mode,
  50. Immediate(static_cast<u32>(instr.xmad.imm20_16)),
  51. GetRegister(instr.gpr39)};
  52. default:
  53. UNIMPLEMENTED_MSG("Unhandled XMAD instruction: {}", opcode->get().GetName());
  54. return {false, false, false, Tegra::Shader::XmadMode::None, Immediate(0), Immediate(0)};
  55. }
  56. }();
  57. op_a = BitfieldExtract(op_a, instr.xmad.high_a ? 16 : 0, 16);
  58. const Node original_b = op_b;
  59. op_b = BitfieldExtract(op_b, is_high_b ? 16 : 0, 16);
  60. // TODO(Rodrigo): Use an appropiate sign for this operation
  61. Node product = Operation(OperationCode::IMul, NO_PRECISE, op_a, op_b);
  62. if (is_psl) {
  63. product = Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, product, Immediate(16));
  64. }
  65. SetTemporary(bb, 0, product);
  66. product = GetTemporary(0);
  67. const Node original_c = op_c;
  68. const Tegra::Shader::XmadMode set_mode = mode; // Workaround to clang compile error
  69. op_c = [&]() {
  70. switch (set_mode) {
  71. case Tegra::Shader::XmadMode::None:
  72. return original_c;
  73. case Tegra::Shader::XmadMode::CLo:
  74. return BitfieldExtract(original_c, 0, 16);
  75. case Tegra::Shader::XmadMode::CHi:
  76. return BitfieldExtract(original_c, 16, 16);
  77. case Tegra::Shader::XmadMode::CBcc: {
  78. const Node shifted_b = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed_b,
  79. NO_PRECISE, original_b, Immediate(16));
  80. return SignedOperation(OperationCode::IAdd, is_signed_c, NO_PRECISE, original_c,
  81. shifted_b);
  82. }
  83. default:
  84. UNIMPLEMENTED_MSG("Unhandled XMAD mode: {}", static_cast<u32>(instr.xmad.mode.Value()));
  85. return Immediate(0);
  86. }
  87. }();
  88. SetTemporary(bb, 1, op_c);
  89. op_c = GetTemporary(1);
  90. // TODO(Rodrigo): Use an appropiate sign for this operation
  91. Node sum = Operation(OperationCode::IAdd, product, op_c);
  92. SetTemporary(bb, 2, sum);
  93. sum = GetTemporary(2);
  94. if (is_merge) {
  95. const Node a = BitfieldExtract(sum, 0, 16);
  96. const Node b =
  97. Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, original_b, Immediate(16));
  98. sum = Operation(OperationCode::IBitwiseOr, NO_PRECISE, a, b);
  99. }
  100. SetInternalFlagsFromInteger(bb, sum, instr.generates_cc);
  101. SetRegister(bb, instr.gpr0, sum);
  102. return pc;
  103. }
  104. } // namespace VideoCommon::Shader