BsGLSLParamParser.cpp 23 KB

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