Difference between revisions of "OpenGL Shading Language"

From OpenGL.org
Jump to: navigation, search
(Using GLSL shaders)
(Error Checking)
(7 intermediate revisions by the same user not shown)
Line 6: 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 ==
Line 39: Line 39:
  
 
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.
 
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 ===
 +
{{main|GLSL Interface Block}}
 +
 +
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 ===
 
=== Predefined variables ===
Line 53: 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 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]].
+
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]].
  
 
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 59: Line 64:
  
 
=== Setting uniforms ===
 
=== Setting uniforms ===
{{main|http://www.opengl.org/wiki/GLSL_Uniform#Uniform_management}}
+
{{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.
 
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 ====
 
==== Setting samplers ====
{{main|http://www.opengl.org/wiki/GLSL_Sampler#Binding_textures_to_samplers}}
+
{{main|GLSL Sampler#Binding textures to 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.
 
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 ===
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.
+
This piece of code shows the process of loading a vertex and fragment shaders. 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.
 
Note that the process of loading and compiling shaders hasn't changed much over the different GL versions.
  
<source lang="cpp">
+
{{:Example/GLSL Full Compile Linking}}
 
+
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);</source>
+
  
 
== See also ==
 
== See also ==

Revision as of 00:38, 22 January 2013

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 piece of code shows the process of loading a vertex and fragment shaders. 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.

Full compile/link of a Vertex and Fragment Shader.

//Read our shaders into the appropriate buffers
std::string vertexSource = //Get source code for vertex shader.
std::string fragmentSource = //Get source code for fragment shader.
 
//Create an empty vertex shader handle
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
 
//Send the vertex shader source code to GL
//Note that std::string's .c_str is NULL character terminated.
const GLchar *source = (const GLchar *)vertexSource.c_str();
glShaderSource(vertexShader, 1, &source, 0);
 
//Compile the vertex shader
glCompileShader(vertexShader);
 
GLint isCompiled = 0;
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &isCompiled);
if(isCompiled == GL_FALSE)
{
	GLint maxLength = 0;
	glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &maxLength);
 
	//The maxLength includes the NULL character
	std::vector<GLchar> infoLog(maxLength);
	glGetShaderInfoLog(vertexShader, maxLength, &maxLength, &infoLog[0]);
 
	//We don't need the shader anymore.
	glDeleteShader(vertexShader);
 
	//Use the infoLog as you see fit.
 
	//In this simple program, we'll just leave
	return;
}
 
//Create an empty fragment shader handle
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
 
//Send the fragment shader source code to GL
//Note that std::string's .c_str is NULL character terminated.
source = (const GLchar *)fragmentSource.c_str();
glShaderSource(fragmentShader, 1, &source, 0);
 
//Compile the fragment shader
glCompileShader(fragmentShader);
 
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &isCompiled);
if(isCompiled == GL_FALSE)
{
	GLint maxLength = 0;
	glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &maxLength);
 
	//The maxLength includes the NULL character
	std::vector<GLchar> infoLog(maxLength);
	glGetShaderInfoLog(fragmentShader, maxLength, &maxLength, &infoLog[0]);
 
	//We don't need the shader anymore.
	glDeleteShader(fragmentShader);
	//Either of them. Don't leak shaders.
	glDeleteShader(vertexShader);
 
	//Use the infoLog as you see fit.
 
	//In this simple program, we'll just leave
	return;
}
 
//Vertex and fragment shaders are successfully compiled.
//Now time to link them together into a program.
//Get a program object.
GLuint program = glCreateProgram();
 
//Attach our shaders to our program
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
 
//Link our program
glLinkProgram(program);
 
//Note the different functions here: glGetProgram* instead of glGetShader*.
GLint isLinked = 0;
glGetProgramiv(program, GL_LINK_STATUS, (int *)&isLinked);
if(isLinked == GL_FALSE)
{
	GLint maxLength = 0;
	glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);
 
	//The maxLength includes the NULL character
	std::vector<GLchar> infoLog(maxLength);
	glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);
 
	//We don't need the program anymore.
	glDeleteProgram(program);
	//Don't leak shaders either.
	glDeleteShader(vertexShader);
	glDeleteShader(fragmentShader);
 
	//Use the infoLog as you see fit.
 
	//In this simple program, we'll just leave
	return;
}
 
//Always detach shaders after a successful link.
glDetachShader(program, vertexShader);
glDetachShader(program, fragmentShader);

See also

External links