2
0

Material.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. // Copyright (C) 2009-2015, Panagiotis Christopoulos Charitos.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include "anki/resource/Material.h"
  6. #include "anki/resource/MaterialProgramCreator.h"
  7. #include "anki/core/App.h"
  8. #include "anki/util/Logger.h"
  9. #include "anki/resource/ProgramResource.h"
  10. #include "anki/resource/TextureResource.h"
  11. #include "anki/util/Hash.h"
  12. #include "anki/util/File.h"
  13. #include "anki/util/Filesystem.h"
  14. #include "anki/misc/Xml.h"
  15. #include <functional> // TODO
  16. #include <algorithm>
  17. #include <sstream>
  18. namespace anki {
  19. //==============================================================================
  20. // Misc =
  21. //==============================================================================
  22. //==============================================================================
  23. /// Given a string that defines blending return the GLenum
  24. static GLenum blendToEnum(const CString& str)
  25. {
  26. // Dont make idiotic mistakes
  27. #define TXT_AND_ENUM(x) \
  28. if(str == #x) \
  29. { \
  30. return x; \
  31. }
  32. TXT_AND_ENUM(GL_ZERO)
  33. TXT_AND_ENUM(GL_ONE)
  34. TXT_AND_ENUM(GL_DST_COLOR)
  35. TXT_AND_ENUM(GL_ONE_MINUS_DST_COLOR)
  36. TXT_AND_ENUM(GL_SRC_ALPHA)
  37. TXT_AND_ENUM(GL_ONE_MINUS_SRC_ALPHA)
  38. TXT_AND_ENUM(GL_DST_ALPHA)
  39. TXT_AND_ENUM(GL_ONE_MINUS_DST_ALPHA)
  40. TXT_AND_ENUM(GL_SRC_ALPHA_SATURATE)
  41. TXT_AND_ENUM(GL_SRC_COLOR)
  42. TXT_AND_ENUM(GL_ONE_MINUS_SRC_COLOR);
  43. ANKI_LOGE("Incorrect blend enum");
  44. return 0;
  45. #undef TXT_AND_ENUM
  46. }
  47. //==============================================================================
  48. // MaterialVariable =
  49. //==============================================================================
  50. //==============================================================================
  51. MaterialVariable::~MaterialVariable()
  52. {}
  53. //==============================================================================
  54. template<typename T>
  55. Error MaterialVariableTemplate<T>::create(ResourceAllocator<U8> alloc,
  56. const CString& name, const T* x, U32 size)
  57. {
  58. Error err = ErrorCode::NONE;
  59. err = m_name.create(alloc, name);
  60. if(!err && size > 0)
  61. {
  62. err = m_data.create(alloc, size);
  63. if(!err)
  64. {
  65. for(U i = 0; i < size; i++)
  66. {
  67. m_data[i] = x[i];
  68. }
  69. }
  70. }
  71. return ErrorCode::NONE;
  72. }
  73. //==============================================================================
  74. template<typename T>
  75. MaterialVariableTemplate<T>* MaterialVariableTemplate<T>::_newInstance(
  76. const MaterialProgramCreator::Input& in,
  77. ResourceAllocator<U8> alloc, TempResourceAllocator<U8> talloc)
  78. {
  79. Error err = ErrorCode::NONE;
  80. MaterialVariableTemplate<T>* out = nullptr;
  81. TempResourceDArrayAuto<F32> floats(talloc);
  82. // Get the float values
  83. if(in.m_value.getSize() > 0)
  84. {
  85. // Has values
  86. U floatsNeeded = in.m_arraySize * (sizeof(T) / sizeof(F32));
  87. if(in.m_value.getSize() != floatsNeeded)
  88. {
  89. ANKI_LOGE("Incorrect number of values. Variable %s",
  90. &in.m_name[0]);
  91. return nullptr;
  92. }
  93. err = floats.create(floatsNeeded);
  94. if(err) return nullptr;
  95. auto it = in.m_value.getBegin();
  96. for(U i = 0; i < floatsNeeded; ++i)
  97. {
  98. F64 d;
  99. err = it->toF64(d);
  100. if(err) return nullptr;
  101. floats[i] = d;
  102. ++it;
  103. }
  104. }
  105. // Create new instance
  106. out = alloc.newInstance<MaterialVariableTemplate<T>>();
  107. if(!out) return nullptr;
  108. if(floats.getSize() > 0)
  109. {
  110. err = out->create(alloc, in.m_name.toCString(),
  111. (T*)&floats[0], in.m_arraySize);
  112. }
  113. else
  114. {
  115. // Buildin
  116. err = out->create(alloc, in.m_name.toCString(), nullptr, 0);
  117. }
  118. if(err && out)
  119. {
  120. alloc.deleteInstance(out);
  121. return nullptr;
  122. }
  123. // Set some values
  124. out->m_instanced = in.m_instanced;
  125. out->m_varType = in.m_type;
  126. out->m_textureUnit = in.m_binding;
  127. out->m_varBlkInfo.m_arraySize = in.m_arraySize;
  128. // Set UBO data
  129. if(out && in.m_inBlock)
  130. {
  131. out->m_varBlkInfo.m_offset = in.m_offset;
  132. ANKI_ASSERT(out->m_varBlkInfo.m_offset >= 0);
  133. out->m_varBlkInfo.m_arrayStride = in.m_arrayStride;
  134. out->m_varBlkInfo.m_matrixStride = in.m_matrixStride;
  135. }
  136. return out;
  137. }
  138. //==============================================================================
  139. // Material =
  140. //==============================================================================
  141. //==============================================================================
  142. Material::Material(ResourceAllocator<U8>& alloc)
  143. : m_varDict(10, Dictionary<MaterialVariable*>::hasher(),
  144. Dictionary<MaterialVariable*>::key_equal(), alloc)
  145. {}
  146. //==============================================================================
  147. Material::~Material()
  148. {
  149. auto alloc = m_resources->_getAllocator();
  150. m_progs.destroy(alloc);
  151. for(auto it : m_vars)
  152. {
  153. if(it)
  154. {
  155. MaterialVariable* mvar = &(*it);
  156. mvar->destroy(alloc);
  157. alloc.deleteInstance(mvar);
  158. }
  159. }
  160. m_vars.destroy(alloc);
  161. m_pplines.destroy(alloc);
  162. }
  163. //==============================================================================
  164. U Material::countShaders(ShaderType type) const
  165. {
  166. U count = 0;
  167. U tessCount = m_tessellation ? 2 : 1;
  168. switch(type)
  169. {
  170. case ShaderType::VERTEX:
  171. count = m_passesCount * m_lodsCount * tessCount;
  172. break;
  173. case ShaderType::TESSELLATION_CONTROL:
  174. if(m_tessellation)
  175. {
  176. count = m_passesCount;
  177. }
  178. break;
  179. case ShaderType::TESSELLATION_EVALUATION:
  180. if(m_tessellation)
  181. {
  182. count = m_passesCount;
  183. }
  184. break;
  185. case ShaderType::GEOMETRY:
  186. count = 0;
  187. break;
  188. case ShaderType::FRAGMENT:
  189. count = m_passesCount * m_lodsCount;
  190. break;
  191. default:
  192. ANKI_ASSERT(0);
  193. }
  194. return count;
  195. }
  196. //==============================================================================
  197. U Material::getShaderIndex(const RenderingKey key, ShaderType type) const
  198. {
  199. ANKI_ASSERT((U)key.m_pass < m_passesCount);
  200. ANKI_ASSERT(key.m_lod < m_lodsCount);
  201. if(key.m_tessellation)
  202. {
  203. ANKI_ASSERT(m_tessellation);
  204. }
  205. U tessCount = m_tessellation ? 2 : 1;
  206. U pass = enumToType(key.m_pass);
  207. U lod = key.m_lod;
  208. U tess = key.m_tessellation;
  209. U offset = 0;
  210. switch(type)
  211. {
  212. case ShaderType::FRAGMENT:
  213. offset += countShaders(ShaderType::GEOMETRY);
  214. case ShaderType::GEOMETRY:
  215. offset += countShaders(ShaderType::TESSELLATION_EVALUATION);
  216. case ShaderType::TESSELLATION_EVALUATION:
  217. offset += countShaders(ShaderType::TESSELLATION_CONTROL);
  218. case ShaderType::TESSELLATION_CONTROL:
  219. offset += countShaders(ShaderType::VERTEX);
  220. case ShaderType::VERTEX:
  221. offset += 0;
  222. break;
  223. default:
  224. ANKI_ASSERT(0);
  225. }
  226. U idx = MAX_U32;
  227. switch(type)
  228. {
  229. case ShaderType::VERTEX:
  230. // Like referencing an array of [pass][lod][tess]
  231. idx = pass * m_lodsCount * tessCount + lod * tessCount + tess;
  232. break;
  233. case ShaderType::TESSELLATION_CONTROL:
  234. // Like an array [pass]
  235. idx = pass;
  236. break;
  237. case ShaderType::TESSELLATION_EVALUATION:
  238. // Like an array [pass]
  239. idx = pass;
  240. break;
  241. case ShaderType::GEOMETRY:
  242. idx = 0;
  243. break;
  244. case ShaderType::FRAGMENT:
  245. // Like an array [pass][lod]
  246. idx = pass * m_lodsCount + lod;
  247. break;
  248. default:
  249. ANKI_ASSERT(0);
  250. }
  251. return offset + idx;
  252. }
  253. //==============================================================================
  254. ProgramResourcePointer& Material::getProgram(
  255. const RenderingKey key, ShaderType type)
  256. {
  257. ProgramResourcePointer& out = m_progs[getShaderIndex(key, type)];
  258. if(out.isLoaded())
  259. {
  260. ANKI_ASSERT(
  261. computeShaderTypeIndex(out->getGlProgram().getType()) == type);
  262. }
  263. return out;
  264. }
  265. //==============================================================================
  266. Error Material::getProgramPipeline(
  267. const RenderingKey& key, PipelineHandle& out)
  268. {
  269. ANKI_ASSERT(enumToType(key.m_pass) < m_passesCount);
  270. ANKI_ASSERT(key.m_lod < m_lodsCount);
  271. Error err = ErrorCode::NONE;
  272. U tessCount = 1;
  273. if(m_tessellation)
  274. {
  275. tessCount = 2;
  276. }
  277. else
  278. {
  279. ANKI_ASSERT(!key.m_tessellation);
  280. }
  281. U idx = enumToType(key.m_pass) * m_lodsCount * tessCount
  282. + key.m_lod * tessCount + key.m_tessellation;
  283. PipelineHandle& ppline = m_pplines[idx];
  284. // Lazily create it
  285. if(ANKI_UNLIKELY(!ppline.isCreated()))
  286. {
  287. Array<ShaderHandle, 5> progs;
  288. U progCount = 0;
  289. progs[progCount++] =
  290. getProgram(key, ShaderType::VERTEX)->getGlProgram();
  291. if(key.m_tessellation)
  292. {
  293. progs[progCount++] = getProgram(
  294. key, ShaderType::TESSELLATION_CONTROL)->getGlProgram();
  295. progs[progCount++] = getProgram(
  296. key, ShaderType::TESSELLATION_EVALUATION)->getGlProgram();
  297. }
  298. progs[progCount++] =
  299. getProgram(key, ShaderType::FRAGMENT)->getGlProgram();
  300. GrManager& gl = m_resources->getGrManager();
  301. CommandBufferHandle cmdBuff;
  302. ANKI_CHECK(cmdBuff.create(&gl));
  303. ANKI_CHECK(ppline.create(cmdBuff, &progs[0], &progs[0] + progCount));
  304. cmdBuff.flush();
  305. }
  306. out = ppline;
  307. return err;
  308. }
  309. //==============================================================================
  310. Error Material::load(const CString& filename, ResourceInitializer& init)
  311. {
  312. Error err = ErrorCode::NONE;
  313. m_resources = &init.m_resources;
  314. XmlDocument doc;
  315. ANKI_CHECK(doc.loadFile(filename, init.m_tempAlloc));
  316. XmlElement el;
  317. ANKI_CHECK(doc.getChildElement("material", el));
  318. ANKI_CHECK(parseMaterialTag(el , init));
  319. return err;
  320. }
  321. //==============================================================================
  322. Error Material::parseMaterialTag(const XmlElement& materialEl,
  323. ResourceInitializer& rinit)
  324. {
  325. Error err = ErrorCode::NONE;
  326. XmlElement el;
  327. // levelsOfDetail
  328. //
  329. XmlElement lodEl;
  330. ANKI_CHECK(materialEl.getChildElementOptional("levelsOfDetail", lodEl));
  331. if(lodEl)
  332. {
  333. I64 tmp;
  334. ANKI_CHECK(lodEl.getI64(tmp));
  335. m_lodsCount = (tmp < 1) ? 1 : tmp;
  336. }
  337. else
  338. {
  339. m_lodsCount = 1;
  340. }
  341. // shadow
  342. //
  343. XmlElement shadowEl;
  344. ANKI_CHECK(materialEl.getChildElementOptional("shadow", shadowEl));
  345. if(shadowEl)
  346. {
  347. I64 tmp;
  348. ANKI_CHECK(shadowEl.getI64(tmp));
  349. m_shadow = tmp;
  350. }
  351. // blendFunctions
  352. //
  353. XmlElement blendFunctionsEl;
  354. ANKI_CHECK(
  355. materialEl.getChildElementOptional("blendFunctions", blendFunctionsEl));
  356. if(blendFunctionsEl)
  357. {
  358. CString cstr;
  359. // sFactor
  360. ANKI_CHECK(blendFunctionsEl.getChildElement("sFactor", el));
  361. ANKI_CHECK(el.getText(cstr));
  362. m_blendingSfactor = blendToEnum(cstr);
  363. if(m_blendingSfactor == 0)
  364. {
  365. return ErrorCode::USER_DATA;
  366. }
  367. // dFactor
  368. ANKI_CHECK(blendFunctionsEl.getChildElement("dFactor", el));
  369. ANKI_CHECK(el.getText(cstr));
  370. m_blendingDfactor = blendToEnum(cstr);
  371. if(m_blendingDfactor == 0)
  372. {
  373. return ErrorCode::USER_DATA;
  374. }
  375. }
  376. else
  377. {
  378. m_passesCount = 2;
  379. }
  380. // depthTesting
  381. //
  382. XmlElement depthTestingEl;
  383. ANKI_CHECK(
  384. materialEl.getChildElementOptional("depthTesting", depthTestingEl));
  385. if(depthTestingEl)
  386. {
  387. I64 tmp;
  388. ANKI_CHECK(depthTestingEl.getI64(tmp));
  389. m_depthTesting = tmp;
  390. }
  391. // wireframe
  392. //
  393. XmlElement wireframeEl;
  394. ANKI_CHECK(materialEl.getChildElementOptional("wireframe", wireframeEl));
  395. if(wireframeEl)
  396. {
  397. I64 tmp;
  398. ANKI_CHECK(wireframeEl.getI64(tmp));
  399. m_wireframe = tmp;
  400. }
  401. // shaderProgram
  402. //
  403. ANKI_CHECK(materialEl.getChildElement("programs", el));
  404. MaterialProgramCreator loader(rinit.m_tempAlloc);
  405. ANKI_CHECK(loader.parseProgramsTag(el));
  406. m_tessellation = loader.hasTessellation();
  407. U tessCount = m_tessellation ? 2 : 1;
  408. // Alloc program vector
  409. ANKI_CHECK(m_progs.create(rinit.m_alloc,
  410. countShaders(ShaderType::VERTEX)
  411. + countShaders(ShaderType::TESSELLATION_CONTROL)
  412. + countShaders(ShaderType::TESSELLATION_EVALUATION)
  413. + countShaders(ShaderType::GEOMETRY)
  414. + countShaders(ShaderType::FRAGMENT)));
  415. // Aloc progam descriptors
  416. ANKI_CHECK(m_pplines.create(rinit.m_alloc,
  417. m_passesCount * m_lodsCount * tessCount));
  418. m_hash = 0;
  419. for(ShaderType shader = ShaderType::VERTEX;
  420. shader <= ShaderType::FRAGMENT;
  421. ++shader)
  422. {
  423. Bool isTessellationShader = shader == ShaderType::TESSELLATION_CONTROL
  424. || shader == ShaderType::TESSELLATION_EVALUATION;
  425. if(!m_tessellation && isTessellationShader)
  426. {
  427. // Skip tessellation if not enabled
  428. continue;
  429. }
  430. if(shader == ShaderType::GEOMETRY)
  431. {
  432. // Skip geometry for now
  433. continue;
  434. }
  435. for(U level = 0; level < m_lodsCount; ++level)
  436. {
  437. if(level > 0 && isTessellationShader)
  438. {
  439. continue;
  440. }
  441. for(U pid = 0; pid < m_passesCount; ++pid)
  442. {
  443. for(U tess = 0; tess < tessCount; ++tess)
  444. {
  445. if(tess == 0 && isTessellationShader)
  446. {
  447. continue;
  448. }
  449. if(tess > 0 && shader == ShaderType::FRAGMENT)
  450. {
  451. continue;
  452. }
  453. TempResourceString src;
  454. TempResourceString::ScopeDestroyer srcd(
  455. &src, rinit.m_tempAlloc);
  456. ANKI_CHECK(src.sprintf(
  457. rinit.m_tempAlloc,
  458. "%s\n"
  459. "#define LOD %u\n"
  460. "#define PASS %u\n"
  461. "#define TESSELLATION %u\n"
  462. "%s\n",
  463. &rinit.m_resources._getShadersPrependedSource()[0],
  464. level, pid, tess, &loader.getProgramSource(shader)[0]));
  465. TempResourceString filename;
  466. TempResourceString::ScopeDestroyer filenamed(
  467. &filename, rinit.m_tempAlloc);
  468. ANKI_CHECK(createProgramSourceToCache(src, filename));
  469. RenderingKey key((Pass)pid, level, tess);
  470. ProgramResourcePointer& progr = getProgram(key, shader);
  471. ANKI_CHECK(
  472. progr.load(filename.toCString(), &rinit.m_resources));
  473. // Update the hash
  474. m_hash ^= computeHash(&src[0], src.getLength());
  475. }
  476. }
  477. }
  478. }
  479. ANKI_CHECK(populateVariables(loader));
  480. // Get uniform block size
  481. ANKI_ASSERT(m_progs.getSize() > 0);
  482. m_shaderBlockSize = loader.getUniformBlockSize();
  483. return err;
  484. }
  485. //==============================================================================
  486. Error Material::createProgramSourceToCache(
  487. const TempResourceString& source, TempResourceString& out)
  488. {
  489. Error err = ErrorCode::NONE;
  490. auto alloc = m_resources->_getTempAllocator();
  491. // Create the hash
  492. U64 h = computeHash(&source[0], source.getLength());
  493. TempResourceString prefix;
  494. TempResourceString::ScopeDestroyer prefixd(&prefix, alloc);
  495. ANKI_CHECK(prefix.toString(alloc, h));
  496. // Create path
  497. ANKI_CHECK(out.sprintf(alloc, "%s/mtl_%s.glsl",
  498. &m_resources->_getCacheDirectory()[0],
  499. &prefix[0]));
  500. // If file not exists write it
  501. if(!fileExists(out.toCString()))
  502. {
  503. // If not create it
  504. File f;
  505. ANKI_CHECK(f.open(out.toCString(), File::OpenFlag::WRITE));
  506. ANKI_CHECK(f.writeText("%s\n", &source[0]));
  507. }
  508. return err;
  509. }
  510. //==============================================================================
  511. Error Material::populateVariables(const MaterialProgramCreator& loader)
  512. {
  513. Error err = ErrorCode::NONE;
  514. U varCount = 0;
  515. for(const auto& in : loader.getInputVariables())
  516. {
  517. if(!in.m_constant)
  518. {
  519. ++varCount;
  520. }
  521. }
  522. ANKI_CHECK(m_vars.create(m_resources->_getAllocator(), varCount));
  523. varCount = 0;
  524. for(const auto& in : loader.getInputVariables())
  525. {
  526. if(in.m_constant)
  527. {
  528. continue;
  529. }
  530. MaterialVariable* mtlvar = nullptr;
  531. switch(in.m_type)
  532. {
  533. // samplers
  534. case ShaderVariableDataType::SAMPLER_2D:
  535. case ShaderVariableDataType::SAMPLER_CUBE:
  536. {
  537. TextureResourcePointer tp;
  538. if(in.m_value.getSize() > 0)
  539. {
  540. ANKI_CHECK(tp.load(
  541. in.m_value.getBegin()->toCString(), m_resources));
  542. }
  543. auto alloc = m_resources->_getAllocator();
  544. MaterialVariableTemplate<TextureResourcePointer>* tvar =
  545. alloc.newInstance<
  546. MaterialVariableTemplate<TextureResourcePointer>>();
  547. if(tvar)
  548. {
  549. err = tvar->create(alloc, in.m_name.toCString(), &tp, 1);
  550. if(err)
  551. {
  552. alloc.deleteInstance(tvar);
  553. tvar = nullptr;
  554. }
  555. }
  556. mtlvar = tvar;
  557. mtlvar->m_varBlkInfo.m_arraySize = 1;
  558. mtlvar->m_textureUnit = in.m_binding;
  559. }
  560. break;
  561. case ShaderVariableDataType::FLOAT:
  562. mtlvar = MaterialVariableTemplate<F32>::_newInstance(in,
  563. m_resources->_getAllocator(), m_resources->_getTempAllocator());
  564. break;
  565. case ShaderVariableDataType::VEC2:
  566. mtlvar = MaterialVariableTemplate<Vec2>::_newInstance(in,
  567. m_resources->_getAllocator(), m_resources->_getTempAllocator());
  568. break;
  569. case ShaderVariableDataType::VEC3:
  570. mtlvar = MaterialVariableTemplate<Vec3>::_newInstance(in,
  571. m_resources->_getAllocator(), m_resources->_getTempAllocator());
  572. break;
  573. case ShaderVariableDataType::VEC4:
  574. mtlvar = MaterialVariableTemplate<Vec4>::_newInstance(in,
  575. m_resources->_getAllocator(), m_resources->_getTempAllocator());
  576. break;
  577. case ShaderVariableDataType::MAT3:
  578. mtlvar = MaterialVariableTemplate<Mat3>::_newInstance(in,
  579. m_resources->_getAllocator(), m_resources->_getTempAllocator());
  580. break;
  581. case ShaderVariableDataType::MAT4:
  582. mtlvar = MaterialVariableTemplate<Mat4>::_newInstance(in,
  583. m_resources->_getAllocator(), m_resources->_getTempAllocator());
  584. break;
  585. // default is error
  586. default:
  587. ANKI_ASSERT(0);
  588. }
  589. if(mtlvar == nullptr)
  590. {
  591. return ErrorCode::USER_DATA;
  592. }
  593. m_vars[varCount++] = mtlvar;
  594. }
  595. return ErrorCode::NONE;
  596. }
  597. } // end namespace anki