shaderutil.c revision 7ec3b29a
1/** 2 * Utilities for OpenGL shading language 3 * 4 * Brian Paul 5 * 9 April 2008 6 */ 7 8 9#include <assert.h> 10#include <stdio.h> 11#include <stdlib.h> 12#include <string.h> 13#include <GL/glew.h> 14#include "glut_wrap.h" 15#include "shaderutil.h" 16 17/** time to compile previous shader */ 18static GLdouble CompileTime = 0.0; 19 20/** time to linke previous program */ 21static GLdouble LinkTime = 0.0; 22 23PFNGLCREATESHADERPROC CreateShader = NULL; 24PFNGLDELETESHADERPROC DeleteShader = NULL; 25PFNGLSHADERSOURCEPROC ShaderSource = NULL; 26PFNGLGETSHADERIVPROC GetShaderiv = NULL; 27PFNGLGETSHADERINFOLOGPROC GetShaderInfoLog = NULL; 28PFNGLCREATEPROGRAMPROC CreateProgram = NULL; 29PFNGLDELETEPROGRAMPROC DeleteProgram = NULL; 30PFNGLATTACHSHADERPROC AttachShader = NULL; 31PFNGLLINKPROGRAMPROC LinkProgram = NULL; 32PFNGLUSEPROGRAMPROC UseProgram = NULL; 33PFNGLGETPROGRAMIVPROC GetProgramiv = NULL; 34PFNGLGETPROGRAMINFOLOGPROC GetProgramInfoLog = NULL; 35PFNGLVALIDATEPROGRAMARBPROC ValidateProgramARB = NULL; 36PFNGLUNIFORM1IPROC Uniform1i = NULL; 37PFNGLUNIFORM1FVPROC Uniform1fv = NULL; 38PFNGLUNIFORM2FVPROC Uniform2fv = NULL; 39PFNGLUNIFORM3FVPROC Uniform3fv = NULL; 40PFNGLUNIFORM4FVPROC Uniform4fv = NULL; 41PFNGLUNIFORMMATRIX4FVPROC UniformMatrix4fv = NULL; 42PFNGLGETACTIVEATTRIBPROC GetActiveAttrib = NULL; 43PFNGLGETATTRIBLOCATIONPROC GetAttribLocation = NULL; 44 45static void GLAPIENTRY 46fake_ValidateProgram(GLuint prog) 47{ 48 (void) prog; 49} 50 51GLboolean 52ShadersSupported(void) 53{ 54 if (GLEW_VERSION_2_0) { 55 CreateShader = glCreateShader; 56 DeleteShader = glDeleteShader; 57 ShaderSource = glShaderSource; 58 GetShaderiv = glGetShaderiv; 59 GetShaderInfoLog = glGetShaderInfoLog; 60 CreateProgram = glCreateProgram; 61 DeleteProgram = glDeleteProgram; 62 AttachShader = glAttachShader; 63 LinkProgram = glLinkProgram; 64 UseProgram = glUseProgram; 65 GetProgramiv = glGetProgramiv; 66 GetProgramInfoLog = glGetProgramInfoLog; 67 ValidateProgramARB = (GLEW_ARB_shader_objects) 68 ? glValidateProgramARB : fake_ValidateProgram; 69 Uniform1i = glUniform1i; 70 Uniform1fv = glUniform1fv; 71 Uniform2fv = glUniform2fv; 72 Uniform3fv = glUniform3fv; 73 Uniform4fv = glUniform4fv; 74 UniformMatrix4fv = glUniformMatrix4fv; 75 GetActiveAttrib = glGetActiveAttrib; 76 GetAttribLocation = glGetAttribLocation; 77 return GL_TRUE; 78 } 79 else if (GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader 80 && GLEW_ARB_shader_objects) { 81 fprintf(stderr, "Warning: Trying ARB GLSL instead of OpenGL 2.x. This may not work.\n"); 82 CreateShader = glCreateShaderObjectARB; 83 DeleteShader = glDeleteObjectARB; 84 ShaderSource = glShaderSourceARB; 85 GetShaderiv = glGetObjectParameterivARB; 86 GetShaderInfoLog = glGetInfoLogARB; 87 CreateProgram = glCreateProgramObjectARB; 88 DeleteProgram = glDeleteObjectARB; 89 AttachShader = glAttachObjectARB; 90 LinkProgram = glLinkProgramARB; 91 UseProgram = glUseProgramObjectARB; 92 GetProgramiv = glGetObjectParameterivARB; 93 GetProgramInfoLog = glGetInfoLogARB; 94 ValidateProgramARB = glValidateProgramARB; 95 Uniform1i = glUniform1iARB; 96 Uniform1fv = glUniform1fvARB; 97 Uniform2fv = glUniform2fvARB; 98 Uniform3fv = glUniform3fvARB; 99 Uniform4fv = glUniform4fvARB; 100 UniformMatrix4fv = glUniformMatrix4fvARB; 101 GetActiveAttrib = glGetActiveAttribARB; 102 GetAttribLocation = glGetAttribLocationARB; 103 return GL_TRUE; 104 } 105 fprintf(stderr, "Sorry, GLSL not supported with this OpenGL.\n"); 106 return GL_FALSE; 107} 108 109 110GLuint 111CompileShaderText(GLenum shaderType, const char *text) 112{ 113 GLuint shader; 114 GLint stat; 115 GLdouble t0, t1; 116 117 shader = CreateShader(shaderType); 118 ShaderSource(shader, 1, (const GLchar **) &text, NULL); 119 120 t0 = glutGet(GLUT_ELAPSED_TIME) * 0.001; 121 glCompileShader(shader); 122 t1 = glutGet(GLUT_ELAPSED_TIME) * 0.001; 123 124 CompileTime = t1 - t0; 125 126 GetShaderiv(shader, GL_COMPILE_STATUS, &stat); 127 if (!stat) { 128 GLchar log[1000]; 129 GLsizei len; 130 GetShaderInfoLog(shader, 1000, &len, log); 131 fprintf(stderr, "Error: problem compiling shader: %s\n", log); 132 exit(1); 133 } 134 else { 135 /*printf("Shader compiled OK\n");*/ 136 } 137 return shader; 138} 139 140 141/** 142 * Read a shader from a file. 143 */ 144GLuint 145CompileShaderFile(GLenum shaderType, const char *filename) 146{ 147 const int max = 100*1000; 148 int n; 149 char *buffer = (char*) malloc(max); 150 GLuint shader; 151 FILE *f; 152 153 f = fopen(filename, "r"); 154 if (!f) { 155 fprintf(stderr, "Unable to open shader file %s\n", filename); 156 free(buffer); 157 return 0; 158 } 159 160 n = fread(buffer, 1, max, f); 161 /*printf("read %d bytes from shader file %s\n", n, filename);*/ 162 if (n > 0) { 163 buffer[n] = 0; 164 shader = CompileShaderText(shaderType, buffer); 165 } 166 else { 167 fclose(f); 168 free(buffer); 169 return 0; 170 } 171 172 fclose(f); 173 free(buffer); 174 175 return shader; 176} 177 178 179GLuint 180LinkShaders(GLuint vertShader, GLuint fragShader) 181{ 182 return LinkShaders3(vertShader, 0, fragShader); 183} 184 185 186GLuint 187LinkShaders3(GLuint vertShader, GLuint geomShader, GLuint fragShader) 188{ 189 GLuint program = CreateProgram(); 190 GLdouble t0, t1; 191 192 assert(vertShader || fragShader); 193 194 if (vertShader) 195 AttachShader(program, vertShader); 196 if (geomShader) 197 AttachShader(program, geomShader); 198 if (fragShader) 199 AttachShader(program, fragShader); 200 201 t0 = glutGet(GLUT_ELAPSED_TIME) * 0.001; 202 LinkProgram(program); 203 t1 = glutGet(GLUT_ELAPSED_TIME) * 0.001; 204 205 LinkTime = t1 - t0; 206 207 /* check link */ 208 { 209 GLint stat; 210 GetProgramiv(program, GL_LINK_STATUS, &stat); 211 if (!stat) { 212 GLchar log[1000]; 213 GLsizei len; 214 GetProgramInfoLog(program, 1000, &len, log); 215 fprintf(stderr, "Shader link error:\n%s\n", log); 216 return 0; 217 } 218 } 219 220 return program; 221} 222 223 224GLuint 225LinkShaders3WithGeometryInfo(GLuint vertShader, GLuint geomShader, GLuint fragShader, 226 GLint verticesOut, GLenum inputType, GLenum outputType) 227{ 228 GLuint program = CreateProgram(); 229 GLdouble t0, t1; 230 231 assert(vertShader || fragShader); 232 233 if (vertShader) 234 AttachShader(program, vertShader); 235 if (geomShader) { 236 AttachShader(program, geomShader); 237 glProgramParameteriARB(program, GL_GEOMETRY_VERTICES_OUT_ARB, verticesOut); 238 glProgramParameteriARB(program, GL_GEOMETRY_INPUT_TYPE_ARB, inputType); 239 glProgramParameteriARB(program, GL_GEOMETRY_OUTPUT_TYPE_ARB, outputType); 240 } 241 if (fragShader) 242 AttachShader(program, fragShader); 243 244 t0 = glutGet(GLUT_ELAPSED_TIME) * 0.001; 245 LinkProgram(program); 246 t1 = glutGet(GLUT_ELAPSED_TIME) * 0.001; 247 248 LinkTime = t1 - t0; 249 250 /* check link */ 251 { 252 GLint stat; 253 GetProgramiv(program, GL_LINK_STATUS, &stat); 254 if (!stat) { 255 GLchar log[1000]; 256 GLsizei len; 257 GetProgramInfoLog(program, 1000, &len, log); 258 fprintf(stderr, "Shader link error:\n%s\n", log); 259 return 0; 260 } 261 } 262 263 return program; 264} 265 266 267GLboolean 268ValidateShaderProgram(GLuint program) 269{ 270 GLint stat; 271 ValidateProgramARB(program); 272 GetProgramiv(program, GL_VALIDATE_STATUS, &stat); 273 274 if (!stat) { 275 GLchar log[1000]; 276 GLsizei len; 277 GetProgramInfoLog(program, 1000, &len, log); 278 fprintf(stderr, "Program validation error:\n%s\n", log); 279 fflush(stderr); 280 return 0; 281 } 282 283 return (GLboolean) stat; 284} 285 286 287GLdouble 288GetShaderCompileTime(void) 289{ 290 return CompileTime; 291} 292 293 294GLdouble 295GetShaderLinkTime(void) 296{ 297 return LinkTime; 298} 299 300 301void 302SetUniformValues(GLuint program, struct uniform_info uniforms[]) 303{ 304 GLuint i; 305 306 for (i = 0; uniforms[i].name; i++) { 307 uniforms[i].location 308 = glGetUniformLocation(program, uniforms[i].name); 309 310 switch (uniforms[i].type) { 311 case GL_INT: 312 case GL_SAMPLER_1D: 313 case GL_SAMPLER_2D: 314 case GL_SAMPLER_3D: 315 case GL_SAMPLER_CUBE: 316 case GL_SAMPLER_2D_RECT_ARB: 317 case GL_SAMPLER_1D_SHADOW: 318 case GL_SAMPLER_2D_SHADOW: 319 case GL_SAMPLER_1D_ARRAY: 320 case GL_SAMPLER_2D_ARRAY: 321 case GL_SAMPLER_1D_ARRAY_SHADOW: 322 case GL_SAMPLER_2D_ARRAY_SHADOW: 323 assert(uniforms[i].value[0] >= 0.0F); 324 Uniform1i(uniforms[i].location, 325 (GLint) uniforms[i].value[0]); 326 break; 327 case GL_FLOAT: 328 Uniform1fv(uniforms[i].location, 1, uniforms[i].value); 329 break; 330 case GL_FLOAT_VEC2: 331 Uniform2fv(uniforms[i].location, 1, uniforms[i].value); 332 break; 333 case GL_FLOAT_VEC3: 334 Uniform3fv(uniforms[i].location, 1, uniforms[i].value); 335 break; 336 case GL_FLOAT_VEC4: 337 Uniform4fv(uniforms[i].location, 1, uniforms[i].value); 338 break; 339 case GL_FLOAT_MAT4: 340 UniformMatrix4fv(uniforms[i].location, 1, GL_FALSE, 341 uniforms[i].value); 342 break; 343 default: 344 if (strncmp(uniforms[i].name, "gl_", 3) == 0) { 345 /* built-in uniform: ignore */ 346 } 347 else { 348 fprintf(stderr, 349 "Unexpected uniform data type in SetUniformValues\n"); 350 abort(); 351 } 352 } 353 } 354} 355 356 357/** Get list of uniforms used in the program */ 358GLuint 359GetUniforms(GLuint program, struct uniform_info uniforms[]) 360{ 361 GLint n, max, i; 362 363 GetProgramiv(program, GL_ACTIVE_UNIFORMS, &n); 364 GetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max); 365 366 for (i = 0; i < n; i++) { 367 GLint size, len; 368 GLenum type; 369 char name[100]; 370 371 glGetActiveUniform(program, i, 100, &len, &size, &type, name); 372 373 uniforms[i].name = strdup(name); 374 uniforms[i].size = size; 375 uniforms[i].type = type; 376 uniforms[i].location = glGetUniformLocation(program, name); 377 } 378 379 uniforms[i].name = NULL; /* end of list */ 380 381 return n; 382} 383 384 385void 386PrintUniforms(const struct uniform_info uniforms[]) 387{ 388 GLint i; 389 390 printf("Uniforms:\n"); 391 392 for (i = 0; uniforms[i].name; i++) { 393 printf(" %d: %s size=%d type=0x%x loc=%d value=%g, %g, %g, %g\n", 394 i, 395 uniforms[i].name, 396 uniforms[i].size, 397 uniforms[i].type, 398 uniforms[i].location, 399 uniforms[i].value[0], 400 uniforms[i].value[1], 401 uniforms[i].value[2], 402 uniforms[i].value[3]); 403 } 404} 405 406 407/** Get list of attribs used in the program */ 408GLuint 409GetAttribs(GLuint program, struct attrib_info attribs[]) 410{ 411 GLint n, max, i; 412 413 GetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &n); 414 GetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max); 415 416 for (i = 0; i < n; i++) { 417 GLint size, len; 418 GLenum type; 419 char name[100]; 420 421 GetActiveAttrib(program, i, 100, &len, &size, &type, name); 422 423 attribs[i].name = strdup(name); 424 attribs[i].size = size; 425 attribs[i].type = type; 426 attribs[i].location = GetAttribLocation(program, name); 427 } 428 429 attribs[i].name = NULL; /* end of list */ 430 431 return n; 432} 433 434 435void 436PrintAttribs(const struct attrib_info attribs[]) 437{ 438 GLint i; 439 440 printf("Attribs:\n"); 441 442 for (i = 0; attribs[i].name; i++) { 443 printf(" %d: %s size=%d type=0x%x loc=%d\n", 444 i, 445 attribs[i].name, 446 attribs[i].size, 447 attribs[i].type, 448 attribs[i].location); 449 } 450} 451