GlProgram.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
  1. // Copyright (C) 2014, Panagiotis Christopoulos Charitos.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include "anki/gl/GlProgram.h"
  6. #include "anki/util/StringList.h"
  7. #include "anki/core/Logger.h"
  8. #define ANKI_DUMP_SHADERS ANKI_DEBUG
  9. #if ANKI_DUMP_SHADERS
  10. # include "anki/util/File.h"
  11. #endif
  12. #include <sstream>
  13. #include <iomanip>
  14. namespace anki {
  15. //==============================================================================
  16. // GlProgramVariable =
  17. //==============================================================================
  18. //==============================================================================
  19. namespace {
  20. #if ANKI_ASSERTIONS
  21. // Template functions that return the GL type using an AnKi type
  22. template<typename T>
  23. static Bool checkType(GLenum glDataType);
  24. template<>
  25. Bool checkType<F32>(GLenum glDataType)
  26. {
  27. return glDataType == GL_FLOAT;
  28. }
  29. template<>
  30. Bool checkType<Vec2>(GLenum glDataType)
  31. {
  32. return glDataType == GL_FLOAT_VEC2;
  33. }
  34. template<>
  35. Bool checkType<Vec3>(GLenum glDataType)
  36. {
  37. return glDataType == GL_FLOAT_VEC3;
  38. }
  39. template<>
  40. Bool checkType<Vec4>(GLenum glDataType)
  41. {
  42. return glDataType == GL_FLOAT_VEC4;
  43. }
  44. template<>
  45. Bool checkType<Mat3>(GLenum glDataType)
  46. {
  47. return glDataType == GL_FLOAT_MAT3;
  48. }
  49. template<>
  50. Bool checkType<Mat4>(GLenum glDataType)
  51. {
  52. return glDataType == GL_FLOAT_MAT4;
  53. }
  54. #endif
  55. static Bool isSampler(GLenum type)
  56. {
  57. Bool is =
  58. type == GL_SAMPLER_2D
  59. || type == GL_SAMPLER_2D_SHADOW
  60. || type == GL_UNSIGNED_INT_SAMPLER_2D
  61. || type == GL_SAMPLER_2D_ARRAY_SHADOW
  62. || type == GL_SAMPLER_2D_ARRAY
  63. || type == GL_SAMPLER_CUBE
  64. #if ANKI_GL == ANKI_GL_DESKTOP
  65. || type == GL_SAMPLER_2D_MULTISAMPLE
  66. #endif
  67. ;
  68. return is;
  69. }
  70. } // end anonymous namespace
  71. //==============================================================================
  72. const GlProgramBlock* GlProgramVariable::getBlock() const
  73. {
  74. ANKI_ASSERT(m_progData);
  75. if(m_blockIdx != -1)
  76. {
  77. ANKI_ASSERT((PtrSize)m_blockIdx < m_progData->m_blocks.size());
  78. }
  79. return (m_blockIdx != -1) ? &m_progData->m_blocks[m_blockIdx] : nullptr;
  80. }
  81. //==============================================================================
  82. template<typename T>
  83. void GlProgramVariable::writeClientMemorySanityChecks(
  84. void* buffBase, U32 buffSize,
  85. const T arr[], U32 size) const
  86. {
  87. // Check pointers
  88. ANKI_ASSERT(buffBase != nullptr && arr != nullptr);
  89. // Check T
  90. ANKI_ASSERT(checkType<T>(m_dataType));
  91. // Check array size
  92. ANKI_ASSERT(size <= m_arrSize && size > 0);
  93. // Check if var in block
  94. ANKI_ASSERT(m_blockIdx != -1);
  95. ANKI_ASSERT(m_offset != -1 && m_arrStride != -1);
  96. // Check if there is space
  97. ANKI_ASSERT(getBlock()->getSize() <= buffSize);
  98. // arrStride should not be zero if array
  99. ANKI_ASSERT(!(size > 1 && m_arrStride == 0));
  100. }
  101. //==============================================================================
  102. template<typename T>
  103. void GlProgramVariable::writeClientMemoryInternal(
  104. void* buffBase, U32 buffSize, const T arr[], U32 size) const
  105. {
  106. writeClientMemorySanityChecks<T>(buffBase, buffSize, arr, size);
  107. U8* buff = (U8*)buffBase + m_offset;
  108. for(U32 i = 0; i < size; i++)
  109. {
  110. ANKI_ASSERT((U8*)buff + sizeof(T) <= (U8*)buffBase + buffSize);
  111. T* ptr = (T*)buff;
  112. *ptr = arr[i];
  113. buff += m_arrStride;
  114. }
  115. }
  116. //==============================================================================
  117. template<typename T, typename Vec>
  118. void GlProgramVariable::writeClientMemoryInternalMatrix(
  119. void* buffBase, U32 buffSize, const T arr[], U32 size) const
  120. {
  121. writeClientMemorySanityChecks<T>(buffBase, buffSize, arr, size);
  122. ANKI_ASSERT(m_matrixStride != -1 && m_matrixStride >= (I32)sizeof(Vec));
  123. U8* buff = (U8*)buffBase + m_offset;
  124. for(U32 i = 0; i < size; i++)
  125. {
  126. U8* subbuff = buff;
  127. T matrix = arr[i];
  128. matrix.transpose();
  129. for(U j = 0; j < sizeof(T) / sizeof(Vec); j++)
  130. {
  131. ANKI_ASSERT(subbuff + sizeof(Vec) <= (U8*)buffBase + buffSize);
  132. Vec* ptr = (Vec*)subbuff;
  133. *ptr = matrix.getRow(j);
  134. subbuff += m_matrixStride;
  135. }
  136. buff += m_arrStride;
  137. }
  138. }
  139. //==============================================================================
  140. void GlProgramVariable::writeClientMemory(void* buff, U32 buffSize,
  141. const F32 arr[], U32 size) const
  142. {
  143. writeClientMemoryInternal(buff, buffSize, arr, size);
  144. }
  145. //==============================================================================
  146. void GlProgramVariable::writeClientMemory(void* buff, U32 buffSize,
  147. const Vec2 arr[], U32 size) const
  148. {
  149. writeClientMemoryInternal(buff, buffSize, arr, size);
  150. }
  151. //==============================================================================
  152. void GlProgramVariable::writeClientMemory(void* buff, U32 buffSize,
  153. const Vec3 arr[], U32 size) const
  154. {
  155. writeClientMemoryInternal(buff, buffSize, arr, size);
  156. }
  157. //==============================================================================
  158. void GlProgramVariable::writeClientMemory(void* buff, U32 buffSize,
  159. const Vec4 arr[], U32 size) const
  160. {
  161. writeClientMemoryInternal(buff, buffSize, arr, size);
  162. }
  163. //==============================================================================
  164. void GlProgramVariable::writeClientMemory(void* buff, U32 buffSize,
  165. const Mat3 arr[], U32 size) const
  166. {
  167. writeClientMemoryInternalMatrix<Mat3, Vec3>(buff, buffSize, arr, size);
  168. }
  169. //==============================================================================
  170. void GlProgramVariable::writeClientMemory(void* buff, U32 buffSize,
  171. const Mat4 arr[], U32 size) const
  172. {
  173. writeClientMemoryInternalMatrix<Mat4, Vec4>(buff, buffSize, arr, size);
  174. }
  175. //==============================================================================
  176. // GlProgram =
  177. //==============================================================================
  178. /// Check if the variable name is worth beeng processed.
  179. ///
  180. /// In case of uniform arrays some implementations (nVidia) on
  181. /// GL_ACTIVE_UNIFORMS they return the number of uniforms that are inside that
  182. /// uniform array in addition to the first element (it will count for example
  183. /// the float_arr[9]). But other implementations don't (Mali T6xx). Also in
  184. /// some cases with big arrays (IS shader) this will overpopulate the uniforms
  185. /// vector and hash map. So, to solve this if the uniform name has something
  186. /// like this "[N]" where N != 0 then ignore the uniform and put it as array
  187. static Bool sanitizeSymbolName(char* name)
  188. {
  189. ANKI_ASSERT(name && strlen(name) > 1);
  190. // Kick everything that starts with "gl" or "_"
  191. if(name[0] == '_')
  192. {
  193. return false;
  194. }
  195. if(strlen(name) > 2 && name[0] == 'g' && name[1] == 'l')
  196. {
  197. return false;
  198. }
  199. // Search for arrays
  200. char* c = strchr(name, '[');
  201. if(c != nullptr)
  202. {
  203. // Found bracket
  204. if(strstr(name, "[0]") == nullptr)
  205. {
  206. // Found something "[N]" where N != 0
  207. return false;
  208. }
  209. else
  210. {
  211. // Found "[0]"
  212. if(strlen(c) != 3)
  213. {
  214. // It's something like "bla[0].xxxxxxx" so _forget_ it
  215. return false;
  216. }
  217. *c = '\0'; // Cut the bracket part
  218. }
  219. }
  220. return true;
  221. }
  222. const U SYMBOL_MAX_NAME_LENGTH = 256;
  223. //==============================================================================
  224. GlProgram& GlProgram::operator=(GlProgram&& b)
  225. {
  226. destroy();
  227. Base::operator=(std::forward<Base>(b));
  228. m_type = b.m_type;
  229. b.m_type = 0;
  230. m_data = b.m_data;
  231. b.m_data = nullptr;
  232. // Fix data
  233. m_data->m_prog = this;
  234. return *this;
  235. }
  236. //==============================================================================
  237. void GlProgram::create(GLenum type, const CString& source,
  238. const GlGlobalHeapAllocator<U8>& alloc, const CString& cacheDir)
  239. {
  240. try
  241. {
  242. createInternal(type, source, alloc, cacheDir);
  243. }
  244. catch(const std::exception& e)
  245. {
  246. destroy();
  247. throw ANKI_EXCEPTION("") << e;
  248. }
  249. }
  250. //==============================================================================
  251. void GlProgram::createInternal(GLenum type, const CString& source,
  252. const GlGlobalHeapAllocator<U8>& alloc_, const CString& cacheDir)
  253. {
  254. ANKI_ASSERT(source);
  255. ANKI_ASSERT(!isCreated() && m_data == nullptr);
  256. GlGlobalHeapAllocator<U8> alloc = alloc_;
  257. m_data = alloc.newInstance<GlProgramData>(alloc);
  258. m_type = type;
  259. // 1) Append some things in the source string
  260. //
  261. U32 version;
  262. {
  263. GLint major, minor;
  264. glGetIntegerv(GL_MAJOR_VERSION, &major);
  265. glGetIntegerv(GL_MINOR_VERSION, &minor);
  266. version = major * 100 + minor * 10;
  267. }
  268. String fullSrc(alloc);
  269. #if ANKI_GL == ANKI_GL_DESKTOP
  270. fullSrc.sprintf("#version %d core\n%s\n", version, &source[0]);
  271. #else
  272. fullSrc.sprintf("#version %d es\n%s\n", version, &source[0]);
  273. #endif
  274. // 2) Gen name, create, compile and link
  275. //
  276. const char* sourceStrs[1] = {nullptr};
  277. sourceStrs[0] = &fullSrc[0];
  278. m_glName = glCreateShaderProgramv(m_type, 1, sourceStrs);
  279. if(m_glName == 0)
  280. {
  281. throw ANKI_EXCEPTION("glCreateShaderProgramv() failed");
  282. }
  283. #if ANKI_DUMP_SHADERS
  284. {
  285. const char* ext;
  286. switch(m_type)
  287. {
  288. case GL_VERTEX_SHADER:
  289. ext = ".vert";
  290. break;
  291. case GL_TESS_CONTROL_SHADER:
  292. ext = ".tesc";
  293. break;
  294. case GL_TESS_EVALUATION_SHADER:
  295. ext = ".tese";
  296. break;
  297. case GL_GEOMETRY_SHADER:
  298. ext = ".geom";
  299. break;
  300. case GL_FRAGMENT_SHADER:
  301. ext = ".frag";
  302. break;
  303. case GL_COMPUTE_SHADER:
  304. ext = ".comp";
  305. break;
  306. default:
  307. ext = nullptr;
  308. ANKI_ASSERT(0);
  309. }
  310. std::stringstream fname;
  311. fname << cacheDir << "/"
  312. << std::setfill('0') << std::setw(4) << (U32)m_glName << ext;
  313. File file(fname.str().c_str(), File::OpenFlag::WRITE);
  314. file.writeText("%s", &fullSrc[0]);
  315. }
  316. #endif
  317. GLint status = GL_FALSE;
  318. glGetProgramiv(m_glName, GL_LINK_STATUS, &status);
  319. if(status == GL_FALSE)
  320. {
  321. GLint infoLen = 0;
  322. GLint charsWritten = 0;
  323. String infoLog(alloc);
  324. static const char* padding =
  325. "======================================="
  326. "=======================================";
  327. glGetProgramiv(m_glName, GL_INFO_LOG_LENGTH, &infoLen);
  328. infoLog.resize(infoLen + 1);
  329. glGetProgramInfoLog(m_glName, infoLen, &charsWritten, &infoLog[0]);
  330. String err(alloc);
  331. err.sprintf("Shader compile failed (type %x):\n%s\n%s\n%s\n",
  332. m_type, padding, &infoLog[0], padding);
  333. // Prettyfy source
  334. StringList lines(
  335. StringList::splitString(fullSrc.toCString(), '\n', alloc));
  336. I lineno = 0;
  337. for(const String& line : lines)
  338. {
  339. String tmp(alloc);
  340. tmp.sprintf("%4d: %s\n", ++lineno, &line[0]);
  341. err += tmp;
  342. }
  343. err += padding;
  344. throw ANKI_EXCEPTION("%s", &err[0]);
  345. }
  346. // 3) Populate with vars and blocks
  347. //
  348. static Array<GLenum, 5> interfaces = {{
  349. GL_UNIFORM_BLOCK, GL_SHADER_STORAGE_BLOCK,
  350. GL_UNIFORM, GL_BUFFER_VARIABLE, GL_PROGRAM_INPUT}};
  351. // First get the count of active resources and name length
  352. Array<GLint, interfaces.size()> count; // Count of symbol after
  353. // kicking some symbols
  354. Array<GLint, interfaces.size()> countReal; // Count of symbols as GL
  355. // reported them
  356. U namesLen = 0;
  357. for(U i = 0; i < interfaces.size(); i++)
  358. {
  359. GLint cnt;
  360. glGetProgramInterfaceiv(
  361. m_glName, interfaces[i], GL_ACTIVE_RESOURCES, &cnt);
  362. count[i] = 0;
  363. countReal[i] = cnt;
  364. for(U c = 0; c < (U)cnt; c++)
  365. {
  366. GLint len = 0;
  367. Array<char, SYMBOL_MAX_NAME_LENGTH> name;
  368. // Get and check the name
  369. glGetProgramResourceName(m_glName, interfaces[i], c,
  370. name.size(), &len, &name[0]);
  371. ANKI_ASSERT((U)len < name.size());
  372. ANKI_ASSERT((U)len == strlen(&name[0]));
  373. if(!sanitizeSymbolName(&name[0]))
  374. {
  375. continue;
  376. }
  377. // Recalc length after trimming
  378. len = std::strlen(&name[0]);
  379. namesLen += (U)len + 1;
  380. ++count[i];
  381. }
  382. }
  383. m_data->m_names = reinterpret_cast<char*>(alloc.allocate(namesLen));
  384. char* namesPtr = m_data->m_names;
  385. // Populate the blocks
  386. if(count[0] + count[1] > 0)
  387. {
  388. m_data->m_blocks.resize(count[0] + count[1]);
  389. initBlocksOfType(GL_UNIFORM_BLOCK,
  390. countReal[0], 0, namesPtr, namesLen);
  391. initBlocksOfType(GL_SHADER_STORAGE_BLOCK,
  392. countReal[1], count[0], namesPtr, namesLen);
  393. }
  394. // Populate the variables
  395. if(count[2] + count[3] + count[4] > 0)
  396. {
  397. m_data->m_variables.resize(count[2] + count[3] + count[4]);
  398. initVariablesOfType(GL_UNIFORM,
  399. countReal[2], 0, 0, namesPtr, namesLen);
  400. initVariablesOfType(GL_BUFFER_VARIABLE,
  401. countReal[3], count[2], count[0], namesPtr, namesLen);
  402. initVariablesOfType(GL_PROGRAM_INPUT,
  403. countReal[4], count[2] + count[3], 0, namesPtr, namesLen);
  404. // Sanity checks
  405. // Iterate all samples and make sure they have set the unit explicitly
  406. std::unordered_map<
  407. U,
  408. U,
  409. std::hash<U>,
  410. std::equal_to<U>,
  411. HeapAllocator<std::pair<U, U>>> unitToCount;
  412. for(const GlProgramVariable& var : m_data->m_variables)
  413. {
  414. if(isSampler(var.m_dataType))
  415. {
  416. if(unitToCount.find(var.m_texUnit) == unitToCount.end())
  417. {
  418. // Doesn't exit
  419. unitToCount[var.m_texUnit] = 1;
  420. }
  421. else
  422. {
  423. unitToCount[var.m_texUnit] = unitToCount[var.m_texUnit] + 1;
  424. }
  425. }
  426. }
  427. for(auto pair : unitToCount)
  428. {
  429. if(pair.second != 1)
  430. {
  431. ANKI_LOGW("It is advised to explicitly set the unit "
  432. "for samplers");
  433. }
  434. }
  435. }
  436. ANKI_ASSERT(namesLen == 0);
  437. }
  438. //==============================================================================
  439. void GlProgram::destroy()
  440. {
  441. if(m_glName != 0)
  442. {
  443. glDeleteProgram(m_glName);
  444. m_glName = 0;
  445. }
  446. if(m_data != nullptr)
  447. {
  448. auto alloc = m_data->m_variables.get_allocator();
  449. alloc.deleteInstance(m_data);
  450. m_data = nullptr;
  451. }
  452. }
  453. //==============================================================================
  454. void GlProgram::initVariablesOfType(
  455. GLenum interface, U activeCount, U indexOffset, U blkIndexOffset,
  456. char*& namesPtr, U& namesLen)
  457. {
  458. U index = indexOffset;
  459. for(U i = 0; i < activeCount; i++)
  460. {
  461. // Get name
  462. Array<char, SYMBOL_MAX_NAME_LENGTH> name;
  463. GLint len;
  464. glGetProgramResourceName(
  465. m_glName, interface, i, name.size(), &len, &name[0]);
  466. if(!sanitizeSymbolName(&name[0]))
  467. {
  468. continue;
  469. }
  470. len = strlen(&name[0]);
  471. strcpy(namesPtr, &name[0]);
  472. // Get the properties
  473. Array<GLenum, 7> prop = {{GL_LOCATION, GL_TYPE, GL_ARRAY_SIZE,
  474. GL_ARRAY_STRIDE, GL_OFFSET, GL_MATRIX_STRIDE, GL_BLOCK_INDEX}};
  475. Array<GLint, 7> out = {{-1, GL_NONE, -1, -1, -1, -1, -1}};
  476. U fromIdx = 0, toIdx = 0;
  477. GlProgramVariable::Type akType = GlProgramVariable::Type::UNIFORM;
  478. switch(interface)
  479. {
  480. case GL_UNIFORM:
  481. fromIdx = 0;
  482. toIdx = prop.getSize() - 1;
  483. akType = GlProgramVariable::Type::UNIFORM;
  484. break;
  485. case GL_BUFFER_VARIABLE:
  486. fromIdx = 1;
  487. toIdx = prop.getSize() - 1;
  488. akType = GlProgramVariable::Type::BUFFER;
  489. break;
  490. case GL_PROGRAM_INPUT:
  491. fromIdx = 0;
  492. toIdx = 2;
  493. akType = GlProgramVariable::Type::INPUT;
  494. break;
  495. default:
  496. ANKI_ASSERT(0);
  497. };
  498. GLsizei outCount = 0;
  499. GLsizei count = toIdx - fromIdx + 1;
  500. glGetProgramResourceiv(m_glName, interface, i,
  501. count, &prop[fromIdx],
  502. count, &outCount, &out[fromIdx]);
  503. if(count != outCount)
  504. {
  505. throw ANKI_EXCEPTION("glGetProgramResourceiv() didn't got all "
  506. "the params");
  507. }
  508. // Create and populate the variable
  509. ANKI_ASSERT(index < m_data->m_variables.size());
  510. GlProgramVariable& var = m_data->m_variables[index++];
  511. var.m_type = akType;
  512. var.m_name = namesPtr;
  513. var.m_progData = m_data;
  514. var.m_dataType = out[1];
  515. ANKI_ASSERT(var.m_dataType != GL_NONE);
  516. var.m_arrSize = out[2];
  517. if(var.m_arrSize == 0)
  518. {
  519. var.m_arrSize = 1;
  520. }
  521. if(interface == GL_UNIFORM || interface == GL_PROGRAM_INPUT)
  522. {
  523. var.m_loc = out[0];
  524. }
  525. if(interface == GL_UNIFORM || interface == GL_BUFFER_VARIABLE)
  526. {
  527. var.m_arrStride = out[3];
  528. var.m_offset = out[4];
  529. var.m_matrixStride = out[5];
  530. }
  531. // Block index
  532. if(out[6] >= 0)
  533. {
  534. ANKI_ASSERT(interface != GL_PROGRAM_INPUT);
  535. U blkIdx = blkIndexOffset + out[6];
  536. ANKI_ASSERT(blkIdx < m_data->m_blocks.size());
  537. // Connect block with variable
  538. ANKI_ASSERT(m_data->m_blocks[blkIdx].m_variablesCount < 255);
  539. m_data->m_blocks[blkIdx].m_variableIdx[
  540. m_data->m_blocks[blkIdx].m_variablesCount++];
  541. var.m_blockIdx = blkIdx;
  542. }
  543. // Sampler unit
  544. if(isSampler(var.m_dataType))
  545. {
  546. GLint unit = -1;
  547. glGetUniformiv(m_glName, var.m_loc, &unit);
  548. ANKI_ASSERT(unit > -1);
  549. var.m_texUnit = unit;
  550. }
  551. // Add to dict
  552. ANKI_ASSERT(m_data->m_variablesDict.find(var.m_name)
  553. == m_data->m_variablesDict.end());
  554. m_data->m_variablesDict[var.m_name] = &var;
  555. // Advance
  556. namesPtr += len + 1;
  557. namesLen -= len + 1;
  558. }
  559. }
  560. //==============================================================================
  561. void GlProgram::initBlocksOfType(
  562. GLenum interface, U activeCount, U indexOffset,
  563. char*& namesPtr, U& namesLen)
  564. {
  565. U index = indexOffset;
  566. for(U i = 0; i < activeCount; i++)
  567. {
  568. // Get name
  569. Array<char, SYMBOL_MAX_NAME_LENGTH> name;
  570. GLint len;
  571. glGetProgramResourceName(
  572. m_glName, interface, i, name.size(), &len, &name[0]);
  573. if(!sanitizeSymbolName(&name[0]))
  574. {
  575. continue;
  576. }
  577. len = strlen(&name[0]);
  578. strcpy(namesPtr, &name[0]);
  579. // Get the properties
  580. Array<GLenum, 2> prop = {{GL_BUFFER_BINDING, GL_BUFFER_DATA_SIZE}};
  581. Array<GLint, 2> out = {{-1, -1}};
  582. GLsizei outCount = 0;
  583. glGetProgramResourceiv(m_glName, interface, i,
  584. prop.getSize(), &prop[0],
  585. out.getSize(), &outCount, &out[0]);
  586. if(prop.getSize() != (U)outCount)
  587. {
  588. throw ANKI_EXCEPTION("glGetProgramResourceiv() didn't got all "
  589. "the params");
  590. }
  591. GlProgramBlock::Type akType = GlProgramBlock::Type::UNIFORM;
  592. switch(interface)
  593. {
  594. case GL_UNIFORM_BLOCK:
  595. akType = GlProgramBlock::Type::UNIFORM;
  596. break;
  597. case GL_SHADER_STORAGE_BLOCK:
  598. akType = GlProgramBlock::Type::SHADER_STORAGE;
  599. break;
  600. default:
  601. ANKI_ASSERT(0);
  602. }
  603. // Create and populate the block
  604. GlProgramBlock& block = m_data->m_blocks[index++];
  605. block.m_type = akType;
  606. block.m_name = namesPtr;
  607. block.m_size = out[1];
  608. block.m_progData = m_data;
  609. ANKI_ASSERT(out[1] > 0);
  610. block.m_bindingPoint = out[0];
  611. ANKI_ASSERT(out[0] >= 0);
  612. // Add to dict
  613. ANKI_ASSERT(m_data->m_blocksDict.find(block.m_name)
  614. == m_data->m_blocksDict.end());
  615. m_data->m_blocksDict[block.m_name] = &block;
  616. // Advance
  617. namesPtr += len + 1;
  618. namesLen -= len + 1;
  619. }
  620. }
  621. //==============================================================================
  622. const GlProgramVariable* GlProgram::tryFindVariable(const CString& name) const
  623. {
  624. ANKI_ASSERT(isCreated() && m_data);
  625. auto it = m_data->m_variablesDict.find(name);
  626. return (it != m_data->m_variablesDict.end()) ? it->second : nullptr;
  627. }
  628. //==============================================================================
  629. const GlProgramVariable& GlProgram::findVariable(const CString& name) const
  630. {
  631. ANKI_ASSERT(isCreated() && m_data);
  632. const GlProgramVariable* var = tryFindVariable(name);
  633. if(var == nullptr)
  634. {
  635. throw ANKI_EXCEPTION("Variable not found: %s", &name[0]);
  636. }
  637. return *var;
  638. }
  639. //==============================================================================
  640. const GlProgramBlock* GlProgram::tryFindBlock(const CString& name) const
  641. {
  642. ANKI_ASSERT(isCreated() && m_data);
  643. auto it = m_data->m_blocksDict.find(name);
  644. return (it != m_data->m_blocksDict.end()) ? it->second : nullptr;
  645. }
  646. //==============================================================================
  647. const GlProgramBlock& GlProgram::findBlock(const CString& name) const
  648. {
  649. ANKI_ASSERT(isCreated() && m_data);
  650. const GlProgramBlock* var = tryFindBlock(name);
  651. if(var == nullptr)
  652. {
  653. throw ANKI_EXCEPTION("Buffer not found: %s", &name[0]);
  654. }
  655. return *var;
  656. }
  657. } // end namespace anki