CSCI441 OpenGL Library 5.9.0
CS@Mines CSCI441 Computer Graphics Course Library
Loading...
Searching...
No Matches
ShaderUtils.hpp
Go to the documentation of this file.
1
14#ifndef CSCI441_SHADER_UTILS_HPP
15#define CSCI441_SHADER_UTILS_HPP
16
17#ifdef CSCI441_USE_GLEW
18 #include <GL/glew.h>
19#else
20 #include <glad/gl.h>
21#endif
22
23#include <cstdio>
24#include <cstring>
25#include <fstream>
26#include <string>
27
28//********************************************************************************************************************
29
30namespace CSCI441_INTERNAL::ShaderUtils {
31 static bool sDEBUG = true;
32
33 // Enables console output
34 [[maybe_unused]] void enableDebugMessages();
35
36 // Disables console output
37 [[maybe_unused]] void disableDebugMessages();
38
39 // Converts a GLenum data type variable to the string name of the associated value
40 // GLenum data type
41 // const char* name of data type
42 const char* GLSL_type_to_string( GLenum type );
43
44 // Converts a GLenum shader type variable to the string name of the associated value
45 // GLenum shader type
46 // const char* name of shader type
47 const char* GL_shader_type_to_string( GLenum type );
48
49 // Converts a GLenum primitive type variable to the string name of the associated value
50 // GLenum primitive type
51 // const char* name of primitive type
52 const char* GL_primitive_type_to_string( GLenum type );
53
54 // Reads the contents of a text file to a character array
55 // const char* filename of shader file to read in
56 // char*& character array to store the contents of the file. Will allocate memory and populate within the function
57 // bool true if file was successfully opened and read. false otherwise
58 bool readTextFromFile( const char* filename, char* &output );
59
60 // Reads the contents of a text file and compiles the associated shader type
61 // const char* filename of shader file to read in
62 // GLenum type of shader file corresponds to
63 // GLuint shader handle if compilation successful. -1 otherwise
64 GLuint compileShader( const char *filename, GLenum shaderType );
65
66 // Prints the shader log for the associated Shader handle
67 void printShaderLog( GLuint shaderHandle );
68
69 // Prints the shader log for the associated Shader Program handle
70 void printProgramLog( GLuint programHandle );
71
72 // Prints the shader log for the associated Program Pipeline handle
73 void printProgramPipelineLog( GLuint pipelineHandle );
74
75 // Prints subroutine information from a Shader program
76 // GLuint Shader Program handle to inspect
77 // GLenum Shader Stage to inspect
78 // GLboolean if opening output line should be printed to console
79 GLboolean printSubroutineInfo(GLuint programHandle, GLenum shaderStage, GLboolean printHeader );
80
81 // Uses Shader Program introspection to print contents of Shader Program
82 // GLuint Shader Program handle to inspect
83 // GLboolean if Shader Program contains a vertex shader
84 // GLboolean if Shader Program contains a tessellation control shader
85 // GLboolean if Shader Program contains a tessellation evaluation shader
86 // GLboolean if Shader Program contains a geometry shader
87 // GLboolean if Shader Program contains a fragment shader
88 // GLboolean if Shader Program contains a compute shader
89 // GLboolean if closing output line should be printed to console (defaults to true)
90 void printShaderProgramInfo( GLuint programHandle,
91 GLboolean hasVertexShader,
92 GLboolean hasTessControlShader, GLboolean hasTessEvalShader,
93 GLboolean hasGeometryShader,
94 GLboolean hasFragmentShader,
95 GLboolean hasComputeShader,
96 GLboolean useLastNewLine );
97}
98
99//********************************************************************************************************************
100
101[[maybe_unused]]
102inline void CSCI441_INTERNAL::ShaderUtils::enableDebugMessages() {
103 sDEBUG = true;
104}
105
106[[maybe_unused]]
107inline void CSCI441_INTERNAL::ShaderUtils::disableDebugMessages() {
108 sDEBUG = false;
109}
110
111//********************************************************************************************************************
112
113inline bool CSCI441_INTERNAL::ShaderUtils::readTextFromFile(
114 const char *filename,
115 char* &output
116){
117 std::string buf = std::string("");
118 std::string line;
119
120 std::ifstream in(filename);
121 if( !in.is_open() ) {
122 fprintf( stderr, "[ERROR]: Could not open file %s\n", filename );
123 return false;
124 }
125 while( std::getline(in, line) ) {
126 buf += line + "\n";
127 }
128
129 output = new char[buf.length()+1];
130 strncpy(output, buf.c_str(), buf.length());
131 output[buf.length()] = '\0';
132
133 in.close();
134
135 return true;
136}
137
138inline const char* CSCI441_INTERNAL::ShaderUtils::GLSL_type_to_string(
139 const GLenum type
140) {
141 switch(type) {
142 case GL_FLOAT: return "float";
143 case GL_FLOAT_VEC2: return "vec2";
144 case GL_FLOAT_VEC3: return "vec3";
145 case GL_FLOAT_VEC4: return "vec4";
146 case GL_DOUBLE: return "double";
147 case GL_DOUBLE_VEC2: return "dvec2";
148 case GL_DOUBLE_VEC3: return "dvec3";
149 case GL_DOUBLE_VEC4: return "dvec4";
150 case GL_INT: return "int";
151 case GL_INT_VEC2: return "ivec2";
152 case GL_INT_VEC3: return "ivec3";
153 case GL_INT_VEC4: return "ivec4";
154 case GL_UNSIGNED_INT: return "unsigned int";
155 case GL_UNSIGNED_INT_VEC2: return "uvec2";
156 case GL_UNSIGNED_INT_VEC3: return "uvec3";
157 case GL_UNSIGNED_INT_VEC4: return "uvec4";
158 case GL_BOOL: return "bool";
159 case GL_BOOL_VEC2: return "bvec2";
160 case GL_BOOL_VEC3: return "bvec3";
161 case GL_BOOL_VEC4: return "bvec4";
162 case GL_FLOAT_MAT2: return "mat2";
163 case GL_FLOAT_MAT3: return "mat3";
164 case GL_FLOAT_MAT4: return "mat4";
165 case GL_FLOAT_MAT2x3: return "mat2x3";
166 case GL_FLOAT_MAT2x4: return "mat2x4";
167 case GL_FLOAT_MAT3x2: return "mat3x2";
168 case GL_FLOAT_MAT3x4: return "mat3x4";
169 case GL_FLOAT_MAT4x2: return "mat4x2";
170 case GL_FLOAT_MAT4x3: return "mat4x3";
171 case GL_DOUBLE_MAT2: return "dmat2";
172 case GL_DOUBLE_MAT3: return "dmat3";
173 case GL_DOUBLE_MAT4: return "dmat4";
174 case GL_DOUBLE_MAT2x3: return "dmat2x3";
175 case GL_DOUBLE_MAT2x4: return "dmat2x4";
176 case GL_DOUBLE_MAT3x2: return "dmat3x2";
177 case GL_DOUBLE_MAT3x4: return "dmat3x4";
178 case GL_DOUBLE_MAT4x2: return "dmat4x2";
179 case GL_DOUBLE_MAT4x3: return "dmat4x3";
180 case GL_SAMPLER_1D: return "sampler1D";
181 case GL_SAMPLER_2D: return "sampler2D";
182 case GL_SAMPLER_3D: return "sampler3D";
183 case GL_SAMPLER_CUBE: return "samplerCube";
184 case GL_SAMPLER_1D_SHADOW: return "sampler1DShadow";
185 case GL_SAMPLER_2D_SHADOW: return "sampler2DShadow";
186 case GL_SAMPLER_1D_ARRAY: return "sampler1DArray";
187 case GL_SAMPLER_2D_ARRAY: return "sampler2DArray";
188 case GL_SAMPLER_2D_MULTISAMPLE: return "sampler2DMS";
189 case GL_SAMPLER_2D_MULTISAMPLE_ARRAY: return "sampler2DMSArray";
190 case GL_SAMPLER_CUBE_SHADOW: return "samplerCubeShadow";
191 case GL_SAMPLER_BUFFER: return "samplerBuffer";
192 case GL_SAMPLER_2D_RECT: return "sampler2DRect";
193 case GL_SAMPLER_2D_RECT_SHADOW: return "sampler2DRectShadow";
194 case GL_INT_SAMPLER_1D: return "isampler1D";
195 case GL_INT_SAMPLER_2D: return "isampler2D";
196 case GL_INT_SAMPLER_3D: return "isampler3D";
197 case GL_INT_SAMPLER_CUBE: return "isamplerCube";
198 case GL_INT_SAMPLER_1D_ARRAY: return "isampler1DArray";
199 case GL_INT_SAMPLER_2D_ARRAY: return "isampler2DArray";
200 case GL_INT_SAMPLER_2D_MULTISAMPLE: return "isampler2DMS";
201 case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return "isampler2DMSArray";
202 case GL_INT_SAMPLER_BUFFER: return "isamplerBuffer";
203 case GL_INT_SAMPLER_2D_RECT: return "isampler2DRect";
204 case GL_UNSIGNED_INT_SAMPLER_1D: return "usampler1D";
205 case GL_UNSIGNED_INT_SAMPLER_2D: return "usampler2D";
206 case GL_UNSIGNED_INT_SAMPLER_3D: return "usampler3D";
207 case GL_UNSIGNED_INT_SAMPLER_CUBE: return "usamplerCube";
208 case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY: return "usampler1DArray";
209 case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: return "usampler2DArray";
210 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE: return "usampler2DMS";
211 case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: return "usampler2DMSArray";
212 case GL_UNSIGNED_INT_SAMPLER_BUFFER: return "usamplerBuffer";
213 case GL_UNSIGNED_INT_SAMPLER_2D_RECT: return "usampler2DRect";
214 case GL_IMAGE_1D: return "image1D";
215 case GL_IMAGE_2D: return "image2D";
216 case GL_IMAGE_3D: return "image3D";
217 case GL_IMAGE_2D_RECT: return "image2DRect";
218 case GL_IMAGE_CUBE: return "imageCube";
219 case GL_IMAGE_BUFFER: return "imageBuffer";
220 case GL_IMAGE_1D_ARRAY: return "image1DArray";
221 case GL_IMAGE_2D_ARRAY: return "image2DArray";
222 case GL_IMAGE_2D_MULTISAMPLE: return "image2DMS";
223 case GL_IMAGE_2D_MULTISAMPLE_ARRAY: return "image2DMSArray";
224 case GL_INT_IMAGE_1D: return "iimage1D";
225 case GL_INT_IMAGE_2D: return "iimage2D";
226 case GL_INT_IMAGE_3D: return "iimage3D";
227 case GL_INT_IMAGE_2D_RECT: return "iimage2DRect";
228 case GL_INT_IMAGE_CUBE: return "iimageCube";
229 case GL_INT_IMAGE_BUFFER: return "iimageBuffer";
230 case GL_INT_IMAGE_1D_ARRAY: return "iimage1DArray";
231 case GL_INT_IMAGE_2D_ARRAY: return "iimage2DArray";
232 case GL_INT_IMAGE_2D_MULTISAMPLE: return "iimage2DMS";
233 case GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY: return "iimage2DMSArray";
234 case GL_UNSIGNED_INT_IMAGE_1D: return "uimage1D";
235 case GL_UNSIGNED_INT_IMAGE_2D: return "uimage2D";
236 case GL_UNSIGNED_INT_IMAGE_3D: return "uimage3D";
237 case GL_UNSIGNED_INT_IMAGE_2D_RECT: return "uimage2DRect";
238 case GL_UNSIGNED_INT_IMAGE_CUBE: return "uimageCube";
239 case GL_UNSIGNED_INT_IMAGE_BUFFER: return "uimageBuffer";
240 case GL_UNSIGNED_INT_IMAGE_1D_ARRAY: return "uimage1DArray";
241 case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: return "uimage2DArray";
242 case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE: return "uimage2DMS";
243 case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY: return "uimage2DMSArray";
244 case GL_UNSIGNED_INT_ATOMIC_COUNTER: return "atomic_uint";
245 default: break;
246 }
247 return "other data type";
248}
249
250inline const char* CSCI441_INTERNAL::ShaderUtils::GL_shader_type_to_string(
251 const GLenum type
252) {
253 switch(type) {
254 case GL_VERTEX_SHADER: return "Vertex Shader";
255 case GL_TESS_CONTROL_SHADER: return "Tess Ctrl Shader";
256 case GL_TESS_EVALUATION_SHADER: return "Tess Eval Shader";
257 case GL_GEOMETRY_SHADER: return "Geometry Shader";
258 case GL_FRAGMENT_SHADER: return "Fragment Shader";
259 case GL_COMPUTE_SHADER: return "Compute Shader";
260 default: break;
261 }
262 return "other shader type";
263}
264
265inline const char* CSCI441_INTERNAL::ShaderUtils::GL_primitive_type_to_string(
266 const GLenum type
267) {
268 switch(type) {
269 case GL_POINTS: return "Points";
270 case GL_LINES: return "Lines";
271 case GL_LINE_STRIP: return "Line Strip";
272 case GL_LINE_LOOP: return "Line Loop";
273 case GL_LINES_ADJACENCY: return "Line Adjacency";
274 case GL_TRIANGLES: return "Triangles";
275 case GL_TRIANGLE_STRIP: return "Triangle Strip";
276 case GL_TRIANGLES_ADJACENCY: return "Triangle Adjacency";
277 case GL_PATCHES: return "Patches";
278 default: break;
279 }
280 return "other primitive type";
281}
282
283inline void CSCI441_INTERNAL::ShaderUtils::printShaderLog(
284 const GLuint shaderHandle
285) {
286 int status;
287 int infoLogLength = 0;
288 int maxLength;
289
290 // check if the handle is to a vertex/fragment shader
291 if( glIsShader( shaderHandle ) ) {
292 glGetShaderiv( shaderHandle, GL_INFO_LOG_LENGTH, &maxLength );
293
294 // create a buffer of designated length
295 char* infoLog = new char[maxLength];
296
297 glGetShaderiv( shaderHandle, GL_COMPILE_STATUS, &status );
298 if( sDEBUG ) printf( "[INFO]: | Shader Handle %2d: Compile%-26s |\n", shaderHandle, (status == 1 ? "d Successfully" : "r Error") );
299
300 // get the info log for the vertex/tesselation/geometry/fragment/compute shader
301 glGetShaderInfoLog(shaderHandle, maxLength, &infoLogLength, infoLog );
302
303 if(infoLogLength > 0 ) {
304 // print info to terminal
305 if( sDEBUG ) printf( "[INFO]: | Shader Handle %d: %s\n", shaderHandle, infoLog );
306 }
307
308 delete[] infoLog;
309 } else {
310 if( sDEBUG ) fprintf( stderr, "[WARN]: | Handle %-3d is not for a Shader |\n", shaderHandle );
311 }
312}
313
314inline void CSCI441_INTERNAL::ShaderUtils::printProgramLog(
315 const GLuint programHandle
316) {
317 int status;
318 int infoLogLength = 0;
319 int maxLength;
320
321 // check if the handle is to a vertex/fragment shader
322 if( glIsProgram( programHandle ) ) {
323 glGetProgramiv( programHandle, GL_INFO_LOG_LENGTH, &maxLength );
324
325 // create a buffer of designated length
326 char* infoLog = new char[maxLength];
327
328 glGetProgramiv( programHandle, GL_LINK_STATUS, &status );
329 if( sDEBUG ) printf("[INFO]: | Program Handle %2d: Linke%-28s |\n", programHandle, (status == 1 ? "d Successfully" : "r Error") );
330
331 // get the info log for the vertex/tesselation/geometry/fragment/compute shader
332 glGetProgramInfoLog(programHandle, maxLength, &infoLogLength, infoLog );
333
334 if(infoLogLength > 0 ) {
335 // print info to terminal
336 if( sDEBUG ) printf( "[INFO]: | Program Handle %d: %s\n", programHandle, infoLog );
337 }
338
339 delete[] infoLog;
340 } else {
341 if( sDEBUG ) fprintf( stderr, "[WARN]: | Handle %-3d is not for a Shader Program |\n", programHandle );
342 }
343}
344
345inline void CSCI441_INTERNAL::ShaderUtils::printProgramPipelineLog(
346 const GLuint pipelineHandle
347) {
348 // check if the handle is to a shader program pipeline
349 if( glIsProgramPipeline( pipelineHandle ) ) {
350 int infoLogLength;
351 int maxLength;
352
353 glGetProgramPipelineiv( pipelineHandle, GL_INFO_LOG_LENGTH, &maxLength );
354
355 // create a buffer of designated length
356 char* infoLog = new char[maxLength];
357
358 // get the info log for the shader program pipeline
359 glGetProgramPipelineInfoLog(pipelineHandle, maxLength, &infoLogLength, infoLog );
360
361 if( infoLogLength > 0 ) {
362 // print info to terminal
363 if( sDEBUG ) printf( "[INFO]: | Pipeline Handle %d: %s\n", pipelineHandle, infoLog );
364 }
365
366 delete[] infoLog;
367 } else {
368 if( sDEBUG ) fprintf( stderr, "[WARN]: | Handle %-3d is not for a Shader Program Pipeline |\n", pipelineHandle );
369 }
370}
371
372inline GLboolean CSCI441_INTERNAL::ShaderUtils::printSubroutineInfo(
373 const GLuint programHandle,
374 const GLenum shaderStage,
375 const GLboolean printHeader
376) {
377 int params, params2;
378 int *params3;
379
380 glGetProgramStageiv(programHandle, shaderStage, GL_ACTIVE_SUBROUTINE_UNIFORMS, &params);
381 bool headerPrinted = false;
382 if( params > 0 ) {
383 if( printHeader ) {
384 printf( "[INFO]: >--------------------------------------------------------<\n");
385 headerPrinted = true;
386 }
387 printf("[INFO]: | GL_ACTIVE_SUBROUTINE_UNIFORMS (%-15s): %5i |\n", CSCI441_INTERNAL::ShaderUtils::GL_shader_type_to_string(shaderStage), params);
388 for(int i = 0; i < params; i++ ) {
389 char name[256];
390 int max_length = 256;
391 int actual_length = 0;
392
393 glGetActiveSubroutineUniformName(programHandle, shaderStage, i, max_length, &actual_length, name );
394 glGetActiveSubroutineUniformiv(programHandle, shaderStage, i, GL_NUM_COMPATIBLE_SUBROUTINES, &params2 );
395 params3 = (int*)malloc(sizeof(int) * params2);
396 glGetActiveSubroutineUniformiv(programHandle, shaderStage, i, GL_COMPATIBLE_SUBROUTINES, params3 );
397 GLint loc = glGetSubroutineUniformLocation(programHandle, shaderStage, name );
398
399 printf("[INFO]: | %i) name: %-15s #subRoutines: %-5i loc: %2i |\n", i, name, params2, loc );
400
401 for(int j = 0; j < params2; j++ ) {
402 GLint idx = params3[j];
403
404 char name2[64];
405 int max_length2 = 64;
406 int actual_length2 = 0;
407 glGetActiveSubroutineName(programHandle, shaderStage, idx, max_length2, &actual_length2, name2 );
408
409 printf("[INFO]: | %i) subroutine: %-25s index: %2i |\n", j, name2, idx );
410 }
411
412 free(params3);
413 }
414 }
415 return !headerPrinted;
416}
417
418inline void CSCI441_INTERNAL::ShaderUtils::printShaderProgramInfo(
419 const GLuint programHandle,
420 const GLboolean hasVertexShader,
421 const GLboolean hasTessControlShader,
422 const GLboolean hasTessEvalShader,
423 const GLboolean hasGeometryShader,
424 const GLboolean hasFragmentShader,
425 const GLboolean hasComputeShader,
426 const GLboolean useLastNewLine = true
427) {
428 GLint major, minor;
429 glGetIntegerv(GL_MAJOR_VERSION, &major);
430 glGetIntegerv(GL_MINOR_VERSION, &minor);
431
432 int params;
433
434 GLuint shaders[6];
435 int max_count = 6;
436 int actual_count;
437
438 GLint max_attr_name_size;
439 GLint max_uniform_name_size;
440
441 // get max var name from program
442 // https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGetActiveAttrib.xhtml
443 glGetProgramiv(programHandle, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attr_name_size);
444 glGetProgramiv(programHandle, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_name_size);
445
446 glGetAttachedShaders(programHandle, max_count, &actual_count, shaders );
447 if(actual_count > 0) {
448 if( sDEBUG ) printf( "[INFO]: >--------------------------------------------------------<\n");
449 if( sDEBUG ) printf("[INFO]: | GL_ATTACHED_SHADERS: %33i |\n", actual_count);
450 for(int i = 0; i < actual_count; i++ ) {
451 GLint shaderType;
452 glGetShaderiv( shaders[i], GL_SHADER_TYPE, &shaderType );
453 if( sDEBUG ) printf("[INFO]: | %i) %-38s Handle: %2i |\n", i, GL_shader_type_to_string(shaderType), shaders[i]);
454 }
455 }
456
457 if(sDEBUG) {
458 if(hasGeometryShader) {
459 if( major > 3 || (major >= 3 && minor >= 2) ) {
460 GLint verticesOut, inputType, outputType;
461 glGetProgramiv(programHandle, GL_GEOMETRY_VERTICES_OUT, &verticesOut);
462 glGetProgramiv(programHandle, GL_GEOMETRY_INPUT_TYPE, &inputType);
463 glGetProgramiv(programHandle, GL_GEOMETRY_OUTPUT_TYPE, &outputType);
464
465 printf( "[INFO]: >--------------------------------------------------------<\n");
466 printf( "[INFO]: | GEOMETRY SHADER PRIMITIVE I/O |\n");
467 printf( "[INFO]: | Input Type: %40s |\n", GL_primitive_type_to_string(inputType) );
468 printf( "[INFO]: | Output Type: %39s |\n", GL_primitive_type_to_string(outputType) );
469 printf( "[INFO]: | Max Vertices Out: %34d |\n", verticesOut );
470 }
471 }
472 }
473
474 if(hasVertexShader) {
475 glGetProgramiv(programHandle, GL_ACTIVE_ATTRIBUTES, &params );
476 if( params > 0 ) {
477 if( sDEBUG ) printf( "[INFO]: >--------------------------------------------------------<\n");
478 if( sDEBUG ) printf( "[INFO]: | GL_ACTIVE_ATTRIBUTES: %32i |\n", params );
479 for( int i = 0; i < params; i++ ) {
480 char* name = (char*) malloc(max_attr_name_size * sizeof(char));
481 int actual_length = 0;
482 int size = 0;
483 GLenum type;
484 glGetActiveAttrib(programHandle, i, max_attr_name_size, &actual_length, &size, &type, name );
485 if( size > 1 ) {
486 for( int j = 0; j < size; j++ ) {
487 // length of string + max array value size (technically it depends on the size of GL type, but I'm not aware a way to get the size)
488 // + array accessors + null
489 int max_array_size = actual_length + 4 + 2 + 1;
490 char* array_name = (char*) malloc(max_array_size * sizeof(char));
491
492 snprintf( array_name, max_array_size, "%s[%i]", name, j );
493 int location = glGetAttribLocation(programHandle, array_name);
494 if( sDEBUG ) printf( "[INFO]: | %i) type: %-15s name: %-13s loc: %2i |\n", i, GLSL_type_to_string( type ), array_name, location );
495 free(array_name);
496 }
497 } else {
498 int location = glGetAttribLocation(programHandle, name );
499 if( sDEBUG ) printf( "[INFO]: | %i) type: %-15s name: %-13s loc: %2i |\n",i, GLSL_type_to_string( type ), name, location );
500 }
501
502 free(name);
503 }
504 }
505 }
506
507 glGetProgramiv(programHandle, GL_ACTIVE_UNIFORMS, &params);
508 if( params > 0 ) {
509 if( sDEBUG ) printf( "[INFO]: >--------------------------------------------------------<\n" );
510 if( sDEBUG ) printf("[INFO]: | GL_ACTIVE_UNIFORMS: %34i |\n", params);
511 for(int i = 0; i < params; i++) {
512 char* name = (char*) malloc(max_uniform_name_size * sizeof(char));
513 int actual_length = 0;
514 int size = 0;
515 GLenum type;
516 glGetActiveUniform(programHandle, i, max_uniform_name_size, &actual_length, &size, &type, name );
517 if(size > 1) {
518 for(int j = 0; j < size; j++) {
519 int max_array_size = actual_length + 4 + 2 + 1;
520 char* array_name = (char*) malloc(max_array_size * sizeof(char));
521 snprintf(array_name, max_array_size, "%s[%i]", name, j);
522 int location = glGetUniformLocation(programHandle, array_name);
523 if(location != -1) {
524 if (sDEBUG) printf("[INFO]: | %2i) type: %-15s name: %-13s loc: %2i |\n", i, GLSL_type_to_string(type), array_name, location);
525 }
526 free(array_name);
527 }
528 } else {
529 int location = glGetUniformLocation(programHandle, name);
530 if(location != -1) {
531 if (sDEBUG) printf("[INFO]: | %2i) type: %-15s name: %-13s loc: %2i |\n",i, GLSL_type_to_string(type), name, location);
532 }
533 }
534 free(name);
535 }
536 }
537
538 int vsCount, tcsCount, tesCount, gsCount, fsCount, csCount;
539 vsCount = tcsCount = tesCount = gsCount = fsCount = csCount = 0;
540
541 glGetProgramiv(programHandle, GL_ACTIVE_UNIFORM_BLOCKS, &params);
542 if( params > 0 ) {
543 if( sDEBUG ) printf( "[INFO]: >--------------------------------------------------------<\n");
544 if( sDEBUG ) printf("[INFO]: | GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS: %20d |\n", params);
545 for(int i = 0; i < params; i++ ) {
546 int params2;
547 glGetActiveUniformBlockiv(programHandle, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &params2 );
548
549 int actualLen;
550 glGetActiveUniformBlockiv(programHandle, i, GL_UNIFORM_BLOCK_NAME_LENGTH, &actualLen);
551 char *name = (char *)malloc(sizeof(char) * actualLen);
552 glGetActiveUniformBlockName(programHandle, i, actualLen, nullptr, name);
553
554 auto indices = (GLuint*)malloc(params2*sizeof(GLuint));
555 glGetActiveUniformBlockiv(programHandle, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, (GLint*)indices);
556
557 auto offsets = (GLint*)malloc(params2*sizeof(GLint));
558 glGetActiveUniformsiv(programHandle, params2, indices, GL_UNIFORM_OFFSET, offsets);
559
560 if( sDEBUG ) printf("[INFO]: | %d) %-34s # Uniforms: %2d |\n", i, name, params2);
561
562 GLint vs, tcs, tes, gs, fs, cs;
563 glGetActiveUniformBlockiv(programHandle, i, GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER, &vs); if( vs ) vsCount++;
564 glGetActiveUniformBlockiv(programHandle, i, GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_CONTROL_SHADER, &tcs); if( tcs) tcsCount++;
565 glGetActiveUniformBlockiv(programHandle, i, GL_UNIFORM_BLOCK_REFERENCED_BY_TESS_EVALUATION_SHADER, &tes); if( tes) tesCount++;
566 glGetActiveUniformBlockiv(programHandle, i, GL_UNIFORM_BLOCK_REFERENCED_BY_GEOMETRY_SHADER, &gs); if( gs ) gsCount++;
567 glGetActiveUniformBlockiv(programHandle, i, GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER, &fs); if( fs ) fsCount++;
568 glGetActiveUniformBlockiv(programHandle, i, GL_UNIFORM_BLOCK_REFERENCED_BY_COMPUTE_SHADER, &cs); if( cs ) csCount++;
569 if( sDEBUG ) printf("[INFO]: | Used in: %-4s %-4s %-4s %-3s %-4s %-4s Shader(s) |\n", (vs ? "Vert" : ""), (tcs ? "Ctrl" : ""), (tes ? "Eval" : ""), (gs ? "Geo" : ""), (fs ? "Frag" : ""), (cs ? "Comp" : ""));
570
571 int maxUniLength;
572 glGetProgramiv(programHandle, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxUniLength);
573 char *name2 = (char *)malloc(sizeof(char) * maxUniLength);
574 for(int j = 0; j < params2; j++) {
575 GLenum type;
576 int uniSize;
577 glGetActiveUniform(programHandle, indices[j], maxUniLength, &actualLen, &uniSize, &type, name2);
578
579 if( sDEBUG ) {
580 printf("[INFO]: | %2d) type: %-15s name: %-21s |\n", j, GLSL_type_to_string(type), name2);
581 printf("[INFO]: | uniform index: %3d offset: %4d |\n", indices[j], offsets[j]);
582 }
583 }
584 }
585
586 if( vsCount + tcsCount + tesCount + gsCount + fsCount + csCount > 0 ) {
587 GLint maxUniBlocks = 0;
588 glGetIntegerv( GL_MAX_COMBINED_UNIFORM_BLOCKS, &maxUniBlocks );
589 if( sDEBUG ) printf( "[INFO]: | Shader Uniform Block Counts %2d/%2d |\n", params, maxUniBlocks);
590 if( hasVertexShader ) {
591 GLint maxVertexUniformBlocks = 0;
592 glGetIntegerv( GL_MAX_VERTEX_UNIFORM_BLOCKS, &maxVertexUniformBlocks );
593
594 if( sDEBUG ) printf( "[INFO]: | Vertex Shader Uniform Blocks: %18d/%2d |\n", vsCount, maxVertexUniformBlocks );
595 }
596 if( hasTessControlShader ) {
597 GLint maxTessControlUniformBlocks = 0;
598 glGetIntegerv( GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS, &maxTessControlUniformBlocks );
599
600 if( sDEBUG ) printf( "[INFO]: | Tess Ctrl Shader Uniform Blocks: %15d/%2d |\n", tcsCount, maxTessControlUniformBlocks );
601 }
602 if( hasTessEvalShader ) {
603 GLint maxTessEvalUniformBlocks = 0;
604 glGetIntegerv( GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS, &maxTessEvalUniformBlocks );
605
606 if( sDEBUG ) printf( "[INFO]: | Tess Eval Shader Uniform Blocks: %15d/%2d |\n", tesCount, maxTessEvalUniformBlocks );
607 }
608 if( hasGeometryShader ) {
609 GLint maxGeometryUniformBlocks = 0;
610 glGetIntegerv( GL_MAX_GEOMETRY_UNIFORM_BLOCKS, &maxGeometryUniformBlocks );
611
612 if( sDEBUG ) printf( "[INFO]: | Geometry Shader Uniform Blocks: %16d/%2d |\n", gsCount, maxGeometryUniformBlocks );
613 }
614 if( hasFragmentShader ) {
615 GLint maxFragmentUniformBlocks = 0;
616 glGetIntegerv( GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &maxFragmentUniformBlocks );
617
618 if( sDEBUG ) printf( "[INFO]: | Fragment Shader Uniform Blocks: %16d/%2d |\n", fsCount, maxFragmentUniformBlocks );
619 }
620 if( hasComputeShader ) {
621 GLint maxComputeUniformBlocks = 0;
622 glGetIntegerv( GL_MAX_COMPUTE_UNIFORM_BLOCKS, &maxComputeUniformBlocks );
623
624 if( sDEBUG ) printf( "[INFO]: | Compute Shader Uniform Blocks: %17d/%2d |\n", csCount, maxComputeUniformBlocks );
625 }
626 }
627 }
628
629 if( sDEBUG ) {
630 if((major == 4 && minor >= 3) || major > 4) {
631 GLint paramsSSBO[1];
632 glGetProgramInterfaceiv(programHandle, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, paramsSSBO);
633 if(paramsSSBO[0] > 0) {
634 GLint maxLen;
635 glGetProgramInterfaceiv(programHandle, GL_SHADER_STORAGE_BLOCK, GL_MAX_NAME_LENGTH, &maxLen);
636 auto ssboName = (GLchar*)malloc(sizeof(GLchar)*maxLen);
637 GLsizei ssboNameLen;
638
639 const int NUM_PROPS = 7;
640 GLenum props[NUM_PROPS] = {GL_BUFFER_BINDING,
641 GL_REFERENCED_BY_VERTEX_SHADER,
642 GL_REFERENCED_BY_TESS_CONTROL_SHADER, GL_REFERENCED_BY_TESS_EVALUATION_SHADER,
643 GL_REFERENCED_BY_GEOMETRY_SHADER,
644 GL_REFERENCED_BY_FRAGMENT_SHADER,
645 GL_REFERENCED_BY_COMPUTE_SHADER};
646 GLsizei numWritten;
647 GLint results[NUM_PROPS];
648
649 int vSSB, teSSB, tcSSB, gSSB, fSSB, cSSB;
650 vSSB = teSSB = tcSSB = gSSB = fSSB = cSSB = 0;
651
652 printf( "[INFO]: >--------------------------------------------------------<\n");
653 printf( "[INFO]: | GL_SHADER_STORAGE_BLOCK: %29d |\n", paramsSSBO[0] );
654 for(int i = 0; i < paramsSSBO[0]; i++) {
655 glGetProgramResourceName(programHandle, GL_SHADER_STORAGE_BLOCK, i, maxLen, &ssboNameLen, ssboName);
656 GLuint ssboIndex = glGetProgramResourceIndex(programHandle, GL_SHADER_STORAGE_BLOCK, ssboName);
657 glGetProgramResourceiv(programHandle, GL_SHADER_STORAGE_BLOCK, i, NUM_PROPS, props, NUM_PROPS, &numWritten, results);
658
659 printf( "[INFO]: | %3d) name: %-19s index: %3d binding: %3d |\n", i, ssboName, ssboIndex, results[0] );
660 printf( "[INFO]: | Used in: %-4s %-4s %-4s %-3s %-4s %-4s Shader(s) |\n", (results[1] ? "Vert" : ""), (results[2] ? "Ctrl" : ""), (results[3] ? "Eval" : ""), (results[4] ? "Geo" : ""), (results[5] ? "Frag" : ""), (results[6] ? "Comp" : ""));
661
662 if(results[1]) vSSB++;
663 if(results[2]) teSSB++;
664 if(results[3]) tcSSB++;
665 if(results[4]) gSSB++;
666 if(results[5]) fSSB++;
667 if(results[6]) cSSB++;
668 }
669
670 GLint maxSSBCounters = 0;
671 glGetIntegerv( GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, &maxSSBCounters );
672 printf( "[INFO]: | Shader Storage Block Counts: %2d/%2d |\n", paramsSSBO[0], maxSSBCounters );
673 if(hasVertexShader) {
674 GLint maxVertSSB = 0;
675 glGetIntegerv( GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &maxVertSSB );
676 printf( "[INFO]: | Vertex Shader Storage Blocks: %2d/%2d |\n", vSSB, maxVertSSB );
677 }
678 if(hasTessControlShader) {
679 GLint maxTESSB = 0;
680 glGetIntegerv( GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS, &maxTESSB );
681 printf( "[INFO]: | Tess Ctrl Shader Storage Blocks: %2d/%2d |\n", teSSB, maxTESSB );
682 }
683 if(hasTessEvalShader) {
684 GLint maxTCSSB = 0;
685 glGetIntegerv( GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS, &maxTCSSB );
686 printf( "[INFO]: | Tess Eval Shader Storage Blocks: %2d/%2d |\n", tcSSB, maxTCSSB );
687 }
688 if(hasGeometryShader) {
689 GLint maxGeoSSB = 0;
690 glGetIntegerv( GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS, &maxGeoSSB );
691 printf( "[INFO]: | Geometry Shader Storage Blocks: %2d/%2d |\n", gSSB, maxGeoSSB );
692 }
693 if(hasFragmentShader) {
694 GLint maxFragSSB = 0;
695 glGetIntegerv( GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &maxFragSSB );
696 printf( "[INFO]: | Fragment Shader Storage Blocks: %2d/%2d |\n", fSSB, maxFragSSB );
697 }
698 if(hasComputeShader) {
699 GLint maxComputeSSB = 0;
700 glGetIntegerv( GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, &maxComputeSSB );
701 printf( "[INFO]: | Compute Shader Storage Blocks: %2d/%2d |\n", cSSB, maxComputeSSB );
702 }
703 }
704 }
705
706 if((major == 4 && minor >= 2) || major > 4) {
707 GLint paramsAtomic[1];
708 glGetProgramInterfaceiv(programHandle, GL_ATOMIC_COUNTER_BUFFER, GL_ACTIVE_RESOURCES, paramsAtomic);
709 if(paramsAtomic[0] > 0) {
710 GLint maxLen;
711 glGetProgramInterfaceiv(programHandle, GL_ATOMIC_COUNTER_BUFFER, GL_MAX_NAME_LENGTH, &maxLen);
712 auto atomicName = (GLchar*)malloc(sizeof(GLchar)*maxLen);
713 GLsizei atomicNameLen;
714
715 const int NUM_PROPS = 8;
716 GLenum props[NUM_PROPS] = {GL_BUFFER_BINDING,
717 GL_REFERENCED_BY_VERTEX_SHADER,
718 GL_REFERENCED_BY_TESS_CONTROL_SHADER,
719 GL_REFERENCED_BY_TESS_EVALUATION_SHADER,
720 GL_REFERENCED_BY_GEOMETRY_SHADER,
721 GL_REFERENCED_BY_FRAGMENT_SHADER,
722 GL_REFERENCED_BY_COMPUTE_SHADER,
723 GL_BUFFER_DATA_SIZE};
724 GLsizei numWritten;
725 GLint results[NUM_PROPS];
726
727 printf( "[INFO]: >--------------------------------------------------------<\n");
728 printf("[INFO]: | GL_ATOMIC_COUNTER_BUFFER: %28d |\n", paramsAtomic[0] );
729
730 int vAC, teAC, tcAC, gAC, fAC, cAC;
731 vAC = teAC = tcAC = gAC = fAC = cAC = 0;
732
733 GLint numUniforms;
734 glGetProgramiv(programHandle, GL_ACTIVE_UNIFORMS, &numUniforms);
735 for(int j = 0; j < numUniforms; j++) {
736 int size = 0;
737 GLenum type;
738 glGetActiveUniform(programHandle, j, maxLen, &atomicNameLen, &size, &type, atomicName );
739
740 GLuint atomicIndex = glGetProgramResourceIndex(programHandle, GL_UNIFORM, atomicName);
741
742 GLenum atomicProps[1] = {GL_ATOMIC_COUNTER_BUFFER_INDEX};
743 GLint atomicResults[1];
744 glGetProgramResourceiv(programHandle, GL_UNIFORM, atomicIndex, 1, atomicProps, 1, nullptr, atomicResults);
745
746 if(atomicResults[0] != -1) {
747 glGetProgramResourceiv(programHandle, GL_ATOMIC_COUNTER_BUFFER, atomicResults[0], NUM_PROPS, props, NUM_PROPS, &numWritten, results);
748
749 GLint offset;
750 glGetActiveUniformsiv(programHandle, 1, &atomicIndex, GL_UNIFORM_OFFSET, &offset);
751
752 printf( "[INFO]: | %3d) type: %-15s name: %-21s |\n", atomicResults[0], GLSL_type_to_string(type), atomicName );
753 printf( "[INFO]: | uniform index: %3d atomic index: %3d |\n", atomicIndex, atomicResults[0] );
754 printf( "[INFO]: | binding: %3d offset: %3d buffer size: %4d |\n", results[0], offset, results[7] );
755 printf( "[INFO]: | Used in: %-4s %-4s %-4s %-3s %-4s %-4s Shader(s) |\n", (results[1] ? "Vert" : ""), (results[2] ? "Ctrl" : ""), (results[3] ? "Eval" : ""), (results[4] ? "Geo" : ""), (results[5] ? "Frag" : ""), (results[6] ? "Comp" : ""));
756
757 if(results[1]) vAC++;
758 if(results[2]) teAC++;
759 if(results[3]) tcAC++;
760 if(results[4]) gAC++;
761 if(results[5]) fAC++;
762 if(results[6]) cAC++;
763 }
764 }
765
766 GLint maxAtomicCounters = 0;
767 glGetIntegerv( GL_MAX_COMBINED_ATOMIC_COUNTERS, &maxAtomicCounters );
768 printf("[INFO]: | Atomic Counter Counts: %4d/%4d |\n", paramsAtomic[0], maxAtomicCounters );
769 if(hasVertexShader) {
770 GLint maxVertAtomicCounters = 0;
771 glGetIntegerv( GL_MAX_VERTEX_ATOMIC_COUNTERS, &maxVertAtomicCounters );
772 printf( "[INFO]: | Vertex Atomic Counters: %4d/%4d |\n", vAC, maxVertAtomicCounters );
773 }
774 if(hasTessControlShader) {
775 GLint maxTCAtomicCounters = 0;
776 glGetIntegerv( GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS, &maxTCAtomicCounters );
777 printf( "[INFO]: | Tess Ctrl Atomic Counters: %4d/%4d |\n", teAC, maxTCAtomicCounters );
778 }
779 if(hasTessEvalShader) {
780 GLint maxTEAtomicCounters = 0;
781 glGetIntegerv( GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS, &maxTEAtomicCounters );
782 printf( "[INFO]: | Tess Eval Atomic Counters: %4d/%4d |\n", tcAC, maxTEAtomicCounters );
783 }
784 if(hasGeometryShader) {
785 GLint maxGeoAtomicCounters = 0;
786 glGetIntegerv( GL_MAX_GEOMETRY_ATOMIC_COUNTERS, &maxGeoAtomicCounters );
787 printf( "[INFO]: | Geometry Atomic Counters: %4d/%4d |\n", gAC, maxGeoAtomicCounters );
788 }
789 if(hasFragmentShader) {
790 GLint maxFragAtomicCounters = 0;
791 glGetIntegerv( GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &maxFragAtomicCounters );
792 printf( "[INFO]: | Fragment Atomic Counters: %4d/%4d |\n", fAC, maxFragAtomicCounters );
793 }
794 if(hasComputeShader) {
795 GLint maxComputeAtomicCounters = 0;
796 glGetIntegerv( GL_MAX_COMPUTE_ATOMIC_COUNTERS, &maxComputeAtomicCounters );
797 printf( "[INFO]: | Compute Atomic Counters: %4d/%4d |\n", cAC, maxComputeAtomicCounters );
798 }
799 }
800 }
801
802 if( major >= 4 ) {
803 GLboolean printHeader = GL_TRUE;
804 if( hasVertexShader ) printHeader = printSubroutineInfo(programHandle, GL_VERTEX_SHADER, printHeader );
805 if( hasTessControlShader) printHeader = printSubroutineInfo(programHandle, GL_TESS_CONTROL_SHADER, printHeader );
806 if( hasTessEvalShader) printHeader = printSubroutineInfo(programHandle, GL_TESS_EVALUATION_SHADER, printHeader );
807 if( hasGeometryShader ) printHeader = printSubroutineInfo(programHandle, GL_GEOMETRY_SHADER, printHeader );
808 if( hasFragmentShader ) printHeader = printSubroutineInfo(programHandle, GL_FRAGMENT_SHADER, printHeader );
809 if( hasComputeShader ) printSubroutineInfo(programHandle, GL_COMPUTE_SHADER, printHeader );
810 }
811 }
812
813 if(useLastNewLine) printf( "[INFO]: \\--------------------------------------------------------/\n\n");
814}
815
816inline GLuint CSCI441_INTERNAL::ShaderUtils::compileShader(
817 const char *filename,
818 const GLenum shaderType
819) {
820 GLuint shaderHandle = glCreateShader( shaderType ); char *shaderString;
821
822 // read in each text file and store the contents in a string
823 if( readTextFromFile( filename, shaderString ) ) {
824
825 // send the contents of each program to the GPU
826 glShaderSource( shaderHandle, 1, (const char**)&shaderString, nullptr );
827
828 // we are good programmers so free up the memory used by each buffer
829 delete [] shaderString;
830
831 // compile each shader on the GPU
832 glCompileShader( shaderHandle );
833
834 // check the shader log
835 printShaderLog( shaderHandle );
836
837 // return the handle of our shader
838 return shaderHandle;
839 } else {
840 return 0;
841 }
842}
843
844#endif // CSCI441_SHADER_UTILS_HPP