引言
本文档仅规定4.60 版本的 OpenGL 着色语言(GLSL)。它要求 __VERSION__ 宏替换为 460,且 #version 指令仅接受 460。若 #version 声明的版本号更小,所接受的语言为该着色语言的旧版本,是否支持取决于 API 中的上下文版本与类型。有关支持哪些语言版本的详细信息,请参阅规范性引用文档。
以往版本的 OpenGL 着色语言以及 OpenGL ES 着色语言,并非本文档所规定版本的严格子集,尤其在精度、名称隐藏规则以及接口变量处理方面差异明显。有关特定语言版本的详细规则,请参阅对应版本的规范。
在全文中,当生成供 Vulkan API 使用的 SPIR-V 时(见规范性引用),均称为面向 Vulkan 目标。
尽管本规范与 OpenGL 规范是 OpenGL 着色语言的权威依据,但在生成 SPIR-V 时,SPIR-V 规范与SPIR-V 客户端 API 规范仍是所生成 SPIR-V 的权威依据。更多细节请参阅规范性引用。
对于 SPIR-V 生成,SPIR-V 客户端 API 规定了用于操作 SPIR-V 着色器的指令。
独立的离线工具链会将 GLSL 编译为 SPIR-V 中间语言。SPIR-V 生成不通过 #extension、#version 或剖面(profile)启用。相反,GLSL 是否用于生成 SPIR-V,由离线工具链的使用方式决定。有关如何为其客户端 API 请求生成 SPIR-V,请参阅对应工具的文档。
GLSL→SPIR-V 编译器必须被告知运行时合法的 SPIR-V 能力集,并对使用超出这些能力的 GLSL 特性报错。对于可由前端根据 GLSL 源码中的内置常量进行错误检查的、与实现相关的限制同样如此:前端可获知此类限制,并在超出时报告错误。
不受 SPIR-V 能力控制、但存在对应 GLSL 等价特性(着色阶段、内置函数、类型、限制等)的 SPIR-V 特性,仅期望在支持该 GLSL 等价特性的 OpenGL 驱动上正常工作。
除非另行指定剖面,本文档中所有对 OpenGL 规范的引用均指向 4.6 核心剖面。
变更记录
相对于 GLSL 4.6 第 8 版的变更
- 公开 GLSL 问题 #198:明确逻辑运算符仅作用于标量。
- 非公开 GLSL 问题 #59:修复 atanh 函数定义域错误。
- 非公开 GLSL 问题 #66:添加说明,明确未初始化的输出形参将被拷贝,导致函数实参变为未定义。
- 非公开 GLSL 问题 #68:对 “数组” 章节进行澄清性修改。本章已重新组织以便于编辑,并澄清了若干规则。无尺寸数组的规则同样纳入 ES 相关内容,尽管它们无法被显式声明,但适用于某些预声明场景。
相对于 GLSL 4.6 第 7 版的变更
- 非公开 GLSL 问题 #57:明确 imageLoad 的精度(如适用)仅由图像参数的精度决定。
- 公开 GLSL 问题 #164:明确 mod 应满足的精度要求。
- 公开 GLSL 问题 #8:明确计算着色器变量可被访问的时机。
- 公开 GLSL 问题 #13:明确位置别名的位宽要求。
- 公开 GLSL 问题 #161:修复布局限定符示例错误。
- 非公开 GLSL 问题 #30:明确结构体成员的精度始终作为结构体类型声明的一部分被固定。
- 非公开 GLSL 问题 #49:明确对一元 + 的支持。
- 非公开 GLSL 问题 #43:明确构造函数的精度。
- 非公开 GLSL 问题 #53:明确接口块允许使用的限定符。
- 非公开 GLSL 问题 #31:删除将 invariant 用于 in 变量的错误示例。
- 修复公开 GLSL 问题 #83:只有不透明类型变量在传入用户自定义函数时,才必须保留其内存限定符(如 readonly)。
- 明确声明原子计数器时的错误条件。
- intBitsToFloat() 可能将非规格化数值刷新为 0.0。
- 明确 precise 不可用于限定结构体定义。
- 非公开 Bugzilla #15755:明确应用可见内存中带精度限定的接口块成员的存储大小。
相对于 GLSL 4.6 第 6 版的变更
- 纳入 GL_KHR_vulkan_glsl 规范。
- 在引言中添加说明,说明驱动中 SPIR-V 特性与 GLSL 特性的对应关系。
- 明确是相同位置触发默认 uniform 块匹配规则。详见 Uniform 变量布局限定符。
相对于 GLSL 4.6 第 5 版的变更
- 非公开 GLSL 问题 #34:明确并统一 int 到 uint 的隐式转换规则,使其与显式构造行为一致。
- 非公开 GLSL 问题 #24:明确 barrier() 本身足以同步控制流与对共享变量、曲面细分控制输出变量的内存访问。对于其他内存访问,仍需额外的内存屏障。
- 规范性引用 IEEE-754 作为浮点格式定义依据。
- 非公开 GLSL 问题 #36:double 类型的 refract 函数要求 eta 参数类型为 double。
- 明确曲面细分阶段与几何阶段中输入变量的限制。
- 非公开 GLSL 问题 #15:明确数组的数组的绑定顺序。
- 非公开 GLSL 问题 #14:Uniform 变量仅在被静态使用时,才需要在链接时匹配。
- 对于精确计算,控制流与三元运算符(?:)的控制表达式不计入精确计算范围。
相对于 GLSL 4.6 第 4 版的变更
- 非公开 Bug 13012:明确内置 uniform 变量可能仅在片元阶段可用。
- 非公开 Bug 13837:三元运算符与逗号运算符可作用于 void 类型。
- 明确预处理产生的错误必须在编译时返回。
- 明确对变量任何部分的访问均构成静态使用。
- 非公开 GLSL 问题 #19:switch 语句末尾的任何标签后必须跟随一条语句。
- 非公开 GLSL 问题 #26:为 SPIR-V 编译时,noise 无效。
- 非公开 GLSL 问题 #20:返回常量值的 length() 表达式不得包含副作用。
- 公开 OpenGL API 问题 #7:变量可同时声明为 readonly 和 writeonly。
- 非公开 GLSL 问题 #16:#line 指令中使用常量表达式的行为未定义。
- 修正浮点图像上 imageAtomicExchange 的返回类型。
- 非公开 GLSL 问题 #32:消除 length() 方法矛盾:非运行时尺寸数组仅支持在显式尺寸数组上调用 length()。
- 非公开 GLSL 问题 #21:明确 interpolateAt 的左值限制。
- 公开 OpenGL API 问题 #53:明确位置别名的位宽要求。
- 公开 GLSL 问题 #15:gl_in 可使用无尺寸数组语法重声明。
- 明确深度 / 模板纹理所需的 DEPTH_COMPONENT 与 STENCIL_COMPONENT 格式。
- 在布局限定符章节的布局限定符表中添加图像格式。
相对于 GLSL 4.6 第 3 版的变更
- 非公开 GLSL 问题 #13:修复 allInvocationsEqual() 拼写错误(表格中曾错误写为 anyInvocationsEqual(),其余拼写正确)。
GLSL 4.50 第 7 版以来的变更概要
- 纳入 GL_ARB_shader_atomic_counter_ops 扩展。
- 纳入 GL_ARB_shader_draw_parameters 扩展。
- 纳入 GL_ARB_shader_group_vote 扩展。
- 纳入 GL_ARB_gl_spirv 扩展。
- 非公开 Bug 16070:允许全局作用域出现多余分号。
- 非公开 GLSL 问题 #5:明确 “链接失败” 实际是指 “编译时或链接时错误”,适用于某些错误类型。
- 非公开 GLSL 问题 #7:将 gl_MaxComputeUniformComponents 修改为 1024。
- 非公开 OpenGL API 问题 #35:SPIR-V 要求透明独立 uniform 变量必须指定 location。
- 非公开 GLSL 问题 #8:进一步明确 interpolateAt() 的插值量可以是结构体成员。
- 非公开 GLSL 问题 #9:规定 xfb_buffer 与块数组的交互方式:每个块数组元素对应的捕获缓冲区递增。
概述
本文档描述 OpenGL 着色语言 4.60 版本。
用该语言编写的独立编译单元称为着色器。一个程序是一组编译并链接在一起的着色器,完整构成 API 管线的一个或多个可编程阶段。同一可编程阶段的所有着色器必须位于同一个程序中。一套完整的可编程阶段可放入单个程序,也可拆分到多个程序中。
本文档的目标是完整、严谨地规定该编程语言。相关规范性引用将定义用于操作程序与着色器并与之通信的 API 入口。
错误处理
通常,由于无法检测所有不合法程序,编译器会接受形式不正确的程序。只有本文档所描述的合法程序才能保证可移植性。鼓励编译器检测不合法程序并输出诊断信息,但不要求覆盖所有情况。词法或语法错误的着色器必须返回编译时错误。其他错误将按规定在编译时或链接时报告。“死”代码仍必须进行错误检查,例如:
if (false) // 将 false 改为 true 不应暴露出额外错误
statement; // 无论如何,该语句必须被错误检查
排版约定
本文档主要使用斜体、粗体与字体选择提升可读性。代码片段使用等宽字体。正文中嵌入的标识符使用斜体。正文中嵌入的关键字使用粗体。运算符以名称称呼,后接括号内的粗体符号。文中用于澄清的语法片段使用粗体表示字面量,斜体表示非终结符。“着色语言语法” 中的官方语法使用全大写表示终结符,小写表示非终结符。
弃用
OpenGL 着色语言已弃用部分特性。这些特性在本文档中明确标注为 **“已弃用”**。它们在当前版本语言中仍然存在,但计划在未来版本中可能移除。OpenGL API 提供向前兼容模式,禁止使用已弃用特性。若在禁止使用已弃用特性的模式下编译,使用这些特性将导致编译时或链接时错误。有关哪些行为会使已弃用语言特性被接受或报错,请参阅 OpenGL 规范。



