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