MaterialResource.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  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/Resource/MaterialResource.h>
  6. #include <AnKi/Resource/ResourceManager.h>
  7. #include <AnKi/Resource/ImageResource.h>
  8. #include <AnKi/Util/Xml.h>
  9. namespace anki
  10. {
  11. static const Array<CString, U32(BuiltinMutatorId::COUNT)> BUILTIN_MUTATOR_NAMES = {
  12. {"NONE", "ANKI_SUB_TECHNIQUE", "ANKI_LOD", "ANKI_BONES", "ANKI_VELOCITY"}};
  13. class BuiltinVarInfo
  14. {
  15. public:
  16. const char* m_name;
  17. ShaderVariableDataType m_type;
  18. U32 m_arraySize;
  19. };
  20. static const Array<BuiltinVarInfo, U(BuiltinMaterialVariableId::COUNT)> BUILTIN_INFOS = {
  21. {{"NONE", ShaderVariableDataType::NONE, 0},
  22. {"m_ankiModelMatrix", ShaderVariableDataType::MAT3X4, 1},
  23. {"m_ankiPreviousModelMatrix", ShaderVariableDataType::MAT3X4, 1},
  24. {"m_ankiBoneTransformsAddress", ShaderVariableDataType::UVEC2, 1},
  25. {"m_ankiPrevBoneTransformsAddress", ShaderVariableDataType::UVEC2, 1},
  26. {"m_ankiPositionsVertexBufferAddresses", ShaderVariableDataType::UVEC2, MAX_LOD_COUNT},
  27. {"m_ankiOthersVertexBufferAddresses", ShaderVariableDataType::UVEC2, MAX_LOD_COUNT},
  28. {"m_ankiBoneWeightsVertexBufferAddresses", ShaderVariableDataType::UVEC2, MAX_LOD_COUNT}}};
  29. static ANKI_USE_RESULT Error checkBuiltin(CString name, ShaderVariableDataType dataType, U32 arraySize,
  30. BuiltinMaterialVariableId& outId)
  31. {
  32. outId = BuiltinMaterialVariableId::NONE;
  33. for(BuiltinMaterialVariableId id : EnumIterable<BuiltinMaterialVariableId>())
  34. {
  35. if(id == BuiltinMaterialVariableId::NONE)
  36. {
  37. continue;
  38. }
  39. if(BUILTIN_INFOS[id].m_name == name)
  40. {
  41. outId = id;
  42. if(BUILTIN_INFOS[id].m_type != dataType || BUILTIN_INFOS[id].m_arraySize != arraySize)
  43. {
  44. ANKI_RESOURCE_LOGE("Incorect type for builtin: %s", name.cstr());
  45. return Error::USER_DATA;
  46. }
  47. break;
  48. }
  49. }
  50. if(outId == BuiltinMaterialVariableId::NONE && (name.find("m_anki") == 0 || name.find("u_anki") == 0))
  51. {
  52. ANKI_RESOURCE_LOGE("Unknown builtin var: %s", name.cstr());
  53. return Error::USER_DATA;
  54. }
  55. return Error::NONE;
  56. }
  57. // This is some trickery to select calling between XmlElement::getAttributeNumber and XmlElement::getAttributeNumbers
  58. namespace
  59. {
  60. template<typename T>
  61. class IsShaderVarDataTypeAnArray
  62. {
  63. public:
  64. static constexpr Bool VALUE = false;
  65. };
  66. #define ANKI_SVDT_MACRO(capital, type, baseType, rowCount, columnCount) \
  67. template<> \
  68. class IsShaderVarDataTypeAnArray<type> \
  69. { \
  70. public: \
  71. static constexpr Bool VALUE = rowCount * columnCount > 1; \
  72. };
  73. #include <AnKi/Gr/ShaderVariableDataTypeDefs.h>
  74. #undef ANKI_SVDT_MACRO
  75. template<typename T, Bool isArray = IsShaderVarDataTypeAnArray<T>::VALUE>
  76. class GetAttribute
  77. {
  78. public:
  79. ANKI_USE_RESULT Error operator()(const XmlElement& el, T& out)
  80. {
  81. return el.getAttributeNumbers("value", out);
  82. }
  83. };
  84. template<typename T>
  85. class GetAttribute<T, false>
  86. {
  87. public:
  88. ANKI_USE_RESULT Error operator()(const XmlElement& el, T& out)
  89. {
  90. return el.getAttributeNumber("value", out);
  91. }
  92. };
  93. } // namespace
  94. MaterialVariable::MaterialVariable()
  95. {
  96. m_Mat4 = Mat4::getZero();
  97. }
  98. MaterialVariable::~MaterialVariable()
  99. {
  100. }
  101. MaterialResource::MaterialResource(ResourceManager* manager)
  102. : ResourceObject(manager)
  103. {
  104. }
  105. MaterialResource::~MaterialResource()
  106. {
  107. for(MaterialVariable& var : m_vars)
  108. {
  109. var.m_name.destroy(getAllocator());
  110. }
  111. m_vars.destroy(getAllocator());
  112. for(Technique& t : m_techniques)
  113. {
  114. t.m_nonBuiltinsMutation.destroy(getAllocator());
  115. }
  116. }
  117. Error MaterialResource::load(const ResourceFilename& filename, Bool async)
  118. {
  119. XmlDocument doc;
  120. XmlElement el;
  121. Bool present = false;
  122. ANKI_CHECK(openFileParseXml(filename, doc));
  123. // <material>
  124. XmlElement rootEl;
  125. ANKI_CHECK(doc.getChildElement("material", rootEl));
  126. // shadow
  127. ANKI_CHECK(rootEl.getAttributeNumberOptional("shadow", m_shadow, present));
  128. m_shadow = m_shadow != 0;
  129. // <techniques>
  130. XmlElement techniquesEl;
  131. ANKI_CHECK(rootEl.getChildElement("techniques", techniquesEl));
  132. XmlElement techniqueEl;
  133. ANKI_CHECK(techniquesEl.getChildElement("technique", techniqueEl));
  134. do
  135. {
  136. ANKI_CHECK(parseTechnique(techniqueEl, async));
  137. ANKI_CHECK(techniqueEl.getNextSiblingElement("technique", techniqueEl));
  138. } while(techniqueEl);
  139. // <inputs>
  140. ANKI_CHECK(rootEl.getChildElementOptional("inputs", el));
  141. if(el)
  142. {
  143. ANKI_CHECK(parseInputs(el, async));
  144. }
  145. return Error::NONE;
  146. }
  147. Error MaterialResource::parseTechnique(XmlElement techniqueEl, Bool async)
  148. {
  149. // name
  150. CString name;
  151. ANKI_CHECK(techniqueEl.getAttributeText("name", name));
  152. RenderingTechnique techniqueId;
  153. if(name == "GBuffer")
  154. {
  155. techniqueId = RenderingTechnique::GBUFFER;
  156. m_presentTechniques |= RenderingTechniqueBit::GBUFFER;
  157. }
  158. else if(name == "ForwardShading")
  159. {
  160. techniqueId = RenderingTechnique::FORWARD_SHADING;
  161. m_presentTechniques |= RenderingTechniqueBit::FORWARD_SHADING;
  162. }
  163. else if(name == "RtShadows")
  164. {
  165. techniqueId = RenderingTechnique::RT_SHADOWS;
  166. m_presentTechniques |= RenderingTechniqueBit::RT_SHADOWS;
  167. }
  168. else
  169. {
  170. ANKI_RESOURCE_LOGE("Unrecognized technique name: %s", name.cstr());
  171. return Error::USER_DATA;
  172. }
  173. Technique& technique = m_techniques[techniqueId];
  174. // shaderProgram
  175. CString fname;
  176. ANKI_CHECK(techniqueEl.getAttributeText("shaderProgram", fname));
  177. ANKI_CHECK(getManager().loadResource(fname, technique.m_prog, async));
  178. // Create the vars
  179. ANKI_CHECK(createVars(technique.m_prog->getBinary()));
  180. // <mutation>
  181. XmlElement mutatorsEl;
  182. ANKI_CHECK(techniqueEl.getChildElementOptional("mutation", mutatorsEl));
  183. if(mutatorsEl)
  184. {
  185. ANKI_CHECK(parseMutators(mutatorsEl, technique));
  186. }
  187. // And find the builtin mutators
  188. ANKI_CHECK(findBuiltinMutators(technique));
  189. return Error::NONE;
  190. }
  191. Error MaterialResource::parseMutators(XmlElement mutatorsEl, Technique& technique)
  192. {
  193. XmlElement mutatorEl;
  194. ANKI_CHECK(mutatorsEl.getChildElement("mutator", mutatorEl));
  195. //
  196. // Process the non-builtin mutators
  197. //
  198. U32 mutatorCount = 0;
  199. ANKI_CHECK(mutatorEl.getSiblingElementsCount(mutatorCount));
  200. ++mutatorCount;
  201. ANKI_ASSERT(mutatorCount > 0);
  202. technique.m_nonBuiltinsMutation.create(getAllocator(), mutatorCount);
  203. mutatorCount = 0;
  204. do
  205. {
  206. SubMutation& smutation = technique.m_nonBuiltinsMutation[mutatorCount];
  207. // name
  208. CString mutatorName;
  209. ANKI_CHECK(mutatorEl.getAttributeText("name", mutatorName));
  210. if(mutatorName.isEmpty())
  211. {
  212. ANKI_RESOURCE_LOGE("Mutator name is empty");
  213. return Error::USER_DATA;
  214. }
  215. for(BuiltinMutatorId id : EnumIterable<BuiltinMutatorId>())
  216. {
  217. if(id == BuiltinMutatorId::NONE)
  218. {
  219. continue;
  220. }
  221. if(mutatorName == BUILTIN_MUTATOR_NAMES[id])
  222. {
  223. ANKI_RESOURCE_LOGE("Materials shouldn't list builtin mutators: %s", mutatorName.cstr());
  224. return Error::USER_DATA;
  225. }
  226. }
  227. if(mutatorName.find("ANKI_") == 0)
  228. {
  229. ANKI_RESOURCE_LOGE("Mutators can't start with ANKI_: %s", mutatorName.cstr());
  230. return Error::USER_DATA;
  231. }
  232. // value
  233. ANKI_CHECK(mutatorEl.getAttributeNumber("value", smutation.m_value));
  234. // Find mutator
  235. smutation.m_mutator = technique.m_prog->tryFindMutator(mutatorName);
  236. if(!smutation.m_mutator)
  237. {
  238. ANKI_RESOURCE_LOGE("Mutator not found in program %s", &mutatorName[0]);
  239. return Error::USER_DATA;
  240. }
  241. if(!smutation.m_mutator->valueExists(smutation.m_value))
  242. {
  243. ANKI_RESOURCE_LOGE("Value %d is not part of the mutator %s", smutation.m_value, &mutatorName[0]);
  244. return Error::USER_DATA;
  245. }
  246. // Advance
  247. ++mutatorCount;
  248. ANKI_CHECK(mutatorEl.getNextSiblingElement("mutator", mutatorEl));
  249. } while(mutatorEl);
  250. ANKI_ASSERT(mutatorCount == technique.m_nonBuiltinsMutation.getSize());
  251. return Error::NONE;
  252. }
  253. Error MaterialResource::findBuiltinMutators(Technique& technique)
  254. {
  255. U builtinMutatorCount = 0;
  256. // SUB_TECHNIQUE
  257. CString subTechniqueMutatorName = BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::SUB_TECHNIQUE];
  258. const ShaderProgramResourceMutator* subTechniqueMutator = technique.m_prog->tryFindMutator(subTechniqueMutatorName);
  259. technique.m_builtinMutators[BuiltinMutatorId::SUB_TECHNIQUE] = subTechniqueMutator;
  260. if(subTechniqueMutator)
  261. {
  262. if(subTechniqueMutator->m_values.getSize() != U32(RenderingSubTechnique::COUNT) - 1)
  263. {
  264. ANKI_RESOURCE_LOGE("Mutator %s should have %u values in the program", subTechniqueMutatorName.cstr(),
  265. U32(RenderingSubTechnique::COUNT) - 1);
  266. return Error::USER_DATA;
  267. }
  268. U32 count = 0;
  269. for(RenderingSubTechnique p : EnumIterable<RenderingSubTechnique>())
  270. {
  271. if(subTechniqueMutator->m_values[count++] != I(p))
  272. {
  273. ANKI_RESOURCE_LOGE("Values of the %s mutator in the program are not the expected",
  274. subTechniqueMutatorName.cstr());
  275. return Error::USER_DATA;
  276. }
  277. }
  278. ++builtinMutatorCount;
  279. }
  280. // LOD
  281. CString lodMutatorName = BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::LOD];
  282. const ShaderProgramResourceMutator* lodMutator = technique.m_prog->tryFindMutator(lodMutatorName);
  283. technique.m_builtinMutators[BuiltinMutatorId::LOD] = lodMutator;
  284. if(lodMutator)
  285. {
  286. if(lodMutator->m_values.getSize() > MAX_LOD_COUNT)
  287. {
  288. ANKI_RESOURCE_LOGE("Mutator %s should have at least %u values in the program", lodMutatorName.cstr(),
  289. U32(MAX_LOD_COUNT));
  290. return Error::USER_DATA;
  291. }
  292. for(U32 i = 0; i < lodMutator->m_values.getSize(); ++i)
  293. {
  294. if(lodMutator->m_values[i] != I(i))
  295. {
  296. ANKI_RESOURCE_LOGE("Values of the %s mutator in the program are not the expected",
  297. lodMutatorName.cstr());
  298. return Error::USER_DATA;
  299. }
  300. }
  301. technique.m_lodCount = U8(lodMutator->m_values.getSize());
  302. ++builtinMutatorCount;
  303. }
  304. // BONES
  305. CString bonesMutatorName = BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::BONES];
  306. const ShaderProgramResourceMutator* bonesMutator = technique.m_prog->tryFindMutator(bonesMutatorName);
  307. technique.m_builtinMutators[BuiltinMutatorId::BONES] = bonesMutator;
  308. if(bonesMutator)
  309. {
  310. if(bonesMutator->m_values.getSize() != 2)
  311. {
  312. ANKI_RESOURCE_LOGE("Mutator %s should have 2 values in the program", bonesMutatorName.cstr());
  313. return Error::USER_DATA;
  314. }
  315. for(U32 i = 0; i < bonesMutator->m_values.getSize(); ++i)
  316. {
  317. if(bonesMutator->m_values[i] != I(i))
  318. {
  319. ANKI_RESOURCE_LOGE("Values of the %s mutator in the program are not the expected",
  320. bonesMutatorName.cstr());
  321. return Error::USER_DATA;
  322. }
  323. }
  324. ++builtinMutatorCount;
  325. // Find if the relevant members are present
  326. if(tryFindVariable(BUILTIN_INFOS[BuiltinMaterialVariableId::BONE_TRANSFORMS_ADDRESS].m_name) == nullptr
  327. || tryFindVariable(BUILTIN_INFOS[BuiltinMaterialVariableId::PREVIOUS_BONE_TRANSFORMS_ADDRESS].m_name)
  328. == nullptr)
  329. {
  330. ANKI_RESOURCE_LOGE("The program is using the %s mutator but AnKiGpuSceneDescriptor::%s or "
  331. "AnKiGpuSceneDescriptor::%s were not found",
  332. bonesMutatorName.cstr(),
  333. BUILTIN_INFOS[BuiltinMaterialVariableId::BONE_TRANSFORMS_ADDRESS].m_name,
  334. BUILTIN_INFOS[BuiltinMaterialVariableId::PREVIOUS_BONE_TRANSFORMS_ADDRESS].m_name);
  335. return Error::USER_DATA;
  336. }
  337. m_supportSkinning = true;
  338. }
  339. // VELOCITY
  340. CString velocityMutatorName = BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::VELOCITY];
  341. const ShaderProgramResourceMutator* velocityMutator = technique.m_prog->tryFindMutator(velocityMutatorName);
  342. technique.m_builtinMutators[BuiltinMutatorId::VELOCITY] = velocityMutator;
  343. if(velocityMutator)
  344. {
  345. if(velocityMutator->m_values.getSize() != 2)
  346. {
  347. ANKI_RESOURCE_LOGE("Mutator %s should have 2 values in the program", velocityMutatorName.cstr());
  348. return Error::USER_DATA;
  349. }
  350. for(U32 i = 0; i < velocityMutator->m_values.getSize(); ++i)
  351. {
  352. if(velocityMutator->m_values[i] != I(i))
  353. {
  354. ANKI_RESOURCE_LOGE("Values of the %s mutator in the program are not the expected",
  355. velocityMutatorName.cstr());
  356. return Error::USER_DATA;
  357. }
  358. }
  359. ++builtinMutatorCount;
  360. }
  361. if(technique.m_nonBuiltinsMutation.getSize() + builtinMutatorCount != technique.m_prog->getMutators().getSize())
  362. {
  363. ANKI_RESOURCE_LOGE("Some mutatators are unacounted for");
  364. return Error::USER_DATA;
  365. }
  366. return Error::NONE;
  367. }
  368. Error MaterialResource::createVars(const ShaderProgramBinary& binary)
  369. {
  370. // Find b_ankiGpuSceneDescriptions
  371. Bool gpuSceneDescriptionsFound = false;
  372. for(const ShaderProgramBinaryBlock& block : binary.m_uniformBlocks)
  373. {
  374. if(block.m_name.getBegin() == CString("b_ankiGpuSceneDescriptions"))
  375. {
  376. if(block.m_set != 1 || block.m_binding != 0)
  377. {
  378. ANKI_RESOURCE_LOGE("b_ankiGpuSceneDescriptions has wrong binding or set");
  379. return Error::USER_DATA;
  380. }
  381. gpuSceneDescriptionsFound = true;
  382. break;
  383. }
  384. }
  385. if(!gpuSceneDescriptionsFound)
  386. {
  387. ANKI_RESOURCE_LOGE("b_ankiGpuSceneDescriptions not found");
  388. return Error::USER_DATA;
  389. }
  390. // Create the material variables
  391. const ShaderProgramBinaryStruct* gpuSceneDescriptionStruct = nullptr;
  392. for(const ShaderProgramBinaryStruct& struct_ : binary.m_structs)
  393. {
  394. if(CString(struct_.m_name.getBegin()) == "AnKiGpuSceneDescription")
  395. {
  396. gpuSceneDescriptionStruct = &struct_;
  397. break;
  398. }
  399. }
  400. if(gpuSceneDescriptionStruct == nullptr)
  401. {
  402. ANKI_RESOURCE_LOGE("AnKiGpuSceneDescription struct was not found in the binary");
  403. return Error::USER_DATA;
  404. }
  405. else if(m_gpuSceneDescriptionStructSize != 0 && gpuSceneDescriptionStruct->m_size)
  406. {
  407. ANKI_RESOURCE_LOGE("sizeof AnKiGpuSceneDescription doesn't match between techniques");
  408. return Error::USER_DATA;
  409. }
  410. else
  411. {
  412. m_gpuSceneDescriptionStructSize = gpuSceneDescriptionStruct->m_size;
  413. }
  414. for(const ShaderProgramBinaryStructMember& member : gpuSceneDescriptionStruct->m_members)
  415. {
  416. CString name = member.m_name.getBegin();
  417. if(member.m_type == ShaderVariableDataType::NONE)
  418. {
  419. ANKI_RESOURCE_LOGE("Non fundamental type was found in AnKiGpuSceneDescription: %s", name.cstr());
  420. return Error::NONE;
  421. }
  422. BuiltinMaterialVariableId builtinId;
  423. ANKI_CHECK(checkBuiltin(name, member.m_type, member.m_arraySize, builtinId));
  424. MaterialVariable* var = tryFindVariable(name);
  425. if(var)
  426. {
  427. if(var->m_dataType != member.m_type || var->m_builtin != builtinId
  428. || var->m_offsetInStruct != member.m_offset)
  429. {
  430. ANKI_RESOURCE_LOGE("Member variable doesn't match between techniques: %s", name.cstr());
  431. return Error::USER_DATA;
  432. }
  433. }
  434. else
  435. {
  436. var = m_vars.emplaceBack(getAllocator());
  437. var->m_name.create(getAllocator(), name);
  438. var->m_dataType = member.m_type;
  439. var->m_builtin = builtinId;
  440. var->m_offsetInStruct = member.m_offset;
  441. }
  442. }
  443. return Error::NONE;
  444. }
  445. Error MaterialResource::parseInputs(XmlElement inputsEl, Bool async)
  446. {
  447. // Connect the input variables
  448. XmlElement inputEl;
  449. ANKI_CHECK(inputsEl.getChildElementOptional("input", inputEl));
  450. while(inputEl)
  451. {
  452. // Get var name
  453. CString varName;
  454. ANKI_CHECK(inputEl.getAttributeText("name", varName));
  455. // Try find var
  456. MaterialVariable* foundVar = tryFindVariable(varName);
  457. if(foundVar == nullptr)
  458. {
  459. ANKI_RESOURCE_LOGE("Variable not found: %s", varName.cstr());
  460. return Error::USER_DATA;
  461. }
  462. if(foundVar->m_builtin != BuiltinMaterialVariableId::NONE)
  463. {
  464. ANKI_RESOURCE_LOGE("Shouldn't list builtin vars: %s", varName.cstr());
  465. return Error::USER_DATA;
  466. }
  467. // Find out if it's a texture by looking at the input value
  468. Bool isTexture = false;
  469. if(foundVar->m_dataType == ShaderVariableDataType::U16)
  470. {
  471. CString valueTxt;
  472. ANKI_CHECK(inputEl.getAttributeText("value", valueTxt));
  473. for(Char c : valueTxt)
  474. {
  475. if(std::isalpha(c))
  476. {
  477. isTexture = true;
  478. break;
  479. }
  480. }
  481. }
  482. // A value will be set
  483. foundVar->m_numericValueIsSet = true;
  484. if(isTexture)
  485. {
  486. CString texfname;
  487. ANKI_CHECK(inputEl.getAttributeText("value", texfname));
  488. ANKI_CHECK(getManager().loadResource(texfname, foundVar->m_image, async));
  489. foundVar->m_bindlessTextureIndex =
  490. U16(foundVar->m_image->getTextureView()->getOrCreateBindlessTextureIndex());
  491. }
  492. else
  493. {
  494. switch(foundVar->m_dataType)
  495. {
  496. #define ANKI_SVDT_MACRO(capital, type, baseType, rowCount, columnCount) \
  497. case ShaderVariableDataType::capital: \
  498. ANKI_CHECK(GetAttribute<type>()(inputEl, foundVar->ANKI_CONCATENATE(m_, type))); \
  499. break;
  500. #include <AnKi/Gr/ShaderVariableDataTypeDefs.h>
  501. #undef ANKI_SVDT_MACRO
  502. default:
  503. ANKI_ASSERT(0);
  504. break;
  505. }
  506. }
  507. // Advance
  508. ANKI_CHECK(inputEl.getNextSiblingElement("input", inputEl));
  509. }
  510. return Error::NONE;
  511. }
  512. const MaterialVariant& MaterialResource::getOrCreateVariant(const RenderingKey& key_) const
  513. {
  514. RenderingKey key = key_;
  515. const Technique& technique = m_techniques[key.m_renderingTechnique];
  516. ANKI_ASSERT(technique.m_prog.isCreated());
  517. key.m_lod = min<U8>(technique.m_lodCount - 1, key.m_lod);
  518. ANKI_ASSERT(!key.m_skinned || technique.m_builtinMutators[BuiltinMutatorId::BONES]);
  519. ANKI_ASSERT(!key.m_velocity || technique.m_builtinMutators[BuiltinMutatorId::VELOCITY]);
  520. MaterialVariant& variant =
  521. technique.m_variantMatrix[key.m_renderingSubTechnique][key.m_lod][key.m_skinned][key.m_velocity];
  522. // Check if it's initialized
  523. {
  524. RLockGuard<RWMutex> lock(technique.m_variantMatrixMtx);
  525. if(variant.m_prog.isCreated())
  526. {
  527. return variant;
  528. }
  529. }
  530. // Not initialized, init it
  531. WLockGuard<RWMutex> lock(technique.m_variantMatrixMtx);
  532. // Check again
  533. if(variant.m_prog.isCreated())
  534. {
  535. return variant;
  536. }
  537. ShaderProgramResourceVariantInitInfo initInfo(technique.m_prog);
  538. for(const SubMutation& m : technique.m_nonBuiltinsMutation)
  539. {
  540. initInfo.addMutation(m.m_mutator->m_name, m.m_value);
  541. }
  542. if(technique.m_builtinMutators[BuiltinMutatorId::SUB_TECHNIQUE])
  543. {
  544. initInfo.addMutation(technique.m_builtinMutators[BuiltinMutatorId::SUB_TECHNIQUE]->m_name,
  545. MutatorValue(key.m_renderingSubTechnique));
  546. }
  547. if(technique.m_builtinMutators[BuiltinMutatorId::LOD])
  548. {
  549. initInfo.addMutation(technique.m_builtinMutators[BuiltinMutatorId::LOD]->m_name, MutatorValue(key.m_lod));
  550. }
  551. if(technique.m_builtinMutators[BuiltinMutatorId::BONES])
  552. {
  553. initInfo.addMutation(technique.m_builtinMutators[BuiltinMutatorId::BONES]->m_name, key.m_skinned != 0);
  554. }
  555. if(technique.m_builtinMutators[BuiltinMutatorId::VELOCITY])
  556. {
  557. initInfo.addMutation(technique.m_builtinMutators[BuiltinMutatorId::VELOCITY]->m_name, key.m_velocity != 0);
  558. }
  559. const ShaderProgramResourceVariant* progVariant;
  560. technique.m_prog->getOrCreateVariant(initInfo, progVariant);
  561. variant.m_prog = progVariant->getProgram();
  562. return variant;
  563. }
  564. } // end namespace anki