GLSL (OpenGL Shading Language)

From Bauman National Library
This page was last modified on 21 May 2016, at 23:25.
OpenGL Shading Language
GLSLlogo.jpg
Paradigm function, lazy, modular
Designed by Khronos Group
First appeared 2002
OS Cross-platform
Filename extensions .glsl
Website https://www.opengl.org/
Influenced by
C

OpenGL Shading Language (abbreviated: GLSL or GLslang)[1], is a high-level shading language based on the syntax of the C programming language. It was created by the OpenGL ARB (OpenGL Architecture Review Board) to give developers more direct control of the graphics pipeline without having to use ARB assembly language or hardware-specific languages.

With advances in graphics cards, new features have been added to allow for increased flexibility in the rendering pipeline at the vertex and fragment level. Programmability at this level is achieved with the use of fragment and vertex shaders.

The OpenGL Shading Language is actually several closely related languages. These languages are used to create shaders for each of the programmable processors contained in the OpenGL processing pipeline. Currently, these processors are the vertex, tessellation control, tessellation evaluation, geometry, fragment, and compute processors.

Unless otherwise noted in this paper, a language feature applies to all languages, and common usage will refer to these languages as a single language. The specific languages will be referred to by the name of the processor they target: vertex, tessellation control, essellation evaluation, geometry, fragment, or compute.

Most OpenGL state is not tracked or made available to shaders. Typically, user-defined variables will be used for communicating between different stages of the OpenGL pipeline. However, a small amount of state is still tracked and automatically made available to shaders, and there are a few built-in variables for interfaces between different stages of the OpenGL pipeline.

History

Originally, this functionality was achieved by writing shaders in ARB assembly language – a complex and unintuitive task. The OpenGL ARB created the OpenGL Shading Language to provide a more intuitive method for programming the graphics processing unit while maintaining the open standards advantage that has driven OpenGL throughout its history.

Originally introduced as an extension to OpenGL 1.4, GLSL was formally included into the OpenGL 2.0 core by the OpenGL ARB. It was the first major revision to OpenGL since the creation of OpenGL 1.0 in 1992.

Some benefits of using GLSL are:

  • Cross-platform compatibility on multiple operating systems, including GNU/Linux, Mac OS X and Windows.
  • The ability to write shaders that can be used on any hardware vendor's graphics card that supports the OpenGL Shading Language.
  • Each hardware vendor includes the GLSL compiler in their driver, thus allowing each vendor to create code optimized for their particular graphics card’s architecture.

Overview

Vertex Processor

The vertex processor is a programmable unit that operates on incoming vertices and their associated data. Compilation units written in the OpenGL Shading Language to run on this processor are called vertex shaders. When a set of vertex shaders are successfully compiled and linked, they result in a vertex shader executable that runs on the vertex processor.

The vertex processor operates on one vertex at a time. It does not replace graphics operations that require knowledge of several vertices at a time.

Tessellation Control Processor

The tessellation control processor is a programmable unit that operates on a patch of incoming vertices and their associated data, emitting a new output patch. Compilation units written in the OpenGL Shading Language to run on this processor are called tessellation control shaders. When a set of tessellation control shaders are successfully compiled and linked, they result in a tessellation control shader executable that runs on the tessellation control processor.

The tessellation control shader is invoked for each vertex of the output patch. Each invocation can read the attributes of any vertex in the input or output patches, but can only write per-vertex attributes for the corresponding output patch vertex. The shader invocations collectively produce a set of per-patch attributes for the output patch. After all tessellation control shader invocations have completed, the output vertices and per-patch attributes are assembled to form a patch to be used by subsequent pipeline stages.

Tessellation control shader invocations run mostly independently, with undefined relative execution order. However, the built-in function barrier() can be used to control execution order by synchronizing invocations, effectively dividing tessellation control shader execution into a set of phases. Tessellation control shaders will get undefined results if one invocation reads a per-vertex or per-patch attribute written by another invocation at any point during the same phase, or if two invocations attempt to write different values to the same per-patch output in a single phase.=== Tessellation Evaluation Processor === The tessellation evaluation processor is a programmable unit that evaluates the position and other attributes of a vertex generated by the tessellation primitive generator, using a patch of incoming vertices and their associated data. Compilation units written in the OpenGL Shading Language to run on this processor are called tessellation evaluation shaders. When a set of tessellation evaluation shaders are successfully compiled and linked, they result in a tessellation evaluation shader executable that runs on the tessellation evaluation processor.

Each invocation of the tessellation evaluation executable computes the position and attributes of a single vertex generated by the tessellation primitive generator. The executable can read the attributes of any vertex in the input patch, plus the tessellation coordinate, which is the relative location of the vertex in the primitive being tessellated. The executable writes the position and other attributes of the vertex.

Geometry Processor

The geometry processor is a programmable unit that operates on data for incoming vertices for a primitive assembled after vertex processing and outputs a sequence of vertices forming output primitives. Compilation units written in the OpenGL Shading Language to run on this processor are called geometry shaders. When a set of geometry shaders are successfully compiled and linked, they result in a geometry shader executable that runs on the geometry processor.

A single invocation of the geometry shader executable on the geometry processor will operate on a declared input primitive with a fixed number of vertices. This single invocation can emit a variable number of vertices that are assembled into primitives of a declared output primitive type and passed to subsequent pipeline stages.

Fragment Processor

The fragment processor is a programmable unit that operates on fragment values and their associated data. Compilation units written in the OpenGL Shading Language to run on this processor are called fragment shaders. When a set of fragment shaders are successfully compiled and linked, they result in a fragment shader executable that runs on the fragment processor.

A fragment shader cannot change a fragment's (x, y) position. Access to neighboring fragments is not allowed. The values computed by the fragment shader are ultimately used to update framebuffer memory or texture memory, depending on the current OpenGL state and the OpenGL command that caused the fragments to be generated.

Compute Processor

The compute processor is a programmable unit that operates independently from the other shader processors. Compilation units written in the OpenGL Shading Language to run on this processor are called compute shaders. When a set of compute shaders are successfully compiled and linked, they result in a compute shader executable that runs on the compute processor.

A compute shader has access to many of the same resources as fragment and other shader processors, including textures, buffers, image variables, and atomic counters. It does not have any predefined inputs nor any fixed-function outputs. It is not part of the graphics pipeline and its visible side effects are through changes to images, storage buffers, and atomic counters.

A compute shader operates on a group of work items called a work group. A work group is a collection of shader invocations that execute the same code, potentially in parallel. An invocation within a work group may share data with other members of the same work group through shared variables and issue memory and control barriers to synchronize with other members of the same work group.

Versions

GLSL versions have evolved alongside specific versions of the OpenGL API. It is only with OpenGL versions 3.3 and above that the GLSL and OpenGL major and minor version numbers match. These versions for GLSL and OpenGL are related in the following table:

GLSL Version OpenGL Version Date Shader Preprocessor
1.10.59 2.0 April 2004 #version 110
1.20.8 2.1 September 2006 #version 120
1.30.10 3.0 August 2008 #version 130
1.40.08 3.1 March 2009 #version 140
1.50.11 3.2 August 2009 #version 150
3.30.6 3.3 February 2010 #version 330
4.00.9 4.0 March 2010 #version 400
4.10.6 4.1 July 2010 #version 410
4.20.11 4.2 August 2011 #version 420
4.30.8 4.3 August 2012 #version 430
4.40 4.4 July 2013 #version 440
4.50 4.5 August 2014 #version 450

Version 4.40

Independent compilation units written in this language are called shaders. A program is a set of shaders that are compiled and linked together, completely creating one or more of the programmable stages of the OpenGL pipeline. All the shaders for a single programmable stage must be within the same program. A complete set of programmable stages can be put into a single program or the stages can be partitioned across multiple programs[2].

Error Handling

Compilers, in general, accept programs that are ill-formed, due to the impossibility of detecting all illformed programs. Portability is only ensured for well-formed programs, which this specification describes. Compilers are encouraged to detect ill-formed programs and issue diagnostic messages, but are not required to do so for all cases. Compile-time errors must be returned for lexically or grammatically incorrect shaders. Other errors are reported at compile time or link time as indicated. Code that is “dead” must still be error checked. For example:

if (false) // changing false to true cannot uncover additional errors
 statement; // statement must be error checked regardless

Examples

A sample trivial GLSL vertex shader

This transforms the input vertex the same way the fixed-function pipeline would.

void main(void) {
	gl_Position = ftransform();
}

Note that ftransform() is no longer available since GLSL 1.40 and GLSL ES 1.0. Instead, the programmer has to manage the projection and modelview matrices explicitly in order to comply with the new OpenGL 3.1 standard.

#version 140

uniform Transformation {
	mat4 projection_matrix;
	mat4 modelview_matrix;
};

in vec3 vertex;

void main(void) {
	gl_Position = projection_matrix * modelview_matrix * vec4(vertex, 1.0);
}

A sample trivial GLSL tessellation shader

This is a simple pass-through Tessellation Control Shader for the position.

#version 400

layout(vertices=3) out;

void main(void) {
	gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;	gl_TessLevelOuter[0] = 1.0;
	gl_TessLevelOuter[1] = 1.0;
	gl_TessLevelOuter[2] = 1.0;
	gl_TessLevelInner[0] = 1.0;
	gl_TessLevelInner[1] = 1.0;
}

This is a simple pass-through Tessellation Evaluation Shader for the position.

#version 400

layout(triangles,equal_spacing) in;

void main(void) {
	vec4 p0 = gl_in[0].gl_Position;
	vec4 p1 = gl_in[1].gl_Position;
	vec4 p2 = gl_in[2].gl_Position;

	vec3 p = gl_TessCoord.xyz;

	gl_Position = p0*p.x + p1*p.y + p2*p.z;
}

A sample trivial GLSL geometry shader

This is a simple pass-through shader for the color and position.

#version 120
#extension GL_EXT_geometry_shader4 : enable

void main(void) {
	for (int i = 0; i < gl_VerticesIn; ++i) {
		gl_FrontColor = gl_FrontColorIn[i];
		gl_Position = gl_PositionIn[i];
		EmitVertex();
	}
}

Since OpenGL 3.2 with GLSL 1.50 geometry shaders were adopted into core functionality which means there is no need to use extensions. However, the syntax is a bit different. This is a simple version 1.50 pass-through shader for vertex positions (of triangle primitives):

#version 150

layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;

void main(void) {
	for (int i = 0; i < gl_in.length(); ++i) {
		gl_Position = gl_in[i].gl_Position;
		EmitVertex();
	}
	EndPrimitive();
}

A sample trivial GLSL fragment shader

This produces a red fragment.

#version 120

void main(void) {
	gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

In GLSL 1.30 and later you can do

glBindFragDataLocation(Program, 0, "MyFragColor");

where:

  • Program – your shader program's handle;
  • 0 – color buffer number, associated with the variable; if you are not using multiple render targets, you must write zero;
  • "MyFragColor" – name of the output variable in the shader program, which is associated with the given buffer.
#version 150

out vec4 MyFragColor;

void main(void) {
	MyFragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

References

Cite error: Invalid <references> tag; parameter "group" is allowed only.

Use <references />, or <references group="..." />

External links

  1. https://en.wikipedia.org/wiki/OpenGL_Shading_Language
    1. "OpenGL Shading Language"
    2. "OpenGL Shading Language Specification 4.40"