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;
} |
|
Swiftless,
In the function
static void validateProgram(GLuint program);
You need to call validate before fetching the log, ( at least with my drivers ). With my drivers the log is lazily populated.
Simply reordering the function gives the correct behavior.
static void validate_program(GLuint program) {
char buffer[BUFFER_SIZE];
memset(buffer, 0, BUFFER_SIZE);
GLsizei length = 0;
GLint status = GL_FALSE;
glValidateProgram(program); // Get OpenGL to try validating the program
glGetProgramiv(program, GL_VALIDATE_STATUS, &status); // Find out if the shader program validated correctly
if (status == GL_FALSE) { // If there was a problem validating
std::cerr << "Error validating program " << program < 0) // If we have any information to display
std::cerr << "Program " << program << " link error: " << buffer << std::endl; // Output the information
}
}
outputs:
Error validating program3
Program 3 link error: Validation Failed: Current draw framebuffer is invalid.
( Why I get that is a bit more complicated. I think it is because I have a headless GL context )
Hi Swiftless,
(Firts of all sorry if my english isn’t much well)
When I run the program using your code it give me this error:
Exception first-chance at 0x00000000 in myProgram.exe: 0xC0000005: Access violation.
Unhandled exception at 0x00000000 in myProgram.exe: 0xC0000005: Access violation.
I don’t know how ot fix that, If you have any advice I would be grateful.
Thak
PS: I use Visual C++ 2010
hey swiftless,
You don’t need to assume a buffer size of 512.
Instead of
//code
const unsigned int BUFFER_SIZE = 512;
why not
glGetShaderiv(shader, GL_INFO_LOG_LENGTH , &BUFFER_SIZE);
Or something similar.
see http://www.khronos.org/opengles/sdk/2.0/docs/man/glGetShaderiv.xml
Hi Dr Deo,
That is absolutely correct! I’m not sure why I didn’t do that in this tutorial.
Thanks,
Swiftless