The OpenGL® Shading Language, Version 4.60.7 第三章翻译
Chapter 3. Basics
3.1. Character Set and Phases of Compilation
The source character set used for the OpenGL Shading Language is Unicode in the UTF-8 encoding
scheme.
After preprocessing, only the following characters are allowed in the resulting stream of GLSL
tokens:
• The letters a-z, A-Z, and the underscore (_).
• The numbers 0-9.
• The symbols period (.), plus (+), dash (-), slash (/), asterisk (*), percent (%), angled brackets (< and
>), square brackets ([ and ]), parentheses (( and )), braces ({ and }), caret (^), vertical bar (|),
ampersand (&), tilde (~), equals (=), exclamation point (!), colon (:), semicolon (;), comma (,), and
question mark (?).
A compile-time error will be given if any other character is used in a GLSL token.
There are no digraphs or trigraphs. There are no escape sequences or other uses of the backslash
beyond use as the line-continuation character.
Lines are relevant for compiler diagnostic messages and the preprocessor. They are terminated by
carriage-return or line-feed. If both are used together, it will count as only a single line termination.
For the remainder of this document, any of these combinations is simply referred to as a new-line.
Lines may be of arbitrary length.
In general, the language’s use of this character set is case sensitive.
There are no character or string data types, so no quoting characters are included.
There is no end-of-file character.
More formally, compilation happens as if the following logical phases were executed in order:
1. Source strings are concatenated to form a single input. All provided new-lines are retained.
2. Line numbering is noted, based on all present new-lines, and does not change when new-lines
are later eliminated.
3. Wherever a backslash ('\') occurs immediately before a new-line, both are eliminated. (Note no
white space is substituted, allowing a single token to span a new-line.) Any newly formed
backslash followed by a new-line is not eliminated; only those pairs originally occurring after
phase 1 are eliminated.
4. All comments are replaced with a single space. (Note that '//' style comments end before their
terminating new-lines and white space is generally relevant to preprocessing.)
5. Preprocessing is done, resulting in a sequence of GLSL tokens, formed from the character set
stated above.
第9页
6. GLSL processing is done on the sequence of GLSL tokens.
Details that fully define source strings, comments, line numbering, new-line elimination, and
preprocessing are all discussed in upcoming sections. Sections beyond those describe GLSL
processing.
3.2. Source Strings
The source for a single shader is an array of strings of characters from the character set. A single
shader is made from the concatenation of these strings. Each string can contain multiple lines,
separated by new-lines. No new-lines need be present in a string; a single line can be formed from
multiple strings. No new-lines or other characters are inserted by the implementation when it
concatenates the strings to form a single shader. Multiple shaders can be linked together to form a
single program.
Diagnostic messages returned from compiling a shader must identify both the line number within a
string and which source string the message applies to. Source strings are counted sequentially with
the first string being string 0. Line numbers are one more than the number of new-lines that have
been processed, including counting the new-lines that will be removed by the line-continuation
character (\).
Lines separated by the line-continuation character preceding a new-line are concatenated together
before either comment processing or preprocessing. This means that no white space is substituted
for the line-continuation character. That is, a single token could be formed by the concatenation by
taking the characters at the end of one line concatenating them with the characters at the
beginning of the next line.
float f\
oo;
// forms a single line equivalent to "float foo;"
// (assuming '\' is the last character before the new-line and "oo" are
// the first two characters of the next line)
3.3. Preprocessor
There is a preprocessor that processes the source strings as part of the compilation process. Except
as noted below, it behaves as the C++ standard preprocessor (see “Normative References”).
The complete list of preprocessor directives is as follows.
#
#define
#undef
#if
#ifdef
#ifndef
第10页
#else
#elif
#endif
#error
#pragma
#extension
#version
#line
The following operators are also available:
defined
##
Each number sign (#) can be preceded in its line only by spaces or horizontal tabs. It may also be
followed by spaces and horizontal tabs, preceding the directive. Each directive is terminated by a
new-line. Preprocessing does not change the number or relative location of new-lines in a source
string. Preprocessing takes places after new-lines have been removed by the line-continuation
character.
The number sign (#) on a line by itself is ignored. Any directive not listed above will cause a
compile-time error.
#define and #undef functionality are defined as is standard for C++ preprocessors for macro
definitions both with and without macro parameters.
The following predefined macros are available:
__LINE__
__FILE__
__VERSION__
__LINE__ will substitute a decimal integer constant that is one more than the number of preceding
new-lines in the current source string.
__FILE__ will substitute a decimal integer constant that says which source string number is
currently being processed.
__VERSION__ will substitute a decimal integer reflecting the version number of the OpenGL Shading
Language. The version of the shading language described in this document will have __VERSION__
substitute the decimal integer 460.
By convention, all macro names containing two consecutive underscores (__) are reserved for use
by underlying software layers. Defining or undefining such a name in a shader does not itself result
in an error, but may result in unintended behaviors that stem from having multiple definitions of
the same name. All macro names prefixed with “GL_” (“GL” followed by a single underscore) are
also reserved, and defining or undefining such a name results in a compile-time error.
第11页
Implementations must support macro-name lengths of up to 1024 characters. Implementations are
allowed to generate an error for a macro name of length greater than 1024 characters, but are also
allowed to support lengths greater than 1024.
#if, #ifdef, #ifndef, #else, #elif, and #endif are defined to operate as is standard for C++
preprocessors except for the following:
• Expressions following #if and #elif are further restricted to expressions operating on literal
integer constants, plus identifiers consumed by the defined operator.
• Character constants are not supported.
The operators available are as follows.
Precedence Operator class Operators Associativity
1 (highest) parenthetical grouping ( ) NA
2 unary defined
+ - ~ !
Right to Left
3 multiplicative * / % Left to Right
4 additive + - Left to Right
5 bit-wise shift << >> Left to Right
6 relational < > <= >= Left to Right
7 equality == != Left to Right
8 bit-wise and & Left to Right
9 bit-wise exclusive or ^ Left to Right
10 bit-wise inclusive or | Left to Right
11 logical and && Left to Right
12 (lowest) logical inclusive or || Left to Right
The defined operator can be used in either of the following ways:
defined identifier
defined ( identifier )
Two tokens in a macro can be concatenated into one token using the token pasting (##) operator, as
is standard for C++ preprocessors. The result must be a valid single token, which will then be
subject to macro expansion. That is, macro expansion happens only after token pasting. There are
no other number sign based operators (e.g. no # or #@), nor is there a sizeof operator.
The semantics of applying operators to integer literals in the preprocessor match those standard in
the C++ preprocessor, not those in the OpenGL Shading Language.
Preprocessor expressions will be evaluated according to the behavior of the host processor, not the
processor targeted by the shader.
#error will cause the implementation to put a compile-time diagnostic message into the shader
第12页
object’s information log (see section 7.12 “Shader, Program and Program Pipeline Queries” of the
OpenGL Specification for how to access a shader object’s information log). The message will be the
tokens following the #error directive, up to the first new-line. The implementation must treat the
presence of a #error directive as a compile-time error.
#pragma allows implementation-dependent compiler control. Tokens following #pragma are not
subject to preprocessor macro expansion. If an implementation does not recognize the tokens
following #pragma, then it will ignore that pragma. The following pragmas are defined as part of
the language.
#pragma STDGL
The STDGL pragma is used to reserve pragmas for use by future revisions of this language. No
implementation may use a pragma whose first token is STDGL.
#pragma optimize(on)
#pragma optimize(off)
can be used to turn off optimizations as an aid in developing and debugging shaders. It can only be
used outside function definitions. By default, optimization is turned on for all shaders. The debug
pragma
#pragma debug(on)
#pragma debug(off)
can be used to enable compiling and annotating a shader with debug information, so that it can be
used with a debugger. It can only be used outside function definitions. By default, debug is turned
off.
Shaders should declare the version of the language they are written to. The language version a
shader is written to is specified by
#version number profile_opt
where number must be a version of the language, following the same convention as __VERSION__
above. The directive “#version 460” is required in any shader that uses version 4.60 of the
language. Any number representing a version of the language a compiler does not support will
cause a compile-time error to be generated. Version 1.10 of the language does not require shaders
to include this directive, and shaders that do not include a #version directive will be treated as
targeting version 1.10. Shaders that specify #version 100 will be treated as targeting version 1.00 of
the OpenGL ES Shading Language. Shaders that specify #version 300 will be treated as targeting
version 3.00 of the OpenGL ES Shading Language. Shaders that specify #version 310 will be treated
as targeting version 3.10 of the OpenGL ES Shading Language.
If the optional profile argument is provided, it must be the name of an OpenGL profile. Currently,
第13页
there are three choices:
core
compatibility
es
A profile argument can only be used with version 150 or greater. If no profile argument is provided
and the version is 150 or greater, the default is core. If version 300 or 310 is specified, the profile
argument is not optional and must be es, or a compile-time error results. The Language
Specification for the es profile is specified in The OpenGL ES Shading Language specification.
Shaders for the core or compatibility profiles that declare different versions can be linked
together. However, es profile shaders cannot be linked with non-es profile shaders or with es
profile shaders of a different version, or a link-time error will result. When linking shaders of
versions allowed by these rules, remaining link-time errors will be given as per the linking rules in
the GLSL version corresponding to the version of the context the shaders are linked under. Shader
compile-time errors must still be given strictly based on the version declared (or defaulted to)
within each shader.
Unless otherwise specified, this specification is documenting the core profile, and everything
specified for the core profile is also available in the compatibility profile. Features specified as
belonging specifically to the compatibility profile are not available in the core profile.
Compatibility-profile features are not available when generating SPIR-V.
There is a built-in macro definition for each profile the implementation supports. All
implementations provide the following macro:
#define GL_core_profile 1
Implementations providing the compatibility profile provide the following macro:
#define GL_compatibility_profile 1
Implementations providing the es profile provide the following macro:
#define GL_es_profile 1
The #version directive must occur in a shader before anything else, except for comments and white
space.
By default, compilers of this language must issue compile-time lexical and grammatical errors for
shaders that do not conform to this specification. Any extended behavior must first be enabled.
Directives to control the behavior of the compiler with respect to extensions are declared with the
#extension directive
第14页
#extension extension_name : behavior
#extension all : behavior
where extension_name is the name of an extension. Extension names are not documented in this
specification. The token all means the behavior applies to all extensions supported by the compiler.
The behavior can be one of the following:
Behavior Effect
require Behave as specified by the extension
extension_name.
Give a compile-time error on the #extension if
the extension extension_name is not supported,
or if all is specified.
enable Behave as specified by the extension
extension_name.
Warn on the #extension if the extension
extension_name is not supported.
Give a compile-time error on the #extension if
all is specified.
warn Behave as specified by the extension
extension_name, except issue warnings on any
detectable use of that extension, unless such use
is supported by other enabled or required
extensions.
If all is specified, then warn on all detectable
uses of any extension used.
Warn on the #extension if the extension
extension_name is not supported.
disable Behave (including issuing errors and warnings)
as if the extension extension_name is not part of
the language definition.
If all is specified, then behavior must revert
back to that of the non-extended core version of
the language being compiled to.
Warn on the #extension if the extension
extension_name is not supported.
The extension directive is a simple, low-level mechanism to set the behavior for each extension. It
does not define policies such as which combinations are appropriate, those must be defined
elsewhere. Order of directives matters in setting the behavior for each extension: Directives that
occur later override those seen earlier. The all variant sets the behavior for all extensions,
overriding all previously issued extension directives, but only for the behaviors warn and disable.
The initial state of the compiler is as if the directive
#extension all : disable
第15页
was issued, telling the compiler that all error and warning reporting must be done according to this
specification, ignoring any extensions.
Each extension can define its allowed granularity of scope. If nothing is said, the granularity is a
shader (that is, a single compilation unit), and the extension directives must occur before any nonpreprocessor
tokens. If necessary, the linker can enforce granularities larger than a single
compilation unit, in which case each involved shader will have to contain the necessary extension
directive.
Macro expansion is not done on lines containing #extension and #version directives.
#line must have, after macro substitution, one of the following forms:
#line line
#line line source-string-number
where line and source-string-number are constant integer expressions. If these constant expressions
are not integer literals then behavior is undefined. After processing this directive (including its
new-line), the implementation will behave as if it is compiling at line number line and source string
number source-string-number. Subsequent source strings will be numbered sequentially, until
another #line directive overrides that numbering.
Note
Some implementations have allowed constant expressions in #line directives and
some have not. Even where expressions are supported the grammar is ambiguous
and so results are implementation dependent. For example, + #line +2 +2 // Line
number set to 4, or file to 2 and line to 2
When shaders are compiled for OpenGL SPIR-V, the following predefined macro is available:
#define GL_SPIRV 100
When targeting Vulkan, the following predefined macro is available:
#define VULKAN 100
3.4. Comments
Comments are delimited by /* and */, or by // and a new-line. The begin comment delimiters (/* or //)
are not recognized as comment delimiters inside of a comment, hence comments cannot be nested.
A /* comment includes its terminating delimiter (*/). However, a // comment does not include (or
eliminate) its terminating new line.
Inside comments, any byte values may be used, except a byte whose value is 0. No errors will be
given for the content of comments and no validation on the content of comments need be done.
第16页
Removal of new-lines by the line-continuation character (\) logically occurs before comments are
processed. That is, a single-line comment ending in the line-continuation character (\) includes the
next line in the comment.
// a single-line comment containing the next line \
a = b; // this is still in the first comment
3.5. Tokens
The language, after preprocessing, is a sequence of tokens. A token can be
token :
keyword
identifier
integer-constant
floating-constant
operator
; { }
3.6. Keywords
The following are the keywords in the language and (after preprocessing) can only be used as
described in this specification, or a compile-time error results:
const uniform buffer shared attribute varying
coherent volatile restrict readonly writeonly
atomic_uint
layout
centroid flat smooth noperspective
patch sample
invariant precise
break continue do for while switch case default
if else
subroutine
in out inout
第17页
int void bool true false float double
discard return
vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4
uint uvec2 uvec3 uvec4
dvec2 dvec3 dvec4
mat2 mat3 mat4
mat2x2 mat2x3 mat2x4
mat3x2 mat3x3 mat3x4
mat4x2 mat4x3 mat4x4
dmat2 dmat3 dmat4
dmat2x2 dmat2x3 dmat2x4
dmat3x2 dmat3x3 dmat3x4
dmat4x2 dmat4x3 dmat4x4
lowp mediump highp precision
sampler1D sampler1DShadow sampler1DArray sampler1DArrayShadow
isampler1D isampler1DArray usampler1D usampler1DArray
sampler2D sampler2DShadow sampler2DArray sampler2DArrayShadow
isampler2D isampler2DArray usampler2D usampler2DArray
sampler2DRect sampler2DRectShadow isampler2DRect usampler2DRect
sampler2DMS isampler2DMS usampler2DMS
sampler2DMSArray isampler2DMSArray usampler2DMSArray
sampler3D isampler3D usampler3D
samplerCube samplerCubeShadow isamplerCube usamplerCube
第18页
samplerCubeArray samplerCubeArrayShadow
isamplerCubeArray usamplerCubeArray
samplerBuffer isamplerBuffer usamplerBuffer
image1D iimage1D uimage1D
image1DArray iimage1DArray uimage1DArray
image2D iimage2D uimage2D
image2DArray iimage2DArray uimage2DArray
image2DRect iimage2DRect uimage2DRect
image2DMS iimage2DMS uimage2DMS
image2DMSArray iimage2DMSArray uimage2DMSArray
image3D iimage3D uimage3D
imageCube iimageCube uimageCube
imageCubeArray iimageCubeArray uimageCubeArray
imageBuffer iimageBuffer uimageBuffer
struct
In addition, when targeting Vulkan, the following keywords also exist:
texture1D texture1DArray
itexture1D itexture1DArray utexture1D utexture1DArray
texture2D texture2DArray
itexture2D itexture2DArray utexture2D utexture2DArray
texture2DRect itexture2DRect utexture2DRect
texture2DMS itexture2DMS utexture2DMS
texture2DMSArray itexture2DMSArray utexture2DMSArray
第19页
texture3D itexture3D utexture3D
textureCube itextureCube utextureCube
textureCubeArray itextureCubeArray utextureCubeArray
textureBuffer itextureBuffer utextureBuffer
sampler samplerShadow
subpassInput isubpassInput usubpassInput
subpassInputMS isubpassInputMS usubpassInputMS
The following are the keywords reserved for future use. Using them will result in a compile-time
error:
common partition active
asm
class union enum typedef template this
resource
goto
inline noinline public static extern external interface
long short half fixed unsigned superp
input output
hvec2 hvec3 hvec4 fvec2 fvec3 fvec4
filter
sizeof cast
namespace using
sampler3DRect
In addition, all identifiers containing two consecutive underscores (__) are reserved for use by
underlying software layers. Defining such a name in a shader does not itself result in an error, but
may result in unintended behaviors that stem from having multiple definitions of the same name.
第20页
3.7. Identifiers
Identifiers are used for variable names, function names, structure names, and field selectors (field
selectors select components of vectors and matrices, similarly to structure members). Identifiers
have the form:
identifier :
nondigit
identifier nondigit
identifier digit
nondigit : one of
_ a b c d e f g h i j k l m n o p q r s t u v w x y z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
digit : one of
0 1 2 3 4 5 6 7 8 9
Identifiers starting with “gl_” are reserved, and in general, may not be declared in a shader; this
results in a compile-time error. However, as noted in the specification, there are some cases where
previously declared variables can be redeclared, and predeclared “gl_” names are allowed to be
redeclared in a shader only for these specific purposes.
Implementations must support identifier lengths of up to 1024 characters. Implementations are
allowed to generate an error for an identifier of length greater than 1024 characters, but are also
allowed to support lengths greater than 1024.
3.8. Definitions
Some language rules described below depend on the following definitions.
3.8.1. Static Use
A shader contains a static use of a variable x if, after preprocessing, the shader contains a statement
that would access any part of x, whether or not flow of control will cause that statement to be
executed. Such a variable is referred to as being statically used. If the access is a write then x is
further said to be statically assigned.
3.8.2. Dynamically Uniform Expressions and Uniform Control Flow
Some operations require an expression to be dynamically uniform, or that it be located in uniform
control flow. These requirements are defined by the following set of definitions.
An invocation is a single execution of main() for a particular stage, operating only on the amount of
data explicitly exposed within that stage’s shaders. (Any implicit operation on additional instances
of data would comprise additional invocations.) For example, in compute execution models, a
single invocation operates only on a single work item, or, in a vertex execution model, a single
invocation operates only on a single vertex.
第21页
An invocation group is the complete set of invocations collectively processing a particular compute
workgroup or graphical operation, where the scope of a "graphical operation" is implementationdependent,
but at least as large as a single triangle or patch, and at most as large as a single
rendering command, as defined by the client API.
Within a single invocation, a single shader statement can be executed multiple times, giving
multiple dynamic instances of that instruction. This can happen when the instruction is executed in
a loop, or in a function called from multiple call sites, or combinations of multiple of these.
Different loop iterations and different dynamic function-call-site chains yield different dynamic
instances of such an instruction. Dynamic instances are distinguished by their control-flow path
within an invocation, not by which invocation executed it. That is, different invocations of main()
execute the same dynamic instances of an instruction when they follow the same control-flow path.
An expression is dynamically uniform for a dynamic instance consuming it when its value is the
same for all invocations (in the invocation group) that execute that dynamic instance.
Uniform control flow (or converged control flow) occurs when all invocations in the invocation
group execute the same control-flow path (and hence the same sequence of dynamic instances of
instructions). Uniform control flow is the initial state at the entry into main(), and lasts until a
conditional branch takes different control paths for different invocations (non-uniform or
divergent control flow). Such divergence can reconverge, with all the invocations once again
executing the same control-flow path, and this re-establishes the existence of uniform control flow.
If control flow is uniform upon entry into a selection or loop, and all invocations in the invocation
group subsequently leave that selection or loop, then control flow reconverges to be uniform.
For example:
main()
{
float a = ...; // this is uniform control flow
if (a < b) { // this expression is true for some fragments, not all
...; // non-uniform control flow
} else {
...; // non-uniform control flow
}
...; // uniform control flow again
}
Note that constant expressions are trivially dynamically uniform. It follows that typical loop
counters based on these are also dynamically uniform.
第22页
翻译
3.1字符集和编译阶段
OpenGL着色器语言的源字符集是 UTF-8编码的Unicode.经过预处理后,只有以下字符允许存在于GLSL的结果流中:
字母 a-z,A-Z,和下划线(_)。
数字0-9
句点(.),加号(+),连字符(-),斜线(/),星号(*),百分号(%),尖括号(<和>)方括号([和]),小括号((和)),花括号({和}),插入符(^),竖线(|),与符号(&),波浪号(~)
等于号(=),叹号(!),冒号(:)分号(;) ,逗号(,),问号(?).
如果在GLSL中使用了别的符号,讲会产生编译期错误。
该语言中不存在三联符。没有转意字符,除了用作续行使用外,也不会使用反斜杠(\)。
预处理器和诊断信息是与行有关的。当遇见回车或换行,一行结束。如果同时使用回车和换行,将只会算为一行。在文档的剩余部分,这几种组合都将被简单的视为新的一行。
一般来说,语言对字符集的使用是大小写敏感的。
没有字符或者字符串数据类型,所以不会存在引号(‘ “)。
没有文件结束符号。
更正式的说,编译是按照下面的逻辑和顺序发生的:
1.源字符串被串联成一个单独的输入。所有新行被保留。
2.行号被基于目前的新行记录下来,并且行号不会因为之后的取消行而改变。
3.无论反斜杠是否出现在行的第一个字符处,此行都会被取消。(注意,允许标识符跨行,反斜杠不会使用空格进行替换)如果一个反斜杠后,跟着一个新行,则该行不会 被 不会取消;只有那些原本发生在1后的会被取消。
4.所有注释将被替换为一个空格(注意 ’//‘形式的注释 在换行前结束,空格通常与预处理有关)。
5.预处理结束,得到一系列由上面规定的字符集形成的GLSL 符号。
6.GLSL 对这一系列GLSL符号完成处理。
定义源字符串,注释,行号,新行取消,和预处理的所有细节将在接下来的章节进行探讨。
3.2源字符串
一个着色器的源码是一个字符串的数组。一个着色器是由这些字符串串联组成的。每个字符串可以容纳多行,由新行分割开。一个字符串中没必要出现新行;一行可以由多个字符串组成。当它连接字符串形成一个着色器时,不会插入新行或字符。多个着色器可以被链接到一起形成一个新的程序(program)。
编译一个着色器时所返回的诊断信息必须指明一个字符串中的行号和这条信息指向哪个字符串。源字符串从0开始计数。行号不止是被处理的新行的数量,还包括由行取消符号(\)所取消的行的计算。
被行取消号所分割的行在注释处理和预处理之前组成一个串联起来的新行 。 换行号不会被用空格替换。也就是说,一个标识符可以由前一行中的尾部的几个字母和由行取消号开始的下一行的开头的几个字母组成。
float f\
oo;
// forms a single line equivalent to “float foo;”
// (assuming '\' is the last character before the new line and “oo” are
// the first two characters of the next line)
3.3预处理指令
编译过程中有一个预处理器去处理源字符串。除了以下提及到的标签,其它的表现都与C++标准预处理器(见第10章”参考文献“)相同。
#
#define
#undef
#if
#ifdef
#ifndef
#else
#elif
#endif
#error
#pragma
#extension
#version
#line
以下的操作符也可以使用
-
defined
-
##
每个数字符号(#)都 可以在只有空格或水平制表符构成的行之前。也可以放在只有空格和水平制表符的行之后。每个标签被一个新行结束。预处理不会改变一个源字符串中的新行数量或位置关系。预处理发生在被取消行符号移除行之后。
#define和#undef 作用被定义为标准C++预处理指令的功能,可以定义和处理宏参数。
下面是预定义宏
__LINE__
__FILE__
__VERSION__
__LINE__ 将被替换为一个指示当前源字符串之前的行的数量的十进制的整数常量。
__FILE__将被替换为一个用来表明当前被处理的源字符串的号码的十进制整数常量。
__VERSION__ 将被替换为一个反映当前OpenGL着色器语言版本号的十进制数字。本文档所描述的着色器语言版本号将被替换为十进制数字440。
为了方便起见,所有的宏的名字都包含为底层软件层所保留的两个连贯的下划线(__)。 定义这样一个名字不会导致它自己报错,可能会导致不确定的行为,以阻止同一个名字有多个定义。所有以GL_(GL后跟一个下划线)为前缀的宏也都是保留的,声明一个这样的宏,会导致一个编译期错误。
#if,#ifdef,#ifndef,#else,#elif,和#endif的定义都与标准C++的预处理指令相同。#if和#elif后跟的表达式被进一步限制为 操作文本数字常量的表达式,加上由defined定义的标识符。不支持字符常量。可用的操作符如下:
defined操作符可以像下面这样使用:
defined identifier
defined ( identifier )
两个宏符号可以使用符号粘贴(##)被连接为一个符号,像标准C++预处理一样。得到的结果必须是一个合法的单一符号,这就是宏扩展的课题了。也就是宏扩展只在符号粘贴后发生。除此之外再没有其它基于数字符号的操作符了(例如,没有# 没有 #@),也没有sizeof操作符。
在预处理指令中为数字文字应用操作符的语言和标准C++的预处理指令抑制,而不像OpenGL着色语言中的语法。
预处理指令表达式将根据主处理器的行为计算表达式,而不是根据着色器指定的处理器。
#erro将引起实现部分向着色器对象的信息日志(如何访问一个着色器对象的信息日志,见OpengGL 图形系统说明书 7.12章”着色器及程序请求“)中输出一条编译时诊断信息。
这条信息回事#erro标签后跟的、直到新一行开始之前的标识符,实现部分就会认为着色器处于错误格式。
#pragma 允许根据编译控制器确定实现内容。#pragma后跟的符号不受宏扩展的约束。如果一个实现不认识#pragma后跟的符号,它会忽略这个编译指令。下面的编译指令被定义为语言的一部分
#pragma STDGL
这个STDGL 编译指令被用于保留那些将来版本会使用的编译指令。没有实现会使用第一个符号是STDGL的编译指令。
-
#pragma optimize(on)
-
#pragma optimize(off)
可以用于关闭优化,以利于开发和调试着色器。它只可以在函数定义的外面使用。默认情况下,所有的着色器的优化是开启状态的。调试编译指令
-
#pragma debug(on)
-
#pragma debug(off)
可以用作开启着色器的调试信息,以便于调试器使用。它只可以再函数定义外使用,默认的,调试模式是关闭状态。
着色器应当指明它们使用的语言版本。一个着色器使用的语言版本通过下面方式指定:
#version number profile
number必须是语言的版本,这个版本号和上面__VERSION__遵守一样的约定。
在任何一个用4.40版本语言的着色器中,需要指定标签”#version 440“。任何一个不支持这个版本号的编译器,在编译器将将生成一个编译器错误。1.10版的语言不需要着色器包含这个标签,并且,不包含#version标签的着色器将被认为是1.10版的,#version 100指定的着色器将被认为是OpenGL ES着色器语言的1.00版。指定了#version 300的着色器将被当做OpenGL ES着色器语言的 3.00版对待。
如果profile项有参数,必须是一个OpenGL包,目前,有三个选择:
-
core
-
compatibility
-
es
只有版本号是150或更高版本时,profile选项才可以被使用。如果不提供这个参数,并且版本号大于150,默认的profile参数是core。如果版本号是300, 这个参数不是可选的,必须是es,否则,将会产生一个编译期错误。 es包的的语言说明书在 OpenGL ES着色器语言说明书中。
不同版本的 core或compatibility 着色器是可以被链接到一起的。但是,es包的着色器不可以和没有es包的着色器或者不同版本的es 着色器链接,否则将会产生一个链接期错误。当按照这个规则链接不同版本的着色器时,剩下的链接期错误将被按照每个着色器所在的相关GLSL版本的链接规则 给出。着色器编译期错误仍然会被严格地按照每个着色器所在的版本给出。
除非另作说明,本说明书使用core包,并且为core包所指定的所有东西在compatibility包中都是可用的。属于compatibility包的特性在compatibility包(兼容包)中是不可用的。
每个包有个实现支持的内置的宏定义,所有实现都提供下面这个宏:
#define GL_core_profile 1
兼容包(compaitibility)的实现中提供下面的宏:
#define GL_compatibility_profile 1
es包中的实现提供下面的宏:
#define GL_es_profile 1
除了注释和空格,#version标签必须在一个着色器的最前面。
默认的,这个语言的编译器会指出着色器编译期中那些不遵循本说明书的词汇和语法错误。任何扩展的行为必须先被使能。那些控制编译器行为的扩展标签,被使用#extension标签声明。
#extension extension_name : behavior
#extension all : behavior
extension_name是扩展的名称。扩展的名称在这个说明书中没有被列出来。符号all意味着这个行为被附加到这个编译器支持的所有扩展上。behavior可以如下的值:
extension标签是一个设置每个扩展的简单的,低级的机制。它不保证哪种组合是比较好的,哪些是必须在别的地方定义的。标签的顺序决定了每个扩展使用的行为:
后面出现的标签会覆盖前面的。all变量为所有扩展设置行为,覆盖所有前面指出的extension标签,但是只针对warn和disable这两个行为。
编译器的初始化状态是
#extension all : disable
如上面指出的,告诉编译器所有的错误和警告会按照本说明报告,忽略任何扩展。
每个扩展都可以被定义其作用域范围。如果什么都没说,作用域将会是整个着色器(也就是说,一个单独的编译但愿),并且扩展标签必须出现在所有非预处理指令前。如果需要,连接器可以强制扩大到大于一个编译但愿,这样的话,每个包含的着色器将必须包含所需的扩展标签。
宏表达式不能在#extension和#version标签行上使用。
#line在宏替换后,会有以下形式:
#line line
#line line source-string-number
line和source-string-number是一个数字常量表达式,在处理标签后(包括新行),实现部分将将表现得像正在编译line和源字符串号 source-string-number所在行一样。后续的源字符串将在这之后一次被标记源字符串号,直到另一个#line标签覆盖正在标记的字符串号。
请注意
一些实现允许在#line指令中使用常量表达式
另一些则没有。即使在支持表达式的地方,语法也是模棱两可的
所以结果取决于实现。例如,+ #line +2 +2 // line
数字设置为4,或文件设置为2和行设置为2
当为OpenGL螺旋- v编译着色器时,可以使用以下预定义的宏:
#define GL_SPIRV 100
当目标为Vulkan时,可以使用以下预定义的宏:
#define VULKAN 100
SPIRV解释
Standard, Portable Intermediate Representation - V (SPIR-V) 标准的可移植中间语言标识 (译者注)
3.4。注释
注释用/*和*/分隔,或者用//和换行符分隔。开始注释分隔符(/*或//)
不能识别为注释内的注释分隔符,因此不能嵌套注释。
注释包括它的结束分隔符(*/)。但是,一个//注释不包含(或
消除)它的终止新行。
在注释内部,可以使用任何字节值,但值为0的字节除外。不会有错误
给出了注释的内容,无需对注释的内容进行验证。
16页
通过行延续符(\)删除新行在逻辑上出现在注释之前
处理。也就是说,以行延续符(\)结尾的单行注释包括
注释的下一行。
// a single-line comment containing the next line \
a = b; // this is still in the first comment
-
3.5。符号
-
预处理后的语言是一个标记序列。符号可以是
符号:
关键字
标识符
整形常量
floating-constant
操作符
;{}
3.6。关键字
以下是语言中的关键字,(经过预处理后)只能作为
或编译时错误的结果:
const uniform buffer shared attribute varying
coherent volatile restrict readonly writeonly
atomic_uint
layout
centroid flat smooth noperspective
patch sample
invariant precise
break continue do for while switch case default
if else
subroutine
in out inout
17
int void bool true false float double
discard return
vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4
uint uvec2 uvec3 uvec4
dvec2 dvec3 dvec4
mat2 mat3 mat4
mat2x2 mat2x3 mat2x4
mat3x2 mat3x3 mat3x4
mat4x2 mat4x3 mat4x4
dmat2 dmat3 dmat4
dmat2x2 dmat2x3 dmat2x4
dmat3x2 dmat3x3 dmat3x4
dmat4x2 dmat4x3 dmat4x4
lowp mediump highp precision
sampler1D sampler1DShadow sampler1DArray sampler1DArrayShadow
isampler1D isampler1DArray usampler1D usampler1DArray
sampler2D sampler2DShadow sampler2DArray sampler2DArrayShadow
isampler2D isampler2DArray usampler2D usampler2DArray
sampler2DRect sampler2DRectShadow isampler2DRect usampler2DRect
sampler2DMS isampler2DMS usampler2DMS
sampler2DMSArray isampler2DMSArray usampler2DMSArray
sampler3D isampler3D usampler3D
samplerCube samplerCubeShadow isamplerCube usamplerCube
18页
samplerCubeArray samplerCubeArrayShadow
isamplerCubeArray usamplerCubeArray
samplerBuffer isamplerBuffer usamplerBuffer
image1D iimage1D uimage1D
image1DArray iimage1DArray uimage1DArray
image2D iimage2D uimage2D
image2DArray iimage2DArray uimage2DArray
image2DRect iimage2DRect uimage2DRect
image2DMS iimage2DMS uimage2DMS
image2DMSArray iimage2DMSArray uimage2DMSArray
image3D iimage3D uimage3D
imageCube iimageCube uimageCube
imageCubeArray iimageCubeArray uimageCubeArray
imageBuffer iimageBuffer uimageBuffer
struct
In addition, when targeting Vulkan, the following keywords also exist:
texture1D texture1DArray
itexture1D itexture1DArray utexture1D utexture1DArray
texture2D texture2DArray
itexture2D itexture2DArray utexture2D utexture2DArray
texture2DRect itexture2DRect utexture2DRect
texture2DMS itexture2DMS utexture2DMS
texture2DMSArray itexture2DMSArray utexture2DMSArray
19页
texture3D itexture3D utexture3D
textureCube itextureCube utextureCube
textureCubeArray itextureCubeArray utextureCubeArray
textureBuffer itextureBuffer utextureBuffer
sampler samplerShadow
subpassInput isubpassInput usubpassInput
subpassInputMS isubpassInputMS usubpassInputMS
以下是为将来保留的关键字。使用它们将导致编译时错误:
common partition active
asm
class union enum typedef template this
resource
goto
inline noinline public static extern external interface
long short half fixed unsigned superp
input output
hvec2 hvec3 hvec4 fvec2 fvec3 fvec4
filter
sizeof cast
namespace using
sampler3DRect
此外,所有包含两个连续下划线(__)的标识符都保留给
底层软件层。在着色器中定义这样的名称本身不会导致错误,但是
可能会导致由于具有相同名称的多个定义而产生的无意识行为。
20.页
3.7。标识符
标识符用于变量名、函数名、结构名和字段选择器(字段
选择器选择向量和矩阵的分量,类似于结构成员)。标识符
的形式:
标识符:
数字
标识符数字
标识符数字
非数字:其中之一
_ a b c d e f g h i j k l m n o p q r s t u v w x y z
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
digit:一个
0 1 2 3 4 5 6 7 8 9
以“gl_”开头的标识符是保留的,一般情况下,不能在着色器中声明;这
导致编译时错误。然而,正如规范中所指出的,在某些情况下
以前声明的变量可以重新声明,并且允许预先声明的“gl_”名称
在着色器中重新声明只是为了这些特定的目的。
实现必须支持多达1024个字符的标识符长度。实现
允许为长度大于1024个字符的标识符生成错误,但也可以
允许支持大于1024的长度。
3.8。定义
下面描述的一些语言规则依赖于下列定义。
3.8.1。静态使用
一个着色器包含一个静态的变量x,如果在预处理之后,着色器包含一个语句
它将访问x的任何部分,不管控制流是否会导致该语句
执行。这样的变量被称为静态使用。如果访问是写,那么x是
进一步说是静态分配的。
3.8.2。动态统一表达式和统一控制流
有些操作要求表达式是动态统一的,或者位于uniform中
控制流。这些需求由以下定义集定义。
调用是对特定阶段的main()的一次执行,只对数量进行操作
在该阶段的着色器中显式暴露的数据。(任何对附加实例的隐式操作
的数据将包括额外的调用。)例如,在计算执行模型中,a
单个调用仅操作单个工作项,或者在顶点执行模型中操作单个工作项
调用只对单个顶点进行操作。
21页
调用组是处理特定计算的完整调用集合
工作组或图形操作,其中“图形操作”的范围取决于实现,
但至少和单个三角形或小块一样大,最多和单个三角形或小块一样大
呈现命令,由客户端API定义。
在一次调用中,一个shader语句可以被多次执行
该指令的多个动态实例。在执行指令时可能发生这种情况
一个循环,或在一个函数中从多个调用点调用,或多个调用点的组合。
不同的循环迭代和不同的动态函数调用站点链产生不同的动态
这种指令的实例。动态实例由它们的控制流路径来区分
在调用中,而不是由哪个调用执行它。也就是说,对main()的不同调用
当遵循相同的控制流路径时,执行指令的相同动态实例。
当一个表达式的值是
执行该动态实例的所有调用(在调用组中)都是如此。
统一控制流(或聚合控制流)发生在调用中的所有调用时
组执行相同的控制流路径(因此具有相同的动态实例序列)
指令)。均匀控制流是进入main()时的初始状态,一直持续到a
条件分支对不同的调用采用不同的控制路径(非统一或
不同的控制流)。这样的分歧可以再次收敛,所有的调用都将再次发生
执行相同的控制流路径,这就重新建立了均匀控制流的存在。
如果在进入选择或循环时控制流是统一的,并且调用中的所有调用都是统一的
组随后离开该选择或循环,然后控制流重新收敛到一致。
例如:
main()
{
float a = ...; // this is uniform control flow
if (a < b) { // this expression is true for some fragments, not all
...; // non-uniform control flow
} else {
...; // non-uniform control flow
}
...; // uniform control flow again
}
注意常量表达式是动态统一的。它遵循典型的循环
基于这些的计数器也是动态统一的。