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