ShaderProgramCompiler.cpp 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  1. // Copyright (C) 2009-2020, 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/shader_compiler/ShaderProgramCompiler.h>
  6. #include <anki/shader_compiler/ShaderProgramParser.h>
  7. #include <anki/shader_compiler/Glslang.h>
  8. #include <anki/shader_compiler/ShaderProgramReflection.h>
  9. #include <anki/util/Serializer.h>
  10. #include <anki/util/HashMap.h>
  11. namespace anki
  12. {
  13. static const char* SHADER_BINARY_MAGIC = "ANKISDR1";
  14. const U32 SHADER_BINARY_VERSION = 1;
  15. Error ShaderProgramBinaryWrapper::serializeToFile(CString fname) const
  16. {
  17. ANKI_ASSERT(m_binary);
  18. File file;
  19. ANKI_CHECK(file.open(fname, FileOpenFlag::WRITE | FileOpenFlag::BINARY));
  20. BinarySerializer serializer;
  21. HeapAllocator<U8> tmpAlloc(m_alloc.getMemoryPool().getAllocationCallback(),
  22. m_alloc.getMemoryPool().getAllocationCallbackUserData());
  23. ANKI_CHECK(serializer.serialize(*m_binary, tmpAlloc, file));
  24. return Error::NONE;
  25. }
  26. Error ShaderProgramBinaryWrapper::deserializeFromFile(CString fname)
  27. {
  28. cleanup();
  29. File file;
  30. ANKI_CHECK(file.open(fname, FileOpenFlag::READ | FileOpenFlag::BINARY));
  31. BinaryDeserializer deserializer;
  32. ANKI_CHECK(deserializer.deserialize(m_binary, m_alloc, file));
  33. m_singleAllocation = true;
  34. if(memcmp(SHADER_BINARY_MAGIC, &m_binary->m_magic[0], 0) != 0)
  35. {
  36. ANKI_SHADER_COMPILER_LOGE("Corrupted or wrong version of shader binary: %s", fname.cstr());
  37. return Error::USER_DATA;
  38. }
  39. return Error::NONE;
  40. }
  41. void ShaderProgramBinaryWrapper::cleanup()
  42. {
  43. if(m_binary == nullptr)
  44. {
  45. return;
  46. }
  47. if(!m_singleAllocation)
  48. {
  49. for(ShaderProgramBinaryMutator& mutator : m_binary->m_mutators)
  50. {
  51. m_alloc.getMemoryPool().free(mutator.m_values.getBegin());
  52. }
  53. m_alloc.getMemoryPool().free(m_binary->m_mutators.getBegin());
  54. for(ShaderProgramBinaryCodeBlock& code : m_binary->m_codeBlocks)
  55. {
  56. m_alloc.getMemoryPool().free(code.m_binary.getBegin());
  57. }
  58. m_alloc.getMemoryPool().free(m_binary->m_codeBlocks.getBegin());
  59. for(ShaderProgramBinaryMutation& m : m_binary->m_mutations)
  60. {
  61. m_alloc.getMemoryPool().free(m.m_values.getBegin());
  62. }
  63. m_alloc.getMemoryPool().free(m_binary->m_mutations.getBegin());
  64. for(ShaderProgramBinaryBlock& block : m_binary->m_uniformBlocks)
  65. {
  66. m_alloc.getMemoryPool().free(block.m_variables.getBegin());
  67. }
  68. m_alloc.getMemoryPool().free(m_binary->m_uniformBlocks.getBegin());
  69. for(ShaderProgramBinaryBlock& block : m_binary->m_storageBlocks)
  70. {
  71. m_alloc.getMemoryPool().free(block.m_variables.getBegin());
  72. }
  73. m_alloc.getMemoryPool().free(m_binary->m_storageBlocks.getBegin());
  74. if(m_binary->m_pushConstantBlock)
  75. {
  76. m_alloc.getMemoryPool().free(m_binary->m_pushConstantBlock->m_variables.getBegin());
  77. m_alloc.getMemoryPool().free(m_binary->m_pushConstantBlock);
  78. }
  79. m_alloc.getMemoryPool().free(m_binary->m_opaques.getBegin());
  80. m_alloc.getMemoryPool().free(m_binary->m_constants.getBegin());
  81. for(ShaderProgramBinaryVariant& variant : m_binary->m_variants)
  82. {
  83. for(ShaderProgramBinaryBlockInstance& block : variant.m_uniformBlocks)
  84. {
  85. m_alloc.getMemoryPool().free(block.m_variables.getBegin());
  86. }
  87. for(ShaderProgramBinaryBlockInstance& block : variant.m_storageBlocks)
  88. {
  89. m_alloc.getMemoryPool().free(block.m_variables.getBegin());
  90. }
  91. if(variant.m_pushConstantBlock)
  92. {
  93. m_alloc.getMemoryPool().free(variant.m_pushConstantBlock->m_variables.getBegin());
  94. }
  95. m_alloc.getMemoryPool().free(variant.m_uniformBlocks.getBegin());
  96. m_alloc.getMemoryPool().free(variant.m_storageBlocks.getBegin());
  97. m_alloc.getMemoryPool().free(variant.m_pushConstantBlock);
  98. m_alloc.getMemoryPool().free(variant.m_constants.getBegin());
  99. m_alloc.getMemoryPool().free(variant.m_opaques.getBegin());
  100. }
  101. m_alloc.getMemoryPool().free(m_binary->m_variants.getBegin());
  102. }
  103. m_alloc.getMemoryPool().free(m_binary);
  104. m_binary = nullptr;
  105. m_singleAllocation = false;
  106. }
  107. /// Spin the dials. Used to compute all mutator combinations.
  108. static Bool spinDials(DynamicArrayAuto<U32>& dials, ConstWeakArray<ShaderProgramParserMutator> mutators)
  109. {
  110. ANKI_ASSERT(dials.getSize() == mutators.getSize() && dials.getSize() > 0);
  111. Bool done = true;
  112. U32 crntDial = dials.getSize() - 1;
  113. while(true)
  114. {
  115. // Turn dial
  116. ++dials[crntDial];
  117. if(dials[crntDial] >= mutators[crntDial].getValues().getSize())
  118. {
  119. if(crntDial == 0)
  120. {
  121. // Reached the 1st dial, stop spinning
  122. done = true;
  123. break;
  124. }
  125. else
  126. {
  127. dials[crntDial] = 0;
  128. --crntDial;
  129. }
  130. }
  131. else
  132. {
  133. done = false;
  134. break;
  135. }
  136. }
  137. return done;
  138. }
  139. static Error compileSpirv(ConstWeakArray<MutatorValue> mutation, const ShaderProgramParser& parser,
  140. GenericMemoryPoolAllocator<U8>& tmpAlloc,
  141. Array<DynamicArrayAuto<U8>, U32(ShaderType::COUNT)>& spirv)
  142. {
  143. // Generate the source and the rest for the variant
  144. ShaderProgramParserVariant parserVariant;
  145. ANKI_CHECK(parser.generateVariant(mutation, parserVariant));
  146. // Compile stages
  147. for(ShaderType shaderType : EnumIterable<ShaderType>())
  148. {
  149. if(!(shaderTypeToBit(shaderType) & parser.getShaderTypes()))
  150. {
  151. continue;
  152. }
  153. // Compile
  154. ANKI_CHECK(compilerGlslToSpirv(parserVariant.getSource(shaderType), shaderType, tmpAlloc, spirv[shaderType]));
  155. ANKI_ASSERT(spirv[shaderType].getSize() > 0);
  156. }
  157. return Error::NONE;
  158. }
  159. static void compileVariantAsync(ConstWeakArray<MutatorValue> mutation, const ShaderProgramParser& parser,
  160. ShaderProgramBinaryVariant& variant,
  161. DynamicArrayAuto<ShaderProgramBinaryCodeBlock>& codeBlocks,
  162. DynamicArrayAuto<U64>& codeBlockHashes, GenericMemoryPoolAllocator<U8>& tmpAlloc,
  163. GenericMemoryPoolAllocator<U8>& binaryAlloc,
  164. ShaderProgramAsyncTaskInterface& taskManager, Mutex& mtx, Atomic<I32>& error)
  165. {
  166. variant = {};
  167. class Ctx
  168. {
  169. public:
  170. GenericMemoryPoolAllocator<U8> m_tmpAlloc;
  171. GenericMemoryPoolAllocator<U8> m_binaryAlloc;
  172. DynamicArrayAuto<MutatorValue> m_mutation = {m_tmpAlloc};
  173. const ShaderProgramParser* m_parser;
  174. ShaderProgramBinaryVariant* m_variant;
  175. DynamicArrayAuto<ShaderProgramBinaryCodeBlock>* m_codeBlocks;
  176. DynamicArrayAuto<U64>* m_codeBlockHashes;
  177. Mutex* m_mtx;
  178. Atomic<I32>* m_err;
  179. Ctx(GenericMemoryPoolAllocator<U8> tmpAlloc)
  180. : m_tmpAlloc(tmpAlloc)
  181. {
  182. }
  183. };
  184. Ctx* ctx = tmpAlloc.newInstance<Ctx>(tmpAlloc);
  185. ctx->m_binaryAlloc = binaryAlloc;
  186. ctx->m_mutation.create(mutation.getSize());
  187. memcpy(ctx->m_mutation.getBegin(), mutation.getBegin(), mutation.getSizeInBytes());
  188. ctx->m_parser = &parser;
  189. ctx->m_variant = &variant;
  190. ctx->m_codeBlocks = &codeBlocks;
  191. ctx->m_codeBlockHashes = &codeBlockHashes;
  192. ctx->m_mtx = &mtx;
  193. ctx->m_err = &error;
  194. auto callback = [](void* userData) {
  195. Ctx& ctx = *static_cast<Ctx*>(userData);
  196. GenericMemoryPoolAllocator<U8>& tmpAlloc = ctx.m_tmpAlloc;
  197. if(ctx.m_err->load() != 0)
  198. {
  199. // Cleanup and return
  200. tmpAlloc.deleteInstance(&ctx);
  201. return;
  202. }
  203. // All good, compile the variant
  204. Array<DynamicArrayAuto<U8>, U32(ShaderType::COUNT)> spirvs = {{{tmpAlloc},
  205. {tmpAlloc},
  206. {tmpAlloc},
  207. {tmpAlloc},
  208. {tmpAlloc},
  209. {tmpAlloc},
  210. {tmpAlloc},
  211. {tmpAlloc},
  212. {tmpAlloc},
  213. {tmpAlloc},
  214. {tmpAlloc},
  215. {tmpAlloc}}};
  216. const Error err = compileSpirv(ctx.m_mutation, *ctx.m_parser, tmpAlloc, spirvs);
  217. if(!err)
  218. {
  219. // No error, check if the spirvs are common with some other variant and store it
  220. LockGuard<Mutex> lock(*ctx.m_mtx);
  221. for(ShaderType shaderType : EnumIterable<ShaderType>())
  222. {
  223. DynamicArrayAuto<U8>& spirv = spirvs[shaderType];
  224. if(spirv.isEmpty())
  225. {
  226. ctx.m_variant->m_codeBlockIndices[shaderType] = MAX_U32;
  227. continue;
  228. }
  229. // Check if the spirv is already generated
  230. const U64 newHash = computeHash(&spirv[0], spirv.getSize());
  231. Bool found = false;
  232. for(U32 i = 0; i < ctx.m_codeBlockHashes->getSize(); ++i)
  233. {
  234. if((*ctx.m_codeBlockHashes)[i] == newHash)
  235. {
  236. // Found it
  237. ctx.m_variant->m_codeBlockIndices[shaderType] = i;
  238. found = true;
  239. break;
  240. }
  241. }
  242. // Create it if not found
  243. if(!found)
  244. {
  245. U8* code = ctx.m_binaryAlloc.allocate(spirv.getSizeInBytes());
  246. memcpy(code, &spirv[0], spirv.getSizeInBytes());
  247. ShaderProgramBinaryCodeBlock block;
  248. block.m_binary.setArray(code, U32(spirv.getSizeInBytes()));
  249. ctx.m_codeBlocks->emplaceBack(block);
  250. ctx.m_codeBlockHashes->emplaceBack(newHash);
  251. ctx.m_variant->m_codeBlockIndices[shaderType] = ctx.m_codeBlocks->getSize() - 1;
  252. }
  253. }
  254. }
  255. else
  256. {
  257. ctx.m_err->store(err._getCode());
  258. }
  259. // Cleanup
  260. tmpAlloc.deleteInstance(&ctx);
  261. };
  262. taskManager.enqueueTask(callback, ctx);
  263. }
  264. class Refl final : public ShaderReflectionVisitorInterface
  265. {
  266. public:
  267. GenericMemoryPoolAllocator<U8> m_alloc;
  268. /// Will be stored in the binary
  269. /// @{
  270. /// [blockType][blockIdx]
  271. Array<DynamicArrayAuto<ShaderProgramBinaryBlock>, 3> m_blocks = {{m_alloc, m_alloc, m_alloc}};
  272. /// [blockType][blockIdx][varIdx]
  273. Array<DynamicArrayAuto<DynamicArrayAuto<ShaderProgramBinaryVariable>>, 3> m_vars = {
  274. {{m_alloc}, {m_alloc}, {m_alloc}}};
  275. DynamicArrayAuto<ShaderProgramBinaryOpaque> m_opaque = {m_alloc};
  276. DynamicArrayAuto<ShaderProgramBinaryConstant> m_consts = {m_alloc};
  277. /// @}
  278. /// Will be stored in a variant
  279. /// @{
  280. /// [blockType][blockInstanceIdx]
  281. Array<DynamicArrayAuto<ShaderProgramBinaryBlockInstance>, 3> m_blockInstances = {{m_alloc, m_alloc, m_alloc}};
  282. DynamicArrayAuto<ShaderProgramBinaryOpaqueInstance> m_opaqueInstances = {m_alloc};
  283. DynamicArrayAuto<ShaderProgramBinaryConstantInstance> m_constInstances = {m_alloc};
  284. Array<U32, 3> m_workgroupSizes = {{MAX_U32, MAX_U32, MAX_U32}};
  285. Array<U32, 3> m_workgroupSizesConstants = {{MAX_U32, MAX_U32, MAX_U32}};
  286. /// @}
  287. Refl(const GenericMemoryPoolAllocator<U8>& alloc)
  288. : m_alloc(alloc)
  289. {
  290. }
  291. Error setWorkgroupSizes(U32 x, U32 y, U32 z, U32 specConstMask) final
  292. {
  293. m_workgroupSizesConstants = {{MAX_U32, MAX_U32, MAX_U32}};
  294. m_workgroupSizes = {{MAX_U32, MAX_U32, MAX_U32}};
  295. const Array<U32, 3> input = {{x, y, z}};
  296. for(U32 i = 0; i < 3; ++i)
  297. {
  298. if(specConstMask & (1 << i))
  299. {
  300. for(const ShaderProgramBinaryConstantInstance& c : m_constInstances)
  301. {
  302. if(m_consts[c.m_index].m_constantId == input[i])
  303. {
  304. m_workgroupSizesConstants[i] = c.m_index;
  305. break;
  306. }
  307. }
  308. if(m_workgroupSizesConstants[i] == MAX_U32)
  309. {
  310. ANKI_SHADER_COMPILER_LOGE("Reflection identified workgroup size dimension %u as spec constant but "
  311. "not such spec constant was found",
  312. i);
  313. return Error::USER_DATA;
  314. }
  315. }
  316. else
  317. {
  318. m_workgroupSizes[i] = input[i];
  319. }
  320. }
  321. return Error::NONE;
  322. }
  323. Error setCounts(U32 uniformBlockCount, U32 storageBlockCount, U32 opaqueCount, Bool pushConstantBlock,
  324. U32 constCount) final
  325. {
  326. m_blockInstances[0].create(uniformBlockCount);
  327. m_blockInstances[1].create(storageBlockCount);
  328. if(pushConstantBlock)
  329. {
  330. m_blockInstances[2].create(1);
  331. }
  332. m_opaqueInstances.create(opaqueCount);
  333. m_constInstances.create(constCount);
  334. return Error::NONE;
  335. }
  336. Error visitUniformBlock(U32 idx, CString name, U32 set, U32 binding, U32 size, U32 varCount) final
  337. {
  338. return visitAnyBlock(idx, name, set, binding, size, varCount, 0);
  339. }
  340. Error visitUniformVariable(U32 blockIdx, U32 idx, CString name, ShaderVariableDataType type,
  341. const ShaderVariableBlockInfo& blockInfo) final
  342. {
  343. return visitAnyVariable(blockIdx, idx, name, type, blockInfo, 0);
  344. }
  345. Error visitStorageBlock(U32 idx, CString name, U32 set, U32 binding, U32 size, U32 varCount) final
  346. {
  347. return visitAnyBlock(idx, name, set, binding, size, varCount, 1);
  348. }
  349. Error visitStorageVariable(U32 blockIdx, U32 idx, CString name, ShaderVariableDataType type,
  350. const ShaderVariableBlockInfo& blockInfo) final
  351. {
  352. return visitAnyVariable(blockIdx, idx, name, type, blockInfo, 1);
  353. }
  354. Error visitPushConstantsBlock(CString name, U32 size, U32 varCount) final
  355. {
  356. return visitAnyBlock(0, name, 0, 0, size, varCount, 2);
  357. }
  358. Error visitPushConstant(U32 idx, CString name, ShaderVariableDataType type,
  359. const ShaderVariableBlockInfo& blockInfo) final
  360. {
  361. return visitAnyVariable(0, idx, name, type, blockInfo, 2);
  362. }
  363. Error visitOpaque(U32 instanceIdx, CString name, ShaderVariableDataType type, U32 set, U32 binding,
  364. U32 arraySize) final
  365. {
  366. // Find the opaque
  367. U32 opaqueIdx = MAX_U32;
  368. for(U32 i = 0; i < m_opaque.getSize(); ++i)
  369. {
  370. if(name == m_opaque[i].m_name.getBegin())
  371. {
  372. if(type != m_opaque[i].m_type || set != m_opaque[i].m_set || binding != m_opaque[i].m_binding)
  373. {
  374. ANKI_SHADER_COMPILER_LOGE(
  375. "The set, binding and type can't difer between shader variants for opaque: %s", name.cstr());
  376. return Error::USER_DATA;
  377. }
  378. opaqueIdx = i;
  379. break;
  380. }
  381. }
  382. // Create the opaque
  383. if(opaqueIdx == MAX_U32)
  384. {
  385. ShaderProgramBinaryOpaque& o = *m_opaque.emplaceBack();
  386. ANKI_CHECK(setName(name, o.m_name));
  387. o.m_type = type;
  388. o.m_binding = binding;
  389. o.m_set = set;
  390. opaqueIdx = m_opaque.getSize() - 1;
  391. }
  392. // Create the instance
  393. ShaderProgramBinaryOpaqueInstance& instance = m_opaqueInstances[instanceIdx];
  394. instance.m_index = opaqueIdx;
  395. instance.m_arraySize = arraySize;
  396. return Error::NONE;
  397. }
  398. Error visitConstant(U32 instanceIdx, CString name, ShaderVariableDataType type, U32 constantId) final
  399. {
  400. // Find const
  401. U32 constIdx = MAX_U32;
  402. for(U32 i = 0; i < m_consts.getSize(); ++i)
  403. {
  404. if(name == m_consts[i].m_name.getBegin())
  405. {
  406. if(type != m_consts[i].m_type || constantId != m_consts[i].m_constantId)
  407. {
  408. ANKI_SHADER_COMPILER_LOGE(
  409. "The type, constantId and stages can't difer between shader variants for const: %s",
  410. name.cstr());
  411. return Error::USER_DATA;
  412. }
  413. constIdx = i;
  414. break;
  415. }
  416. }
  417. // Create the const
  418. if(constIdx == MAX_U32)
  419. {
  420. ShaderProgramBinaryConstant& c = *m_consts.emplaceBack();
  421. ANKI_CHECK(setName(name, c.m_name));
  422. c.m_type = type;
  423. c.m_constantId = constantId;
  424. constIdx = m_consts.getSize() - 1;
  425. }
  426. // Create the instance
  427. ShaderProgramBinaryConstantInstance& instance = m_constInstances[instanceIdx];
  428. instance.m_index = constIdx;
  429. return Error::NONE;
  430. }
  431. static ANKI_USE_RESULT Error setName(CString in, Array<char, MAX_SHADER_BINARY_NAME_LENGTH + 1>& out)
  432. {
  433. if(in.getLength() + 1 > MAX_SHADER_BINARY_NAME_LENGTH)
  434. {
  435. ANKI_SHADER_COMPILER_LOGE("Name too long: %s", in.cstr());
  436. return Error::USER_DATA;
  437. }
  438. else if(in.getLength() == 0)
  439. {
  440. ANKI_SHADER_COMPILER_LOGE("Found an empty string as name");
  441. return Error::USER_DATA;
  442. }
  443. else
  444. {
  445. memcpy(out.getBegin(), in.getBegin(), in.getLength() + 1);
  446. }
  447. return Error::NONE;
  448. }
  449. static ANKI_USE_RESULT Error findBlock(CString name, U32 set, U32 binding,
  450. ConstWeakArray<ShaderProgramBinaryBlock> arr, U32& idx)
  451. {
  452. idx = MAX_U32;
  453. for(U32 i = 0; i < arr.getSize(); ++i)
  454. {
  455. const ShaderProgramBinaryBlock& block = arr[i];
  456. if(block.m_name.getBegin() == name)
  457. {
  458. if(set != block.m_set || binding != block.m_binding)
  459. {
  460. ANKI_SHADER_COMPILER_LOGE("The set and binding can't difer between shader variants for block: %s",
  461. name.cstr());
  462. return Error::USER_DATA;
  463. }
  464. idx = i;
  465. break;
  466. }
  467. return Error::NONE;
  468. }
  469. return Error::NONE;
  470. }
  471. Error visitAnyBlock(U32 blockInstanceIdx, CString name, U32 set, U32 binding, U32 size, U32 varSize, U32 blockType)
  472. {
  473. // Init the block
  474. U32 blockIdx;
  475. ANKI_CHECK(findBlock(name, set, binding, m_blocks[blockType], blockIdx));
  476. if(blockIdx == MAX_U32)
  477. {
  478. // Not found, create it
  479. ShaderProgramBinaryBlock& block = *m_blocks[blockType].emplaceBack();
  480. ANKI_CHECK(setName(name, block.m_name));
  481. block.m_set = set;
  482. block.m_binding = binding;
  483. blockIdx = m_blocks[blockType].getSize() - 1;
  484. // Create some storage for vars as well
  485. m_vars[blockType].emplaceBack(m_alloc);
  486. ANKI_ASSERT(m_vars[blockType].getSize() == m_blocks[blockType].getSize());
  487. }
  488. // Init the instance
  489. ShaderProgramBinaryBlockInstance& instance = m_blockInstances[blockType][blockInstanceIdx];
  490. instance.m_index = blockIdx;
  491. instance.m_size = size;
  492. instance.m_variables.setArray(m_alloc.newArray<ShaderProgramBinaryVariableInstance>(varSize), varSize);
  493. return Error::NONE;
  494. }
  495. Error visitAnyVariable(U32 blockInstanceIdx, U32 varInstanceIdx, CString name, ShaderVariableDataType type,
  496. const ShaderVariableBlockInfo& blockInfo, U32 blockType)
  497. {
  498. // Find the variable
  499. U32 varIdx = MAX_U32;
  500. const U32 blockIdx = m_blockInstances[blockType][blockInstanceIdx].m_index;
  501. for(U32 i = 0; i < m_vars[blockType][blockIdx].getSize(); ++i)
  502. {
  503. const ShaderProgramBinaryVariable& var = m_vars[blockType][blockIdx][i];
  504. if(var.m_name.getBegin() == name)
  505. {
  506. if(var.m_type != type)
  507. {
  508. ANKI_SHADER_COMPILER_LOGE("The type should not differ between variants for variable: %s",
  509. name.cstr());
  510. return Error::USER_DATA;
  511. }
  512. varIdx = i;
  513. break;
  514. }
  515. }
  516. // Create the variable
  517. if(varIdx == MAX_U32)
  518. {
  519. ShaderProgramBinaryVariable& var = *m_vars[blockType][blockIdx].emplaceBack();
  520. ANKI_CHECK(setName(name, var.m_name));
  521. var.m_type = type;
  522. varIdx = m_vars[blockType][blockIdx].getSize() - 1;
  523. }
  524. // Init the instance
  525. ShaderProgramBinaryVariableInstance& instance =
  526. m_blockInstances[blockType][blockInstanceIdx].m_variables[varInstanceIdx];
  527. instance.m_blockInfo = blockInfo;
  528. instance.m_index = varIdx;
  529. return Error::NONE;
  530. }
  531. };
  532. static Error doReflection(ShaderProgramBinary& binary, GenericMemoryPoolAllocator<U8>& tmpAlloc,
  533. GenericMemoryPoolAllocator<U8>& binaryAlloc)
  534. {
  535. ANKI_ASSERT(binary.m_variants.getSize() > 0);
  536. Refl refl(binaryAlloc);
  537. for(ShaderProgramBinaryVariant& variant : binary.m_variants)
  538. {
  539. Array<ConstWeakArray<U8>, U32(ShaderType::COUNT)> spirvs;
  540. for(ShaderType stage : EnumIterable<ShaderType>())
  541. {
  542. if(variant.m_codeBlockIndices[stage] != MAX_U32)
  543. {
  544. spirvs[stage] = binary.m_codeBlocks[variant.m_codeBlockIndices[stage]].m_binary;
  545. }
  546. }
  547. ANKI_CHECK(performSpirvReflection(spirvs, tmpAlloc, refl));
  548. // Store the instances
  549. if(refl.m_blockInstances[0].getSize())
  550. {
  551. ShaderProgramBinaryBlockInstance* instances;
  552. U32 size, storageSize;
  553. refl.m_blockInstances[0].moveAndReset(instances, size, storageSize);
  554. variant.m_uniformBlocks.setArray(instances, size);
  555. }
  556. if(refl.m_blockInstances[1].getSize())
  557. {
  558. ShaderProgramBinaryBlockInstance* instances;
  559. U32 size, storageSize;
  560. refl.m_blockInstances[1].moveAndReset(instances, size, storageSize);
  561. variant.m_storageBlocks.setArray(instances, size);
  562. }
  563. if(refl.m_blockInstances[2].getSize())
  564. {
  565. ShaderProgramBinaryBlockInstance* instances;
  566. U32 size, storageSize;
  567. refl.m_blockInstances[2].moveAndReset(instances, size, storageSize);
  568. ANKI_ASSERT(size == 1);
  569. variant.m_pushConstantBlock = instances;
  570. }
  571. if(refl.m_opaqueInstances.getSize())
  572. {
  573. ShaderProgramBinaryOpaqueInstance* instances;
  574. U32 size, storageSize;
  575. refl.m_opaqueInstances.moveAndReset(instances, size, storageSize);
  576. variant.m_opaques.setArray(instances, size);
  577. }
  578. if(refl.m_constInstances.getSize())
  579. {
  580. ShaderProgramBinaryConstantInstance* instances;
  581. U32 size, storageSize;
  582. refl.m_constInstances.moveAndReset(instances, size, storageSize);
  583. variant.m_constants.setArray(instances, size);
  584. }
  585. variant.m_workgroupSizes = refl.m_workgroupSizes;
  586. variant.m_workgroupSizesConstants = refl.m_workgroupSizesConstants;
  587. }
  588. if(refl.m_blocks[0].getSize())
  589. {
  590. ShaderProgramBinaryBlock* blocks;
  591. U32 size, storageSize;
  592. refl.m_blocks[0].moveAndReset(blocks, size, storageSize);
  593. binary.m_uniformBlocks.setArray(blocks, size);
  594. for(U32 i = 0; i < size; ++i)
  595. {
  596. ShaderProgramBinaryVariable* vars;
  597. U32 varSize, varStorageSize;
  598. refl.m_vars[0][i].moveAndReset(vars, varSize, varStorageSize);
  599. binary.m_uniformBlocks[i].m_variables.setArray(vars, varSize);
  600. }
  601. }
  602. if(refl.m_blocks[1].getSize())
  603. {
  604. ShaderProgramBinaryBlock* blocks;
  605. U32 size, storageSize;
  606. refl.m_blocks[1].moveAndReset(blocks, size, storageSize);
  607. binary.m_storageBlocks.setArray(blocks, size);
  608. for(U32 i = 0; i < size; ++i)
  609. {
  610. ShaderProgramBinaryVariable* vars;
  611. U32 varSize, varStorageSize;
  612. refl.m_vars[1][i].moveAndReset(vars, varSize, varStorageSize);
  613. binary.m_storageBlocks[i].m_variables.setArray(vars, varSize);
  614. }
  615. }
  616. if(refl.m_blocks[2].getSize())
  617. {
  618. ShaderProgramBinaryBlock* blocks;
  619. U32 size, storageSize;
  620. refl.m_blocks[2].moveAndReset(blocks, size, storageSize);
  621. ANKI_ASSERT(size == 1);
  622. binary.m_pushConstantBlock = blocks;
  623. ShaderProgramBinaryVariable* vars;
  624. U32 varSize, varStorageSize;
  625. refl.m_vars[2][0].moveAndReset(vars, varSize, varStorageSize);
  626. binary.m_pushConstantBlock->m_variables.setArray(vars, varSize);
  627. }
  628. if(refl.m_opaque.getSize())
  629. {
  630. ShaderProgramBinaryOpaque* opaques;
  631. U32 size, storageSize;
  632. refl.m_opaque.moveAndReset(opaques, size, storageSize);
  633. binary.m_opaques.setArray(opaques, size);
  634. }
  635. if(refl.m_consts.getSize())
  636. {
  637. ShaderProgramBinaryConstant* consts;
  638. U32 size, storageSize;
  639. refl.m_consts.moveAndReset(consts, size, storageSize);
  640. binary.m_constants.setArray(consts, size);
  641. }
  642. return Error::NONE;
  643. }
  644. Error compileShaderProgramInternal(CString fname, ShaderProgramFilesystemInterface& fsystem,
  645. ShaderProgramPostParseInterface* postParseCallback,
  646. ShaderProgramAsyncTaskInterface* taskManager_,
  647. GenericMemoryPoolAllocator<U8> tempAllocator,
  648. const GpuDeviceCapabilities& gpuCapabilities, const BindlessLimits& bindlessLimits,
  649. ShaderProgramBinaryWrapper& binaryW)
  650. {
  651. // Initialize the binary
  652. binaryW.cleanup();
  653. binaryW.m_singleAllocation = false;
  654. GenericMemoryPoolAllocator<U8> binaryAllocator = binaryW.m_alloc;
  655. binaryW.m_binary = binaryAllocator.newInstance<ShaderProgramBinary>();
  656. ShaderProgramBinary& binary = *binaryW.m_binary;
  657. binary = {};
  658. memcpy(&binary.m_magic[0], SHADER_BINARY_MAGIC, 8);
  659. // Parse source
  660. ShaderProgramParser parser(fname, &fsystem, tempAllocator, gpuCapabilities, bindlessLimits);
  661. ANKI_CHECK(parser.parse());
  662. if(postParseCallback && postParseCallback->skipCompilation(parser.getHash()))
  663. {
  664. return Error::NONE;
  665. }
  666. // Get mutators
  667. U32 mutationCount = 0;
  668. if(parser.getMutators().getSize() > 0)
  669. {
  670. binary.m_mutators.setArray(binaryAllocator.newArray<ShaderProgramBinaryMutator>(parser.getMutators().getSize()),
  671. parser.getMutators().getSize());
  672. for(U32 i = 0; i < binary.m_mutators.getSize(); ++i)
  673. {
  674. ShaderProgramBinaryMutator& out = binary.m_mutators[i];
  675. const ShaderProgramParserMutator& in = parser.getMutators()[i];
  676. ANKI_ASSERT(in.getName().getLength() < out.m_name.getSize());
  677. memcpy(&out.m_name[0], in.getName().cstr(), in.getName().getLength() + 1);
  678. out.m_values.setArray(binaryAllocator.newArray<I32>(in.getValues().getSize()), in.getValues().getSize());
  679. memcpy(out.m_values.getBegin(), in.getValues().getBegin(), in.getValues().getSizeInBytes());
  680. // Update the count
  681. mutationCount = (i == 0) ? out.m_values.getSize() : mutationCount * out.m_values.getSize();
  682. }
  683. }
  684. else
  685. {
  686. ANKI_ASSERT(binary.m_mutators.getSize() == 0);
  687. }
  688. // Create all variants
  689. Mutex mtx;
  690. Atomic<I32> errorAtomic(0);
  691. class SyncronousShaderProgramAsyncTaskInterface : public ShaderProgramAsyncTaskInterface
  692. {
  693. public:
  694. void enqueueTask(void (*callback)(void* userData), void* userData) final
  695. {
  696. callback(userData);
  697. }
  698. Error joinTasks() final
  699. {
  700. // Nothing
  701. return Error::NONE;
  702. }
  703. } syncTaskManager;
  704. ShaderProgramAsyncTaskInterface& taskManager = (taskManager_) ? *taskManager_ : syncTaskManager;
  705. if(parser.getMutators().getSize() > 0)
  706. {
  707. // Initialize
  708. DynamicArrayAuto<MutatorValue> originalMutationValues(tempAllocator, parser.getMutators().getSize());
  709. DynamicArrayAuto<MutatorValue> rewrittenMutationValues(tempAllocator, parser.getMutators().getSize());
  710. DynamicArrayAuto<U32> dials(tempAllocator, parser.getMutators().getSize(), 0);
  711. DynamicArrayAuto<ShaderProgramBinaryVariant> variants(binaryAllocator);
  712. DynamicArrayAuto<ShaderProgramBinaryCodeBlock> codeBlocks(binaryAllocator);
  713. DynamicArrayAuto<ShaderProgramBinaryMutation> mutations(binaryAllocator, mutationCount);
  714. DynamicArrayAuto<U64> codeBlockHashes(tempAllocator);
  715. HashMapAuto<U64, U32> mutationHashToIdx(tempAllocator);
  716. // Grow the storage of the variants array. Can't have it resize, threads will work on stale data
  717. variants.resizeStorage(mutationCount);
  718. const ShaderProgramBinaryVariant* baseVariant = nullptr;
  719. mutationCount = 0;
  720. // Spin for all possible combinations of mutators and
  721. // - Create the spirv
  722. // - Populate the binary variant
  723. do
  724. {
  725. // Create the mutation
  726. for(U32 i = 0; i < parser.getMutators().getSize(); ++i)
  727. {
  728. originalMutationValues[i] = parser.getMutators()[i].getValues()[dials[i]];
  729. rewrittenMutationValues[i] = originalMutationValues[i];
  730. }
  731. ShaderProgramBinaryMutation& mutation = mutations[mutationCount++];
  732. mutation.m_values.setArray(binaryAllocator.newArray<MutatorValue>(originalMutationValues.getSize()),
  733. originalMutationValues.getSize());
  734. memcpy(mutation.m_values.getBegin(), originalMutationValues.getBegin(),
  735. originalMutationValues.getSizeInBytes());
  736. mutation.m_hash = computeHash(originalMutationValues.getBegin(), originalMutationValues.getSizeInBytes());
  737. ANKI_ASSERT(mutation.m_hash > 0);
  738. const Bool rewritten = parser.rewriteMutation(
  739. WeakArray<MutatorValue>(rewrittenMutationValues.getBegin(), rewrittenMutationValues.getSize()));
  740. // Create the variant
  741. if(!rewritten)
  742. {
  743. // New and unique mutation and thus variant, add it
  744. ShaderProgramBinaryVariant& variant = *variants.emplaceBack();
  745. baseVariant = (baseVariant == nullptr) ? variants.getBegin() : baseVariant;
  746. compileVariantAsync(originalMutationValues, parser, variant, codeBlocks, codeBlockHashes, tempAllocator,
  747. binaryAllocator, taskManager, mtx, errorAtomic);
  748. mutation.m_variantIndex = variants.getSize() - 1;
  749. ANKI_ASSERT(mutationHashToIdx.find(mutation.m_hash) == mutationHashToIdx.getEnd());
  750. mutationHashToIdx.emplace(mutation.m_hash, mutationCount - 1);
  751. }
  752. else
  753. {
  754. // Check if the rewritten mutation exists
  755. const U64 otherMutationHash =
  756. computeHash(rewrittenMutationValues.getBegin(), rewrittenMutationValues.getSizeInBytes());
  757. auto it = mutationHashToIdx.find(otherMutationHash);
  758. ShaderProgramBinaryVariant* variant = nullptr;
  759. if(it == mutationHashToIdx.getEnd())
  760. {
  761. // Rewrite variant not found, create it
  762. variant = variants.emplaceBack();
  763. baseVariant = (baseVariant == nullptr) ? variants.getBegin() : baseVariant;
  764. compileVariantAsync(originalMutationValues, parser, *variant, codeBlocks, codeBlockHashes,
  765. tempAllocator, binaryAllocator, taskManager, mtx, errorAtomic);
  766. ShaderProgramBinaryMutation& otherMutation = mutations[mutationCount++];
  767. otherMutation.m_values.setArray(
  768. binaryAllocator.newArray<MutatorValue>(rewrittenMutationValues.getSize()),
  769. rewrittenMutationValues.getSize());
  770. memcpy(otherMutation.m_values.getBegin(), rewrittenMutationValues.getBegin(),
  771. rewrittenMutationValues.getSizeInBytes());
  772. mutation.m_hash = otherMutationHash;
  773. mutation.m_variantIndex = variants.getSize() - 1;
  774. it = mutationHashToIdx.emplace(otherMutationHash, mutationCount - 1);
  775. }
  776. // Setup the new mutation
  777. mutation.m_variantIndex = mutations[*it].m_variantIndex;
  778. mutationHashToIdx.emplace(mutation.m_hash, U32(&mutation - mutations.getBegin()));
  779. }
  780. } while(!spinDials(dials, parser.getMutators()));
  781. ANKI_ASSERT(mutationCount == mutations.getSize());
  782. ANKI_ASSERT(baseVariant == variants.getBegin() && "Can't have the variants array grow");
  783. // Done, wait the threads
  784. ANKI_CHECK(taskManager.joinTasks());
  785. ANKI_CHECK(Error(errorAtomic.getNonAtomically()));
  786. // Store temp containers to binary
  787. U32 size, storage;
  788. ShaderProgramBinaryVariant* firstVariant;
  789. variants.moveAndReset(firstVariant, size, storage);
  790. binary.m_variants.setArray(firstVariant, size);
  791. ShaderProgramBinaryCodeBlock* firstCodeBlock;
  792. codeBlocks.moveAndReset(firstCodeBlock, size, storage);
  793. binary.m_codeBlocks.setArray(firstCodeBlock, size);
  794. ShaderProgramBinaryMutation* firstMutation;
  795. mutations.moveAndReset(firstMutation, size, storage);
  796. binary.m_mutations.setArray(firstMutation, size);
  797. }
  798. else
  799. {
  800. DynamicArrayAuto<MutatorValue> mutation(tempAllocator);
  801. DynamicArrayAuto<ShaderProgramBinaryCodeBlock> codeBlocks(binaryAllocator);
  802. DynamicArrayAuto<U64> codeBlockHashes(tempAllocator);
  803. binary.m_variants.setArray(binaryAllocator.newInstance<ShaderProgramBinaryVariant>(), 1);
  804. compileVariantAsync(mutation, parser, binary.m_variants[0], codeBlocks, codeBlockHashes, tempAllocator,
  805. binaryAllocator, taskManager, mtx, errorAtomic);
  806. ANKI_CHECK(taskManager.joinTasks());
  807. ANKI_CHECK(Error(errorAtomic.getNonAtomically()));
  808. ANKI_ASSERT(codeBlocks.getSize() == U32(__builtin_popcount(U32(parser.getShaderTypes()))));
  809. ShaderProgramBinaryCodeBlock* firstCodeBlock;
  810. U32 size, storage;
  811. codeBlocks.moveAndReset(firstCodeBlock, size, storage);
  812. binary.m_codeBlocks.setArray(firstCodeBlock, size);
  813. binary.m_mutations.setArray(binaryAllocator.newInstance<ShaderProgramBinaryMutation>(), 1);
  814. binary.m_mutations[0].m_hash = 1;
  815. binary.m_mutations[0].m_variantIndex = 0;
  816. }
  817. // Sort the mutations
  818. std::sort(
  819. binary.m_mutations.getBegin(), binary.m_mutations.getEnd(),
  820. [](const ShaderProgramBinaryMutation& a, const ShaderProgramBinaryMutation& b) { return a.m_hash < b.m_hash; });
  821. // Misc
  822. binary.m_presentShaderTypes = parser.getShaderTypes();
  823. // Reflection
  824. ANKI_CHECK(doReflection(binary, tempAllocator, binaryAllocator));
  825. return Error::NONE;
  826. }
  827. Error compileShaderProgram(CString fname, ShaderProgramFilesystemInterface& fsystem,
  828. ShaderProgramPostParseInterface* postParseCallback,
  829. ShaderProgramAsyncTaskInterface* taskManager, GenericMemoryPoolAllocator<U8> tempAllocator,
  830. const GpuDeviceCapabilities& gpuCapabilities, const BindlessLimits& bindlessLimits,
  831. ShaderProgramBinaryWrapper& binaryW)
  832. {
  833. const Error err = compileShaderProgramInternal(fname, fsystem, postParseCallback, taskManager, tempAllocator,
  834. gpuCapabilities, bindlessLimits, binaryW);
  835. if(err)
  836. {
  837. ANKI_SHADER_COMPILER_LOGE("Failed to compile: %s", fname.cstr());
  838. }
  839. return err;
  840. }
  841. } // end namespace anki