13.6 - GLSL Compiling & Linking¶
Compiling¶
GLSL programs are compiled using functionality in the WebGL API of your
JavaScript program. If errors occur during compilation they can be captured
and displayed. A function similar to the one below is part of any WebGL program.
The following function is a method of the SceneDownload
class defined
in the file scene_download.js
.
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 | /** ---------------------------------------------------------------------
* Create and compile an individual shader.
* @param gl {WebGLRenderingContext} The WebGL context.
* @param type {Number} The type of shader, either
* gl.VERTEX_SHADER or gl.FRAGMENT_SHADER
* @param source {String} The code/text of the shader
* @returns {WebGLShader} A WebGL shader program object.
*/
self.createAndCompileShader = function (gl, type, source) {
let typeName;
switch (type) {
case gl.VERTEX_SHADER:
typeName = "Vertex Shader";
break;
case gl.FRAGMENT_SHADER:
typeName = "Fragment Shader";
break;
default:
out.displayError("Invalid type of shader " +
"in createAndCompileShader()");
return null;
}
// Create shader object
let shader = gl.createShader(type);
if (!shader) {
out.displayError("Fatal error: gl could not create a shader object.");
return null;
}
// Put the source code into the gl shader object
gl.shaderSource(shader, source);
// Compile the shader code
gl.compileShader(shader);
// Check for any compiler errors
let compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (!compiled) {
// There are errors, so display them
let errors = gl.getShaderInfoLog(shader);
out.displayError('Failed to compile ' + typeName
+ ' with these errors:\n' + errors);
gl.deleteShader(shader);
return null;
}
return shader;
};
|
Some notes about this function:
- The
type
parameter is a WebGL ENUM (a numeric constant). The switch statement in lines 9-20 is strictly for creating more meaningful error messages. - The
out
object is used to display messages to a web page. If you do not want web page messages, you could replace the function calls toout
functions with calls toconsole.log
and look for errors in the JavaScript console window. - Typically the only reason why the
gl.createShader()
function would fail is lack of GPU memory or a loss of the WebGL context. You could get the exact error using a call togl.getError()
. - The compiler error messages are typically very helpful. Make sure you notice the line number and column number of the error and that you read the error message very carefully.
- It is important that you not “pollute” the GPU memory with invalid or unused objects. The GPU does not do automatic “garbage collection”. Notice that the shader is explicitly deleted if errors occur.
Linking¶
Linking a vertex shader and a fragment shader into a single program makes
sure that both programs reference the same global variables. A function
similar to the one below is part of any WebGL program.
The following function is a method of the SceneDownload
class defined
in the file scene_download.js
.
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 | /** ---------------------------------------------------------------------
* Given two shader programs, create a complete rendering program.
* @param gl {WebGLRenderingContext} The WebGL context.
* @param vertexShaderCode {String} Code for a vertex shader.
* @param fragmentShaderCode {String} Code for a fragment shader.
* @returns WebGLProgram {WebGLProgram} A WebGL shader program object.
*/
self.createProgram = function (gl, vertexShaderCode, fragmentShaderCode) {
// Create the 2 required shaders
var vertexShader = self.createAndCompileShader(gl, gl.VERTEX_SHADER,
vertexShaderCode);
var fragmentShader = self.createAndCompileShader(gl, gl.FRAGMENT_SHADER,
fragmentShaderCode);
if (!vertexShader || !fragmentShader) {
return null;
}
// Create a WebGLProgram object
var program = gl.createProgram();
if (!program) {
out.displayError('Fatal error: Failed to create a program object');
return null;
}
// Attach the shader objects
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
// Link the WebGLProgram object
gl.linkProgram(program);
// Check for success
var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
if (!linked) {
// There were errors, so get the errors and display them.
var error = gl.getProgramInfoLog(program);
out.displayError('Fatal error: Failed to link program: ' + error);
gl.deleteProgram(program);
gl.deleteShader(fragmentShader);
gl.deleteShader(vertexShader);
return null;
}
// Remember the shaders. This allows for them to be cleanly deleted.
program.vShader = vertexShader;
program.fShader = fragmentShader;
return program;
};
|
Automated Shader Programs¶
Since shader programs are simply strings of text before being compiled, it is possible to create shader programs “on the fly.” That is, you could have a set of strings that define various shader commands and then combine those strings in complex ways to create a specific shader for a specific rendering situation. Such an idea is well beyond these basic tutorials, but it is an idea you might find very powerful if you pursued more advanced computer graphics.