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