BsGLSLParamParser.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "GLSL/BsGLSLParamParser.h"
  4. namespace bs { namespace ct
  5. {
  6. INT32 GLSLAttribute::matchesName(const String& name)
  7. {
  8. if (name.length() >= mName.length())
  9. {
  10. if (name.substr(0, mName.length()) == mName)
  11. {
  12. String indexStr = name.substr(mName.length(), name.length());
  13. return parseUINT32(indexStr, 0);
  14. }
  15. }
  16. return -1;
  17. }
  18. List<VertexElement> GLSLParamParser::buildVertexDeclaration(GLuint glProgram)
  19. {
  20. GLint numAttributes = 0;
  21. glGetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTES, &numAttributes);
  22. BS_CHECK_GL_ERROR();
  23. GLint maxNameSize = 0;
  24. glGetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxNameSize);
  25. BS_CHECK_GL_ERROR();
  26. GLchar* attributeName = (GLchar*)bs_alloc(sizeof(GLchar)* maxNameSize);
  27. List<VertexElement> elementList;
  28. for (GLint i = 0; i < numAttributes; i++)
  29. {
  30. GLint attribSize = 0;
  31. GLenum attribType = 0;
  32. glGetActiveAttrib(glProgram, i, maxNameSize, nullptr, &attribSize, &attribType, attributeName);
  33. BS_CHECK_GL_ERROR();
  34. VertexElementSemantic semantic = VES_POSITION;
  35. UINT16 index = 0;
  36. if (attribNameToElementSemantic(attributeName, semantic, index))
  37. {
  38. VertexElementType type = glTypeToAttributeType(attribType);
  39. UINT32 slot = glGetAttribLocation(glProgram, attributeName);
  40. BS_CHECK_GL_ERROR();
  41. elementList.push_back(VertexElement(0, slot, type, semantic, index));
  42. }
  43. else
  44. {
  45. // Ignore built-in attributes
  46. if(memcmp(attributeName, "gl_", 3) != 0)
  47. LOGWRN("Cannot determine vertex input attribute type for attribute: " + String(attributeName));
  48. }
  49. }
  50. bs_free(attributeName);
  51. return elementList;
  52. }
  53. VertexElementType GLSLParamParser::glTypeToAttributeType(GLenum glType)
  54. {
  55. switch (glType)
  56. {
  57. case GL_FLOAT:
  58. return VET_FLOAT1;
  59. case GL_FLOAT_VEC2:
  60. return VET_FLOAT2;
  61. case GL_FLOAT_VEC3:
  62. return VET_FLOAT3;
  63. case GL_FLOAT_VEC4:
  64. return VET_FLOAT4;
  65. case GL_INT:
  66. return VET_INT1;
  67. case GL_INT_VEC2:
  68. return VET_INT2;
  69. case GL_INT_VEC3:
  70. return VET_INT3;
  71. case GL_INT_VEC4:
  72. return VET_INT4;
  73. case GL_UNSIGNED_INT:
  74. return VET_UINT1;
  75. case GL_UNSIGNED_INT_VEC2:
  76. return VET_UINT2;
  77. case GL_UNSIGNED_INT_VEC3:
  78. return VET_UINT3;
  79. case GL_UNSIGNED_INT_VEC4:
  80. return VET_UINT4;
  81. default:
  82. BS_EXCEPT(NotImplementedException, "Unsupported vertex attribute type.");
  83. }
  84. return VET_FLOAT4;
  85. }
  86. bool GLSLParamParser::attribNameToElementSemantic(const String& name, VertexElementSemantic& semantic, UINT16& index)
  87. {
  88. static GLSLAttribute attributes[] =
  89. {
  90. GLSLAttribute("bs_position", VES_POSITION),
  91. GLSLAttribute("bs_normal", VES_NORMAL),
  92. GLSLAttribute("bs_tangent", VES_TANGENT),
  93. GLSLAttribute("bs_bitangent", VES_BITANGENT),
  94. GLSLAttribute("bs_texcoord", VES_TEXCOORD),
  95. GLSLAttribute("bs_color", VES_COLOR),
  96. GLSLAttribute("bs_blendweights", VES_BLEND_WEIGHTS),
  97. GLSLAttribute("bs_blendindices", VES_BLEND_INDICES),
  98. GLSLAttribute("POSITION", VES_POSITION),
  99. GLSLAttribute("NORMAL", VES_NORMAL),
  100. GLSLAttribute("TANGENT", VES_TANGENT),
  101. GLSLAttribute("BITANGENT", VES_BITANGENT),
  102. GLSLAttribute("TEXCOORD", VES_TEXCOORD),
  103. GLSLAttribute("COLOR", VES_COLOR),
  104. GLSLAttribute("BLENDWEIGHT", VES_BLEND_WEIGHTS),
  105. GLSLAttribute("BLENDINDICES", VES_BLEND_INDICES)
  106. };
  107. static const UINT32 numAttribs = sizeof(attributes) / sizeof(attributes[0]);
  108. for (UINT32 i = 0; i < numAttribs; i++)
  109. {
  110. INT32 attribIndex = attributes[i].matchesName(name);
  111. if (attribIndex != -1)
  112. {
  113. index = attribIndex;
  114. semantic = attributes[i].getSemantic();
  115. return true;
  116. }
  117. }
  118. return false;
  119. }
  120. void GLSLParamParser::buildUniformDescriptions(GLuint glProgram, GpuProgramType type, GpuParamDesc& returnParamDesc)
  121. {
  122. // Scan through the active uniform blocks
  123. GLint maxBufferSize = 0;
  124. glGetProgramiv(glProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxBufferSize);
  125. BS_CHECK_GL_ERROR();
  126. GLint maxBlockNameBufferSize = 0;
  127. glGetProgramiv(glProgram, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &maxBlockNameBufferSize);
  128. BS_CHECK_GL_ERROR();
  129. GLint maxStorageBlockNameBufferSize = 0;
  130. #if BS_OPENGL_4_3 || BS_OPENGLES_3_1
  131. glGetProgramInterfaceiv(glProgram, GL_SHADER_STORAGE_BLOCK, GL_MAX_NAME_LENGTH, &maxStorageBlockNameBufferSize);
  132. BS_CHECK_GL_ERROR();
  133. #endif
  134. maxBufferSize = std::max(maxBufferSize, maxBlockNameBufferSize);
  135. maxBufferSize = std::max(maxBufferSize, maxStorageBlockNameBufferSize);
  136. GLchar* uniformName = (GLchar*)bs_alloc(sizeof(GLchar)* maxBufferSize);
  137. GpuParamBlockDesc newGlobalBlockDesc;
  138. newGlobalBlockDesc.slot = 0;
  139. newGlobalBlockDesc.set = mapParameterToSet(type, ParamType::UniformBlock);
  140. newGlobalBlockDesc.name = "BS_INTERNAL_Globals";
  141. newGlobalBlockDesc.blockSize = 0;
  142. newGlobalBlockDesc.isShareable = false;
  143. returnParamDesc.paramBlocks[newGlobalBlockDesc.name] = newGlobalBlockDesc;
  144. GpuParamBlockDesc& globalBlockDesc = returnParamDesc.paramBlocks[newGlobalBlockDesc.name];
  145. // Enumerate uniform blocks
  146. GLint uniformBlockCount = 0;
  147. #if BS_OPENGL_4_3 || BS_OPENGLES_3_1
  148. // Use program interface extension if available
  149. glGetProgramInterfaceiv(glProgram, GL_UNIFORM_BLOCK, GL_ACTIVE_RESOURCES, &uniformBlockCount);
  150. BS_CHECK_GL_ERROR();
  151. #else
  152. // Fall back to old API if not available
  153. glGetProgramiv(glProgram, GL_ACTIVE_UNIFORM_BLOCKS, &uniformBlockCount);
  154. BS_CHECK_GL_ERROR();
  155. #endif
  156. Map<UINT32, String> blockSlotToName;
  157. Set<String> blockNames;
  158. for (GLuint index = 0; index < (GLuint)uniformBlockCount; index++)
  159. {
  160. GLsizei unusedSize = 0;
  161. #if BS_OPENGL_4_3 || BS_OPENGLES_3_1
  162. glGetProgramResourceName(glProgram, GL_UNIFORM_BLOCK, index, maxBufferSize, &unusedSize, uniformName);
  163. BS_CHECK_GL_ERROR();
  164. #else
  165. glGetActiveUniformBlockName(glProgram, index, maxBlockNameBufferSize, &unusedSize, uniformName);
  166. BS_CHECK_GL_ERROR();
  167. #endif
  168. GpuParamBlockDesc newBlockDesc;
  169. newBlockDesc.slot = index + 1;
  170. newBlockDesc.set = mapParameterToSet(type, ParamType::UniformBlock);
  171. newBlockDesc.name = uniformName;
  172. newBlockDesc.blockSize = 0;
  173. newBlockDesc.isShareable = true;
  174. returnParamDesc.paramBlocks[newBlockDesc.name] = newBlockDesc;
  175. blockSlotToName.insert(std::make_pair(index + 1, newBlockDesc.name));
  176. blockNames.insert(newBlockDesc.name);
  177. }
  178. #if BS_OPENGL_4_3 || BS_OPENGLES_3_1
  179. // Scan through the shared storage blocks
  180. GLint storageBlockCount = 0;
  181. glGetProgramInterfaceiv(glProgram, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &storageBlockCount);
  182. BS_CHECK_GL_ERROR();
  183. for (GLuint index = 0; index < (GLuint)storageBlockCount; index++)
  184. {
  185. GLsizei unusedSize = 0;
  186. glGetProgramResourceName(glProgram, GL_SHADER_STORAGE_BLOCK, index, maxBufferSize, &unusedSize, uniformName);
  187. BS_CHECK_GL_ERROR();
  188. GpuParamObjectDesc bufferParam;
  189. bufferParam.name = uniformName;
  190. bufferParam.slot = index;
  191. bufferParam.type = GPOT_RWSTRUCTURED_BUFFER;
  192. bufferParam.set = mapParameterToSet(type, ParamType::StorageBlock);
  193. returnParamDesc.buffers.insert(std::make_pair(uniformName, bufferParam));
  194. }
  195. #endif
  196. Map<String, UINT32> foundFirstArrayIndex;
  197. Map<String, GpuParamDataDesc> foundStructs;
  198. // Get the number of active uniforms
  199. GLint uniformCount = 0;
  200. glGetProgramiv(glProgram, GL_ACTIVE_UNIFORMS, &uniformCount);
  201. BS_CHECK_GL_ERROR();
  202. // Loop over each of the active uniforms, and add them to the reference container
  203. // only do this for user defined uniforms, ignore built in gl state uniforms
  204. for (GLuint index = 0; index < (GLuint)uniformCount; index++)
  205. {
  206. GLsizei arraySize = 0;
  207. glGetActiveUniformName(glProgram, index, maxBufferSize, &arraySize, uniformName);
  208. BS_CHECK_GL_ERROR();
  209. String paramName = String(uniformName);
  210. // Naming rules and packing rules used here are described in
  211. // OpenGL Core Specification 2.11.4
  212. // Check if parameter is a part of a struct
  213. Vector<String> nameElements = StringUtil::tokenise(paramName, ".");
  214. bool inStruct = false;
  215. String structName;
  216. if (nameElements.size() > 1)
  217. {
  218. auto uniformBlockFind = blockNames.find(nameElements[0]);
  219. // Check if the name is not a struct, and instead a Uniform block namespace
  220. if (uniformBlockFind != blockNames.end())
  221. {
  222. // Possibly it's a struct inside a named uniform block
  223. if (nameElements.size() > 2)
  224. {
  225. inStruct = true;
  226. structName = nameElements[1];
  227. }
  228. }
  229. else
  230. {
  231. inStruct = true;
  232. structName = nameElements[0];
  233. }
  234. }
  235. String cleanParamName = paramName; // Param name without array indexes
  236. // Check if the parameter is in an array
  237. UINT32 arrayIdx = 0;
  238. bool isInArray = false;
  239. if (inStruct)
  240. {
  241. // If the uniform name has a "[" in it then its an array element uniform.
  242. String::size_type arrayStart = structName.find("[");
  243. String::size_type arrayEnd = structName.find("]");
  244. if (arrayStart != String::npos)
  245. {
  246. String strArrIdx = structName.substr(arrayStart + 1, arrayEnd - (arrayStart + 1));
  247. arrayIdx = parseUINT32(strArrIdx, 0);
  248. isInArray = true;
  249. structName = structName.substr(0, arrayStart);
  250. }
  251. }
  252. else
  253. {
  254. // If the uniform name has a "[" in it then its an array element uniform.
  255. String::size_type arrayStart = cleanParamName.find("[");
  256. String::size_type arrayEnd = cleanParamName.find("]");
  257. if (arrayStart != String::npos)
  258. {
  259. String strArrIdx = cleanParamName.substr(arrayStart + 1, arrayEnd - (arrayStart + 1));
  260. arrayIdx = parseUINT32(strArrIdx, 0);
  261. isInArray = true;
  262. cleanParamName = cleanParamName.substr(0, arrayStart);
  263. }
  264. }
  265. if (inStruct)
  266. {
  267. // OpenGL makes struct management really difficult, which is why I have given up on implementing this so far
  268. // Some of the issues I encountered:
  269. // - Elements will be optimized out if they are not used. This makes it hard to determine proper structure size.
  270. // - If struct is within a Uniform buffer block, then it is possible because the element won't be optimized out of the buffer
  271. // - If the struct is within a global buffer, it is impossible to determine actual size, since the element will be optimized out of the buffer too
  272. // - Same issue happens with arrays, as OpenGL will optimize out array elements. With global buffers this makes it impossible to determine
  273. // actual array size (for example suppose OpenGL optimized out few last elements)
  274. // - Normal arrays work fine as OpenGL has utilities for reporting their actual size, but those do not work with structs
  275. BS_EXCEPT(NotImplementedException, "Structs are not supported.")
  276. }
  277. // GLSL will optimize out unused array indexes, so there's no guarantee that 0 is the first,
  278. // so we store the first one here
  279. int firstArrayIndex = 0;
  280. if (isInArray)
  281. {
  282. String& nameToSearch = cleanParamName;
  283. if (inStruct)
  284. nameToSearch = structName;
  285. auto arrayIndexFind = foundFirstArrayIndex.find(nameToSearch);
  286. if (arrayIndexFind == foundFirstArrayIndex.end())
  287. {
  288. foundFirstArrayIndex[nameToSearch] = arrayIdx;
  289. }
  290. firstArrayIndex = foundFirstArrayIndex[nameToSearch];
  291. }
  292. GLint uniformType;
  293. glGetActiveUniformsiv(glProgram, 1, &index, GL_UNIFORM_TYPE, &uniformType);
  294. BS_CHECK_GL_ERROR();
  295. GpuParamObjectType samplerType = GPOT_UNKNOWN;
  296. GpuParamObjectType textureType = GPOT_UNKNOWN;
  297. bool isSampler = false;
  298. bool isImage = false;
  299. bool isBuffer = false;
  300. bool isRWBuffer = false;
  301. switch (uniformType)
  302. {
  303. case GL_SAMPLER_1D:
  304. case GL_SAMPLER_1D_SHADOW:
  305. case GL_UNSIGNED_INT_SAMPLER_1D:
  306. case GL_INT_SAMPLER_1D:
  307. samplerType = GPOT_SAMPLER1D;
  308. textureType = GPOT_TEXTURE1D;
  309. isSampler = true;
  310. break;
  311. case GL_SAMPLER_1D_ARRAY:
  312. case GL_SAMPLER_1D_ARRAY_SHADOW:
  313. case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
  314. case GL_INT_SAMPLER_1D_ARRAY:
  315. samplerType = GPOT_SAMPLER1D;
  316. textureType = GPOT_TEXTURE1DARRAY;
  317. isSampler = true;
  318. break;
  319. case GL_SAMPLER_2D:
  320. case GL_SAMPLER_2D_SHADOW:
  321. case GL_UNSIGNED_INT_SAMPLER_2D:
  322. case GL_INT_SAMPLER_2D:
  323. samplerType = GPOT_SAMPLER2D;
  324. textureType = GPOT_TEXTURE2D;
  325. isSampler = true;
  326. break;
  327. case GL_SAMPLER_2D_ARRAY:
  328. case GL_SAMPLER_2D_ARRAY_SHADOW:
  329. case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
  330. case GL_INT_SAMPLER_2D_ARRAY:
  331. samplerType = GPOT_SAMPLER2D;
  332. textureType = GPOT_TEXTURE2DARRAY;
  333. isSampler = true;
  334. break;
  335. case GL_SAMPLER_2D_MULTISAMPLE:
  336. case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
  337. case GL_INT_SAMPLER_2D_MULTISAMPLE:
  338. samplerType = GPOT_SAMPLER2DMS;
  339. textureType = GPOT_TEXTURE2DMS;
  340. isSampler = true;
  341. break;
  342. case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
  343. case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
  344. case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
  345. samplerType = GPOT_SAMPLER2DMS;
  346. textureType = GPOT_TEXTURE2DMSARRAY;
  347. isSampler = true;
  348. break;
  349. case GL_SAMPLER_3D:
  350. case GL_UNSIGNED_INT_SAMPLER_3D:
  351. case GL_INT_SAMPLER_3D:
  352. samplerType = GPOT_SAMPLER3D;
  353. textureType = GPOT_TEXTURE3D;
  354. isSampler = true;
  355. break;
  356. case GL_SAMPLER_CUBE:
  357. case GL_SAMPLER_CUBE_SHADOW:
  358. case GL_UNSIGNED_INT_SAMPLER_CUBE:
  359. case GL_INT_SAMPLER_CUBE:
  360. samplerType = GPOT_SAMPLERCUBE;
  361. textureType = GPOT_TEXTURECUBE;
  362. isSampler = true;
  363. break;
  364. case GL_SAMPLER_CUBE_MAP_ARRAY:
  365. case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
  366. case GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY:
  367. case GL_INT_SAMPLER_CUBE_MAP_ARRAY:
  368. samplerType = GPOT_SAMPLERCUBE;
  369. textureType = GPOT_TEXTURECUBEARRAY;
  370. isSampler = true;
  371. break;
  372. case GL_IMAGE_1D:
  373. case GL_UNSIGNED_INT_IMAGE_1D:
  374. case GL_INT_IMAGE_1D:
  375. textureType = GPOT_RWTEXTURE1D;
  376. isImage = true;
  377. break;
  378. case GL_IMAGE_1D_ARRAY:
  379. case GL_UNSIGNED_INT_IMAGE_1D_ARRAY:
  380. case GL_INT_IMAGE_1D_ARRAY:
  381. textureType = GPOT_RWTEXTURE1DARRAY;
  382. isImage = true;
  383. break;
  384. case GL_IMAGE_2D:
  385. case GL_UNSIGNED_INT_IMAGE_2D:
  386. case GL_INT_IMAGE_2D:
  387. textureType = GPOT_RWTEXTURE2D;
  388. isImage = true;
  389. break;
  390. case GL_IMAGE_2D_ARRAY:
  391. case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
  392. case GL_INT_IMAGE_2D_ARRAY:
  393. textureType = GPOT_RWTEXTURE2DARRAY;
  394. isImage = true;
  395. break;
  396. case GL_IMAGE_2D_MULTISAMPLE:
  397. case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE:
  398. case GL_INT_IMAGE_2D_MULTISAMPLE:
  399. textureType = GPOT_RWTEXTURE2DMS;
  400. isImage = true;
  401. break;
  402. case GL_IMAGE_2D_MULTISAMPLE_ARRAY:
  403. case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
  404. case GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
  405. textureType = GPOT_RWTEXTURE2DMSARRAY;
  406. isImage = true;
  407. break;
  408. case GL_IMAGE_3D:
  409. case GL_UNSIGNED_INT_IMAGE_3D:
  410. case GL_INT_IMAGE_3D:
  411. textureType = GPOT_RWTEXTURE3D;
  412. isImage = true;
  413. break;
  414. case GL_SAMPLER_BUFFER:
  415. case GL_UNSIGNED_INT_SAMPLER_BUFFER:
  416. case GL_INT_SAMPLER_BUFFER:
  417. isBuffer = true;
  418. break;
  419. case GL_IMAGE_BUFFER:
  420. case GL_UNSIGNED_INT_IMAGE_BUFFER:
  421. case GL_INT_IMAGE_BUFFER:
  422. isRWBuffer = true;
  423. break;
  424. }
  425. if (isSampler)
  426. {
  427. GpuParamObjectDesc samplerParam;
  428. samplerParam.name = paramName;
  429. samplerParam.type = samplerType;
  430. samplerParam.slot = glGetUniformLocation(glProgram, uniformName);
  431. samplerParam.set = mapParameterToSet(type, ParamType::Sampler);
  432. GpuParamObjectDesc textureParam;
  433. textureParam.name = paramName;
  434. textureParam.type = textureType;
  435. textureParam.slot = samplerParam.slot;
  436. textureParam.set = mapParameterToSet(type, ParamType::Texture);
  437. returnParamDesc.samplers.insert(std::make_pair(paramName, samplerParam));
  438. returnParamDesc.textures.insert(std::make_pair(paramName, textureParam));
  439. BS_CHECK_GL_ERROR();
  440. }
  441. else if (isImage)
  442. {
  443. GpuParamObjectDesc textureParam;
  444. textureParam.name = paramName;
  445. textureParam.type = textureType;
  446. textureParam.slot = glGetUniformLocation(glProgram, uniformName);
  447. textureParam.set = mapParameterToSet(type, ParamType::Image);
  448. returnParamDesc.loadStoreTextures.insert(std::make_pair(paramName, textureParam));
  449. BS_CHECK_GL_ERROR();
  450. }
  451. else if (isBuffer)
  452. {
  453. GpuParamObjectDesc bufferParam;
  454. bufferParam.name = paramName;
  455. bufferParam.type = GPOT_BYTE_BUFFER;
  456. bufferParam.slot = glGetUniformLocation(glProgram, uniformName);
  457. bufferParam.set = mapParameterToSet(type, ParamType::Texture);
  458. returnParamDesc.buffers.insert(std::make_pair(paramName, bufferParam));
  459. BS_CHECK_GL_ERROR();
  460. }
  461. else if(isRWBuffer)
  462. {
  463. GpuParamObjectDesc bufferParam;
  464. bufferParam.name = paramName;
  465. bufferParam.type = GPOT_RWBYTE_BUFFER;
  466. bufferParam.slot = glGetUniformLocation(glProgram, uniformName);
  467. bufferParam.set = mapParameterToSet(type, ParamType::Image);
  468. returnParamDesc.buffers.insert(std::make_pair(paramName, bufferParam));
  469. BS_CHECK_GL_ERROR();
  470. }
  471. else
  472. {
  473. // If array index is larger than 0 and uniform is not a part of a struct,
  474. // it means we already processed it (struct arrays are processed differently)
  475. if (!inStruct && arrayIdx != 0)
  476. continue;
  477. GLint blockIndex;
  478. glGetActiveUniformsiv(glProgram, 1, &index, GL_UNIFORM_BLOCK_INDEX, &blockIndex);
  479. BS_CHECK_GL_ERROR();
  480. GpuParamDataDesc gpuParam;
  481. if (isInArray)
  482. gpuParam.name = cleanParamName;
  483. else
  484. gpuParam.name = paramName;
  485. determineParamInfo(gpuParam, paramName, glProgram, index);
  486. if (blockIndex != -1)
  487. {
  488. GLint blockOffset;
  489. glGetActiveUniformsiv(glProgram, 1, &index, GL_UNIFORM_OFFSET, &blockOffset);
  490. blockOffset = blockOffset / 4;
  491. gpuParam.gpuMemOffset = blockOffset;
  492. String& blockName = blockSlotToName[blockIndex + 1];
  493. GpuParamBlockDesc& curBlockDesc = returnParamDesc.paramBlocks[blockName];
  494. gpuParam.paramBlockSlot = curBlockDesc.slot;
  495. gpuParam.paramBlockSet = mapParameterToSet(type, ParamType::UniformBlock);
  496. gpuParam.cpuMemOffset = blockOffset;
  497. curBlockDesc.blockSize = std::max(curBlockDesc.blockSize, gpuParam.cpuMemOffset + gpuParam.arrayElementStride * gpuParam.arraySize);
  498. BS_CHECK_GL_ERROR();
  499. }
  500. else
  501. {
  502. gpuParam.gpuMemOffset = glGetUniformLocation(glProgram, uniformName);
  503. gpuParam.paramBlockSlot = 0;
  504. gpuParam.paramBlockSet = mapParameterToSet(type, ParamType::UniformBlock);
  505. gpuParam.cpuMemOffset = globalBlockDesc.blockSize;
  506. globalBlockDesc.blockSize = std::max(globalBlockDesc.blockSize, gpuParam.cpuMemOffset + gpuParam.arrayElementStride * gpuParam.arraySize);
  507. BS_CHECK_GL_ERROR();
  508. }
  509. // If parameter is not a part of a struct we're done
  510. if (!inStruct)
  511. {
  512. returnParamDesc.params.insert(std::make_pair(gpuParam.name, gpuParam));
  513. continue;
  514. }
  515. // If the parameter is part of a struct, then we need to update the struct definition
  516. auto findExistingStruct = foundStructs.find(structName);
  517. // Create new definition if one doesn't exist
  518. if (findExistingStruct == foundStructs.end())
  519. {
  520. foundStructs[structName] = GpuParamDataDesc();
  521. GpuParamDataDesc& structDesc = foundStructs[structName];
  522. structDesc.type = GPDT_STRUCT;
  523. structDesc.name = structName;
  524. structDesc.arraySize = 1;
  525. structDesc.elementSize = 0;
  526. structDesc.arrayElementStride = 0;
  527. structDesc.gpuMemOffset = gpuParam.gpuMemOffset;
  528. structDesc.cpuMemOffset = gpuParam.cpuMemOffset;
  529. structDesc.paramBlockSlot = gpuParam.paramBlockSlot;
  530. structDesc.paramBlockSet = gpuParam.paramBlockSet;
  531. }
  532. // Update struct with size of the new parameter
  533. GpuParamDataDesc& structDesc = foundStructs[structName];
  534. assert(gpuParam.cpuMemOffset >= structDesc.cpuMemOffset);
  535. if (arrayIdx == (UINT32)firstArrayIndex) // Determine element size only using the first array element
  536. {
  537. structDesc.elementSize = std::max(structDesc.elementSize, (gpuParam.cpuMemOffset - structDesc.cpuMemOffset) + gpuParam.arrayElementStride * gpuParam.arraySize);
  538. structDesc.arrayElementStride = structDesc.elementSize;
  539. }
  540. // New array element reached, determine arrayElementStride
  541. if (arrayIdx != (UINT32)firstArrayIndex)
  542. {
  543. UINT32 numElements = arrayIdx - firstArrayIndex;
  544. structDesc.arrayElementStride = (gpuParam.cpuMemOffset - structDesc.cpuMemOffset) / numElements;
  545. }
  546. structDesc.arraySize = std::max(structDesc.arraySize, arrayIdx + 1);
  547. }
  548. }
  549. for (auto iter = foundStructs.begin(); iter != foundStructs.end(); ++iter)
  550. returnParamDesc.params.insert(std::make_pair(iter->first, iter->second));
  551. // Param blocks always need to be a multiple of 4, so make it so
  552. for (auto iter = returnParamDesc.paramBlocks.begin(); iter != returnParamDesc.paramBlocks.end(); ++iter)
  553. {
  554. GpuParamBlockDesc& blockDesc = iter->second;
  555. if (blockDesc.blockSize % 4 != 0)
  556. blockDesc.blockSize += (4 - (blockDesc.blockSize % 4));
  557. }
  558. #if BS_DEBUG_MODE
  559. // Check if manually calculated and OpenGL buffer sizes match
  560. UINT32 blockIdx = 0;
  561. for (auto iter = returnParamDesc.paramBlocks.begin(); iter != returnParamDesc.paramBlocks.end(); ++iter)
  562. {
  563. if (iter->second.slot == 0)
  564. continue;
  565. GLint blockSize = 0;
  566. glGetActiveUniformBlockiv(glProgram, blockIdx, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
  567. BS_CHECK_GL_ERROR();
  568. assert(blockSize % 4 == 0);
  569. blockSize = blockSize / 4;
  570. if ((INT32)iter->second.blockSize != blockSize)
  571. BS_EXCEPT(InternalErrorException, "OpenGL specified and manual uniform block buffer sizes don't match!");
  572. blockIdx++;
  573. }
  574. #endif
  575. bs_free(uniformName);
  576. }
  577. void GLSLParamParser::determineParamInfo(GpuParamDataDesc& desc, const String& paramName, GLuint programHandle, GLuint uniformIndex)
  578. {
  579. GLint arraySize;
  580. glGetActiveUniformsiv(programHandle, 1, &uniformIndex, GL_UNIFORM_SIZE, &arraySize);
  581. BS_CHECK_GL_ERROR();
  582. desc.arraySize = arraySize;
  583. GLint uniformType;
  584. glGetActiveUniformsiv(programHandle, 1, &uniformIndex, GL_UNIFORM_TYPE, &uniformType);
  585. BS_CHECK_GL_ERROR();
  586. switch (uniformType)
  587. {
  588. case GL_BOOL:
  589. desc.type = GPDT_BOOL;
  590. desc.elementSize = 1;
  591. break;
  592. case GL_FLOAT:
  593. desc.type = GPDT_FLOAT1;
  594. desc.elementSize = 1;
  595. break;
  596. case GL_FLOAT_VEC2:
  597. desc.type = GPDT_FLOAT2;
  598. desc.elementSize = 2;
  599. break;
  600. case GL_FLOAT_VEC3:
  601. desc.type = GPDT_FLOAT3;
  602. desc.elementSize = 3;
  603. break;
  604. case GL_FLOAT_VEC4:
  605. desc.type = GPDT_FLOAT4;
  606. desc.elementSize = 4;
  607. break;
  608. case GL_INT:
  609. case GL_UNSIGNED_INT:
  610. desc.type = GPDT_INT1;
  611. desc.elementSize = 1;
  612. break;
  613. case GL_INT_VEC2:
  614. case GL_UNSIGNED_INT_VEC2:
  615. desc.type = GPDT_INT2;
  616. desc.elementSize = 2;
  617. break;
  618. case GL_INT_VEC3:
  619. case GL_UNSIGNED_INT_VEC3:
  620. desc.type = GPDT_INT3;
  621. desc.elementSize = 3;
  622. break;
  623. case GL_INT_VEC4:
  624. case GL_UNSIGNED_INT_VEC4:
  625. desc.type = GPDT_INT4;
  626. desc.elementSize = 4;
  627. break;
  628. case GL_FLOAT_MAT2:
  629. desc.type = GPDT_MATRIX_2X2;
  630. desc.elementSize = 4;
  631. break;
  632. case GL_FLOAT_MAT3:
  633. desc.type = GPDT_MATRIX_3X3;
  634. desc.elementSize = 9;
  635. break;
  636. case GL_FLOAT_MAT4:
  637. desc.type = GPDT_MATRIX_4X4;
  638. desc.elementSize = 16;
  639. break;
  640. case GL_FLOAT_MAT2x3:
  641. desc.type = GPDT_MATRIX_2X3;
  642. desc.elementSize = 6;
  643. break;
  644. case GL_FLOAT_MAT3x2:
  645. desc.type = GPDT_MATRIX_3X2;
  646. desc.elementSize = 6;
  647. break;
  648. case GL_FLOAT_MAT2x4:
  649. desc.type = GPDT_MATRIX_2X4;
  650. desc.elementSize = 8;
  651. break;
  652. case GL_FLOAT_MAT4x2:
  653. desc.type = GPDT_MATRIX_4X2;
  654. desc.elementSize = 8;
  655. break;
  656. case GL_FLOAT_MAT3x4:
  657. desc.type = GPDT_MATRIX_3X4;
  658. desc.elementSize = 12;
  659. break;
  660. case GL_FLOAT_MAT4x3:
  661. desc.type = GPDT_MATRIX_4X3;
  662. desc.elementSize = 12;
  663. break;
  664. default:
  665. BS_EXCEPT(InternalErrorException, "Invalid shader parameter type: " + toString(uniformType) + " for parameter " + paramName);
  666. }
  667. if (arraySize > 1)
  668. {
  669. GLint arrayStride;
  670. glGetActiveUniformsiv(programHandle, 1, &uniformIndex, GL_UNIFORM_ARRAY_STRIDE, &arrayStride);
  671. BS_CHECK_GL_ERROR();
  672. if (arrayStride > 0)
  673. {
  674. assert(arrayStride % 4 == 0);
  675. desc.arrayElementStride = arrayStride / 4;
  676. }
  677. else
  678. desc.arrayElementStride = desc.elementSize;
  679. }
  680. else
  681. desc.arrayElementStride = desc.elementSize;
  682. }
  683. UINT32 GLSLParamParser::mapParameterToSet(GpuProgramType progType, ParamType paramType)
  684. {
  685. UINT32 progTypeIdx = (UINT32)progType;
  686. UINT32 paramTypeIdx = (UINT32)paramType;
  687. return progTypeIdx * (UINT32)ParamType::Count + paramTypeIdx;
  688. }
  689. }}