Vulkan编程指南翻译 第六章 着色器和管线 第1节 GLSL简介

99 篇文章 54 订阅
81 篇文章 2 订阅

第六章 着色器和管线

在本章你将学到

l 什么事着色器及如何使用它

l SPIR-V -- Vulkan渲染语言的基础知识

l 如何构造着色器管线并用它做工作

 

着色器是在设备上执行的小程序。他们是任何复杂Vulkan程序构建的基础单元。对你的应用程序中操作来讲,着色器比Vulkan API更重要。本章介绍着色器和着色器模块,展示他们如何从SPIR-V二进制文件构建,并讲解如何使用标准工具从GLSL生成这些二进制文件。讲解由着色器组成的管线和需要运行它们的其他信息,然后展示如何在设备上执行着色器来完成工作。

着色器是设备上执行工作的基础的构建单位。Vulkan着色器通过SPIR-V表示,它是一个二进制中间码,可表示程序代码。SPIR-V可以用编译器离线生成,或直接在程序内部在线的生成,或者直接通过高级语言传递给运行时库。本书示例程序使用第一种方式:离线的编译后从磁盘载入生成的SPIR-V二进制文件。

 

原始的着色器程序由GLSL语言书写,参照Vulkan标准。这是一个相较于OpenGL使用的着色语言有修改和增强的版本。因此,大多数例子,依GLSL而言讨论Vulkan的特征。然而,应该明白Vulkan本身和GLSL没有任何关系,它也不关心SPIR-V着色器程序从哪里来。

 

6.1  GLSL总览

 

尽管并不是Vulkan标准的一部分,VulkanOpenGL特性部分相似。在OpenGL中,官方支持的高级语言是GLSL--OpenGL Shading Language。因此,在SPIR-V设计期间,很多工作集中在保证至少有一个高级语言适合生成SPIR-V着色器。GLSL经少量修改就可以被Vulkan使用。一些新添加的特性让GLSL着色器可以清晰的和Vulkan系统交互,OpenGL不被引入Vulkan的遗留特征被从Vulkan GLSL规范中去除了。

结果就是一个简洁版的GLSL支持Vulkan绝大多数特征,但也同时保持了OpenGLVulkan之间高度的兼容性。简而言之,如果你坚持在OpenGL程序中使用高级特征,你在着色器中写的多数代码都将可使用官方的编译器直接编译为SPIR-V中间码。淡然,你也可以使用自己写的编译器和工具,或者使用第三方的编译器来从任意语言产生SPIR-V模块。

GLSL的修改允许它被用来产生Vulkan可用SPIR-V着色器程序,这些修改记录在GL_KHR_vulkan_glsl拓展的文档中。

在本节,我们简单的介绍GLSL。这里假设读者对于高级着色语言是有一些熟悉的,并且有能力来深入的研究GLSL

Listing 6.1 展示一个最简单的GLSL着色器。它只是一个空函数,返回void,什么操作也不做。这实际上对于Vulkan管线任何阶段来说是一个有效的着色器程序,即使在一些阶段执行它会造成为定义的行为。

Listing 6.1: Simplest Possible GLSL Shader

#version 450 core

void main (void)

{

// Do nothing!

}

所有的GSL着色器都应一个#version宏开头,来告知GLSL编译器我们正在使用哪个版本的GLSL这允许编译器进行适当的错误检查,并允许随着时间语言引进新的结构。

当被编译为SPIR-V以供Vulkan使用时,编译器应向在用的GL_KHR_vulkan_glsl拓展自动定义VULKAN宏,以便你可以在GLSL着色器的#ifdef VULKAN or #if VULKAN >{version} 代码块中包含Vulkan特定的构造或者功能,这样着色器就可以被OpenGLVulkan共同使用了。

贯穿这本书,当讨论GLSL语境下Vulkan特定的特征时,都默认假设缩写代码要么只为Vulkan所写,要么被包含在合适的#ifdef预处理条件中,以被编译为Vulkan所用。

GLSLC风格的语言,它的语法和许多语义符号借鉴子CC++。如果你是一个C程序员,你应该对下面的结构感到熟悉forwhile循环类似的构造;流程控制关键词如breakcontinueswitch语言;条件操作符如==, <, and >;二元操作符a ? b : c等等。这些都可以在GLSL着色器中使用

GLSLjichu的数据类型是有符号和无符号整型和浮点数,通过 int, uint, and float表示。双精度浮点数一刻通过double来声明。在GLSL内部,它们没有预定义的位宽,和C类似。GLSL没有stdint这个类似物,所以不支持定义任意位宽的变量,即使GLSLSPIR-V规范提供了Vulkan所用变量的数值范围和精度的最小保障。然而,位宽和布局只被定义来从内存中读取或写入。整型在内存中以二进制补码的形式存储,浮点数尽量遵循IEEE标准,除了精度要求上的小差别,来处理反常和不是数字(NaN)的值等等。

除了基本标量整型和浮点类型,GLSL内置最多四个成员的向量和4×4的矩阵作为第一等公民。可以声明基本类型(有符号、无符号整型和浮点类型标量)的向量和矩阵。Vec2vec3vec4类型,比如,是二元、三元和四元浮点类型的向量。整型向量可用i或者u作为前缀以表示有符号和无符号。故,ivec4是一个四元有符号整型向量,uvec4是四元无符号整型向量。d前缀用来表示双精度浮点类型。故,dvec4是四元双精度浮点类型的向量。

矩阵用matN或者matNxM这样的形式书写,各代表N x N方阵和N x M矩阵。d前锥也可以和矩阵类型一起使用表示双精度矩阵。因此,dmat44 x 4的双精度浮点方阵类型。然而,并没有整型的矩阵。矩阵被认为是列矩阵,可以被当作向量的数组。故,mmat4

m[3]表示一个四元素的浮点向量(vec4),它是m最后一列。

Boolean 类型也是GLSL的第一等公民,可以形成向量(但并不能形成矩阵),和浮点、整型变量一样。Boolean变量使用bool类型来声明。对向量的的关系运算产生Boolean类型数组,每一个元素都代表一个比较的结果。内置函数any()all()被用来判断数组中是否有一个为true和是否所有的元素都是true

系统产生的数据通过内置的变量传递给GLSL着色器。比如gl_FragCoord, gl_VertexIndex等变量,它们每一个都将在本书相关的章节讲到。内置变量一般拥有特殊的语义,对它们的读写会改变着色器程序的行为。

用户自定义数据通常通过内存传递给着色器。变量可以被绑定在一个block里,然后绑定到设备可访问的资源,存在在程序可以读写的内存里。这允许你向着色器程序传递大量的数据。针对小但频繁更新的数据,“push constants”这种特殊类型的变量我们在本书稍后讲解。

GLSL提供了大量的内置函数。然而,和C语言相比,GLSL并没有头文件。所以并不必须要使用#include 宏。GLSL的标准库已经内置到编译器里面了。它包括了很多数学函数,纹理访问函数,和一些特殊的流程控制函数--它们可以控制设备上着色器程序的执行。

 

 

 

 

 

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值