ShaderProgramReflection.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029
  1. // Copyright (C) 2009-2022, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/ShaderCompiler/ShaderProgramReflection.h>
  6. #include <AnKi/Gr/Utils/Functions.h>
  7. #include <SpirvCross/spirv_glsl.hpp>
  8. namespace anki {
  9. static ShaderVariableDataType spirvcrossBaseTypeToAnki(spirv_cross::SPIRType::BaseType cross)
  10. {
  11. ShaderVariableDataType out = ShaderVariableDataType::kNone;
  12. switch(cross)
  13. {
  14. case spirv_cross::SPIRType::SByte:
  15. out = ShaderVariableDataType::kI8;
  16. break;
  17. case spirv_cross::SPIRType::UByte:
  18. out = ShaderVariableDataType::kU8;
  19. break;
  20. case spirv_cross::SPIRType::Short:
  21. out = ShaderVariableDataType::kI16;
  22. break;
  23. case spirv_cross::SPIRType::UShort:
  24. out = ShaderVariableDataType::kU16;
  25. break;
  26. case spirv_cross::SPIRType::Int:
  27. out = ShaderVariableDataType::kI32;
  28. break;
  29. case spirv_cross::SPIRType::UInt:
  30. out = ShaderVariableDataType::kU32;
  31. break;
  32. case spirv_cross::SPIRType::Int64:
  33. out = ShaderVariableDataType::kI64;
  34. break;
  35. case spirv_cross::SPIRType::UInt64:
  36. out = ShaderVariableDataType::kU64;
  37. break;
  38. case spirv_cross::SPIRType::Half:
  39. out = ShaderVariableDataType::kF16;
  40. break;
  41. case spirv_cross::SPIRType::Float:
  42. out = ShaderVariableDataType::kF32;
  43. break;
  44. default:
  45. break;
  46. }
  47. return out;
  48. }
  49. /// Populates the reflection info.
  50. class SpirvReflector : public spirv_cross::Compiler
  51. {
  52. public:
  53. SpirvReflector(const U32* ir, PtrSize wordCount, BaseMemoryPool* tmpPool,
  54. ShaderReflectionVisitorInterface* interface)
  55. : spirv_cross::Compiler(ir, wordCount)
  56. , m_pool(tmpPool)
  57. , m_interface(interface)
  58. {
  59. }
  60. [[nodiscard]] static Error performSpirvReflection(Array<ConstWeakArray<U8>, U32(ShaderType::kCount)> spirv,
  61. BaseMemoryPool& tmpPool,
  62. ShaderReflectionVisitorInterface& interface);
  63. private:
  64. class Var
  65. {
  66. public:
  67. StringRaii m_name;
  68. ShaderVariableBlockInfo m_blockInfo;
  69. ShaderVariableDataType m_type = ShaderVariableDataType::kNone;
  70. Var(BaseMemoryPool* pool)
  71. : m_name(pool)
  72. {
  73. }
  74. };
  75. class Block
  76. {
  77. public:
  78. StringRaii m_name;
  79. DynamicArrayRaii<Var> m_vars;
  80. U32 m_binding = kMaxU32;
  81. U32 m_set = kMaxU32;
  82. U32 m_size = kMaxU32;
  83. Block(BaseMemoryPool* pool)
  84. : m_name(pool)
  85. , m_vars(pool)
  86. {
  87. }
  88. };
  89. class Opaque
  90. {
  91. public:
  92. StringRaii m_name;
  93. ShaderVariableDataType m_type = ShaderVariableDataType::kNone;
  94. U32 m_binding = kMaxU32;
  95. U32 m_set = kMaxU32;
  96. U32 m_arraySize = kMaxU32;
  97. Opaque(BaseMemoryPool* pool)
  98. : m_name(pool)
  99. {
  100. }
  101. };
  102. class Const
  103. {
  104. public:
  105. StringRaii m_name;
  106. ShaderVariableDataType m_type = ShaderVariableDataType::kNone;
  107. U32 m_constantId = kMaxU32;
  108. Const(BaseMemoryPool* pool)
  109. : m_name(pool)
  110. {
  111. }
  112. };
  113. class StructMember
  114. {
  115. public:
  116. StringRaii m_name;
  117. ShaderVariableDataType m_type = ShaderVariableDataType::kNone;
  118. U32 m_structIndex = kMaxU32; ///< The member is actually a struct.
  119. U32 m_offset = kMaxU32;
  120. U32 m_arraySize = kMaxU32;
  121. StructMember(BaseMemoryPool* pool)
  122. : m_name(pool)
  123. {
  124. }
  125. };
  126. class Struct
  127. {
  128. public:
  129. StringRaii m_name;
  130. DynamicArrayRaii<StructMember> m_members;
  131. U32 m_size = 0;
  132. U32 m_alignment = 0;
  133. Struct(BaseMemoryPool* pool)
  134. : m_name(pool)
  135. , m_members(pool)
  136. {
  137. }
  138. };
  139. BaseMemoryPool* m_pool = nullptr;
  140. ShaderReflectionVisitorInterface* m_interface = nullptr;
  141. Error spirvTypeToAnki(const spirv_cross::SPIRType& type, ShaderVariableDataType& out) const;
  142. Error blockReflection(const spirv_cross::Resource& res, Bool isStorage, DynamicArrayRaii<Block>& blocks) const;
  143. Error opaqueReflection(const spirv_cross::Resource& res, DynamicArrayRaii<Opaque>& opaques) const;
  144. Error constsReflection(DynamicArrayRaii<Const>& consts) const;
  145. Error blockVariablesReflection(spirv_cross::TypeID resourceId, DynamicArrayRaii<Var>& vars) const;
  146. Error blockVariableReflection(const spirv_cross::SPIRType& type, CString parentVariable, U32 baseOffset,
  147. DynamicArrayRaii<Var>& vars) const;
  148. Error workgroupSizes(U32& sizex, U32& sizey, U32& sizez, U32& specConstMask);
  149. Error structsReflection(DynamicArrayRaii<Struct>& structs) const;
  150. Error structReflection(uint32_t id, const spirv_cross::SPIRType& type, U32 depth, Bool& skipped,
  151. DynamicArrayRaii<Struct>& structs, U32& structIndexInStructsArr) const;
  152. };
  153. Error SpirvReflector::structsReflection(DynamicArrayRaii<Struct>& structs) const
  154. {
  155. Error err = Error::kNone;
  156. ir.for_each_typed_id<spirv_cross::SPIRType>([&err, &structs, this](uint32_t id, const spirv_cross::SPIRType& type) {
  157. if(err)
  158. {
  159. return;
  160. }
  161. if(type.basetype != spirv_cross::SPIRType::Struct || type.pointer || !type.array.empty()
  162. || has_decoration(type.self, spv::DecorationBlock))
  163. {
  164. return;
  165. }
  166. U32 idx;
  167. Bool skipped;
  168. err = structReflection(id, type, 0, skipped, structs, idx);
  169. });
  170. return err;
  171. }
  172. Error SpirvReflector::structReflection(uint32_t id, const spirv_cross::SPIRType& type, U32 depth, Bool& skipped,
  173. DynamicArrayRaii<Struct>& structs, U32& structIndexInStructsArr) const
  174. {
  175. skipped = false;
  176. // Name
  177. std::string name = to_name(id);
  178. // Skip GL builtins, SPIRV-Cross things and symbols that should be skipped
  179. if(CString(name.c_str()).find("gl_") == 0 || CString(name.c_str()).find("_") == 0
  180. || (depth == 0 && m_interface->skipSymbol(name.c_str())))
  181. {
  182. skipped = true;
  183. return Error::kNone;
  184. }
  185. // Check if the struct is already there
  186. structIndexInStructsArr = 0;
  187. for(const Struct& s : structs)
  188. {
  189. if(s.m_name == name.c_str())
  190. {
  191. return Error::kNone;
  192. }
  193. ++structIndexInStructsArr;
  194. }
  195. // Create new struct
  196. BaseMemoryPool& pool = structs.getMemoryPool();
  197. Struct cstruct(&pool);
  198. cstruct.m_name = name.c_str();
  199. U32 membersOffset = 0;
  200. Bool aMemberWasSkipped = false;
  201. // Members
  202. for(U32 i = 0; i < type.member_types.size(); ++i)
  203. {
  204. StructMember& member = *cstruct.m_members.emplaceBack(&pool);
  205. const spirv_cross::SPIRType& memberType = get<spirv_cross::SPIRType>(type.member_types[i]);
  206. // Get name
  207. const spirv_cross::Meta* meta = ir.find_meta(type.self);
  208. ANKI_ASSERT(meta);
  209. ANKI_ASSERT(i < meta->members.size());
  210. ANKI_ASSERT(!meta->members[i].alias.empty());
  211. member.m_name = meta->members[i].alias.c_str();
  212. // Array size
  213. if(!memberType.array.empty())
  214. {
  215. if(memberType.array.size() > 1)
  216. {
  217. ANKI_SHADER_COMPILER_LOGE("Can't support multi-dimentional arrays at the moment");
  218. return Error::kUserData;
  219. }
  220. const Bool notSpecConstantArraySize = memberType.array_size_literal[0];
  221. if(notSpecConstantArraySize)
  222. {
  223. // Have a min to acount for unsized arrays of SSBOs
  224. member.m_arraySize = max(memberType.array[0], 1u);
  225. }
  226. else
  227. {
  228. ANKI_SHADER_COMPILER_LOGE("Arrays with spec constant size are not allowed: %s", member.m_name.cstr());
  229. return Error::kFunctionFailed;
  230. }
  231. }
  232. else
  233. {
  234. member.m_arraySize = 1;
  235. }
  236. // Type
  237. const ShaderVariableDataType baseType = spirvcrossBaseTypeToAnki(memberType.basetype);
  238. const Bool isNumeric = baseType != ShaderVariableDataType::kNone;
  239. ShaderVariableDataType actualType = ShaderVariableDataType::kNone;
  240. U32 memberSize = 0;
  241. U32 memberAlignment = 0;
  242. if(isNumeric)
  243. {
  244. const Bool isMatrix = memberType.columns > 1;
  245. if(0)
  246. {
  247. }
  248. #define ANKI_SVDT_MACRO(type, baseType_, rowCount, columnCount, isIntagralType) \
  249. else if(ShaderVariableDataType::k##baseType_ == baseType && isMatrix && memberType.vecsize == rowCount \
  250. && memberType.columns == columnCount) \
  251. { \
  252. actualType = ShaderVariableDataType::k##type; \
  253. memberSize = sizeof(type); \
  254. memberAlignment = alignof(baseType_); \
  255. } \
  256. else if(ShaderVariableDataType::k##baseType_ == baseType && !isMatrix && memberType.vecsize == rowCount) \
  257. { \
  258. actualType = ShaderVariableDataType::k##type; \
  259. memberSize = sizeof(type); \
  260. memberAlignment = alignof(baseType_); \
  261. }
  262. #include <AnKi/Gr/ShaderVariableDataType.defs.h>
  263. #undef ANKI_SVDT_MACRO
  264. member.m_type = actualType;
  265. }
  266. else if(memberType.basetype == spirv_cross::SPIRType::Struct)
  267. {
  268. U32 idx = kMaxU32;
  269. Bool memberSkipped = false;
  270. ANKI_CHECK(structReflection(type.member_types[i], memberType, depth + 1, memberSkipped, structs, idx));
  271. if(memberSkipped)
  272. {
  273. aMemberWasSkipped = true;
  274. break;
  275. }
  276. else
  277. {
  278. ANKI_ASSERT(idx < structs.getSize());
  279. member.m_structIndex = idx;
  280. memberSize = structs[idx].m_size;
  281. memberAlignment = structs[idx].m_alignment;
  282. }
  283. }
  284. else
  285. {
  286. ANKI_SHADER_COMPILER_LOGE("Unhandled base type for member: %s", name.c_str());
  287. return Error::kFunctionFailed;
  288. }
  289. // Update offsets and alignments
  290. memberSize *= member.m_arraySize;
  291. member.m_offset = getAlignedRoundUp(memberAlignment, membersOffset);
  292. cstruct.m_alignment = max(cstruct.m_alignment, memberAlignment);
  293. cstruct.m_size = member.m_offset + memberSize;
  294. membersOffset = member.m_offset + memberSize;
  295. }
  296. if(!aMemberWasSkipped)
  297. {
  298. // Now you can create the struct
  299. alignRoundUp(cstruct.m_alignment, cstruct.m_size);
  300. Struct& newStruct = *structs.emplaceBack(&pool);
  301. newStruct = std::move(cstruct);
  302. }
  303. else
  304. {
  305. skipped = true;
  306. }
  307. return Error::kNone;
  308. }
  309. Error SpirvReflector::blockVariablesReflection(spirv_cross::TypeID resourceId, DynamicArrayRaii<Var>& vars) const
  310. {
  311. Bool found = false;
  312. Error err = Error::kNone;
  313. ir.for_each_typed_id<spirv_cross::SPIRType>([&](uint32_t, const spirv_cross::SPIRType& type) {
  314. if(err)
  315. {
  316. return;
  317. }
  318. if(type.basetype == spirv_cross::SPIRType::Struct && !type.pointer && type.array.empty())
  319. {
  320. if(type.self == resourceId)
  321. {
  322. found = true;
  323. err = blockVariableReflection(type, CString(), 0, vars);
  324. }
  325. }
  326. });
  327. ANKI_CHECK(err);
  328. if(!found)
  329. {
  330. ANKI_SHADER_COMPILER_LOGE("Can't determine the type of a block");
  331. return Error::kUserData;
  332. }
  333. return Error::kNone;
  334. }
  335. Error SpirvReflector::blockVariableReflection(const spirv_cross::SPIRType& type, CString parentVariable, U32 baseOffset,
  336. DynamicArrayRaii<Var>& vars) const
  337. {
  338. ANKI_ASSERT(type.basetype == spirv_cross::SPIRType::Struct);
  339. for(U32 i = 0; i < type.member_types.size(); ++i)
  340. {
  341. Var var(m_pool);
  342. const spirv_cross::SPIRType& memberType = get<spirv_cross::SPIRType>(type.member_types[i]);
  343. // Name
  344. {
  345. const spirv_cross::Meta* meta = ir.find_meta(type.self);
  346. ANKI_ASSERT(meta);
  347. ANKI_ASSERT(i < meta->members.size());
  348. ANKI_ASSERT(!meta->members[i].alias.empty());
  349. const std::string& name = meta->members[i].alias;
  350. if(parentVariable.isEmpty())
  351. {
  352. var.m_name.create(name.c_str());
  353. }
  354. else
  355. {
  356. var.m_name.sprintf("%s.%s", parentVariable.cstr(), name.c_str());
  357. }
  358. }
  359. // Offset
  360. {
  361. auto it = ir.meta.find(type.self);
  362. ANKI_ASSERT(it != ir.meta.end());
  363. const spirv_cross::Vector<spirv_cross::Meta::Decoration>& memb = it->second.members;
  364. ANKI_ASSERT(i < memb.size());
  365. const spirv_cross::Meta::Decoration& dec = memb[i];
  366. ANKI_ASSERT(dec.decoration_flags.get(spv::DecorationOffset));
  367. var.m_blockInfo.m_offset = I16(dec.offset + baseOffset);
  368. }
  369. // Array size
  370. Bool isArray = false;
  371. {
  372. if(!memberType.array.empty())
  373. {
  374. if(memberType.array.size() > 1)
  375. {
  376. ANKI_SHADER_COMPILER_LOGE("Can't support multi-dimentional arrays at the moment");
  377. return Error::kUserData;
  378. }
  379. const Bool notSpecConstantArraySize = memberType.array_size_literal[0];
  380. if(notSpecConstantArraySize)
  381. {
  382. // Have a min to acount for unsized arrays of SSBOs
  383. var.m_blockInfo.m_arraySize = max<I16>(I16(memberType.array[0]), 1);
  384. isArray = true;
  385. }
  386. else
  387. {
  388. var.m_blockInfo.m_arraySize = 1;
  389. isArray = true;
  390. }
  391. }
  392. else
  393. {
  394. var.m_blockInfo.m_arraySize = 1;
  395. }
  396. }
  397. // Array stride
  398. if(has_decoration(type.member_types[i], spv::DecorationArrayStride))
  399. {
  400. var.m_blockInfo.m_arrayStride = I16(get_decoration(type.member_types[i], spv::DecorationArrayStride));
  401. }
  402. const ShaderVariableDataType baseType = spirvcrossBaseTypeToAnki(memberType.basetype);
  403. const Bool isNumeric = baseType != ShaderVariableDataType::kNone;
  404. if(memberType.basetype == spirv_cross::SPIRType::Struct)
  405. {
  406. if(var.m_blockInfo.m_arraySize == 1 && !isArray)
  407. {
  408. ANKI_CHECK(blockVariableReflection(memberType, var.m_name, var.m_blockInfo.m_offset, vars));
  409. }
  410. else
  411. {
  412. for(U32 i = 0; i < U32(var.m_blockInfo.m_arraySize); ++i)
  413. {
  414. StringRaii newName(m_pool);
  415. newName.sprintf("%s[%u]", var.m_name.getBegin(), i);
  416. ANKI_CHECK(blockVariableReflection(
  417. memberType, newName, var.m_blockInfo.m_offset + var.m_blockInfo.m_arrayStride * i, vars));
  418. }
  419. }
  420. }
  421. else if(isNumeric)
  422. {
  423. const Bool isMatrix = memberType.columns > 1;
  424. if(0)
  425. {
  426. }
  427. #define ANKI_SVDT_MACRO(type_, baseType_, rowCount, columnCount, isIntagralType) \
  428. else if(ShaderVariableDataType::k##baseType_ == baseType && isMatrix && memberType.vecsize == rowCount \
  429. && memberType.columns == columnCount) \
  430. { \
  431. var.m_type = ShaderVariableDataType::k##type_; \
  432. auto it = ir.meta.find(type.self); \
  433. ANKI_ASSERT(it != ir.meta.end()); \
  434. const spirv_cross::Vector<spirv_cross::Meta::Decoration>& memberDecorations = it->second.members; \
  435. ANKI_ASSERT(i < memberDecorations.size()); \
  436. var.m_blockInfo.m_matrixStride = I16(memberDecorations[i].matrix_stride); \
  437. } \
  438. else if(ShaderVariableDataType::k##baseType_ == baseType && !isMatrix && memberType.vecsize == rowCount) \
  439. { \
  440. var.m_type = ShaderVariableDataType::k##type_; \
  441. }
  442. #include <AnKi/Gr/ShaderVariableDataType.defs.h>
  443. #undef ANKI_SVDT_MACRO
  444. if(var.m_type == ShaderVariableDataType::kNone)
  445. {
  446. ANKI_SHADER_COMPILER_LOGE("Unhandled numeric member: %s", var.m_name.cstr());
  447. return Error::kFunctionFailed;
  448. }
  449. }
  450. else
  451. {
  452. ANKI_SHADER_COMPILER_LOGE("Unhandled base type for member: %s", var.m_name.cstr());
  453. return Error::kFunctionFailed;
  454. }
  455. // Store the member if it's no struct
  456. if(var.m_type != ShaderVariableDataType::kNone)
  457. {
  458. vars.emplaceBack(std::move(var));
  459. }
  460. }
  461. return Error::kNone;
  462. }
  463. Error SpirvReflector::blockReflection(const spirv_cross::Resource& res, [[maybe_unused]] Bool isStorage,
  464. DynamicArrayRaii<Block>& blocks) const
  465. {
  466. Block newBlock(m_pool);
  467. const spirv_cross::SPIRType type = get_type(res.type_id);
  468. const spirv_cross::Bitset decorationMask = get_decoration_bitset(res.id);
  469. const Bool isPushConstant = get_storage_class(res.id) == spv::StorageClassPushConstant;
  470. // Name
  471. {
  472. const std::string name = (!res.name.empty()) ? res.name : to_name(res.base_type_id);
  473. if(name.length() == 0)
  474. {
  475. ANKI_SHADER_COMPILER_LOGE("Can't accept zero name length");
  476. return Error::kUserData;
  477. }
  478. if(m_interface->skipSymbol(name.c_str()))
  479. {
  480. return Error::kNone;
  481. }
  482. newBlock.m_name.create(name.c_str());
  483. }
  484. // Set
  485. if(!isPushConstant)
  486. {
  487. newBlock.m_set = get_decoration(res.id, spv::DecorationDescriptorSet);
  488. if(newBlock.m_set >= kMaxDescriptorSets)
  489. {
  490. ANKI_SHADER_COMPILER_LOGE("Too high descriptor set: %u", newBlock.m_set);
  491. return Error::kUserData;
  492. }
  493. }
  494. // Binding
  495. if(!isPushConstant)
  496. {
  497. newBlock.m_binding = get_decoration(res.id, spv::DecorationBinding);
  498. }
  499. // Size
  500. newBlock.m_size = U32(get_declared_struct_size(get_type(res.base_type_id)));
  501. ANKI_ASSERT(isStorage || newBlock.m_size > 0);
  502. // Add it
  503. const Block* otherFound = nullptr;
  504. for(const Block& other : blocks)
  505. {
  506. const Bool bindingSame = other.m_set == newBlock.m_set && other.m_binding == newBlock.m_binding;
  507. const Bool nameSame = strcmp(other.m_name.getBegin(), newBlock.m_name.getBegin()) == 0;
  508. const Bool sizeSame = other.m_size == newBlock.m_size;
  509. const Bool err0 = bindingSame && (!nameSame || !sizeSame);
  510. const Bool err1 = nameSame && (!bindingSame || !sizeSame);
  511. if(err0 || err1)
  512. {
  513. ANKI_SHADER_COMPILER_LOGE("Linking error. Blocks %s and %s", other.m_name.cstr(), newBlock.m_name.cstr());
  514. return Error::kUserData;
  515. }
  516. if(bindingSame)
  517. {
  518. otherFound = &other;
  519. break;
  520. }
  521. }
  522. if(!otherFound)
  523. {
  524. // Get the variables
  525. ANKI_CHECK(blockVariablesReflection(res.base_type_id, newBlock.m_vars));
  526. // Store the block
  527. blocks.emplaceBack(std::move(newBlock));
  528. }
  529. #if ANKI_ENABLE_ASSERTIONS
  530. else
  531. {
  532. DynamicArrayRaii<Var> vars(m_pool);
  533. ANKI_CHECK(blockVariablesReflection(res.base_type_id, vars));
  534. ANKI_ASSERT(vars.getSize() == otherFound->m_vars.getSize() && "Expecting same vars");
  535. }
  536. #endif
  537. return Error::kNone;
  538. }
  539. Error SpirvReflector::spirvTypeToAnki(const spirv_cross::SPIRType& type, ShaderVariableDataType& out) const
  540. {
  541. switch(type.basetype)
  542. {
  543. case spirv_cross::SPIRType::Image:
  544. case spirv_cross::SPIRType::SampledImage:
  545. {
  546. switch(type.image.dim)
  547. {
  548. case spv::Dim1D:
  549. out = (type.image.arrayed) ? ShaderVariableDataType::kTexture1DArray : ShaderVariableDataType::kTexture1D;
  550. break;
  551. case spv::Dim2D:
  552. out = (type.image.arrayed) ? ShaderVariableDataType::kTexture2DArray : ShaderVariableDataType::kTexture2D;
  553. break;
  554. case spv::Dim3D:
  555. out = ShaderVariableDataType::kTexture3D;
  556. break;
  557. case spv::DimCube:
  558. out =
  559. (type.image.arrayed) ? ShaderVariableDataType::kTextureCubeArray : ShaderVariableDataType::kTextureCube;
  560. break;
  561. default:
  562. ANKI_ASSERT(0);
  563. }
  564. break;
  565. }
  566. case spirv_cross::SPIRType::Sampler:
  567. out = ShaderVariableDataType::kSampler;
  568. break;
  569. default:
  570. ANKI_SHADER_COMPILER_LOGE("Can't determine the type");
  571. return Error::kUserData;
  572. }
  573. return Error::kNone;
  574. }
  575. Error SpirvReflector::opaqueReflection(const spirv_cross::Resource& res, DynamicArrayRaii<Opaque>& opaques) const
  576. {
  577. Opaque newOpaque(m_pool);
  578. const spirv_cross::SPIRType type = get_type(res.type_id);
  579. const spirv_cross::Bitset decorationMask = get_decoration_bitset(res.id);
  580. const spirv_cross::ID fallbackId = spirv_cross::ID(res.id);
  581. // Name
  582. const std::string name = (!res.name.empty()) ? res.name : get_fallback_name(fallbackId);
  583. if(name.length() == 0)
  584. {
  585. ANKI_SHADER_COMPILER_LOGE("Can't accept zero length name");
  586. return Error::kUserData;
  587. }
  588. if(m_interface->skipSymbol(name.c_str()))
  589. {
  590. return Error::kNone;
  591. }
  592. newOpaque.m_name.create(name.c_str());
  593. // Type
  594. ANKI_CHECK(spirvTypeToAnki(type, newOpaque.m_type));
  595. // Set
  596. newOpaque.m_set = get_decoration(res.id, spv::DecorationDescriptorSet);
  597. if(newOpaque.m_set >= kMaxDescriptorSets)
  598. {
  599. ANKI_SHADER_COMPILER_LOGE("Too high descriptor set: %u", newOpaque.m_set);
  600. return Error::kUserData;
  601. }
  602. // Binding
  603. newOpaque.m_binding = get_decoration(res.id, spv::DecorationBinding);
  604. // Size
  605. if(type.array.size() == 0)
  606. {
  607. newOpaque.m_arraySize = 1;
  608. }
  609. else if(type.array.size() == 1)
  610. {
  611. newOpaque.m_arraySize = type.array[0];
  612. }
  613. else
  614. {
  615. ANKI_SHADER_COMPILER_LOGE("Can't support multi-dimensional arrays: %s", newOpaque.m_name.cstr());
  616. return Error::kUserData;
  617. }
  618. // Add it
  619. Bool found = false;
  620. for(const Opaque& other : opaques)
  621. {
  622. const Bool bindingSame = other.m_set == newOpaque.m_set && other.m_binding == newOpaque.m_binding;
  623. const Bool nameSame = other.m_name == newOpaque.m_name;
  624. const Bool sizeSame = other.m_arraySize == newOpaque.m_arraySize;
  625. const Bool typeSame = other.m_type == newOpaque.m_type;
  626. const Bool err = nameSame && (!bindingSame || !sizeSame || !typeSame);
  627. if(err)
  628. {
  629. ANKI_SHADER_COMPILER_LOGE("Linking error");
  630. return Error::kUserData;
  631. }
  632. if(nameSame)
  633. {
  634. found = true;
  635. break;
  636. }
  637. }
  638. if(!found)
  639. {
  640. opaques.emplaceBack(std::move(newOpaque));
  641. }
  642. return Error::kNone;
  643. }
  644. Error SpirvReflector::constsReflection(DynamicArrayRaii<Const>& consts) const
  645. {
  646. spirv_cross::SmallVector<spirv_cross::SpecializationConstant> specConsts = get_specialization_constants();
  647. for(const spirv_cross::SpecializationConstant& c : specConsts)
  648. {
  649. Const newConst(m_pool);
  650. const spirv_cross::SPIRConstant cc = get<spirv_cross::SPIRConstant>(c.id);
  651. const spirv_cross::SPIRType type = get<spirv_cross::SPIRType>(cc.constant_type);
  652. const std::string name = get_name(c.id);
  653. if(name.length() == 0)
  654. {
  655. ANKI_SHADER_COMPILER_LOGE("Can't accept zero legth name");
  656. return Error::kUserData;
  657. }
  658. newConst.m_name.create(name.c_str());
  659. newConst.m_constantId = c.constant_id;
  660. switch(type.basetype)
  661. {
  662. case spirv_cross::SPIRType::UInt:
  663. newConst.m_type = ShaderVariableDataType::kU32;
  664. break;
  665. case spirv_cross::SPIRType::Int:
  666. newConst.m_type = ShaderVariableDataType::kI32;
  667. break;
  668. case spirv_cross::SPIRType::Float:
  669. newConst.m_type = ShaderVariableDataType::kF32;
  670. break;
  671. default:
  672. ANKI_SHADER_COMPILER_LOGE("Can't determine the type of the spec constant: %s", name.c_str());
  673. return Error::kUserData;
  674. }
  675. // Search for it
  676. Const* foundConst = nullptr;
  677. for(Const& other : consts)
  678. {
  679. const Bool nameSame = other.m_name == newConst.m_name;
  680. const Bool typeSame = other.m_type == newConst.m_type;
  681. const Bool idSame = other.m_constantId == newConst.m_constantId;
  682. const Bool err0 = nameSame && (!typeSame || !idSame);
  683. const Bool err1 = idSame && (!nameSame || !typeSame);
  684. if(err0 || err1)
  685. {
  686. ANKI_SHADER_COMPILER_LOGE("Linking error");
  687. return Error::kUserData;
  688. }
  689. if(idSame)
  690. {
  691. foundConst = &other;
  692. break;
  693. }
  694. }
  695. // Add it or update it
  696. if(foundConst == nullptr)
  697. {
  698. consts.emplaceBack(std::move(newConst));
  699. }
  700. }
  701. return Error::kNone;
  702. }
  703. Error SpirvReflector::workgroupSizes(U32& sizex, U32& sizey, U32& sizez, U32& specConstMask)
  704. {
  705. sizex = sizey = sizez = specConstMask = 0;
  706. auto entries = get_entry_points_and_stages();
  707. for(const auto& e : entries)
  708. {
  709. if(e.execution_model == spv::ExecutionModelGLCompute)
  710. {
  711. const auto& spvEntry = get_entry_point(e.name, e.execution_model);
  712. spirv_cross::SpecializationConstant specx, specy, specz;
  713. get_work_group_size_specialization_constants(specx, specy, specz);
  714. if(specx.id != spirv_cross::ID(0))
  715. {
  716. specConstMask |= 1;
  717. sizex = specx.constant_id;
  718. }
  719. else
  720. {
  721. sizex = spvEntry.workgroup_size.x;
  722. }
  723. if(specy.id != spirv_cross::ID(0))
  724. {
  725. specConstMask |= 2;
  726. sizey = specy.constant_id;
  727. }
  728. else
  729. {
  730. sizey = spvEntry.workgroup_size.y;
  731. }
  732. if(specz.id != spirv_cross::ID(0))
  733. {
  734. specConstMask |= 4;
  735. sizez = specz.constant_id;
  736. }
  737. else
  738. {
  739. sizez = spvEntry.workgroup_size.z;
  740. }
  741. }
  742. }
  743. return Error::kNone;
  744. }
  745. Error SpirvReflector::performSpirvReflection(Array<ConstWeakArray<U8>, U32(ShaderType::kCount)> spirv,
  746. BaseMemoryPool& tmpPool, ShaderReflectionVisitorInterface& interface)
  747. {
  748. DynamicArrayRaii<Block> uniformBlocks(&tmpPool);
  749. DynamicArrayRaii<Block> storageBlocks(&tmpPool);
  750. DynamicArrayRaii<Block> pushConstantBlock(&tmpPool);
  751. DynamicArrayRaii<Opaque> opaques(&tmpPool);
  752. DynamicArrayRaii<Const> specializationConstants(&tmpPool);
  753. Array<U32, 3> workgroupSizes = {};
  754. U32 workgroupSizeSpecConstMask = 0;
  755. DynamicArrayRaii<Struct> structs(&tmpPool);
  756. // Perform reflection for each stage
  757. for(const ShaderType type : EnumIterable<ShaderType>())
  758. {
  759. if(spirv[type].getSize() == 0)
  760. {
  761. continue;
  762. }
  763. // Parse SPIR-V
  764. const unsigned int* spvb = reinterpret_cast<const unsigned int*>(spirv[type].getBegin());
  765. SpirvReflector compiler(spvb, spirv[type].getSizeInBytes() / sizeof(unsigned int), &tmpPool, &interface);
  766. // Uniform blocks
  767. for(const spirv_cross::Resource& res : compiler.get_shader_resources().uniform_buffers)
  768. {
  769. ANKI_CHECK(compiler.blockReflection(res, false, uniformBlocks));
  770. }
  771. // Sorage blocks
  772. for(const spirv_cross::Resource& res : compiler.get_shader_resources().storage_buffers)
  773. {
  774. ANKI_CHECK(compiler.blockReflection(res, true, storageBlocks));
  775. }
  776. // Push constants
  777. if(compiler.get_shader_resources().push_constant_buffers.size() == 1)
  778. {
  779. ANKI_CHECK(compiler.blockReflection(compiler.get_shader_resources().push_constant_buffers[0], false,
  780. pushConstantBlock));
  781. }
  782. else if(compiler.get_shader_resources().push_constant_buffers.size() > 1)
  783. {
  784. ANKI_SHADER_COMPILER_LOGE("Expecting only a single push constants block");
  785. return Error::kUserData;
  786. }
  787. // Opaque
  788. for(const spirv_cross::Resource& res : compiler.get_shader_resources().separate_images)
  789. {
  790. ANKI_CHECK(compiler.opaqueReflection(res, opaques));
  791. }
  792. for(const spirv_cross::Resource& res : compiler.get_shader_resources().storage_images)
  793. {
  794. ANKI_CHECK(compiler.opaqueReflection(res, opaques));
  795. }
  796. for(const spirv_cross::Resource& res : compiler.get_shader_resources().separate_samplers)
  797. {
  798. ANKI_CHECK(compiler.opaqueReflection(res, opaques));
  799. }
  800. // Spec consts
  801. ANKI_CHECK(compiler.constsReflection(specializationConstants));
  802. // Workgroup sizes
  803. if(type == ShaderType::kCompute)
  804. {
  805. ANKI_CHECK(compiler.workgroupSizes(workgroupSizes[0], workgroupSizes[1], workgroupSizes[2],
  806. workgroupSizeSpecConstMask));
  807. }
  808. // Structs
  809. ANKI_CHECK(compiler.structsReflection(structs));
  810. }
  811. // Inform through the interface
  812. ANKI_CHECK(interface.setCounts(uniformBlocks.getSize(), storageBlocks.getSize(), opaques.getSize(),
  813. pushConstantBlock.getSize() == 1, specializationConstants.getSize(),
  814. structs.getSize()));
  815. for(U32 i = 0; i < uniformBlocks.getSize(); ++i)
  816. {
  817. const Block& block = uniformBlocks[i];
  818. ANKI_CHECK(interface.visitUniformBlock(i, block.m_name, block.m_set, block.m_binding, block.m_size,
  819. block.m_vars.getSize()));
  820. for(U32 j = 0; j < block.m_vars.getSize(); ++j)
  821. {
  822. const Var& var = block.m_vars[j];
  823. ANKI_CHECK(interface.visitUniformVariable(i, j, var.m_name, var.m_type, var.m_blockInfo));
  824. }
  825. }
  826. for(U32 i = 0; i < storageBlocks.getSize(); ++i)
  827. {
  828. const Block& block = storageBlocks[i];
  829. ANKI_CHECK(interface.visitStorageBlock(i, block.m_name, block.m_set, block.m_binding, block.m_size,
  830. block.m_vars.getSize()));
  831. for(U32 j = 0; j < block.m_vars.getSize(); ++j)
  832. {
  833. const Var& var = block.m_vars[j];
  834. ANKI_CHECK(interface.visitStorageVariable(i, j, var.m_name, var.m_type, var.m_blockInfo));
  835. }
  836. }
  837. if(pushConstantBlock.getSize() == 1)
  838. {
  839. ANKI_CHECK(interface.visitPushConstantsBlock(pushConstantBlock[0].m_name, pushConstantBlock[0].m_size,
  840. pushConstantBlock[0].m_vars.getSize()));
  841. for(U32 j = 0; j < pushConstantBlock[0].m_vars.getSize(); ++j)
  842. {
  843. const Var& var = pushConstantBlock[0].m_vars[j];
  844. ANKI_CHECK(interface.visitPushConstant(j, var.m_name, var.m_type, var.m_blockInfo));
  845. }
  846. }
  847. for(U32 i = 0; i < opaques.getSize(); ++i)
  848. {
  849. const Opaque& o = opaques[i];
  850. ANKI_CHECK(interface.visitOpaque(i, o.m_name, o.m_type, o.m_set, o.m_binding, o.m_arraySize));
  851. }
  852. for(U32 i = 0; i < specializationConstants.getSize(); ++i)
  853. {
  854. const Const& c = specializationConstants[i];
  855. ANKI_CHECK(interface.visitConstant(i, c.m_name, c.m_type, c.m_constantId));
  856. }
  857. if(spirv[ShaderType::kCompute].getSize())
  858. {
  859. ANKI_CHECK(interface.setWorkgroupSizes(workgroupSizes[0], workgroupSizes[1], workgroupSizes[2],
  860. workgroupSizeSpecConstMask));
  861. }
  862. for(U32 i = 0; i < structs.getSize(); ++i)
  863. {
  864. const Struct& s = structs[i];
  865. ANKI_CHECK(interface.visitStruct(i, s.m_name, s.m_members.getSize(), s.m_size));
  866. for(U32 j = 0; j < s.m_members.getSize(); ++j)
  867. {
  868. const StructMember& sm = s.m_members[j];
  869. ANKI_CHECK(interface.visitStructMember(i, s.m_name, j, sm.m_name, sm.m_type,
  870. (sm.m_structIndex != kMaxU32) ? structs[sm.m_structIndex].m_name
  871. : CString(),
  872. sm.m_offset, sm.m_arraySize));
  873. }
  874. }
  875. return Error::kNone;
  876. }
  877. Error performSpirvReflection(Array<ConstWeakArray<U8>, U32(ShaderType::kCount)> spirv, BaseMemoryPool& tmpPool,
  878. ShaderReflectionVisitorInterface& interface)
  879. {
  880. return SpirvReflector::performSpirvReflection(spirv, tmpPool, interface);
  881. }
  882. } // end namespace anki