ShaderProgramResourceSystem.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  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/resource/ShaderProgramResourceSystem.h>
  6. #include <anki/resource/ResourceFilesystem.h>
  7. #include <anki/util/Tracer.h>
  8. #include <anki/gr/GrManager.h>
  9. #include <anki/shader_compiler/ShaderProgramCompiler.h>
  10. #include <anki/util/Filesystem.h>
  11. #include <anki/util/ThreadHive.h>
  12. #include <anki/util/System.h>
  13. namespace anki
  14. {
  15. void ShaderProgramRaytracingLibrary::getShaderGroupHandle(U32 groupIndex, WeakArray<U8>& handle) const
  16. {
  17. const U32 shaderGroupHandleSize = m_program->getManager().getDeviceCapabilities().m_shaderGroupHandleSize;
  18. ANKI_ASSERT(handle.getSizeInBytes() == shaderGroupHandleSize);
  19. const U32 begin = shaderGroupHandleSize * groupIndex;
  20. ConstWeakArray<U8> handles = m_program->getShaderGroupHandles();
  21. ANKI_ASSERT(begin + shaderGroupHandleSize <= handles.getSizeInBytes());
  22. memcpy(&handle[0], &handles[begin], shaderGroupHandleSize);
  23. }
  24. ShaderProgramResourceSystem::~ShaderProgramResourceSystem()
  25. {
  26. m_cacheDir.destroy(m_alloc);
  27. for(ShaderProgramRaytracingLibrary& lib : m_rtLibraries)
  28. {
  29. lib.m_libraryName.destroy(m_alloc);
  30. lib.m_groupHashToGroupIndex.destroy(m_alloc);
  31. }
  32. m_rtLibraries.destroy(m_alloc);
  33. }
  34. Error ShaderProgramResourceSystem::init()
  35. {
  36. ANKI_TRACE_SCOPED_EVENT(COMPILE_SHADERS);
  37. ANKI_CHECK(compileAllShaders(m_cacheDir, *m_gr, *m_fs, m_alloc));
  38. if(m_gr->getDeviceCapabilities().m_rayTracingEnabled)
  39. {
  40. ANKI_CHECK(createRayTracingPrograms(m_cacheDir, *m_gr, *m_fs, m_alloc, m_rtLibraries));
  41. }
  42. return Error::NONE;
  43. }
  44. Error ShaderProgramResourceSystem::compileAllShaders(CString cacheDir, GrManager& gr, ResourceFilesystem& fs,
  45. GenericMemoryPoolAllocator<U8>& alloc)
  46. {
  47. ANKI_RESOURCE_LOGI("Compiling shader programs");
  48. U32 shadersCompileCount = 0;
  49. ThreadHive threadHive(getCpuCoresCount(), alloc, false);
  50. // Compute hash for both
  51. const GpuDeviceCapabilities caps = gr.getDeviceCapabilities();
  52. const BindlessLimits limits = gr.getBindlessLimits();
  53. U64 gpuHash = computeHash(&caps, sizeof(caps));
  54. gpuHash = appendHash(&limits, sizeof(limits), gpuHash);
  55. gpuHash = appendHash(&SHADER_BINARY_VERSION, sizeof(SHADER_BINARY_VERSION), gpuHash);
  56. ANKI_CHECK(fs.iterateAllFilenames([&](CString fname) -> Error {
  57. // Check file extension
  58. StringAuto extension(alloc);
  59. getFilepathExtension(fname, extension);
  60. if(extension.getLength() != 8 || extension != "ankiprog")
  61. {
  62. return Error::NONE;
  63. }
  64. if(fname.find("/Rt") != CString::NPOS && !gr.getDeviceCapabilities().m_rayTracingEnabled)
  65. {
  66. // Skip RT programs
  67. return Error::NONE;
  68. }
  69. // Get some filenames
  70. StringAuto baseFname(alloc);
  71. getFilepathFilename(fname, baseFname);
  72. StringAuto metaFname(alloc);
  73. metaFname.sprintf("%s/%smeta", cacheDir.cstr(), baseFname.cstr());
  74. // Get the hash from the meta file
  75. U64 metafileHash = 0;
  76. if(fileExists(metaFname))
  77. {
  78. File metaFile;
  79. ANKI_CHECK(metaFile.open(metaFname, FileOpenFlag::READ | FileOpenFlag::BINARY));
  80. ANKI_CHECK(metaFile.read(&metafileHash, sizeof(metafileHash)));
  81. }
  82. // Load interface
  83. class FSystem : public ShaderProgramFilesystemInterface
  84. {
  85. public:
  86. ResourceFilesystem* m_fsystem = nullptr;
  87. Error readAllText(CString filename, StringAuto& txt) final
  88. {
  89. ResourceFilePtr file;
  90. ANKI_CHECK(m_fsystem->openFile(filename, file));
  91. ANKI_CHECK(file->readAllText(txt));
  92. return Error::NONE;
  93. }
  94. } fsystem;
  95. fsystem.m_fsystem = &fs;
  96. // Skip interface
  97. class Skip : public ShaderProgramPostParseInterface
  98. {
  99. public:
  100. U64 m_metafileHash;
  101. U64 m_newHash;
  102. U64 m_gpuHash;
  103. CString m_fname;
  104. Bool skipCompilation(U64 hash)
  105. {
  106. ANKI_ASSERT(hash != 0);
  107. const Array<U64, 2> hashes = {hash, m_gpuHash};
  108. const U64 finalHash = computeHash(hashes.getBegin(), hashes.getSizeInBytes());
  109. m_newHash = finalHash;
  110. const Bool skip = finalHash == m_metafileHash;
  111. if(!skip)
  112. {
  113. ANKI_RESOURCE_LOGI("\t%s", m_fname.cstr());
  114. }
  115. return skip;
  116. };
  117. } skip;
  118. skip.m_metafileHash = metafileHash;
  119. skip.m_newHash = 0;
  120. skip.m_gpuHash = gpuHash;
  121. skip.m_fname = fname;
  122. // Threading interface
  123. class TaskManager : public ShaderProgramAsyncTaskInterface
  124. {
  125. public:
  126. ThreadHive* m_hive = nullptr;
  127. GenericMemoryPoolAllocator<U8> m_alloc;
  128. void enqueueTask(void (*callback)(void* userData), void* userData)
  129. {
  130. class Ctx
  131. {
  132. public:
  133. void (*m_callback)(void* userData);
  134. void* m_userData;
  135. GenericMemoryPoolAllocator<U8> m_alloc;
  136. };
  137. Ctx* ctx = m_alloc.newInstance<Ctx>();
  138. ctx->m_callback = callback;
  139. ctx->m_userData = userData;
  140. ctx->m_alloc = m_alloc;
  141. m_hive->submitTask(
  142. [](void* userData, U32 threadId, ThreadHive& hive, ThreadHiveSemaphore* signalSemaphore) {
  143. Ctx* ctx = static_cast<Ctx*>(userData);
  144. ctx->m_callback(ctx->m_userData);
  145. auto alloc = ctx->m_alloc;
  146. alloc.deleteInstance(ctx);
  147. },
  148. ctx);
  149. }
  150. Error joinTasks()
  151. {
  152. m_hive->waitAllTasks();
  153. return Error::NONE;
  154. }
  155. } taskManager;
  156. taskManager.m_hive = &threadHive;
  157. taskManager.m_alloc = alloc;
  158. // Compile
  159. ShaderProgramBinaryWrapper binary(alloc);
  160. ANKI_CHECK(compileShaderProgram(fname, fsystem, &skip, &taskManager, alloc, caps, limits, binary));
  161. const Bool cachedBinIsUpToDate = metafileHash == skip.m_newHash;
  162. if(!cachedBinIsUpToDate)
  163. {
  164. ++shadersCompileCount;
  165. }
  166. // Update the meta file
  167. if(!cachedBinIsUpToDate)
  168. {
  169. File metaFile;
  170. ANKI_CHECK(metaFile.open(metaFname, FileOpenFlag::WRITE | FileOpenFlag::BINARY));
  171. ANKI_CHECK(metaFile.write(&skip.m_newHash, sizeof(skip.m_newHash)));
  172. }
  173. // Save the binary to the cache
  174. if(!cachedBinIsUpToDate)
  175. {
  176. StringAuto storeFname(alloc);
  177. storeFname.sprintf("%s/%sbin", cacheDir.cstr(), baseFname.cstr());
  178. ANKI_CHECK(binary.serializeToFile(storeFname));
  179. }
  180. return Error::NONE;
  181. }));
  182. ANKI_RESOURCE_LOGI("Compiled %u shader programs", shadersCompileCount);
  183. return Error::NONE;
  184. }
  185. Error ShaderProgramResourceSystem::createRayTracingPrograms(CString cacheDir, GrManager& gr, ResourceFilesystem& fs,
  186. GenericMemoryPoolAllocator<U8>& alloc,
  187. DynamicArray<ShaderProgramRaytracingLibrary>& outLibs)
  188. {
  189. ANKI_RESOURCE_LOGI("Creating ray tracing programs");
  190. U32 rtProgramCount = 0;
  191. // Gather the RT program fnames
  192. StringListAuto rtPrograms(alloc);
  193. ANKI_CHECK(fs.iterateAllFilenames([&](CString fname) -> Error {
  194. // Check file extension
  195. StringAuto extension(alloc);
  196. getFilepathExtension(fname, extension);
  197. if(extension.getLength() != 8 || extension != "ankiprog")
  198. {
  199. return Error::NONE;
  200. }
  201. if(fname.find("/Rt") == CString::NPOS)
  202. {
  203. // Skip non-RT programs
  204. return Error::NONE;
  205. }
  206. rtPrograms.pushBack(fname);
  207. return Error::NONE;
  208. }));
  209. // Group things together
  210. class Shader
  211. {
  212. public:
  213. ShaderPtr m_shader;
  214. U64 m_hash = 0;
  215. };
  216. class HitGroup
  217. {
  218. public:
  219. U32 m_chit = MAX_U32;
  220. U32 m_ahit = MAX_U32;
  221. U64 m_hitGroupHash = 0;
  222. };
  223. class RayType
  224. {
  225. public:
  226. RayType(GenericMemoryPoolAllocator<U8> alloc)
  227. : m_hitGroups(alloc)
  228. {
  229. }
  230. U32 m_miss = MAX_U32;
  231. U32 m_typeIndex = MAX_U32;
  232. DynamicArrayAuto<HitGroup> m_hitGroups;
  233. };
  234. class Lib
  235. {
  236. public:
  237. Lib(GenericMemoryPoolAllocator<U8> alloc)
  238. : m_alloc(alloc)
  239. {
  240. }
  241. GenericMemoryPoolAllocator<U8> m_alloc;
  242. StringAuto m_name{m_alloc};
  243. ShaderPtr m_rayGenShader;
  244. DynamicArrayAuto<Shader> m_shaders{m_alloc};
  245. DynamicArrayAuto<RayType> m_rayTypes{m_alloc};
  246. ShaderTypeBit m_presentStages = ShaderTypeBit::NONE;
  247. };
  248. DynamicArrayAuto<Lib> libs(alloc);
  249. for(const String& filename : rtPrograms)
  250. {
  251. // Get the binary
  252. StringAuto baseFilename(alloc);
  253. getFilepathFilename(filename, baseFilename);
  254. StringAuto binaryFilename(alloc);
  255. binaryFilename.sprintf("%s/%sbin", cacheDir.cstr(), baseFilename.cstr());
  256. ShaderProgramBinaryWrapper binaryw(alloc);
  257. ANKI_CHECK(binaryw.deserializeFromFile(binaryFilename));
  258. const ShaderProgramBinary& binary = binaryw.getBinary();
  259. // Checks
  260. if(binary.m_libraryName[0] == '\0')
  261. {
  262. ANKI_RESOURCE_LOGE("Library is missing from program: %s", filename.cstr());
  263. return Error::USER_DATA;
  264. }
  265. const U32 rayTypeNumber = binary.m_rayType;
  266. // Create the program name
  267. StringAuto progName(alloc);
  268. getFilepathFilename(filename, progName);
  269. char* cprogName = const_cast<char*>(progName.cstr());
  270. if(progName.getLength() > MAX_GR_OBJECT_NAME_LENGTH)
  271. {
  272. cprogName[MAX_GR_OBJECT_NAME_LENGTH] = '\0';
  273. }
  274. // Find or create the lib
  275. Lib* lib = nullptr;
  276. {
  277. for(Lib& l : libs)
  278. {
  279. if(l.m_name == CString(&binary.m_libraryName[0]))
  280. {
  281. lib = &l;
  282. break;
  283. }
  284. }
  285. if(lib == nullptr)
  286. {
  287. libs.emplaceBack(alloc);
  288. lib = &libs.getBack();
  289. lib->m_name.create(CString(&binary.m_libraryName[0]));
  290. }
  291. }
  292. // Ray gen
  293. if(!!(binary.m_presentShaderTypes & ShaderTypeBit::RAY_GEN))
  294. {
  295. if(lib->m_rayGenShader.isCreated())
  296. {
  297. ANKI_RESOURCE_LOGE("The library already has a ray gen shader: %s", filename.cstr());
  298. return Error::USER_DATA;
  299. }
  300. if(!!(binary.m_presentShaderTypes & ~ShaderTypeBit::RAY_GEN))
  301. {
  302. ANKI_RESOURCE_LOGE("Ray gen can't co-exist with other types: %s", filename.cstr());
  303. return Error::USER_DATA;
  304. }
  305. if(binary.m_constants.getSize() || binary.m_mutators.getSize())
  306. {
  307. ANKI_RESOURCE_LOGE("Ray gen can't have spec constants or mutators ATM: %s", filename.cstr());
  308. return Error::USER_DATA;
  309. }
  310. ShaderInitInfo inf(cprogName);
  311. inf.m_shaderType = ShaderType::RAY_GEN;
  312. inf.m_binary = binary.m_codeBlocks[0].m_binary;
  313. lib->m_rayGenShader = gr.newShader(inf);
  314. lib->m_presentStages |= ShaderTypeBit::RAY_GEN;
  315. }
  316. // Miss shaders
  317. if(!!(binary.m_presentShaderTypes & ShaderTypeBit::MISS))
  318. {
  319. if(!!(binary.m_presentShaderTypes & ~ShaderTypeBit::MISS))
  320. {
  321. ANKI_RESOURCE_LOGE("Miss shaders can't co-exist with other types: %s", filename.cstr());
  322. return Error::USER_DATA;
  323. }
  324. if(binary.m_constants.getSize() || binary.m_mutators.getSize())
  325. {
  326. ANKI_RESOURCE_LOGE("Miss can't have spec constants or mutators ATM: %s", filename.cstr());
  327. return Error::USER_DATA;
  328. }
  329. if(rayTypeNumber == MAX_U32)
  330. {
  331. ANKI_RESOURCE_LOGE("Miss shader should have set the ray type: %s", filename.cstr());
  332. return Error::USER_DATA;
  333. }
  334. RayType* rayType = nullptr;
  335. for(RayType& rt : lib->m_rayTypes)
  336. {
  337. if(rt.m_typeIndex == rayTypeNumber)
  338. {
  339. rayType = &rt;
  340. break;
  341. }
  342. }
  343. if(rayType == nullptr)
  344. {
  345. lib->m_rayTypes.emplaceBack(alloc);
  346. rayType = &lib->m_rayTypes.getBack();
  347. rayType->m_typeIndex = rayTypeNumber;
  348. }
  349. if(rayType->m_miss != MAX_U32)
  350. {
  351. ANKI_RESOURCE_LOGE(
  352. "There is another miss program with the same library and sub-library names with this: %s",
  353. filename.cstr());
  354. return Error::USER_DATA;
  355. }
  356. Shader* shader = nullptr;
  357. for(Shader& s : lib->m_shaders)
  358. {
  359. if(s.m_hash == binary.m_codeBlocks[0].m_hash)
  360. {
  361. shader = &s;
  362. break;
  363. }
  364. }
  365. if(shader == nullptr)
  366. {
  367. shader = lib->m_shaders.emplaceBack();
  368. ShaderInitInfo inf(cprogName);
  369. inf.m_shaderType = ShaderType::MISS;
  370. inf.m_binary = binary.m_codeBlocks[0].m_binary;
  371. shader->m_shader = gr.newShader(inf);
  372. shader->m_hash = binary.m_codeBlocks[0].m_hash;
  373. }
  374. rayType->m_miss = U32(shader - &lib->m_shaders[0]);
  375. lib->m_presentStages |= ShaderTypeBit::MISS;
  376. }
  377. // Hit shaders
  378. if(!!(binary.m_presentShaderTypes & (ShaderTypeBit::ANY_HIT | ShaderTypeBit::CLOSEST_HIT)))
  379. {
  380. if(!!(binary.m_presentShaderTypes & ~(ShaderTypeBit::ANY_HIT | ShaderTypeBit::CLOSEST_HIT)))
  381. {
  382. ANKI_RESOURCE_LOGE("Hit shaders can't co-exist with other types: %s", filename.cstr());
  383. return Error::USER_DATA;
  384. }
  385. if(rayTypeNumber == MAX_U32)
  386. {
  387. ANKI_RESOURCE_LOGE("Hit shaders should have set the ray type: %s", filename.cstr());
  388. return Error::USER_DATA;
  389. }
  390. // Before you iterate the mutations do some work if there are none
  391. ConstWeakArray<ShaderProgramBinaryMutation> mutations;
  392. ShaderProgramBinaryMutation dummyMutation;
  393. if(binary.m_mutations.getSize())
  394. {
  395. mutations = binary.m_mutations;
  396. }
  397. else
  398. {
  399. dummyMutation.m_hash = 0;
  400. dummyMutation.m_variantIndex = 0;
  401. mutations = ConstWeakArray<ShaderProgramBinaryMutation>(&dummyMutation, 1);
  402. }
  403. // Iterate all mutations
  404. for(const ShaderProgramBinaryMutation& mutation : mutations)
  405. {
  406. const ShaderProgramBinaryVariant& variant = binary.m_variants[mutation.m_variantIndex];
  407. // Generate the hash
  408. const U64 hitGroupHash =
  409. ShaderProgramRaytracingLibrary::generateHitGroupHash(filename, mutation.m_hash);
  410. HitGroup hitGroup;
  411. hitGroup.m_hitGroupHash = hitGroupHash;
  412. for(ShaderType shaderType : EnumIterable<ShaderType>())
  413. {
  414. const U32 codeBlockIndex = variant.m_codeBlockIndices[shaderType];
  415. if(codeBlockIndex == MAX_U32)
  416. {
  417. continue;
  418. }
  419. ANKI_ASSERT(shaderType == ShaderType::ANY_HIT || shaderType == ShaderType::CLOSEST_HIT);
  420. // Find the shader
  421. Shader* shader = nullptr;
  422. for(Shader& s : lib->m_shaders)
  423. {
  424. if(s.m_hash == binary.m_codeBlocks[codeBlockIndex].m_hash)
  425. {
  426. shader = &s;
  427. break;
  428. }
  429. }
  430. // Crete the shader
  431. if(shader == nullptr)
  432. {
  433. shader = lib->m_shaders.emplaceBack();
  434. ShaderInitInfo inf(cprogName);
  435. inf.m_shaderType = shaderType;
  436. inf.m_binary = binary.m_codeBlocks[codeBlockIndex].m_binary;
  437. shader->m_shader = gr.newShader(inf);
  438. shader->m_hash = binary.m_codeBlocks[codeBlockIndex].m_hash;
  439. }
  440. const U32 shaderIndex = U32(shader - &lib->m_shaders[0]);
  441. if(shaderType == ShaderType::ANY_HIT)
  442. {
  443. hitGroup.m_ahit = shaderIndex;
  444. lib->m_presentStages |= ShaderTypeBit::ANY_HIT;
  445. }
  446. else
  447. {
  448. hitGroup.m_chit = shaderIndex;
  449. lib->m_presentStages |= ShaderTypeBit::CLOSEST_HIT;
  450. }
  451. }
  452. // Get or create the ray type
  453. RayType* rayType = nullptr;
  454. for(RayType& rt : lib->m_rayTypes)
  455. {
  456. if(rt.m_typeIndex == rayTypeNumber)
  457. {
  458. rayType = &rt;
  459. break;
  460. }
  461. }
  462. if(rayType == nullptr)
  463. {
  464. lib->m_rayTypes.emplaceBack(alloc);
  465. rayType = &lib->m_rayTypes.getBack();
  466. rayType->m_typeIndex = rayTypeNumber;
  467. }
  468. // Try to find if the hit group aleady exists. If it does then something is wrong
  469. for(const HitGroup& hg : rayType->m_hitGroups)
  470. {
  471. if(hg.m_hitGroupHash == hitGroup.m_hitGroupHash)
  472. {
  473. ANKI_ASSERT(!"Found a hitgroup with the same hash. Something is wrong");
  474. }
  475. }
  476. // Create the hitgroup
  477. rayType->m_hitGroups.emplaceBack(hitGroup);
  478. }
  479. }
  480. }
  481. // Create the libraries
  482. if(libs.getSize() != 0)
  483. {
  484. outLibs.resize(alloc, libs.getSize());
  485. for(U32 libIdx = 0; libIdx < libs.getSize(); ++libIdx)
  486. {
  487. ShaderProgramRaytracingLibrary& outLib = outLibs[libIdx];
  488. Lib& inLib = libs[libIdx];
  489. if(inLib.m_presentStages
  490. != (ShaderTypeBit::RAY_GEN | ShaderTypeBit::MISS | ShaderTypeBit::CLOSEST_HIT | ShaderTypeBit::ANY_HIT))
  491. {
  492. ANKI_RESOURCE_LOGE("The libray is missing shader shader types: %s", inLib.m_name.cstr());
  493. return Error::USER_DATA;
  494. }
  495. // Sort because the expectation is that the miss shaders are organized based on ray type
  496. std::sort(inLib.m_rayTypes.getBegin(), inLib.m_rayTypes.getEnd(),
  497. [](const RayType& a, const RayType& b) { return a.m_typeIndex < b.m_typeIndex; });
  498. outLib.m_libraryName.create(alloc, inLib.m_name);
  499. outLib.m_rayTypeCount = inLib.m_rayTypes.getSize();
  500. DynamicArrayAuto<RayTracingHitGroup> initInfoHitGroups(alloc);
  501. DynamicArrayAuto<ShaderPtr> missShaders(alloc);
  502. for(U32 rayTypeIdx = 0; rayTypeIdx < inLib.m_rayTypes.getSize(); ++rayTypeIdx)
  503. {
  504. const RayType& inRayType = inLib.m_rayTypes[rayTypeIdx];
  505. if(inRayType.m_typeIndex != rayTypeIdx)
  506. {
  507. ANKI_RESOURCE_LOGE("Ray types are not contiguous for library: %s", inLib.m_name.cstr());
  508. return Error::USER_DATA;
  509. }
  510. // Add the hitgroups to the init info
  511. for(U32 hitGroupIdx = 0; hitGroupIdx < inRayType.m_hitGroups.getSize(); ++hitGroupIdx)
  512. {
  513. const HitGroup& inHitGroup = inRayType.m_hitGroups[hitGroupIdx];
  514. outLib.m_groupHashToGroupIndex.emplace(alloc, inHitGroup.m_hitGroupHash,
  515. initInfoHitGroups.getSize() + outLib.m_rayTypeCount + 1);
  516. RayTracingHitGroup* infoHitGroup = initInfoHitGroups.emplaceBack();
  517. if(inHitGroup.m_ahit != MAX_U32)
  518. {
  519. infoHitGroup->m_anyHitShader = inLib.m_shaders[inHitGroup.m_ahit].m_shader;
  520. }
  521. if(inHitGroup.m_chit != MAX_U32)
  522. {
  523. infoHitGroup->m_closestHitShader = inLib.m_shaders[inHitGroup.m_chit].m_shader;
  524. }
  525. }
  526. // Add the miss shader
  527. ANKI_ASSERT(inRayType.m_miss != MAX_U32);
  528. missShaders.emplaceBack(inLib.m_shaders[inRayType.m_miss].m_shader);
  529. }
  530. // Program name
  531. StringAuto progName(alloc, inLib.m_name);
  532. char* cprogName = const_cast<char*>(progName.cstr());
  533. if(progName.getLength() > MAX_GR_OBJECT_NAME_LENGTH)
  534. {
  535. cprogName[MAX_GR_OBJECT_NAME_LENGTH] = '\0';
  536. }
  537. // Create the program
  538. ShaderProgramInitInfo inf(cprogName);
  539. inf.m_rayTracingShaders.m_rayGenShader = inLib.m_rayGenShader;
  540. inf.m_rayTracingShaders.m_missShaders = missShaders;
  541. inf.m_rayTracingShaders.m_hitGroups = initInfoHitGroups;
  542. outLib.m_program = gr.newShaderProgram(inf);
  543. ++rtProgramCount;
  544. }
  545. }
  546. ANKI_RESOURCE_LOGI("Created %u ray tracing programs", rtProgramCount);
  547. return Error::NONE;
  548. }
  549. } // end namespace anki