Shaders & Programs - validation, info log...

I’ve always set up shaders like so:


handle = GL.glCreateShader(type);
		
GL.glShaderSource(handle, source);		
		
GL.glCompileShader(handle);
if (GL.glGetShaderiv(handle, ShaderState.COMPILE_STATUS) == GL.FALSE)
	throw new OpenGLException("Error compiling shader: " + handle);

And I’ve always set up program objects like so:


handle = GL.glCreateProgram();

for (ShaderObject shaderObj : shaderObjs)
	GL.glAttachShader(handle, shaderObj.getHandle());

GL.glLinkProgram(handle);
if (GL.glGetProgramiv(handle, ProgramState.LINK_STATUS) == GL.FALSE)
	throw new OpenGLException("Error linking program: " + handle);

for (ShaderObject shaderObj : shaderObjs)
	GL.glDetachShader(handle, shaderObj.getHandle());

I’m not exactly sure what else I should do; I’ve previously seen the use of glValidateProgram and checking that the program is validated. However, I’m not sure if it’s necessary. If it’s compiled and linked successfully, won’t that mean that it’s validated for use? Also I’ve known about the use of info-logs and I’m not exactly sure how I should use them and what to use them for. On top of that, is there anything else I should known about?

Oh and I nearly forgot, should I always detach shader objects from the program after the program is linked? Is there any reason that you’d keep them attached?

Yes, you should detach the objects. There’s no need to keep them around after the shader program is compiled.

Info logs are useful for finding errors in your shaders.

Not using them is like having a compiler with no output. You can use it perfectly fine, but if you have an error, it’s a nightmare to track down.

How about validation, and how should I use info logs?

I’m a bit busy so I can’t give you Java code, but here’s some snippets from my Rust libraries:

Shaders:


let shader = gl::CreateShader(ty);
unsafe
{
    // Compile shader
    src.with_c_str(|ptr| gl::ShaderSource(shader, 1, &ptr, ptr::null()));

    // Error Checking
    gl::CompileShader(shader);
    
    let mut status = gl::FALSE as GLint;
    gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);
    
    if status != (gl::TRUE as GLint)
    {
        /*The following calculates the length of the log so I can pass an appropriately sized buffer.
LWJGL should let you skip this part*/
        let mut len = 0;
        gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
        let mut buf = vec::from_elem(len as uint - 1, 0u8);
        gl::GetShaderInfoLog(shader, len, ptr::mut_null(), buf.as_mut_ptr() as *mut GLchar);
        fail!("Error compiling shader:\n{}\n", str::raw::from_utf8(buf));
    }
}

Programs:


let program = gl::CreateProgram();

gl::AttachShader(program, vs);
gl::AttachShader(program, fs);

gl::LinkProgram(program);

gl::DeleteShader(vs);
gl::DeleteShader(fs);
// Error Checking
unsafe
{
    let mut status = gl::FALSE as GLint;
    gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);
    
    if status != (gl::TRUE as GLint)
    {
        /*The following calculates the length of the log so I can pass an appropriately sized buffer.
LWJGL should let you skip this part*/
        let mut len: GLint = 0;
        gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
        let mut buf = vec::from_elem(len as uint - 1, 0u8);
        gl::GetProgramInfoLog(program, len, ptr::mut_null(), buf.as_mut_ptr() as *mut GLchar);
        fail!("Error linking shader program:\n{}\n", str::raw::from_utf8(buf));
    }
}

Hopefully you can convert it to Java code easily enough. LWJGL versions should be a bit simpler.

I do similar things, compiling and checking for errors. I also do parse the error text to get the offending line in the shader, problem is of course that there are differences between Nvidia AMD …

I also just read that one can speed up shader compilation by allowing the driver to do it in parallel.

This is a pastebin of a complete class that I’m using to manage (load, validate…) a shader, if you want to compare. You will find infolog by example.
I’m sorry comments are in french :o, (if needed, I can translate !)

Don’t forget Intel. Using arrays with the Intel GLSL compiler is a nightmare.

The parallel compiling and linking code is just a concept. If you were to compile and link your shader/shader programs but don’t query the compilation results or do anything that requires the compilation to complete (query uniforms and attributes), IN THEORY the driver could compile the GLSL shader in a separate thread and the driver would only need to block if the compilation wasn’t complete by the first time the shader is actually needed. I’m not aware of any driver that actually does that in the first place, and I doubt the gains would noticeable when you compare shader compilation to texture loading and 3D model loading in an actual game. It might also make debugging shaders slightly harder since a compilation error would not be detected until the shader was actually used, which could leave a bug in a rarely used shader to explode to some unfortunate user. Well, not likely, but still.

I haven’t seen too many uses for glValidateProgram, since you can just try to compile and see the error logs. There are some issues with Macs and NVIDIA cards around validating: