MaterialResource.cpp 21 KB

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