ShaderProgramReflection.cpp 25 KB

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