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