MaterialResource.cpp 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242
  1. // Copyright (C) 2009-2020, 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/TextureResource.h>
  8. #include <anki/util/Xml.h>
  9. namespace anki
  10. {
  11. static const Array<CString, U32(BuiltinMutatorId::COUNT)> BUILTIN_MUTATOR_NAMES = {
  12. {"NONE", "ANKI_INSTANCE_COUNT", "ANKI_PASS", "ANKI_LOD", "ANKI_BONES", "ANKI_VELOCITY"}};
  13. class BuiltinVarInfo
  14. {
  15. public:
  16. const char* m_name;
  17. ShaderVariableDataType m_type;
  18. Bool m_instanced;
  19. };
  20. static const Array<BuiltinVarInfo, U(BuiltinMaterialVariableId::COUNT)> BUILTIN_INFOS = {
  21. {{"NONE", ShaderVariableDataType::NONE, false},
  22. {"m_ankiMvp", ShaderVariableDataType::MAT4, true},
  23. {"m_ankiPreviousMvp", ShaderVariableDataType::MAT4, true},
  24. {"m_ankiModelMatrix", ShaderVariableDataType::MAT4, true},
  25. {"m_ankiViewMatrix", ShaderVariableDataType::MAT4, false},
  26. {"m_ankiProjectionMatrix", ShaderVariableDataType::MAT4, false},
  27. {"m_ankiModelViewMatrix", ShaderVariableDataType::MAT4, true},
  28. {"m_ankiViewProjectionMatrix", ShaderVariableDataType::MAT4, false},
  29. {"m_ankiNormalMatrix", ShaderVariableDataType::MAT3, true},
  30. {"m_ankiRotationMatrix", ShaderVariableDataType::MAT3, true},
  31. {"m_ankiCameraRotationMatrix", ShaderVariableDataType::MAT3, false},
  32. {"m_ankiCameraPosition", ShaderVariableDataType::VEC3, false},
  33. {"u_ankiGlobalSampler", ShaderVariableDataType::SAMPLER, false}}};
  34. static ANKI_USE_RESULT Error checkBuiltin(CString name, ShaderVariableDataType dataType, Bool instanced,
  35. BuiltinMaterialVariableId& outId)
  36. {
  37. outId = BuiltinMaterialVariableId::NONE;
  38. for(BuiltinMaterialVariableId id : EnumIterable<BuiltinMaterialVariableId>())
  39. {
  40. if(id == BuiltinMaterialVariableId::NONE)
  41. {
  42. continue;
  43. }
  44. if(BUILTIN_INFOS[id].m_name == name)
  45. {
  46. outId = id;
  47. if(BUILTIN_INFOS[id].m_type != dataType)
  48. {
  49. ANKI_RESOURCE_LOGE("Incorect type for builtin: %s", name.cstr());
  50. return Error::USER_DATA;
  51. }
  52. if(instanced && !BUILTIN_INFOS[id].m_instanced)
  53. {
  54. ANKI_RESOURCE_LOGE("Variable %s be instanced: %s",
  55. (BUILTIN_INFOS[id].m_instanced) ? "should" : "shouldn't", name.cstr());
  56. return Error::USER_DATA;
  57. }
  58. break;
  59. }
  60. }
  61. if(outId == BuiltinMaterialVariableId::NONE && (name.find("m_anki") == 0 || name.find("u_anki") == 0))
  62. {
  63. ANKI_RESOURCE_LOGE("Unknown builtin var: %s", name.cstr());
  64. return Error::USER_DATA;
  65. }
  66. return Error::NONE;
  67. }
  68. // This is some trickery to select calling between XmlElement::getAttributeNumber and XmlElement::getAttributeNumbers
  69. namespace
  70. {
  71. template<typename T>
  72. class IsShaderVarDataTypeAnArray
  73. {
  74. public:
  75. static constexpr Bool VALUE = false;
  76. };
  77. #define ANKI_SVDT_MACRO(capital, type, baseType, rowCount, columnCount) \
  78. template<> \
  79. class IsShaderVarDataTypeAnArray<type> \
  80. { \
  81. public: \
  82. static constexpr Bool VALUE = rowCount * columnCount > 1; \
  83. };
  84. #include <anki/gr/ShaderVariableDataTypeDefs.h>
  85. #undef ANKI_SVDT_MACRO
  86. template<typename T, Bool isArray = IsShaderVarDataTypeAnArray<T>::VALUE>
  87. class GetAttribute
  88. {
  89. public:
  90. Error operator()(const XmlElement& el, T& out)
  91. {
  92. return el.getAttributeNumbers("value", out);
  93. }
  94. };
  95. template<typename T>
  96. class GetAttribute<T, false>
  97. {
  98. public:
  99. Error operator()(const XmlElement& el, T& out)
  100. {
  101. return el.getAttributeNumber("value", out);
  102. }
  103. };
  104. } // namespace
  105. class GpuMaterialTexture
  106. {
  107. public:
  108. const char* m_name;
  109. U32 m_textureSlot;
  110. };
  111. static const Array<GpuMaterialTexture, TEXTURE_CHANNEL_COUNT> GPU_MATERIAL_TEXTURES = {
  112. {{"TEXTURE_CHANNEL_DIFFUSE", TEXTURE_CHANNEL_DIFFUSE},
  113. {"TEXTURE_CHANNEL_NORMAL", TEXTURE_CHANNEL_NORMAL},
  114. {"TEXTURE_CHANNEL_ROUGHNESS_METALNESS", TEXTURE_CHANNEL_ROUGHNESS_METALNESS},
  115. {"TEXTURE_CHANNEL_EMISSION", TEXTURE_CHANNEL_EMISSION},
  116. {"TEXTURE_CHANNEL_HEIGHT", TEXTURE_CHANNEL_HEIGHT},
  117. {"TEXTURE_CHANNEL_AUX_0", TEXTURE_CHANNEL_AUX_0},
  118. {"TEXTURE_CHANNEL_AUX_1", TEXTURE_CHANNEL_AUX_1},
  119. {"TEXTURE_CHANNEL_AUX_2", TEXTURE_CHANNEL_AUX_2}}};
  120. class GpuMaterialFloats
  121. {
  122. public:
  123. const char* m_name;
  124. U32 m_offsetof;
  125. U32 m_floatCount;
  126. };
  127. static const Array<GpuMaterialFloats, 5> GPU_MATERIAL_FLOATS = {
  128. {{"diffuseColor", offsetof(MaterialGpuDescriptor, m_diffuseColor), 3},
  129. {"specularColor", offsetof(MaterialGpuDescriptor, m_specularColor), 3},
  130. {"emissiveColor", offsetof(MaterialGpuDescriptor, m_emissiveColor), 3},
  131. {"roughness", offsetof(MaterialGpuDescriptor, m_roughness), 1},
  132. {"metalness", offsetof(MaterialGpuDescriptor, m_metalness), 1}}};
  133. MaterialVariable::MaterialVariable()
  134. {
  135. m_Mat4 = Mat4::getZero();
  136. }
  137. MaterialVariable::~MaterialVariable()
  138. {
  139. }
  140. MaterialResource::MaterialResource(ResourceManager* manager)
  141. : ResourceObject(manager)
  142. {
  143. memset(&m_materialGpuDescriptor, 0, sizeof(m_materialGpuDescriptor));
  144. }
  145. MaterialResource::~MaterialResource()
  146. {
  147. for(Pass p : EnumIterable<Pass>())
  148. {
  149. for(U32 l = 0; l < MAX_LOD_COUNT; ++l)
  150. {
  151. for(U32 inst = 0; inst < MAX_INSTANCE_GROUPS; ++inst)
  152. {
  153. for(U32 skinned = 0; skinned <= 1; ++skinned)
  154. {
  155. for(U32 vel = 0; vel <= 1; ++vel)
  156. {
  157. MaterialVariant& variant = m_variantMatrix[p][l][inst][skinned][vel];
  158. variant.m_blockInfos.destroy(getAllocator());
  159. variant.m_opaqueBindings.destroy(getAllocator());
  160. }
  161. }
  162. }
  163. }
  164. }
  165. for(MaterialVariable& var : m_vars)
  166. {
  167. var.m_name.destroy(getAllocator());
  168. }
  169. m_vars.destroy(getAllocator());
  170. m_nonBuiltinsMutation.destroy(getAllocator());
  171. }
  172. Error MaterialResource::load(const ResourceFilename& filename, Bool async)
  173. {
  174. XmlDocument doc;
  175. XmlElement el;
  176. Bool present = false;
  177. ANKI_CHECK(openFileParseXml(filename, doc));
  178. // <material>
  179. XmlElement rootEl;
  180. ANKI_CHECK(doc.getChildElement("material", rootEl));
  181. // shaderProgram
  182. CString fname;
  183. ANKI_CHECK(rootEl.getAttributeText("shaderProgram", fname));
  184. ANKI_CHECK(getManager().loadResource(fname, m_prog, async));
  185. // Good time to create the vars
  186. ANKI_CHECK(createVars());
  187. // shadow
  188. ANKI_CHECK(rootEl.getAttributeNumberOptional("shadow", m_shadow, present));
  189. m_shadow = m_shadow != 0;
  190. // forwardShading
  191. ANKI_CHECK(rootEl.getAttributeNumberOptional("forwardShading", m_forwardShading, present));
  192. m_forwardShading = m_forwardShading != 0;
  193. // <mutation>
  194. XmlElement mutatorsEl;
  195. ANKI_CHECK(rootEl.getChildElementOptional("mutation", mutatorsEl));
  196. if(mutatorsEl)
  197. {
  198. ANKI_CHECK(parseMutators(mutatorsEl));
  199. }
  200. // The rest of the mutators
  201. ANKI_CHECK(findBuiltinMutators());
  202. // <inputs>
  203. ANKI_CHECK(rootEl.getChildElementOptional("inputs", el));
  204. if(el)
  205. {
  206. ANKI_CHECK(parseInputs(el, async));
  207. }
  208. // <rtMaterial>
  209. XmlElement rtMaterialEl;
  210. ANKI_CHECK(doc.getChildElementOptional("rtMaterial", rtMaterialEl));
  211. if(rtMaterialEl && getManager().getGrManager().getDeviceCapabilities().m_rayTracingEnabled)
  212. {
  213. ANKI_CHECK(parseRtMaterial(rtMaterialEl));
  214. }
  215. return Error::NONE;
  216. }
  217. Error MaterialResource::parseMutators(XmlElement mutatorsEl)
  218. {
  219. XmlElement mutatorEl;
  220. ANKI_CHECK(mutatorsEl.getChildElement("mutator", mutatorEl));
  221. //
  222. // Process the non-builtin mutators
  223. //
  224. U32 mutatorCount = 0;
  225. ANKI_CHECK(mutatorEl.getSiblingElementsCount(mutatorCount));
  226. ++mutatorCount;
  227. ANKI_ASSERT(mutatorCount > 0);
  228. m_nonBuiltinsMutation.create(getAllocator(), mutatorCount);
  229. mutatorCount = 0;
  230. do
  231. {
  232. SubMutation& smutation = m_nonBuiltinsMutation[mutatorCount];
  233. // name
  234. CString mutatorName;
  235. ANKI_CHECK(mutatorEl.getAttributeText("name", mutatorName));
  236. if(mutatorName.isEmpty())
  237. {
  238. ANKI_RESOURCE_LOGE("Mutator name is empty");
  239. return Error::USER_DATA;
  240. }
  241. for(BuiltinMutatorId id : EnumIterable<BuiltinMutatorId>())
  242. {
  243. if(id == BuiltinMutatorId::NONE)
  244. {
  245. continue;
  246. }
  247. if(mutatorName == BUILTIN_MUTATOR_NAMES[id])
  248. {
  249. ANKI_RESOURCE_LOGE("Cannot list builtin mutator: %s", mutatorName.cstr());
  250. return Error::USER_DATA;
  251. }
  252. }
  253. if(mutatorName.find("ANKI_") == 0)
  254. {
  255. ANKI_RESOURCE_LOGE("Mutators can't start with ANKI_: %s", mutatorName.cstr());
  256. return Error::USER_DATA;
  257. }
  258. // value
  259. ANKI_CHECK(mutatorEl.getAttributeNumber("value", smutation.m_value));
  260. // Find mutator
  261. smutation.m_mutator = m_prog->tryFindMutator(mutatorName);
  262. if(!smutation.m_mutator)
  263. {
  264. ANKI_RESOURCE_LOGE("Mutator not found in program %s", &mutatorName[0]);
  265. return Error::USER_DATA;
  266. }
  267. if(!smutation.m_mutator->valueExists(smutation.m_value))
  268. {
  269. ANKI_RESOURCE_LOGE("Value %d is not part of the mutator %s", smutation.m_value, &mutatorName[0]);
  270. return Error::USER_DATA;
  271. }
  272. // Advance
  273. ++mutatorCount;
  274. ANKI_CHECK(mutatorEl.getNextSiblingElement("mutator", mutatorEl));
  275. } while(mutatorEl);
  276. ANKI_ASSERT(mutatorCount == m_nonBuiltinsMutation.getSize());
  277. return Error::NONE;
  278. }
  279. Error MaterialResource::findBuiltinMutators()
  280. {
  281. // INSTANCE_COUNT
  282. U builtinMutatorCount = 0;
  283. m_builtinMutators[BuiltinMutatorId::INSTANCE_COUNT] =
  284. m_prog->tryFindMutator(BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::INSTANCE_COUNT]);
  285. if(m_builtinMutators[BuiltinMutatorId::INSTANCE_COUNT])
  286. {
  287. if(m_builtinMutators[BuiltinMutatorId::INSTANCE_COUNT]->m_values.getSize() != MAX_INSTANCE_GROUPS)
  288. {
  289. ANKI_RESOURCE_LOGE("Mutator %s should have %u values in the program",
  290. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::INSTANCE_COUNT].cstr(), MAX_INSTANCE_GROUPS);
  291. return Error::USER_DATA;
  292. }
  293. for(U32 i = 0; i < MAX_INSTANCE_GROUPS; ++i)
  294. {
  295. if(m_builtinMutators[BuiltinMutatorId::INSTANCE_COUNT]->m_values[i] != (1 << i))
  296. {
  297. ANKI_RESOURCE_LOGE("Values of the %s mutator in the program are not the expected",
  298. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::INSTANCE_COUNT].cstr());
  299. return Error::USER_DATA;
  300. }
  301. }
  302. ++builtinMutatorCount;
  303. }
  304. // PASS
  305. m_builtinMutators[BuiltinMutatorId::PASS] = m_prog->tryFindMutator(BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::PASS]);
  306. if(m_builtinMutators[BuiltinMutatorId::PASS] && m_forwardShading)
  307. {
  308. ANKI_RESOURCE_LOGE("Mutator is not required for forward shading: %s",
  309. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::PASS].cstr());
  310. return Error::USER_DATA;
  311. }
  312. else if(!m_builtinMutators[BuiltinMutatorId::PASS] && !m_forwardShading)
  313. {
  314. ANKI_RESOURCE_LOGE("Mutator is required for opaque shading: %s",
  315. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::PASS].cstr());
  316. return Error::USER_DATA;
  317. }
  318. if(m_builtinMutators[BuiltinMutatorId::PASS])
  319. {
  320. if(m_builtinMutators[BuiltinMutatorId::PASS]->m_values.getSize() != U32(Pass::COUNT) - 1)
  321. {
  322. ANKI_RESOURCE_LOGE("Mutator %s should have %u values in the program",
  323. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::PASS].cstr(), U32(Pass::COUNT) - 1);
  324. return Error::USER_DATA;
  325. }
  326. U32 count = 0;
  327. for(Pass p : EnumIterable<Pass>())
  328. {
  329. if(p == Pass::FS)
  330. {
  331. continue;
  332. }
  333. if(m_builtinMutators[BuiltinMutatorId::PASS]->m_values[count++] != I(p))
  334. {
  335. ANKI_RESOURCE_LOGE("Values of the %s mutator in the program are not the expected",
  336. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::PASS].cstr());
  337. return Error::USER_DATA;
  338. }
  339. }
  340. ++builtinMutatorCount;
  341. }
  342. if(!m_forwardShading && !m_builtinMutators[BuiltinMutatorId::PASS])
  343. {
  344. ANKI_RESOURCE_LOGE("%s mutator is required", BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::PASS].cstr());
  345. return Error::USER_DATA;
  346. }
  347. // LOD
  348. m_builtinMutators[BuiltinMutatorId::LOD] = m_prog->tryFindMutator(BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::LOD]);
  349. if(m_builtinMutators[BuiltinMutatorId::LOD])
  350. {
  351. if(m_builtinMutators[BuiltinMutatorId::LOD]->m_values.getSize() > MAX_LOD_COUNT)
  352. {
  353. ANKI_RESOURCE_LOGE("Mutator %s should have at least %u values in the program",
  354. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::LOD].cstr(), U32(MAX_LOD_COUNT));
  355. return Error::USER_DATA;
  356. }
  357. for(U32 i = 0; i < m_builtinMutators[BuiltinMutatorId::LOD]->m_values.getSize(); ++i)
  358. {
  359. if(m_builtinMutators[BuiltinMutatorId::LOD]->m_values[i] != I(i))
  360. {
  361. ANKI_RESOURCE_LOGE("Values of the %s mutator in the program are not the expected",
  362. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::LOD].cstr());
  363. return Error::USER_DATA;
  364. }
  365. }
  366. m_lodCount = U8(m_builtinMutators[BuiltinMutatorId::LOD]->m_values.getSize());
  367. ++builtinMutatorCount;
  368. }
  369. // BONES
  370. m_builtinMutators[BuiltinMutatorId::BONES] = m_prog->tryFindMutator(BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::BONES]);
  371. if(m_builtinMutators[BuiltinMutatorId::BONES])
  372. {
  373. if(m_builtinMutators[BuiltinMutatorId::BONES]->m_values.getSize() != 2)
  374. {
  375. ANKI_RESOURCE_LOGE("Mutator %s should have 2 values in the program",
  376. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::BONES].cstr());
  377. return Error::USER_DATA;
  378. }
  379. for(U32 i = 0; i < m_builtinMutators[BuiltinMutatorId::BONES]->m_values.getSize(); ++i)
  380. {
  381. if(m_builtinMutators[BuiltinMutatorId::BONES]->m_values[i] != I(i))
  382. {
  383. ANKI_RESOURCE_LOGE("Values of the %s mutator in the program are not the expected",
  384. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::BONES].cstr());
  385. return Error::USER_DATA;
  386. }
  387. }
  388. ++builtinMutatorCount;
  389. // Find the binding of the transforms
  390. const ShaderProgramBinary& binary = m_prog->getBinary();
  391. for(const ShaderProgramBinaryBlock& block : binary.m_storageBlocks)
  392. {
  393. if(block.m_name.getBegin() == CString("b_ankiBoneTransforms"))
  394. {
  395. if(block.m_set != m_descriptorSetIdx)
  396. {
  397. ANKI_RESOURCE_LOGE("The set of b_ankiBoneTransforms should be %u", m_descriptorSetIdx);
  398. return Error::USER_DATA;
  399. }
  400. m_boneTrfsBinding = block.m_binding;
  401. }
  402. else if(block.m_name.getBegin() == CString("b_ankiPrevFrameBoneTransforms"))
  403. {
  404. if(block.m_set != m_descriptorSetIdx)
  405. {
  406. ANKI_RESOURCE_LOGE("The set of b_ankiPrevFrameBoneTransforms should be %u", m_descriptorSetIdx);
  407. return Error::USER_DATA;
  408. }
  409. m_prevFrameBoneTrfsBinding = block.m_binding;
  410. }
  411. }
  412. if(m_boneTrfsBinding == MAX_U32 || m_prevFrameBoneTrfsBinding == MAX_U32)
  413. {
  414. ANKI_RESOURCE_LOGE("The program is using the %s mutator but b_ankiBoneTransforms or "
  415. "b_ankiPrevFrameBoneTransforms was not found",
  416. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::BONES].cstr());
  417. return Error::NONE;
  418. }
  419. }
  420. // VELOCITY
  421. m_builtinMutators[BuiltinMutatorId::VELOCITY] =
  422. m_prog->tryFindMutator(BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::VELOCITY]);
  423. if(m_builtinMutators[BuiltinMutatorId::VELOCITY])
  424. {
  425. if(m_builtinMutators[BuiltinMutatorId::VELOCITY]->m_values.getSize() != 2)
  426. {
  427. ANKI_RESOURCE_LOGE("Mutator %s should have 2 values in the program",
  428. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::VELOCITY].cstr());
  429. return Error::USER_DATA;
  430. }
  431. for(U32 i = 0; i < m_builtinMutators[BuiltinMutatorId::VELOCITY]->m_values.getSize(); ++i)
  432. {
  433. if(m_builtinMutators[BuiltinMutatorId::VELOCITY]->m_values[i] != I(i))
  434. {
  435. ANKI_RESOURCE_LOGE("Values of the %s mutator in the program are not the expected",
  436. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::VELOCITY].cstr());
  437. return Error::USER_DATA;
  438. }
  439. }
  440. ++builtinMutatorCount;
  441. }
  442. if(m_nonBuiltinsMutation.getSize() + builtinMutatorCount != m_prog->getMutators().getSize())
  443. {
  444. ANKI_RESOURCE_LOGE("Some mutatators are unacounted for");
  445. return Error::USER_DATA;
  446. }
  447. return Error::NONE;
  448. }
  449. Error MaterialResource::parseVariable(CString fullVarName, Bool& instanced, U32& idx, CString& name)
  450. {
  451. idx = 0;
  452. if(fullVarName.find("u_ankiPerDraw") != CString::NPOS)
  453. {
  454. instanced = false;
  455. }
  456. else if(fullVarName.find("u_ankiPerInstance") != CString::NPOS)
  457. {
  458. instanced = true;
  459. }
  460. else
  461. {
  462. ANKI_RESOURCE_LOGE("Wrong variable name: %s", fullVarName.cstr());
  463. return Error::USER_DATA;
  464. }
  465. const PtrSize leftBracket = fullVarName.find("[");
  466. const PtrSize rightBracket = fullVarName.find("]");
  467. if(instanced)
  468. {
  469. const Bool correct =
  470. (leftBracket == CString::NPOS && rightBracket == CString::NPOS)
  471. || (leftBracket != CString::NPOS && rightBracket != CString::NPOS && rightBracket > leftBracket);
  472. if(!correct)
  473. {
  474. ANKI_RESOURCE_LOGE("Wrong variable name: %s", fullVarName.cstr());
  475. return Error::USER_DATA;
  476. }
  477. if(leftBracket != CString::NPOS)
  478. {
  479. Array<char, 8> idxStr = {};
  480. for(PtrSize i = leftBracket + 1; i < rightBracket; ++i)
  481. {
  482. idxStr[i - (leftBracket + 1)] = fullVarName[i];
  483. }
  484. ANKI_CHECK(CString(idxStr.getBegin()).toNumber(idx));
  485. }
  486. else
  487. {
  488. idx = 0;
  489. }
  490. }
  491. else
  492. {
  493. if(leftBracket != CString::NPOS || rightBracket != CString::NPOS)
  494. {
  495. ANKI_RESOURCE_LOGE("Can't support non instanced array variables: %s", fullVarName.cstr());
  496. return Error::USER_DATA;
  497. }
  498. }
  499. const PtrSize dot = fullVarName.find(".");
  500. if(dot == CString::NPOS)
  501. {
  502. ANKI_RESOURCE_LOGE("Wrong variable name: %s", fullVarName.cstr());
  503. return Error::USER_DATA;
  504. }
  505. name = fullVarName.getBegin() + dot + 1;
  506. return Error::NONE;
  507. }
  508. Error MaterialResource::createVars()
  509. {
  510. const ShaderProgramBinary& binary = m_prog->getBinary();
  511. // Create the uniform vars
  512. U32 descriptorSet = MAX_U32;
  513. U32 maxDescriptorSet = 0;
  514. for(const ShaderProgramBinaryBlock& block : binary.m_uniformBlocks)
  515. {
  516. maxDescriptorSet = max(maxDescriptorSet, block.m_set);
  517. if(block.m_name.getBegin() != CString("b_ankiMaterial"))
  518. {
  519. continue;
  520. }
  521. descriptorSet = block.m_set;
  522. m_uboIdx = U32(&block - binary.m_uniformBlocks.getBegin());
  523. m_uboBinding = block.m_binding;
  524. for(const ShaderProgramBinaryVariable& var : block.m_variables)
  525. {
  526. Bool instanced;
  527. U32 idx;
  528. CString name;
  529. ANKI_CHECK(parseVariable(var.m_name.getBegin(), instanced, idx, name));
  530. ANKI_ASSERT(name.getLength() > 0 && (instanced || idx == 0));
  531. if(idx > 0)
  532. {
  533. if(idx > MAX_INSTANCES)
  534. {
  535. ANKI_RESOURCE_LOGE("Array variable exceeds the instance count: %s", var.m_name.getBegin());
  536. return Error::USER_DATA;
  537. }
  538. if(idx == 1)
  539. {
  540. // Find the idx==0
  541. MaterialVariable* other = tryFindVariable(name);
  542. ANKI_ASSERT(other);
  543. ANKI_ASSERT(other->m_indexInBinary2ndElement == MAX_U32);
  544. other->m_indexInBinary2ndElement = U32(&var - block.m_variables.getBegin());
  545. }
  546. // Skip var
  547. continue;
  548. }
  549. const MaterialVariable* other = tryFindVariable(name);
  550. if(other)
  551. {
  552. ANKI_RESOURCE_LOGE("Variable found twice: %s", name.cstr());
  553. return Error::USER_DATA;
  554. }
  555. MaterialVariable& in = *m_vars.emplaceBack(getAllocator());
  556. in.m_name.create(getAllocator(), name);
  557. in.m_index = m_vars.getSize() - 1;
  558. in.m_indexInBinary = U32(&var - block.m_variables.getBegin());
  559. in.m_constant = false;
  560. in.m_instanced = instanced;
  561. in.m_dataType = var.m_type;
  562. // Check if it's builtin
  563. ANKI_CHECK(checkBuiltin(name, in.m_dataType, instanced, in.m_builtin));
  564. }
  565. }
  566. if(descriptorSet == MAX_U32)
  567. {
  568. ANKI_RESOURCE_LOGE("The b_ankiMaterial UBO is missing");
  569. return Error::USER_DATA;
  570. }
  571. // Continue with the opaque if it's a material shader program
  572. for(const ShaderProgramBinaryOpaque& o : binary.m_opaques)
  573. {
  574. maxDescriptorSet = max(maxDescriptorSet, o.m_set);
  575. if(o.m_set != descriptorSet)
  576. {
  577. continue;
  578. }
  579. MaterialVariable& in = *m_vars.emplaceBack(getAllocator());
  580. in.m_name.create(getAllocator(), o.m_name.getBegin());
  581. in.m_index = m_vars.getSize() - 1;
  582. in.m_indexInBinary = U32(&o - binary.m_opaques.getBegin());
  583. in.m_constant = false;
  584. in.m_instanced = false;
  585. in.m_dataType = o.m_type;
  586. // Check if it's builtin
  587. ANKI_CHECK(checkBuiltin(in.m_name, in.m_dataType, false, in.m_builtin));
  588. }
  589. if(descriptorSet != maxDescriptorSet)
  590. {
  591. ANKI_RESOURCE_LOGE("All bindings of a material shader should be in the highest descriptor set");
  592. return Error::USER_DATA;
  593. }
  594. m_descriptorSetIdx = U8(descriptorSet);
  595. // Consts
  596. for(const ShaderProgramResourceConstant& c : m_prog->getConstants())
  597. {
  598. MaterialVariable& in = *m_vars.emplaceBack(getAllocator());
  599. in.m_name.create(getAllocator(), c.m_name);
  600. in.m_index = m_vars.getSize() - 1;
  601. in.m_constant = true;
  602. in.m_instanced = false;
  603. in.m_dataType = c.m_dataType;
  604. }
  605. return Error::NONE;
  606. }
  607. Error MaterialResource::parseInputs(XmlElement inputsEl, Bool async)
  608. {
  609. // Connect the input variables
  610. XmlElement inputEl;
  611. ANKI_CHECK(inputsEl.getChildElementOptional("input", inputEl));
  612. while(inputEl)
  613. {
  614. // Get var name
  615. CString varName;
  616. ANKI_CHECK(inputEl.getAttributeText("shaderVar", varName));
  617. // Try find var
  618. MaterialVariable* foundVar = tryFindVariable(varName);
  619. if(foundVar == nullptr)
  620. {
  621. ANKI_RESOURCE_LOGE("Variable \"%s\" not found", varName.cstr());
  622. return Error::USER_DATA;
  623. }
  624. if(foundVar->m_builtin != BuiltinMaterialVariableId::NONE)
  625. {
  626. ANKI_RESOURCE_LOGE("Shouldn't list builtin vars: %s", varName.cstr());
  627. return Error::USER_DATA;
  628. }
  629. // A value will be set
  630. foundVar->m_numericValueIsSet = true;
  631. // Process var
  632. if(foundVar->isConstant())
  633. {
  634. // Const
  635. switch(foundVar->getDataType())
  636. {
  637. #define ANKI_SVDT_MACRO(capital, type, baseType, rowCount, columnCount) \
  638. case ShaderVariableDataType::capital: \
  639. ANKI_CHECK(GetAttribute<type>()(inputEl, foundVar->ANKI_CONCATENATE(m_, type))); \
  640. break;
  641. #include <anki/gr/ShaderVariableDataTypeDefs.h>
  642. #undef ANKI_SVDT_MACRO
  643. default:
  644. ANKI_ASSERT(0);
  645. break;
  646. }
  647. }
  648. else
  649. {
  650. // Not built-in
  651. if(foundVar->isInstanced())
  652. {
  653. ANKI_RESOURCE_LOGE("Only some builtin variables can be instanced: %s", foundVar->getName().cstr());
  654. return Error::USER_DATA;
  655. }
  656. switch(foundVar->getDataType())
  657. {
  658. #define ANKI_SVDT_MACRO(capital, type, baseType, rowCount, columnCount) \
  659. case ShaderVariableDataType::capital: \
  660. ANKI_CHECK(GetAttribute<type>()(inputEl, foundVar->ANKI_CONCATENATE(m_, type))); \
  661. break;
  662. #include <anki/gr/ShaderVariableDataTypeDefs.h>
  663. #undef ANKI_SVDT_MACRO
  664. case ShaderVariableDataType::TEXTURE_2D:
  665. case ShaderVariableDataType::TEXTURE_2D_ARRAY:
  666. case ShaderVariableDataType::TEXTURE_3D:
  667. case ShaderVariableDataType::TEXTURE_CUBE:
  668. {
  669. CString texfname;
  670. ANKI_CHECK(inputEl.getAttributeText("value", texfname));
  671. ANKI_CHECK(getManager().loadResource(texfname, foundVar->m_tex, async));
  672. break;
  673. }
  674. default:
  675. ANKI_ASSERT(0);
  676. break;
  677. }
  678. }
  679. // Advance
  680. ANKI_CHECK(inputEl.getNextSiblingElement("input", inputEl));
  681. }
  682. return Error::NONE;
  683. }
  684. const MaterialVariant& MaterialResource::getOrCreateVariant(const RenderingKey& key_) const
  685. {
  686. RenderingKey key = key_;
  687. key.setLod(min<U32>(m_lodCount - 1, key.getLod()));
  688. if(!isInstanced())
  689. {
  690. ANKI_ASSERT(key.getInstanceCount() == 1);
  691. }
  692. ANKI_ASSERT(!key.isSkinned() || m_builtinMutators[BuiltinMutatorId::BONES]);
  693. ANKI_ASSERT(!key.hasVelocity() || m_builtinMutators[BuiltinMutatorId::VELOCITY]);
  694. key.setInstanceCount(1 << getInstanceGroupIdx(key.getInstanceCount()));
  695. MaterialVariant& variant = m_variantMatrix[key.getPass()][key.getLod()][getInstanceGroupIdx(key.getInstanceCount())]
  696. [key.isSkinned()][key.hasVelocity()];
  697. // Check if it's initialized
  698. {
  699. RLockGuard<RWMutex> lock(m_variantMatrixMtx);
  700. if(variant.m_prog.isCreated())
  701. {
  702. return variant;
  703. }
  704. }
  705. // Not initialized, init it
  706. WLockGuard<RWMutex> lock(m_variantMatrixMtx);
  707. // Check again
  708. if(variant.m_prog.isCreated())
  709. {
  710. return variant;
  711. }
  712. ShaderProgramResourceVariantInitInfo initInfo(m_prog);
  713. for(const SubMutation& m : m_nonBuiltinsMutation)
  714. {
  715. initInfo.addMutation(m.m_mutator->m_name, m.m_value);
  716. }
  717. if(m_builtinMutators[BuiltinMutatorId::INSTANCE_COUNT])
  718. {
  719. initInfo.addMutation(m_builtinMutators[BuiltinMutatorId::INSTANCE_COUNT]->m_name, key.getInstanceCount());
  720. }
  721. if(m_builtinMutators[BuiltinMutatorId::PASS])
  722. {
  723. initInfo.addMutation(m_builtinMutators[BuiltinMutatorId::PASS]->m_name, MutatorValue(key.getPass()));
  724. }
  725. if(m_builtinMutators[BuiltinMutatorId::LOD])
  726. {
  727. initInfo.addMutation(m_builtinMutators[BuiltinMutatorId::LOD]->m_name, MutatorValue(key.getLod()));
  728. }
  729. if(m_builtinMutators[BuiltinMutatorId::BONES])
  730. {
  731. initInfo.addMutation(m_builtinMutators[BuiltinMutatorId::BONES]->m_name, key.isSkinned() != 0);
  732. }
  733. if(m_builtinMutators[BuiltinMutatorId::VELOCITY])
  734. {
  735. initInfo.addMutation(m_builtinMutators[BuiltinMutatorId::VELOCITY]->m_name, key.hasVelocity() != 0);
  736. }
  737. for(const MaterialVariable& var : m_vars)
  738. {
  739. if(!var.isConstant())
  740. {
  741. continue;
  742. }
  743. if(!var.valueSetByMaterial())
  744. {
  745. continue;
  746. }
  747. switch(var.m_dataType)
  748. {
  749. #define ANKI_SVDT_MACRO(capital, type, baseType, rowCount, columnCount) \
  750. case ShaderVariableDataType::capital: \
  751. initInfo.addConstant(var.getName(), var.getValue<type>()); \
  752. break;
  753. #include <anki/gr/ShaderVariableDataTypeDefs.h>
  754. #undef ANKI_SVDT_MACRO
  755. default:
  756. ANKI_ASSERT(0);
  757. }
  758. }
  759. const ShaderProgramResourceVariant* progVariant;
  760. m_prog->getOrCreateVariant(initInfo, progVariant);
  761. // Init the variant
  762. initVariant(*progVariant, variant, key.getInstanceCount());
  763. return variant;
  764. }
  765. void MaterialResource::initVariant(const ShaderProgramResourceVariant& progVariant, MaterialVariant& variant,
  766. U32 instanceCount) const
  767. {
  768. // Find the block instance
  769. const ShaderProgramBinary& binary = m_prog->getBinary();
  770. const ShaderProgramBinaryVariant& binaryVariant = progVariant.getBinaryVariant();
  771. const ShaderProgramBinaryBlockInstance* binaryBlockInstance = nullptr;
  772. for(const ShaderProgramBinaryBlockInstance& instance : binaryVariant.m_uniformBlocks)
  773. {
  774. if(instance.m_index == m_uboIdx)
  775. {
  776. binaryBlockInstance = &instance;
  777. break;
  778. }
  779. }
  780. if(binaryBlockInstance == nullptr)
  781. {
  782. ANKI_RESOURCE_LOGF("The uniform block doesn't appear to be active for variant. Material: %s",
  783. getFilename().cstr());
  784. }
  785. // Some init
  786. variant.m_prog = progVariant.getProgram();
  787. variant.m_blockInfos.create(getAllocator(), m_vars.getSize());
  788. variant.m_opaqueBindings.create(getAllocator(), m_vars.getSize(), -1);
  789. variant.m_uniBlockSize = binaryBlockInstance->m_size;
  790. ANKI_ASSERT(variant.m_uniBlockSize > 0);
  791. // Initialize the block infos, active vars and bindings
  792. for(const MaterialVariable& var : m_vars)
  793. {
  794. if(var.m_constant)
  795. {
  796. for(const ShaderProgramResourceConstant& c : m_prog->getConstants())
  797. {
  798. if(c.m_name == var.m_name)
  799. {
  800. variant.m_activeVars.set(var.m_index, progVariant.isConstantActive(c));
  801. break;
  802. }
  803. }
  804. }
  805. else if(var.inBlock())
  806. {
  807. for(const ShaderProgramBinaryVariableInstance& instance : binaryBlockInstance->m_variables)
  808. {
  809. if(instance.m_index == var.m_indexInBinary)
  810. {
  811. variant.m_activeVars.set(var.m_index, true);
  812. variant.m_blockInfos[var.m_index] = instance.m_blockInfo;
  813. if(var.m_instanced)
  814. {
  815. variant.m_blockInfos[var.m_index].m_arraySize = I16(instanceCount);
  816. }
  817. else
  818. {
  819. break;
  820. }
  821. }
  822. else if(instance.m_index == var.m_indexInBinary2ndElement)
  823. {
  824. // Then we need to update the stride
  825. ANKI_ASSERT(variant.m_blockInfos[var.m_index].m_offset >= 0);
  826. const I16 stride = I16(instance.m_blockInfo.m_offset - variant.m_blockInfos[var.m_index].m_offset);
  827. ANKI_ASSERT(stride >= 4);
  828. variant.m_blockInfos[var.m_index].m_arrayStride = stride;
  829. }
  830. }
  831. }
  832. else
  833. {
  834. ANKI_ASSERT(var.isSampler() || var.isTexture());
  835. for(const ShaderProgramBinaryOpaqueInstance& instance : binaryVariant.m_opaques)
  836. {
  837. if(instance.m_index == var.m_indexInBinary)
  838. {
  839. variant.m_activeVars.set(var.m_index, true);
  840. variant.m_opaqueBindings[var.m_index] = I16(binary.m_opaques[instance.m_index].m_binding);
  841. break;
  842. }
  843. }
  844. }
  845. }
  846. // No make sure that the vars that are active
  847. for(const MaterialVariable& var : m_vars)
  848. {
  849. if(var.m_builtin == BuiltinMaterialVariableId::NONE && variant.m_activeVars.get(var.m_index)
  850. && !var.valueSetByMaterial())
  851. {
  852. ANKI_RESOURCE_LOGF("An active variable doesn't have its value set by the material: %s", var.m_name.cstr());
  853. }
  854. ANKI_ASSERT(!(var.m_instanced && var.m_indexInBinary2ndElement == MAX_U32));
  855. }
  856. // Debug print
  857. #if 0
  858. ANKI_RESOURCE_LOGI("binary variant idx %u\n", U32(&binaryVariant - binary.m_variants.getBegin()));
  859. for(const MaterialVariable& var : m_vars)
  860. {
  861. ANKI_RESOURCE_LOGI(
  862. "Var %s %s\n", var.m_name.cstr(), variant.m_activeVars.get(var.m_index) ? "active" : "inactive");
  863. if(var.inBlock() && variant.m_activeVars.get(var.m_index))
  864. {
  865. const ShaderVariableBlockInfo& inf = variant.m_blockInfos[var.m_index];
  866. ANKI_RESOURCE_LOGI(
  867. "\tblockInfo %d,%d,%d,%d\n", inf.m_offset, inf.m_arraySize, inf.m_arrayStride, inf.m_matrixStride);
  868. }
  869. }
  870. #endif
  871. }
  872. U32 MaterialResource::getInstanceGroupIdx(U32 instanceCount)
  873. {
  874. ANKI_ASSERT(instanceCount > 0);
  875. instanceCount = nextPowerOfTwo(instanceCount);
  876. ANKI_ASSERT(instanceCount <= MAX_INSTANCES);
  877. return U32(std::log2(F32(instanceCount)));
  878. }
  879. Error MaterialResource::parseRtMaterial(XmlElement rtMaterialEl)
  880. {
  881. // rayType
  882. XmlElement rayTypeEl;
  883. ANKI_CHECK(rtMaterialEl.getChildElement("rayType", rayTypeEl));
  884. do
  885. {
  886. // type
  887. CString typeStr;
  888. ANKI_CHECK(rayTypeEl.getAttributeText("type", typeStr));
  889. RayType type = RayType::COUNT;
  890. if(typeStr == "shadows")
  891. {
  892. type = RayType::SHADOWS;
  893. }
  894. else if(typeStr == "gi")
  895. {
  896. type = RayType::GI;
  897. }
  898. else if(typeStr == "reflections")
  899. {
  900. type = RayType::REFLECTIONS;
  901. }
  902. else if(typeStr == "pathTracing")
  903. {
  904. type = RayType::PATH_TRACING;
  905. }
  906. else
  907. {
  908. ANKI_RESOURCE_LOGE("Uknown ray tracing type: %s", typeStr.cstr());
  909. return Error::USER_DATA;
  910. }
  911. if(m_rtPrograms[type].isCreated())
  912. {
  913. ANKI_RESOURCE_LOGE("Ray tracing type already set: %s", typeStr.cstr());
  914. return Error::USER_DATA;
  915. }
  916. m_rayTypes |= RayTypeBit(1 << type);
  917. // shaderProgram
  918. CString fname;
  919. ANKI_CHECK(rayTypeEl.getAttributeText("shaderProgram", fname));
  920. ANKI_CHECK(getManager().loadResource(fname, m_rtPrograms[type], false));
  921. // mutation
  922. XmlElement mutationEl;
  923. ANKI_CHECK(rayTypeEl.getChildElementOptional("mutation", mutationEl));
  924. DynamicArrayAuto<SubMutation> mutatorValues(getTempAllocator());
  925. if(mutationEl)
  926. {
  927. XmlElement mutatorEl;
  928. ANKI_CHECK(mutationEl.getChildElement("mutator", mutatorEl));
  929. U32 mutatorCount = 0;
  930. ANKI_CHECK(mutatorEl.getSiblingElementsCount(mutatorCount));
  931. ++mutatorCount;
  932. mutatorValues.resize(mutatorCount);
  933. mutatorCount = 0;
  934. do
  935. {
  936. // name
  937. CString mutatorName;
  938. ANKI_CHECK(mutatorEl.getAttributeText("name", mutatorName));
  939. if(mutatorName.isEmpty())
  940. {
  941. ANKI_RESOURCE_LOGE("Mutator name is empty");
  942. return Error::USER_DATA;
  943. }
  944. // value
  945. MutatorValue mutatorValue;
  946. ANKI_CHECK(mutatorEl.getAttributeNumber("value", mutatorValue));
  947. // Check
  948. const ShaderProgramResourceMutator* mutatorPtr = m_rtPrograms[type]->tryFindMutator(mutatorName);
  949. if(mutatorPtr == nullptr)
  950. {
  951. ANKI_RESOURCE_LOGE("Mutator not found: %s", mutatorName.cstr());
  952. return Error::USER_DATA;
  953. }
  954. if(!mutatorPtr->valueExists(mutatorValue))
  955. {
  956. ANKI_RESOURCE_LOGE("Mutator value doesn't exist: %s", mutatorName.cstr());
  957. return Error::USER_DATA;
  958. }
  959. // All good
  960. mutatorValues[mutatorCount].m_mutator = mutatorPtr;
  961. mutatorValues[mutatorCount].m_value = mutatorValue;
  962. // Advance
  963. ++mutatorCount;
  964. ANKI_CHECK(mutatorEl.getNextSiblingElement("mutator", mutatorEl));
  965. } while(mutatorEl);
  966. ANKI_ASSERT(mutatorCount == mutatorValues.getSize());
  967. }
  968. if(mutatorValues.getSize() != m_rtPrograms[type]->getMutators().getSize())
  969. {
  970. ANKI_RESOURCE_LOGE("Forgot to set all mutators on some RT mutation");
  971. return Error::USER_DATA;
  972. }
  973. // Get the shader group handle
  974. ShaderProgramResourceVariantInitInfo variantInitInfo(m_rtPrograms[type]);
  975. for(const SubMutation& subMutation : mutatorValues)
  976. {
  977. variantInitInfo.addMutation(subMutation.m_mutator->m_name, subMutation.m_value);
  978. }
  979. const ShaderProgramResourceVariant* progVariant;
  980. m_rtPrograms[type]->getOrCreateVariant(variantInitInfo, progVariant);
  981. m_rtShaderGroupHandles[type] = progVariant->getHitShaderGroupHandle();
  982. // Advance
  983. ANKI_CHECK(rayTypeEl.getNextSiblingElement("rayType", rayTypeEl));
  984. } while(rayTypeEl);
  985. // input
  986. XmlElement inputsEl;
  987. ANKI_CHECK(rtMaterialEl.getChildElementOptional("inputs", inputsEl));
  988. if(inputsEl)
  989. {
  990. XmlElement inputEl;
  991. ANKI_CHECK(inputsEl.getChildElement("input", inputEl));
  992. do
  993. {
  994. // name
  995. CString inputName;
  996. ANKI_CHECK(inputEl.getAttributeText("name", inputName));
  997. // Check if texture
  998. Bool found = false;
  999. for(U32 i = 0; i < GPU_MATERIAL_TEXTURES.getSize(); ++i)
  1000. {
  1001. if(GPU_MATERIAL_TEXTURES[i].m_name == inputName)
  1002. {
  1003. // Found, load the texture
  1004. CString fname;
  1005. ANKI_CHECK(inputEl.getAttributeText("value", fname));
  1006. const U32 textureIdx = GPU_MATERIAL_TEXTURES[i].m_textureSlot;
  1007. ANKI_CHECK(getManager().loadResource(fname, m_textureResources[textureIdx], false));
  1008. m_textureViews[m_textureViewCount] = m_textureResources[textureIdx]->getGrTextureView();
  1009. m_materialGpuDescriptor.m_bindlessTextureIndices[textureIdx] =
  1010. U16(m_textureViews[m_textureViewCount]->getOrCreateBindlessTextureIndex());
  1011. ++m_textureViewCount;
  1012. found = true;
  1013. break;
  1014. }
  1015. }
  1016. // Check floats
  1017. if(!found)
  1018. {
  1019. for(U32 i = 0; i < GPU_MATERIAL_FLOATS.getSize(); ++i)
  1020. {
  1021. if(GPU_MATERIAL_FLOATS[i].m_name == inputName)
  1022. {
  1023. // Found it, set the value
  1024. if(GPU_MATERIAL_FLOATS[i].m_floatCount == 3)
  1025. {
  1026. Vec3 val;
  1027. ANKI_CHECK(inputEl.getAttributeNumbers("value", val));
  1028. memcpy(reinterpret_cast<U8*>(&m_materialGpuDescriptor) + GPU_MATERIAL_FLOATS[i].m_offsetof,
  1029. &val, sizeof(val));
  1030. }
  1031. else
  1032. {
  1033. ANKI_ASSERT(GPU_MATERIAL_FLOATS[i].m_floatCount == 1);
  1034. F32 val;
  1035. ANKI_CHECK(inputEl.getAttributeNumber("value", val));
  1036. memcpy(reinterpret_cast<U8*>(&m_materialGpuDescriptor) + GPU_MATERIAL_FLOATS[i].m_offsetof,
  1037. &val, sizeof(val));
  1038. }
  1039. found = true;
  1040. break;
  1041. }
  1042. }
  1043. }
  1044. if(!found)
  1045. {
  1046. ANKI_RESOURCE_LOGE("Input name is incorrect: %s", inputName.cstr());
  1047. return Error::USER_DATA;
  1048. }
  1049. // Advance
  1050. ANKI_CHECK(inputEl.getNextSiblingElement("input", inputEl));
  1051. } while(inputEl);
  1052. }
  1053. return Error::NONE;
  1054. }
  1055. } // end namespace anki