ShaderProgramCompiler.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. // Copyright (C) 2009-2023, 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/Dxc.h>
  8. #include <AnKi/Util/Serializer.h>
  9. #include <AnKi/Util/HashMap.h>
  10. #include <SpirvCross/spirv_cross.hpp>
  11. namespace anki {
  12. void freeShaderProgramBinary(ShaderProgramBinary*& binary)
  13. {
  14. if(binary == nullptr)
  15. {
  16. return;
  17. }
  18. BaseMemoryPool& mempool = ShaderCompilerMemoryPool::getSingleton();
  19. for(ShaderProgramBinaryCodeBlock& code : binary->m_codeBlocks)
  20. {
  21. mempool.free(code.m_binary.getBegin());
  22. }
  23. mempool.free(binary->m_codeBlocks.getBegin());
  24. for(ShaderProgramBinaryMutator& mutator : binary->m_mutators)
  25. {
  26. mempool.free(mutator.m_values.getBegin());
  27. }
  28. mempool.free(binary->m_mutators.getBegin());
  29. for(ShaderProgramBinaryMutation& m : binary->m_mutations)
  30. {
  31. mempool.free(m.m_values.getBegin());
  32. }
  33. mempool.free(binary->m_mutations.getBegin());
  34. for(ShaderProgramBinaryVariant& variant : binary->m_variants)
  35. {
  36. mempool.free(variant.m_techniqueCodeBlocks.getBegin());
  37. }
  38. mempool.free(binary->m_variants.getBegin());
  39. mempool.free(binary->m_techniques.getBegin());
  40. for(ShaderProgramBinaryStruct& s : binary->m_structs)
  41. {
  42. mempool.free(s.m_members.getBegin());
  43. }
  44. mempool.free(binary->m_structs.getBegin());
  45. mempool.free(binary);
  46. binary = nullptr;
  47. }
  48. /// Spin the dials. Used to compute all mutator combinations.
  49. static Bool spinDials(ShaderCompilerDynamicArray<U32>& dials, ConstWeakArray<ShaderProgramParserMutator> mutators)
  50. {
  51. ANKI_ASSERT(dials.getSize() == mutators.getSize() && dials.getSize() > 0);
  52. Bool done = true;
  53. U32 crntDial = dials.getSize() - 1;
  54. while(true)
  55. {
  56. // Turn dial
  57. ++dials[crntDial];
  58. if(dials[crntDial] >= mutators[crntDial].m_values.getSize())
  59. {
  60. if(crntDial == 0)
  61. {
  62. // Reached the 1st dial, stop spinning
  63. done = true;
  64. break;
  65. }
  66. else
  67. {
  68. dials[crntDial] = 0;
  69. --crntDial;
  70. }
  71. }
  72. else
  73. {
  74. done = false;
  75. break;
  76. }
  77. }
  78. return done;
  79. }
  80. template<typename TFunc>
  81. static void visitSpirv(ConstWeakArray<U32> spv, TFunc func)
  82. {
  83. ANKI_ASSERT(spv.getSize() > 5);
  84. const U32* it = &spv[5];
  85. do
  86. {
  87. const U32 instructionCount = *it >> 16u;
  88. const U32 opcode = *it & 0xFFFFu;
  89. func(opcode);
  90. it += instructionCount;
  91. } while(it < spv.getEnd());
  92. ANKI_ASSERT(it == spv.getEnd());
  93. }
  94. static Error doReflectionSpirv(ConstWeakArray<U8> spirv, ShaderType type, ShaderReflection& refl, ShaderCompilerString& errorStr)
  95. {
  96. spirv_cross::Compiler spvc(reinterpret_cast<const U32*>(&spirv[0]), spirv.getSize() / sizeof(U32));
  97. spirv_cross::ShaderResources rsrc = spvc.get_shader_resources();
  98. spirv_cross::ShaderResources rsrcActive = spvc.get_shader_resources(spvc.get_active_interface_variables());
  99. auto func = [&](const spirv_cross::SmallVector<spirv_cross::Resource>& resources, const DescriptorType origType) -> Error {
  100. for(const spirv_cross::Resource& r : resources)
  101. {
  102. const U32 id = r.id;
  103. const U32 set = spvc.get_decoration(id, spv::Decoration::DecorationDescriptorSet);
  104. const U32 binding = spvc.get_decoration(id, spv::Decoration::DecorationBinding);
  105. if(set >= kMaxDescriptorSets || binding >= kMaxBindingsPerDescriptorSet)
  106. {
  107. errorStr.sprintf("Exceeded set or binding for: %s", r.name.c_str());
  108. return Error::kUserData;
  109. }
  110. const spirv_cross::SPIRType& typeInfo = spvc.get_type(r.type_id);
  111. U32 arraySize = 1;
  112. if(typeInfo.array.size() != 0)
  113. {
  114. if(typeInfo.array.size() != 1 || (arraySize = typeInfo.array[0]) == 0)
  115. {
  116. errorStr.sprintf("Only 1D arrays are supported: %s", r.name.c_str());
  117. return Error::kUserData;
  118. }
  119. }
  120. refl.m_descriptorSetMask.set(set);
  121. // Images are special, they might be texel buffers
  122. DescriptorType type = origType;
  123. if(type == DescriptorType::kTexture)
  124. {
  125. if(typeInfo.image.dim == spv::DimBuffer && typeInfo.image.sampled == 1)
  126. {
  127. type = DescriptorType::kReadTexelBuffer;
  128. }
  129. else if(typeInfo.image.dim == spv::DimBuffer && typeInfo.image.sampled == 2)
  130. {
  131. type = DescriptorType::kReadWriteTexelBuffer;
  132. }
  133. }
  134. // Check that there are no other descriptors with the same binding
  135. if(refl.m_descriptorTypes[set][binding] == DescriptorType::kCount)
  136. {
  137. // New binding, init it
  138. refl.m_descriptorTypes[set][binding] = type;
  139. refl.m_descriptorArraySizes[set][binding] = U16(arraySize);
  140. }
  141. else
  142. {
  143. // Same binding, make sure the type is compatible
  144. if(refl.m_descriptorTypes[set][binding] != type || refl.m_descriptorArraySizes[set][binding] != arraySize)
  145. {
  146. errorStr.sprintf("Descriptor with same binding but different type or array size: %s", r.name.c_str());
  147. return Error::kUserData;
  148. }
  149. }
  150. }
  151. return Error::kNone;
  152. };
  153. Error err = Error::kNone;
  154. err = func(rsrc.uniform_buffers, DescriptorType::kUniformBuffer);
  155. if(!err)
  156. {
  157. err = func(rsrc.separate_images, DescriptorType::kTexture); // This also handles texture buffers
  158. }
  159. if(!err)
  160. {
  161. err = func(rsrc.separate_samplers, DescriptorType::kSampler);
  162. }
  163. if(!err)
  164. {
  165. err = func(rsrc.storage_buffers, DescriptorType::kStorageBuffer);
  166. }
  167. if(!err)
  168. {
  169. err = func(rsrc.storage_images, DescriptorType::kStorageImage);
  170. }
  171. if(!err)
  172. {
  173. err = func(rsrc.acceleration_structures, DescriptorType::kAccelerationStructure);
  174. }
  175. // Color attachments
  176. if(type == ShaderType::kFragment)
  177. {
  178. for(const spirv_cross::Resource& r : rsrc.stage_outputs)
  179. {
  180. const U32 id = r.id;
  181. const U32 location = spvc.get_decoration(id, spv::Decoration::DecorationLocation);
  182. refl.m_colorAttachmentWritemask.set(location);
  183. }
  184. }
  185. // Push consts
  186. if(rsrc.push_constant_buffers.size() == 1)
  187. {
  188. const U32 blockSize = U32(spvc.get_declared_struct_size(spvc.get_type(rsrc.push_constant_buffers[0].base_type_id)));
  189. if(blockSize == 0 || (blockSize % 16) != 0 || blockSize > kMaxU8)
  190. {
  191. errorStr.sprintf("Incorrect push constants size");
  192. return Error::kUserData;
  193. }
  194. refl.m_pushConstantsSize = U8(blockSize);
  195. }
  196. // Attribs
  197. if(type == ShaderType::kVertex)
  198. {
  199. for(const spirv_cross::Resource& r : rsrcActive.stage_inputs)
  200. {
  201. VertexAttribute a = VertexAttribute::kCount;
  202. #define ANKI_ATTRIB_NAME(x) "in.var." #x
  203. if(r.name == ANKI_ATTRIB_NAME(POSITION))
  204. {
  205. a = VertexAttribute::kPosition;
  206. }
  207. else if(r.name == ANKI_ATTRIB_NAME(NORMAL))
  208. {
  209. a = VertexAttribute::kNormal;
  210. }
  211. else if(r.name == ANKI_ATTRIB_NAME(TEXCOORD0) || r.name == ANKI_ATTRIB_NAME(TEXCOORD))
  212. {
  213. a = VertexAttribute::kTexCoord;
  214. }
  215. else if(r.name == ANKI_ATTRIB_NAME(COLOR))
  216. {
  217. a = VertexAttribute::kColor;
  218. }
  219. else if(r.name == ANKI_ATTRIB_NAME(MISC0) || r.name == ANKI_ATTRIB_NAME(MISC))
  220. {
  221. a = VertexAttribute::kMisc0;
  222. }
  223. else if(r.name == ANKI_ATTRIB_NAME(MISC1))
  224. {
  225. a = VertexAttribute::kMisc1;
  226. }
  227. else if(r.name == ANKI_ATTRIB_NAME(MISC2))
  228. {
  229. a = VertexAttribute::kMisc2;
  230. }
  231. else if(r.name == ANKI_ATTRIB_NAME(MISC3))
  232. {
  233. a = VertexAttribute::kMisc3;
  234. }
  235. else
  236. {
  237. errorStr.sprintf("Unexpected attribute name: %s", r.name.c_str());
  238. return Error::kUserData;
  239. }
  240. #undef ANKI_ATTRIB_NAME
  241. refl.m_vertexAttributeMask.set(a);
  242. const U32 id = r.id;
  243. const U32 location = spvc.get_decoration(id, spv::Decoration::DecorationLocation);
  244. if(location > kMaxU8)
  245. {
  246. errorStr.sprintf("Too high location value for attribute: %s", r.name.c_str());
  247. return Error::kUserData;
  248. }
  249. refl.m_vertexAttributeLocations[a] = U8(location);
  250. }
  251. }
  252. // Discards?
  253. if(type == ShaderType::kFragment)
  254. {
  255. visitSpirv(ConstWeakArray<U32>(reinterpret_cast<const U32*>(&spirv[0]), spirv.getSize() / sizeof(U32)), [&](U32 cmd) {
  256. if(cmd == spv::OpKill)
  257. {
  258. refl.m_discards = true;
  259. }
  260. });
  261. }
  262. return Error::kNone;
  263. }
  264. static void compileVariantAsync(const ShaderProgramParser& parser, ShaderProgramBinaryMutation& mutation,
  265. ShaderCompilerDynamicArray<ShaderProgramBinaryVariant>& variants,
  266. ShaderCompilerDynamicArray<ShaderProgramBinaryCodeBlock>& codeBlocks,
  267. ShaderCompilerDynamicArray<U64>& sourceCodeHashes, ShaderProgramAsyncTaskInterface& taskManager, Mutex& mtx,
  268. Atomic<I32>& error)
  269. {
  270. class Ctx
  271. {
  272. public:
  273. const ShaderProgramParser* m_parser;
  274. ShaderProgramBinaryMutation* m_mutation;
  275. ShaderCompilerDynamicArray<ShaderProgramBinaryVariant>* m_variants;
  276. ShaderCompilerDynamicArray<ShaderProgramBinaryCodeBlock>* m_codeBlocks;
  277. ShaderCompilerDynamicArray<U64>* m_sourceCodeHashes;
  278. Mutex* m_mtx;
  279. Atomic<I32>* m_err;
  280. };
  281. Ctx* ctx = newInstance<Ctx>(ShaderCompilerMemoryPool::getSingleton());
  282. ctx->m_parser = &parser;
  283. ctx->m_mutation = &mutation;
  284. ctx->m_variants = &variants;
  285. ctx->m_codeBlocks = &codeBlocks;
  286. ctx->m_sourceCodeHashes = &sourceCodeHashes;
  287. ctx->m_mtx = &mtx;
  288. ctx->m_err = &error;
  289. auto callback = [](void* userData) {
  290. Ctx& ctx = *static_cast<Ctx*>(userData);
  291. class Cleanup
  292. {
  293. public:
  294. Ctx* m_ctx;
  295. ~Cleanup()
  296. {
  297. deleteInstance(ShaderCompilerMemoryPool::getSingleton(), m_ctx);
  298. }
  299. } cleanup{&ctx};
  300. if(ctx.m_err->load() != 0)
  301. {
  302. // Don't bother
  303. return;
  304. }
  305. const U32 techniqueCount = ctx.m_parser->getTechniques().getSize();
  306. // Compile the sources
  307. ShaderCompilerDynamicArray<ShaderProgramBinaryTechniqueCodeBlocks> codeBlockIndices;
  308. codeBlockIndices.resize(techniqueCount);
  309. for(auto& it : codeBlockIndices)
  310. {
  311. it.m_codeBlockIndices.fill(kMaxU32);
  312. }
  313. ShaderCompilerString compilerErrorLog;
  314. Error err = Error::kNone;
  315. U newCodeBlockCount = 0;
  316. for(U32 t = 0; t < techniqueCount && !err; ++t)
  317. {
  318. const ShaderProgramParserTechnique& technique = ctx.m_parser->getTechniques()[t];
  319. for(ShaderType shaderType : EnumBitsIterable<ShaderType, ShaderTypeBit>(technique.m_shaderTypes))
  320. {
  321. ShaderCompilerString source;
  322. ctx.m_parser->generateVariant(ctx.m_mutation->m_values, technique, shaderType, source);
  323. // Check if the source code was found before
  324. const U64 sourceCodeHash = source.computeHash();
  325. if(technique.m_activeMutators[shaderType] != kMaxU64)
  326. {
  327. LockGuard lock(*ctx.m_mtx);
  328. ANKI_ASSERT(ctx.m_sourceCodeHashes->getSize() == ctx.m_codeBlocks->getSize());
  329. Bool found = false;
  330. for(U32 i = 0; i < ctx.m_sourceCodeHashes->getSize(); ++i)
  331. {
  332. if((*ctx.m_sourceCodeHashes)[i] == sourceCodeHash)
  333. {
  334. codeBlockIndices[t].m_codeBlockIndices[shaderType] = i;
  335. found = true;
  336. break;
  337. }
  338. }
  339. if(found)
  340. {
  341. continue;
  342. }
  343. }
  344. ShaderCompilerDynamicArray<U8> spirv;
  345. err = compileHlslToSpirv(source, shaderType, ctx.m_parser->compileWith16bitTypes(), spirv, compilerErrorLog);
  346. if(err)
  347. {
  348. break;
  349. }
  350. const U64 newHash = computeHash(spirv.getBegin(), spirv.getSizeInBytes());
  351. ShaderReflection refl;
  352. err = doReflectionSpirv(spirv, shaderType, refl, compilerErrorLog);
  353. if(err)
  354. {
  355. break;
  356. }
  357. // Add the binary if not already there
  358. {
  359. LockGuard lock(*ctx.m_mtx);
  360. Bool found = false;
  361. for(U32 j = 0; j < ctx.m_codeBlocks->getSize(); ++j)
  362. {
  363. if((*ctx.m_codeBlocks)[j].m_hash == newHash)
  364. {
  365. codeBlockIndices[t].m_codeBlockIndices[shaderType] = j;
  366. found = true;
  367. break;
  368. }
  369. }
  370. if(!found)
  371. {
  372. codeBlockIndices[t].m_codeBlockIndices[shaderType] = ctx.m_codeBlocks->getSize();
  373. auto& codeBlock = *ctx.m_codeBlocks->emplaceBack();
  374. spirv.moveAndReset(codeBlock.m_binary);
  375. codeBlock.m_hash = newHash;
  376. codeBlock.m_reflection = refl;
  377. ctx.m_sourceCodeHashes->emplaceBack(sourceCodeHash);
  378. ANKI_ASSERT(ctx.m_sourceCodeHashes->getSize() == ctx.m_codeBlocks->getSize());
  379. ++newCodeBlockCount;
  380. }
  381. }
  382. }
  383. }
  384. if(err)
  385. {
  386. I32 expectedErr = 0;
  387. const Bool isFirstError = ctx.m_err->compareExchange(expectedErr, err._getCode());
  388. if(isFirstError)
  389. {
  390. ANKI_SHADER_COMPILER_LOGE("Shader compilation failed:\n%s", compilerErrorLog.cstr());
  391. return;
  392. }
  393. return;
  394. }
  395. // Do variant stuff
  396. {
  397. LockGuard lock(*ctx.m_mtx);
  398. Bool createVariant = true;
  399. if(newCodeBlockCount == 0)
  400. {
  401. // No new code blocks generated, search all variants to see if there is a duplicate
  402. for(U32 i = 0; i < ctx.m_variants->getSize(); ++i)
  403. {
  404. Bool same = true;
  405. for(U32 t = 0; t < techniqueCount; ++t)
  406. {
  407. const ShaderProgramBinaryTechniqueCodeBlocks& a = (*ctx.m_variants)[i].m_techniqueCodeBlocks[t];
  408. const ShaderProgramBinaryTechniqueCodeBlocks& b = codeBlockIndices[t];
  409. if(memcmp(&a, &b, sizeof(a)) != 0)
  410. {
  411. // Not the same
  412. same = false;
  413. break;
  414. }
  415. }
  416. if(same)
  417. {
  418. createVariant = false;
  419. ctx.m_mutation->m_variantIndex = i;
  420. break;
  421. }
  422. }
  423. }
  424. // Create a new variant
  425. if(createVariant)
  426. {
  427. ctx.m_mutation->m_variantIndex = ctx.m_variants->getSize();
  428. ShaderProgramBinaryVariant* variant = ctx.m_variants->emplaceBack();
  429. codeBlockIndices.moveAndReset(variant->m_techniqueCodeBlocks);
  430. }
  431. }
  432. };
  433. taskManager.enqueueTask(callback, ctx);
  434. }
  435. Error compileShaderProgramInternal(CString fname, ShaderProgramFilesystemInterface& fsystem, ShaderProgramPostParseInterface* postParseCallback,
  436. ShaderProgramAsyncTaskInterface* taskManager_, ConstWeakArray<ShaderCompilerDefine> defines,
  437. ShaderProgramBinary*& binary)
  438. {
  439. ShaderCompilerMemoryPool& memPool = ShaderCompilerMemoryPool::getSingleton();
  440. // Initialize the binary
  441. binary = newInstance<ShaderProgramBinary>(memPool);
  442. memcpy(&binary->m_magic[0], kShaderBinaryMagic, 8);
  443. // Parse source
  444. ShaderProgramParser parser(fname, &fsystem, defines);
  445. ANKI_CHECK(parser.parse());
  446. if(postParseCallback && postParseCallback->skipCompilation(parser.getHash()))
  447. {
  448. return Error::kNone;
  449. }
  450. // Get mutators
  451. U32 mutationCount = 0;
  452. if(parser.getMutators().getSize() > 0)
  453. {
  454. newArray(memPool, parser.getMutators().getSize(), binary->m_mutators);
  455. for(U32 i = 0; i < binary->m_mutators.getSize(); ++i)
  456. {
  457. ShaderProgramBinaryMutator& out = binary->m_mutators[i];
  458. const ShaderProgramParserMutator& in = parser.getMutators()[i];
  459. zeroMemory(out);
  460. newArray(memPool, in.m_values.getSize(), out.m_values);
  461. memcpy(out.m_values.getBegin(), in.m_values.getBegin(), in.m_values.getSizeInBytes());
  462. memcpy(out.m_name.getBegin(), in.m_name.cstr(), in.m_name.getLength() + 1);
  463. // Update the count
  464. mutationCount = (i == 0) ? out.m_values.getSize() : mutationCount * out.m_values.getSize();
  465. }
  466. }
  467. else
  468. {
  469. ANKI_ASSERT(binary->m_mutators.getSize() == 0);
  470. }
  471. // Create all variants
  472. Mutex mtx;
  473. Atomic<I32> errorAtomic(0);
  474. class SyncronousShaderProgramAsyncTaskInterface : public ShaderProgramAsyncTaskInterface
  475. {
  476. public:
  477. void enqueueTask(void (*callback)(void* userData), void* userData) final
  478. {
  479. callback(userData);
  480. }
  481. Error joinTasks() final
  482. {
  483. // Nothing
  484. return Error::kNone;
  485. }
  486. } syncTaskManager;
  487. ShaderProgramAsyncTaskInterface& taskManager = (taskManager_) ? *taskManager_ : syncTaskManager;
  488. if(parser.getMutators().getSize() > 0)
  489. {
  490. // Initialize
  491. ShaderCompilerDynamicArray<MutatorValue> mutationValues;
  492. mutationValues.resize(parser.getMutators().getSize());
  493. ShaderCompilerDynamicArray<U32> dials;
  494. dials.resize(parser.getMutators().getSize(), 0);
  495. ShaderCompilerDynamicArray<ShaderProgramBinaryVariant> variants;
  496. ShaderCompilerDynamicArray<ShaderProgramBinaryCodeBlock> codeBlocks;
  497. ShaderCompilerDynamicArray<U64> sourceCodeHashes;
  498. ShaderCompilerDynamicArray<ShaderProgramBinaryMutation> mutations;
  499. mutations.resize(mutationCount);
  500. ShaderCompilerHashMap<U64, U32> mutationHashToIdx;
  501. // Grow the storage of the variants array. Can't have it resize, threads will work on stale data
  502. variants.resizeStorage(mutationCount);
  503. mutationCount = 0;
  504. // Spin for all possible combinations of mutators and
  505. // - Create the spirv
  506. // - Populate the binary variant
  507. do
  508. {
  509. // Create the mutation
  510. for(U32 i = 0; i < parser.getMutators().getSize(); ++i)
  511. {
  512. mutationValues[i] = parser.getMutators()[i].m_values[dials[i]];
  513. }
  514. ShaderProgramBinaryMutation& mutation = mutations[mutationCount++];
  515. newArray(memPool, mutationValues.getSize(), mutation.m_values);
  516. memcpy(mutation.m_values.getBegin(), mutationValues.getBegin(), mutationValues.getSizeInBytes());
  517. mutation.m_hash = computeHash(mutationValues.getBegin(), mutationValues.getSizeInBytes());
  518. ANKI_ASSERT(mutation.m_hash > 0);
  519. if(parser.skipMutation(mutationValues))
  520. {
  521. mutation.m_variantIndex = kMaxU32;
  522. }
  523. else
  524. {
  525. // New and unique mutation and thus variant, add it
  526. compileVariantAsync(parser, mutation, variants, codeBlocks, sourceCodeHashes, taskManager, mtx, errorAtomic);
  527. ANKI_ASSERT(mutationHashToIdx.find(mutation.m_hash) == mutationHashToIdx.getEnd());
  528. mutationHashToIdx.emplace(mutation.m_hash, mutationCount - 1);
  529. }
  530. } while(!spinDials(dials, parser.getMutators()));
  531. ANKI_ASSERT(mutationCount == mutations.getSize());
  532. // Done, wait the threads
  533. ANKI_CHECK(taskManager.joinTasks());
  534. // Now error out
  535. ANKI_CHECK(Error(errorAtomic.getNonAtomically()));
  536. // Store temp containers to binary
  537. codeBlocks.moveAndReset(binary->m_codeBlocks);
  538. mutations.moveAndReset(binary->m_mutations);
  539. variants.moveAndReset(binary->m_variants);
  540. }
  541. else
  542. {
  543. newArray(memPool, 1, binary->m_mutations);
  544. ShaderCompilerDynamicArray<ShaderProgramBinaryVariant> variants;
  545. ShaderCompilerDynamicArray<ShaderProgramBinaryCodeBlock> codeBlocks;
  546. ShaderCompilerDynamicArray<U64> sourceCodeHashes;
  547. compileVariantAsync(parser, binary->m_mutations[0], variants, codeBlocks, sourceCodeHashes, taskManager, mtx, errorAtomic);
  548. ANKI_CHECK(taskManager.joinTasks());
  549. ANKI_CHECK(Error(errorAtomic.getNonAtomically()));
  550. ANKI_ASSERT(codeBlocks.getSize() >= parser.getTechniques().getSize());
  551. ANKI_ASSERT(binary->m_mutations[0].m_variantIndex == 0);
  552. ANKI_ASSERT(variants.getSize() == 1);
  553. binary->m_mutations[0].m_hash = 1;
  554. codeBlocks.moveAndReset(binary->m_codeBlocks);
  555. variants.moveAndReset(binary->m_variants);
  556. }
  557. // Sort the mutations
  558. std::sort(binary->m_mutations.getBegin(), binary->m_mutations.getEnd(),
  559. [](const ShaderProgramBinaryMutation& a, const ShaderProgramBinaryMutation& b) {
  560. return a.m_hash < b.m_hash;
  561. });
  562. // Techniques
  563. newArray(memPool, parser.getTechniques().getSize(), binary->m_techniques);
  564. for(U32 i = 0; i < parser.getTechniques().getSize(); ++i)
  565. {
  566. zeroMemory(binary->m_techniques[i].m_name);
  567. memcpy(binary->m_techniques[i].m_name.getBegin(), parser.getTechniques()[i].m_name.cstr(), parser.getTechniques()[i].m_name.getLength() + 1);
  568. binary->m_techniques[i].m_shaderTypes = parser.getTechniques()[i].m_shaderTypes;
  569. binary->m_shaderTypes |= parser.getTechniques()[i].m_shaderTypes;
  570. }
  571. // Structs
  572. if(parser.getGhostStructs().getSize())
  573. {
  574. newArray(memPool, parser.getGhostStructs().getSize(), binary->m_structs);
  575. }
  576. for(U32 i = 0; i < parser.getGhostStructs().getSize(); ++i)
  577. {
  578. const ShaderProgramParserGhostStruct& in = parser.getGhostStructs()[i];
  579. ShaderProgramBinaryStruct& out = binary->m_structs[i];
  580. zeroMemory(out);
  581. memcpy(out.m_name.getBegin(), in.m_name.cstr(), in.m_name.getLength() + 1);
  582. ANKI_ASSERT(in.m_members.getSize());
  583. newArray(memPool, in.m_members.getSize(), out.m_members);
  584. for(U32 j = 0; j < in.m_members.getSize(); ++j)
  585. {
  586. const ShaderProgramParserMember& inm = in.m_members[j];
  587. ShaderProgramBinaryStructMember& outm = out.m_members[j];
  588. zeroMemory(outm.m_name);
  589. memcpy(outm.m_name.getBegin(), inm.m_name.cstr(), inm.m_name.getLength() + 1);
  590. outm.m_offset = inm.m_offset;
  591. outm.m_type = inm.m_type;
  592. }
  593. out.m_size = in.m_members.getBack().m_offset + getShaderVariableDataTypeInfo(in.m_members.getBack().m_type).m_size;
  594. }
  595. return Error::kNone;
  596. }
  597. Error compileShaderProgram(CString fname, ShaderProgramFilesystemInterface& fsystem, ShaderProgramPostParseInterface* postParseCallback,
  598. ShaderProgramAsyncTaskInterface* taskManager, ConstWeakArray<ShaderCompilerDefine> defines, ShaderProgramBinary*& binary)
  599. {
  600. const Error err = compileShaderProgramInternal(fname, fsystem, postParseCallback, taskManager, defines, binary);
  601. if(err)
  602. {
  603. ANKI_SHADER_COMPILER_LOGE("Failed to compile: %s", fname.cstr());
  604. freeShaderProgramBinary(binary);
  605. }
  606. return err;
  607. }
  608. } // end namespace anki