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