MaterialResource.cpp 23 KB

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