ShaderProgramCompiler.cpp 35 KB

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