other.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  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 "common/logging/log.h"
  7. #include "video_core/engines/shader_bytecode.h"
  8. #include "video_core/shader/node_helper.h"
  9. #include "video_core/shader/shader_ir.h"
  10. namespace VideoCommon::Shader {
  11. using std::move;
  12. using Tegra::Shader::ConditionCode;
  13. using Tegra::Shader::Instruction;
  14. using Tegra::Shader::IpaInterpMode;
  15. using Tegra::Shader::OpCode;
  16. using Tegra::Shader::PixelImap;
  17. using Tegra::Shader::Register;
  18. using Tegra::Shader::SystemVariable;
  19. using Index = Tegra::Shader::Attribute::Index;
  20. u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
  21. const Instruction instr = {program_code[pc]};
  22. const auto opcode = OpCode::Decode(instr);
  23. switch (opcode->get().GetId()) {
  24. case OpCode::Id::NOP: {
  25. UNIMPLEMENTED_IF(instr.nop.cc != Tegra::Shader::ConditionCode::T);
  26. UNIMPLEMENTED_IF(instr.nop.trigger != 0);
  27. // With the previous preconditions, this instruction is a no-operation.
  28. break;
  29. }
  30. case OpCode::Id::EXIT: {
  31. const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
  32. UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, "EXIT condition code used: {}",
  33. static_cast<u32>(cc));
  34. switch (instr.flow.cond) {
  35. case Tegra::Shader::FlowCondition::Always:
  36. bb.push_back(Operation(OperationCode::Exit));
  37. if (instr.pred.pred_index == static_cast<u64>(Tegra::Shader::Pred::UnusedIndex)) {
  38. // If this is an unconditional exit then just end processing here,
  39. // otherwise we have to account for the possibility of the condition
  40. // not being met, so continue processing the next instruction.
  41. pc = MAX_PROGRAM_LENGTH - 1;
  42. }
  43. break;
  44. case Tegra::Shader::FlowCondition::Fcsm_Tr:
  45. // TODO(bunnei): What is this used for? If we assume this conditon is not
  46. // satisifed, dual vertex shaders in Farming Simulator make more sense
  47. UNIMPLEMENTED_MSG("Skipping unknown FlowCondition::Fcsm_Tr");
  48. break;
  49. default:
  50. UNIMPLEMENTED_MSG("Unhandled flow condition: {}",
  51. static_cast<u32>(instr.flow.cond.Value()));
  52. }
  53. break;
  54. }
  55. case OpCode::Id::KIL: {
  56. UNIMPLEMENTED_IF(instr.flow.cond != Tegra::Shader::FlowCondition::Always);
  57. const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
  58. UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, "KIL condition code used: {}",
  59. static_cast<u32>(cc));
  60. bb.push_back(Operation(OperationCode::Discard));
  61. break;
  62. }
  63. case OpCode::Id::S2R: {
  64. const Node value = [this, instr] {
  65. switch (instr.sys20) {
  66. case SystemVariable::LaneId:
  67. LOG_WARNING(HW_GPU, "S2R instruction with LaneId is incomplete");
  68. return Immediate(0U);
  69. case SystemVariable::InvocationId:
  70. return Operation(OperationCode::InvocationId);
  71. case SystemVariable::Ydirection:
  72. return Operation(OperationCode::YNegate);
  73. case SystemVariable::InvocationInfo:
  74. LOG_WARNING(HW_GPU, "S2R instruction with InvocationInfo is incomplete");
  75. return Immediate(0U);
  76. case SystemVariable::WscaleFactorXY:
  77. UNIMPLEMENTED_MSG("S2R WscaleFactorXY is not implemented");
  78. return Immediate(0U);
  79. case SystemVariable::WscaleFactorZ:
  80. UNIMPLEMENTED_MSG("S2R WscaleFactorZ is not implemented");
  81. return Immediate(0U);
  82. case SystemVariable::Tid: {
  83. Node value = Immediate(0);
  84. value = BitfieldInsert(value, Operation(OperationCode::LocalInvocationIdX), 0, 9);
  85. value = BitfieldInsert(value, Operation(OperationCode::LocalInvocationIdY), 16, 9);
  86. value = BitfieldInsert(value, Operation(OperationCode::LocalInvocationIdZ), 26, 5);
  87. return value;
  88. }
  89. case SystemVariable::TidX:
  90. return Operation(OperationCode::LocalInvocationIdX);
  91. case SystemVariable::TidY:
  92. return Operation(OperationCode::LocalInvocationIdY);
  93. case SystemVariable::TidZ:
  94. return Operation(OperationCode::LocalInvocationIdZ);
  95. case SystemVariable::CtaIdX:
  96. return Operation(OperationCode::WorkGroupIdX);
  97. case SystemVariable::CtaIdY:
  98. return Operation(OperationCode::WorkGroupIdY);
  99. case SystemVariable::CtaIdZ:
  100. return Operation(OperationCode::WorkGroupIdZ);
  101. case SystemVariable::EqMask:
  102. case SystemVariable::LtMask:
  103. case SystemVariable::LeMask:
  104. case SystemVariable::GtMask:
  105. case SystemVariable::GeMask:
  106. uses_warps = true;
  107. switch (instr.sys20) {
  108. case SystemVariable::EqMask:
  109. return Operation(OperationCode::ThreadEqMask);
  110. case SystemVariable::LtMask:
  111. return Operation(OperationCode::ThreadLtMask);
  112. case SystemVariable::LeMask:
  113. return Operation(OperationCode::ThreadLeMask);
  114. case SystemVariable::GtMask:
  115. return Operation(OperationCode::ThreadGtMask);
  116. case SystemVariable::GeMask:
  117. return Operation(OperationCode::ThreadGeMask);
  118. default:
  119. UNREACHABLE();
  120. return Immediate(0u);
  121. }
  122. default:
  123. UNIMPLEMENTED_MSG("Unhandled system move: {}",
  124. static_cast<u32>(instr.sys20.Value()));
  125. return Immediate(0u);
  126. }
  127. }();
  128. SetRegister(bb, instr.gpr0, value);
  129. break;
  130. }
  131. case OpCode::Id::BRA: {
  132. Node branch;
  133. if (instr.bra.constant_buffer == 0) {
  134. const u32 target = pc + instr.bra.GetBranchTarget();
  135. branch = Operation(OperationCode::Branch, Immediate(target));
  136. } else {
  137. const u32 target = pc + 1;
  138. const Node op_a = GetConstBuffer(instr.cbuf36.index, instr.cbuf36.GetOffset());
  139. const Node convert = SignedOperation(OperationCode::IArithmeticShiftRight, true,
  140. PRECISE, op_a, Immediate(3));
  141. const Node operand =
  142. Operation(OperationCode::IAdd, PRECISE, convert, Immediate(target));
  143. branch = Operation(OperationCode::BranchIndirect, operand);
  144. }
  145. const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
  146. if (cc != Tegra::Shader::ConditionCode::T) {
  147. bb.push_back(Conditional(GetConditionCode(cc), {branch}));
  148. } else {
  149. bb.push_back(branch);
  150. }
  151. break;
  152. }
  153. case OpCode::Id::BRX: {
  154. Node operand;
  155. if (instr.brx.constant_buffer != 0) {
  156. const s32 target = pc + 1;
  157. const Node index = GetRegister(instr.gpr8);
  158. const Node op_a =
  159. GetConstBufferIndirect(instr.cbuf36.index, instr.cbuf36.GetOffset() + 0, index);
  160. const Node convert = SignedOperation(OperationCode::IArithmeticShiftRight, true,
  161. PRECISE, op_a, Immediate(3));
  162. operand = Operation(OperationCode::IAdd, PRECISE, convert, Immediate(target));
  163. } else {
  164. const s32 target = pc + instr.brx.GetBranchExtend();
  165. const Node op_a = GetRegister(instr.gpr8);
  166. const Node convert = SignedOperation(OperationCode::IArithmeticShiftRight, true,
  167. PRECISE, op_a, Immediate(3));
  168. operand = Operation(OperationCode::IAdd, PRECISE, convert, Immediate(target));
  169. }
  170. const Node branch = Operation(OperationCode::BranchIndirect, operand);
  171. const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
  172. if (cc != Tegra::Shader::ConditionCode::T) {
  173. bb.push_back(Conditional(GetConditionCode(cc), {branch}));
  174. } else {
  175. bb.push_back(branch);
  176. }
  177. break;
  178. }
  179. case OpCode::Id::SSY: {
  180. UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0,
  181. "Constant buffer flow is not supported");
  182. if (disable_flow_stack) {
  183. break;
  184. }
  185. // The SSY opcode tells the GPU where to re-converge divergent execution paths with SYNC.
  186. const u32 target = pc + instr.bra.GetBranchTarget();
  187. bb.push_back(
  188. Operation(OperationCode::PushFlowStack, MetaStackClass::Ssy, Immediate(target)));
  189. break;
  190. }
  191. case OpCode::Id::PBK: {
  192. UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0,
  193. "Constant buffer PBK is not supported");
  194. if (disable_flow_stack) {
  195. break;
  196. }
  197. // PBK pushes to a stack the address where BRK will jump to.
  198. const u32 target = pc + instr.bra.GetBranchTarget();
  199. bb.push_back(
  200. Operation(OperationCode::PushFlowStack, MetaStackClass::Pbk, Immediate(target)));
  201. break;
  202. }
  203. case OpCode::Id::SYNC: {
  204. const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
  205. UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, "SYNC condition code used: {}",
  206. static_cast<u32>(cc));
  207. if (decompiled) {
  208. break;
  209. }
  210. // The SYNC opcode jumps to the address previously set by the SSY opcode
  211. bb.push_back(Operation(OperationCode::PopFlowStack, MetaStackClass::Ssy));
  212. break;
  213. }
  214. case OpCode::Id::BRK: {
  215. const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
  216. UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, "BRK condition code used: {}",
  217. static_cast<u32>(cc));
  218. if (decompiled) {
  219. break;
  220. }
  221. // The BRK opcode jumps to the address previously set by the PBK opcode
  222. bb.push_back(Operation(OperationCode::PopFlowStack, MetaStackClass::Pbk));
  223. break;
  224. }
  225. case OpCode::Id::IPA: {
  226. const bool is_physical = instr.ipa.idx && instr.gpr8.Value() != 0xff;
  227. const auto attribute = instr.attribute.fmt28;
  228. const Index index = attribute.index;
  229. Node value = is_physical ? GetPhysicalInputAttribute(instr.gpr8)
  230. : GetInputAttribute(index, attribute.element);
  231. // Code taken from Ryujinx.
  232. if (index >= Index::Attribute_0 && index <= Index::Attribute_31) {
  233. const u32 location = static_cast<u32>(index) - static_cast<u32>(Index::Attribute_0);
  234. if (header.ps.GetPixelImap(location) == PixelImap::Perspective) {
  235. Node position_w = GetInputAttribute(Index::Position, 3);
  236. value = Operation(OperationCode::FMul, move(value), move(position_w));
  237. }
  238. }
  239. if (instr.ipa.interp_mode == IpaInterpMode::Multiply) {
  240. value = Operation(OperationCode::FMul, move(value), GetRegister(instr.gpr20));
  241. }
  242. value = GetSaturatedFloat(move(value), instr.ipa.saturate);
  243. SetRegister(bb, instr.gpr0, move(value));
  244. break;
  245. }
  246. case OpCode::Id::OUT_R: {
  247. UNIMPLEMENTED_IF_MSG(instr.gpr20.Value() != Register::ZeroIndex,
  248. "Stream buffer is not supported");
  249. if (instr.out.emit) {
  250. // gpr0 is used to store the next address and gpr8 contains the address to emit.
  251. // Hardware uses pointers here but we just ignore it
  252. bb.push_back(Operation(OperationCode::EmitVertex));
  253. SetRegister(bb, instr.gpr0, Immediate(0));
  254. }
  255. if (instr.out.cut) {
  256. bb.push_back(Operation(OperationCode::EndPrimitive));
  257. }
  258. break;
  259. }
  260. case OpCode::Id::ISBERD: {
  261. UNIMPLEMENTED_IF(instr.isberd.o != 0);
  262. UNIMPLEMENTED_IF(instr.isberd.skew != 0);
  263. UNIMPLEMENTED_IF(instr.isberd.shift != Tegra::Shader::IsberdShift::None);
  264. UNIMPLEMENTED_IF(instr.isberd.mode != Tegra::Shader::IsberdMode::None);
  265. LOG_WARNING(HW_GPU, "ISBERD instruction is incomplete");
  266. SetRegister(bb, instr.gpr0, GetRegister(instr.gpr8));
  267. break;
  268. }
  269. case OpCode::Id::MEMBAR: {
  270. UNIMPLEMENTED_IF(instr.membar.type != Tegra::Shader::MembarType::GL);
  271. UNIMPLEMENTED_IF(instr.membar.unknown != Tegra::Shader::MembarUnknown::Default);
  272. bb.push_back(Operation(OperationCode::MemoryBarrierGL));
  273. break;
  274. }
  275. case OpCode::Id::DEPBAR: {
  276. LOG_DEBUG(HW_GPU, "DEPBAR instruction is stubbed");
  277. break;
  278. }
  279. default:
  280. UNIMPLEMENTED_MSG("Unhandled instruction: {}", opcode->get().GetName());
  281. }
  282. return pc;
  283. }
  284. } // namespace VideoCommon::Shader