shaderutil.c revision 32001f49
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 return 0; 280 } 281 282 return (GLboolean) stat; 283} 284 285 286GLdouble 287GetShaderCompileTime(void) 288{ 289 return CompileTime; 290} 291 292 293GLdouble 294GetShaderLinkTime(void) 295{ 296 return LinkTime; 297} 298 299 300void 301SetUniformValues(GLuint program, struct uniform_info uniforms[]) 302{ 303 GLuint i; 304 305 for (i = 0; uniforms[i].name; i++) { 306 uniforms[i].location 307 = glGetUniformLocation(program, uniforms[i].name); 308 309 switch (uniforms[i].type) { 310 case GL_INT: 311 case GL_SAMPLER_1D: 312 case GL_SAMPLER_2D: 313 case GL_SAMPLER_3D: 314 case GL_SAMPLER_CUBE: 315 case GL_SAMPLER_2D_RECT_ARB: 316 case GL_SAMPLER_1D_SHADOW: 317 case GL_SAMPLER_2D_SHADOW: 318 case GL_SAMPLER_1D_ARRAY: 319 case GL_SAMPLER_2D_ARRAY: 320 case GL_SAMPLER_1D_ARRAY_SHADOW: 321 case GL_SAMPLER_2D_ARRAY_SHADOW: 322 assert(uniforms[i].value[0] >= 0.0F); 323 Uniform1i(uniforms[i].location, 324 (GLint) uniforms[i].value[0]); 325 break; 326 case GL_FLOAT: 327 Uniform1fv(uniforms[i].location, 1, uniforms[i].value); 328 break; 329 case GL_FLOAT_VEC2: 330 Uniform2fv(uniforms[i].location, 1, uniforms[i].value); 331 break; 332 case GL_FLOAT_VEC3: 333 Uniform3fv(uniforms[i].location, 1, uniforms[i].value); 334 break; 335 case GL_FLOAT_VEC4: 336 Uniform4fv(uniforms[i].location, 1, uniforms[i].value); 337 break; 338 case GL_FLOAT_MAT4: 339 UniformMatrix4fv(uniforms[i].location, 1, GL_FALSE, 340 uniforms[i].value); 341 break; 342 default: 343 if (strncmp(uniforms[i].name, "gl_", 3) == 0) { 344 /* built-in uniform: ignore */ 345 } 346 else { 347 fprintf(stderr, 348 "Unexpected uniform data type in SetUniformValues\n"); 349 abort(); 350 } 351 } 352 } 353} 354 355 356/** Get list of uniforms used in the program */ 357GLuint 358GetUniforms(GLuint program, struct uniform_info uniforms[]) 359{ 360 GLint n, max, i; 361 362 GetProgramiv(program, GL_ACTIVE_UNIFORMS, &n); 363 GetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max); 364 365 for (i = 0; i < n; i++) { 366 GLint size, len; 367 GLenum type; 368 char name[100]; 369 370 glGetActiveUniform(program, i, 100, &len, &size, &type, name); 371 372 uniforms[i].name = strdup(name); 373 uniforms[i].size = size; 374 uniforms[i].type = type; 375 uniforms[i].location = glGetUniformLocation(program, name); 376 } 377 378 uniforms[i].name = NULL; /* end of list */ 379 380 return n; 381} 382 383 384void 385PrintUniforms(const struct uniform_info uniforms[]) 386{ 387 GLint i; 388 389 printf("Uniforms:\n"); 390 391 for (i = 0; uniforms[i].name; i++) { 392 printf(" %d: %s size=%d type=0x%x loc=%d value=%g, %g, %g, %g\n", 393 i, 394 uniforms[i].name, 395 uniforms[i].size, 396 uniforms[i].type, 397 uniforms[i].location, 398 uniforms[i].value[0], 399 uniforms[i].value[1], 400 uniforms[i].value[2], 401 uniforms[i].value[3]); 402 } 403} 404 405 406/** Get list of attribs used in the program */ 407GLuint 408GetAttribs(GLuint program, struct attrib_info attribs[]) 409{ 410 GLint n, max, i; 411 412 GetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &n); 413 GetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max); 414 415 for (i = 0; i < n; i++) { 416 GLint size, len; 417 GLenum type; 418 char name[100]; 419 420 GetActiveAttrib(program, i, 100, &len, &size, &type, name); 421 422 attribs[i].name = strdup(name); 423 attribs[i].size = size; 424 attribs[i].type = type; 425 attribs[i].location = GetAttribLocation(program, name); 426 } 427 428 attribs[i].name = NULL; /* end of list */ 429 430 return n; 431} 432 433 434void 435PrintAttribs(const struct attrib_info attribs[]) 436{ 437 GLint i; 438 439 printf("Attribs:\n"); 440 441 for (i = 0; attribs[i].name; i++) { 442 printf(" %d: %s size=%d type=0x%x loc=%d\n", 443 i, 444 attribs[i].name, 445 attribs[i].size, 446 attribs[i].type, 447 attribs[i].location); 448 } 449} 450