shader_ir.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  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.h"
  12. #include "video_core/shader/node_helper.h"
  13. #include "video_core/shader/registry.h"
  14. #include "video_core/shader/shader_ir.h"
  15. namespace VideoCommon::Shader {
  16. using Tegra::Shader::Attribute;
  17. using Tegra::Shader::Instruction;
  18. using Tegra::Shader::IpaMode;
  19. using Tegra::Shader::Pred;
  20. using Tegra::Shader::PredCondition;
  21. using Tegra::Shader::PredOperation;
  22. using Tegra::Shader::Register;
  23. ShaderIR::ShaderIR(const ProgramCode& program_code_, u32 main_offset_, CompilerSettings settings_,
  24. Registry& registry_)
  25. : program_code{program_code_}, main_offset{main_offset_}, settings{settings_}, registry{
  26. registry_} {
  27. Decode();
  28. PostDecode();
  29. }
  30. ShaderIR::~ShaderIR() = default;
  31. Node ShaderIR::GetRegister(Register reg) {
  32. if (reg != Register::ZeroIndex) {
  33. used_registers.insert(static_cast<u32>(reg));
  34. }
  35. return MakeNode<GprNode>(reg);
  36. }
  37. Node ShaderIR::GetCustomVariable(u32 id) {
  38. return MakeNode<CustomVarNode>(id);
  39. }
  40. Node ShaderIR::GetImmediate19(Instruction instr) {
  41. return Immediate(instr.alu.GetImm20_19());
  42. }
  43. Node ShaderIR::GetImmediate32(Instruction instr) {
  44. return Immediate(instr.alu.GetImm20_32());
  45. }
  46. Node ShaderIR::GetConstBuffer(u64 index_, u64 offset_) {
  47. const auto index = static_cast<u32>(index_);
  48. const auto offset = static_cast<u32>(offset_);
  49. used_cbufs.try_emplace(index).first->second.MarkAsUsed(offset);
  50. return MakeNode<CbufNode>(index, Immediate(offset));
  51. }
  52. Node ShaderIR::GetConstBufferIndirect(u64 index_, u64 offset_, Node node) {
  53. const auto index = static_cast<u32>(index_);
  54. const auto offset = static_cast<u32>(offset_);
  55. used_cbufs.try_emplace(index).first->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. Node node = MakeNode<InternalFlagNode>(flag);
  94. if (negated) {
  95. return Operation(OperationCode::LogicalNegate, std::move(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. return value;
  140. case Register::Size::Word:
  141. // Default - do nothing
  142. return value;
  143. default:
  144. UNREACHABLE_MSG("Unimplemented conversion size: {}", static_cast<u32>(size));
  145. return value;
  146. }
  147. }
  148. Node ShaderIR::GetOperandAbsNegInteger(Node value, bool absolute, bool negate, bool is_signed) {
  149. if (!is_signed) {
  150. // Absolute or negate on an unsigned is pointless
  151. return value;
  152. }
  153. if (absolute) {
  154. value = Operation(OperationCode::IAbsolute, NO_PRECISE, std::move(value));
  155. }
  156. if (negate) {
  157. value = Operation(OperationCode::INegate, NO_PRECISE, std::move(value));
  158. }
  159. return value;
  160. }
  161. Node ShaderIR::UnpackHalfImmediate(Instruction instr, bool has_negation) {
  162. Node value = Immediate(instr.half_imm.PackImmediates());
  163. if (!has_negation) {
  164. return value;
  165. }
  166. Node first_negate = GetPredicate(instr.half_imm.first_negate != 0);
  167. Node second_negate = GetPredicate(instr.half_imm.second_negate != 0);
  168. return Operation(OperationCode::HNegate, NO_PRECISE, std::move(value), std::move(first_negate),
  169. std::move(second_negate));
  170. }
  171. Node ShaderIR::UnpackHalfFloat(Node value, Tegra::Shader::HalfType type) {
  172. return Operation(OperationCode::HUnpack, type, std::move(value));
  173. }
  174. Node ShaderIR::HalfMerge(Node dest, Node src, Tegra::Shader::HalfMerge merge) {
  175. switch (merge) {
  176. case Tegra::Shader::HalfMerge::H0_H1:
  177. return src;
  178. case Tegra::Shader::HalfMerge::F32:
  179. return Operation(OperationCode::HMergeF32, std::move(src));
  180. case Tegra::Shader::HalfMerge::Mrg_H0:
  181. return Operation(OperationCode::HMergeH0, std::move(dest), std::move(src));
  182. case Tegra::Shader::HalfMerge::Mrg_H1:
  183. return Operation(OperationCode::HMergeH1, std::move(dest), std::move(src));
  184. }
  185. UNREACHABLE();
  186. return src;
  187. }
  188. Node ShaderIR::GetOperandAbsNegHalf(Node value, bool absolute, bool negate) {
  189. if (absolute) {
  190. value = Operation(OperationCode::HAbsolute, NO_PRECISE, std::move(value));
  191. }
  192. if (negate) {
  193. value = Operation(OperationCode::HNegate, NO_PRECISE, std::move(value), GetPredicate(true),
  194. GetPredicate(true));
  195. }
  196. return value;
  197. }
  198. Node ShaderIR::GetSaturatedHalfFloat(Node value, bool saturate) {
  199. if (!saturate) {
  200. return value;
  201. }
  202. Node positive_zero = Immediate(std::copysignf(0, 1));
  203. Node positive_one = Immediate(1.0f);
  204. return Operation(OperationCode::HClamp, NO_PRECISE, std::move(value), std::move(positive_zero),
  205. std::move(positive_one));
  206. }
  207. Node ShaderIR::GetPredicateComparisonFloat(PredCondition condition, Node op_a, Node op_b) {
  208. if (condition == PredCondition::T) {
  209. return GetPredicate(true);
  210. } else if (condition == PredCondition::F) {
  211. return GetPredicate(false);
  212. }
  213. static constexpr std::array comparison_table{
  214. OperationCode(0),
  215. OperationCode::LogicalFOrdLessThan, // LT
  216. OperationCode::LogicalFOrdEqual, // EQ
  217. OperationCode::LogicalFOrdLessEqual, // LE
  218. OperationCode::LogicalFOrdGreaterThan, // GT
  219. OperationCode::LogicalFOrdNotEqual, // NE
  220. OperationCode::LogicalFOrdGreaterEqual, // GE
  221. OperationCode::LogicalFOrdered, // NUM
  222. OperationCode::LogicalFUnordered, // NAN
  223. OperationCode::LogicalFUnordLessThan, // LTU
  224. OperationCode::LogicalFUnordEqual, // EQU
  225. OperationCode::LogicalFUnordLessEqual, // LEU
  226. OperationCode::LogicalFUnordGreaterThan, // GTU
  227. OperationCode::LogicalFUnordNotEqual, // NEU
  228. OperationCode::LogicalFUnordGreaterEqual, // GEU
  229. };
  230. const std::size_t index = static_cast<std::size_t>(condition);
  231. ASSERT_MSG(index < std::size(comparison_table), "Invalid condition={}", index);
  232. return Operation(comparison_table[index], op_a, op_b);
  233. }
  234. Node ShaderIR::GetPredicateComparisonInteger(PredCondition condition, bool is_signed, Node op_a,
  235. Node op_b) {
  236. static constexpr std::array comparison_table{
  237. std::pair{PredCondition::LT, OperationCode::LogicalILessThan},
  238. std::pair{PredCondition::EQ, OperationCode::LogicalIEqual},
  239. std::pair{PredCondition::LE, OperationCode::LogicalILessEqual},
  240. std::pair{PredCondition::GT, OperationCode::LogicalIGreaterThan},
  241. std::pair{PredCondition::NE, OperationCode::LogicalINotEqual},
  242. std::pair{PredCondition::GE, OperationCode::LogicalIGreaterEqual},
  243. };
  244. const auto comparison =
  245. std::find_if(comparison_table.cbegin(), comparison_table.cend(),
  246. [condition](const auto entry) { return condition == entry.first; });
  247. UNIMPLEMENTED_IF_MSG(comparison == comparison_table.cend(),
  248. "Unknown predicate comparison operation");
  249. return SignedOperation(comparison->second, is_signed, NO_PRECISE, std::move(op_a),
  250. std::move(op_b));
  251. }
  252. Node ShaderIR::GetPredicateComparisonHalf(Tegra::Shader::PredCondition condition, Node op_a,
  253. Node op_b) {
  254. static constexpr std::array comparison_table{
  255. std::pair{PredCondition::LT, OperationCode::Logical2HLessThan},
  256. std::pair{PredCondition::EQ, OperationCode::Logical2HEqual},
  257. std::pair{PredCondition::LE, OperationCode::Logical2HLessEqual},
  258. std::pair{PredCondition::GT, OperationCode::Logical2HGreaterThan},
  259. std::pair{PredCondition::NE, OperationCode::Logical2HNotEqual},
  260. std::pair{PredCondition::GE, OperationCode::Logical2HGreaterEqual},
  261. std::pair{PredCondition::LTU, OperationCode::Logical2HLessThanWithNan},
  262. std::pair{PredCondition::LEU, OperationCode::Logical2HLessEqualWithNan},
  263. std::pair{PredCondition::GTU, OperationCode::Logical2HGreaterThanWithNan},
  264. std::pair{PredCondition::NEU, OperationCode::Logical2HNotEqualWithNan},
  265. std::pair{PredCondition::GEU, OperationCode::Logical2HGreaterEqualWithNan},
  266. };
  267. const auto comparison =
  268. std::find_if(comparison_table.cbegin(), comparison_table.cend(),
  269. [condition](const auto entry) { return condition == entry.first; });
  270. UNIMPLEMENTED_IF_MSG(comparison == comparison_table.cend(),
  271. "Unknown predicate comparison operation");
  272. return Operation(comparison->second, NO_PRECISE, std::move(op_a), std::move(op_b));
  273. }
  274. OperationCode ShaderIR::GetPredicateCombiner(PredOperation operation) {
  275. static constexpr std::array operation_table{
  276. OperationCode::LogicalAnd,
  277. OperationCode::LogicalOr,
  278. OperationCode::LogicalXor,
  279. };
  280. const auto index = static_cast<std::size_t>(operation);
  281. if (index >= operation_table.size()) {
  282. UNIMPLEMENTED_MSG("Unknown predicate operation.");
  283. return {};
  284. }
  285. return operation_table[index];
  286. }
  287. Node ShaderIR::GetConditionCode(Tegra::Shader::ConditionCode cc) const {
  288. switch (cc) {
  289. case Tegra::Shader::ConditionCode::NEU:
  290. return GetInternalFlag(InternalFlag::Zero, true);
  291. case Tegra::Shader::ConditionCode::FCSM_TR:
  292. UNIMPLEMENTED_MSG("EXIT.FCSM_TR is not implemented");
  293. return MakeNode<PredicateNode>(Pred::NeverExecute, false);
  294. default:
  295. UNIMPLEMENTED_MSG("Unimplemented condition code: {}", static_cast<u32>(cc));
  296. return MakeNode<PredicateNode>(Pred::NeverExecute, false);
  297. }
  298. }
  299. void ShaderIR::SetRegister(NodeBlock& bb, Register dest, Node src) {
  300. bb.push_back(Operation(OperationCode::Assign, GetRegister(dest), std::move(src)));
  301. }
  302. void ShaderIR::SetPredicate(NodeBlock& bb, u64 dest, Node src) {
  303. bb.push_back(Operation(OperationCode::LogicalAssign, GetPredicate(dest), std::move(src)));
  304. }
  305. void ShaderIR::SetInternalFlag(NodeBlock& bb, InternalFlag flag, Node value) {
  306. bb.push_back(Operation(OperationCode::LogicalAssign, GetInternalFlag(flag), std::move(value)));
  307. }
  308. void ShaderIR::SetLocalMemory(NodeBlock& bb, Node address, Node value) {
  309. bb.push_back(
  310. Operation(OperationCode::Assign, GetLocalMemory(std::move(address)), std::move(value)));
  311. }
  312. void ShaderIR::SetSharedMemory(NodeBlock& bb, Node address, Node value) {
  313. bb.push_back(
  314. Operation(OperationCode::Assign, GetSharedMemory(std::move(address)), std::move(value)));
  315. }
  316. void ShaderIR::SetTemporary(NodeBlock& bb, u32 id, Node value) {
  317. SetRegister(bb, Register::ZeroIndex + 1 + id, std::move(value));
  318. }
  319. void ShaderIR::SetInternalFlagsFromFloat(NodeBlock& bb, Node value, bool sets_cc) {
  320. if (!sets_cc) {
  321. return;
  322. }
  323. Node zerop = Operation(OperationCode::LogicalFOrdEqual, std::move(value), Immediate(0.0f));
  324. SetInternalFlag(bb, InternalFlag::Zero, std::move(zerop));
  325. LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete");
  326. }
  327. void ShaderIR::SetInternalFlagsFromInteger(NodeBlock& bb, Node value, bool sets_cc) {
  328. if (!sets_cc) {
  329. return;
  330. }
  331. Node zerop = Operation(OperationCode::LogicalIEqual, std::move(value), Immediate(0));
  332. SetInternalFlag(bb, InternalFlag::Zero, std::move(zerop));
  333. LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete");
  334. }
  335. Node ShaderIR::BitfieldExtract(Node value, u32 offset, u32 bits) {
  336. return Operation(OperationCode::UBitfieldExtract, NO_PRECISE, std::move(value),
  337. Immediate(offset), Immediate(bits));
  338. }
  339. Node ShaderIR::BitfieldInsert(Node base, Node insert, u32 offset, u32 bits) {
  340. return Operation(OperationCode::UBitfieldInsert, NO_PRECISE, base, insert, Immediate(offset),
  341. Immediate(bits));
  342. }
  343. void ShaderIR::MarkAttributeUsage(Attribute::Index index, u64 element) {
  344. switch (index) {
  345. case Attribute::Index::LayerViewportPointSize:
  346. switch (element) {
  347. case 0:
  348. UNIMPLEMENTED();
  349. break;
  350. case 1:
  351. uses_layer = true;
  352. break;
  353. case 2:
  354. uses_viewport_index = true;
  355. break;
  356. case 3:
  357. uses_point_size = true;
  358. break;
  359. }
  360. break;
  361. case Attribute::Index::TessCoordInstanceIDVertexID:
  362. switch (element) {
  363. case 2:
  364. uses_instance_id = true;
  365. break;
  366. case 3:
  367. uses_vertex_id = true;
  368. break;
  369. }
  370. break;
  371. case Attribute::Index::ClipDistances0123:
  372. case Attribute::Index::ClipDistances4567: {
  373. const u64 clip_index = (index == Attribute::Index::ClipDistances4567 ? 4 : 0) + element;
  374. used_clip_distances.at(clip_index) = true;
  375. break;
  376. }
  377. case Attribute::Index::FrontColor:
  378. case Attribute::Index::FrontSecondaryColor:
  379. case Attribute::Index::BackColor:
  380. case Attribute::Index::BackSecondaryColor:
  381. uses_legacy_varyings = true;
  382. break;
  383. default:
  384. if (index >= Attribute::Index::TexCoord_0 && index <= Attribute::Index::TexCoord_7) {
  385. uses_legacy_varyings = true;
  386. }
  387. break;
  388. }
  389. }
  390. std::size_t ShaderIR::DeclareAmend(Node new_amend) {
  391. const std::size_t id = amend_code.size();
  392. amend_code.push_back(new_amend);
  393. return id;
  394. }
  395. u32 ShaderIR::NewCustomVariable() {
  396. return num_custom_variables++;
  397. }
  398. } // namespace VideoCommon::Shader