Difference between revisions of "Core Language (GLSL)"

From OpenGL.org
Jump to: navigation, search
(Added notations about control flow constructs.)
Line 56: Line 56:
== Qualifiers ==
== Qualifiers ==
{{main|GLSL Qualifiers}}
{{main|GLSL Type Qualifiers}}
Variables declared at global and local scope can have a number of qualifiers associated with them. Most of these are unique to shading languages.
Variables declared at global and local scope can have a number of qualifiers associated with them. Most of these are unique to shading languages.

Revision as of 19:41, 19 March 2011

The OpenGL Shading Language 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 switch statement. This section will not cover the entire language in detail; the GLSL specification can handle that. This page will will note the differences between GLSL and C.

Compilation settings

The OpenGL Shading Language requires certain information to be presented early in a shader object's compilation. In a command-line-based compiler, these would be compiler settings. GLSL's compilation model instead requires them to be part of the language.

These should be in the first lines of the first string associated with a shader object. If you want to globally apply these, then you should put them in a string that you then put at the beginning of every shader object's string block.


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.

To specify which version of GLSL should be used, use this directive:

 #version 1.50

This would tell the compiler to compile for version 1.50, or error if that version is not available.

The version number can be followed by the profile name. This can be core or compatibility. If this is not specified, the default is core.

The #version directive must appear before anything else in a shader, save for whitespace and comments.


Many OpenGL Extensions modify GLSL's behavior and functionality 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.

Similar to the #version directive, the user can activate specific extensions with the "#extension" directive. The syntax is as follows:

 #extension extension_name : behavior

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, but before .

Preprocessor directives

All of the keywords beginning with # are preprocessor directives, much like with C. GLSL provides most of the standard C set of preprocessor directives (#define, #if, etc), in addition to the ones listed above. The most notable omission is #include.

Macro expansion does not work on #version and #extension directives.

Standard macros

GLSL defines a number of macros. __FILE__ is not a filename; it is a decimal integer representing which string in the list of strings given to the shader. __LINE__ is the line number. __VERSION__ is a decimal integer representing the GLSL version being compiled. If the version is 3.30, then __VERSION__ will be "330".

The macro GL_core_profile is always defined to be "1". The macro GL_compatibility_profile is only defined to be "1" if the version for this shader was set to be compatibility.


The GLSL defines a number of types. Some of them are familiar to C/C++ users, while others are quite different.


Variables declared at global and local scope can have a number of qualifiers associated with them. Most of these are unique to shading languages.


Functions can be defined in GLSL, but they have a very different way of working from C/C++ functions.

Just like in C/C++, execution of a shader begins with the function main. This function takes no parameters and returns no values.


The C/C++ function model allows functions to be recursive. That is, function A can call function B, which itself calls function A. Indeed, function A can call itself. Obviously, there has to be some condition to prevent infinite recursion, but C/C++ allows this to work.

GLSL does not. The GLSL memory model does not allow for recursive function calls. This allows GLSL to execute on hardware that simply doesn't allow for recursion. It allows GLSL to function when there is no ability to write arbitrarily to memory, which is true of most shader hardware (though it is becoming less true with time.

So, no recursion in GLSL. Of any kind.


GLSL functions are declared and defined similarly to C/C++ functions. A function declaration in GLSL looks like this:

void MyFunction(in float inputValue, out int outputValue, inout float inAndOutValue);

Functions in GLSL use a calling convention called "value-return." This means that values passed to functions are copied into parameters when the function is called, and outputs are copied out when the function returns.

The in, out, and inout qualifiers are not the same as type qualifiers, even though some of them are named the same. These are parameter qualifiers, and they have a different meaning here.

A parameter declared as in means that the value given to that parameter will be copied into the parameter when the function is called. The function may then modify that parameter as they see fit, but those changes will not affect the calling code.

A parameter declared as out will not have its value initialized by the caller. The function will modify the parameter, and after the function's execution is complete, the value of the parameter will be copied out into the variable that the user specified when calling the function. Note that the initial value of the parameter at the start of the function being called is undefined, just as if one had simply created a local variable.

The inout declaration combines both. The parameter's value will be initialized by the value supplied by the user, and its final value will be output

The default if no qualifier is specific is in.

Consider the following:

void MyFunction(in float inputValue, out int outputValue, inout float inAndOutValue)
  inputValue = 0.0;
  outputValue = int(inAndOutValue + inputValue);
  inAndOutValue = 3.0;
void main()
  float in1 = 10.5;
  int out1 = 5;
  float out2 = 10.0;
  MyFunction(in1, out1, out2);

MyFunction will receive a 10.5, an undefined value, and a 10.0 as parameters. After the function is called, the values in main are:

in1 10.5
out1 10
out2 3.0

Notice that the value of in1 does not change.

For parameters declared as out or inout, the caller must pass an l-value. To put it simply, it must be a variable that can be set. So it cannot be an expression (calling MyFunction(in1, 2+4, out2) is an error). They also cannot be called on a value that is unsettable. This includes shader inputs (global variables declared with the in qualifier), uniforms, or const-qualified values.

Functions can have return values just like C/C++. But the out and inout qualifiers allow functions to return multiple values.

Control flow

GLSL uses the standard C/C++ set of control code. If-else statements, switch statements, for, while, and do-while loops. It has the usual break, continue, and return commands.

What it does not have is goto.

It also has a new jump command: discard. This keyword can only be used in fragment shaders. It causes the fragment shader's results to be discarded and ignored by the rest of the pipeline. That fragment's value(s) will not be written to the framebuffer.

Note: This does not mean that fragment shaders actually stop processing once the discard command is reached. In general, fragment shaders are grouped into blocks of four; so long as one of them is running, they all must be running and executing the same code. Because of that, only discarding from all four fragments will cause processing to stop.

Using discard is different from return from main. Executing return still means that the values written to the shader outputs will be used by the rest of the pipeline. Executing discard means that they will not.

Reserved names

GLSL reserves any name beginning with "gl_"; attempts to define variables or functions with that name will result in an error.