Difference between revisions of "OpenGL Shading Language"

From OpenGL.org
Jump to: navigation, search
(Adding Error Checking section)
m (Version change.)
(22 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{missing}}
 
 
 
{{infobox feature
 
{{infobox feature
 
| core = 2.0
 
| core = 2.0
Line 8: Line 6:
 
The '''OpenGL Shading Language''' (GLSL) is the principle [[shading languages]] for OpenGL. While there are several shading languages available for use in OpenGL, GLSL is the only one that is a part of the OpenGL core.
 
The '''OpenGL Shading Language''' (GLSL) is the principle [[shading languages]] for OpenGL. While there are several shading languages available for use in OpenGL, GLSL is the only one that is a part of the OpenGL core.
  
GLSL is a C-style language. The language has undergone a number of version changes, and it shares the deprecation model of OpenGL. The current version of GLSL is 1.50.
+
GLSL is a C-style language. The language has undergone a number of version changes, and it shares the deprecation model of OpenGL. The current version of GLSL is 4.30.
  
 
== Compilation model ==
 
== Compilation model ==
 +
{{main|GLSL_Object}}
  
GLSL is quite unique among shading languages due to its compilation model. Most shading languages use a simple, one-stage model: you give it a string representing a shader for one of the shader stages, and it gives you a shader object that you can bind to the context and render with.
+
GLSL is quite unique among shading languages due to its compilation model. It's compilation model is more like the standard C paradigm. Compilation is overseen by [[GLSL Object|a number of object types]]. Note that these do not follow the standard [[OpenGL Objects]] paradigm.
 
+
GLSL uses a more complicated model based on the compilation of C programs. In C, a compilation unit, typically a single source file that may include several external header files, is compiled into an object file. A number of object files are then linked into a single program.
+
 
+
GLSL operates in a similar fashion. A set of source files, given as a series of strings, are compiled into a shader object. This is the analog of an object file. Unlike typical shading languages, there is no requirement that this shader object represent a full shader stage. The only limitation is that it can only compile code that is appropriate for a single, specific shader stage.
+
 
+
Shader objects are useless in that form, just as object files from compiled C programs are useless directly. Shader objects must be linked into a single program object. Unlike most shader languages, the program objects contain ''all'' shader stages at once. Only one program can be bound for rendering at any one time, and it is illegal for a program object to omit certain stages entirely.
+
 
+
{{legacy note|If the fixed-function pipeline is available, a program can omit one or more stages that the fixed-function pipeline can cover.}}
+
  
 
=== Terminology ===
 
=== Terminology ===
Line 31: Line 22:
  
 
== Language ==
 
== Language ==
 +
{{main|GLSL Core Language}}
  
GLSL is a C-style language, so it covers most of the features you would expect with such a language. Control structures (for-loops, if-else statements, etc) exist in GLSL, including the <code>switch</code> statement. This section will not cover the entire language in detail; the [http://www.opengl.org/documentation/glsl/ GLSL specification] can handle that. This section will hit the highlights of the important differences between GLSL and C.
+
GLSL is a lot like C/C++ in many ways. It supports most of the familiar structural components (for-loops, if-statements, etc). But it has some important language differences.
  
=== Version ===
+
=== Standard library ===
  
The OpenGL Shading Language has gone though a number of revisions, some of them quite substantial. As part of the [[OpenGL Specification]], a version of OpenGL is required to support one or more specific versions of GLSL. It may optionally support more.
+
The OpenGL Shading Language defines a number of '''standard functions'''. Some standard functions are specific to certain shader stages, while most are available in any stage. There is reference documentation for these functions available [http://www.opengl.org/sdk/docs/manglsl/ here].
  
To specify which version of GLSL should be used, use this directive:
+
=== Variable types ===
 +
{{main|GLSL Types}}
  
  #version 1.50
+
C has a number of basic types. GLSL uses some of these, but adds many, many more.
  
This would tell the compiler to compile for version 1.50, or error if that version is not available.
+
=== Type qualifiers ===
 +
{{main|GLSL Type Qualifiers}}
  
You should put this before any other language features.
+
GLSL's uses a large number of qualifiers to specify where the values that various variables contain come from. Qualifiers also modify how those variables can be used.
  
==== Extensions ====
+
=== Interface blocks ===
 +
{{main|GLSL Interface Block}}
  
[[OpenGL Extensions]] apply to GLSL as well. Unlike regular OpenGL, where extensions are implicitly always there whether you use it or not, GLSL extensions must explicitly be specified in the particular shader string being compiled.
+
Certain variable definitions can be grouped into interface blocks. These can be used to make communication between different shader stages easier, or to allow storage for variables to come from a buffer object.
  
Similar to the #version directive, the user can activate specific extensions with the "#extension" directive. The syntax is as follows:
+
=== Predefined variables ===
 +
{{main|GLSL Predefined Variables}}
  
  #extension ''extension_name'' : ''behavior''
+
The different shader stages have a number of predefined variables for them. These are provided by the system for various system-specific use.
 
+
The "extension_name" can also be the string "all". This means it works for all extensions. The available behaviors are:
+
 
+
* ''enable'': Causes the named extension to work; if the implementation does not support the extension, it only gives a warning. Fails if used with "all".
+
* ''require'': Causes the named extension to work; if the implementation does not support the extension, it fails. It also fails if used with "all".
+
* ''warn'': Causes the named extension to work; however, using the extension will emit warnings. If used with "all", then the use of any extensions will emit warnings.
+
* ''disable'': Prevents the named extension from working at all. Thus, any use of it will be seen as undefined syntax and cause an error. If used with "all", then this prevents any extensions from working.
+
 
+
You should put these definitions before any other language features.
+
 
+
=== Basic types ===
+
 
+
C has a number of basic types. What C does not have the concept of is basic vector-types: a basic type that intrinsically store more than one value. The OpenGL Shading Language does define vector types.
+
 
+
The basic non-vector types are:
+
 
+
* bool: conditional type, values may be either true or false
+
* int: a signed integer
+
* uint: an unsigned integer
+
* float: a floating point number
+
 
+
Each of these types, including booleans, can have 2, 3, and 4-component vector equivalents. The ''n'' digit below can be 2, 3, or 4:
+
 
+
* bvec''n'': a vector of booleans
+
* ivec''n'': a vector of signed integers
+
* uvec''n'': a vector of unsigned integers
+
* vec''n'': a vector of floating-point numbers
+
 
+
Vector values can have the same math operators applied to them that scalar values do. These all perform the component-wise operations on each component. However, in order for these operators to work on vectors, the two vectors must have the same number of components.
+
 
+
You can access vectors using the following syntax:
+
 
+
<pre>
+
vec4 someVec;
+
someVec.x + someVec.y;
+
</pre>
+
 
+
This is called ''swizzling''. You can use x, y, z, or w, referring to the first, second, third, and fourth components, respectively.
+
 
+
The reason it has that name swizzling is because the following syntax is entirely valid:
+
 
+
<pre>
+
vec2 someVec;
+
vec4 otherVec = someVec.xyxx;
+
vec3 thirdVec = otherVec.zyy;
+
</pre>
+
 
+
You can use any combination of up to 4 of the letters to create a vector (of the same basic type) of that length. So <code>otherVec.zyy</code> is a vec3, which is how we can initialize a vec3 value with it. Any combination of up to 4 letters is acceptable, so long as the source vector actually has those components. Attempting to access the 'w' component of a vec3 for example is a compile-time error.
+
 
+
Additionally, there are 3 sets of swizzle masks. You can use xyzw, rgba (for colors), or stpq (for texture coordinates). These three sets have no actual difference; they're just syntactic sugar.
+
 
+
==== Matrices ====
+
 
+
In addition to vectors, there are also matrix types. All matrix types are floating-point. Matrix types are as follows, where ''n'' and ''m'' can be the numbers 2, 3, or 4:
+
 
+
* mat''n''x''m'': A matrix with ''n'' columns and ''m'' rows. OpenGL uses column-major matrices, which is standard for mathematics users. Example: mat3x4.
+
* mat''n'': A symmetric matrix with ''n'' columns and rows. This type is equivalent to mat''n''x''n''.
+
 
+
Swizzling does not work with matrices. You can instead access a matrix's fields with array syntax:
+
 
+
<pre>
+
mat3 theMatrix;
+
theMatrix[1] = vec3(3.0, 3.0, 3.0); //Sets the second column to all 3.0s
+
theMatrix[2][0] = 16.0; //Sets the first entry of the third column to 16.0.
+
</pre>
+
 
+
==== Structs and arrays ====
+
 
+
 
+
 
+
==== Constructors ====
+
 
+
All types have constructor syntax that allows you to create values of that type. Constructors use this general syntax:
+
 
+
  ''type''(''value'', ''value'', ...);
+
 
+
The ''type'' is the type you wish to create, be it scalar, vector, matrix, struct, or array.
+
 
+
Constructors for scalar types are special. They can
+
 
+
==== Samplers ====
+
 
+
Texture access is not as simple as reading a value from a memory address. Filtering and other processes are applied to textures, and how texture coordinates are interpreted can be part of the texture access operation. For these reason, texture access is somewhat complicated.
+
 
+
It starts with ''samplers'', a special type that GLSL defines. Each sampler represents a texture that is attached to the program. Samplers have a type that defines what kind of texture can be attached to them. The following samplers types are available:
+
 
+
* ''sampler1D''
+
* ''sampler2D''
+
* ''sampler3D''
+
* ''samplerCube''
+
* ''sampler2DRect''
+
* ''sampler1DShadow'': For doing depth shadow texture accesses. Depth formats are required.
+
* ''sampler2DShadow''
+
* ''samplerCubeShadow''
+
* ''sampler2DRectShadow''
+
* ''sampler1DArray'': For array textures.
+
* ''sampler2DArray''
+
* ''sampler1DArrayShadow''
+
* ''sampler2DArrayShadow''
+
* ''samplerBuffer'': For [[Texture Buffers|buffer textures]]
+
* ''sampler2DMS'': For [[Multisample Textures|multisample textures]].
+
* ''sampler2DMSArray''
+
 
+
These samplers are for textures with floating-point [[Image Formats|image formats]]. For textures with integral image formats, you can preceed the sampler type with "i" for signed integers or "u" for unsigned integers. However, there are no integral "shadow" samplers.
+
 
+
=== Uniforms ===
+
{{main|GLSL Uniforms}}
+
 
+
=== Stage inputs and outputs ===
+
 
+
Each stage in the shader pipeline can define a number of input values and a number of output values. There is an implementation-defined maximum number of inputs and outputs for each stage.
+
 
+
In a very few cases, there are also certain built-in outputs or inputs that can be used. These are generated or required by fixed-functionality processes. However, most inputs and outputs are user-defined.
+
 
+
GLSL creates linkage between outputs from one stage and inputs to the next stage very simply. Because the entire program consists of all stages at once, the linkage is made via matching the variable names. It is illegal for the types of the two variables to be different if they have the same name. This will cause a linker error.
+
 
+
Inputs and outputs are defined as follows:
+
 
+
  in vec3 position;
+
  in vec3 normal;
+
  out vec3 vertNormal;
+
 
+
The "position" and "normal" are inputs, while "vertNormal" is an output of this stage.
+
 
+
The term "centroid" can be used in front of inputs and outputs as well. The syntax "centroid in" means . The syntax "centroid out" means .
+
 
+
==== Interpolation ====
+
 
+
The outputs from a vertex shader (or geometry shader) are interpolated across the surface of a primitive to compute the corresponding input values for the fragment shader. There are some controls that can be applied to the outputs that allow the user to decide how this interpolation takes place.
+
 
+
The default is to use the interpolation mechanism specified by OpenGL. This can be overridden by placing an interpolation qualifier on the output:
+
 
+
* ''flat'': No interpolation at all. The fragment shader value will receive a constant value over the surface of the triangle, based on the value of the [[Flat Shading|provoking vertex]].
+
* ''smooth'': Perspective-correct interpolation.
+
* ''noperspective'': Pure linear interpolation.
+
 
+
==== Multisampling ====
+
 
+
Multisampling causes multiple samples from a single pixel to be processed. Exactly which samples within a pixel are process is implementation defined. This can cause the interpolated value to fall outside of the actual portion of the primitive being rasterized.
+
 
+
This is usually fine. Sometimes, it is important that interpolated values never fall outside of the boundaries of the primitive. This would be the case if certain values would produce undefined results.
+
 
+
The way to handle this is to use "centroid" before the "out" and "in" value. This forces the multisampling algorithm to ensure that the interpolated value is within the boundaries of the primitive.
+
 
+
This does cause performance loss to some degree, so it should only be done where you have actually seen a visual glitch.
+
  
 
== Using GLSL shaders ==
 
== Using GLSL shaders ==
Line 207: Line 58:
  
 
==== Attributes and draw buffers ====
 
==== Attributes and draw buffers ====
 
+
For the stages at the start and end of the pipeline (vertex and fragment, respectively), the initial input values and final output values do not come from or go to shader stages. The input values to a vertex shader come from [[Vertex Attribute|vertex data]] [[Vertex Specification|specified]] in a [[Vertex Array Objects|vertex array object]], pulled from [[Vertex Buffer Objects|vertex buffer objects]] during [[Vertex Rendering]]. The output values of a fragment shader are piped to particular buffers for the currently bound framebuffer; either the [[Default Framebuffer|default framebuffer]] or a [[Framebuffer Objects|framebuffer object]].
For the stages at the start and end of the pipeline (vertex and fragment, respectively), the initial input values and final output values do not come from or go to shader stages. The input values to a vertex shader come from [[Vertex Attributes|vertex data]] [[Vertex Specification|specified]] in a [[Vertex Array Objects|vertex array object]], pulled from [[Vertex Buffer Objects|vertex buffer objects]]. The output values of a fragment shader are piped to particular buffers for the currently bound framebuffer; either the [[Default Framebuffer|default framebuffer]] or a [[Framebuffer Objects|framebuffer object]].
+
  
 
Because of this, there is a mapping layer for the program's inputs and outputs. The vertex shader's input names are mapped to attribute indices, while the fragment shader's output names are mapped to draw buffer indices. This mapping can be created before the program is linked. If it is not, or if the mapping does not cover all of the inputs and outputs, then the linker will automatically define what indices are mapped to which unmapped input or output names. This auto-generated mapping can be queried by the user after the program is linked.
 
Because of this, there is a mapping layer for the program's inputs and outputs. The vertex shader's input names are mapped to attribute indices, while the fragment shader's output names are mapped to draw buffer indices. This mapping can be created before the program is linked. If it is not, or if the mapping does not cover all of the inputs and outputs, then the linker will automatically define what indices are mapped to which unmapped input or output names. This auto-generated mapping can be queried by the user after the program is linked.
Line 214: Line 64:
  
 
=== Setting uniforms ===
 
=== Setting uniforms ===
 +
{{main|GLSL Uniform#Uniform management}}
  
 +
Uniforms in GLSL a shader variables that are set from user code, but only are allowed to change between different {{code|glDraw*}} calls. Uniforms can be queried and set by the code external to a particular shader. Uniforms can be arranged into blocks, and the data storage for these blocks can come from buffer objects.
  
 +
==== Setting samplers ====
 +
{{main|GLSL Sampler#Binding textures to samplers}}
  
=== Setting samplers ===
+
Samplers are special types which must be defined as uniforms. They represent bound textures in the OpenGL context. They are set like integer, 1D uniform values.
  
 
=== Error Checking ===
 
=== Error Checking ===
Line 224: Line 78:
 
Note that the process of loading and compiling shaders hasn't changed much over the different GL versions.
 
Note that the process of loading and compiling shaders hasn't changed much over the different GL versions.
  
<pre>
+
<source lang="cpp">
char *vertexsource;
+
 
char *fragmentsource;
+
char *vertexsource;
int isCompiled_VS, isCompiled_FS;
+
char *fragmentsource;
int IsLinked;
+
int isCompiled_VS, isCompiled_FS;
int maxLength;
+
int IsLinked;
char *vertexInfoLog;
+
int maxLength;
char *fragmentInfoLog;
+
char *vertexInfoLog;
char *shaderProgramInfoLog;
+
char *fragmentInfoLog;
 +
char *shaderProgramInfoLog;
  
/* Read our shaders into the appropriate buffers */
+
/* Read our shaders into the appropriate buffers */
/* You need to code your own version of ReadTextFile() */
+
/* You need to code your own version of ReadTextFile() */
/* Also, the file extension that you give to your vertex and fragment shader doesn't matter.
+
/* Also, the file extension that you give to your vertex and fragment shader doesn't matter.
/* Don't forget, OpenGL doesn't care about your files. */
+
/* Don't forget, OpenGL doesn't care about your files. */
        /* Let's assuming that ReadTextFile allocates a char array and fills it with text */
+
/* Let's assuming that ReadTextFile allocates a char array and fills it with text */
vertexsource = ReadTextFile("myfile.vert");
+
vertexsource = ReadTextFile("myfile.vert");
fragmentsource = ReadTextFile("myfile.frag");
+
fragmentsource = ReadTextFile("myfile.frag");
  
/* Create an empty vertex shader handle */
+
/* Create an empty vertex shader handle */
vertexshader = glCreateShader(GL_VERTEX_SHADER);
+
vertexshader = glCreateShader(GL_VERTEX_SHADER);
  
/* Send the vertex shader source code to GL */
+
/* Send the vertex shader source code to GL */
/* Note that the source code is NULL character terminated. */
+
/* Note that the source code is NULL character terminated. */
/* GL will automatically detect that therefore the length info can be 0 in this case (the last parameter) */
+
/* GL will automatically detect that therefore the length info can be 0 in this case (the last parameter) */
glShaderSource(vertexshader, 1, (const GLchar**)&vertexsource, 0);
+
glShaderSource(vertexshader, 1, (const GLchar**)&vertexsource, 0);
  
/* Compile the vertex shader */
+
/* Compile the vertex shader */
glCompileShader(vertexshader);
+
glCompileShader(vertexshader);
  
glGetShaderiv(vertexshader, GL_COMPILE_STATUS, &IsCompiled_VS);
+
glGetShaderiv(vertexshader, GL_COMPILE_STATUS, &IsCompiled_VS);
if(IsCompiled_VS == FALSE)
+
if(IsCompiled_VS == FALSE)
{
+
{
glGetShaderiv(vertexshader, GL_INFO_LOG_LENGTH, &maxLength);
+
glGetShaderiv(vertexshader, GL_INFO_LOG_LENGTH, &maxLength);
  
/* The maxLength includes the NULL character */
+
/* The maxLength includes the NULL character */
vertexInfoLog = new char[maxLength];
+
vertexInfoLog = new char[maxLength];
  
glGetShaderInfoLog(vertexshader, maxLength, &maxLength, vertexInfoLog);
+
glGetShaderInfoLog(vertexshader, maxLength, &maxLength, vertexInfoLog);
  
/* Handle the error in an appropriate way such as displaying a message or writing to a log file. */
+
/* Handle the error in an appropriate way such as displaying a message or writing to a log file. */
/* In this simple program, we'll just leave */
+
/* In this simple program, we'll just leave */
delete [] vertexInfoLog;
+
delete [] vertexInfoLog;
return;
+
return;
}
+
}
  
/* Create an empty fragment shader handle */
+
/* Create an empty fragment shader handle */
fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
+
fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
  
/* Send the fragment shader source code to GL */
+
/* Send the fragment shader source code to GL */
/* Note that the source code is NULL character terminated. */
+
/* Note that the source code is NULL character terminated. */
/* GL will automatically detect that therefore the length info can be 0 in this case (the last parameter) */
+
/* GL will automatically detect that therefore the length info can be 0 in this case (the last parameter) */
glShaderSource(fragmentshader, 1, (const GLchar**)&fragmentsource, 0);
+
glShaderSource(fragmentshader, 1, (const GLchar**)&fragmentsource, 0);
  
/* Compile the fragment shader */
+
/* Compile the fragment shader */
glCompileShader(fragmentshader);
+
glCompileShader(fragmentshader);
  
glGetShaderiv(fragmentshader, GL_COMPILE_STATUS, &IsCompiled_FS);
+
glGetShaderiv(fragmentshader, GL_COMPILE_STATUS, &IsCompiled_FS);
if(IsCompiled_FS == FALSE)
+
if(IsCompiled_FS == FALSE)
{
+
{
glGetShaderiv(fragmentshader, GL_INFO_LOG_LENGTH, &maxLength);
+
glGetShaderiv(fragmentshader, GL_INFO_LOG_LENGTH, &maxLength);
  
/* The maxLength includes the NULL character */
+
/* The maxLength includes the NULL character */
fragmentInfoLog = new char[maxLength];
+
fragmentInfoLog = new char[maxLength];
  
glGetShaderInfoLog(fragmentshader, maxLength, &maxLength, fragmentInfoLog);
+
glGetShaderInfoLog(fragmentshader, maxLength, &maxLength, fragmentInfoLog);
  
/* Handle the error in an appropriate way such as displaying a message or writing to a log file. */
+
/* Handle the error in an appropriate way such as displaying a message or writing to a log file. */
/* In this simple program, we'll just leave */
+
/* In this simple program, we'll just leave */
delete [] fragmentInfoLog;
+
delete [] fragmentInfoLog;
return;
+
return;
}
+
}
  
/* If we reached this point it means the vertex and fragment shaders compiled and are syntax error free. */
+
/* If we reached this point it means the vertex and fragment shaders compiled and are syntax error free. */
/* We must link them together to make a GL shader program */
+
/* We must link them together to make a GL shader program */
/* GL shader programs are monolithic. It is a single piece made of 1 vertex shader and 1 fragment shader. */
+
/* GL shader programs are monolithic. It is a single piece made of 1 vertex shader and 1 fragment shader. */
/* Assign our program handle a "name" */
+
/* Assign our program handle a "name" */
shaderprogram = glCreateProgram();
+
shaderprogram = glCreateProgram();
  
/* Attach our shaders to our program */
+
/* Attach our shaders to our program */
glAttachShader(shaderprogram, vertexshader);
+
glAttachShader(shaderprogram, vertexshader);
glAttachShader(shaderprogram, fragmentshader);
+
glAttachShader(shaderprogram, fragmentshader);
  
/* Link our program */
+
/* Link our program */
/* At this stage, the vertex and fragment programs are inspected, optimized and a binary code is generated for the shader. */
+
/* At this stage, the vertex and fragment programs are inspected, optimized and a binary code is generated for the shader. */
/* The binary code is uploaded to the GPU, if there is no error. */
+
/* The binary code is uploaded to the GPU, if there is no error. */
glLinkProgram(shaderprogram);
+
glLinkProgram(shaderprogram);
  
/* Again, we must check and make sure that it linked. If it fails, it would mean either there is a mismatch between the vertex */
+
/* Again, we must check and make sure that it linked. If it fails, it would mean either there is a mismatch between the vertex */
/* and fragment shaders. It might be that you have surpassed your GPU's abilities. Perhaps too many ALU operations or */
+
/* and fragment shaders. It might be that you have surpassed your GPU's abilities. Perhaps too many ALU operations or */
/* too many texel fetch instructions or too many interpolators or dynamic loops. */
+
/* too many texel fetch instructions or too many interpolators or dynamic loops. */
  
glGetProgramiv(shaderprogram, GL_LINK_STATUS, (int *)&IsLinked);
+
glGetProgramiv(shaderprogram, GL_LINK_STATUS, (int *)&IsLinked);
if(IsLinked == FALSE)
+
if(IsLinked == FALSE)
{
+
{
/* Noticed that glGetProgramiv is used to get the length for a shader program, not glGetShaderiv. */
+
/* Noticed that glGetProgramiv is used to get the length for a shader program, not glGetShaderiv. */
glGetProgramiv(shaderprogram, GL_INFO_LOG_LENGTH, &maxLength);
+
glGetProgramiv(shaderprogram, GL_INFO_LOG_LENGTH, &maxLength);
  
/* The maxLength includes the NULL character */
+
/* The maxLength includes the NULL character */
shaderProgramInfoLog = new char[maxLength];
+
shaderProgramInfoLog = new char[maxLength];
  
/* Notice that glGetProgramInfoLog, not glGetShaderInfoLog. */
+
/* Notice that glGetProgramInfoLog, not glGetShaderInfoLog. */
glGetProgramInfoLog(shaderprogram, maxLength, &maxLength, shaderProgramInfoLog);
+
glGetProgramInfoLog(shaderprogram, maxLength, &maxLength, shaderProgramInfoLog);
  
/* Handle the error in an appropriate way such as displaying a message or writing to a log file. */
+
/* Handle the error in an appropriate way such as displaying a message or writing to a log file. */
/* In this simple program, we'll just leave */
+
/* In this simple program, we'll just leave */
free(shaderProgramInfoLog);
+
free(shaderProgramInfoLog);
return;
+
return;
}
+
}
  
/* Deallocating these */
+
/* Deallocating these */
delete [] vertexsource;
+
delete [] vertexsource;
delete [] fragmentsource;
+
delete [] fragmentsource;
  
/* In your rendering code, you just need to call glUseProgram, call the various glUniform** to update your uniforms */
+
/* In your rendering code, you just need to call glUseProgram, call the various glUniform** to update your uniforms */
/* and then render. */
+
/* and then render. */
/* Load the shader into the rendering pipeline */
+
/* Load the shader into the rendering pipeline */
glUseProgram(shaderprogram);
+
glUseProgram(shaderprogram);
  
/* When the user shuts down your program, you should deallocate all your GL resources. */
+
/* When the user shuts down your program, you should deallocate all your GL resources. */
/* Unbind your shader. */
+
/* Unbind your shader. */
glUseProgram(0);
+
glUseProgram(0);
/* Let's detach */
+
/* Let's detach */
glDetachShader(shaderprogram, vertexshader);
+
glDetachShader(shaderprogram, vertexshader);
glDetachShader(shaderprogram, fragmentshader);
+
glDetachShader(shaderprogram, fragmentshader);
/* Delete the shaders */
+
/* Delete the shaders */
glDeleteShader(vertexshader);
+
glDeleteShader(vertexshader);
glDeleteShader(fragmentshader);
+
glDeleteShader(fragmentshader);
/* Delete the shader object */
+
/* Delete the shader object */
glDeleteProgram(shaderprogram);
+
glDeleteProgram(shaderprogram);</source>
</pre>
+
  
 
== See also ==
 
== See also ==
  
 
* GLSL
 
* GLSL
 +
** [[GLSL Sampler]]
 +
** [[GLSL Uniform]]
 +
** [[Uniform Buffer Object]]
 
** [[GLSL : common mistakes]]
 
** [[GLSL : common mistakes]]
** [[Multitexture with GLSL]]
 
 
** [[GLSL : nVidia specific features]]
 
** [[GLSL : nVidia specific features]]
 
** [[Hardware_specifics:_NVidia#GLSL_shader_conformance]]
 
** [[Hardware_specifics:_NVidia#GLSL_shader_conformance]]
 
** [[History of OpenGL]]
 
** [[History of OpenGL]]
* [[Cg]] shading language
 
* [[Shading languages]] (general)
 
** [[Shading languages]]
 
** [[Shading languages: General]]
 
** [[Shading languages: Which shading language should I use?]]
 
** [[Shading languages: How to detect shader model?]]
 
  
 
==External links==
 
==External links==
Line 374: Line 224:
 
*[http://www.opengl.org/documentation/red_book/ OpenGL Red Book]
 
*[http://www.opengl.org/documentation/red_book/ OpenGL Red Book]
 
*[http://www.opengl.org/documentation/blue_book/ OpenGL Blue Book]
 
*[http://www.opengl.org/documentation/blue_book/ OpenGL Blue Book]
*[http://www.opengl.org/documentation/extensions/ OpenGL Extensions]
 
 
*[http://www.lighthouse3d.com/opengl/ Tutorials and Examples from Lighthouse3D]
 
*[http://www.lighthouse3d.com/opengl/ Tutorials and Examples from Lighthouse3D]
*[http://nehe.gamedev.net Tutorials and Examples from Nehe]
 
 
*[http://www.ati.com/developer/rendermonkey/ RenderMonkey Shader Development Environment]
 
*[http://www.ati.com/developer/rendermonkey/ RenderMonkey Shader Development Environment]
  
 
[[Category:OpenGL Shading Language]]
 
[[Category:OpenGL Shading Language]]
 
[[Category:Shading Languages]]
 
[[Category:Shading Languages]]

Revision as of 23:18, 27 September 2012

OpenGL Shading Language
Core in version 4.5
Core since version 2.0
ARB extension GL_ARB_shader_objects, GL_ARB_vertex_shader, GL_ARB_fragment_shader, GL_ARB_shading_language_100

The OpenGL Shading Language (GLSL) is the principle shading languages for OpenGL. While there are several shading languages available for use in OpenGL, GLSL is the only one that is a part of the OpenGL core.

GLSL is a C-style language. The language has undergone a number of version changes, and it shares the deprecation model of OpenGL. The current version of GLSL is 4.30.

Compilation model

GLSL is quite unique among shading languages due to its compilation model. It's compilation model is more like the standard C paradigm. Compilation is overseen by a number of object types. Note that these do not follow the standard OpenGL Objects paradigm.

Terminology

Because of GLSL's unique compilation model, GLSL uses unique terminology.

According to GLSL's standard terminology, a shader is just a compiled set of strings for a particular programmable stage; it does not even need to have the complete code for that stage. A program is a fully linked program that covers multiple programmable stages.

For the sake of clarity, we will adjust this slightly. When the term shader is used, it will be synonymous with the GLSL concept of program. To refer to a GLSL shader, the term shader object will be used.

Language

GLSL is a lot like C/C++ in many ways. It supports most of the familiar structural components (for-loops, if-statements, etc). But it has some important language differences.

Standard library

The OpenGL Shading Language defines a number of standard functions. Some standard functions are specific to certain shader stages, while most are available in any stage. There is reference documentation for these functions available here.

Variable types

C has a number of basic types. GLSL uses some of these, but adds many, many more.

Type qualifiers

GLSL's uses a large number of qualifiers to specify where the values that various variables contain come from. Qualifiers also modify how those variables can be used.

Interface blocks

Certain variable definitions can be grouped into interface blocks. These can be used to make communication between different shader stages easier, or to allow storage for variables to come from a buffer object.

Predefined variables

The different shader stages have a number of predefined variables for them. These are provided by the system for various system-specific use.

Using GLSL shaders

Building shaders

Attributes and draw buffers

For the stages at the start and end of the pipeline (vertex and fragment, respectively), the initial input values and final output values do not come from or go to shader stages. The input values to a vertex shader come from vertex data specified in a vertex array object, pulled from vertex buffer objects during Vertex Rendering. The output values of a fragment shader are piped to particular buffers for the currently bound framebuffer; either the default framebuffer or a framebuffer object.

Because of this, there is a mapping layer for the program's inputs and outputs. The vertex shader's input names are mapped to attribute indices, while the fragment shader's output names are mapped to draw buffer indices. This mapping can be created before the program is linked. If it is not, or if the mapping does not cover all of the inputs and outputs, then the linker will automatically define what indices are mapped to which unmapped input or output names. This auto-generated mapping can be queried by the user after the program is linked.


Setting uniforms

Uniforms in GLSL a shader variables that are set from user code, but only are allowed to change between different glDraw*​ calls. Uniforms can be queried and set by the code external to a particular shader. Uniforms can be arranged into blocks, and the data storage for these blocks can come from buffer objects.

Setting samplers

Samplers are special types which must be defined as uniforms. They represent bound textures in the OpenGL context. They are set like integer, 1D uniform values.

Error Checking

This short piece of code shows the process of loading a vertex and fragment shader from 2 text files. Then it compiles them and also checks for errors. The idea here is to encourage newcomers to GLSL to always check for errors. It is in C++ but that doesn't matter.

Note that the process of loading and compiling shaders hasn't changed much over the different GL versions.

char *vertexsource;
char *fragmentsource;
int isCompiled_VS, isCompiled_FS;
int IsLinked;
int maxLength;
char *vertexInfoLog;
char *fragmentInfoLog;
char *shaderProgramInfoLog;
 
/* Read our shaders into the appropriate buffers */
/* You need to code your own version of ReadTextFile() */
/* Also, the file extension that you give to your vertex and fragment shader doesn't matter.
/* Don't forget, OpenGL doesn't care about your files. */
	/* Let's assuming that ReadTextFile allocates a char array and fills it with text */
vertexsource = ReadTextFile("myfile.vert");
fragmentsource = ReadTextFile("myfile.frag");
 
/* Create an empty vertex shader handle */
vertexshader = glCreateShader(GL_VERTEX_SHADER);
 
/* Send the vertex shader source code to GL */
/* Note that the source code is NULL character terminated. */
/* GL will automatically detect that therefore the length info can be 0 in this case (the last parameter) */
glShaderSource(vertexshader, 1, (const GLchar**)&vertexsource, 0);
 
/* Compile the vertex shader */
glCompileShader(vertexshader);
 
glGetShaderiv(vertexshader, GL_COMPILE_STATUS, &IsCompiled_VS);
if(IsCompiled_VS == FALSE)
{
	glGetShaderiv(vertexshader, GL_INFO_LOG_LENGTH, &maxLength);
 
	/* The maxLength includes the NULL character */
	vertexInfoLog = new char[maxLength];
 
	glGetShaderInfoLog(vertexshader, maxLength, &maxLength, vertexInfoLog);
 
	/* Handle the error in an appropriate way such as displaying a message or writing to a log file. */
	/* In this simple program, we'll just leave */
	delete [] vertexInfoLog;
	return;
}
 
/* Create an empty fragment shader handle */
fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
 
/* Send the fragment shader source code to GL */
/* Note that the source code is NULL character terminated. */
/* GL will automatically detect that therefore the length info can be 0 in this case (the last parameter) */
glShaderSource(fragmentshader, 1, (const GLchar**)&fragmentsource, 0);
 
/* Compile the fragment shader */
glCompileShader(fragmentshader);
 
glGetShaderiv(fragmentshader, GL_COMPILE_STATUS, &IsCompiled_FS);
if(IsCompiled_FS == FALSE)
{
	glGetShaderiv(fragmentshader, GL_INFO_LOG_LENGTH, &maxLength);
 
	/* The maxLength includes the NULL character */
	fragmentInfoLog = new char[maxLength];
 
	glGetShaderInfoLog(fragmentshader, maxLength, &maxLength, fragmentInfoLog);
 
	/* Handle the error in an appropriate way such as displaying a message or writing to a log file. */
	/* In this simple program, we'll just leave */
	delete [] fragmentInfoLog;
	return;
}
 
/* If we reached this point it means the vertex and fragment shaders compiled and are syntax error free. */
/* We must link them together to make a GL shader program */
/* GL shader programs are monolithic. It is a single piece made of 1 vertex shader and 1 fragment shader. */
/* Assign our program handle a "name" */
shaderprogram = glCreateProgram();
 
/* Attach our shaders to our program */
glAttachShader(shaderprogram, vertexshader);
glAttachShader(shaderprogram, fragmentshader);
 
/* Link our program */
/* At this stage, the vertex and fragment programs are inspected, optimized and a binary code is generated for the shader. */
/* The binary code is uploaded to the GPU, if there is no error. */
glLinkProgram(shaderprogram);
 
/* Again, we must check and make sure that it linked. If it fails, it would mean either there is a mismatch between the vertex */
/* and fragment shaders. It might be that you have surpassed your GPU's abilities. Perhaps too many ALU operations or */
/* too many texel fetch instructions or too many interpolators or dynamic loops. */
 
glGetProgramiv(shaderprogram, GL_LINK_STATUS, (int *)&IsLinked);
if(IsLinked == FALSE)
{
	/* Noticed that glGetProgramiv is used to get the length for a shader program, not glGetShaderiv. */
	glGetProgramiv(shaderprogram, GL_INFO_LOG_LENGTH, &maxLength);
 
	/* The maxLength includes the NULL character */
	shaderProgramInfoLog = new char[maxLength];
 
	/* Notice that glGetProgramInfoLog, not glGetShaderInfoLog. */
	glGetProgramInfoLog(shaderprogram, maxLength, &maxLength, shaderProgramInfoLog);
 
	/* Handle the error in an appropriate way such as displaying a message or writing to a log file. */
	/* In this simple program, we'll just leave */
	free(shaderProgramInfoLog);
	return;
}
 
/* Deallocating these */
delete [] vertexsource;
delete [] fragmentsource;
 
/* In your rendering code, you just need to call glUseProgram, call the various glUniform** to update your uniforms */
/* and then render. */
/* Load the shader into the rendering pipeline */
glUseProgram(shaderprogram);
 
/* When the user shuts down your program, you should deallocate all your GL resources. */
/* Unbind your shader. */
glUseProgram(0);
/* Let's detach */
glDetachShader(shaderprogram, vertexshader);
glDetachShader(shaderprogram, fragmentshader);
/* Delete the shaders */
glDeleteShader(vertexshader);
glDeleteShader(fragmentshader);
/* Delete the shader object */
glDeleteProgram(shaderprogram);

See also

External links