BsGLSLParamParser.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "BsGLSLParamParser.h"
  4. namespace BansheeEngine
  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. GLint maxNameSize = 0;
  23. glGetProgramiv(glProgram, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxNameSize);
  24. GLchar* attributeName = (GLchar*)bs_alloc(sizeof(GLchar)* maxNameSize);
  25. List<VertexElement> elementList;
  26. for (GLint i = 0; i < numAttributes; i++)
  27. {
  28. GLint attribSize = 0;
  29. GLenum attribType = 0;
  30. glGetActiveAttrib(glProgram, i, maxNameSize, nullptr, &attribSize, &attribType, attributeName);
  31. VertexElementSemantic semantic = VES_POSITION;
  32. UINT16 index = 0;
  33. if (attribNameToElementSemantic(attributeName, semantic, index))
  34. {
  35. VertexElementType type = glTypeToAttributeType(attribType);
  36. elementList.push_back(VertexElement(0, i, type, semantic, index));
  37. }
  38. else
  39. {
  40. // Ignore built-in attributes
  41. if(memcmp(attributeName, "gl_", 3) != 0)
  42. LOGWRN("Cannot determine vertex input attribute type for attribute: " + String(attributeName));
  43. }
  44. }
  45. bs_free(attributeName);
  46. return elementList;
  47. }
  48. VertexElementType GLSLParamParser::glTypeToAttributeType(GLenum glType)
  49. {
  50. switch (glType)
  51. {
  52. case GL_FLOAT:
  53. return VET_FLOAT1;
  54. case GL_FLOAT_VEC2:
  55. return VET_FLOAT2;
  56. case GL_FLOAT_VEC3:
  57. return VET_FLOAT3;
  58. case GL_FLOAT_VEC4:
  59. return VET_FLOAT4;
  60. case GL_INT:
  61. return VET_INT1;
  62. case GL_INT_VEC2:
  63. return VET_INT2;
  64. case GL_INT_VEC3:
  65. return VET_INT3;
  66. case GL_INT_VEC4:
  67. return VET_INT4;
  68. case GL_UNSIGNED_INT:
  69. return VET_UINT1;
  70. case GL_UNSIGNED_INT_VEC2:
  71. return VET_UINT2;
  72. case GL_UNSIGNED_INT_VEC3:
  73. return VET_UINT3;
  74. case GL_UNSIGNED_INT_VEC4:
  75. return VET_UINT4;
  76. default:
  77. BS_EXCEPT(NotImplementedException, "Unsupported vertex attribute type.");
  78. }
  79. return VET_FLOAT4;
  80. }
  81. bool GLSLParamParser::attribNameToElementSemantic(const String& name, VertexElementSemantic& semantic, UINT16& index)
  82. {
  83. static GLSLAttribute attributes[] =
  84. {
  85. GLSLAttribute("bs_position", VES_POSITION),
  86. GLSLAttribute("bs_normal", VES_NORMAL),
  87. GLSLAttribute("bs_tangent", VES_TANGENT),
  88. GLSLAttribute("bs_bitangent", VES_BITANGENT),
  89. GLSLAttribute("bs_texcoord", VES_TEXCOORD),
  90. GLSLAttribute("bs_color", VES_COLOR),
  91. GLSLAttribute("bs_blendweights", VES_BLEND_WEIGHTS),
  92. GLSLAttribute("bs_blendindices", VES_BLEND_INDICES)
  93. };
  94. static const UINT32 numAttribs = sizeof(attributes) / sizeof(attributes[0]);
  95. for (UINT32 i = 0; i < numAttribs; i++)
  96. {
  97. INT32 attribIndex = attributes[i].matchesName(name);
  98. if (attribIndex != -1)
  99. {
  100. index = attribIndex;
  101. semantic = attributes[i].getSemantic();
  102. return true;
  103. }
  104. }
  105. return false;
  106. }
  107. void GLSLParamParser::buildUniformDescriptions(GLuint glProgram, GpuParamDesc& returnParamDesc)
  108. {
  109. // scan through the active uniforms and add them to the reference list
  110. GLint maxBufferSize = 0;
  111. glGetProgramiv(glProgram, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxBufferSize);
  112. GLint maxBlockNameBufferSize = 0;
  113. glGetProgramiv(glProgram, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &maxBlockNameBufferSize);
  114. if (maxBlockNameBufferSize > maxBufferSize)
  115. maxBufferSize = maxBlockNameBufferSize;
  116. GLchar* uniformName = (GLchar*)bs_alloc(sizeof(GLchar)* maxBufferSize);
  117. GpuParamBlockDesc newGlobalBlockDesc;
  118. newGlobalBlockDesc.slot = 0;
  119. newGlobalBlockDesc.name = "BS_INTERNAL_Globals";
  120. newGlobalBlockDesc.blockSize = 0;
  121. newGlobalBlockDesc.isShareable = false;
  122. returnParamDesc.paramBlocks[newGlobalBlockDesc.name] = newGlobalBlockDesc;
  123. GpuParamBlockDesc& globalBlockDesc = returnParamDesc.paramBlocks[newGlobalBlockDesc.name];
  124. GLint uniformBlockCount = 0;
  125. glGetProgramiv(glProgram, GL_ACTIVE_UNIFORM_BLOCKS, &uniformBlockCount);
  126. Map<UINT32, String> blockSlotToName;
  127. Set<String> blockNames;
  128. for (GLuint index = 0; index < (GLuint)uniformBlockCount; index++)
  129. {
  130. GLsizei unusedSize = 0;
  131. glGetActiveUniformBlockName(glProgram, index, maxBufferSize, &unusedSize, uniformName);
  132. GpuParamBlockDesc newBlockDesc;
  133. newBlockDesc.slot = index + 1;
  134. newBlockDesc.name = uniformName;
  135. newBlockDesc.blockSize = 0;
  136. newBlockDesc.isShareable = true;
  137. returnParamDesc.paramBlocks[newBlockDesc.name] = newBlockDesc;
  138. blockSlotToName.insert(std::make_pair(newBlockDesc.slot, newBlockDesc.name));
  139. blockNames.insert(newBlockDesc.name);
  140. }
  141. Map<String, UINT32> foundFirstArrayIndex;
  142. Map<String, GpuParamDataDesc> foundStructs;
  143. // get the number of active uniforms
  144. GLint uniformCount = 0;
  145. glGetProgramiv(glProgram, GL_ACTIVE_UNIFORMS, &uniformCount);
  146. // Loop over each of the active uniforms, and add them to the reference container
  147. // only do this for user defined uniforms, ignore built in gl state uniforms
  148. for (GLuint index = 0; index < (GLuint)uniformCount; index++)
  149. {
  150. GLsizei arraySize = 0;
  151. glGetActiveUniformName(glProgram, index, maxBufferSize, &arraySize, uniformName);
  152. String paramName = String(uniformName);
  153. // Naming rules and packing rules used here are described in
  154. // OpenGL Core Specification 2.11.4
  155. // Check if parameter is a part of a struct
  156. Vector<String> nameElements = StringUtil::tokenise(paramName, ".");
  157. bool inStruct = false;
  158. String structName;
  159. if (nameElements.size() > 1)
  160. {
  161. auto uniformBlockFind = blockNames.find(nameElements[0]);
  162. // Check if the name is not a struct, and instead a Uniform block namespace
  163. if (uniformBlockFind != blockNames.end())
  164. {
  165. // Possibly it's a struct inside a named uniform block
  166. if (nameElements.size() > 2)
  167. {
  168. inStruct = true;
  169. structName = nameElements[1];
  170. }
  171. }
  172. else
  173. {
  174. inStruct = true;
  175. structName = nameElements[0];
  176. }
  177. }
  178. String cleanParamName = paramName; // Param name without array indexes
  179. // Check if the parameter is in an array
  180. UINT32 arrayIdx = 0;
  181. bool isInArray = false;
  182. if (inStruct)
  183. {
  184. // If the uniform name has a "[" in it then its an array element uniform.
  185. String::size_type arrayStart = structName.find("[");
  186. String::size_type arrayEnd = structName.find("]");
  187. if (arrayStart != String::npos)
  188. {
  189. String strArrIdx = structName.substr(arrayStart + 1, arrayEnd - (arrayStart + 1));
  190. arrayIdx = parseUINT32(strArrIdx, 0);
  191. isInArray = true;
  192. structName = structName.substr(0, arrayStart);
  193. }
  194. }
  195. else
  196. {
  197. // If the uniform name has a "[" in it then its an array element uniform.
  198. String::size_type arrayStart = cleanParamName.find("[");
  199. String::size_type arrayEnd = cleanParamName.find("]");
  200. if (arrayStart != String::npos)
  201. {
  202. String strArrIdx = cleanParamName.substr(arrayStart + 1, arrayEnd - (arrayStart + 1));
  203. arrayIdx = parseUINT32(strArrIdx, 0);
  204. isInArray = true;
  205. cleanParamName = cleanParamName.substr(0, arrayStart);
  206. }
  207. }
  208. if (inStruct)
  209. {
  210. // OpenGL makes struct management really difficult, which is why I have given up on implementing this so far
  211. // Some of the issues I encountered:
  212. // - Elements will be optimized out if they are not used. This makes it hard to determine proper structure size.
  213. // - If struct is within a Uniform buffer block, then it is possible because the element won't be optimized out of the buffer
  214. // - 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
  215. // - Same issue happens with arrays, as OpenGL will optimize out array elements. With global buffers this makes it impossible to determine
  216. // actual array size (for example suppose OpenGL optimized out few last elements)
  217. // - Normal arrays work fine as OpenGL has utilities for reporting their actual size, but those do not work with structs
  218. BS_EXCEPT(NotImplementedException, "Structs are not supported.")
  219. }
  220. // GLSL will optimize out unused array indexes, so there's no guarantee that 0 is the first,
  221. // so we store the first one here
  222. int firstArrayIndex = 0;
  223. if (isInArray)
  224. {
  225. String& nameToSearch = cleanParamName;
  226. if (inStruct)
  227. nameToSearch = structName;
  228. auto arrayIndexFind = foundFirstArrayIndex.find(nameToSearch);
  229. if (arrayIndexFind == foundFirstArrayIndex.end())
  230. {
  231. foundFirstArrayIndex[nameToSearch] = arrayIdx;
  232. }
  233. firstArrayIndex = foundFirstArrayIndex[nameToSearch];
  234. }
  235. GLint uniformType;
  236. glGetActiveUniformsiv(glProgram, 1, &index, GL_UNIFORM_TYPE, &uniformType);
  237. bool isSampler = false;
  238. bool isImage = false;
  239. bool isBuffer = false;
  240. switch (uniformType)
  241. {
  242. case GL_SAMPLER_1D:
  243. case GL_SAMPLER_2D:
  244. case GL_SAMPLER_3D:
  245. case GL_SAMPLER_2D_MULTISAMPLE:
  246. case GL_SAMPLER_CUBE:
  247. isSampler = true;
  248. break;
  249. case GL_IMAGE_1D:
  250. case GL_IMAGE_2D:
  251. case GL_IMAGE_3D:
  252. case GL_IMAGE_CUBE:
  253. case GL_IMAGE_2D_MULTISAMPLE:
  254. isImage = true;
  255. break;
  256. case GL_SAMPLER_BUFFER:
  257. case GL_IMAGE_BUFFER:
  258. isBuffer = true;
  259. break;
  260. }
  261. if (isSampler)
  262. {
  263. GpuParamObjectDesc samplerParam;
  264. samplerParam.name = paramName;
  265. samplerParam.slot = glGetUniformLocation(glProgram, uniformName);
  266. GpuParamObjectDesc textureParam;
  267. textureParam.name = paramName;
  268. textureParam.slot = samplerParam.slot;
  269. switch (uniformType)
  270. {
  271. case GL_SAMPLER_1D:
  272. samplerParam.type = GPOT_SAMPLER1D;
  273. textureParam.type = GPOT_TEXTURE1D;
  274. break;
  275. case GL_SAMPLER_2D:
  276. samplerParam.type = GPOT_SAMPLER2D;
  277. textureParam.type = GPOT_TEXTURE2D;
  278. break;
  279. case GL_SAMPLER_3D:
  280. samplerParam.type = GPOT_SAMPLER3D;
  281. textureParam.type = GPOT_TEXTURE3D;
  282. break;
  283. case GL_SAMPLER_CUBE:
  284. samplerParam.type = GPOT_SAMPLERCUBE;
  285. textureParam.type = GPOT_TEXTURECUBE;
  286. break;
  287. case GL_SAMPLER_2D_MULTISAMPLE:
  288. samplerParam.type = GPOT_SAMPLER2DMS;
  289. textureParam.type = GPOT_TEXTURE2DMS;
  290. break;
  291. }
  292. returnParamDesc.samplers.insert(std::make_pair(paramName, samplerParam));
  293. returnParamDesc.textures.insert(std::make_pair(paramName, textureParam));
  294. }
  295. else if (isImage)
  296. {
  297. GpuParamObjectDesc textureParam;
  298. textureParam.name = paramName;
  299. textureParam.slot = glGetUniformLocation(glProgram, uniformName);
  300. switch (uniformType)
  301. {
  302. case GL_IMAGE_1D:
  303. textureParam.type = GPOT_RWTEXTURE1D;
  304. break;
  305. case GL_IMAGE_2D:
  306. textureParam.type = GPOT_RWTEXTURE2D;
  307. break;
  308. case GL_IMAGE_3D:
  309. textureParam.type = GPOT_RWTEXTURE3D;
  310. break;
  311. case GL_IMAGE_2D_MULTISAMPLE:
  312. textureParam.type = GPOT_RWTEXTURE2DMS;
  313. break;
  314. }
  315. returnParamDesc.loadStoreTextures.insert(std::make_pair(paramName, textureParam));
  316. }
  317. else if (isBuffer)
  318. {
  319. GpuParamObjectDesc bufferParam;
  320. bufferParam.name = paramName;
  321. bufferParam.slot = glGetUniformLocation(glProgram, uniformName);
  322. if (uniformType == GL_IMAGE_BUFFER)
  323. bufferParam.type = GPOT_RWSTRUCTURED_BUFFER;
  324. else // Sampler buffer
  325. bufferParam.type = GPOT_STRUCTURED_BUFFER;
  326. returnParamDesc.buffers.insert(std::make_pair(paramName, bufferParam));
  327. }
  328. else
  329. {
  330. // If array index is larger than 0 and uniform is not a part of a struct,
  331. // it means we already processed it (struct arrays are processed differently)
  332. if (!inStruct && arrayIdx != 0)
  333. continue;
  334. GLint blockIndex;
  335. glGetActiveUniformsiv(glProgram, 1, &index, GL_UNIFORM_BLOCK_INDEX, &blockIndex);
  336. GpuParamDataDesc gpuParam;
  337. if (isInArray)
  338. gpuParam.name = cleanParamName;
  339. else
  340. gpuParam.name = paramName;
  341. determineParamInfo(gpuParam, paramName, glProgram, index);
  342. if (blockIndex != -1)
  343. {
  344. GLint blockOffset;
  345. glGetActiveUniformsiv(glProgram, 1, &index, GL_UNIFORM_OFFSET, &blockOffset);
  346. blockOffset = blockOffset / 4;
  347. gpuParam.gpuMemOffset = blockOffset;
  348. gpuParam.paramBlockSlot = blockIndex + 1; // 0 is reserved for globals
  349. String& blockName = blockSlotToName[gpuParam.paramBlockSlot];
  350. GpuParamBlockDesc& curBlockDesc = returnParamDesc.paramBlocks[blockName];
  351. gpuParam.cpuMemOffset = blockOffset;
  352. curBlockDesc.blockSize = std::max(curBlockDesc.blockSize, gpuParam.cpuMemOffset + gpuParam.arrayElementStride * gpuParam.arraySize);
  353. }
  354. else
  355. {
  356. gpuParam.gpuMemOffset = glGetUniformLocation(glProgram, uniformName);
  357. gpuParam.paramBlockSlot = 0;
  358. gpuParam.cpuMemOffset = globalBlockDesc.blockSize;
  359. globalBlockDesc.blockSize = std::max(globalBlockDesc.blockSize, gpuParam.cpuMemOffset + gpuParam.arrayElementStride * gpuParam.arraySize);
  360. }
  361. // If parameter is not a part of a struct we're done
  362. if (!inStruct)
  363. {
  364. returnParamDesc.params.insert(std::make_pair(gpuParam.name, gpuParam));
  365. continue;
  366. }
  367. // If the parameter is part of a struct, then we need to update the struct definition
  368. auto findExistingStruct = foundStructs.find(structName);
  369. // Create new definition if one doesn't exist
  370. if (findExistingStruct == foundStructs.end())
  371. {
  372. foundStructs[structName] = GpuParamDataDesc();
  373. GpuParamDataDesc& structDesc = foundStructs[structName];
  374. structDesc.type = GPDT_STRUCT;
  375. structDesc.name = structName;
  376. structDesc.arraySize = 1;
  377. structDesc.elementSize = 0;
  378. structDesc.arrayElementStride = 0;
  379. structDesc.gpuMemOffset = gpuParam.gpuMemOffset;
  380. structDesc.cpuMemOffset = gpuParam.cpuMemOffset;
  381. structDesc.paramBlockSlot = gpuParam.paramBlockSlot;
  382. }
  383. // Update struct with size of the new parameter
  384. GpuParamDataDesc& structDesc = foundStructs[structName];
  385. assert(gpuParam.cpuMemOffset >= structDesc.cpuMemOffset);
  386. if (arrayIdx == firstArrayIndex) // Determine element size only using the first array element
  387. {
  388. structDesc.elementSize = std::max(structDesc.elementSize, (gpuParam.cpuMemOffset - structDesc.cpuMemOffset) + gpuParam.arrayElementStride * gpuParam.arraySize);
  389. structDesc.arrayElementStride = structDesc.elementSize;
  390. }
  391. // New array element reached, determine arrayElementStride
  392. if (arrayIdx != firstArrayIndex)
  393. {
  394. UINT32 numElements = arrayIdx - firstArrayIndex;
  395. structDesc.arrayElementStride = (gpuParam.cpuMemOffset - structDesc.cpuMemOffset) / numElements;
  396. }
  397. structDesc.arraySize = std::max(structDesc.arraySize, arrayIdx + 1);
  398. }
  399. }
  400. for (auto iter = foundStructs.begin(); iter != foundStructs.end(); ++iter)
  401. returnParamDesc.params.insert(std::make_pair(iter->first, iter->second));
  402. // Param blocks always need to be a multiple of 4, so make it so
  403. for (auto iter = returnParamDesc.paramBlocks.begin(); iter != returnParamDesc.paramBlocks.end(); ++iter)
  404. {
  405. GpuParamBlockDesc& blockDesc = iter->second;
  406. if (blockDesc.blockSize % 4 != 0)
  407. blockDesc.blockSize += (4 - (blockDesc.blockSize % 4));
  408. }
  409. #if BS_DEBUG_MODE
  410. // Check if manually calculated and OpenGL buffer sizes match
  411. for (auto iter = returnParamDesc.paramBlocks.begin(); iter != returnParamDesc.paramBlocks.end(); ++iter)
  412. {
  413. if (iter->second.slot == 0)
  414. continue;
  415. GLint blockSize = 0;
  416. glGetActiveUniformBlockiv(glProgram, iter->second.slot - 1, GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize);
  417. assert(blockSize % 4 == 0);
  418. blockSize = blockSize / 4;
  419. if (iter->second.blockSize != blockSize)
  420. BS_EXCEPT(InternalErrorException, "OpenGL specified and manual uniform block buffer sizes don't match!");
  421. }
  422. #endif
  423. bs_free(uniformName);
  424. }
  425. void GLSLParamParser::determineParamInfo(GpuParamDataDesc& desc, const String& paramName, GLuint programHandle, GLuint uniformIndex)
  426. {
  427. GLint arraySize;
  428. glGetActiveUniformsiv(programHandle, 1, &uniformIndex, GL_UNIFORM_SIZE, &arraySize);
  429. desc.arraySize = arraySize;
  430. GLint uniformType;
  431. glGetActiveUniformsiv(programHandle, 1, &uniformIndex, GL_UNIFORM_TYPE, &uniformType);
  432. switch (uniformType)
  433. {
  434. case GL_BOOL:
  435. desc.type = GPDT_BOOL;
  436. desc.elementSize = 1;
  437. break;
  438. case GL_FLOAT:
  439. desc.type = GPDT_FLOAT1;
  440. desc.elementSize = 1;
  441. break;
  442. case GL_FLOAT_VEC2:
  443. desc.type = GPDT_FLOAT2;
  444. desc.elementSize = 2;
  445. break;
  446. case GL_FLOAT_VEC3:
  447. desc.type = GPDT_FLOAT3;
  448. desc.elementSize = 3;
  449. break;
  450. case GL_FLOAT_VEC4:
  451. desc.type = GPDT_FLOAT4;
  452. desc.elementSize = 4;
  453. break;
  454. case GL_INT:
  455. case GL_UNSIGNED_INT:
  456. desc.type = GPDT_INT1;
  457. desc.elementSize = 1;
  458. break;
  459. case GL_INT_VEC2:
  460. case GL_UNSIGNED_INT_VEC2:
  461. desc.type = GPDT_INT2;
  462. desc.elementSize = 2;
  463. break;
  464. case GL_INT_VEC3:
  465. case GL_UNSIGNED_INT_VEC3:
  466. desc.type = GPDT_INT3;
  467. desc.elementSize = 3;
  468. break;
  469. case GL_INT_VEC4:
  470. case GL_UNSIGNED_INT_VEC4:
  471. desc.type = GPDT_INT4;
  472. desc.elementSize = 4;
  473. break;
  474. case GL_FLOAT_MAT2:
  475. desc.type = GPDT_MATRIX_2X2;
  476. desc.elementSize = 4;
  477. break;
  478. case GL_FLOAT_MAT3:
  479. desc.type = GPDT_MATRIX_3X3;
  480. desc.elementSize = 9;
  481. break;
  482. case GL_FLOAT_MAT4:
  483. desc.type = GPDT_MATRIX_4X4;
  484. desc.elementSize = 16;
  485. break;
  486. case GL_FLOAT_MAT2x3:
  487. desc.type = GPDT_MATRIX_2X3;
  488. desc.elementSize = 6;
  489. break;
  490. case GL_FLOAT_MAT3x2:
  491. desc.type = GPDT_MATRIX_3X2;
  492. desc.elementSize = 6;
  493. break;
  494. case GL_FLOAT_MAT2x4:
  495. desc.type = GPDT_MATRIX_2X4;
  496. desc.elementSize = 8;
  497. break;
  498. case GL_FLOAT_MAT4x2:
  499. desc.type = GPDT_MATRIX_4X2;
  500. desc.elementSize = 8;
  501. break;
  502. case GL_FLOAT_MAT3x4:
  503. desc.type = GPDT_MATRIX_3X4;
  504. desc.elementSize = 12;
  505. break;
  506. case GL_FLOAT_MAT4x3:
  507. desc.type = GPDT_MATRIX_4X3;
  508. desc.elementSize = 12;
  509. break;
  510. default:
  511. BS_EXCEPT(InternalErrorException, "Invalid shader parameter type: " + toString(uniformType) + " for parameter " + paramName);
  512. }
  513. if (arraySize > 1)
  514. {
  515. GLint arrayStride;
  516. glGetActiveUniformsiv(programHandle, 1, &uniformIndex, GL_UNIFORM_ARRAY_STRIDE, &arrayStride);
  517. if (arrayStride > 0)
  518. {
  519. assert(arrayStride % 4 == 0);
  520. desc.arrayElementStride = arrayStride / 4;
  521. }
  522. else
  523. desc.arrayElementStride = desc.elementSize;
  524. }
  525. else
  526. desc.arrayElementStride = desc.elementSize;
  527. }
  528. }