2. GLSL Validation

Jump To:

shader.h Source
shader.cpp Source
main.cpp Source
shader.vert Source
shader.frag Source
Download

When developing with C++, it is often handy when the compiler tells you where a problem is. With GLSL validation, we can find out where exactly we have an error within our shader program.

This tutorial is going to show you how to validate a GLSL program. If your shaders fails validation, the output will be written to the console, and will hopefully help you find the problem.

Let get to it..

Shader.H File:

This tutorial is going to start off nice and simple, no changes will be made to this file 🙂

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.

   

#ifndef __SHADER_H
#define __SHADER_H

#if ( (defined(__MACH__)) && (defined(__APPLE__)) )   
#include <stdlib.h>
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#include <OpenGL/glext.h>
#else
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glut.h>
#include <GL/glext.h>
#endif
 
#include <string>

class Shader {
public:
    Shader();
    Shader(const char *vsFile, const char *fsFile);
    ~Shader();
    
    void init(const char *vsFile, const char *fsFile);
    
    void bind();
    void unbind();
    
    unsigned int id();
    
private:
    unsigned int shader_id;
    unsigned int shader_vp;
    unsigned int shader_fp;
};

#endif

Shader.CPP File:

Shader.cpp is where we are going to make *all* of our changes. To get validation working, we are going to add two new methods. One for validating the seperate vertex and fragment shaders, and one for validating the final shader program.

We are going to call these methods validateShader and validateProgram. validateShader will take two parameters, the first being the shader we want the check, and the second being the filename of the file associated with the shader.

static void validateShader(GLuint shader, const char* file = 0)

We are going to need three variables for this. The first is just the size of the output buffer that we want. This can be any value, but 512 sounds nice.

    const unsigned int BUFFER_SIZE = 512;

The second variable will be an array of char’s and will be used to contain the output from our validation. We then make a call to memset to set the char array to all 0’s.

    char buffer[BUFFER_SIZE];
    memset(buffer, 0, BUFFER_SIZE);

The final variable will be called length, and guess what. It will contain the length of the buffer we get back from OpenGL.

    GLsizei length = 0;    

All we have to do now, is read back the shader log from opengl and store it in our buffer.

    glGetShaderInfoLog(shader, BUFFER_SIZE, &length, buffer);

Finally, we just output the information if the length of the returned string is greater than 0. Meaning we have something to output.

    if (length > 0) {
        cerr << “Shader ” << shader << ” (<< (file?file:“”) << “) compile error: ” << buffer << endl;

The next method, validateProgram will take one parameter, and this will be an integer associated with the shader we are validating.

static void validateProgram(GLuint program)

The first few lines of the method are practically identical to that of the previous. We just want to change the output from the shader log:

    const unsigned int BUFFER_SIZE = 512;
    char buffer[BUFFER_SIZE];
    memset(buffer, 0, BUFFER_SIZE);
    GLsizei length = 0;
    
    glGetShaderInfoLog(shader, BUFFER_SIZE, &length, buffer);
    if (length > 0) {

Here, we now want to state that we have a problem linking the shaders, and output the error.

        cerr << “Program ” << program << ” link error: ” << buffer << endl;
    

Now for the new parts, we want to make a call to validate the program, and then using an integer, read back the status of the shader.

    glValidateProgram(program);
    GLint status;
    glGetProgramiv(program, GL_VALIDATE_STATUS, &status);

Once we have read back the status, we check to make sure the status is GL_TRUE, if it is GL_FALSE, then we have an error, and we output which GLSL shader program had the error.

    if (status == GL_FALSE)
        cerr << “Error validating shader ” << program << endl;

 

Then we just have to call the methods we have just created. These are called from within the init() method. I am going to call the validation methods after the respective compile calls for the shaders like so:

    glCompileShader(shader_vp);
    validateShader(shader_vp, vsFile);
    glCompileShader(shader_fp);
    validateShader(shader_fp, fsFile);

And then at the end of the init method, make a call to validateProgram:

validateProgram(shader_id);

That is the end of this tutorial, the rest of the page simply contains the source code for this tutorial.

If you have any questions, just email me at swiftless@gmail.com

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
    #include “shader.h”
#include <string.h>
#include <iostream>
#include <stdlib.h>

using namespace std;

static char* textFileRead(const char *fileName) {
    char* text;
    
    if (fileName != NULL) {
        FILE *file = fopen(fileName, “rt”);
        
        if (file != NULL) {
            fseek(file, 0, SEEK_END);
            int count = ftell(file);
            rewind(file);
            
            if (count > 0) {
                text = (char*)malloc(sizeof(char) * (count + 1));
                count = fread(text, sizeof(char), count, file);
                text[count] = ‘\0’;
            }
            fclose(file);
        }
    }
    return text;
}

static void validateShader(GLuint shader, const char* file = 0) {
    const unsigned int BUFFER_SIZE = 512;
    char buffer[BUFFER_SIZE];
    memset(buffer, 0, BUFFER_SIZE);
    GLsizei length = 0;
    
    glGetShaderInfoLog(shader, BUFFER_SIZE, &length, buffer);
    if (length > 0) {
        cerr << “Shader ” << shader << ” (<< (file?file:“”) << “) compile error: 
” << buffer << endl;
    }
}

static void validateProgram(GLuint program) {
    const unsigned int BUFFER_SIZE = 512;
    char buffer[BUFFER_SIZE];
    memset(buffer, 0, BUFFER_SIZE);
    GLsizei length = 0;
    
    memset(buffer, 0, BUFFER_SIZE);
    glGetProgramInfoLog(program, BUFFER_SIZE, &length, buffer);
    if (length > 0)
        cerr << “Program ” << program << ” link error: ” << buffer << endl;
    
    glValidateProgram(program);
    GLint status;
    glGetProgramiv(program, GL_VALIDATE_STATUS, &status);
    if (status == GL_FALSE)
        cerr << “Error validating shader ” << program << endl;
}

Shader::Shader() {
    
}

Shader::Shader(const char *vsFile, const char *fsFile) {
    init(vsFile, fsFile);
}

void Shader::init(const char *vsFile, const char *fsFile) {
    shader_vp = glCreateShader(GL_VERTEX_SHADER);
    shader_fp = glCreateShader(GL_FRAGMENT_SHADER);
    
    const char* vsText = textFileRead(vsFile);
    const char* fsText = textFileRead(fsFile);    
    
    if (vsText == NULL || fsText == NULL) {
        cerr << “Either vertex shader or fragment shader file not found.” << endl
;
        return;
    }
    
    glShaderSource(shader_vp, 1, &vsText, 0);
    glShaderSource(shader_fp, 1, &fsText, 0);
    
    glCompileShader(shader_vp);
    validateShader(shader_vp, vsFile);
    glCompileShader(shader_fp);
    validateShader(shader_fp, fsFile);
    
    shader_id = glCreateProgram();
    glAttachShader(shader_id, shader_fp);
    glAttachShader(shader_id, shader_vp);
    glLinkProgram(shader_id);
    validateProgram(shader_id);
}

Shader::~Shader() {
    glDetachShader(shader_id, shader_fp);
    glDetachShader(shader_id, shader_vp);
    
    glDeleteShader(shader_fp);
    glDeleteShader(shader_vp);
    glDeleteProgram(shader_id);
}

unsigned int Shader::id() {
    return shader_id;
}

void Shader::bind() {
    glUseProgram(shader_id);
}

void Shader::unbind() {
    glUseProgram(0);
}

Main.CPP File:

No need to do anything here 😀

1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.

    #if ( (defined(__MACH__)) && (defined(__APPLE__)) )   
#include <stdlib.h>
#include <OpenGL/gl.h>
#include <GLUT/glut.h>
#include <OpenGL/glext.h>
#else
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glut.h>
#include <GL/glext.h>
#endif

#include “shader.h”

Shader shader;

GLfloat angle = 0.0; //set the angle of rotation

void init(void) {
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    
    shader.init(“shader.vert”, “shader.frag”);
}

void cube (void) {
    glRotatef(angle, 1.0, 0.0, 0.0); //rotate on the x axis
    glRotatef(angle, 0.0, 1.0, 0.0); //rotate on the y axis
    glRotatef(angle, 0.0, 0.0, 1.0); //rotate on the z axis
    glColor4f(1.0, 0.0, 0.0, 1.0);
    glutWireCube(2);
}

void display (void) {
    glClearColor (0.0,0.0,0.0,1.0);
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();  
    gluLookAt (0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
    
    shader.bind();
    cube();
    shader.unbind();
    
    glutSwapBuffers();
    angle += 0.1f;
}

void reshape (int w, int h) {
    glViewport (0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    gluPerspective (60, (GLfloat)w / (GLfloat)h, 1.0, 100.0);
    glMatrixMode (GL_MODELVIEW);
}

int main (int argc, char **argv) {
    glutInit(&argc, argv);
    //set up
the double buffering

    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH;

    glutInitWindowSize(500, 500);
    glutInitWindowPosition(100, 100);
    glutCreateWindow(“A basic OpenGL Window);
    
    glewInit();

    glutDisplayFunc(display);
    glutIdleFunc(display);
    
    glutReshapeFunc(reshape);
    
    init();
    
    glutMainLoop();
    
    return 0;
}

Vertex Shader Source:

Woo, no changes here 🙂

1.
2.
3.
4.
5.
    void main() {            
    // Set the position of the current vertex 
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

 

Fragment Shader Source:

For this tutorial, we are not going to make any changes here either 🙂

If you have any questions, please email me at swiftless@gmail.com

1.
2.
3.
4.
    void main() {
    // Set the output color of our current pixel
    gl_FragColor = vec4(1.0);
}

 

Download:

Download shader.h Source Code for this Tutorial

Download shader.cpp Source Code for this Tutorial

Download main.cpp Source Code for this Tutorial

Download shader.vert Source Code for this Tutorial

Download shader.frag Source Code for this Tutorial

  • March 25, 2010
  • 4