shader_interpreter.cpp 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <array>
  6. #include <cmath>
  7. #include <numeric>
  8. #include <boost/container/static_vector.hpp>
  9. #include <nihstro/shader_bytecode.h>
  10. #include "common/assert.h"
  11. #include "common/common_types.h"
  12. #include "common/logging/log.h"
  13. #include "common/vector_math.h"
  14. #include "video_core/pica_state.h"
  15. #include "video_core/pica_types.h"
  16. #include "video_core/shader/shader.h"
  17. #include "video_core/shader/shader_interpreter.h"
  18. using nihstro::OpCode;
  19. using nihstro::Instruction;
  20. using nihstro::RegisterType;
  21. using nihstro::SourceRegister;
  22. using nihstro::SwizzlePattern;
  23. namespace Pica {
  24. namespace Shader {
  25. constexpr u32 INVALID_ADDRESS = 0xFFFFFFFF;
  26. struct CallStackElement {
  27. u32 final_address; // Address upon which we jump to return_address
  28. u32 return_address; // Where to jump when leaving scope
  29. u8 repeat_counter; // How often to repeat until this call stack element is removed
  30. u8 loop_increment; // Which value to add to the loop counter after an iteration
  31. // TODO: Should this be a signed value? Does it even matter?
  32. u32 loop_address; // The address where we'll return to after each loop iteration
  33. };
  34. template <bool Debug>
  35. void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned offset) {
  36. // TODO: Is there a maximal size for this?
  37. boost::container::static_vector<CallStackElement, 16> call_stack;
  38. u32 program_counter = offset;
  39. auto call = [&program_counter, &call_stack](u32 offset, u32 num_instructions, u32 return_offset,
  40. u8 repeat_count, u8 loop_increment) {
  41. // -1 to make sure when incrementing the PC we end up at the correct offset
  42. program_counter = offset - 1;
  43. ASSERT(call_stack.size() < call_stack.capacity());
  44. call_stack.push_back(
  45. {offset + num_instructions, return_offset, repeat_count, loop_increment, offset});
  46. };
  47. auto evaluate_condition = [&state](Instruction::FlowControlType flow_control) {
  48. using Op = Instruction::FlowControlType::Op;
  49. bool result_x = flow_control.refx.Value() == state.conditional_code[0];
  50. bool result_y = flow_control.refy.Value() == state.conditional_code[1];
  51. switch (flow_control.op) {
  52. case Op::Or:
  53. return result_x || result_y;
  54. case Op::And:
  55. return result_x && result_y;
  56. case Op::JustX:
  57. return result_x;
  58. case Op::JustY:
  59. return result_y;
  60. default:
  61. UNREACHABLE();
  62. return false;
  63. }
  64. };
  65. const auto& uniforms = g_state.vs.uniforms;
  66. const auto& swizzle_data = g_state.vs.swizzle_data;
  67. const auto& program_code = g_state.vs.program_code;
  68. // Placeholder for invalid inputs
  69. static float24 dummy_vec4_float24[4];
  70. unsigned iteration = 0;
  71. bool exit_loop = false;
  72. while (!exit_loop) {
  73. if (!call_stack.empty()) {
  74. auto& top = call_stack.back();
  75. if (program_counter == top.final_address) {
  76. state.address_registers[2] += top.loop_increment;
  77. if (top.repeat_counter-- == 0) {
  78. program_counter = top.return_address;
  79. call_stack.pop_back();
  80. } else {
  81. program_counter = top.loop_address;
  82. }
  83. // TODO: Is "trying again" accurate to hardware?
  84. continue;
  85. }
  86. }
  87. const Instruction instr = {program_code[program_counter]};
  88. const SwizzlePattern swizzle = {swizzle_data[instr.common.operand_desc_id]};
  89. Record<DebugDataRecord::CUR_INSTR>(state.debug, iteration, program_counter);
  90. if (iteration > 0)
  91. Record<DebugDataRecord::NEXT_INSTR>(state.debug, iteration - 1, program_counter);
  92. state.debug.max_offset = std::max<u32>(state.debug.max_offset, 1 + program_counter);
  93. auto LookupSourceRegister = [&](const SourceRegister& source_reg) -> const float24* {
  94. switch (source_reg.GetRegisterType()) {
  95. case RegisterType::Input:
  96. return &state.registers.input[source_reg.GetIndex()].x;
  97. case RegisterType::Temporary:
  98. return &state.registers.temporary[source_reg.GetIndex()].x;
  99. case RegisterType::FloatUniform:
  100. return &uniforms.f[source_reg.GetIndex()].x;
  101. default:
  102. return dummy_vec4_float24;
  103. }
  104. };
  105. switch (instr.opcode.Value().GetInfo().type) {
  106. case OpCode::Type::Arithmetic: {
  107. const bool is_inverted =
  108. (0 != (instr.opcode.Value().GetInfo().subtype & OpCode::Info::SrcInversed));
  109. const int address_offset =
  110. (instr.common.address_register_index == 0)
  111. ? 0
  112. : state.address_registers[instr.common.address_register_index - 1];
  113. const float24* src1_ = LookupSourceRegister(instr.common.GetSrc1(is_inverted) +
  114. (is_inverted ? 0 : address_offset));
  115. const float24* src2_ = LookupSourceRegister(instr.common.GetSrc2(is_inverted) +
  116. (is_inverted ? address_offset : 0));
  117. const bool negate_src1 = ((bool)swizzle.negate_src1 != false);
  118. const bool negate_src2 = ((bool)swizzle.negate_src2 != false);
  119. float24 src1[4] = {
  120. src1_[(int)swizzle.src1_selector_0.Value()],
  121. src1_[(int)swizzle.src1_selector_1.Value()],
  122. src1_[(int)swizzle.src1_selector_2.Value()],
  123. src1_[(int)swizzle.src1_selector_3.Value()],
  124. };
  125. if (negate_src1) {
  126. src1[0] = -src1[0];
  127. src1[1] = -src1[1];
  128. src1[2] = -src1[2];
  129. src1[3] = -src1[3];
  130. }
  131. float24 src2[4] = {
  132. src2_[(int)swizzle.src2_selector_0.Value()],
  133. src2_[(int)swizzle.src2_selector_1.Value()],
  134. src2_[(int)swizzle.src2_selector_2.Value()],
  135. src2_[(int)swizzle.src2_selector_3.Value()],
  136. };
  137. if (negate_src2) {
  138. src2[0] = -src2[0];
  139. src2[1] = -src2[1];
  140. src2[2] = -src2[2];
  141. src2[3] = -src2[3];
  142. }
  143. float24* dest =
  144. (instr.common.dest.Value() < 0x10)
  145. ? &state.output_registers.value[instr.common.dest.Value().GetIndex()][0]
  146. : (instr.common.dest.Value() < 0x20)
  147. ? &state.registers.temporary[instr.common.dest.Value().GetIndex()][0]
  148. : dummy_vec4_float24;
  149. state.debug.max_opdesc_id =
  150. std::max<u32>(state.debug.max_opdesc_id, 1 + instr.common.operand_desc_id);
  151. switch (instr.opcode.Value().EffectiveOpCode()) {
  152. case OpCode::Id::ADD: {
  153. Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
  154. Record<DebugDataRecord::SRC2>(state.debug, iteration, src2);
  155. Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
  156. for (int i = 0; i < 4; ++i) {
  157. if (!swizzle.DestComponentEnabled(i))
  158. continue;
  159. dest[i] = src1[i] + src2[i];
  160. }
  161. Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
  162. break;
  163. }
  164. case OpCode::Id::MUL: {
  165. Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
  166. Record<DebugDataRecord::SRC2>(state.debug, iteration, src2);
  167. Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
  168. for (int i = 0; i < 4; ++i) {
  169. if (!swizzle.DestComponentEnabled(i))
  170. continue;
  171. dest[i] = src1[i] * src2[i];
  172. }
  173. Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
  174. break;
  175. }
  176. case OpCode::Id::FLR:
  177. Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
  178. Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
  179. for (int i = 0; i < 4; ++i) {
  180. if (!swizzle.DestComponentEnabled(i))
  181. continue;
  182. dest[i] = float24::FromFloat32(std::floor(src1[i].ToFloat32()));
  183. }
  184. Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
  185. break;
  186. case OpCode::Id::MAX:
  187. Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
  188. Record<DebugDataRecord::SRC2>(state.debug, iteration, src2);
  189. Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
  190. for (int i = 0; i < 4; ++i) {
  191. if (!swizzle.DestComponentEnabled(i))
  192. continue;
  193. // NOTE: Exact form required to match NaN semantics to hardware:
  194. // max(0, NaN) -> NaN
  195. // max(NaN, 0) -> 0
  196. dest[i] = (src1[i] > src2[i]) ? src1[i] : src2[i];
  197. }
  198. Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
  199. break;
  200. case OpCode::Id::MIN:
  201. Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
  202. Record<DebugDataRecord::SRC2>(state.debug, iteration, src2);
  203. Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
  204. for (int i = 0; i < 4; ++i) {
  205. if (!swizzle.DestComponentEnabled(i))
  206. continue;
  207. // NOTE: Exact form required to match NaN semantics to hardware:
  208. // min(0, NaN) -> NaN
  209. // min(NaN, 0) -> 0
  210. dest[i] = (src1[i] < src2[i]) ? src1[i] : src2[i];
  211. }
  212. Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
  213. break;
  214. case OpCode::Id::DP3:
  215. case OpCode::Id::DP4:
  216. case OpCode::Id::DPH:
  217. case OpCode::Id::DPHI: {
  218. Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
  219. Record<DebugDataRecord::SRC2>(state.debug, iteration, src2);
  220. Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
  221. OpCode::Id opcode = instr.opcode.Value().EffectiveOpCode();
  222. if (opcode == OpCode::Id::DPH || opcode == OpCode::Id::DPHI)
  223. src1[3] = float24::FromFloat32(1.0f);
  224. int num_components = (opcode == OpCode::Id::DP3) ? 3 : 4;
  225. float24 dot = std::inner_product(src1, src1 + num_components, src2,
  226. float24::FromFloat32(0.f));
  227. for (int i = 0; i < 4; ++i) {
  228. if (!swizzle.DestComponentEnabled(i))
  229. continue;
  230. dest[i] = dot;
  231. }
  232. Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
  233. break;
  234. }
  235. // Reciprocal
  236. case OpCode::Id::RCP: {
  237. Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
  238. Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
  239. float24 rcp_res = float24::FromFloat32(1.0f / src1[0].ToFloat32());
  240. for (int i = 0; i < 4; ++i) {
  241. if (!swizzle.DestComponentEnabled(i))
  242. continue;
  243. dest[i] = rcp_res;
  244. }
  245. Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
  246. break;
  247. }
  248. // Reciprocal Square Root
  249. case OpCode::Id::RSQ: {
  250. Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
  251. Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
  252. float24 rsq_res = float24::FromFloat32(1.0f / std::sqrt(src1[0].ToFloat32()));
  253. for (int i = 0; i < 4; ++i) {
  254. if (!swizzle.DestComponentEnabled(i))
  255. continue;
  256. dest[i] = rsq_res;
  257. }
  258. Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
  259. break;
  260. }
  261. case OpCode::Id::MOVA: {
  262. Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
  263. for (int i = 0; i < 2; ++i) {
  264. if (!swizzle.DestComponentEnabled(i))
  265. continue;
  266. // TODO: Figure out how the rounding is done on hardware
  267. state.address_registers[i] = static_cast<s32>(src1[i].ToFloat32());
  268. }
  269. Record<DebugDataRecord::ADDR_REG_OUT>(state.debug, iteration,
  270. state.address_registers);
  271. break;
  272. }
  273. case OpCode::Id::MOV: {
  274. Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
  275. Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
  276. for (int i = 0; i < 4; ++i) {
  277. if (!swizzle.DestComponentEnabled(i))
  278. continue;
  279. dest[i] = src1[i];
  280. }
  281. Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
  282. break;
  283. }
  284. case OpCode::Id::SGE:
  285. case OpCode::Id::SGEI:
  286. Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
  287. Record<DebugDataRecord::SRC2>(state.debug, iteration, src2);
  288. Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
  289. for (int i = 0; i < 4; ++i) {
  290. if (!swizzle.DestComponentEnabled(i))
  291. continue;
  292. dest[i] = (src1[i] >= src2[i]) ? float24::FromFloat32(1.0f)
  293. : float24::FromFloat32(0.0f);
  294. }
  295. Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
  296. break;
  297. case OpCode::Id::SLT:
  298. case OpCode::Id::SLTI:
  299. Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
  300. Record<DebugDataRecord::SRC2>(state.debug, iteration, src2);
  301. Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
  302. for (int i = 0; i < 4; ++i) {
  303. if (!swizzle.DestComponentEnabled(i))
  304. continue;
  305. dest[i] = (src1[i] < src2[i]) ? float24::FromFloat32(1.0f)
  306. : float24::FromFloat32(0.0f);
  307. }
  308. Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
  309. break;
  310. case OpCode::Id::CMP:
  311. Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
  312. Record<DebugDataRecord::SRC2>(state.debug, iteration, src2);
  313. for (int i = 0; i < 2; ++i) {
  314. // TODO: Can you restrict to one compare via dest masking?
  315. auto compare_op = instr.common.compare_op;
  316. auto op = (i == 0) ? compare_op.x.Value() : compare_op.y.Value();
  317. switch (op) {
  318. case Instruction::Common::CompareOpType::Equal:
  319. state.conditional_code[i] = (src1[i] == src2[i]);
  320. break;
  321. case Instruction::Common::CompareOpType::NotEqual:
  322. state.conditional_code[i] = (src1[i] != src2[i]);
  323. break;
  324. case Instruction::Common::CompareOpType::LessThan:
  325. state.conditional_code[i] = (src1[i] < src2[i]);
  326. break;
  327. case Instruction::Common::CompareOpType::LessEqual:
  328. state.conditional_code[i] = (src1[i] <= src2[i]);
  329. break;
  330. case Instruction::Common::CompareOpType::GreaterThan:
  331. state.conditional_code[i] = (src1[i] > src2[i]);
  332. break;
  333. case Instruction::Common::CompareOpType::GreaterEqual:
  334. state.conditional_code[i] = (src1[i] >= src2[i]);
  335. break;
  336. default:
  337. LOG_ERROR(HW_GPU, "Unknown compare mode %x", static_cast<int>(op));
  338. break;
  339. }
  340. }
  341. Record<DebugDataRecord::CMP_RESULT>(state.debug, iteration, state.conditional_code);
  342. break;
  343. case OpCode::Id::EX2: {
  344. Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
  345. Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
  346. // EX2 only takes first component exp2 and writes it to all dest components
  347. float24 ex2_res = float24::FromFloat32(std::exp2(src1[0].ToFloat32()));
  348. for (int i = 0; i < 4; ++i) {
  349. if (!swizzle.DestComponentEnabled(i))
  350. continue;
  351. dest[i] = ex2_res;
  352. }
  353. Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
  354. break;
  355. }
  356. case OpCode::Id::LG2: {
  357. Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
  358. Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
  359. // LG2 only takes the first component log2 and writes it to all dest components
  360. float24 lg2_res = float24::FromFloat32(std::log2(src1[0].ToFloat32()));
  361. for (int i = 0; i < 4; ++i) {
  362. if (!swizzle.DestComponentEnabled(i))
  363. continue;
  364. dest[i] = lg2_res;
  365. }
  366. Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
  367. break;
  368. }
  369. default:
  370. LOG_ERROR(HW_GPU, "Unhandled arithmetic instruction: 0x%02x (%s): 0x%08x",
  371. (int)instr.opcode.Value().EffectiveOpCode(),
  372. instr.opcode.Value().GetInfo().name, instr.hex);
  373. DEBUG_ASSERT(false);
  374. break;
  375. }
  376. break;
  377. }
  378. case OpCode::Type::MultiplyAdd: {
  379. if ((instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MAD) ||
  380. (instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MADI)) {
  381. const SwizzlePattern& swizzle = *reinterpret_cast<const SwizzlePattern*>(
  382. &swizzle_data[instr.mad.operand_desc_id]);
  383. bool is_inverted = (instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MADI);
  384. const int address_offset =
  385. (instr.mad.address_register_index == 0)
  386. ? 0
  387. : state.address_registers[instr.mad.address_register_index - 1];
  388. const float24* src1_ = LookupSourceRegister(instr.mad.GetSrc1(is_inverted));
  389. const float24* src2_ = LookupSourceRegister(instr.mad.GetSrc2(is_inverted) +
  390. (!is_inverted * address_offset));
  391. const float24* src3_ = LookupSourceRegister(instr.mad.GetSrc3(is_inverted) +
  392. (is_inverted * address_offset));
  393. const bool negate_src1 = ((bool)swizzle.negate_src1 != false);
  394. const bool negate_src2 = ((bool)swizzle.negate_src2 != false);
  395. const bool negate_src3 = ((bool)swizzle.negate_src3 != false);
  396. float24 src1[4] = {
  397. src1_[(int)swizzle.src1_selector_0.Value()],
  398. src1_[(int)swizzle.src1_selector_1.Value()],
  399. src1_[(int)swizzle.src1_selector_2.Value()],
  400. src1_[(int)swizzle.src1_selector_3.Value()],
  401. };
  402. if (negate_src1) {
  403. src1[0] = -src1[0];
  404. src1[1] = -src1[1];
  405. src1[2] = -src1[2];
  406. src1[3] = -src1[3];
  407. }
  408. float24 src2[4] = {
  409. src2_[(int)swizzle.src2_selector_0.Value()],
  410. src2_[(int)swizzle.src2_selector_1.Value()],
  411. src2_[(int)swizzle.src2_selector_2.Value()],
  412. src2_[(int)swizzle.src2_selector_3.Value()],
  413. };
  414. if (negate_src2) {
  415. src2[0] = -src2[0];
  416. src2[1] = -src2[1];
  417. src2[2] = -src2[2];
  418. src2[3] = -src2[3];
  419. }
  420. float24 src3[4] = {
  421. src3_[(int)swizzle.src3_selector_0.Value()],
  422. src3_[(int)swizzle.src3_selector_1.Value()],
  423. src3_[(int)swizzle.src3_selector_2.Value()],
  424. src3_[(int)swizzle.src3_selector_3.Value()],
  425. };
  426. if (negate_src3) {
  427. src3[0] = -src3[0];
  428. src3[1] = -src3[1];
  429. src3[2] = -src3[2];
  430. src3[3] = -src3[3];
  431. }
  432. float24* dest =
  433. (instr.mad.dest.Value() < 0x10)
  434. ? &state.output_registers.value[instr.mad.dest.Value().GetIndex()][0]
  435. : (instr.mad.dest.Value() < 0x20)
  436. ? &state.registers.temporary[instr.mad.dest.Value().GetIndex()][0]
  437. : dummy_vec4_float24;
  438. Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
  439. Record<DebugDataRecord::SRC2>(state.debug, iteration, src2);
  440. Record<DebugDataRecord::SRC3>(state.debug, iteration, src3);
  441. Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
  442. for (int i = 0; i < 4; ++i) {
  443. if (!swizzle.DestComponentEnabled(i))
  444. continue;
  445. dest[i] = src1[i] * src2[i] + src3[i];
  446. }
  447. Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
  448. } else {
  449. LOG_ERROR(HW_GPU, "Unhandled multiply-add instruction: 0x%02x (%s): 0x%08x",
  450. (int)instr.opcode.Value().EffectiveOpCode(),
  451. instr.opcode.Value().GetInfo().name, instr.hex);
  452. }
  453. break;
  454. }
  455. default: {
  456. // Handle each instruction on its own
  457. switch (instr.opcode.Value()) {
  458. case OpCode::Id::END:
  459. exit_loop = true;
  460. break;
  461. case OpCode::Id::JMPC:
  462. Record<DebugDataRecord::COND_CMP_IN>(state.debug, iteration,
  463. state.conditional_code);
  464. if (evaluate_condition(instr.flow_control)) {
  465. program_counter = instr.flow_control.dest_offset - 1;
  466. }
  467. break;
  468. case OpCode::Id::JMPU:
  469. Record<DebugDataRecord::COND_BOOL_IN>(
  470. state.debug, iteration, uniforms.b[instr.flow_control.bool_uniform_id]);
  471. if (uniforms.b[instr.flow_control.bool_uniform_id] ==
  472. !(instr.flow_control.num_instructions & 1)) {
  473. program_counter = instr.flow_control.dest_offset - 1;
  474. }
  475. break;
  476. case OpCode::Id::CALL:
  477. call(instr.flow_control.dest_offset, instr.flow_control.num_instructions,
  478. program_counter + 1, 0, 0);
  479. break;
  480. case OpCode::Id::CALLU:
  481. Record<DebugDataRecord::COND_BOOL_IN>(
  482. state.debug, iteration, uniforms.b[instr.flow_control.bool_uniform_id]);
  483. if (uniforms.b[instr.flow_control.bool_uniform_id]) {
  484. call(instr.flow_control.dest_offset, instr.flow_control.num_instructions,
  485. program_counter + 1, 0, 0);
  486. }
  487. break;
  488. case OpCode::Id::CALLC:
  489. Record<DebugDataRecord::COND_CMP_IN>(state.debug, iteration,
  490. state.conditional_code);
  491. if (evaluate_condition(instr.flow_control)) {
  492. call(instr.flow_control.dest_offset, instr.flow_control.num_instructions,
  493. program_counter + 1, 0, 0);
  494. }
  495. break;
  496. case OpCode::Id::NOP:
  497. break;
  498. case OpCode::Id::IFU:
  499. Record<DebugDataRecord::COND_BOOL_IN>(
  500. state.debug, iteration, uniforms.b[instr.flow_control.bool_uniform_id]);
  501. if (uniforms.b[instr.flow_control.bool_uniform_id]) {
  502. call(program_counter + 1, instr.flow_control.dest_offset - program_counter - 1,
  503. instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0,
  504. 0);
  505. } else {
  506. call(instr.flow_control.dest_offset, instr.flow_control.num_instructions,
  507. instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0,
  508. 0);
  509. }
  510. break;
  511. case OpCode::Id::IFC: {
  512. // TODO: Do we need to consider swizzlers here?
  513. Record<DebugDataRecord::COND_CMP_IN>(state.debug, iteration,
  514. state.conditional_code);
  515. if (evaluate_condition(instr.flow_control)) {
  516. call(program_counter + 1, instr.flow_control.dest_offset - program_counter - 1,
  517. instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0,
  518. 0);
  519. } else {
  520. call(instr.flow_control.dest_offset, instr.flow_control.num_instructions,
  521. instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0,
  522. 0);
  523. }
  524. break;
  525. }
  526. case OpCode::Id::LOOP: {
  527. Math::Vec4<u8> loop_param(uniforms.i[instr.flow_control.int_uniform_id].x,
  528. uniforms.i[instr.flow_control.int_uniform_id].y,
  529. uniforms.i[instr.flow_control.int_uniform_id].z,
  530. uniforms.i[instr.flow_control.int_uniform_id].w);
  531. state.address_registers[2] = loop_param.y;
  532. Record<DebugDataRecord::LOOP_INT_IN>(state.debug, iteration, loop_param);
  533. call(program_counter + 1, instr.flow_control.dest_offset - program_counter + 1,
  534. instr.flow_control.dest_offset + 1, loop_param.x, loop_param.z);
  535. break;
  536. }
  537. default:
  538. LOG_ERROR(HW_GPU, "Unhandled instruction: 0x%02x (%s): 0x%08x",
  539. (int)instr.opcode.Value().EffectiveOpCode(),
  540. instr.opcode.Value().GetInfo().name, instr.hex);
  541. break;
  542. }
  543. break;
  544. }
  545. }
  546. ++program_counter;
  547. ++iteration;
  548. }
  549. }
  550. // Explicit instantiation
  551. template void RunInterpreter(const ShaderSetup& setup, UnitState<false>& state, unsigned offset);
  552. template void RunInterpreter(const ShaderSetup& setup, UnitState<true>& state, unsigned offset);
  553. } // namespace
  554. } // namespace