ShaderProgramResourceSystem.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. // Copyright (C) 2009-present, 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/Resource/ResourceManager.h>
  8. #include <AnKi/Util/Tracer.h>
  9. #include <AnKi/Gr/GrManager.h>
  10. #include <AnKi/ShaderCompiler/ShaderCompiler.h>
  11. #include <AnKi/Util/Filesystem.h>
  12. #include <AnKi/Util/System.h>
  13. #include <AnKi/Util/BitSet.h>
  14. #include <AnKi/Util/CVarSet.h>
  15. namespace anki {
  16. class ShaderProgramResourceSystem::ShaderH
  17. {
  18. public:
  19. ShaderPtr m_shader;
  20. U64 m_hash = 0; ///< Hash of the binary.
  21. };
  22. class ShaderProgramResourceSystem::ShaderGroup
  23. {
  24. public:
  25. U32 m_rayGen = kMaxU32;
  26. U32 m_miss = kMaxU32;
  27. U32 m_chit = kMaxU32;
  28. U32 m_ahit = kMaxU32;
  29. ResourceDynamicArray<U64> m_groupHashes;
  30. };
  31. class ShaderProgramResourceSystem::Lib
  32. {
  33. public:
  34. ResourceString m_name;
  35. ResourceDynamicArray<ShaderH> m_shaders;
  36. ResourceDynamicArray<ShaderGroup> m_rayGenGroups;
  37. ResourceDynamicArray<ShaderGroup> m_missGroups;
  38. ResourceDynamicArray<ShaderGroup> m_hitGroups;
  39. ShaderTypeBit m_presentStages = ShaderTypeBit::kNone;
  40. U32 addShader(const ShaderBinaryCodeBlock& codeBlock, CString progName, ShaderType shaderType)
  41. {
  42. ShaderH* shader = nullptr;
  43. for(ShaderH& s : m_shaders)
  44. {
  45. if(s.m_hash == codeBlock.m_hash)
  46. {
  47. shader = &s;
  48. break;
  49. }
  50. }
  51. if(shader == nullptr)
  52. {
  53. shader = m_shaders.emplaceBack();
  54. ShaderInitInfo inf(progName);
  55. inf.m_shaderType = shaderType;
  56. inf.m_binary = codeBlock.m_binary;
  57. inf.m_reflection = codeBlock.m_reflection;
  58. shader->m_shader = GrManager::getSingleton().newShader(inf);
  59. shader->m_hash = codeBlock.m_hash;
  60. m_presentStages |= ShaderTypeBit(1 << shaderType);
  61. }
  62. return U32(shader - m_shaders.getBegin());
  63. }
  64. void addGroup(CString filename, U64 mutationHash, U32 rayGen, U32 miss, U32 chit, U32 ahit)
  65. {
  66. ResourceDynamicArray<ShaderGroup>* groupArray = nullptr;
  67. RayTracingShaderGroupType groupType;
  68. if(rayGen < kMaxU32)
  69. {
  70. groupType = RayTracingShaderGroupType::kRayGen;
  71. groupArray = &m_rayGenGroups;
  72. }
  73. else if(miss < kMaxU32)
  74. {
  75. groupType = RayTracingShaderGroupType::kMiss;
  76. groupArray = &m_missGroups;
  77. }
  78. else
  79. {
  80. ANKI_ASSERT(chit < kMaxU32 || ahit < kMaxU32);
  81. groupType = RayTracingShaderGroupType::kHit;
  82. groupArray = &m_hitGroups;
  83. }
  84. ShaderGroup* pgroup = nullptr;
  85. for(ShaderGroup& s : *groupArray)
  86. {
  87. if(s.m_rayGen == rayGen && s.m_miss == miss && s.m_ahit == ahit && s.m_chit == chit)
  88. {
  89. pgroup = &s;
  90. break;
  91. }
  92. }
  93. if(!pgroup)
  94. {
  95. pgroup = groupArray->emplaceBack();
  96. pgroup->m_rayGen = rayGen;
  97. pgroup->m_miss = miss;
  98. pgroup->m_chit = chit;
  99. pgroup->m_ahit = ahit;
  100. }
  101. const U64 groupHash = ShaderProgramRaytracingLibrary::generateShaderGroupGroupHash(filename, mutationHash, groupType);
  102. #if ANKI_ASSERTIONS_ENABLED
  103. for(U64 hash : pgroup->m_groupHashes)
  104. {
  105. ANKI_ASSERT(hash != groupHash && "Shouldn't find group with the same hash");
  106. }
  107. #endif
  108. pgroup->m_groupHashes.emplaceBack(groupHash);
  109. }
  110. };
  111. U64 ShaderProgramRaytracingLibrary::generateShaderGroupGroupHash(CString resourceFilename, U64 mutationHash, RayTracingShaderGroupType groupType)
  112. {
  113. ANKI_ASSERT(resourceFilename.getLength() > 0);
  114. ANKI_ASSERT(groupType < RayTracingShaderGroupType::kCount);
  115. String basename;
  116. getFilepathFilename(resourceFilename, basename);
  117. U64 hash = appendHash(basename.cstr(), basename.getLength(), mutationHash);
  118. hash = appendHash(&groupType, sizeof(groupType), hash);
  119. return hash;
  120. }
  121. Error ShaderProgramResourceSystem::init()
  122. {
  123. if(!GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled)
  124. {
  125. return Error::kNone;
  126. }
  127. // Create RT pipeline libraries
  128. const Error err = createRayTracingPrograms(m_rtLibraries);
  129. if(err)
  130. {
  131. ANKI_RESOURCE_LOGE("Failed to create ray tracing programs");
  132. }
  133. return err;
  134. }
  135. Error ShaderProgramResourceSystem::createRayTracingPrograms(ResourceDynamicArray<ShaderProgramRaytracingLibrary>& outLibs)
  136. {
  137. ANKI_RESOURCE_LOGI("Creating ray tracing programs");
  138. U32 rtProgramCount = 0;
  139. ResourceDynamicArray<Lib> libs;
  140. Error err = Error::kNone;
  141. ResourceFilesystem::getSingleton().iterateAllFilenames([&](CString filename) {
  142. // Check file extension
  143. String extension;
  144. getFilepathExtension(filename, extension);
  145. const Char binExtension[] = "ankiprogbin";
  146. if(extension.getLength() != sizeof(binExtension) - 1 || extension != binExtension)
  147. {
  148. return FunctorContinue::kContinue;
  149. }
  150. // Get the binary
  151. ResourceFilePtr file;
  152. if((err = ResourceFilesystem::getSingleton().openFile(filename, file)))
  153. {
  154. return FunctorContinue::kStop;
  155. }
  156. ShaderBinary* binary;
  157. if((err = deserializeShaderBinaryFromAnyFile(*file, binary, ResourceMemoryPool::getSingleton())))
  158. {
  159. return FunctorContinue::kStop;
  160. }
  161. class Dummy
  162. {
  163. public:
  164. ShaderBinary* m_binary;
  165. ~Dummy()
  166. {
  167. ResourceMemoryPool::getSingleton().free(m_binary);
  168. }
  169. } dummy{binary};
  170. if(!(binary->m_shaderTypes & ShaderTypeBit::kAllRayTracing))
  171. {
  172. return FunctorContinue::kContinue;
  173. }
  174. // Create the program name
  175. String progName;
  176. getFilepathFilename(filename, progName);
  177. for(const ShaderBinaryTechnique& technique : binary->m_techniques)
  178. {
  179. if(!(technique.m_shaderTypes & ShaderTypeBit::kAllRayTracing))
  180. {
  181. continue;
  182. }
  183. const U32 techniqueIdx = U32(&technique - binary->m_techniques.getBegin());
  184. // Find or create the lib
  185. Lib* lib = nullptr;
  186. {
  187. for(Lib& l : libs)
  188. {
  189. if(l.m_name == technique.m_name.getBegin())
  190. {
  191. lib = &l;
  192. break;
  193. }
  194. }
  195. if(lib == nullptr)
  196. {
  197. libs.emplaceBack();
  198. lib = &libs.getBack();
  199. lib->m_name = technique.m_name.getBegin();
  200. }
  201. }
  202. // Ray gen
  203. if(!!(technique.m_shaderTypes & ShaderTypeBit::kRayGen))
  204. {
  205. // Iterate all mutations
  206. ConstWeakArray<ShaderBinaryMutation> mutations;
  207. ShaderBinaryMutation dummyMutation;
  208. if(binary->m_mutations.getSize() > 1)
  209. {
  210. mutations = binary->m_mutations;
  211. }
  212. else
  213. {
  214. dummyMutation.m_hash = 0;
  215. dummyMutation.m_variantIndex = 0;
  216. mutations = ConstWeakArray<ShaderBinaryMutation>(&dummyMutation, 1);
  217. }
  218. for(const ShaderBinaryMutation& mutation : mutations)
  219. {
  220. const ShaderBinaryVariant& variant = binary->m_variants[mutation.m_variantIndex];
  221. const U32 codeBlockIndex = variant.m_techniqueCodeBlocks[techniqueIdx].m_codeBlockIndices[ShaderType::kRayGen];
  222. const U32 shaderIdx = lib->addShader(binary->m_codeBlocks[codeBlockIndex], progName, ShaderType::kRayGen);
  223. lib->addGroup(filename, mutation.m_hash, shaderIdx, kMaxU32, kMaxU32, kMaxU32);
  224. }
  225. }
  226. // Miss
  227. if(!!(technique.m_shaderTypes & ShaderTypeBit::kMiss))
  228. {
  229. // Iterate all mutations
  230. ConstWeakArray<ShaderBinaryMutation> mutations;
  231. ShaderBinaryMutation dummyMutation;
  232. if(binary->m_mutations.getSize() > 1)
  233. {
  234. mutations = binary->m_mutations;
  235. }
  236. else
  237. {
  238. dummyMutation.m_hash = 0;
  239. dummyMutation.m_variantIndex = 0;
  240. mutations = ConstWeakArray<ShaderBinaryMutation>(&dummyMutation, 1);
  241. }
  242. for(const ShaderBinaryMutation& mutation : mutations)
  243. {
  244. const ShaderBinaryVariant& variant = binary->m_variants[mutation.m_variantIndex];
  245. const U32 codeBlockIndex = variant.m_techniqueCodeBlocks[techniqueIdx].m_codeBlockIndices[ShaderType::kMiss];
  246. ANKI_ASSERT(codeBlockIndex < kMaxU32);
  247. const U32 shaderIdx = lib->addShader(binary->m_codeBlocks[codeBlockIndex], progName, ShaderType::kMiss);
  248. lib->addGroup(filename, mutation.m_hash, kMaxU32, shaderIdx, kMaxU32, kMaxU32);
  249. }
  250. }
  251. // Hit shaders
  252. if(!!(technique.m_shaderTypes & ShaderTypeBit::kAllHit))
  253. {
  254. // Before you iterate the mutations do some work if there are none
  255. ConstWeakArray<ShaderBinaryMutation> mutations;
  256. ShaderBinaryMutation dummyMutation;
  257. if(binary->m_mutations.getSize() > 1)
  258. {
  259. mutations = binary->m_mutations;
  260. }
  261. else
  262. {
  263. dummyMutation.m_hash = 0;
  264. dummyMutation.m_variantIndex = 0;
  265. mutations = ConstWeakArray<ShaderBinaryMutation>(&dummyMutation, 1);
  266. }
  267. // Iterate all mutations
  268. for(const ShaderBinaryMutation& mutation : mutations)
  269. {
  270. if(mutation.m_variantIndex == kMaxU32)
  271. {
  272. continue;
  273. }
  274. const ShaderBinaryVariant& variant = binary->m_variants[mutation.m_variantIndex];
  275. const U32 ahitCodeBlockIndex = variant.m_techniqueCodeBlocks[techniqueIdx].m_codeBlockIndices[ShaderType::kAnyHit];
  276. const U32 chitCodeBlockIndex = variant.m_techniqueCodeBlocks[techniqueIdx].m_codeBlockIndices[ShaderType::kClosestHit];
  277. ANKI_ASSERT(ahitCodeBlockIndex != kMaxU32 || chitCodeBlockIndex != kMaxU32);
  278. const U32 ahitShaderIdx = (ahitCodeBlockIndex != kMaxU32)
  279. ? lib->addShader(binary->m_codeBlocks[ahitCodeBlockIndex], progName, ShaderType::kAnyHit)
  280. : kMaxU32;
  281. const U32 chitShaderIdx = (chitCodeBlockIndex != kMaxU32)
  282. ? lib->addShader(binary->m_codeBlocks[chitCodeBlockIndex], progName, ShaderType::kClosestHit)
  283. : kMaxU32;
  284. lib->addGroup(filename, mutation.m_hash, kMaxU32, kMaxU32, chitShaderIdx, ahitShaderIdx);
  285. }
  286. }
  287. } // iterate techniques
  288. return FunctorContinue::kContinue;
  289. }); // For all RT filenames
  290. ANKI_CHECK(err);
  291. // Create the libraries. The value that goes to the m_resourceHashToShaderGroupHandleIndex hashmap is the index of the shader handle inside the
  292. // program. Leverage the fact that there is a predefined order between group types (ray gen first, miss and hit follows). See the ShaderProgram
  293. // class for info.
  294. if(libs.getSize() != 0)
  295. {
  296. outLibs.resize(libs.getSize());
  297. for(U32 libIdx = 0; libIdx < libs.getSize(); ++libIdx)
  298. {
  299. ShaderProgramRaytracingLibrary& outLib = outLibs[libIdx];
  300. const Lib& inLib = libs[libIdx];
  301. const ShaderTypeBit requiredShaders = ShaderTypeBit::kRayGen | ShaderTypeBit::kMiss;
  302. if((inLib.m_presentStages & requiredShaders) != requiredShaders
  303. || !(inLib.m_presentStages & (ShaderTypeBit::kClosestHit | ShaderTypeBit::kAnyHit)))
  304. {
  305. ANKI_RESOURCE_LOGE("The libray is missing shader types: %s", inLib.m_name.cstr());
  306. return Error::kUserData;
  307. }
  308. outLib.m_libraryName = inLib.m_name;
  309. ResourceDynamicArray<RayTracingHitGroup> initInfoHitGroups;
  310. ResourceDynamicArray<Shader*> missShaders;
  311. ResourceDynamicArray<Shader*> rayGenShaders;
  312. U32 groupCount = 0;
  313. // Ray gen
  314. for(const ShaderGroup& group : inLib.m_rayGenGroups)
  315. {
  316. rayGenShaders.emplaceBack(inLib.m_shaders[group.m_rayGen].m_shader.get());
  317. for(U64 hash : group.m_groupHashes)
  318. {
  319. outLib.m_resourceHashToShaderGroupHandleIndex.emplace(hash, groupCount);
  320. }
  321. ++groupCount;
  322. }
  323. // Miss
  324. for(const ShaderGroup& group : inLib.m_missGroups)
  325. {
  326. missShaders.emplaceBack(inLib.m_shaders[group.m_miss].m_shader.get());
  327. for(U64 hash : group.m_groupHashes)
  328. {
  329. outLib.m_resourceHashToShaderGroupHandleIndex.emplace(hash, groupCount);
  330. }
  331. ++groupCount;
  332. }
  333. // Hit
  334. for(const ShaderGroup& group : inLib.m_hitGroups)
  335. {
  336. RayTracingHitGroup* infoHitGroup = initInfoHitGroups.emplaceBack();
  337. if(group.m_ahit < kMaxU32)
  338. {
  339. infoHitGroup->m_anyHitShader = inLib.m_shaders[group.m_ahit].m_shader.get();
  340. }
  341. if(group.m_chit < kMaxU32)
  342. {
  343. infoHitGroup->m_closestHitShader = inLib.m_shaders[group.m_chit].m_shader.get();
  344. }
  345. for(U64 hash : group.m_groupHashes)
  346. {
  347. outLib.m_resourceHashToShaderGroupHandleIndex.emplace(hash, groupCount);
  348. }
  349. ++groupCount;
  350. }
  351. // Create the program
  352. ShaderProgramInitInfo inf(inLib.m_name);
  353. inf.m_rayTracingShaders.m_rayGenShaders = rayGenShaders;
  354. inf.m_rayTracingShaders.m_missShaders = missShaders;
  355. inf.m_rayTracingShaders.m_hitGroups = initInfoHitGroups;
  356. outLib.m_program = GrManager::getSingleton().newShaderProgram(inf);
  357. ++rtProgramCount;
  358. }
  359. }
  360. ANKI_RESOURCE_LOGI("Created %u ray tracing programs", rtProgramCount);
  361. return Error::kNone;
  362. }
  363. } // end namespace anki