MaterialResource.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  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/MaterialResource.h>
  6. #include <AnKi/Resource/ResourceManager.h>
  7. #include <AnKi/Resource/ImageResource.h>
  8. #include <AnKi/Core/App.h>
  9. #include <AnKi/Util/Xml.h>
  10. namespace anki {
  11. inline constexpr Array<CString, U32(BuiltinMutatorId::kCount)> kBuiltinMutatorNames = {{"NONE", "ANKI_BONES", "ANKI_VELOCITY"}};
  12. // This is some trickery to select calling between XmlElement::getAttributeNumber and XmlElement::getAttributeNumbers
  13. namespace {
  14. template<typename T>
  15. class IsShaderVarDataTypeAnArray
  16. {
  17. public:
  18. static constexpr Bool kValue = false;
  19. };
  20. #define ANKI_SVDT_MACRO(type, baseType, rowCount, columnCount, isIntagralType) \
  21. template<> \
  22. class IsShaderVarDataTypeAnArray<type> \
  23. { \
  24. public: \
  25. static constexpr Bool kValue = rowCount * columnCount > 1; \
  26. };
  27. #include <AnKi/Gr/ShaderVariableDataType.def.h>
  28. #undef ANKI_SVDT_MACRO
  29. template<typename T, Bool isArray = IsShaderVarDataTypeAnArray<T>::kValue>
  30. class GetAttribute
  31. {
  32. public:
  33. Error operator()(const XmlElement& el, T& out)
  34. {
  35. return el.getAttributeNumbers("value", out);
  36. }
  37. };
  38. template<typename T>
  39. class GetAttribute<T, false>
  40. {
  41. public:
  42. Error operator()(const XmlElement& el, T& out)
  43. {
  44. return el.getAttributeNumber("value", out);
  45. }
  46. };
  47. } // namespace
  48. static Bool mutatorValueExists(const ShaderBinaryMutator& m, MutatorValue val)
  49. {
  50. for(MutatorValue v : m.m_values)
  51. {
  52. if(v == val)
  53. {
  54. return true;
  55. }
  56. }
  57. return false;
  58. }
  59. MaterialVariable::MaterialVariable()
  60. {
  61. m_Mat4 = Mat4::getZero();
  62. }
  63. MaterialVariable::~MaterialVariable()
  64. {
  65. }
  66. MaterialResource::MaterialResource()
  67. {
  68. }
  69. MaterialResource::~MaterialResource()
  70. {
  71. ResourceMemoryPool::getSingleton().free(m_prefilledLocalConstants);
  72. }
  73. const MaterialVariable* MaterialResource::tryFindVariableInternal(CString name) const
  74. {
  75. for(const MaterialVariable& v : m_vars)
  76. {
  77. if(v.m_name == name)
  78. {
  79. return &v;
  80. }
  81. }
  82. return nullptr;
  83. }
  84. Error MaterialResource::load(const ResourceFilename& filename, Bool async)
  85. {
  86. ResourceXmlDocument doc;
  87. XmlElement el;
  88. ANKI_CHECK(openFileParseXml(filename, doc));
  89. // <material>
  90. XmlElement rootEl;
  91. ANKI_CHECK(doc.getChildElement("material", rootEl));
  92. // <shaderPrograms>
  93. XmlElement shaderProgramEl;
  94. ANKI_CHECK(rootEl.getChildElement("shaderProgram", shaderProgramEl));
  95. ANKI_CHECK(parseShaderProgram(shaderProgramEl, async));
  96. ANKI_ASSERT(!!m_techniquesMask);
  97. // <inputs>
  98. BitSet<128> varsSet(false);
  99. ANKI_CHECK(rootEl.getChildElementOptional("inputs", el));
  100. if(el)
  101. {
  102. XmlElement inputEl;
  103. ANKI_CHECK(el.getChildElement("input", inputEl));
  104. do
  105. {
  106. ANKI_CHECK(parseInput(inputEl, async, varsSet));
  107. ANKI_CHECK(inputEl.getNextSiblingElement("input", inputEl));
  108. } while(inputEl);
  109. }
  110. if(varsSet.getSetBitCount() != m_vars.getSize())
  111. {
  112. ANKI_RESOURCE_LOGV("Material doesn't contain default value for %u input variables", U32(m_vars.getSize() - varsSet.getSetBitCount()));
  113. // Remove unreferenced variables
  114. ResourceDynamicArray<MaterialVariable> newVars;
  115. for(U32 i = 0; i < m_vars.getSize(); ++i)
  116. {
  117. if(varsSet.get(i))
  118. {
  119. newVars.emplaceBack(std::move(m_vars[i]));
  120. }
  121. }
  122. m_vars = std::move(newVars);
  123. }
  124. prefillLocalConstants();
  125. return Error::kNone;
  126. }
  127. Error MaterialResource::parseShaderProgram(XmlElement shaderProgramEl, Bool async)
  128. {
  129. // name
  130. CString shaderName;
  131. ANKI_CHECK(shaderProgramEl.getAttributeText("name", shaderName));
  132. ResourceString fname;
  133. fname.sprintf("ShaderBinaries/%s.ankiprogbin", shaderName.cstr());
  134. ANKI_CHECK(ResourceManager::getSingleton().loadResource(fname, m_prog, async));
  135. // Find present techniques
  136. for(const ShaderBinaryTechnique& t : m_prog->getBinary().m_techniques)
  137. {
  138. if(t.m_name.getBegin() == CString("GBufferLegacy"))
  139. {
  140. m_techniquesMask |= RenderingTechniqueBit::kGBuffer;
  141. m_shaderTechniques |= ShaderTechniqueBit::kLegacy;
  142. }
  143. else if(t.m_name.getBegin() == CString("GBufferMeshShaders"))
  144. {
  145. m_techniquesMask |= RenderingTechniqueBit::kGBuffer;
  146. m_shaderTechniques |= ShaderTechniqueBit::kMeshSaders;
  147. }
  148. else if(t.m_name.getBegin() == CString("GBufferSwMeshletRendering"))
  149. {
  150. m_techniquesMask |= RenderingTechniqueBit::kGBuffer;
  151. m_shaderTechniques |= ShaderTechniqueBit::kSwMeshletRendering;
  152. }
  153. else if(t.m_name.getBegin() == CString("ShadowsLegacy"))
  154. {
  155. m_techniquesMask |= RenderingTechniqueBit::kDepth;
  156. m_shaderTechniques |= ShaderTechniqueBit::kLegacy;
  157. }
  158. else if(t.m_name.getBegin() == CString("ShadowsMeshShaders"))
  159. {
  160. m_techniquesMask |= RenderingTechniqueBit::kDepth;
  161. m_shaderTechniques |= ShaderTechniqueBit::kMeshSaders;
  162. }
  163. else if(t.m_name.getBegin() == CString("ShadowsSwMeshletRendering"))
  164. {
  165. m_techniquesMask |= RenderingTechniqueBit::kDepth;
  166. m_shaderTechniques |= ShaderTechniqueBit::kSwMeshletRendering;
  167. }
  168. else if(t.m_name.getBegin() == CString("RtShadows"))
  169. {
  170. if(GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled)
  171. {
  172. m_techniquesMask |= RenderingTechniqueBit::kRtShadow;
  173. }
  174. }
  175. else if(t.m_name.getBegin() == CString("ForwardSwMeshletRendering"))
  176. {
  177. m_techniquesMask |= RenderingTechniqueBit::kForward;
  178. m_shaderTechniques |= ShaderTechniqueBit::kSwMeshletRendering;
  179. }
  180. else if(t.m_name.getBegin() == CString("ForwardMeshShaders"))
  181. {
  182. m_techniquesMask |= RenderingTechniqueBit::kForward;
  183. m_shaderTechniques |= ShaderTechniqueBit::kMeshSaders;
  184. }
  185. else if(t.m_name.getBegin() == CString("ForwardLegacy"))
  186. {
  187. m_techniquesMask |= RenderingTechniqueBit::kForward;
  188. m_shaderTechniques |= ShaderTechniqueBit::kLegacy;
  189. }
  190. else if(t.m_name.getBegin() == CString("RtMaterialFetch"))
  191. {
  192. if(GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled)
  193. {
  194. m_techniquesMask |= RenderingTechniqueBit::kRtMaterialFetch;
  195. }
  196. }
  197. else
  198. {
  199. ANKI_RESOURCE_LOGE("Found unneeded technique in the shader: %s", t.m_name.getBegin());
  200. return Error::kUserData;
  201. }
  202. }
  203. // <mutation>
  204. XmlElement mutatorsEl;
  205. ANKI_CHECK(shaderProgramEl.getChildElementOptional("mutation", mutatorsEl));
  206. if(mutatorsEl)
  207. {
  208. ANKI_CHECK(parseMutators(mutatorsEl));
  209. }
  210. // And find the builtin mutators
  211. ANKI_CHECK(findBuiltinMutators());
  212. // Create the vars
  213. ANKI_CHECK(createVars());
  214. return Error::kNone;
  215. }
  216. Error MaterialResource::parseMutators(XmlElement mutatorsEl)
  217. {
  218. XmlElement mutatorEl;
  219. ANKI_CHECK(mutatorsEl.getChildElement("mutator", mutatorEl));
  220. U32 mutatorCount = 0;
  221. ANKI_CHECK(mutatorEl.getSiblingElementsCount(mutatorCount));
  222. ++mutatorCount;
  223. ANKI_ASSERT(mutatorCount > 0);
  224. m_partialMutation.resize(mutatorCount);
  225. mutatorCount = 0;
  226. do
  227. {
  228. PartialMutation& pmutation = m_partialMutation[mutatorCount];
  229. // name
  230. CString mutatorName;
  231. ANKI_CHECK(mutatorEl.getAttributeText("name", mutatorName));
  232. if(mutatorName.isEmpty())
  233. {
  234. ANKI_RESOURCE_LOGE("Mutator name is empty");
  235. return Error::kUserData;
  236. }
  237. for(BuiltinMutatorId id : EnumIterable<BuiltinMutatorId>())
  238. {
  239. if(id == BuiltinMutatorId::kNone)
  240. {
  241. continue;
  242. }
  243. if(mutatorName == kBuiltinMutatorNames[id])
  244. {
  245. ANKI_RESOURCE_LOGE("Materials shouldn't list builtin mutators: %s", mutatorName.cstr());
  246. return Error::kUserData;
  247. }
  248. }
  249. if(mutatorName.find("ANKI_") == 0)
  250. {
  251. ANKI_RESOURCE_LOGE("Mutators can't start with ANKI_: %s", mutatorName.cstr());
  252. return Error::kUserData;
  253. }
  254. // value
  255. ANKI_CHECK(mutatorEl.getAttributeNumber("value", pmutation.m_value));
  256. // Find mutator
  257. pmutation.m_mutator = m_prog->tryFindMutator(mutatorName);
  258. if(!pmutation.m_mutator)
  259. {
  260. ANKI_RESOURCE_LOGE("Mutator not found in program %s", &mutatorName[0]);
  261. return Error::kUserData;
  262. }
  263. if(!mutatorValueExists(*pmutation.m_mutator, pmutation.m_value))
  264. {
  265. ANKI_RESOURCE_LOGE("Value %d is not part of the mutator %s", pmutation.m_value, mutatorName.cstr());
  266. return Error::kUserData;
  267. }
  268. // Advance
  269. ++mutatorCount;
  270. ANKI_CHECK(mutatorEl.getNextSiblingElement("mutator", mutatorEl));
  271. } while(mutatorEl);
  272. ANKI_ASSERT(mutatorCount == m_partialMutation.getSize());
  273. return Error::kNone;
  274. }
  275. Error MaterialResource::findBuiltinMutators()
  276. {
  277. U builtinMutatorCount = 0;
  278. // ANKI_BONES
  279. CString bonesMutatorName = kBuiltinMutatorNames[BuiltinMutatorId::kBones];
  280. const ShaderBinaryMutator* bonesMutator = m_prog->tryFindMutator(bonesMutatorName);
  281. if(bonesMutator)
  282. {
  283. if(bonesMutator->m_values.getSize() != 2)
  284. {
  285. ANKI_RESOURCE_LOGE("Mutator %s should have 2 values in the program", bonesMutatorName.cstr());
  286. return Error::kUserData;
  287. }
  288. for(U32 i = 0; i < bonesMutator->m_values.getSize(); ++i)
  289. {
  290. if(bonesMutator->m_values[i] != MutatorValue(i))
  291. {
  292. ANKI_RESOURCE_LOGE("Values of the %s mutator in the program are not the expected", bonesMutatorName.cstr());
  293. return Error::kUserData;
  294. }
  295. }
  296. ++builtinMutatorCount;
  297. m_supportsSkinning = true;
  298. m_presentBuildinMutatorMask |= U32(1 << BuiltinMutatorId::kBones);
  299. }
  300. // VELOCITY
  301. CString velocityMutatorName = kBuiltinMutatorNames[BuiltinMutatorId::kVelocity];
  302. const ShaderBinaryMutator* velocityMutator = m_prog->tryFindMutator(velocityMutatorName);
  303. if(velocityMutator)
  304. {
  305. if(velocityMutator->m_values.getSize() != 2)
  306. {
  307. ANKI_RESOURCE_LOGE("Mutator %s should have 2 values in the program", velocityMutatorName.cstr());
  308. return Error::kUserData;
  309. }
  310. for(U32 i = 0; i < velocityMutator->m_values.getSize(); ++i)
  311. {
  312. if(velocityMutator->m_values[i] != MutatorValue(i))
  313. {
  314. ANKI_RESOURCE_LOGE("Values of the %s mutator in the program are not the expected", velocityMutatorName.cstr());
  315. return Error::kUserData;
  316. }
  317. }
  318. ++builtinMutatorCount;
  319. m_presentBuildinMutatorMask |= U32(1 << BuiltinMutatorId::kVelocity);
  320. }
  321. if(m_partialMutation.getSize() + builtinMutatorCount != m_prog->getBinary().m_mutators.getSize())
  322. {
  323. ANKI_RESOURCE_LOGE("Some mutatators are unacounted for");
  324. return Error::kUserData;
  325. }
  326. return Error::kNone;
  327. }
  328. Error MaterialResource::createVars()
  329. {
  330. const ShaderBinary& binary = m_prog->getBinary();
  331. // Find struct
  332. const ShaderBinaryStruct* localConstantsStruct = nullptr;
  333. for(const ShaderBinaryStruct& strct : binary.m_structs)
  334. {
  335. if(CString(strct.m_name.getBegin()) == "AnKiLocalConstants")
  336. {
  337. localConstantsStruct = &strct;
  338. break;
  339. }
  340. }
  341. // Create vars
  342. for(U32 i = 0; localConstantsStruct && i < localConstantsStruct->m_members.getSize(); ++i)
  343. {
  344. const ShaderBinaryStructMember& member = localConstantsStruct->m_members[i];
  345. const CString memberName = member.m_name.getBegin();
  346. MaterialVariable& var = *m_vars.emplaceBack();
  347. zeroMemory(var);
  348. var.m_name = memberName;
  349. var.m_dataType = member.m_type;
  350. var.m_offsetInLocalConstants = member.m_offset;
  351. }
  352. m_localConstantsSize = (localConstantsStruct) ? localConstantsStruct->m_size : 0;
  353. return Error::kNone;
  354. }
  355. Error MaterialResource::parseInput(XmlElement inputEl, Bool async, BitSet<128>& varsSet)
  356. {
  357. // Get var name
  358. CString varName;
  359. ANKI_CHECK(inputEl.getAttributeText("name", varName));
  360. // Try find var
  361. MaterialVariable* foundVar = tryFindVariable(varName);
  362. if(!foundVar)
  363. {
  364. ANKI_RESOURCE_LOGE("Input name is wrong, variable not found: %s", varName.cstr());
  365. return Error::kUserData;
  366. }
  367. // Set check
  368. const U32 idx = U32(foundVar - m_vars.getBegin());
  369. if(varsSet.get(idx))
  370. {
  371. ANKI_RESOURCE_LOGE("Input already has a value: %s", varName.cstr());
  372. return Error::kUserData;
  373. }
  374. varsSet.set(idx);
  375. // Set the value
  376. if(foundVar->m_dataType == ShaderVariableDataType::kU32)
  377. {
  378. // U32 is a bit special. It might be a number or a bindless texture
  379. CString value;
  380. ANKI_CHECK(inputEl.getAttributeText("value", value));
  381. // Check if the value has letters
  382. Bool containsAlpharithmetic = false;
  383. for(Char c : value)
  384. {
  385. if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'a'))
  386. {
  387. containsAlpharithmetic = true;
  388. break;
  389. }
  390. }
  391. // If it has letters it's a texture
  392. if(containsAlpharithmetic)
  393. {
  394. ANKI_CHECK(ResourceManager::getSingleton().loadResource(value, foundVar->m_image, async));
  395. foundVar->m_U32 = foundVar->m_image->getTexture().getOrCreateBindlessTextureIndex(TextureSubresourceDesc::all());
  396. }
  397. else
  398. {
  399. ANKI_CHECK(GetAttribute<U32>()(inputEl, foundVar->m_U32));
  400. }
  401. }
  402. else
  403. {
  404. switch(foundVar->m_dataType)
  405. {
  406. #define ANKI_SVDT_MACRO(type, baseType, rowCount, columnCount, isIntagralType) \
  407. case ShaderVariableDataType::k##type: \
  408. ANKI_CHECK(GetAttribute<type>()(inputEl, foundVar->ANKI_CONCATENATE(m_, type))); \
  409. break;
  410. #include <AnKi/Gr/ShaderVariableDataType.def.h>
  411. #undef ANKI_SVDT_MACRO
  412. default:
  413. ANKI_ASSERT(0);
  414. break;
  415. }
  416. }
  417. return Error::kNone;
  418. }
  419. void MaterialResource::prefillLocalConstants()
  420. {
  421. if(m_localConstantsSize == 0)
  422. {
  423. return;
  424. }
  425. m_prefilledLocalConstants = ResourceMemoryPool::getSingleton().allocate(m_localConstantsSize, 1);
  426. memset(m_prefilledLocalConstants, 0, m_localConstantsSize);
  427. for(const MaterialVariable& var : m_vars)
  428. {
  429. switch(var.m_dataType)
  430. {
  431. #define ANKI_SVDT_MACRO(type, baseType, rowCount, columnCount, isIntagralType) \
  432. case ShaderVariableDataType::k##type: \
  433. ANKI_ASSERT(var.m_offsetInLocalConstants + sizeof(type) <= m_localConstantsSize); \
  434. memcpy(static_cast<U8*>(m_prefilledLocalConstants) + var.m_offsetInLocalConstants, &var.m_##type, sizeof(type)); \
  435. break;
  436. #include <AnKi/Gr/ShaderVariableDataType.def.h>
  437. #undef ANKI_SVDT_MACRO
  438. default:
  439. ANKI_ASSERT(0);
  440. break;
  441. }
  442. }
  443. }
  444. const MaterialVariant& MaterialResource::getOrCreateVariant(const RenderingKey& key_) const
  445. {
  446. RenderingKey key = key_;
  447. // Sanitize the key
  448. if(!(m_presentBuildinMutatorMask & U32(BuiltinMutatorId::kVelocity)) && key.getVelocity())
  449. {
  450. // Particles set their own velocity
  451. key.setVelocity(false);
  452. }
  453. if(key.getRenderingTechnique() != RenderingTechnique::kGBuffer && key.getVelocity())
  454. {
  455. // Only GBuffer technique can write to velocity buffers
  456. key.setVelocity(false);
  457. }
  458. const Bool meshShadersSupported = GrManager::getSingleton().getDeviceCapabilities().m_meshShaders;
  459. ANKI_ASSERT(!(key.getMeshletRendering() && (!meshShadersSupported && !g_meshletRenderingCVar))
  460. && "Can't be asking for meshlet rendering if mesh shaders or SW meshlet rendering are not supported/enabled");
  461. if(key.getMeshletRendering() && !(m_shaderTechniques & (ShaderTechniqueBit::kMeshSaders | ShaderTechniqueBit::kSwMeshletRendering)))
  462. {
  463. key.setMeshletRendering(false);
  464. }
  465. ANKI_ASSERT(!key.getSkinned() || !!(m_presentBuildinMutatorMask & U32(1 << BuiltinMutatorId::kBones)));
  466. ANKI_ASSERT(!key.getVelocity() || !!(m_presentBuildinMutatorMask & U32(1 << BuiltinMutatorId::kVelocity)));
  467. MaterialVariant& variant = m_variantMatrix[key.getRenderingTechnique()][key.getSkinned()][key.getVelocity()][key.getMeshletRendering()];
  468. // Check if it's initialized
  469. {
  470. RLockGuard<RWMutex> lock(m_variantMatrixMtx);
  471. if(variant.m_prog.isCreated()) [[likely]]
  472. {
  473. return variant;
  474. }
  475. }
  476. // Not initialized, init it
  477. WLockGuard<RWMutex> lock(m_variantMatrixMtx);
  478. // Check again
  479. if(variant.m_prog.isCreated())
  480. {
  481. return variant;
  482. }
  483. ShaderProgramResourceVariantInitInfo initInfo(m_prog);
  484. for(const PartialMutation& m : m_partialMutation)
  485. {
  486. initInfo.addMutation(m.m_mutator->m_name.getBegin(), m.m_value);
  487. }
  488. if(!!(m_presentBuildinMutatorMask & U32(1 << BuiltinMutatorId::kBones)))
  489. {
  490. initInfo.addMutation(kBuiltinMutatorNames[BuiltinMutatorId::kBones], MutatorValue(key.getSkinned()));
  491. }
  492. if(!!(m_presentBuildinMutatorMask & U32(1 << BuiltinMutatorId::kVelocity)))
  493. {
  494. initInfo.addMutation(kBuiltinMutatorNames[BuiltinMutatorId::kVelocity], MutatorValue(key.getVelocity()));
  495. }
  496. switch(key.getRenderingTechnique())
  497. {
  498. case RenderingTechnique::kGBuffer:
  499. if(key.getMeshletRendering() && meshShadersSupported)
  500. {
  501. initInfo.requestTechniqueAndTypes(ShaderTypeBit::kMesh | ShaderTypeBit::kPixel, "GBufferMeshShaders");
  502. }
  503. else if(key.getMeshletRendering())
  504. {
  505. initInfo.requestTechniqueAndTypes(ShaderTypeBit::kVertex | ShaderTypeBit::kPixel, "GBufferSwMeshletRendering");
  506. }
  507. else
  508. {
  509. initInfo.requestTechniqueAndTypes(ShaderTypeBit::kVertex | ShaderTypeBit::kPixel, "GBufferLegacy");
  510. }
  511. break;
  512. case RenderingTechnique::kDepth:
  513. if(key.getMeshletRendering() && meshShadersSupported)
  514. {
  515. initInfo.requestTechniqueAndTypes(ShaderTypeBit::kMesh | ShaderTypeBit::kPixel, "ShadowsMeshShaders");
  516. }
  517. else if(key.getMeshletRendering())
  518. {
  519. initInfo.requestTechniqueAndTypes(ShaderTypeBit::kVertex | ShaderTypeBit::kPixel, "ShadowsSwMeshletRendering");
  520. }
  521. else
  522. {
  523. initInfo.requestTechniqueAndTypes(ShaderTypeBit::kVertex | ShaderTypeBit::kPixel, "ShadowsLegacy");
  524. }
  525. break;
  526. case RenderingTechnique::kForward:
  527. if(key.getMeshletRendering() && meshShadersSupported)
  528. {
  529. initInfo.requestTechniqueAndTypes(ShaderTypeBit::kMesh | ShaderTypeBit::kPixel, "ForwardMeshShaders");
  530. }
  531. else if(key.getMeshletRendering())
  532. {
  533. initInfo.requestTechniqueAndTypes(ShaderTypeBit::kVertex | ShaderTypeBit::kPixel, "ForwardSwMeshletRendering");
  534. }
  535. else
  536. {
  537. initInfo.requestTechniqueAndTypes(ShaderTypeBit::kVertex | ShaderTypeBit::kPixel, "ForwardLegacy");
  538. }
  539. break;
  540. case RenderingTechnique::kRtShadow:
  541. initInfo.requestTechniqueAndTypes(ShaderTypeBit::kAllHit, "RtShadows");
  542. break;
  543. case RenderingTechnique::kRtMaterialFetch:
  544. initInfo.requestTechniqueAndTypes(ShaderTypeBit::kAllHit, "RtMaterialFetch");
  545. break;
  546. default:
  547. ANKI_ASSERT(0);
  548. }
  549. const ShaderProgramResourceVariant* progVariant = nullptr;
  550. m_prog->getOrCreateVariant(initInfo, progVariant);
  551. if(!progVariant)
  552. {
  553. ANKI_RESOURCE_LOGF("Fetched skipped mutation on program %s", getFilename().cstr());
  554. }
  555. variant.m_prog.reset(&progVariant->getProgram());
  556. if(!!(RenderingTechniqueBit(1 << key.getRenderingTechnique()) & RenderingTechniqueBit::kAllRt))
  557. {
  558. variant.m_rtShaderGroupHandleIndex = progVariant->getShaderGroupHandleIndex();
  559. }
  560. return variant;
  561. }
  562. } // end namespace anki