Merge branch 'mesa_7_6_branch' into mesa_7_7_branch
[mesa.git] / progs / util / shaderutil.c
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 <GL/glut.h>
15 #include "shaderutil.h"
16
17 /** time to compile previous shader */
18 static GLdouble CompileTime = 0.0;
19
20 /** time to linke previous program */
21 static GLdouble LinkTime = 0.0;
22
23
24 GLboolean
25 ShadersSupported(void)
26 {
27 const char *version = (const char *) glGetString(GL_VERSION);
28
29 /* NVIDIA binary drivers will return "3.0.0", and they clearly support
30 * shaders.
31 */
32 if (version[0] >= '2' && version[1] == '.') {
33 return GL_TRUE;
34 }
35 else if (glutExtensionSupported("GL_ARB_vertex_shader")
36 && glutExtensionSupported("GL_ARB_fragment_shader")
37 && glutExtensionSupported("GL_ARB_shader_objects")) {
38 fprintf(stderr, "Warning: Trying ARB GLSL instead of OpenGL 2.x. This may not work.\n");
39 return GL_TRUE;
40 }
41 fprintf(stderr, "Sorry, GLSL not supported with this OpenGL.\n");
42 return GL_FALSE;
43 }
44
45
46 GLuint
47 CompileShaderText(GLenum shaderType, const char *text)
48 {
49 GLuint shader;
50 GLint stat;
51 GLdouble t0, t1;
52
53 shader = glCreateShader(shaderType);
54 glShaderSource(shader, 1, (const GLchar **) &text, NULL);
55
56 t0 = glutGet(GLUT_ELAPSED_TIME) * 0.001;
57 glCompileShader(shader);
58 t1 = glutGet(GLUT_ELAPSED_TIME) * 0.001;
59
60 CompileTime = t1 - t0;
61
62 glGetShaderiv(shader, GL_COMPILE_STATUS, &stat);
63 if (!stat) {
64 GLchar log[1000];
65 GLsizei len;
66 glGetShaderInfoLog(shader, 1000, &len, log);
67 fprintf(stderr, "Error: problem compiling shader: %s\n", log);
68 exit(1);
69 }
70 else {
71 /*printf("Shader compiled OK\n");*/
72 }
73 return shader;
74 }
75
76
77 /**
78 * Read a shader from a file.
79 */
80 GLuint
81 CompileShaderFile(GLenum shaderType, const char *filename)
82 {
83 const int max = 100*1000;
84 int n;
85 char *buffer = (char*) malloc(max);
86 GLuint shader;
87 FILE *f;
88
89 f = fopen(filename, "r");
90 if (!f) {
91 fprintf(stderr, "Unable to open shader file %s\n", filename);
92 free(buffer);
93 return 0;
94 }
95
96 n = fread(buffer, 1, max, f);
97 /*printf("read %d bytes from shader file %s\n", n, filename);*/
98 if (n > 0) {
99 buffer[n] = 0;
100 shader = CompileShaderText(shaderType, buffer);
101 }
102 else {
103 fclose(f);
104 free(buffer);
105 return 0;
106 }
107
108 fclose(f);
109 free(buffer);
110
111 return shader;
112 }
113
114
115 GLuint
116 LinkShaders(GLuint vertShader, GLuint fragShader)
117 {
118 GLuint program = glCreateProgram();
119 GLdouble t0, t1;
120
121 assert(vertShader || fragShader);
122
123 if (fragShader)
124 glAttachShader(program, fragShader);
125 if (vertShader)
126 glAttachShader(program, vertShader);
127
128 t0 = glutGet(GLUT_ELAPSED_TIME) * 0.001;
129 glLinkProgram(program);
130 t1 = glutGet(GLUT_ELAPSED_TIME) * 0.001;
131
132 LinkTime = t1 - t0;
133
134 /* check link */
135 {
136 GLint stat;
137 glGetProgramiv(program, GL_LINK_STATUS, &stat);
138 if (!stat) {
139 GLchar log[1000];
140 GLsizei len;
141 glGetProgramInfoLog(program, 1000, &len, log);
142 fprintf(stderr, "Shader link error:\n%s\n", log);
143 return 0;
144 }
145 }
146
147 return program;
148 }
149
150
151 GLboolean
152 ValidateShaderProgram(GLuint program)
153 {
154 GLint stat;
155 glValidateProgramARB(program);
156 glGetProgramiv(program, GL_VALIDATE_STATUS, &stat);
157
158 if (!stat) {
159 GLchar log[1000];
160 GLsizei len;
161 glGetProgramInfoLog(program, 1000, &len, log);
162 fprintf(stderr, "Program validation error:\n%s\n", log);
163 return 0;
164 }
165
166 return (GLboolean) stat;
167 }
168
169
170 GLdouble
171 GetShaderCompileTime(void)
172 {
173 return CompileTime;
174 }
175
176
177 GLdouble
178 GetShaderLinkTime(void)
179 {
180 return LinkTime;
181 }
182
183
184 void
185 SetUniformValues(GLuint program, struct uniform_info uniforms[])
186 {
187 GLuint i;
188
189 for (i = 0; uniforms[i].name; i++) {
190 uniforms[i].location
191 = glGetUniformLocation(program, uniforms[i].name);
192
193 switch (uniforms[i].type) {
194 case GL_INT:
195 case GL_SAMPLER_1D:
196 case GL_SAMPLER_2D:
197 case GL_SAMPLER_3D:
198 case GL_SAMPLER_CUBE:
199 case GL_SAMPLER_2D_RECT_ARB:
200 assert(uniforms[i].value[0] >= 0.0F);
201 glUniform1i(uniforms[i].location,
202 (GLint) uniforms[i].value[0]);
203 break;
204 case GL_FLOAT:
205 glUniform1fv(uniforms[i].location, 1, uniforms[i].value);
206 break;
207 case GL_FLOAT_VEC2:
208 glUniform2fv(uniforms[i].location, 1, uniforms[i].value);
209 break;
210 case GL_FLOAT_VEC3:
211 glUniform3fv(uniforms[i].location, 1, uniforms[i].value);
212 break;
213 case GL_FLOAT_VEC4:
214 glUniform4fv(uniforms[i].location, 1, uniforms[i].value);
215 break;
216 default:
217 if (strncmp(uniforms[i].name, "gl_", 3) == 0) {
218 /* built-in uniform: ignore */
219 }
220 else {
221 fprintf(stderr,
222 "Unexpected uniform data type in SetUniformValues\n");
223 abort();
224 }
225 }
226 }
227 }
228
229
230 /** Get list of uniforms used in the program */
231 GLuint
232 GetUniforms(GLuint program, struct uniform_info uniforms[])
233 {
234 GLint n, max, i;
235
236 glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &n);
237 glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max);
238
239 for (i = 0; i < n; i++) {
240 GLint size, len;
241 GLenum type;
242 char name[100];
243
244 glGetActiveUniform(program, i, 100, &len, &size, &type, name);
245
246 uniforms[i].name = strdup(name);
247 uniforms[i].size = size;
248 uniforms[i].type = type;
249 uniforms[i].location = glGetUniformLocation(program, name);
250 }
251
252 uniforms[i].name = NULL; /* end of list */
253
254 return n;
255 }
256
257
258 void
259 PrintUniforms(const struct uniform_info uniforms[])
260 {
261 GLint i;
262
263 printf("Uniforms:\n");
264
265 for (i = 0; uniforms[i].name; i++) {
266 printf(" %d: %s size=%d type=0x%x loc=%d value=%g, %g, %g, %g\n",
267 i,
268 uniforms[i].name,
269 uniforms[i].size,
270 uniforms[i].type,
271 uniforms[i].location,
272 uniforms[i].value[0],
273 uniforms[i].value[1],
274 uniforms[i].value[2],
275 uniforms[i].value[3]);
276 }
277 }
278
279
280 /** Get list of attribs used in the program */
281 GLuint
282 GetAttribs(GLuint program, struct attrib_info attribs[])
283 {
284 GLint n, max, i;
285
286 glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &n);
287 glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max);
288
289 for (i = 0; i < n; i++) {
290 GLint size, len;
291 GLenum type;
292 char name[100];
293
294 glGetActiveAttrib(program, i, 100, &len, &size, &type, name);
295
296 attribs[i].name = strdup(name);
297 attribs[i].size = size;
298 attribs[i].type = type;
299 attribs[i].location = glGetAttribLocation(program, name);
300 }
301
302 attribs[i].name = NULL; /* end of list */
303
304 return n;
305 }
306
307
308 void
309 PrintAttribs(const struct attrib_info attribs[])
310 {
311 GLint i;
312
313 printf("Attribs:\n");
314
315 for (i = 0; attribs[i].name; i++) {
316 printf(" %d: %s size=%d type=0x%x loc=%d\n",
317 i,
318 attribs[i].name,
319 attribs[i].size,
320 attribs[i].type,
321 attribs[i].location);
322 }
323 }