collect_shader_info_pass.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "shader_recompiler/environment.h"
  5. #include "shader_recompiler/frontend/ir/modifiers.h"
  6. #include "shader_recompiler/frontend/ir/program.h"
  7. #include "shader_recompiler/frontend/ir/value.h"
  8. #include "shader_recompiler/ir_opt/passes.h"
  9. #include "shader_recompiler/shader_info.h"
  10. namespace Shader::Optimization {
  11. namespace {
  12. void AddConstantBufferDescriptor(Info& info, u32 index, u32 count) {
  13. if (count != 1) {
  14. throw NotImplementedException("Constant buffer descriptor indexing");
  15. }
  16. if ((info.constant_buffer_mask & (1U << index)) != 0) {
  17. return;
  18. }
  19. info.constant_buffer_mask |= 1U << index;
  20. auto& cbufs{info.constant_buffer_descriptors};
  21. cbufs.insert(std::ranges::lower_bound(cbufs, index, {}, &ConstantBufferDescriptor::index),
  22. ConstantBufferDescriptor{
  23. .index = index,
  24. .count = 1,
  25. });
  26. }
  27. void GetAttribute(Info& info, IR::Attribute attribute) {
  28. if (IR::IsGeneric(attribute)) {
  29. info.input_generics.at(IR::GenericAttributeIndex(attribute)).used = true;
  30. return;
  31. }
  32. switch (attribute) {
  33. case IR::Attribute::PrimitiveId:
  34. info.loads_primitive_id = true;
  35. break;
  36. case IR::Attribute::PositionX:
  37. case IR::Attribute::PositionY:
  38. case IR::Attribute::PositionZ:
  39. case IR::Attribute::PositionW:
  40. info.loads_position = true;
  41. break;
  42. case IR::Attribute::InstanceId:
  43. info.loads_instance_id = true;
  44. break;
  45. case IR::Attribute::VertexId:
  46. info.loads_vertex_id = true;
  47. break;
  48. case IR::Attribute::FrontFace:
  49. info.loads_front_face = true;
  50. break;
  51. case IR::Attribute::PointSpriteS:
  52. case IR::Attribute::PointSpriteT:
  53. info.loads_point_coord = true;
  54. break;
  55. case IR::Attribute::TessellationEvaluationPointU:
  56. case IR::Attribute::TessellationEvaluationPointV:
  57. info.loads_tess_coord = true;
  58. break;
  59. default:
  60. throw NotImplementedException("Get attribute {}", attribute);
  61. }
  62. }
  63. void SetAttribute(Info& info, IR::Attribute attribute) {
  64. if (IR::IsGeneric(attribute)) {
  65. info.stores_generics.at(IR::GenericAttributeIndex(attribute)) = true;
  66. return;
  67. }
  68. switch (attribute) {
  69. case IR::Attribute::PointSize:
  70. info.stores_point_size = true;
  71. break;
  72. case IR::Attribute::PositionX:
  73. case IR::Attribute::PositionY:
  74. case IR::Attribute::PositionZ:
  75. case IR::Attribute::PositionW:
  76. info.stores_position = true;
  77. break;
  78. case IR::Attribute::ClipDistance0:
  79. case IR::Attribute::ClipDistance1:
  80. case IR::Attribute::ClipDistance2:
  81. case IR::Attribute::ClipDistance3:
  82. case IR::Attribute::ClipDistance4:
  83. case IR::Attribute::ClipDistance5:
  84. case IR::Attribute::ClipDistance6:
  85. case IR::Attribute::ClipDistance7:
  86. info.stores_clip_distance = true;
  87. break;
  88. case IR::Attribute::Layer:
  89. info.stores_layer = true;
  90. break;
  91. case IR::Attribute::ViewportIndex:
  92. info.stores_viewport_index = true;
  93. break;
  94. case IR::Attribute::ViewportMask:
  95. info.stores_viewport_mask = true;
  96. break;
  97. default:
  98. throw NotImplementedException("Set attribute {}", attribute);
  99. }
  100. }
  101. void GetPatch(Info& info, IR::Patch patch) {
  102. if (!IR::IsGeneric(patch)) {
  103. throw NotImplementedException("Reading non-generic patch {}", patch);
  104. }
  105. info.uses_patches.at(IR::GenericPatchIndex(patch)) = true;
  106. }
  107. void SetPatch(Info& info, IR::Patch patch) {
  108. if (IR::IsGeneric(patch)) {
  109. info.uses_patches.at(IR::GenericPatchIndex(patch)) = true;
  110. return;
  111. }
  112. switch (patch) {
  113. case IR::Patch::TessellationLodLeft:
  114. case IR::Patch::TessellationLodTop:
  115. case IR::Patch::TessellationLodRight:
  116. case IR::Patch::TessellationLodBottom:
  117. info.stores_tess_level_outer = true;
  118. break;
  119. case IR::Patch::TessellationLodInteriorU:
  120. case IR::Patch::TessellationLodInteriorV:
  121. info.stores_tess_level_inner = true;
  122. break;
  123. default:
  124. throw NotImplementedException("Set patch {}", patch);
  125. }
  126. }
  127. void CheckCBufNVN(Info& info, IR::Inst& inst) {
  128. const IR::Value cbuf_index{inst.Arg(0)};
  129. if (!cbuf_index.IsImmediate()) {
  130. info.nvn_buffer_used.set();
  131. return;
  132. }
  133. const u32 index{cbuf_index.U32()};
  134. if (index != 0) {
  135. return;
  136. }
  137. const IR::Value cbuf_offset{inst.Arg(1)};
  138. if (!cbuf_offset.IsImmediate()) {
  139. info.nvn_buffer_used.set();
  140. return;
  141. }
  142. const u32 offset{cbuf_offset.U32()};
  143. const u32 descriptor_size{0x10};
  144. const u32 upper_limit{info.nvn_buffer_base + descriptor_size * 16};
  145. if (offset >= info.nvn_buffer_base && offset < upper_limit) {
  146. const std::size_t nvn_index{(offset - info.nvn_buffer_base) / descriptor_size};
  147. info.nvn_buffer_used.set(nvn_index, true);
  148. }
  149. }
  150. void VisitUsages(Info& info, IR::Inst& inst) {
  151. switch (inst.GetOpcode()) {
  152. case IR::Opcode::CompositeConstructF16x2:
  153. case IR::Opcode::CompositeConstructF16x3:
  154. case IR::Opcode::CompositeConstructF16x4:
  155. case IR::Opcode::CompositeExtractF16x2:
  156. case IR::Opcode::CompositeExtractF16x3:
  157. case IR::Opcode::CompositeExtractF16x4:
  158. case IR::Opcode::CompositeInsertF16x2:
  159. case IR::Opcode::CompositeInsertF16x3:
  160. case IR::Opcode::CompositeInsertF16x4:
  161. case IR::Opcode::SelectF16:
  162. case IR::Opcode::BitCastU16F16:
  163. case IR::Opcode::BitCastF16U16:
  164. case IR::Opcode::PackFloat2x16:
  165. case IR::Opcode::UnpackFloat2x16:
  166. case IR::Opcode::ConvertS16F16:
  167. case IR::Opcode::ConvertS32F16:
  168. case IR::Opcode::ConvertS64F16:
  169. case IR::Opcode::ConvertU16F16:
  170. case IR::Opcode::ConvertU32F16:
  171. case IR::Opcode::ConvertU64F16:
  172. case IR::Opcode::ConvertF16S8:
  173. case IR::Opcode::ConvertF16S16:
  174. case IR::Opcode::ConvertF16S32:
  175. case IR::Opcode::ConvertF16S64:
  176. case IR::Opcode::ConvertF16U8:
  177. case IR::Opcode::ConvertF16U16:
  178. case IR::Opcode::ConvertF16U32:
  179. case IR::Opcode::ConvertF16U64:
  180. case IR::Opcode::FPAbs16:
  181. case IR::Opcode::FPAdd16:
  182. case IR::Opcode::FPCeil16:
  183. case IR::Opcode::FPFloor16:
  184. case IR::Opcode::FPFma16:
  185. case IR::Opcode::FPMul16:
  186. case IR::Opcode::FPNeg16:
  187. case IR::Opcode::FPRoundEven16:
  188. case IR::Opcode::FPSaturate16:
  189. case IR::Opcode::FPClamp16:
  190. case IR::Opcode::FPTrunc16:
  191. case IR::Opcode::FPOrdEqual16:
  192. case IR::Opcode::FPUnordEqual16:
  193. case IR::Opcode::FPOrdNotEqual16:
  194. case IR::Opcode::FPUnordNotEqual16:
  195. case IR::Opcode::FPOrdLessThan16:
  196. case IR::Opcode::FPUnordLessThan16:
  197. case IR::Opcode::FPOrdGreaterThan16:
  198. case IR::Opcode::FPUnordGreaterThan16:
  199. case IR::Opcode::FPOrdLessThanEqual16:
  200. case IR::Opcode::FPUnordLessThanEqual16:
  201. case IR::Opcode::FPOrdGreaterThanEqual16:
  202. case IR::Opcode::FPUnordGreaterThanEqual16:
  203. case IR::Opcode::FPIsNan16:
  204. case IR::Opcode::GlobalAtomicAddF16x2:
  205. case IR::Opcode::GlobalAtomicMinF16x2:
  206. case IR::Opcode::GlobalAtomicMaxF16x2:
  207. case IR::Opcode::StorageAtomicAddF16x2:
  208. case IR::Opcode::StorageAtomicMinF16x2:
  209. case IR::Opcode::StorageAtomicMaxF16x2:
  210. info.uses_fp16 = true;
  211. break;
  212. case IR::Opcode::CompositeConstructF64x2:
  213. case IR::Opcode::CompositeConstructF64x3:
  214. case IR::Opcode::CompositeConstructF64x4:
  215. case IR::Opcode::CompositeExtractF64x2:
  216. case IR::Opcode::CompositeExtractF64x3:
  217. case IR::Opcode::CompositeExtractF64x4:
  218. case IR::Opcode::CompositeInsertF64x2:
  219. case IR::Opcode::CompositeInsertF64x3:
  220. case IR::Opcode::CompositeInsertF64x4:
  221. case IR::Opcode::SelectF64:
  222. case IR::Opcode::BitCastU64F64:
  223. case IR::Opcode::BitCastF64U64:
  224. case IR::Opcode::PackDouble2x32:
  225. case IR::Opcode::UnpackDouble2x32:
  226. case IR::Opcode::FPAbs64:
  227. case IR::Opcode::FPAdd64:
  228. case IR::Opcode::FPCeil64:
  229. case IR::Opcode::FPFloor64:
  230. case IR::Opcode::FPFma64:
  231. case IR::Opcode::FPMax64:
  232. case IR::Opcode::FPMin64:
  233. case IR::Opcode::FPMul64:
  234. case IR::Opcode::FPNeg64:
  235. case IR::Opcode::FPRecip64:
  236. case IR::Opcode::FPRecipSqrt64:
  237. case IR::Opcode::FPRoundEven64:
  238. case IR::Opcode::FPSaturate64:
  239. case IR::Opcode::FPClamp64:
  240. case IR::Opcode::FPTrunc64:
  241. case IR::Opcode::FPOrdEqual64:
  242. case IR::Opcode::FPUnordEqual64:
  243. case IR::Opcode::FPOrdNotEqual64:
  244. case IR::Opcode::FPUnordNotEqual64:
  245. case IR::Opcode::FPOrdLessThan64:
  246. case IR::Opcode::FPUnordLessThan64:
  247. case IR::Opcode::FPOrdGreaterThan64:
  248. case IR::Opcode::FPUnordGreaterThan64:
  249. case IR::Opcode::FPOrdLessThanEqual64:
  250. case IR::Opcode::FPUnordLessThanEqual64:
  251. case IR::Opcode::FPOrdGreaterThanEqual64:
  252. case IR::Opcode::FPUnordGreaterThanEqual64:
  253. case IR::Opcode::FPIsNan64:
  254. case IR::Opcode::ConvertS16F64:
  255. case IR::Opcode::ConvertS32F64:
  256. case IR::Opcode::ConvertS64F64:
  257. case IR::Opcode::ConvertU16F64:
  258. case IR::Opcode::ConvertU32F64:
  259. case IR::Opcode::ConvertU64F64:
  260. case IR::Opcode::ConvertF32F64:
  261. case IR::Opcode::ConvertF64F32:
  262. case IR::Opcode::ConvertF64S8:
  263. case IR::Opcode::ConvertF64S16:
  264. case IR::Opcode::ConvertF64S32:
  265. case IR::Opcode::ConvertF64S64:
  266. case IR::Opcode::ConvertF64U8:
  267. case IR::Opcode::ConvertF64U16:
  268. case IR::Opcode::ConvertF64U32:
  269. case IR::Opcode::ConvertF64U64:
  270. info.uses_fp64 = true;
  271. break;
  272. default:
  273. break;
  274. }
  275. switch (inst.GetOpcode()) {
  276. case IR::Opcode::GetCbufU8:
  277. case IR::Opcode::GetCbufS8:
  278. case IR::Opcode::UndefU8:
  279. case IR::Opcode::LoadGlobalU8:
  280. case IR::Opcode::LoadGlobalS8:
  281. case IR::Opcode::WriteGlobalU8:
  282. case IR::Opcode::WriteGlobalS8:
  283. case IR::Opcode::LoadStorageU8:
  284. case IR::Opcode::LoadStorageS8:
  285. case IR::Opcode::WriteStorageU8:
  286. case IR::Opcode::WriteStorageS8:
  287. case IR::Opcode::LoadSharedU8:
  288. case IR::Opcode::LoadSharedS8:
  289. case IR::Opcode::WriteSharedU8:
  290. case IR::Opcode::SelectU8:
  291. case IR::Opcode::ConvertF16S8:
  292. case IR::Opcode::ConvertF16U8:
  293. case IR::Opcode::ConvertF32S8:
  294. case IR::Opcode::ConvertF32U8:
  295. case IR::Opcode::ConvertF64S8:
  296. case IR::Opcode::ConvertF64U8:
  297. info.uses_int8 = true;
  298. break;
  299. default:
  300. break;
  301. }
  302. switch (inst.GetOpcode()) {
  303. case IR::Opcode::GetCbufU16:
  304. case IR::Opcode::GetCbufS16:
  305. case IR::Opcode::UndefU16:
  306. case IR::Opcode::LoadGlobalU16:
  307. case IR::Opcode::LoadGlobalS16:
  308. case IR::Opcode::WriteGlobalU16:
  309. case IR::Opcode::WriteGlobalS16:
  310. case IR::Opcode::LoadStorageU16:
  311. case IR::Opcode::LoadStorageS16:
  312. case IR::Opcode::WriteStorageU16:
  313. case IR::Opcode::WriteStorageS16:
  314. case IR::Opcode::LoadSharedU16:
  315. case IR::Opcode::LoadSharedS16:
  316. case IR::Opcode::WriteSharedU16:
  317. case IR::Opcode::SelectU16:
  318. case IR::Opcode::BitCastU16F16:
  319. case IR::Opcode::BitCastF16U16:
  320. case IR::Opcode::ConvertS16F16:
  321. case IR::Opcode::ConvertS16F32:
  322. case IR::Opcode::ConvertS16F64:
  323. case IR::Opcode::ConvertU16F16:
  324. case IR::Opcode::ConvertU16F32:
  325. case IR::Opcode::ConvertU16F64:
  326. case IR::Opcode::ConvertF16S16:
  327. case IR::Opcode::ConvertF16U16:
  328. case IR::Opcode::ConvertF32S16:
  329. case IR::Opcode::ConvertF32U16:
  330. case IR::Opcode::ConvertF64S16:
  331. case IR::Opcode::ConvertF64U16:
  332. info.uses_int16 = true;
  333. break;
  334. default:
  335. break;
  336. }
  337. switch (inst.GetOpcode()) {
  338. case IR::Opcode::UndefU64:
  339. case IR::Opcode::LoadGlobalU8:
  340. case IR::Opcode::LoadGlobalS8:
  341. case IR::Opcode::LoadGlobalU16:
  342. case IR::Opcode::LoadGlobalS16:
  343. case IR::Opcode::LoadGlobal32:
  344. case IR::Opcode::LoadGlobal64:
  345. case IR::Opcode::LoadGlobal128:
  346. case IR::Opcode::WriteGlobalU8:
  347. case IR::Opcode::WriteGlobalS8:
  348. case IR::Opcode::WriteGlobalU16:
  349. case IR::Opcode::WriteGlobalS16:
  350. case IR::Opcode::WriteGlobal32:
  351. case IR::Opcode::WriteGlobal64:
  352. case IR::Opcode::WriteGlobal128:
  353. case IR::Opcode::SelectU64:
  354. case IR::Opcode::BitCastU64F64:
  355. case IR::Opcode::BitCastF64U64:
  356. case IR::Opcode::PackUint2x32:
  357. case IR::Opcode::UnpackUint2x32:
  358. case IR::Opcode::IAdd64:
  359. case IR::Opcode::ISub64:
  360. case IR::Opcode::INeg64:
  361. case IR::Opcode::ShiftLeftLogical64:
  362. case IR::Opcode::ShiftRightLogical64:
  363. case IR::Opcode::ShiftRightArithmetic64:
  364. case IR::Opcode::ConvertS64F16:
  365. case IR::Opcode::ConvertS64F32:
  366. case IR::Opcode::ConvertS64F64:
  367. case IR::Opcode::ConvertU64F16:
  368. case IR::Opcode::ConvertU64F32:
  369. case IR::Opcode::ConvertU64F64:
  370. case IR::Opcode::ConvertU64U32:
  371. case IR::Opcode::ConvertU32U64:
  372. case IR::Opcode::ConvertF16U64:
  373. case IR::Opcode::ConvertF32U64:
  374. case IR::Opcode::ConvertF64U64:
  375. case IR::Opcode::SharedAtomicExchange64:
  376. case IR::Opcode::GlobalAtomicIAdd64:
  377. case IR::Opcode::GlobalAtomicSMin64:
  378. case IR::Opcode::GlobalAtomicUMin64:
  379. case IR::Opcode::GlobalAtomicSMax64:
  380. case IR::Opcode::GlobalAtomicUMax64:
  381. case IR::Opcode::GlobalAtomicAnd64:
  382. case IR::Opcode::GlobalAtomicOr64:
  383. case IR::Opcode::GlobalAtomicXor64:
  384. case IR::Opcode::GlobalAtomicExchange64:
  385. case IR::Opcode::StorageAtomicIAdd64:
  386. case IR::Opcode::StorageAtomicSMin64:
  387. case IR::Opcode::StorageAtomicUMin64:
  388. case IR::Opcode::StorageAtomicSMax64:
  389. case IR::Opcode::StorageAtomicUMax64:
  390. case IR::Opcode::StorageAtomicAnd64:
  391. case IR::Opcode::StorageAtomicOr64:
  392. case IR::Opcode::StorageAtomicXor64:
  393. case IR::Opcode::StorageAtomicExchange64:
  394. info.uses_int64 = true;
  395. break;
  396. default:
  397. break;
  398. }
  399. switch (inst.GetOpcode()) {
  400. case IR::Opcode::WriteGlobalU8:
  401. case IR::Opcode::WriteGlobalS8:
  402. case IR::Opcode::WriteGlobalU16:
  403. case IR::Opcode::WriteGlobalS16:
  404. case IR::Opcode::WriteGlobal32:
  405. case IR::Opcode::WriteGlobal64:
  406. case IR::Opcode::WriteGlobal128:
  407. case IR::Opcode::GlobalAtomicIAdd32:
  408. case IR::Opcode::GlobalAtomicSMin32:
  409. case IR::Opcode::GlobalAtomicUMin32:
  410. case IR::Opcode::GlobalAtomicSMax32:
  411. case IR::Opcode::GlobalAtomicUMax32:
  412. case IR::Opcode::GlobalAtomicInc32:
  413. case IR::Opcode::GlobalAtomicDec32:
  414. case IR::Opcode::GlobalAtomicAnd32:
  415. case IR::Opcode::GlobalAtomicOr32:
  416. case IR::Opcode::GlobalAtomicXor32:
  417. case IR::Opcode::GlobalAtomicExchange32:
  418. case IR::Opcode::GlobalAtomicIAdd64:
  419. case IR::Opcode::GlobalAtomicSMin64:
  420. case IR::Opcode::GlobalAtomicUMin64:
  421. case IR::Opcode::GlobalAtomicSMax64:
  422. case IR::Opcode::GlobalAtomicUMax64:
  423. case IR::Opcode::GlobalAtomicAnd64:
  424. case IR::Opcode::GlobalAtomicOr64:
  425. case IR::Opcode::GlobalAtomicXor64:
  426. case IR::Opcode::GlobalAtomicExchange64:
  427. case IR::Opcode::GlobalAtomicAddF32:
  428. case IR::Opcode::GlobalAtomicAddF16x2:
  429. case IR::Opcode::GlobalAtomicAddF32x2:
  430. case IR::Opcode::GlobalAtomicMinF16x2:
  431. case IR::Opcode::GlobalAtomicMinF32x2:
  432. case IR::Opcode::GlobalAtomicMaxF16x2:
  433. case IR::Opcode::GlobalAtomicMaxF32x2:
  434. info.stores_global_memory = true;
  435. [[fallthrough]];
  436. case IR::Opcode::LoadGlobalU8:
  437. case IR::Opcode::LoadGlobalS8:
  438. case IR::Opcode::LoadGlobalU16:
  439. case IR::Opcode::LoadGlobalS16:
  440. case IR::Opcode::LoadGlobal32:
  441. case IR::Opcode::LoadGlobal64:
  442. case IR::Opcode::LoadGlobal128:
  443. info.uses_int64 = true;
  444. info.uses_global_memory = true;
  445. info.used_constant_buffer_types |= IR::Type::U32 | IR::Type::U32x2;
  446. info.used_storage_buffer_types |= IR::Type::U32 | IR::Type::U32x2 | IR::Type::U32x4;
  447. break;
  448. default:
  449. break;
  450. }
  451. switch (inst.GetOpcode()) {
  452. case IR::Opcode::DemoteToHelperInvocation:
  453. info.uses_demote_to_helper_invocation = true;
  454. break;
  455. case IR::Opcode::GetAttribute:
  456. GetAttribute(info, inst.Arg(0).Attribute());
  457. break;
  458. case IR::Opcode::SetAttribute:
  459. SetAttribute(info, inst.Arg(0).Attribute());
  460. break;
  461. case IR::Opcode::GetPatch:
  462. GetPatch(info, inst.Arg(0).Patch());
  463. break;
  464. case IR::Opcode::SetPatch:
  465. SetPatch(info, inst.Arg(0).Patch());
  466. break;
  467. case IR::Opcode::GetAttributeIndexed:
  468. info.loads_indexed_attributes = true;
  469. break;
  470. case IR::Opcode::SetAttributeIndexed:
  471. info.stores_indexed_attributes = true;
  472. break;
  473. case IR::Opcode::SetFragColor:
  474. info.stores_frag_color[inst.Arg(0).U32()] = true;
  475. break;
  476. case IR::Opcode::SetSampleMask:
  477. info.stores_sample_mask = true;
  478. break;
  479. case IR::Opcode::SetFragDepth:
  480. info.stores_frag_depth = true;
  481. break;
  482. case IR::Opcode::WorkgroupId:
  483. info.uses_workgroup_id = true;
  484. break;
  485. case IR::Opcode::LocalInvocationId:
  486. info.uses_local_invocation_id = true;
  487. break;
  488. case IR::Opcode::InvocationId:
  489. info.uses_invocation_id = true;
  490. break;
  491. case IR::Opcode::SampleId:
  492. info.uses_sample_id = true;
  493. break;
  494. case IR::Opcode::IsHelperInvocation:
  495. info.uses_is_helper_invocation = true;
  496. break;
  497. case IR::Opcode::LaneId:
  498. case IR::Opcode::ShuffleIndex:
  499. case IR::Opcode::ShuffleUp:
  500. case IR::Opcode::ShuffleDown:
  501. case IR::Opcode::ShuffleButterfly:
  502. info.uses_subgroup_invocation_id = true;
  503. break;
  504. case IR::Opcode::GetCbufU8:
  505. case IR::Opcode::GetCbufS8:
  506. case IR::Opcode::GetCbufU16:
  507. case IR::Opcode::GetCbufS16:
  508. case IR::Opcode::GetCbufU32:
  509. case IR::Opcode::GetCbufF32:
  510. case IR::Opcode::GetCbufU32x2: {
  511. if (const IR::Value index{inst.Arg(0)}; index.IsImmediate()) {
  512. AddConstantBufferDescriptor(info, index.U32(), 1);
  513. } else {
  514. throw NotImplementedException("Constant buffer with non-immediate index");
  515. }
  516. switch (inst.GetOpcode()) {
  517. case IR::Opcode::GetCbufU8:
  518. case IR::Opcode::GetCbufS8:
  519. info.used_constant_buffer_types |= IR::Type::U8;
  520. break;
  521. case IR::Opcode::GetCbufU16:
  522. case IR::Opcode::GetCbufS16:
  523. info.used_constant_buffer_types |= IR::Type::U16;
  524. break;
  525. case IR::Opcode::GetCbufU32:
  526. info.used_constant_buffer_types |= IR::Type::U32;
  527. break;
  528. case IR::Opcode::GetCbufF32:
  529. info.used_constant_buffer_types |= IR::Type::F32;
  530. break;
  531. case IR::Opcode::GetCbufU32x2:
  532. info.used_constant_buffer_types |= IR::Type::U32x2;
  533. break;
  534. default:
  535. break;
  536. }
  537. break;
  538. }
  539. case IR::Opcode::BindlessImageSampleImplicitLod:
  540. case IR::Opcode::BindlessImageSampleExplicitLod:
  541. case IR::Opcode::BindlessImageSampleDrefImplicitLod:
  542. case IR::Opcode::BindlessImageSampleDrefExplicitLod:
  543. case IR::Opcode::BindlessImageGather:
  544. case IR::Opcode::BindlessImageGatherDref:
  545. case IR::Opcode::BindlessImageFetch:
  546. case IR::Opcode::BindlessImageQueryDimensions:
  547. case IR::Opcode::BindlessImageQueryLod:
  548. case IR::Opcode::BindlessImageGradient:
  549. case IR::Opcode::BoundImageSampleImplicitLod:
  550. case IR::Opcode::BoundImageSampleExplicitLod:
  551. case IR::Opcode::BoundImageSampleDrefImplicitLod:
  552. case IR::Opcode::BoundImageSampleDrefExplicitLod:
  553. case IR::Opcode::BoundImageGather:
  554. case IR::Opcode::BoundImageGatherDref:
  555. case IR::Opcode::BoundImageFetch:
  556. case IR::Opcode::BoundImageQueryDimensions:
  557. case IR::Opcode::BoundImageQueryLod:
  558. case IR::Opcode::BoundImageGradient:
  559. case IR::Opcode::ImageSampleImplicitLod:
  560. case IR::Opcode::ImageSampleExplicitLod:
  561. case IR::Opcode::ImageSampleDrefImplicitLod:
  562. case IR::Opcode::ImageSampleDrefExplicitLod:
  563. case IR::Opcode::ImageGather:
  564. case IR::Opcode::ImageGatherDref:
  565. case IR::Opcode::ImageFetch:
  566. case IR::Opcode::ImageQueryDimensions:
  567. case IR::Opcode::ImageQueryLod:
  568. case IR::Opcode::ImageGradient: {
  569. const TextureType type{inst.Flags<IR::TextureInstInfo>().type};
  570. info.uses_sampled_1d |= type == TextureType::Color1D || type == TextureType::ColorArray1D;
  571. info.uses_sparse_residency |=
  572. inst.GetAssociatedPseudoOperation(IR::Opcode::GetSparseFromOp) != nullptr;
  573. break;
  574. }
  575. case IR::Opcode::ImageRead: {
  576. const auto flags{inst.Flags<IR::TextureInstInfo>()};
  577. info.uses_typeless_image_reads |= flags.image_format == ImageFormat::Typeless;
  578. info.uses_sparse_residency |=
  579. inst.GetAssociatedPseudoOperation(IR::Opcode::GetSparseFromOp) != nullptr;
  580. break;
  581. }
  582. case IR::Opcode::ImageWrite: {
  583. const auto flags{inst.Flags<IR::TextureInstInfo>()};
  584. info.uses_typeless_image_writes |= flags.image_format == ImageFormat::Typeless;
  585. info.uses_image_buffers |= flags.type == TextureType::Buffer;
  586. break;
  587. }
  588. case IR::Opcode::SubgroupEqMask:
  589. case IR::Opcode::SubgroupLtMask:
  590. case IR::Opcode::SubgroupLeMask:
  591. case IR::Opcode::SubgroupGtMask:
  592. case IR::Opcode::SubgroupGeMask:
  593. info.uses_subgroup_mask = true;
  594. break;
  595. case IR::Opcode::VoteAll:
  596. case IR::Opcode::VoteAny:
  597. case IR::Opcode::VoteEqual:
  598. case IR::Opcode::SubgroupBallot:
  599. info.uses_subgroup_vote = true;
  600. break;
  601. case IR::Opcode::FSwizzleAdd:
  602. info.uses_fswzadd = true;
  603. break;
  604. case IR::Opcode::DPdxFine:
  605. case IR::Opcode::DPdyFine:
  606. case IR::Opcode::DPdxCoarse:
  607. case IR::Opcode::DPdyCoarse:
  608. info.uses_derivatives = true;
  609. break;
  610. case IR::Opcode::LoadStorageU8:
  611. case IR::Opcode::LoadStorageS8:
  612. case IR::Opcode::WriteStorageU8:
  613. case IR::Opcode::WriteStorageS8:
  614. info.used_storage_buffer_types |= IR::Type::U8;
  615. break;
  616. case IR::Opcode::LoadStorageU16:
  617. case IR::Opcode::LoadStorageS16:
  618. case IR::Opcode::WriteStorageU16:
  619. case IR::Opcode::WriteStorageS16:
  620. info.used_storage_buffer_types |= IR::Type::U16;
  621. break;
  622. case IR::Opcode::LoadStorage32:
  623. case IR::Opcode::WriteStorage32:
  624. case IR::Opcode::StorageAtomicIAdd32:
  625. case IR::Opcode::StorageAtomicSMin32:
  626. case IR::Opcode::StorageAtomicUMin32:
  627. case IR::Opcode::StorageAtomicSMax32:
  628. case IR::Opcode::StorageAtomicUMax32:
  629. case IR::Opcode::StorageAtomicAnd32:
  630. case IR::Opcode::StorageAtomicOr32:
  631. case IR::Opcode::StorageAtomicXor32:
  632. case IR::Opcode::StorageAtomicExchange32:
  633. info.used_storage_buffer_types |= IR::Type::U32;
  634. break;
  635. case IR::Opcode::LoadStorage64:
  636. case IR::Opcode::WriteStorage64:
  637. info.used_storage_buffer_types |= IR::Type::U32x2;
  638. break;
  639. case IR::Opcode::LoadStorage128:
  640. case IR::Opcode::WriteStorage128:
  641. info.used_storage_buffer_types |= IR::Type::U32x4;
  642. break;
  643. case IR::Opcode::SharedAtomicInc32:
  644. info.uses_shared_increment = true;
  645. break;
  646. case IR::Opcode::SharedAtomicDec32:
  647. info.uses_shared_decrement = true;
  648. break;
  649. case IR::Opcode::SharedAtomicExchange64:
  650. info.uses_int64_bit_atomics = true;
  651. break;
  652. case IR::Opcode::GlobalAtomicInc32:
  653. case IR::Opcode::StorageAtomicInc32:
  654. info.used_storage_buffer_types |= IR::Type::U32;
  655. info.uses_global_increment = true;
  656. break;
  657. case IR::Opcode::GlobalAtomicDec32:
  658. case IR::Opcode::StorageAtomicDec32:
  659. info.used_storage_buffer_types |= IR::Type::U32;
  660. info.uses_global_decrement = true;
  661. break;
  662. case IR::Opcode::GlobalAtomicAddF32:
  663. case IR::Opcode::StorageAtomicAddF32:
  664. info.used_storage_buffer_types |= IR::Type::U32;
  665. info.uses_atomic_f32_add = true;
  666. break;
  667. case IR::Opcode::GlobalAtomicAddF16x2:
  668. case IR::Opcode::StorageAtomicAddF16x2:
  669. info.used_storage_buffer_types |= IR::Type::U32;
  670. info.uses_atomic_f16x2_add = true;
  671. break;
  672. case IR::Opcode::GlobalAtomicAddF32x2:
  673. case IR::Opcode::StorageAtomicAddF32x2:
  674. info.used_storage_buffer_types |= IR::Type::U32;
  675. info.uses_atomic_f32x2_add = true;
  676. break;
  677. case IR::Opcode::GlobalAtomicMinF16x2:
  678. case IR::Opcode::StorageAtomicMinF16x2:
  679. info.used_storage_buffer_types |= IR::Type::U32;
  680. info.uses_atomic_f16x2_min = true;
  681. break;
  682. case IR::Opcode::GlobalAtomicMinF32x2:
  683. case IR::Opcode::StorageAtomicMinF32x2:
  684. info.used_storage_buffer_types |= IR::Type::U32;
  685. info.uses_atomic_f32x2_min = true;
  686. break;
  687. case IR::Opcode::GlobalAtomicMaxF16x2:
  688. case IR::Opcode::StorageAtomicMaxF16x2:
  689. info.used_storage_buffer_types |= IR::Type::U32;
  690. info.uses_atomic_f16x2_max = true;
  691. break;
  692. case IR::Opcode::GlobalAtomicMaxF32x2:
  693. case IR::Opcode::StorageAtomicMaxF32x2:
  694. info.used_storage_buffer_types |= IR::Type::U32;
  695. info.uses_atomic_f32x2_max = true;
  696. break;
  697. case IR::Opcode::GlobalAtomicIAdd64:
  698. case IR::Opcode::GlobalAtomicSMin64:
  699. case IR::Opcode::GlobalAtomicUMin64:
  700. case IR::Opcode::GlobalAtomicSMax64:
  701. case IR::Opcode::GlobalAtomicUMax64:
  702. case IR::Opcode::GlobalAtomicAnd64:
  703. case IR::Opcode::GlobalAtomicOr64:
  704. case IR::Opcode::GlobalAtomicXor64:
  705. case IR::Opcode::GlobalAtomicExchange64:
  706. case IR::Opcode::StorageAtomicIAdd64:
  707. case IR::Opcode::StorageAtomicSMin64:
  708. case IR::Opcode::StorageAtomicUMin64:
  709. case IR::Opcode::StorageAtomicSMax64:
  710. case IR::Opcode::StorageAtomicUMax64:
  711. case IR::Opcode::StorageAtomicAnd64:
  712. case IR::Opcode::StorageAtomicOr64:
  713. case IR::Opcode::StorageAtomicXor64:
  714. info.used_storage_buffer_types |= IR::Type::U64;
  715. info.uses_int64_bit_atomics = true;
  716. break;
  717. case IR::Opcode::BindlessImageAtomicIAdd32:
  718. case IR::Opcode::BindlessImageAtomicSMin32:
  719. case IR::Opcode::BindlessImageAtomicUMin32:
  720. case IR::Opcode::BindlessImageAtomicSMax32:
  721. case IR::Opcode::BindlessImageAtomicUMax32:
  722. case IR::Opcode::BindlessImageAtomicInc32:
  723. case IR::Opcode::BindlessImageAtomicDec32:
  724. case IR::Opcode::BindlessImageAtomicAnd32:
  725. case IR::Opcode::BindlessImageAtomicOr32:
  726. case IR::Opcode::BindlessImageAtomicXor32:
  727. case IR::Opcode::BindlessImageAtomicExchange32:
  728. case IR::Opcode::BoundImageAtomicIAdd32:
  729. case IR::Opcode::BoundImageAtomicSMin32:
  730. case IR::Opcode::BoundImageAtomicUMin32:
  731. case IR::Opcode::BoundImageAtomicSMax32:
  732. case IR::Opcode::BoundImageAtomicUMax32:
  733. case IR::Opcode::BoundImageAtomicInc32:
  734. case IR::Opcode::BoundImageAtomicDec32:
  735. case IR::Opcode::BoundImageAtomicAnd32:
  736. case IR::Opcode::BoundImageAtomicOr32:
  737. case IR::Opcode::BoundImageAtomicXor32:
  738. case IR::Opcode::BoundImageAtomicExchange32:
  739. case IR::Opcode::ImageAtomicIAdd32:
  740. case IR::Opcode::ImageAtomicSMin32:
  741. case IR::Opcode::ImageAtomicUMin32:
  742. case IR::Opcode::ImageAtomicSMax32:
  743. case IR::Opcode::ImageAtomicUMax32:
  744. case IR::Opcode::ImageAtomicInc32:
  745. case IR::Opcode::ImageAtomicDec32:
  746. case IR::Opcode::ImageAtomicAnd32:
  747. case IR::Opcode::ImageAtomicOr32:
  748. case IR::Opcode::ImageAtomicXor32:
  749. case IR::Opcode::ImageAtomicExchange32:
  750. info.uses_atomic_image_u32 = true;
  751. break;
  752. default:
  753. break;
  754. }
  755. }
  756. void VisitFpModifiers(Info& info, IR::Inst& inst) {
  757. switch (inst.GetOpcode()) {
  758. case IR::Opcode::FPAdd16:
  759. case IR::Opcode::FPFma16:
  760. case IR::Opcode::FPMul16:
  761. case IR::Opcode::FPRoundEven16:
  762. case IR::Opcode::FPFloor16:
  763. case IR::Opcode::FPCeil16:
  764. case IR::Opcode::FPTrunc16: {
  765. const auto control{inst.Flags<IR::FpControl>()};
  766. switch (control.fmz_mode) {
  767. case IR::FmzMode::DontCare:
  768. break;
  769. case IR::FmzMode::FTZ:
  770. case IR::FmzMode::FMZ:
  771. info.uses_fp16_denorms_flush = true;
  772. break;
  773. case IR::FmzMode::None:
  774. info.uses_fp16_denorms_preserve = true;
  775. break;
  776. }
  777. break;
  778. }
  779. case IR::Opcode::FPAdd32:
  780. case IR::Opcode::FPFma32:
  781. case IR::Opcode::FPMul32:
  782. case IR::Opcode::FPRoundEven32:
  783. case IR::Opcode::FPFloor32:
  784. case IR::Opcode::FPCeil32:
  785. case IR::Opcode::FPTrunc32:
  786. case IR::Opcode::FPOrdEqual32:
  787. case IR::Opcode::FPUnordEqual32:
  788. case IR::Opcode::FPOrdNotEqual32:
  789. case IR::Opcode::FPUnordNotEqual32:
  790. case IR::Opcode::FPOrdLessThan32:
  791. case IR::Opcode::FPUnordLessThan32:
  792. case IR::Opcode::FPOrdGreaterThan32:
  793. case IR::Opcode::FPUnordGreaterThan32:
  794. case IR::Opcode::FPOrdLessThanEqual32:
  795. case IR::Opcode::FPUnordLessThanEqual32:
  796. case IR::Opcode::FPOrdGreaterThanEqual32:
  797. case IR::Opcode::FPUnordGreaterThanEqual32:
  798. case IR::Opcode::ConvertF16F32:
  799. case IR::Opcode::ConvertF64F32: {
  800. const auto control{inst.Flags<IR::FpControl>()};
  801. switch (control.fmz_mode) {
  802. case IR::FmzMode::DontCare:
  803. break;
  804. case IR::FmzMode::FTZ:
  805. case IR::FmzMode::FMZ:
  806. info.uses_fp32_denorms_flush = true;
  807. break;
  808. case IR::FmzMode::None:
  809. info.uses_fp32_denorms_preserve = true;
  810. break;
  811. }
  812. break;
  813. }
  814. default:
  815. break;
  816. }
  817. }
  818. void VisitCbufs(Info& info, IR::Inst& inst) {
  819. switch (inst.GetOpcode()) {
  820. case IR::Opcode::GetCbufU8:
  821. case IR::Opcode::GetCbufS8:
  822. case IR::Opcode::GetCbufU16:
  823. case IR::Opcode::GetCbufS16:
  824. case IR::Opcode::GetCbufU32:
  825. case IR::Opcode::GetCbufF32:
  826. case IR::Opcode::GetCbufU32x2: {
  827. CheckCBufNVN(info, inst);
  828. break;
  829. }
  830. default:
  831. break;
  832. }
  833. }
  834. void Visit(Info& info, IR::Inst& inst) {
  835. VisitUsages(info, inst);
  836. VisitFpModifiers(info, inst);
  837. VisitCbufs(info, inst);
  838. }
  839. void GatherInfoFromHeader(Environment& env, Info& info) {
  840. Stage stage{env.ShaderStage()};
  841. if (stage == Stage::Compute) {
  842. return;
  843. }
  844. const auto& header{env.SPH()};
  845. if (stage == Stage::Fragment) {
  846. if (!info.loads_indexed_attributes) {
  847. return;
  848. }
  849. for (size_t i = 0; i < info.input_generics.size(); i++) {
  850. info.input_generics[i].used |= header.ps.IsGenericVectorActive(i);
  851. }
  852. info.loads_position |= header.ps.imap_systemb.position != 0;
  853. return;
  854. }
  855. if (info.loads_indexed_attributes) {
  856. for (size_t i = 0; i < info.input_generics.size(); i++) {
  857. info.input_generics[i].used |= header.vtg.IsInputGenericVectorActive(i);
  858. }
  859. info.loads_position |= header.vtg.imap_systemb.position != 0;
  860. }
  861. if (info.stores_indexed_attributes) {
  862. for (size_t i = 0; i < info.stores_generics.size(); i++) {
  863. info.stores_generics[i] |= header.vtg.IsOutputGenericVectorActive(i);
  864. }
  865. info.stores_clip_distance |= header.vtg.omap_systemc.clip_distances != 0;
  866. info.stores_position |= header.vtg.omap_systemb.position != 0;
  867. }
  868. }
  869. } // Anonymous namespace
  870. void CollectShaderInfoPass(Environment& env, IR::Program& program) {
  871. Info& info{program.info};
  872. const u32 base{[&] {
  873. switch (program.stage) {
  874. case Stage::VertexA:
  875. case Stage::VertexB:
  876. return 0x110u;
  877. case Stage::TessellationControl:
  878. return 0x210u;
  879. case Stage::TessellationEval:
  880. return 0x310u;
  881. case Stage::Geometry:
  882. return 0x410u;
  883. case Stage::Fragment:
  884. return 0x510u;
  885. case Stage::Compute:
  886. return 0x310u;
  887. }
  888. throw InvalidArgument("Invalid stage {}", program.stage);
  889. }()};
  890. info.nvn_buffer_base = base;
  891. for (IR::Block* const block : program.post_order_blocks) {
  892. for (IR::Inst& inst : block->Instructions()) {
  893. Visit(info, inst);
  894. }
  895. }
  896. GatherInfoFromHeader(env, info);
  897. }
  898. } // namespace Shader::Optimization