MaterialResource.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798
  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/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. inline constexpr Array<CString, U32(BuiltinMutatorId::kCount)> kBuiltinMutatorNames = {{"NONE", "ANKI_TECHNIQUE", "ANKI_BONES", "ANKI_VELOCITY"}};
  11. inline constexpr Array<CString, U(RenderingTechnique::kCount)> kTechniqueNames = {{"GBuffer", "Depth", "Forward", "RtShadow"}};
  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.defs.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. MaterialVariable::MaterialVariable()
  49. {
  50. m_Mat4 = Mat4::getZero();
  51. }
  52. MaterialVariable::~MaterialVariable()
  53. {
  54. }
  55. class MaterialResource::Program
  56. {
  57. public:
  58. ShaderProgramResourcePtr m_prog;
  59. mutable Array4d<MaterialVariant, U(RenderingTechnique::kCount), 2, 2, 2> m_variantMatrix;
  60. mutable RWMutex m_variantMatrixMtx;
  61. ResourceDynamicArray<PartialMutation> m_partialMutation; ///< Only with the non-builtins.
  62. U32 m_presentBuildinMutators = 0;
  63. U32 m_localUniformsStructIdx = 0; ///< Struct index in the program binary.
  64. U8 m_lodCount = 1;
  65. Program() = default;
  66. Program(const Program&) = delete; // Non-copyable
  67. Program(Program&& b)
  68. {
  69. *this = std::move(b);
  70. }
  71. Program& operator=(const Program& b) = delete; // Non-copyable
  72. Program& operator=(Program&& b)
  73. {
  74. m_prog = std::move(b.m_prog);
  75. for(RenderingTechnique t : EnumIterable<RenderingTechnique>())
  76. {
  77. for(U32 skin = 0; skin < 2; ++skin)
  78. {
  79. for(U32 vel = 0; vel < 2; ++vel)
  80. {
  81. for(U32 mesh = 0; mesh < 2; ++mesh)
  82. {
  83. m_variantMatrix[t][skin][vel][mesh] = std::move(b.m_variantMatrix[t][skin][vel][mesh]);
  84. }
  85. }
  86. }
  87. }
  88. m_partialMutation = std::move(b.m_partialMutation);
  89. m_presentBuildinMutators = b.m_presentBuildinMutators;
  90. m_localUniformsStructIdx = b.m_localUniformsStructIdx;
  91. m_lodCount = b.m_lodCount;
  92. return *this;
  93. }
  94. };
  95. MaterialResource::MaterialResource()
  96. {
  97. memset(m_techniqueToProgram.getBegin(), 0xFF, m_techniqueToProgram.getSizeInBytes());
  98. }
  99. MaterialResource::~MaterialResource()
  100. {
  101. ResourceMemoryPool::getSingleton().free(m_prefilledLocalUniforms);
  102. }
  103. const MaterialVariable* MaterialResource::tryFindVariableInternal(CString name) const
  104. {
  105. for(const MaterialVariable& v : m_vars)
  106. {
  107. if(v.m_name == name)
  108. {
  109. return &v;
  110. }
  111. }
  112. return nullptr;
  113. }
  114. Error MaterialResource::load(const ResourceFilename& filename, Bool async)
  115. {
  116. ResourceXmlDocument doc;
  117. XmlElement el;
  118. ANKI_CHECK(openFileParseXml(filename, doc));
  119. // <material>
  120. XmlElement rootEl;
  121. ANKI_CHECK(doc.getChildElement("material", rootEl));
  122. // <shaderPrograms>
  123. XmlElement shaderProgramsEl;
  124. ANKI_CHECK(rootEl.getChildElement("shaderPrograms", shaderProgramsEl));
  125. XmlElement shaderProgramEl;
  126. ANKI_CHECK(shaderProgramsEl.getChildElement("shaderProgram", shaderProgramEl));
  127. do
  128. {
  129. ANKI_CHECK(parseShaderProgram(shaderProgramEl, async));
  130. ANKI_CHECK(shaderProgramEl.getNextSiblingElement("shaderProgram", shaderProgramEl));
  131. } while(shaderProgramEl);
  132. ANKI_ASSERT(!!m_techniquesMask);
  133. // <inputs>
  134. BitSet<128> varsSet(false);
  135. ANKI_CHECK(rootEl.getChildElementOptional("inputs", el));
  136. if(el)
  137. {
  138. XmlElement inputEl;
  139. ANKI_CHECK(el.getChildElement("input", inputEl));
  140. do
  141. {
  142. ANKI_CHECK(parseInput(inputEl, async, varsSet));
  143. ANKI_CHECK(inputEl.getNextSiblingElement("input", inputEl));
  144. } while(inputEl);
  145. }
  146. if(varsSet.getSetBitCount() != m_vars.getSize())
  147. {
  148. ANKI_RESOURCE_LOGE("Forgot to set a default value in %u input variables", U32(m_vars.getSize() - varsSet.getSetBitCount()));
  149. return Error::kUserData;
  150. }
  151. prefillLocalUniforms();
  152. return Error::kNone;
  153. }
  154. Error MaterialResource::parseShaderProgram(XmlElement shaderProgramEl, Bool async)
  155. {
  156. // name
  157. CString shaderName;
  158. ANKI_CHECK(shaderProgramEl.getAttributeText("name", shaderName));
  159. if(!GrManager::getSingleton().getDeviceCapabilities().m_rayTracingEnabled && shaderName.find("Rt") == 0)
  160. {
  161. // Skip RT programs when RT is disabled
  162. return Error::kNone;
  163. }
  164. ResourceString fname;
  165. fname.sprintf("ShaderBinaries/%s.ankiprogbin", shaderName.cstr());
  166. Program& prog = *m_programs.emplaceBack();
  167. ANKI_CHECK(ResourceManager::getSingleton().loadResource(fname, prog.m_prog, async));
  168. // <mutation>
  169. XmlElement mutatorsEl;
  170. ANKI_CHECK(shaderProgramEl.getChildElementOptional("mutation", mutatorsEl));
  171. if(mutatorsEl)
  172. {
  173. ANKI_CHECK(parseMutators(mutatorsEl, prog));
  174. }
  175. // And find the builtin mutators
  176. ANKI_CHECK(findBuiltinMutators(prog));
  177. // Create the vars
  178. ANKI_CHECK(createVars(prog));
  179. return Error::kNone;
  180. }
  181. Error MaterialResource::createVars(Program& prog)
  182. {
  183. const ShaderProgramBinary& binary = prog.m_prog->getBinary();
  184. // Find struct
  185. const ShaderProgramBinaryStruct* localUniformsStruct = nullptr;
  186. for(const ShaderProgramBinaryStruct& strct : binary.m_structs)
  187. {
  188. if(CString(strct.m_name.getBegin()) == "AnKiLocalConstants")
  189. {
  190. localUniformsStruct = &strct;
  191. break;
  192. }
  193. ++prog.m_localUniformsStructIdx;
  194. }
  195. if(localUniformsStruct == nullptr)
  196. {
  197. prog.m_localUniformsStructIdx = kMaxU32;
  198. }
  199. // Iterate all members of the local uniforms struct to add its members
  200. U32 offsetof = 0;
  201. for(U32 i = 0; localUniformsStruct && i < localUniformsStruct->m_members.getSize(); ++i)
  202. {
  203. const ShaderProgramBinaryStructMember& member = localUniformsStruct->m_members[i];
  204. const CString memberName = member.m_name.getBegin();
  205. // Check if it needs to be added
  206. Bool addIt = false;
  207. if(member.m_dependentMutator == kMaxU32)
  208. {
  209. addIt = true;
  210. }
  211. else
  212. {
  213. Bool found = false;
  214. for(const PartialMutation& m : prog.m_partialMutation)
  215. {
  216. if(m.m_mutator->m_name == binary.m_mutators[member.m_dependentMutator].m_name.getBegin())
  217. {
  218. if(m.m_value == member.m_dependentMutatorValue)
  219. {
  220. addIt = true;
  221. }
  222. found = true;
  223. break;
  224. }
  225. }
  226. if(!found)
  227. {
  228. ANKI_RESOURCE_LOGE("Incorrect combination of member variable %s and dependent mutator %s", memberName.cstr(),
  229. binary.m_mutators[member.m_dependentMutator].m_name.getBegin());
  230. return Error::kUserData;
  231. }
  232. }
  233. if(addIt)
  234. {
  235. MaterialVariable* var = tryFindVariable(memberName);
  236. if(var)
  237. {
  238. if(var->m_dataType != member.m_type || var->m_offsetInLocalUniforms != offsetof)
  239. {
  240. ANKI_RESOURCE_LOGE("Member variable doesn't match between techniques: %s", memberName.cstr());
  241. return Error::kUserData;
  242. }
  243. }
  244. else
  245. {
  246. // Check that there are no other vars that overlap with the current var. This could happen if
  247. // different programs have different signature for AnKiLocalConstants
  248. for(const MaterialVariable& otherVar : m_vars)
  249. {
  250. if(!otherVar.isUniform())
  251. {
  252. continue;
  253. }
  254. const U32 aVarOffset = otherVar.m_offsetInLocalUniforms;
  255. const U32 aVarEnd = aVarOffset + getShaderVariableDataTypeInfo(otherVar.m_dataType).m_size;
  256. const U32 bVarOffset = offsetof;
  257. const U32 bVarEnd = bVarOffset + getShaderVariableDataTypeInfo(member.m_type).m_size;
  258. if((aVarOffset <= bVarOffset && aVarEnd > bVarOffset) || (bVarOffset <= aVarOffset && bVarEnd > aVarOffset))
  259. {
  260. ANKI_RESOURCE_LOGE("Member %s in AnKiLocalConstants overlaps with %s. Check your shaders", memberName.cstr(),
  261. otherVar.m_name.cstr());
  262. return Error::kUserData;
  263. }
  264. }
  265. // All good, add it
  266. var = m_vars.emplaceBack();
  267. var->m_name = memberName;
  268. var->m_offsetInLocalUniforms = offsetof;
  269. var->m_dataType = member.m_type;
  270. offsetof += getShaderVariableDataTypeInfo(member.m_type).m_size;
  271. }
  272. }
  273. }
  274. m_localUniformsSize = max(offsetof, m_localUniformsSize);
  275. // Iterate all variants of builtin mutators to gather the opaques
  276. ShaderProgramResourceVariantInitInfo initInfo(prog.m_prog);
  277. for(const PartialMutation& m : prog.m_partialMutation)
  278. {
  279. initInfo.addMutation(m.m_mutator->m_name, m.m_value);
  280. }
  281. Array<const ShaderProgramResourceMutator*, U(BuiltinMutatorId::kCount)> mutatorPtrs = {};
  282. for(BuiltinMutatorId id : EnumIterable<BuiltinMutatorId>())
  283. {
  284. mutatorPtrs[id] = prog.m_prog->tryFindMutator(kBuiltinMutatorNames[id]);
  285. }
  286. #define ANKI_LOOP(builtIn) \
  287. for(U32 i = 0; i < ((mutatorPtrs[BuiltinMutatorId::builtIn]) ? mutatorPtrs[BuiltinMutatorId::builtIn]->m_values.getSize() : 1); ++i) \
  288. { \
  289. if(mutatorPtrs[BuiltinMutatorId::builtIn]) \
  290. { \
  291. initInfo.addMutation(mutatorPtrs[BuiltinMutatorId::builtIn]->m_name, mutatorPtrs[BuiltinMutatorId::builtIn]->m_values[i]); \
  292. }
  293. #define ANKI_LOOP_END() }
  294. ANKI_LOOP(kTechnique)
  295. ANKI_LOOP(kBones)
  296. ANKI_LOOP(kVelocity)
  297. {
  298. const ShaderProgramResourceVariant* variant;
  299. prog.m_prog->getOrCreateVariant(initInfo, variant);
  300. if(!variant)
  301. {
  302. // Skipped variant
  303. continue;
  304. }
  305. // Add opaque vars
  306. for(const ShaderProgramBinaryOpaqueInstance& instance : variant->getBinaryVariant().m_opaques)
  307. {
  308. const ShaderProgramBinaryOpaque& opaque = binary.m_opaques[instance.m_index];
  309. if(opaque.m_type == ShaderVariableDataType::kSampler)
  310. {
  311. continue;
  312. }
  313. const CString opaqueName = opaque.m_name.getBegin();
  314. MaterialVariable* var = tryFindVariable(opaqueName);
  315. if(var)
  316. {
  317. if(var->m_dataType != opaque.m_type || var->m_opaqueBinding != opaque.m_binding)
  318. {
  319. ANKI_RESOURCE_LOGE("Opaque variable doesn't match between techniques: %s", opaqueName.cstr());
  320. return Error::kUserData;
  321. }
  322. }
  323. else
  324. {
  325. // Check that there are no other opaque with the same binding
  326. for(const MaterialVariable& otherVar : m_vars)
  327. {
  328. if(!otherVar.isBoundableTexture())
  329. {
  330. continue;
  331. }
  332. if(otherVar.m_opaqueBinding == opaque.m_binding)
  333. {
  334. ANKI_RESOURCE_LOGE("Opaque variable %s has the same binding as %s. Check your shaders", otherVar.m_name.cstr(),
  335. opaqueName.cstr());
  336. return Error::kUserData;
  337. }
  338. }
  339. // All good, add it
  340. var = m_vars.emplaceBack();
  341. var->m_name = opaqueName;
  342. var->m_opaqueBinding = opaque.m_binding;
  343. var->m_dataType = opaque.m_type;
  344. }
  345. }
  346. }
  347. ANKI_LOOP_END()
  348. ANKI_LOOP_END()
  349. ANKI_LOOP_END()
  350. #undef ANKI_LOOP
  351. #undef ANKI_LOOP_END
  352. return Error::kNone;
  353. }
  354. Error MaterialResource::parseMutators(XmlElement mutatorsEl, Program& prog)
  355. {
  356. XmlElement mutatorEl;
  357. ANKI_CHECK(mutatorsEl.getChildElement("mutator", mutatorEl));
  358. U32 mutatorCount = 0;
  359. ANKI_CHECK(mutatorEl.getSiblingElementsCount(mutatorCount));
  360. ++mutatorCount;
  361. ANKI_ASSERT(mutatorCount > 0);
  362. prog.m_partialMutation.resize(mutatorCount);
  363. mutatorCount = 0;
  364. do
  365. {
  366. PartialMutation& pmutation = prog.m_partialMutation[mutatorCount];
  367. // name
  368. CString mutatorName;
  369. ANKI_CHECK(mutatorEl.getAttributeText("name", mutatorName));
  370. if(mutatorName.isEmpty())
  371. {
  372. ANKI_RESOURCE_LOGE("Mutator name is empty");
  373. return Error::kUserData;
  374. }
  375. for(BuiltinMutatorId id : EnumIterable<BuiltinMutatorId>())
  376. {
  377. if(id == BuiltinMutatorId::kNone)
  378. {
  379. continue;
  380. }
  381. if(mutatorName == kBuiltinMutatorNames[id])
  382. {
  383. ANKI_RESOURCE_LOGE("Materials shouldn't list builtin mutators: %s", mutatorName.cstr());
  384. return Error::kUserData;
  385. }
  386. }
  387. if(mutatorName.find("ANKI_") == 0)
  388. {
  389. ANKI_RESOURCE_LOGE("Mutators can't start with ANKI_: %s", mutatorName.cstr());
  390. return Error::kUserData;
  391. }
  392. // value
  393. ANKI_CHECK(mutatorEl.getAttributeNumber("value", pmutation.m_value));
  394. // Find mutator
  395. pmutation.m_mutator = prog.m_prog->tryFindMutator(mutatorName);
  396. if(!pmutation.m_mutator)
  397. {
  398. ANKI_RESOURCE_LOGE("Mutator not found in program %s", &mutatorName[0]);
  399. return Error::kUserData;
  400. }
  401. if(!pmutation.m_mutator->valueExists(pmutation.m_value))
  402. {
  403. ANKI_RESOURCE_LOGE("Value %d is not part of the mutator %s", pmutation.m_value, mutatorName.cstr());
  404. return Error::kUserData;
  405. }
  406. // Advance
  407. ++mutatorCount;
  408. ANKI_CHECK(mutatorEl.getNextSiblingElement("mutator", mutatorEl));
  409. } while(mutatorEl);
  410. ANKI_ASSERT(mutatorCount == prog.m_partialMutation.getSize());
  411. return Error::kNone;
  412. }
  413. Error MaterialResource::findBuiltinMutators(Program& prog)
  414. {
  415. U builtinMutatorCount = 0;
  416. // ANKI_TECHNIQUE
  417. CString techniqueMutatorName = kBuiltinMutatorNames[BuiltinMutatorId::kTechnique];
  418. const ShaderProgramResourceMutator* techniqueMutator = prog.m_prog->tryFindMutator(techniqueMutatorName);
  419. if(techniqueMutator)
  420. {
  421. for(U32 i = 0; i < techniqueMutator->m_values.getSize(); ++i)
  422. {
  423. const MutatorValue mvalue = techniqueMutator->m_values[i];
  424. if(mvalue >= MutatorValue(RenderingTechnique::kCount) || mvalue < MutatorValue(RenderingTechnique::kFirst))
  425. {
  426. ANKI_RESOURCE_LOGE("Mutator %s has a wrong value %d", techniqueMutatorName.cstr(), mvalue);
  427. return Error::kUserData;
  428. }
  429. const RenderingTechnique techniqueId = RenderingTechnique(mvalue);
  430. const PtrSize progIdx = &prog - m_programs.getBegin();
  431. ANKI_ASSERT(progIdx < m_programs.getSize());
  432. m_techniqueToProgram[techniqueId] = U8(progIdx);
  433. const RenderingTechniqueBit mask = RenderingTechniqueBit(1 << techniqueId);
  434. if(!!(m_techniquesMask & mask))
  435. {
  436. ANKI_RESOURCE_LOGE("The %s technique appeared more than once", kTechniqueNames[mvalue].cstr());
  437. return Error::kUserData;
  438. }
  439. m_techniquesMask |= mask;
  440. }
  441. ++builtinMutatorCount;
  442. prog.m_presentBuildinMutators |= U32(1 << BuiltinMutatorId::kTechnique);
  443. }
  444. else
  445. {
  446. ANKI_RESOURCE_LOGE("Mutator %s should be present in every shader program referenced by a material", techniqueMutatorName.cstr());
  447. return Error::kUserData;
  448. }
  449. // ANKI_BONES
  450. CString bonesMutatorName = kBuiltinMutatorNames[BuiltinMutatorId::kBones];
  451. const ShaderProgramResourceMutator* bonesMutator = prog.m_prog->tryFindMutator(bonesMutatorName);
  452. if(bonesMutator)
  453. {
  454. if(bonesMutator->m_values.getSize() != 2)
  455. {
  456. ANKI_RESOURCE_LOGE("Mutator %s should have 2 values in the program", bonesMutatorName.cstr());
  457. return Error::kUserData;
  458. }
  459. for(U32 i = 0; i < bonesMutator->m_values.getSize(); ++i)
  460. {
  461. if(bonesMutator->m_values[i] != MutatorValue(i))
  462. {
  463. ANKI_RESOURCE_LOGE("Values of the %s mutator in the program are not the expected", bonesMutatorName.cstr());
  464. return Error::kUserData;
  465. }
  466. }
  467. ++builtinMutatorCount;
  468. m_supportsSkinning = true;
  469. prog.m_presentBuildinMutators |= U32(1 << BuiltinMutatorId::kBones);
  470. }
  471. // VELOCITY
  472. CString velocityMutatorName = kBuiltinMutatorNames[BuiltinMutatorId::kVelocity];
  473. const ShaderProgramResourceMutator* velocityMutator = prog.m_prog->tryFindMutator(velocityMutatorName);
  474. if(velocityMutator)
  475. {
  476. if(velocityMutator->m_values.getSize() != 2)
  477. {
  478. ANKI_RESOURCE_LOGE("Mutator %s should have 2 values in the program", velocityMutatorName.cstr());
  479. return Error::kUserData;
  480. }
  481. for(U32 i = 0; i < velocityMutator->m_values.getSize(); ++i)
  482. {
  483. if(velocityMutator->m_values[i] != MutatorValue(i))
  484. {
  485. ANKI_RESOURCE_LOGE("Values of the %s mutator in the program are not the expected", velocityMutatorName.cstr());
  486. return Error::kUserData;
  487. }
  488. }
  489. ++builtinMutatorCount;
  490. prog.m_presentBuildinMutators |= U32(1 << BuiltinMutatorId::kVelocity);
  491. }
  492. if(prog.m_partialMutation.getSize() + builtinMutatorCount != prog.m_prog->getMutators().getSize())
  493. {
  494. ANKI_RESOURCE_LOGE("Some mutatators are unacounted for");
  495. return Error::kUserData;
  496. }
  497. return Error::kNone;
  498. }
  499. Error MaterialResource::parseInput(XmlElement inputEl, Bool async, BitSet<128>& varsSet)
  500. {
  501. // Get var name
  502. CString varName;
  503. ANKI_CHECK(inputEl.getAttributeText("name", varName));
  504. // Try find var
  505. MaterialVariable* foundVar = tryFindVariable(varName);
  506. if(!foundVar)
  507. {
  508. ANKI_RESOURCE_LOGE("Input name is wrong, variable not found: %s", varName.cstr());
  509. return Error::kUserData;
  510. }
  511. // Set check
  512. const U32 idx = U32(foundVar - m_vars.getBegin());
  513. if(varsSet.get(idx))
  514. {
  515. ANKI_RESOURCE_LOGE("Input already has a value: %s", varName.cstr());
  516. return Error::kUserData;
  517. }
  518. varsSet.set(idx);
  519. // Set the value
  520. if(foundVar->isBoundableTexture())
  521. {
  522. CString texfname;
  523. ANKI_CHECK(inputEl.getAttributeText("value", texfname));
  524. ANKI_CHECK(ResourceManager::getSingleton().loadResource(texfname, foundVar->m_image, async));
  525. m_textures.emplaceBack(&foundVar->m_image->getTexture());
  526. }
  527. else if(foundVar->m_dataType == ShaderVariableDataType::kU32)
  528. {
  529. // U32 is a bit special. It might be a number or a bindless texture
  530. CString value;
  531. ANKI_CHECK(inputEl.getAttributeText("value", value));
  532. // Check if the value has letters
  533. Bool containsAlpharithmetic = false;
  534. for(Char c : value)
  535. {
  536. if((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'a'))
  537. {
  538. containsAlpharithmetic = true;
  539. break;
  540. }
  541. }
  542. // If it has letters it's a texture
  543. if(containsAlpharithmetic)
  544. {
  545. ANKI_CHECK(ResourceManager::getSingleton().loadResource(value, foundVar->m_image, async));
  546. foundVar->m_U32 = foundVar->m_image->getTextureView().getOrCreateBindlessTextureIndex();
  547. }
  548. else
  549. {
  550. ANKI_CHECK(GetAttribute<U32>()(inputEl, foundVar->m_U32));
  551. }
  552. }
  553. else
  554. {
  555. switch(foundVar->m_dataType)
  556. {
  557. #define ANKI_SVDT_MACRO(type, baseType, rowCount, columnCount, isIntagralType) \
  558. case ShaderVariableDataType::k##type: \
  559. ANKI_CHECK(GetAttribute<type>()(inputEl, foundVar->ANKI_CONCATENATE(m_, type))); \
  560. break;
  561. #include <AnKi/Gr/ShaderVariableDataType.defs.h>
  562. #undef ANKI_SVDT_MACRO
  563. default:
  564. ANKI_ASSERT(0);
  565. break;
  566. }
  567. }
  568. return Error::kNone;
  569. }
  570. void MaterialResource::prefillLocalUniforms()
  571. {
  572. if(m_localUniformsSize == 0)
  573. {
  574. return;
  575. }
  576. m_prefilledLocalUniforms = ResourceMemoryPool::getSingleton().allocate(m_localUniformsSize, 1);
  577. memset(m_prefilledLocalUniforms, 0, m_localUniformsSize);
  578. for(const MaterialVariable& var : m_vars)
  579. {
  580. if(!var.isUniform())
  581. {
  582. continue;
  583. }
  584. switch(var.m_dataType)
  585. {
  586. #define ANKI_SVDT_MACRO(type, baseType, rowCount, columnCount, isIntagralType) \
  587. case ShaderVariableDataType::k##type: \
  588. ANKI_ASSERT(var.m_offsetInLocalUniforms + sizeof(type) <= m_localUniformsSize); \
  589. memcpy(static_cast<U8*>(m_prefilledLocalUniforms) + var.m_offsetInLocalUniforms, &var.m_##type, sizeof(type)); \
  590. break;
  591. #include <AnKi/Gr/ShaderVariableDataType.defs.h>
  592. #undef ANKI_SVDT_MACRO
  593. default:
  594. ANKI_ASSERT(0);
  595. break;
  596. }
  597. }
  598. }
  599. const MaterialVariant& MaterialResource::getOrCreateVariant(const RenderingKey& key_) const
  600. {
  601. RenderingKey key = key_;
  602. ANKI_ASSERT(m_techniqueToProgram[key.getRenderingTechnique()] != kMaxU8);
  603. const Program& prog = m_programs[m_techniqueToProgram[key.getRenderingTechnique()]];
  604. // Sanitize the key
  605. if(!(prog.m_presentBuildinMutators & U32(BuiltinMutatorId::kVelocity)) && key.getVelocity())
  606. {
  607. // Particles set their own velocity
  608. key.setVelocity(false);
  609. }
  610. if(key.getRenderingTechnique() != RenderingTechnique::kGBuffer && key.getVelocity())
  611. {
  612. // Only GBuffer technique can write to velocity buffers
  613. key.setVelocity(false);
  614. }
  615. if(!GrManager::getSingleton().getDeviceCapabilities().m_meshShaders)
  616. {
  617. key.setMeshShaders(false);
  618. }
  619. ANKI_ASSERT(!key.getSkinned() || !!(prog.m_presentBuildinMutators & U32(1 << BuiltinMutatorId::kBones)));
  620. ANKI_ASSERT(!key.getVelocity() || !!(prog.m_presentBuildinMutators & U32(1 << BuiltinMutatorId::kVelocity)));
  621. MaterialVariant& variant = prog.m_variantMatrix[key.getRenderingTechnique()][key.getSkinned()][key.getVelocity()][key.getMeshShaders()];
  622. // Check if it's initialized
  623. {
  624. RLockGuard<RWMutex> lock(prog.m_variantMatrixMtx);
  625. if(variant.m_prog.isCreated()) [[likely]]
  626. {
  627. ANKI_ASSERT(key.getMeshShaders() == !!(variant.m_prog->getShaderTypes() & ShaderTypeBit::kAllModernGeometry));
  628. return variant;
  629. }
  630. }
  631. // Not initialized, init it
  632. WLockGuard<RWMutex> lock(prog.m_variantMatrixMtx);
  633. // Check again
  634. if(variant.m_prog.isCreated())
  635. {
  636. return variant;
  637. }
  638. ShaderProgramResourceVariantInitInfo initInfo(prog.m_prog);
  639. for(const PartialMutation& m : prog.m_partialMutation)
  640. {
  641. initInfo.addMutation(m.m_mutator->m_name, m.m_value);
  642. }
  643. initInfo.addMutation(kBuiltinMutatorNames[BuiltinMutatorId::kTechnique], MutatorValue(key.getRenderingTechnique()));
  644. if(!!(prog.m_presentBuildinMutators & U32(1 << BuiltinMutatorId::kBones)))
  645. {
  646. initInfo.addMutation(kBuiltinMutatorNames[BuiltinMutatorId::kBones], MutatorValue(key.getSkinned()));
  647. }
  648. if(!!(prog.m_presentBuildinMutators & U32(1 << BuiltinMutatorId::kVelocity)))
  649. {
  650. initInfo.addMutation(kBuiltinMutatorNames[BuiltinMutatorId::kVelocity], MutatorValue(key.getVelocity()));
  651. }
  652. initInfo.requestMeshShaders(key.getMeshShaders());
  653. const ShaderProgramResourceVariant* progVariant = nullptr;
  654. prog.m_prog->getOrCreateVariant(initInfo, progVariant);
  655. if(!progVariant)
  656. {
  657. ANKI_RESOURCE_LOGF("Fetched skipped mutation on program %s", getFilename().cstr());
  658. }
  659. variant.m_prog.reset(&progVariant->getProgram());
  660. ANKI_ASSERT(key.getMeshShaders() == !!(variant.m_prog->getShaderTypes() & ShaderTypeBit::kAllModernGeometry));
  661. if(!!(RenderingTechniqueBit(1 << key.getRenderingTechnique()) & RenderingTechniqueBit::kAllRt))
  662. {
  663. variant.m_rtShaderGroupHandleIndex = progVariant->getShaderGroupHandleIndex();
  664. }
  665. return variant;
  666. }
  667. } // end namespace anki