other.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  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/shader_ir.h"
  8. namespace VideoCommon::Shader {
  9. using Tegra::Shader::Instruction;
  10. using Tegra::Shader::OpCode;
  11. using Tegra::Shader::ConditionCode;
  12. u32 ShaderIR::DecodeOther(BasicBlock& bb, u32 pc) {
  13. const Instruction instr = {program_code[pc]};
  14. const auto opcode = OpCode::Decode(instr);
  15. switch (opcode->get().GetId()) {
  16. case OpCode::Id::EXIT: {
  17. const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
  18. UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, "EXIT condition code used: {}",
  19. static_cast<u32>(cc));
  20. switch (instr.flow.cond) {
  21. case Tegra::Shader::FlowCondition::Always:
  22. bb.push_back(Operation(OperationCode::Exit));
  23. if (instr.pred.pred_index == static_cast<u64>(Tegra::Shader::Pred::UnusedIndex)) {
  24. // If this is an unconditional exit then just end processing here,
  25. // otherwise we have to account for the possibility of the condition
  26. // not being met, so continue processing the next instruction.
  27. pc = MAX_PROGRAM_LENGTH - 1;
  28. }
  29. break;
  30. case Tegra::Shader::FlowCondition::Fcsm_Tr:
  31. // TODO(bunnei): What is this used for? If we assume this conditon is not
  32. // satisifed, dual vertex shaders in Farming Simulator make more sense
  33. UNIMPLEMENTED_MSG("Skipping unknown FlowCondition::Fcsm_Tr");
  34. break;
  35. default:
  36. UNIMPLEMENTED_MSG("Unhandled flow condition: {}",
  37. static_cast<u32>(instr.flow.cond.Value()));
  38. }
  39. break;
  40. }
  41. case OpCode::Id::KIL: {
  42. UNIMPLEMENTED_IF(instr.flow.cond != Tegra::Shader::FlowCondition::Always);
  43. const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
  44. UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, "KIL condition code used: {}",
  45. static_cast<u32>(cc));
  46. bb.push_back(Operation(OperationCode::Kil));
  47. break;
  48. }
  49. case OpCode::Id::MOV_SYS: {
  50. switch (instr.sys20) {
  51. case Tegra::Shader::SystemVariable::InvocationInfo: {
  52. LOG_WARNING(HW_GPU, "MOV_SYS instruction with InvocationInfo is incomplete");
  53. SetRegister(bb, instr.gpr0, Immediate(0u));
  54. break;
  55. }
  56. case Tegra::Shader::SystemVariable::Ydirection: {
  57. // Config pack's third value is Y_NEGATE's state.
  58. SetRegister(bb, instr.gpr0, Operation(OperationCode::YNegate));
  59. break;
  60. }
  61. default:
  62. UNIMPLEMENTED_MSG("Unhandled system move: {}", static_cast<u32>(instr.sys20.Value()));
  63. }
  64. break;
  65. }
  66. case OpCode::Id::BRA: {
  67. UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0,
  68. "BRA with constant buffers are not implemented");
  69. const u32 target = pc + instr.bra.GetBranchTarget();
  70. const Node branch = Operation(OperationCode::Bra, Immediate(target));
  71. const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
  72. if (cc != Tegra::Shader::ConditionCode::T) {
  73. bb.push_back(Conditional(GetConditionCode(cc), {branch}));
  74. } else {
  75. bb.push_back(branch);
  76. }
  77. break;
  78. }
  79. case OpCode::Id::SSY: {
  80. UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0,
  81. "Constant buffer flow is not supported");
  82. // The SSY opcode tells the GPU where to re-converge divergent execution paths, it sets the
  83. // target of the jump that the SYNC instruction will make. The SSY opcode has a similar
  84. // structure to the BRA opcode.
  85. const u32 target = pc + instr.bra.GetBranchTarget();
  86. bb.push_back(Operation(OperationCode::Ssy, Immediate(target)));
  87. break;
  88. }
  89. case OpCode::Id::PBK: {
  90. UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0,
  91. "Constant buffer PBK is not supported");
  92. // PBK pushes to a stack the address where BRK will jump to. This shares stack with SSY but
  93. // using SYNC on a PBK address will kill the shader execution. We don't emulate this because
  94. // it's very unlikely a driver will emit such invalid shader.
  95. const u32 target = pc + instr.bra.GetBranchTarget();
  96. bb.push_back(Operation(OperationCode::Pbk, Immediate(target)));
  97. break;
  98. }
  99. case OpCode::Id::SYNC: {
  100. const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
  101. UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, "SYNC condition code used: {}",
  102. static_cast<u32>(cc));
  103. // The SYNC opcode jumps to the address previously set by the SSY opcode
  104. bb.push_back(Operation(OperationCode::Sync));
  105. break;
  106. }
  107. case OpCode::Id::BRK: {
  108. const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
  109. UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, "BRK condition code used: {}",
  110. static_cast<u32>(cc));
  111. // The BRK opcode jumps to the address previously set by the PBK opcode
  112. bb.push_back(Operation(OperationCode::Brk));
  113. break;
  114. }
  115. case OpCode::Id::IPA: {
  116. const auto& attribute = instr.attribute.fmt28;
  117. const Tegra::Shader::IpaMode input_mode{instr.ipa.interp_mode.Value(),
  118. instr.ipa.sample_mode.Value()};
  119. const Node input_attr = GetInputAttribute(attribute.index, attribute.element, input_mode);
  120. const Node ipa = Operation(OperationCode::Ipa, input_attr);
  121. const Node value = GetSaturatedFloat(ipa, instr.ipa.saturate);
  122. SetRegister(bb, instr.gpr0, value);
  123. break;
  124. }
  125. case OpCode::Id::DEPBAR: {
  126. LOG_WARNING(HW_GPU, "DEPBAR instruction is stubbed");
  127. break;
  128. }
  129. default:
  130. UNIMPLEMENTED_MSG("Unhandled instruction: {}", opcode->get().GetName());
  131. }
  132. return pc;
  133. }
  134. } // namespace VideoCommon::Shader