2.8 SPIR-V
SPIR-V是Khronos标准的一种中间语言,这是一种着色器程序分发的替代方案。OpenGL支持GLSL形式的着色器程序,同样也支持SPIR-V形式的着色器程序。通常来说,我们需要某些离线的处理工具,从GLSL这样的高级着色语言来生成SPIR-V形式的代码,进而在用户程序当中发布已生成的SPIR-V程序,而不是直接发布GLSL的源代码。
SPIR-V的创建、发布和使用都是采用二进制单元的模块(module)形式。一个SPIR-V模块在内存中是一段32位词的内容,或者直接存储为32位词的文件。不过,OpenGL和GLSL都不会直接操作文件,所以SPIR-V模块必须是作为内存中的32位词数据指针传递到OpenGL中使用的。
每个SPIR-V模块都可以包含一个或者多个入口点,用来启动一段着色器程序,并且每个入口点都隶属于已知的OpenGL流水线阶段(pipeline stage)。每个这样的入口点都会构成一段独立而完整的OpenGL流水线阶段。换句话说,桌面GLSL会保存多个编译过的着色器单元,然后将它们组合成一个阶段,但是SPIR-V着色器不同。它的编译过程是在离线状态下,通过某个前端工具将高级语言翻译成SPIR-V完成的,因此得到的是一个完整的阶段。即使对于同一个阶段来说,一个独立的SPIR-V模块也可能包含多个入口点。
SPIR-V模块是可以专有化的,也就是说,我们可以在最后编译之前实时修改模块中某些特定的标识常量。这样做是为了降低一个着色器的多个(轻微修改后的)版本对应的SPIR-V模块的数量。
2.8.1 选择SPIR-V的理由
如果用户期望发布SPIR-V形式的着色器,而不是GLSL形式的,那么可能有以下几种原因。有些原因可能符合你目前的状况,有些可能不符合:
更好的可移植性。有一类可移植性问题是因为不同平台的驱动程序对于GLSL的高级语法会有稍微不同的解释。而高级语言之所以被称作高级,部分原因就是它们节约了开发者的宝贵时间。但是,这种便利的前提条件有的时候是很难完全确定的,因而导致了驱动层面的不同结果。SPIR-V更为严格,对于语法的表达也更为规范,因此解释过程中并没有很大的歧义。所以SPIR-V在不同平台的解释过程中变数更小,因而提升了可移植性。当然,我们并没有使用SPIR-V进行编码,而是继续使用诸如GLSL这样的高级语言。但是为了生成SPIR-V程序,需要选择一个针对全平台的前端工具。也就是说,选择了一个独立的GLSL前端之后,我们就消除了因为不同平台的GLSL语法解释过程而产生的可移植性问题。有些人可能会选择其他的前端来编写着色器代码,这样也没有问题。我们真正要关注的重点是:应用程序中的GLSL着色器是否都采用了平台一致的GLSL解释方式,进而生成一致的SPIR-V代码。
多种源语言支持。SPIR-V可以支持GLSL之外的其他高级语言。只要最后发布的SPIR-V是正确格式的,我们就不需要关心它是如何生成的。
减少发布尺寸。SPIR-V有多种特性来显著降低着色器发布后的尺寸。对于独立的着色器来说,SPIR-V的形式通常比GLSL的形式更大一些,但这两者生成的最终结果其实都很小。但是如果将相关的着色器集合起来,尺寸就会大得多。而SPIR-V提供了两种特性来处理这种集合的形式:每个模块的专有化和多重入口点。专有化可以让我们延迟修改某些常量数值&#x