基本概念
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)
编译过程中有一个预处理器去处理源字符串。除了以下提及到的标签,其它的表现都与C++标准预处理器(见第10章”参考文献“)相同。
#
#define
#undef
#if
#ifdef
#ifndef
#else
#elif
#endif
#error
#pragma
#extension
#version
#line
defined
##
每个数字符号(#)都 可以在只有空格或水平制表符构成的行之前。也可以放在只有空格和水平制表符的行之后。每个标签被一个新行结束。预处理不会改变一个源字符串中的新行数量或位置关系。预处理发生在被取消行符号移除行之后。
#define和#undef 作用被定义为标准C++预处理指令的功能,可以定义和处理宏参数。
下面是预定义宏
__LINE__
__FILE__
__VERSION__
__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
#pragma optimize(on)
#pragma optimize(off)
#pragma debug(on)
#pragma debug(off)
着色器应当指明它们使用的语言版本。一个着色器使用的语言版本通过下面方式指定:
#version number profile
在任何一个用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
#define GL_compatibility_profile 1
#define GL_es_profile 1
默认的,这个语言的编译器会指出着色器编译期中那些不遵循本说明书的词汇和语法错误。任何扩展的行为必须先被使能。那些控制编译器行为的扩展标签,被使用#extension标签声明。
#extension extension_name : behavior
#extension all : behavior
extension标签是一个设置每个扩展的简单的,低级的机制。它不保证哪种组合是比较好的,哪些是必须在别的地方定义的。标签的顺序决定了每个扩展使用的行为:
后面出现的标签会覆盖前面的。all变量为所有扩展设置行为,覆盖所有前面指出的extension标签,但是只针对warn和disable这两个行为。
编译器的初始化状态是
#extension all : disable
每个扩展都可以被定义其作用域范围。如果什么都没说,作用域将会是整个着色器(也就是说,一个单独的编译但愿),并且扩展标签必须出现在所有非预处理指令前。如果需要,连接器可以强制扩大到大于一个编译但愿,这样的话,每个包含的着色器将必须包含所需的扩展标签。
宏表达式不能在#extension和#version标签行上使用。
#line在宏替换后,会有以下形式:
#line line
#line line source-string-number