shader_interpreter.cpp 28 KB

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