MaterialResource.cpp 21 KB

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