Difference between revisions of "Type Qualifier (GLSL)"

From OpenGL.org
Jump to: navigation, search
(Invariance qualifiers: Added a section on memory qualifiers.)
(Tessellation control output vertex count)
(3 intermediate revisions by the same user not shown)
Line 59: Line 59:
 
==== Interpolation qualifiers ====
 
==== Interpolation qualifiers ====
  
Fragment shader inputs can have interpolation qualifiers. Interpolation qualifiers can also be used on the outputs from whichever [[Vertex Processing]] stage is the last before [[Vertex Post-Processing]] This traditionally has been the vertex shader, but it could be the geometry shader or the tessellation evaluation shader.
+
Certain inputs and outputs can have interpolation qualifiers. These are for any values which could be interpolated as a result of rasterization. These include:
  
The interpolation qualifiers for corresponding values must match; failure to do so is a linker error.
+
* Vertex shader outputs
 +
* Tessellation control shader inputs
 +
* Tessellation evaluation shader outputs
 +
* Geometry shader inputs and outputs
 +
* Fragment shader inputs.
  
Interpolation qualifiers control how interpolation happens across a triangle or other primitive. There are three basic interpolation qualifiers.
+
Interpolation qualifiers affect linking. If an output provides a qualifier that the corresponding input does not, then it is a mismatch.
  
{{code|flat}} means that there is no interpolation. The value given to the fragment shader is based on the [[Provoking Vertex]] conventions.
+
Interpolation qualifiers control how interpolation of values happens across a triangle or other primitive. There are three basic interpolation qualifiers.
  
{{code|noperspective}} means that there will be linear interpolation in window-space. This is usually not what you want, but it can have its uses.
+
; {{code|flat}}
 +
: The value will not be interpolated. The value given to the fragment shader is the value from the [[Provoking Vertex]] for that primitive.
 +
; {{code|noperspective}}
 +
: The value will be linearly interpolated in window-space. This is usually not what you want, but it can have its uses.
 +
; {{code|smooth}}
 +
: The value will be interpolated in a perspective-correct fashion. This is the default if no qualifier is present.
  
{{code|smooth}}, the default, means to do perspective-correct interpolation.
+
The {{code|centroid}} and {{code|sample}} (requires GL 4.0/{{extref|gpu_shader5}}) qualifiers are not strictly interpolation qualifiers. They can only be used on fragment shader inputs, so they don't affect interface matching. But they are used to control aspects of interpolation. They only have an effect when multisampling is being used.
  
The {{code|centroid}} qualifier only matters when multisampling. If this qualifier is not present, then the value is interpolated to the pixel's center, anywhere in the pixel, or to one of the pixel's samples. This sample may lie ''outside'' of the actual primitive being rendered, since a primitive can cover only part of a pixel's area. The <code>centroid</code> qualifier is used to prevent this; the interpolation point must fall within both the pixel's area and the primitive's area.
+
During multisampling, if {{code|centroid}} is not present, then the value is interpolated to the pixel's center, anywhere in the pixel, or to one of the pixel's samples. This sample may lie ''outside'' of the actual primitive being rendered, since a primitive can cover only part of a pixel's area. The {{code|centroid}} qualifier is used to prevent this; the interpolation point must fall within both the pixel's area and the primitive's area.
  
 
This is useful for parameters or computations that would have undefined values if they fell outside of the primitive's area. A square root is only defined for positive numbers, so if you are taking the square root of an interpolated value, you may need to use {{code|centroid}} interpolation.
 
This is useful for parameters or computations that would have undefined values if they fell outside of the primitive's area. A square root is only defined for positive numbers, so if you are taking the square root of an interpolated value, you may need to use {{code|centroid}} interpolation.
 +
 +
The {{code|sample}} qualifier forces OpenGL to interpolate this qualifier to the location of the particular sample. This is only really useful with per-sample shading.
  
 
=== Uniforms ===
 
=== Uniforms ===
Line 125: Line 136:
  
 
This will allocate the attribute indices 2, 3, 4, and 5.
 
This will allocate the attribute indices 2, 3, 4, and 5.
 +
 +
=== Tessellation control output vertex count ===
 +
{{infobox feature
 +
| name = Tessellation Control Shader
 +
| core = 4.0
 +
| core_extension = {{extref|tessellation_shader}}
 +
}}
 +
 +
[[Tessellation Control Shader]]s (TCS) output patches with a particular vertex count. This is defined by a layout qualifier:
 +
{{clear float}}
 +
layout(vertices = {{param|vertex_count}}) out;
 +
 +
The TCS will be invoked once for each vertex output.
 +
 +
=== Tessellation evaluation options ===
 +
{{main|Tessellation Evaluation Shader#Tessellation options}}
 +
 +
The Tessellation Evaluation Shader (requires GL 4.0 or {{extref|tessellation_shader}}) has a large number of special layout qualifiers that control its behavior.
  
 
=== Geometry shader primitives ===
 
=== Geometry shader primitives ===

Revision as of 01:55, 22 November 2012

A type qualifier is used in the OpenGL Shading Language (GLSL) to modify the storage or behavior of global and locally defined variables. These qualifiers change particular aspects of the variable, such as where they get their data from and so forth. They come in a number of different categories.

Storage qualifiers

Storage qualifiers define where a variable's storage comes from.

Default

If no storage qualifier is specified when declaring a global variable, then the variable is just a normal global variable. All global variables have a scope of the particular shader stage. So if you have two vertex shader objects that define int someValue;​, when you link them into a program, they will both be referring to the same value.

If no storage qualifier is specified for a local variable, then the variable is a local variable that can be modified.

Constant qualifier

Global or local variables can be declared with the const​ qualifier. This means that the variable's value cannot be changed after it is initialized. This also means that the variable declaration must initialize the variable.

Note: The GLSL const​ is different from C++'s const​ qualifier. In C++, a const​ variable is a runtime-constant at that point in the program. Other code could change the memory referenced by that variable; all const​ in C++ means is that this particular variable cannot be used to change the memory behind it. In GLSL, const​ is much simpler: it is a compile-time constant. Thus, a const​ variable can always be used as an integral constant expression.

The initializer for a const variable must be a constant expression. Constant expressions are expressions that only contain:

  • Literal values (3, 2.4, etc)
  • A previously defined global or local variable that is qualified as const.
  • A type constructor that is given only constant expressions as arguments.
  • A operator whose arguments are constant expressions (ie: 5+4).
  • A built-in function call whose arguments are all constant expressions. Notably exempt from this are the texture functions, because uniform variables are not compile-time constant. All of the texture functions take a sampler uniform as a parameter, and therefore they are not compile-time constants.

Shader stage inputs and outputs

Global variables declared with the in​ qualifier are shader stage input variables. These variables are given values by the previous stage (possibly via interpolation of values output from multiple shader executions). These variables are not constant (in the sense of const​), but they cannot be changed by user code.

Global variables declared with the out​ qualifier are shader stage output variables. These values are passed to the next stage of the pipeline (possibly via interpolation of values output from multiple shader executions). The shader must set all output variables at some point in its execution (unless the fragment shader executes the discard​ statement), except for those outputs that are not read by the next shader.

Neither qualifier can be used on local variables.

These variables can be of any non-sampler basic type. They cannot be of struct types, but they can be arrays. There are usually very strict limits on the number of inputs and outputs available to a shader stage.

These variables are how the shader communicates to the earlier and later parts of the pipeline. Each variable name and type will match with an equivalent variable name and type on the next or previous shader stage. So, for each vertex shader output, the fragment shader will have a matching input with the same name and type. Using the same name with a different type is a linker error.

Also, it is allowed to have output variables that are not read by the next stage. It is not allowed to have input variables not written by the previous stage.

There are some special cases with input and output variables for different stages.

Vertex shader inputs

Inputs for vertex shaders are attributes. They are passed from vertex arrays to the vertex shader.

Array inputs can be defined. Each array value takes up one attribute index, sequentially from the first. So this input: in float values[5]​ will take up 5 attributes.

Matrix inputs take up one attribute index for each row.

Geometry shader inputs

Fragment shader outputs

Fragment shader outputs cannot be matrices or booleans; they must be floating-point or integer vectors or scalars.

Each fragment shader output corresponds to a draw buffer, set with the glDrawBuffers command. The association between output values and draw buffers is made with glBindFragDataLocation or with explicit binding via layout(location = #)​ in the shader before linking the program. Any unassigned outputs will be assigned values by the linker arbitrarily.

Interpolation qualifiers

Certain inputs and outputs can have interpolation qualifiers. These are for any values which could be interpolated as a result of rasterization. These include:

  • Vertex shader outputs
  • Tessellation control shader inputs
  • Tessellation evaluation shader outputs
  • Geometry shader inputs and outputs
  • Fragment shader inputs.

Interpolation qualifiers affect linking. If an output provides a qualifier that the corresponding input does not, then it is a mismatch.

Interpolation qualifiers control how interpolation of values happens across a triangle or other primitive. There are three basic interpolation qualifiers.

flat​
The value will not be interpolated. The value given to the fragment shader is the value from the Provoking Vertex for that primitive.
noperspective​
The value will be linearly interpolated in window-space. This is usually not what you want, but it can have its uses.
smooth​
The value will be interpolated in a perspective-correct fashion. This is the default if no qualifier is present.

The centroid​ and sample​ (requires GL 4.0/ARB_gpu_shader5) qualifiers are not strictly interpolation qualifiers. They can only be used on fragment shader inputs, so they don't affect interface matching. But they are used to control aspects of interpolation. They only have an effect when multisampling is being used.

During multisampling, if centroid​ is not present, then the value is interpolated to the pixel's center, anywhere in the pixel, or to one of the pixel's samples. This sample may lie outside of the actual primitive being rendered, since a primitive can cover only part of a pixel's area. The centroid​ qualifier is used to prevent this; the interpolation point must fall within both the pixel's area and the primitive's area.

This is useful for parameters or computations that would have undefined values if they fell outside of the primitive's area. A square root is only defined for positive numbers, so if you are taking the square root of an interpolated value, you may need to use centroid​ interpolation.

The sample​ qualifier forces OpenGL to interpolate this qualifier to the location of the particular sample. This is only really useful with per-sample shading.

Uniforms

Global variables and Interface Blocks can be declared with the uniform​ qualifier. This means that the value does not change between multiple executions of a shader during the rendering of a primitive (ie: during a glDraw* call). These values are set by the user from the OpenGL API.

They are constant, but not compile-time constant (so not const​).

Buffer

In OpenGL 4.3 (or with the ARB_shader_storage_buffer_object extension), interface blocks can be qualified with the buffer​ qualifier. This means that the storage for the block comes from a buffer object, similarly to Uniform Buffer Objects and uniform blocks. Unlike UBOs, storage blocks can be written to. They can also have an unbounded size.

Interface blocks

Inputs, outputs, uniforms, and buffer variables for various stages can grouped into interface blocks.

Shared

Variables declared with the shared​ qualifier are shared among several shader invocations. Such variables can only be used in Compute Shaders. Shared variables are shared among all invocations in a work group.

Layout qualifiers

Uniforms, buffer, inputs, and outputs can also have layout qualifiers. Different stages have their own layout qualifiers, and the different types can have their own as well.

All layout qualifiers are defined with a common syntax:

layout(qualifier1​, qualifier2​ = value, ...) variable definition


The qualifier​ values are specific to a particular use of layouts. The qualifiers are order-independent, unless otherwise noted. Some qualifiers can have values assigned to them, as with qualifier2​ in the above example. These values must be literals.

Some layout qualifiers can apply to all inputs or outputs. In which case, the variable definition can just be in​ or out​.

Vertex shader attribute index

Vertex shader inputs can specify the attribute index that the particular input uses. This is done with this syntax:

layout(location = attribute index) in vec3 position;

With this syntax, you can forgo the use of glBindAttribLocation entirely. If you try to combine the two and they conflict, the layout qualifier always wins.

Attributes that take up multiple attribute slots will be given a sequential block of that number of attributes in order starting with the given attribute. For example:

layout(location = 2) in vec3 values[4];

This will allocate the attribute indices 2, 3, 4, and 5.

Tessellation control output vertex count

Tessellation Control Shader
Core in version 4.5
Core since version 4.0
Core ARB extension ARB_tessellation_shader

Tessellation Control Shaders (TCS) output patches with a particular vertex count. This is defined by a layout qualifier:

layout(vertices = vertex_count​) out;

The TCS will be invoked once for each vertex output.

Tessellation evaluation options

The Tessellation Evaluation Shader (requires GL 4.0 or ARB_tessellation_shader) has a large number of special layout qualifiers that control its behavior.

Geometry shader primitives

Geometry Shaders take a particular primitive type as input and return a particular primitive type as outputs. Also, geometry shaders have a defined maximum number of vertices that they can output. These specifications cannot be used on a variable definition; it can only be used on the qualifiers in​ and out​ as a whole.

 layout(primitive type​) in;
 layout(primitive type​, max_vertices = integer value) out;

For inputs, the primitive type​ can be any of the following:

  • points
  • lines
  • lines_adjacency
  • triangles
  • triangles_adjacency

For outputs, the primitive type​ can be any of the following:

  • points
  • line_strip
  • triangle_strip

The value of max_vertices​ defines the maximum number of vertices the geometry shader can every output in a single invocation.

Fragment shader coordinate origin

The gl_FragCoord​ predefined variable represents the location of the fragment in window-space. There are two layout qualifiers that can affect this. These are specified by redeclaring the predefined variable.

The qualifier origin_upper_left​ specifies that gl_FragCoord​ will have the origin (0, 0) in the upper-left of the screen. The standard OpenGL convention is to have it in the lower-left. This does not change the Z or W of the gl_FragCoord​ value.

The qualifier pixel_center_integer​ specifies that the X and Y of gl_FragCoord​ will be shifted by a half-pixel, so that the center of each pixel is an integer value. The standard OpenGL convention puts the integer values at the corner of the pixel.

These are used as follows:

layout(origin_upper_left) in vec4 gl_FragCoord;

Early fragment tests

By the OpenGL specification, the depth and stencil tests are performed after the fragment shader's execution (implementations can and will do it before the fragment shader, but only if it won't affect the apparent output). However, with a fragment shader's ability to write to arbitrary images and buffers in OpenGL 4.2+, it is useful to be able to enforce early tests. This can be done in GL 4.2 (or with ARB_shader_image_load_store):

layout(early_fragment_tests) in;

Any writes to gl_FragDepth​ in a shader that defines this will be ignored.

Fragment shader buffer output

Fragment shader outputs can specify the buffer index that a particular output writes to. This uses the same syntax as vertex shader attributes:

layout(location = output index) out vec4 outColor;

As with vertex shader inputs, this allows the user to forgo the use of glBindFragDataLocation. Similarly, the values in the shader override the values provided by this function.

For dual source blending, the syntax includes a second qualifier:

layout(location = output index, index = dual output index) out vec4 outColor;

Again, this allows one to forgo the use of glBindFragDataLocationIndexed.

Program separation linkage

Program Separation
Core in version 4.5
Core since version 4.1
Core ARB extension ARB_separate_shader_objects

Normally, when linking shaders into a program, the output variables from one stage are matched with the input variables from another stage. However, when linking programs together dynamically in a program pipeline object, an alternative method of linking is allowed. The name linking is allowed, but so is linking by location.

Input and output variables for communication between shader stages (ie: not vertex shader input or fragment shader output) can have a location associated with them. This is used instead of a name when linking between two shader stages (whether statically or dynamically via a program pipeline). This is provided by the layout location​ qualifier.

For example, given a vertex shader that provides these outputs:

layout(location = 0) out vec4 color;
layout(location = 1) out vec2 texCoord;
layout(location = 2) out vec3 normal;

Normally, the fragment shader would have to use exactly those names. This is not required when using separate programs. If an output has a location specified, the next stage can provide that location with a different name. So a matching fragment shader could look like this:

layout(location = 0) in vec4 diffuseAlbedo;
layout(location = 1) in vec2 texCoord
layout(location = 2) in vec3 cameraSpaceNormal;
Note: The ARB_separate_shader_objects extension was released in a form where this kind of layout location linking outside of separate shaders did not work. That is, if you specified location indices, they were effectively ignored unless you were linking a separate program. The spec was changed to fix this, so that linkage would be the same whether separate or together; if location indices are specified, they are always used. However, AMD implemented the old behavior for a time, and it is not clear that their implementation was updated to fix this.

Interface block memory layout

Variables declared in interface blocks that get their storage from buffers (uniform blocks or shader storage blocks) have a number of layout qualifiers to define the packing and ordering of the variables defined in the block.

Binding points

Uniform and shader storage blocks, and all opaque types have a value which represents the location in the GL context where an object that is to be read/modified is stored. These binding points, like input attribute indices and output data locations can be bound in the shader when using GLSL 4.20 or the GL_ARB_shading_language_420pack extension. This is done by using the "binding" syntax:

layout(binding = 3) uniform sampler2D mainTexture;
layout(binding = 1, std140) uniform MainBlock
{
  vec3 data;
};

The first line is the equivalent of getting the uniform location for "mainTexture" and setting its uniform value to "3". Similarly, the second line is the equivalent of getting the "MainBlock" block location and setting its block index to "1". This only sets the initial value; source code can modify it later.

Precision qualifiers

Note: Precision qualifiers in GLSL are supported for compatibility with OpenGL ES 2.0. They use the same syntax as ES 2.0's qualifiers, but they have no functional effects. Do not use them unless you want your shaders to be ES 2.0 compatible.

There are three precision qualifiers: highp​, mediump​, and lowp​. They have no semantic meaning or functional effect. They can apply to any floating-point type (vector or matrix), or any integer type.

Precision statements

All variables of a certain type can be declared to have a precision by using the precision​ statement. It's syntax is as follows:

precision precision-qualifier​ type​;

In this case, type​ can only be float​ or int​. This will affect all collections of that basic type. So float​ will affect all floating-point scalars, vectors, and matrices. The int​ type will affect all signed and unsigned integer scalars and vectors.

Memory qualifiers

Image Load/Store
Core in version 4.5
Core since version 4.2
Core ARB extension ARB_shader_image_load_store

image​ variables, buffer​ variables, and shader storage blocks (and their contents) can have a number of memory qualifiers applied to them. These affect how they can be used and how values read from/written to them will be seen in other shader invocations. Multiple qualifiers can be used on the same variable.

coherent​
Normally, the compiler is free to assume that this shader invocation is the only invocation that modifies values read through this variable. It also can freely assume that other shader invocations may not see values written through this variable.
Using this qualifier is required to allow dependent shader invocations to communicate with one another, as it enforces the coherency of memory accesses. Using this requires the appropriate memory barriers to be executed, so that visibility can be achieved.
When communicating between shader invocations for different rendering commands, glMemoryBarrier should be used instead of this qualifier.
volatile​
The compiler normally is free to assume that values accessed through variables will only change after memory barriers or other synchronization. With this qualifier, the compiler assumes that the contents of the storage represented by the variable could be changed at any time.
restrict​
Normally, the compiler must assume that you could access the same image/buffer object separate variables in the same shader. Therefore, if you write to one variable, and read from a second, the compiler assumes that it is possible that you could be reading the value you just wrote. With this qualifier, you are telling the compiler that this particular variable is the only variable that can modify the memory visible through that variable within this shader invocation (other shader stages don't count here). This allows the compiler to optimize reads/writes better.
You should use this wherever possible.
readonly​
Normally, the compiler allows you to read and write from variables as you wish. If you use this, the variable can only be used for reading operations (atomic reads that don't change the value also count).
writeonly​
Normally, the compiler allows you to read and write from variables as you wish. If you use this, the variable can only be used for writing operations (atomic writes are forbidden because they also count as reads).

These qualifiers can be used on parameters of image types. If you pass an image to a function, the function parameter's qualifier list much match that of the image declaration. The parameter could have more qualifiers, but it cannot have fewer.

Invariance qualifiers

There is a way to qualify certain output variables as being invariant. This allows different programs to compute the exact same answer, assuming certain conditions are met.

The invariant​ qualifier can be applied to an existing declaration, as in this case:

invariant gl_Position; //Not redeclared; just uses invariant.
in vec3 Color;
invariant Color; //Again makes existing declaration invariant.

Or you can use it at the declaration site.

invariant in vec3 Color;

Qualifier order

Unless you are in GLSL 4.20 or using ARB_shading_language_420pack, qualifiers always come in a particular order. For non-parameter values, the order is always this:

invariant-qualifier interpolation-qualifier layout-qualifier other-storage-qualifier precision-qualifier

The centroid​ qualifier, if present, must immediately precede in​ or out​. For the purpose of ordering, it is considered part of the in​ or out​ storage qualifier, not part of the interpolation qualifier.

GLSL 4.20/ARB_shading_language_420pack removes the ordering restriction in most cases. centroid​ still has to immediate precede in​ or out​. It also allows multiple layout qualifiers, but you can still only use one qualifier from the other groups. The groups of qualifiers match the main headings above: storage, layout, precision, etc.

Built-in redeclaration

The GLSL defines a number of predefined variables at the various shader stages. These variables are defined with a particular set of qualifiers, as stated in the above article. If you wish to use them with a different qualifier, you can redeclare them. You must use the same type, however. And some variables cannot be redeclared with a new qualifier; gl_Position in the vertex shader for example cannot use an interpolation qualifier at all.

Removed qualifiers

The following qualifiers are deprecated as of GLSL 1.30 (OpenGL 3.0) and removed from GLSL 1.40 and above.

The attribute​ qualifier is effectively equivalent to an input qualifier in vertex shaders. It cannot be used in any other shader stage. It cannot be used in interface blocks.

The varying​ qualifier is equivalent to the input of a fragment shader or the output of a vertex shader. It cannot be used in any other shader stages. It cannot be used in interface blocks.