shader_ir.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. // Copyright 2018 yuzu 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 "common/assert.h"
  8. #include "common/common_types.h"
  9. #include "common/logging/log.h"
  10. #include "video_core/engines/shader_bytecode.h"
  11. #include "video_core/shader/node_helper.h"
  12. #include "video_core/shader/registry.h"
  13. #include "video_core/shader/shader_ir.h"
  14. namespace VideoCommon::Shader {
  15. using Tegra::Shader::Attribute;
  16. using Tegra::Shader::Instruction;
  17. using Tegra::Shader::IpaMode;
  18. using Tegra::Shader::Pred;
  19. using Tegra::Shader::PredCondition;
  20. using Tegra::Shader::PredOperation;
  21. using Tegra::Shader::Register;
  22. ShaderIR::ShaderIR(const ProgramCode& program_code, u32 main_offset, CompilerSettings settings,
  23. Registry& registry)
  24. : program_code{program_code}, main_offset{main_offset}, settings{settings}, registry{registry} {
  25. Decode();
  26. PostDecode();
  27. }
  28. ShaderIR::~ShaderIR() = default;
  29. Node ShaderIR::GetRegister(Register reg) {
  30. if (reg != Register::ZeroIndex) {
  31. used_registers.insert(static_cast<u32>(reg));
  32. }
  33. return MakeNode<GprNode>(reg);
  34. }
  35. Node ShaderIR::GetCustomVariable(u32 id) {
  36. return MakeNode<CustomVarNode>(id);
  37. }
  38. Node ShaderIR::GetImmediate19(Instruction instr) {
  39. return Immediate(instr.alu.GetImm20_19());
  40. }
  41. Node ShaderIR::GetImmediate32(Instruction instr) {
  42. return Immediate(instr.alu.GetImm20_32());
  43. }
  44. Node ShaderIR::GetConstBuffer(u64 index_, u64 offset_) {
  45. const auto index = static_cast<u32>(index_);
  46. const auto offset = static_cast<u32>(offset_);
  47. const auto [entry, is_new] = used_cbufs.try_emplace(index);
  48. entry->second.MarkAsUsed(offset);
  49. return MakeNode<CbufNode>(index, Immediate(offset));
  50. }
  51. Node ShaderIR::GetConstBufferIndirect(u64 index_, u64 offset_, Node node) {
  52. const auto index = static_cast<u32>(index_);
  53. const auto offset = static_cast<u32>(offset_);
  54. const auto [entry, is_new] = used_cbufs.try_emplace(index);
  55. entry->second.MarkAsUsedIndirect();
  56. Node final_offset = [&] {
  57. // Attempt to inline constant buffer without a variable offset. This is done to allow
  58. // tracking LDC calls.
  59. if (const auto gpr = std::get_if<GprNode>(&*node)) {
  60. if (gpr->GetIndex() == Register::ZeroIndex) {
  61. return Immediate(offset);
  62. }
  63. }
  64. return Operation(OperationCode::UAdd, NO_PRECISE, std::move(node), Immediate(offset));
  65. }();
  66. return MakeNode<CbufNode>(index, std::move(final_offset));
  67. }
  68. Node ShaderIR::GetPredicate(u64 pred_, bool negated) {
  69. const auto pred = static_cast<Pred>(pred_);
  70. if (pred != Pred::UnusedIndex && pred != Pred::NeverExecute) {
  71. used_predicates.insert(pred);
  72. }
  73. return MakeNode<PredicateNode>(pred, negated);
  74. }
  75. Node ShaderIR::GetPredicate(bool immediate) {
  76. return GetPredicate(static_cast<u64>(immediate ? Pred::UnusedIndex : Pred::NeverExecute));
  77. }
  78. Node ShaderIR::GetInputAttribute(Attribute::Index index, u64 element, Node buffer) {
  79. MarkAttributeUsage(index, element);
  80. used_input_attributes.emplace(index);
  81. return MakeNode<AbufNode>(index, static_cast<u32>(element), std::move(buffer));
  82. }
  83. Node ShaderIR::GetPhysicalInputAttribute(Tegra::Shader::Register physical_address, Node buffer) {
  84. uses_physical_attributes = true;
  85. return MakeNode<AbufNode>(GetRegister(physical_address), buffer);
  86. }
  87. Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buffer) {
  88. MarkAttributeUsage(index, element);
  89. used_output_attributes.insert(index);
  90. return MakeNode<AbufNode>(index, static_cast<u32>(element), std::move(buffer));
  91. }
  92. Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) const {
  93. const Node node = MakeNode<InternalFlagNode>(flag);
  94. if (negated) {
  95. return Operation(OperationCode::LogicalNegate, node);
  96. }
  97. return node;
  98. }
  99. Node ShaderIR::GetLocalMemory(Node address) {
  100. return MakeNode<LmemNode>(std::move(address));
  101. }
  102. Node ShaderIR::GetSharedMemory(Node address) {
  103. return MakeNode<SmemNode>(std::move(address));
  104. }
  105. Node ShaderIR::GetTemporary(u32 id) {
  106. return GetRegister(Register::ZeroIndex + 1 + id);
  107. }
  108. Node ShaderIR::GetOperandAbsNegFloat(Node value, bool absolute, bool negate) {
  109. if (absolute) {
  110. value = Operation(OperationCode::FAbsolute, NO_PRECISE, std::move(value));
  111. }
  112. if (negate) {
  113. value = Operation(OperationCode::FNegate, NO_PRECISE, std::move(value));
  114. }
  115. return value;
  116. }
  117. Node ShaderIR::GetSaturatedFloat(Node value, bool saturate) {
  118. if (!saturate) {
  119. return value;
  120. }
  121. Node positive_zero = Immediate(std::copysignf(0, 1));
  122. Node positive_one = Immediate(1.0f);
  123. return Operation(OperationCode::FClamp, NO_PRECISE, std::move(value), std::move(positive_zero),
  124. std::move(positive_one));
  125. }
  126. Node ShaderIR::ConvertIntegerSize(Node value, Register::Size size, bool is_signed) {
  127. switch (size) {
  128. case Register::Size::Byte:
  129. value = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed, NO_PRECISE,
  130. std::move(value), Immediate(24));
  131. value = SignedOperation(OperationCode::IArithmeticShiftRight, is_signed, NO_PRECISE,
  132. std::move(value), Immediate(24));
  133. return value;
  134. case Register::Size::Short:
  135. value = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed, NO_PRECISE,
  136. std::move(value), Immediate(16));
  137. value = SignedOperation(OperationCode::IArithmeticShiftRight, is_signed, NO_PRECISE,
  138. std::move(value), Immediate(16));
  139. case Register::Size::Word:
  140. // Default - do nothing
  141. return value;
  142. default:
  143. UNREACHABLE_MSG("Unimplemented conversion size: {}", static_cast<u32>(size));
  144. return value;
  145. }
  146. }
  147. Node ShaderIR::GetOperandAbsNegInteger(Node value, bool absolute, bool negate, bool is_signed) {
  148. if (!is_signed) {
  149. // Absolute or negate on an unsigned is pointless
  150. return value;
  151. }
  152. if (absolute) {
  153. value = Operation(OperationCode::IAbsolute, NO_PRECISE, std::move(value));
  154. }
  155. if (negate) {
  156. value = Operation(OperationCode::INegate, NO_PRECISE, std::move(value));
  157. }
  158. return value;
  159. }
  160. Node ShaderIR::UnpackHalfImmediate(Instruction instr, bool has_negation) {
  161. Node value = Immediate(instr.half_imm.PackImmediates());
  162. if (!has_negation) {
  163. return value;
  164. }
  165. Node first_negate = GetPredicate(instr.half_imm.first_negate != 0);
  166. Node second_negate = GetPredicate(instr.half_imm.second_negate != 0);
  167. return Operation(OperationCode::HNegate, NO_PRECISE, std::move(value), std::move(first_negate),
  168. std::move(second_negate));
  169. }
  170. Node ShaderIR::UnpackHalfFloat(Node value, Tegra::Shader::HalfType type) {
  171. return Operation(OperationCode::HUnpack, type, std::move(value));
  172. }
  173. Node ShaderIR::HalfMerge(Node dest, Node src, Tegra::Shader::HalfMerge merge) {
  174. switch (merge) {
  175. case Tegra::Shader::HalfMerge::H0_H1:
  176. return src;
  177. case Tegra::Shader::HalfMerge::F32:
  178. return Operation(OperationCode::HMergeF32, std::move(src));
  179. case Tegra::Shader::HalfMerge::Mrg_H0:
  180. return Operation(OperationCode::HMergeH0, std::move(dest), std::move(src));
  181. case Tegra::Shader::HalfMerge::Mrg_H1:
  182. return Operation(OperationCode::HMergeH1, std::move(dest), std::move(src));
  183. }
  184. UNREACHABLE();
  185. return src;
  186. }
  187. Node ShaderIR::GetOperandAbsNegHalf(Node value, bool absolute, bool negate) {
  188. if (absolute) {
  189. value = Operation(OperationCode::HAbsolute, NO_PRECISE, std::move(value));
  190. }
  191. if (negate) {
  192. value = Operation(OperationCode::HNegate, NO_PRECISE, std::move(value), GetPredicate(true),
  193. GetPredicate(true));
  194. }
  195. return value;
  196. }
  197. Node ShaderIR::GetSaturatedHalfFloat(Node value, bool saturate) {
  198. if (!saturate) {
  199. return value;
  200. }
  201. Node positive_zero = Immediate(std::copysignf(0, 1));
  202. Node positive_one = Immediate(1.0f);
  203. return Operation(OperationCode::HClamp, NO_PRECISE, std::move(value), std::move(positive_zero),
  204. std::move(positive_one));
  205. }
  206. Node ShaderIR::GetPredicateComparisonFloat(PredCondition condition, Node op_a, Node op_b) {
  207. static constexpr std::array comparison_table{
  208. std::pair{PredCondition::LessThan, OperationCode::LogicalFLessThan},
  209. std::pair{PredCondition::Equal, OperationCode::LogicalFEqual},
  210. std::pair{PredCondition::LessEqual, OperationCode::LogicalFLessEqual},
  211. std::pair{PredCondition::GreaterThan, OperationCode::LogicalFGreaterThan},
  212. std::pair{PredCondition::NotEqual, OperationCode::LogicalFNotEqual},
  213. std::pair{PredCondition::GreaterEqual, OperationCode::LogicalFGreaterEqual},
  214. std::pair{PredCondition::LessThanWithNan, OperationCode::LogicalFLessThan},
  215. std::pair{PredCondition::NotEqualWithNan, OperationCode::LogicalFNotEqual},
  216. std::pair{PredCondition::LessEqualWithNan, OperationCode::LogicalFLessEqual},
  217. std::pair{PredCondition::GreaterThanWithNan, OperationCode::LogicalFGreaterThan},
  218. std::pair{PredCondition::GreaterEqualWithNan, OperationCode::LogicalFGreaterEqual},
  219. };
  220. const auto comparison =
  221. std::find_if(comparison_table.cbegin(), comparison_table.cend(),
  222. [condition](const auto entry) { return condition == entry.first; });
  223. UNIMPLEMENTED_IF_MSG(comparison == comparison_table.cend(),
  224. "Unknown predicate comparison operation");
  225. Node predicate = Operation(comparison->second, NO_PRECISE, op_a, op_b);
  226. if (condition == PredCondition::LessThanWithNan ||
  227. condition == PredCondition::NotEqualWithNan ||
  228. condition == PredCondition::LessEqualWithNan ||
  229. condition == PredCondition::GreaterThanWithNan ||
  230. condition == PredCondition::GreaterEqualWithNan) {
  231. predicate = Operation(OperationCode::LogicalOr, predicate,
  232. Operation(OperationCode::LogicalFIsNan, op_a));
  233. predicate = Operation(OperationCode::LogicalOr, predicate,
  234. Operation(OperationCode::LogicalFIsNan, op_b));
  235. }
  236. return predicate;
  237. }
  238. Node ShaderIR::GetPredicateComparisonInteger(PredCondition condition, bool is_signed, Node op_a,
  239. Node op_b) {
  240. static constexpr std::array comparison_table{
  241. std::pair{PredCondition::LessThan, OperationCode::LogicalILessThan},
  242. std::pair{PredCondition::Equal, OperationCode::LogicalIEqual},
  243. std::pair{PredCondition::LessEqual, OperationCode::LogicalILessEqual},
  244. std::pair{PredCondition::GreaterThan, OperationCode::LogicalIGreaterThan},
  245. std::pair{PredCondition::NotEqual, OperationCode::LogicalINotEqual},
  246. std::pair{PredCondition::GreaterEqual, OperationCode::LogicalIGreaterEqual},
  247. std::pair{PredCondition::LessThanWithNan, OperationCode::LogicalILessThan},
  248. std::pair{PredCondition::NotEqualWithNan, OperationCode::LogicalINotEqual},
  249. std::pair{PredCondition::LessEqualWithNan, OperationCode::LogicalILessEqual},
  250. std::pair{PredCondition::GreaterThanWithNan, OperationCode::LogicalIGreaterThan},
  251. std::pair{PredCondition::GreaterEqualWithNan, OperationCode::LogicalIGreaterEqual},
  252. };
  253. const auto comparison =
  254. std::find_if(comparison_table.cbegin(), comparison_table.cend(),
  255. [condition](const auto entry) { return condition == entry.first; });
  256. UNIMPLEMENTED_IF_MSG(comparison == comparison_table.cend(),
  257. "Unknown predicate comparison operation");
  258. Node predicate = SignedOperation(comparison->second, is_signed, NO_PRECISE, std::move(op_a),
  259. std::move(op_b));
  260. UNIMPLEMENTED_IF_MSG(condition == PredCondition::LessThanWithNan ||
  261. condition == PredCondition::NotEqualWithNan ||
  262. condition == PredCondition::LessEqualWithNan ||
  263. condition == PredCondition::GreaterThanWithNan ||
  264. condition == PredCondition::GreaterEqualWithNan,
  265. "NaN comparisons for integers are not implemented");
  266. return predicate;
  267. }
  268. Node ShaderIR::GetPredicateComparisonHalf(Tegra::Shader::PredCondition condition, Node op_a,
  269. Node op_b) {
  270. static constexpr std::array comparison_table{
  271. std::pair{PredCondition::LessThan, OperationCode::Logical2HLessThan},
  272. std::pair{PredCondition::Equal, OperationCode::Logical2HEqual},
  273. std::pair{PredCondition::LessEqual, OperationCode::Logical2HLessEqual},
  274. std::pair{PredCondition::GreaterThan, OperationCode::Logical2HGreaterThan},
  275. std::pair{PredCondition::NotEqual, OperationCode::Logical2HNotEqual},
  276. std::pair{PredCondition::GreaterEqual, OperationCode::Logical2HGreaterEqual},
  277. std::pair{PredCondition::LessThanWithNan, OperationCode::Logical2HLessThanWithNan},
  278. std::pair{PredCondition::NotEqualWithNan, OperationCode::Logical2HNotEqualWithNan},
  279. std::pair{PredCondition::LessEqualWithNan, OperationCode::Logical2HLessEqualWithNan},
  280. std::pair{PredCondition::GreaterThanWithNan, OperationCode::Logical2HGreaterThanWithNan},
  281. std::pair{PredCondition::GreaterEqualWithNan, OperationCode::Logical2HGreaterEqualWithNan},
  282. };
  283. const auto comparison =
  284. std::find_if(comparison_table.cbegin(), comparison_table.cend(),
  285. [condition](const auto entry) { return condition == entry.first; });
  286. UNIMPLEMENTED_IF_MSG(comparison == comparison_table.cend(),
  287. "Unknown predicate comparison operation");
  288. return Operation(comparison->second, NO_PRECISE, std::move(op_a), std::move(op_b));
  289. }
  290. OperationCode ShaderIR::GetPredicateCombiner(PredOperation operation) {
  291. static constexpr std::array operation_table{
  292. OperationCode::LogicalAnd,
  293. OperationCode::LogicalOr,
  294. OperationCode::LogicalXor,
  295. };
  296. const auto index = static_cast<std::size_t>(operation);
  297. if (index >= operation_table.size()) {
  298. UNIMPLEMENTED_MSG("Unknown predicate operation.");
  299. return {};
  300. }
  301. return operation_table[index];
  302. }
  303. Node ShaderIR::GetConditionCode(Tegra::Shader::ConditionCode cc) const {
  304. switch (cc) {
  305. case Tegra::Shader::ConditionCode::NEU:
  306. return GetInternalFlag(InternalFlag::Zero, true);
  307. default:
  308. UNIMPLEMENTED_MSG("Unimplemented condition code: {}", static_cast<u32>(cc));
  309. return MakeNode<PredicateNode>(Pred::NeverExecute, false);
  310. }
  311. }
  312. void ShaderIR::SetRegister(NodeBlock& bb, Register dest, Node src) {
  313. bb.push_back(Operation(OperationCode::Assign, GetRegister(dest), std::move(src)));
  314. }
  315. void ShaderIR::SetPredicate(NodeBlock& bb, u64 dest, Node src) {
  316. bb.push_back(Operation(OperationCode::LogicalAssign, GetPredicate(dest), std::move(src)));
  317. }
  318. void ShaderIR::SetInternalFlag(NodeBlock& bb, InternalFlag flag, Node value) {
  319. bb.push_back(Operation(OperationCode::LogicalAssign, GetInternalFlag(flag), std::move(value)));
  320. }
  321. void ShaderIR::SetLocalMemory(NodeBlock& bb, Node address, Node value) {
  322. bb.push_back(
  323. Operation(OperationCode::Assign, GetLocalMemory(std::move(address)), std::move(value)));
  324. }
  325. void ShaderIR::SetSharedMemory(NodeBlock& bb, Node address, Node value) {
  326. bb.push_back(
  327. Operation(OperationCode::Assign, GetSharedMemory(std::move(address)), std::move(value)));
  328. }
  329. void ShaderIR::SetTemporary(NodeBlock& bb, u32 id, Node value) {
  330. SetRegister(bb, Register::ZeroIndex + 1 + id, std::move(value));
  331. }
  332. void ShaderIR::SetInternalFlagsFromFloat(NodeBlock& bb, Node value, bool sets_cc) {
  333. if (!sets_cc) {
  334. return;
  335. }
  336. Node zerop = Operation(OperationCode::LogicalFEqual, std::move(value), Immediate(0.0f));
  337. SetInternalFlag(bb, InternalFlag::Zero, std::move(zerop));
  338. LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete");
  339. }
  340. void ShaderIR::SetInternalFlagsFromInteger(NodeBlock& bb, Node value, bool sets_cc) {
  341. if (!sets_cc) {
  342. return;
  343. }
  344. Node zerop = Operation(OperationCode::LogicalIEqual, std::move(value), Immediate(0));
  345. SetInternalFlag(bb, InternalFlag::Zero, std::move(zerop));
  346. LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete");
  347. }
  348. Node ShaderIR::BitfieldExtract(Node value, u32 offset, u32 bits) {
  349. return Operation(OperationCode::UBitfieldExtract, NO_PRECISE, std::move(value),
  350. Immediate(offset), Immediate(bits));
  351. }
  352. Node ShaderIR::BitfieldInsert(Node base, Node insert, u32 offset, u32 bits) {
  353. return Operation(OperationCode::UBitfieldInsert, NO_PRECISE, base, insert, Immediate(offset),
  354. Immediate(bits));
  355. }
  356. void ShaderIR::MarkAttributeUsage(Attribute::Index index, u64 element) {
  357. switch (index) {
  358. case Attribute::Index::LayerViewportPointSize:
  359. switch (element) {
  360. case 0:
  361. UNIMPLEMENTED();
  362. break;
  363. case 1:
  364. uses_layer = true;
  365. break;
  366. case 2:
  367. uses_viewport_index = true;
  368. break;
  369. case 3:
  370. uses_point_size = true;
  371. break;
  372. }
  373. break;
  374. case Attribute::Index::TessCoordInstanceIDVertexID:
  375. switch (element) {
  376. case 2:
  377. uses_instance_id = true;
  378. break;
  379. case 3:
  380. uses_vertex_id = true;
  381. break;
  382. }
  383. break;
  384. case Attribute::Index::ClipDistances0123:
  385. case Attribute::Index::ClipDistances4567: {
  386. const u64 clip_index = (index == Attribute::Index::ClipDistances4567 ? 4 : 0) + element;
  387. used_clip_distances.at(clip_index) = true;
  388. break;
  389. }
  390. case Attribute::Index::FrontColor:
  391. case Attribute::Index::FrontSecondaryColor:
  392. case Attribute::Index::BackColor:
  393. case Attribute::Index::BackSecondaryColor:
  394. uses_legacy_varyings = true;
  395. break;
  396. default:
  397. if (index >= Attribute::Index::TexCoord_0 && index <= Attribute::Index::TexCoord_7) {
  398. uses_legacy_varyings = true;
  399. }
  400. break;
  401. }
  402. }
  403. std::size_t ShaderIR::DeclareAmend(Node new_amend) {
  404. const std::size_t id = amend_code.size();
  405. amend_code.push_back(new_amend);
  406. return id;
  407. }
  408. u32 ShaderIR::NewCustomVariable() {
  409. return num_custom_variables++;
  410. }
  411. } // namespace VideoCommon::Shader