MaterialResource.cpp 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025
  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(
  35. CString name, ShaderVariableDataType dataType, Bool instanced, 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",
  56. name.cstr());
  57. return Error::USER_DATA;
  58. }
  59. break;
  60. }
  61. }
  62. if(outId == BuiltinMaterialVariableId::NONE && (name.find("m_anki") == 0 || name.find("u_anki") == 0))
  63. {
  64. ANKI_RESOURCE_LOGE("Unknown builtin var: %s", name.cstr());
  65. return Error::USER_DATA;
  66. }
  67. return Error::NONE;
  68. }
  69. MaterialVariable::MaterialVariable()
  70. {
  71. m_mat4 = Mat4::getZero();
  72. m_mat4(3, 3) = NO_VALUE; // Add a random value
  73. }
  74. MaterialVariable::~MaterialVariable()
  75. {
  76. }
  77. MaterialResource::MaterialResource(ResourceManager* manager)
  78. : ResourceObject(manager)
  79. {
  80. }
  81. MaterialResource::~MaterialResource()
  82. {
  83. for(Pass p : EnumIterable<Pass>())
  84. {
  85. for(U32 l = 0; l < MAX_LOD_COUNT; ++l)
  86. {
  87. for(U32 inst = 0; inst < MAX_INSTANCE_GROUPS; ++inst)
  88. {
  89. for(U32 skinned = 0; skinned <= 1; ++skinned)
  90. {
  91. for(U32 vel = 0; vel <= 1; ++vel)
  92. {
  93. MaterialVariant& variant = m_variantMatrix[p][l][inst][skinned][vel];
  94. variant.m_blockInfos.destroy(getAllocator());
  95. variant.m_opaqueBindings.destroy(getAllocator());
  96. }
  97. }
  98. }
  99. }
  100. }
  101. for(MaterialVariable& var : m_vars)
  102. {
  103. var.m_name.destroy(getAllocator());
  104. }
  105. m_vars.destroy(getAllocator());
  106. m_nonBuiltinsMutation.destroy(getAllocator());
  107. }
  108. Error MaterialResource::load(const ResourceFilename& filename, Bool async)
  109. {
  110. XmlDocument doc;
  111. XmlElement el;
  112. Bool present = false;
  113. ANKI_CHECK(openFileParseXml(filename, doc));
  114. // <material>
  115. XmlElement rootEl;
  116. ANKI_CHECK(doc.getChildElement("material", rootEl));
  117. // shaderProgram
  118. CString fname;
  119. ANKI_CHECK(rootEl.getAttributeText("shaderProgram", fname));
  120. ANKI_CHECK(getManager().loadResource(fname, m_prog, async));
  121. // Good time to create the vars
  122. ANKI_CHECK(createVars());
  123. // shadow
  124. ANKI_CHECK(rootEl.getAttributeNumberOptional("shadow", m_shadow, present));
  125. m_shadow = m_shadow != 0;
  126. // forwardShading
  127. ANKI_CHECK(rootEl.getAttributeNumberOptional("forwardShading", m_forwardShading, present));
  128. m_forwardShading = m_forwardShading != 0;
  129. // <mutation>
  130. XmlElement mutatorsEl;
  131. ANKI_CHECK(rootEl.getChildElementOptional("mutation", mutatorsEl));
  132. if(mutatorsEl)
  133. {
  134. ANKI_CHECK(parseMutators(mutatorsEl));
  135. }
  136. // The rest of the mutators
  137. ANKI_CHECK(findBuiltinMutators());
  138. // <inputs>
  139. ANKI_CHECK(rootEl.getChildElementOptional("inputs", el));
  140. if(el)
  141. {
  142. ANKI_CHECK(parseInputs(el, async));
  143. }
  144. return Error::NONE;
  145. }
  146. Error MaterialResource::parseMutators(XmlElement mutatorsEl)
  147. {
  148. XmlElement mutatorEl;
  149. ANKI_CHECK(mutatorsEl.getChildElement("mutator", mutatorEl));
  150. //
  151. // Process the non-builtin mutators
  152. //
  153. U32 mutatorCount = 0;
  154. ANKI_CHECK(mutatorEl.getSiblingElementsCount(mutatorCount));
  155. ++mutatorCount;
  156. ANKI_ASSERT(mutatorCount > 0);
  157. m_nonBuiltinsMutation.create(getAllocator(), mutatorCount);
  158. mutatorCount = 0;
  159. do
  160. {
  161. SubMutation& smutation = m_nonBuiltinsMutation[mutatorCount];
  162. // name
  163. CString mutatorName;
  164. ANKI_CHECK(mutatorEl.getAttributeText("name", mutatorName));
  165. if(mutatorName.isEmpty())
  166. {
  167. ANKI_RESOURCE_LOGE("Mutator name is empty");
  168. return Error::USER_DATA;
  169. }
  170. for(BuiltinMutatorId id : EnumIterable<BuiltinMutatorId>())
  171. {
  172. if(id == BuiltinMutatorId::NONE)
  173. {
  174. continue;
  175. }
  176. if(mutatorName == BUILTIN_MUTATOR_NAMES[id])
  177. {
  178. ANKI_RESOURCE_LOGE("Cannot list builtin mutator: %s", mutatorName.cstr());
  179. return Error::USER_DATA;
  180. }
  181. }
  182. if(mutatorName.find("ANKI_") == 0)
  183. {
  184. ANKI_RESOURCE_LOGE("Mutators can't start with ANKI_: %s", mutatorName.cstr());
  185. return Error::USER_DATA;
  186. }
  187. // value
  188. ANKI_CHECK(mutatorEl.getAttributeNumber("value", smutation.m_value));
  189. // Find mutator
  190. smutation.m_mutator = m_prog->tryFindMutator(mutatorName);
  191. if(!smutation.m_mutator)
  192. {
  193. ANKI_RESOURCE_LOGE("Mutator not found in program %s", &mutatorName[0]);
  194. return Error::USER_DATA;
  195. }
  196. if(!smutation.m_mutator->valueExists(smutation.m_value))
  197. {
  198. ANKI_RESOURCE_LOGE("Value %d is not part of the mutator %s", smutation.m_value, &mutatorName[0]);
  199. return Error::USER_DATA;
  200. }
  201. // Advance
  202. ++mutatorCount;
  203. ANKI_CHECK(mutatorEl.getNextSiblingElement("mutator", mutatorEl));
  204. } while(mutatorEl);
  205. ANKI_ASSERT(mutatorCount == m_nonBuiltinsMutation.getSize());
  206. return Error::NONE;
  207. }
  208. Error MaterialResource::findBuiltinMutators()
  209. {
  210. // INSTANCE_COUNT
  211. U builtinMutatorCount = 0;
  212. m_builtinMutators[BuiltinMutatorId::INSTANCE_COUNT] =
  213. m_prog->tryFindMutator(BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::INSTANCE_COUNT]);
  214. if(m_builtinMutators[BuiltinMutatorId::INSTANCE_COUNT])
  215. {
  216. if(m_builtinMutators[BuiltinMutatorId::INSTANCE_COUNT]->m_values.getSize() != MAX_INSTANCE_GROUPS)
  217. {
  218. ANKI_RESOURCE_LOGE("Mutator %s should have %u values in the program",
  219. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::INSTANCE_COUNT].cstr(),
  220. MAX_INSTANCE_GROUPS);
  221. return Error::USER_DATA;
  222. }
  223. for(U32 i = 0; i < MAX_INSTANCE_GROUPS; ++i)
  224. {
  225. if(m_builtinMutators[BuiltinMutatorId::INSTANCE_COUNT]->m_values[i] != (1 << i))
  226. {
  227. ANKI_RESOURCE_LOGE("Values of the %s mutator in the program are not the expected",
  228. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::INSTANCE_COUNT].cstr());
  229. return Error::USER_DATA;
  230. }
  231. }
  232. ++builtinMutatorCount;
  233. }
  234. // PASS
  235. m_builtinMutators[BuiltinMutatorId::PASS] = m_prog->tryFindMutator(BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::PASS]);
  236. if(m_builtinMutators[BuiltinMutatorId::PASS] && m_forwardShading)
  237. {
  238. ANKI_RESOURCE_LOGE(
  239. "Mutator is not required for forward shading: %s", BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::PASS].cstr());
  240. return Error::USER_DATA;
  241. }
  242. else if(!m_builtinMutators[BuiltinMutatorId::PASS] && !m_forwardShading)
  243. {
  244. ANKI_RESOURCE_LOGE(
  245. "Mutator is required for opaque shading: %s", BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::PASS].cstr());
  246. return Error::USER_DATA;
  247. }
  248. if(m_builtinMutators[BuiltinMutatorId::PASS])
  249. {
  250. if(m_builtinMutators[BuiltinMutatorId::PASS]->m_values.getSize() != U32(Pass::COUNT) - 1)
  251. {
  252. ANKI_RESOURCE_LOGE("Mutator %s should have %u values in the program",
  253. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::PASS].cstr(),
  254. U32(Pass::COUNT) - 1);
  255. return Error::USER_DATA;
  256. }
  257. U32 count = 0;
  258. for(Pass p : EnumIterable<Pass>())
  259. {
  260. if(p == Pass::FS)
  261. {
  262. continue;
  263. }
  264. if(m_builtinMutators[BuiltinMutatorId::PASS]->m_values[count++] != I(p))
  265. {
  266. ANKI_RESOURCE_LOGE("Values of the %s mutator in the program are not the expected",
  267. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::PASS].cstr());
  268. return Error::USER_DATA;
  269. }
  270. }
  271. ++builtinMutatorCount;
  272. }
  273. if(!m_forwardShading && !m_builtinMutators[BuiltinMutatorId::PASS])
  274. {
  275. ANKI_RESOURCE_LOGE("%s mutator is required", BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::PASS].cstr());
  276. return Error::USER_DATA;
  277. }
  278. // LOD
  279. m_builtinMutators[BuiltinMutatorId::LOD] = m_prog->tryFindMutator(BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::LOD]);
  280. if(m_builtinMutators[BuiltinMutatorId::LOD])
  281. {
  282. if(m_builtinMutators[BuiltinMutatorId::LOD]->m_values.getSize() > MAX_LOD_COUNT)
  283. {
  284. ANKI_RESOURCE_LOGE("Mutator %s should have at least %u values in the program",
  285. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::LOD].cstr(),
  286. U32(MAX_LOD_COUNT));
  287. return Error::USER_DATA;
  288. }
  289. for(U32 i = 0; i < m_builtinMutators[BuiltinMutatorId::LOD]->m_values.getSize(); ++i)
  290. {
  291. if(m_builtinMutators[BuiltinMutatorId::LOD]->m_values[i] != I(i))
  292. {
  293. ANKI_RESOURCE_LOGE("Values of the %s mutator in the program are not the expected",
  294. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::LOD].cstr());
  295. return Error::USER_DATA;
  296. }
  297. }
  298. m_lodCount = U8(m_builtinMutators[BuiltinMutatorId::LOD]->m_values.getSize());
  299. ++builtinMutatorCount;
  300. }
  301. // BONES
  302. m_builtinMutators[BuiltinMutatorId::BONES] = m_prog->tryFindMutator(BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::BONES]);
  303. if(m_builtinMutators[BuiltinMutatorId::BONES])
  304. {
  305. if(m_builtinMutators[BuiltinMutatorId::BONES]->m_values.getSize() != 2)
  306. {
  307. ANKI_RESOURCE_LOGE("Mutator %s should have 2 values in the program",
  308. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::BONES].cstr());
  309. return Error::USER_DATA;
  310. }
  311. for(U32 i = 0; i < m_builtinMutators[BuiltinMutatorId::BONES]->m_values.getSize(); ++i)
  312. {
  313. if(m_builtinMutators[BuiltinMutatorId::BONES]->m_values[i] != I(i))
  314. {
  315. ANKI_RESOURCE_LOGE("Values of the %s mutator in the program are not the expected",
  316. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::BONES].cstr());
  317. return Error::USER_DATA;
  318. }
  319. }
  320. ++builtinMutatorCount;
  321. // Find the binding of the transforms
  322. const ShaderProgramBinary& binary = m_prog->getBinary();
  323. for(const ShaderProgramBinaryBlock& block : binary.m_storageBlocks)
  324. {
  325. if(block.m_name.getBegin() == CString("b_ankiBoneTransforms"))
  326. {
  327. if(block.m_set != m_descriptorSetIdx)
  328. {
  329. ANKI_RESOURCE_LOGE("The set of u_ankiBoneTransforms should be %u", m_descriptorSetIdx);
  330. return Error::USER_DATA;
  331. }
  332. m_boneTrfsBinding = block.m_binding;
  333. break;
  334. }
  335. }
  336. if(m_boneTrfsBinding == MAX_U32)
  337. {
  338. ANKI_RESOURCE_LOGE("The program is using the %s mutator but b_ankiBoneTransforms was not found",
  339. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::BONES].cstr());
  340. return Error::NONE;
  341. }
  342. }
  343. // VELOCITY
  344. m_builtinMutators[BuiltinMutatorId::VELOCITY] =
  345. m_prog->tryFindMutator(BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::VELOCITY]);
  346. if(m_builtinMutators[BuiltinMutatorId::VELOCITY])
  347. {
  348. if(m_builtinMutators[BuiltinMutatorId::VELOCITY]->m_values.getSize() != 2)
  349. {
  350. ANKI_RESOURCE_LOGE("Mutator %s should have 2 values in the program",
  351. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::VELOCITY].cstr());
  352. return Error::USER_DATA;
  353. }
  354. for(U32 i = 0; i < m_builtinMutators[BuiltinMutatorId::VELOCITY]->m_values.getSize(); ++i)
  355. {
  356. if(m_builtinMutators[BuiltinMutatorId::VELOCITY]->m_values[i] != I(i))
  357. {
  358. ANKI_RESOURCE_LOGE("Values of the %s mutator in the program are not the expected",
  359. BUILTIN_MUTATOR_NAMES[BuiltinMutatorId::VELOCITY].cstr());
  360. return Error::USER_DATA;
  361. }
  362. }
  363. ++builtinMutatorCount;
  364. }
  365. if(m_nonBuiltinsMutation.getSize() + builtinMutatorCount != m_prog->getMutators().getSize())
  366. {
  367. ANKI_RESOURCE_LOGE("Some mutatators are unacounted for");
  368. return Error::USER_DATA;
  369. }
  370. return Error::NONE;
  371. }
  372. Error MaterialResource::parseVariable(CString fullVarName, Bool& instanced, U32& idx, CString& name)
  373. {
  374. idx = 0;
  375. if(fullVarName.find("u_ankiPerDraw") != CString::NPOS)
  376. {
  377. instanced = false;
  378. }
  379. else if(fullVarName.find("u_ankiPerInstance") != CString::NPOS)
  380. {
  381. instanced = true;
  382. }
  383. else
  384. {
  385. ANKI_RESOURCE_LOGE("Wrong variable name: %s", fullVarName.cstr());
  386. return Error::USER_DATA;
  387. }
  388. const PtrSize leftBracket = fullVarName.find("[");
  389. const PtrSize rightBracket = fullVarName.find("]");
  390. if(instanced)
  391. {
  392. const Bool correct =
  393. (leftBracket == CString::NPOS && rightBracket == CString::NPOS)
  394. || (leftBracket != CString::NPOS && rightBracket != CString::NPOS && rightBracket > leftBracket);
  395. if(!correct)
  396. {
  397. ANKI_RESOURCE_LOGE("Wrong variable name: %s", fullVarName.cstr());
  398. return Error::USER_DATA;
  399. }
  400. if(leftBracket != CString::NPOS)
  401. {
  402. Array<char, 8> idxStr = {};
  403. for(PtrSize i = leftBracket + 1; i < rightBracket; ++i)
  404. {
  405. idxStr[i - (leftBracket + 1)] = fullVarName[i];
  406. }
  407. ANKI_CHECK(CString(idxStr.getBegin()).toNumber(idx));
  408. }
  409. else
  410. {
  411. idx = 0;
  412. }
  413. }
  414. else
  415. {
  416. if(leftBracket != CString::NPOS || rightBracket != CString::NPOS)
  417. {
  418. ANKI_RESOURCE_LOGE("Can't support non instanced array variables: %s", fullVarName.cstr());
  419. return Error::USER_DATA;
  420. }
  421. }
  422. const PtrSize dot = fullVarName.find(".");
  423. if(dot == CString::NPOS)
  424. {
  425. ANKI_RESOURCE_LOGE("Wrong variable name: %s", fullVarName.cstr());
  426. return Error::USER_DATA;
  427. }
  428. name = fullVarName.getBegin() + dot + 1;
  429. return Error::NONE;
  430. }
  431. Error MaterialResource::createVars()
  432. {
  433. const ShaderProgramBinary& binary = m_prog->getBinary();
  434. // Create the uniform vars
  435. U32 descriptorSet = MAX_U32;
  436. U32 maxDescriptorSet = 0;
  437. for(const ShaderProgramBinaryBlock& block : binary.m_uniformBlocks)
  438. {
  439. maxDescriptorSet = max(maxDescriptorSet, block.m_set);
  440. if(block.m_name.getBegin() != CString("b_ankiMaterial"))
  441. {
  442. continue;
  443. }
  444. descriptorSet = block.m_set;
  445. m_uboIdx = U32(&block - binary.m_uniformBlocks.getBegin());
  446. m_uboBinding = block.m_binding;
  447. for(const ShaderProgramBinaryVariable& var : block.m_variables)
  448. {
  449. Bool instanced;
  450. U32 idx;
  451. CString name;
  452. ANKI_CHECK(parseVariable(var.m_name.getBegin(), instanced, idx, name));
  453. ANKI_ASSERT(name.getLength() > 0 && (instanced || idx == 0));
  454. if(idx > 0)
  455. {
  456. if(idx > MAX_INSTANCES)
  457. {
  458. ANKI_RESOURCE_LOGE("Array variable exceeds the instance count: %s", var.m_name.getBegin());
  459. return Error::USER_DATA;
  460. }
  461. if(idx == 1)
  462. {
  463. // Find the idx==0
  464. MaterialVariable* other = tryFindVariable(name);
  465. ANKI_ASSERT(other);
  466. ANKI_ASSERT(other->m_indexInBinary2ndElement == MAX_U32);
  467. other->m_indexInBinary2ndElement = U32(&var - block.m_variables.getBegin());
  468. }
  469. // Skip var
  470. continue;
  471. }
  472. const MaterialVariable* other = tryFindVariable(name);
  473. if(other)
  474. {
  475. ANKI_RESOURCE_LOGE("Variable found twice: %s", name.cstr());
  476. return Error::USER_DATA;
  477. }
  478. MaterialVariable& in = *m_vars.emplaceBack(getAllocator());
  479. in.m_name.create(getAllocator(), name);
  480. in.m_index = m_vars.getSize() - 1;
  481. in.m_indexInBinary = U32(&var - block.m_variables.getBegin());
  482. in.m_constant = false;
  483. in.m_instanced = instanced;
  484. in.m_dataType = var.m_type;
  485. // Check if it's builtin
  486. ANKI_CHECK(checkBuiltin(name, in.m_dataType, instanced, in.m_builtin));
  487. }
  488. }
  489. if(descriptorSet == MAX_U32)
  490. {
  491. ANKI_RESOURCE_LOGE("The b_ankiMaterial UBO is missing");
  492. return Error::USER_DATA;
  493. }
  494. // Continue with the opaque if it's a material shader program
  495. for(const ShaderProgramBinaryOpaque& o : binary.m_opaques)
  496. {
  497. maxDescriptorSet = max(maxDescriptorSet, o.m_set);
  498. if(o.m_set != descriptorSet)
  499. {
  500. continue;
  501. }
  502. MaterialVariable& in = *m_vars.emplaceBack(getAllocator());
  503. in.m_name.create(getAllocator(), o.m_name.getBegin());
  504. in.m_index = m_vars.getSize() - 1;
  505. in.m_indexInBinary = U32(&o - binary.m_opaques.getBegin());
  506. in.m_constant = false;
  507. in.m_instanced = false;
  508. in.m_dataType = o.m_type;
  509. // Check if it's builtin
  510. ANKI_CHECK(checkBuiltin(in.m_name, in.m_dataType, false, in.m_builtin));
  511. }
  512. if(descriptorSet != maxDescriptorSet)
  513. {
  514. ANKI_RESOURCE_LOGE("All bindings of a material shader should be in the highest descriptor set");
  515. return Error::USER_DATA;
  516. }
  517. m_descriptorSetIdx = U8(descriptorSet);
  518. // Consts
  519. for(const ShaderProgramResourceConstant& c : m_prog->getConstants())
  520. {
  521. MaterialVariable& in = *m_vars.emplaceBack(getAllocator());
  522. in.m_name.create(getAllocator(), c.m_name);
  523. in.m_index = m_vars.getSize() - 1;
  524. in.m_constant = true;
  525. in.m_instanced = false;
  526. in.m_dataType = c.m_dataType;
  527. }
  528. return Error::NONE;
  529. }
  530. Error MaterialResource::parseInputs(XmlElement inputsEl, Bool async)
  531. {
  532. // Connect the input variables
  533. XmlElement inputEl;
  534. ANKI_CHECK(inputsEl.getChildElementOptional("input", inputEl));
  535. while(inputEl)
  536. {
  537. // Get var name
  538. CString varName;
  539. ANKI_CHECK(inputEl.getAttributeText("shaderVar", varName));
  540. // Try find var
  541. MaterialVariable* foundVar = tryFindVariable(varName);
  542. if(foundVar == nullptr)
  543. {
  544. ANKI_RESOURCE_LOGE("Variable \"%s\" not found", varName.cstr());
  545. return Error::USER_DATA;
  546. }
  547. if(foundVar->m_builtin != BuiltinMaterialVariableId::NONE)
  548. {
  549. ANKI_RESOURCE_LOGE("Shouldn't list builtin vars: %s", varName.cstr());
  550. return Error::USER_DATA;
  551. }
  552. // A value will be set
  553. foundVar->m_mat4(3, 3) = 0.0f;
  554. // Process var
  555. if(foundVar->isConstant())
  556. {
  557. // Const
  558. switch(foundVar->getDataType())
  559. {
  560. case ShaderVariableDataType::INT:
  561. ANKI_CHECK(inputEl.getAttributeNumber("value", foundVar->m_int));
  562. break;
  563. case ShaderVariableDataType::IVEC2:
  564. ANKI_CHECK(inputEl.getAttributeNumbers("value", foundVar->m_ivec2));
  565. break;
  566. case ShaderVariableDataType::IVEC3:
  567. ANKI_CHECK(inputEl.getAttributeNumbers("value", foundVar->m_ivec3));
  568. break;
  569. case ShaderVariableDataType::IVEC4:
  570. ANKI_CHECK(inputEl.getAttributeNumbers("value", foundVar->m_ivec4));
  571. break;
  572. case ShaderVariableDataType::UINT:
  573. ANKI_CHECK(inputEl.getAttributeNumber("value", foundVar->m_uint));
  574. break;
  575. case ShaderVariableDataType::UVEC2:
  576. ANKI_CHECK(inputEl.getAttributeNumbers("value", foundVar->m_uvec2));
  577. break;
  578. case ShaderVariableDataType::UVEC3:
  579. ANKI_CHECK(inputEl.getAttributeNumbers("value", foundVar->m_uvec3));
  580. break;
  581. case ShaderVariableDataType::UVEC4:
  582. ANKI_CHECK(inputEl.getAttributeNumbers("value", foundVar->m_uvec4));
  583. break;
  584. case ShaderVariableDataType::FLOAT:
  585. ANKI_CHECK(inputEl.getAttributeNumber("value", foundVar->m_float));
  586. break;
  587. case ShaderVariableDataType::VEC2:
  588. ANKI_CHECK(inputEl.getAttributeNumbers("value", foundVar->m_vec2));
  589. break;
  590. case ShaderVariableDataType::VEC3:
  591. ANKI_CHECK(inputEl.getAttributeNumbers("value", foundVar->m_vec3));
  592. break;
  593. case ShaderVariableDataType::VEC4:
  594. ANKI_CHECK(inputEl.getAttributeNumbers("value", foundVar->m_vec4));
  595. break;
  596. default:
  597. ANKI_ASSERT(0);
  598. break;
  599. }
  600. }
  601. else
  602. {
  603. // Not built-in
  604. if(foundVar->isInstanced())
  605. {
  606. ANKI_RESOURCE_LOGE("Only some builtin variables can be instanced: %s", foundVar->getName().cstr());
  607. return Error::USER_DATA;
  608. }
  609. switch(foundVar->getDataType())
  610. {
  611. case ShaderVariableDataType::INT:
  612. ANKI_CHECK(inputEl.getAttributeNumber("value", foundVar->m_int));
  613. break;
  614. case ShaderVariableDataType::IVEC2:
  615. ANKI_CHECK(inputEl.getAttributeNumbers("value", foundVar->m_ivec2));
  616. break;
  617. case ShaderVariableDataType::IVEC3:
  618. ANKI_CHECK(inputEl.getAttributeNumbers("value", foundVar->m_ivec3));
  619. break;
  620. case ShaderVariableDataType::IVEC4:
  621. ANKI_CHECK(inputEl.getAttributeNumbers("value", foundVar->m_ivec4));
  622. break;
  623. case ShaderVariableDataType::UINT:
  624. ANKI_CHECK(inputEl.getAttributeNumber("value", foundVar->m_uint));
  625. break;
  626. case ShaderVariableDataType::UVEC2:
  627. ANKI_CHECK(inputEl.getAttributeNumbers("value", foundVar->m_uvec2));
  628. break;
  629. case ShaderVariableDataType::UVEC3:
  630. ANKI_CHECK(inputEl.getAttributeNumbers("value", foundVar->m_uvec3));
  631. break;
  632. case ShaderVariableDataType::UVEC4:
  633. ANKI_CHECK(inputEl.getAttributeNumbers("value", foundVar->m_uvec4));
  634. break;
  635. case ShaderVariableDataType::FLOAT:
  636. ANKI_CHECK(inputEl.getAttributeNumber("value", foundVar->m_float));
  637. break;
  638. case ShaderVariableDataType::VEC2:
  639. ANKI_CHECK(inputEl.getAttributeNumbers("value", foundVar->m_vec2));
  640. break;
  641. case ShaderVariableDataType::VEC3:
  642. ANKI_CHECK(inputEl.getAttributeNumbers("value", foundVar->m_vec3));
  643. break;
  644. case ShaderVariableDataType::VEC4:
  645. ANKI_CHECK(inputEl.getAttributeNumbers("value", foundVar->m_vec4));
  646. break;
  647. case ShaderVariableDataType::MAT3:
  648. ANKI_CHECK(inputEl.getAttributeNumbers("value", foundVar->m_mat3));
  649. break;
  650. case ShaderVariableDataType::MAT4:
  651. ANKI_CHECK(inputEl.getAttributeNumbers("value", foundVar->m_mat4));
  652. break;
  653. case ShaderVariableDataType::TEXTURE_2D:
  654. case ShaderVariableDataType::TEXTURE_2D_ARRAY:
  655. case ShaderVariableDataType::TEXTURE_3D:
  656. case ShaderVariableDataType::TEXTURE_CUBE:
  657. {
  658. CString texfname;
  659. ANKI_CHECK(inputEl.getAttributeText("value", texfname));
  660. ANKI_CHECK(getManager().loadResource(texfname, foundVar->m_tex, async));
  661. break;
  662. }
  663. default:
  664. ANKI_ASSERT(0);
  665. break;
  666. }
  667. }
  668. // Advance
  669. ANKI_CHECK(inputEl.getNextSiblingElement("input", inputEl));
  670. }
  671. return Error::NONE;
  672. }
  673. const MaterialVariant& MaterialResource::getOrCreateVariant(const RenderingKey& key_) const
  674. {
  675. RenderingKey key = key_;
  676. key.setLod(min<U32>(m_lodCount - 1, key.getLod()));
  677. if(!isInstanced())
  678. {
  679. ANKI_ASSERT(key.getInstanceCount() == 1);
  680. }
  681. ANKI_ASSERT(!key.isSkinned() || m_builtinMutators[BuiltinMutatorId::BONES]);
  682. ANKI_ASSERT(!key.hasVelocity() || m_builtinMutators[BuiltinMutatorId::VELOCITY]);
  683. key.setInstanceCount(1 << getInstanceGroupIdx(key.getInstanceCount()));
  684. MaterialVariant& variant = m_variantMatrix[key.getPass()][key.getLod()][getInstanceGroupIdx(key.getInstanceCount())]
  685. [key.isSkinned()][key.hasVelocity()];
  686. // Check if it's initialized
  687. {
  688. RLockGuard<RWMutex> lock(m_variantMatrixMtx);
  689. if(variant.m_prog.isCreated())
  690. {
  691. return variant;
  692. }
  693. }
  694. // Not initialized, init it
  695. WLockGuard<RWMutex> lock(m_variantMatrixMtx);
  696. // Check again
  697. if(variant.m_prog.isCreated())
  698. {
  699. return variant;
  700. }
  701. ShaderProgramResourceVariantInitInfo initInfo(m_prog);
  702. for(const SubMutation& m : m_nonBuiltinsMutation)
  703. {
  704. initInfo.addMutation(m.m_mutator->m_name, m.m_value);
  705. }
  706. if(m_builtinMutators[BuiltinMutatorId::INSTANCE_COUNT])
  707. {
  708. initInfo.addMutation(m_builtinMutators[BuiltinMutatorId::INSTANCE_COUNT]->m_name, key.getInstanceCount());
  709. }
  710. if(m_builtinMutators[BuiltinMutatorId::PASS])
  711. {
  712. initInfo.addMutation(m_builtinMutators[BuiltinMutatorId::PASS]->m_name, MutatorValue(key.getPass()));
  713. }
  714. if(m_builtinMutators[BuiltinMutatorId::LOD])
  715. {
  716. initInfo.addMutation(m_builtinMutators[BuiltinMutatorId::LOD]->m_name, MutatorValue(key.getLod()));
  717. }
  718. if(m_builtinMutators[BuiltinMutatorId::BONES])
  719. {
  720. initInfo.addMutation(m_builtinMutators[BuiltinMutatorId::BONES]->m_name, key.isSkinned() != 0);
  721. }
  722. if(m_builtinMutators[BuiltinMutatorId::VELOCITY])
  723. {
  724. initInfo.addMutation(m_builtinMutators[BuiltinMutatorId::VELOCITY]->m_name, key.hasVelocity() != 0);
  725. }
  726. for(const MaterialVariable& var : m_vars)
  727. {
  728. if(!var.isConstant())
  729. {
  730. continue;
  731. }
  732. if(!var.valueSetByMaterial())
  733. {
  734. continue;
  735. }
  736. switch(var.m_dataType)
  737. {
  738. case ShaderVariableDataType::INT:
  739. initInfo.addConstant(var.getName(), var.getValue<I32>());
  740. break;
  741. case ShaderVariableDataType::IVEC2:
  742. initInfo.addConstant(var.getName(), var.getValue<IVec2>());
  743. break;
  744. case ShaderVariableDataType::IVEC3:
  745. initInfo.addConstant(var.getName(), var.getValue<IVec3>());
  746. break;
  747. case ShaderVariableDataType::IVEC4:
  748. initInfo.addConstant(var.getName(), var.getValue<IVec4>());
  749. break;
  750. case ShaderVariableDataType::FLOAT:
  751. initInfo.addConstant(var.getName(), var.getValue<F32>());
  752. break;
  753. case ShaderVariableDataType::VEC2:
  754. initInfo.addConstant(var.getName(), var.getValue<Vec2>());
  755. break;
  756. case ShaderVariableDataType::VEC3:
  757. initInfo.addConstant(var.getName(), var.getValue<Vec3>());
  758. break;
  759. case ShaderVariableDataType::VEC4:
  760. initInfo.addConstant(var.getName(), var.getValue<Vec4>());
  761. break;
  762. default:
  763. ANKI_ASSERT(0);
  764. }
  765. }
  766. const ShaderProgramResourceVariant* progVariant;
  767. m_prog->getOrCreateVariant(initInfo, progVariant);
  768. // Init the variant
  769. initVariant(*progVariant, variant, key.getInstanceCount());
  770. return variant;
  771. }
  772. void MaterialResource::initVariant(
  773. const ShaderProgramResourceVariant& progVariant, MaterialVariant& variant, U32 instanceCount) const
  774. {
  775. // Find the block instance
  776. const ShaderProgramBinary& binary = m_prog->getBinary();
  777. const ShaderProgramBinaryVariant& binaryVariant = progVariant.getBinaryVariant();
  778. const ShaderProgramBinaryBlockInstance* binaryBlockInstance = nullptr;
  779. for(const ShaderProgramBinaryBlockInstance& instance : binaryVariant.m_uniformBlocks)
  780. {
  781. if(instance.m_index == m_uboIdx)
  782. {
  783. binaryBlockInstance = &instance;
  784. break;
  785. }
  786. }
  787. if(binaryBlockInstance == nullptr)
  788. {
  789. ANKI_RESOURCE_LOGF(
  790. "The uniform block doesn't appear to be active for variant. Material: %s", getFilename().cstr());
  791. }
  792. // Some init
  793. variant.m_prog = progVariant.getProgram();
  794. variant.m_blockInfos.create(getAllocator(), m_vars.getSize());
  795. variant.m_opaqueBindings.create(getAllocator(), m_vars.getSize(), -1);
  796. variant.m_uniBlockSize = binaryBlockInstance->m_size;
  797. ANKI_ASSERT(variant.m_uniBlockSize > 0);
  798. // Initialize the block infos, active vars and bindings
  799. for(const MaterialVariable& var : m_vars)
  800. {
  801. if(var.m_constant)
  802. {
  803. for(const ShaderProgramResourceConstant& c : m_prog->getConstants())
  804. {
  805. if(c.m_name == var.m_name)
  806. {
  807. variant.m_activeVars.set(var.m_index, progVariant.isConstantActive(c));
  808. break;
  809. }
  810. }
  811. }
  812. else if(var.inBlock())
  813. {
  814. for(const ShaderProgramBinaryVariableInstance& instance : binaryBlockInstance->m_variables)
  815. {
  816. if(instance.m_index == var.m_indexInBinary)
  817. {
  818. variant.m_activeVars.set(var.m_index, true);
  819. variant.m_blockInfos[var.m_index] = instance.m_blockInfo;
  820. if(var.m_instanced)
  821. {
  822. variant.m_blockInfos[var.m_index].m_arraySize = I16(instanceCount);
  823. }
  824. else
  825. {
  826. break;
  827. }
  828. }
  829. else if(instance.m_index == var.m_indexInBinary2ndElement)
  830. {
  831. // Then we need to update the stride
  832. ANKI_ASSERT(variant.m_blockInfos[var.m_index].m_offset >= 0);
  833. const I16 stride = I16(instance.m_blockInfo.m_offset - variant.m_blockInfos[var.m_index].m_offset);
  834. ANKI_ASSERT(stride >= 4);
  835. variant.m_blockInfos[var.m_index].m_arrayStride = stride;
  836. }
  837. }
  838. }
  839. else
  840. {
  841. ANKI_ASSERT(var.isSampler() || var.isTexture());
  842. for(const ShaderProgramBinaryOpaqueInstance& instance : binaryVariant.m_opaques)
  843. {
  844. if(instance.m_index == var.m_indexInBinary)
  845. {
  846. variant.m_activeVars.set(var.m_index, true);
  847. variant.m_opaqueBindings[var.m_index] = I16(binary.m_opaques[instance.m_index].m_binding);
  848. break;
  849. }
  850. }
  851. }
  852. }
  853. // No make sure that the vars that are active
  854. for(const MaterialVariable& var : m_vars)
  855. {
  856. if(var.m_builtin == BuiltinMaterialVariableId::NONE && variant.m_activeVars.get(var.m_index)
  857. && !var.valueSetByMaterial())
  858. {
  859. ANKI_RESOURCE_LOGF("An active variable doesn't have its value set by the material: %s", var.m_name.cstr());
  860. }
  861. ANKI_ASSERT(!(var.m_instanced && var.m_indexInBinary2ndElement == MAX_U32));
  862. }
  863. // Debug print
  864. #if 0
  865. printf("binary variant idx %u\n", U32(&binaryVariant - binary.m_variants.getBegin()));
  866. for(const MaterialVariable& var : m_vars)
  867. {
  868. printf("Var %s %s\n", var.m_name.cstr(), variant.m_activeVars.get(var.m_index) ? "active" : "inactive");
  869. if(var.inBlock() && variant.m_activeVars.get(var.m_index))
  870. {
  871. const ShaderVariableBlockInfo& inf = variant.m_blockInfos[var.m_index];
  872. printf("\tblockInfo %d,%d,%d,%d\n", inf.m_offset, inf.m_arraySize, inf.m_arrayStride, inf.m_matrixStride);
  873. }
  874. }
  875. #endif
  876. }
  877. U32 MaterialResource::getInstanceGroupIdx(U32 instanceCount)
  878. {
  879. ANKI_ASSERT(instanceCount > 0);
  880. instanceCount = nextPowerOfTwo(instanceCount);
  881. ANKI_ASSERT(instanceCount <= MAX_INSTANCES);
  882. return U32(std::log2(F32(instanceCount)));
  883. }
  884. } // end namespace anki