摘抄“GPU Programming And Cg Language Primer 1rd Edition” 中文名“GPU编程与CG语言之阳春白雪下里巴人” express
在上一章中,咱们已经介绍了 Cg 语言的基础数据类型( 7 种)、内置数据类型,以及数组、结构、接口等类型,本章将在此基础上讨论 Cg 中的表达式,表达式由操做符( operator )关联一个或多个操做数( operand )构成,咱们首先阐述各类类型的操做符,并结合数据类型讲解操做符的具体使用方法。编程
Cg 中的操做符与 C 语言中的相似(操做符的功能和写法与 C 相同,但用法不尽相同),按照操做符的功能能够划分为:关系操做符、逻辑操做符、条件操做符。 Cg 中有一类较为独特的操做符,称为 Swizzle 操做符, 这个操做符用于取出向量类型变量中的份量。此外,与 C 语言不一样的是, Cg 容许在向量类型变量上使用操做符,例如 > 操做符能够用来比较两个向量各个份量的大小关系。 Cg 中的表达式还有不少与 C 语言不一样的细节之处,将在本章中一一分说。数组
6.1 关系操做符( Comparison Operators )函数
关系操做符,用于比较同类型数据(不一样类型的基础数据须要进行类型转换,不一样长度的向量,不能进行比较)之间的大小关系或者等价关系。 Cg 中有 6 种关系操做符,如 表 1 所示 , 关系操做符运算后的返回类型均为 bool 类型。oop
关系操做符性能
|
功能测试 |
用法ui |
< spa |
小于教程 |
expr < expr |
<= |
小于或等于 |
expr <= expr |
!= |
不等于 |
expr != expr |
==
|
等于 |
expr == expr |
>= |
大于或等于 |
expr >= expr |
> |
大于 |
expr > expr |
表 1 关系操做符
在 Cg 中,因为关系操做符以及下节会讲到的逻辑操做符,都返回 bool 类型结果,因此这两种操做符有时也被统一称为 boolean operator 。
Cg 语言表达式容许对向量使用全部的 boolean operator ,若是是二元操做符,则被操做的两个向量的长度必须一致。表达式中向量的每一个份量都进行一对一的运算,最后返回的结果是一个 bool 类型的向量,长度和操做数向量一致。例如:
float3 a = float4(0.5, 0.0, 1.0);
float3 b = float4(0.6, -0.1, 0.9);
bool3 c = a<b;
运算后向量 c 的结果为 float3(true, false, true);
6.2 逻辑操做符( Logical Operators )
Cg 语言中有 3 种逻辑操做符 ( 也被称为 boolean Operators) ,如 表 2 所示,逻辑操做符运算后的返回类型均为 bool 类型。
逻辑操做符
|
功能 |
用法 |
&& |
逻辑与 |
expr && expr |
|| |
逻辑或 |
expr || expr |
! |
逻辑非 |
!expr |
表 2 逻辑操做符
正如上节所说,逻辑操做符也能够对向量使用,返回的变量类型是一样长度的内置 bool 向量。
有一点须要注意: Cg 中的逻辑与( && )和逻辑或( || )不存在 C 中的短路现象( short-circuiting ,即只用计算一个操做数的 bool 值便可),而是参与运算的操做数据都进行 bool 分析。
6.3 数学操做符( Math Operators )
Cg 语言对向量的数学操做提供了内置的支持, Cg 中的数学操做符有: * 乘法; / 除法; - 取反; + 加法;—减法; % 求余; ++ ;——; *= ; /= ; += ; -= ;后面四种运算符有时被概括入赋值操做符,不过它们实际上进行数学计算,而后进行赋值,因此这里也放入数学操做符中进行说明。
在文献【 2 】第 3.3 节 Math Expressions 中,其行文意思容易让人以为“好像只有加减乘除等运算能够对向量进行”,实际上通过个人测试, ++ 、——等数学运算符一样可使用在向量上。因此“ Cg 语言对向量的数学操做提供内置支持”这句话是很是准确的。
须要注意的是:求余操做符 % 。只能在 int 类型数据间进行,不然编译器会提示错误信息: error C1021: operands to “ % ” must be integral.
当使用这些数学操做符对一个标量和一个向量进行运算时,标量首先被复制到一个长度相同的向量中,而后进行运算,例以下面的代码形式是正确的:
void function()
{
float2 a = float2(1.0, 1.0);
float b = 2.0;
f *= d;
f *= 2.0;
}
6.4 移位操做符
Cg 语言中的移位操做符,功能和 C 语言中的同样,也能够做用在向量上,可是向量类型必须是 int 类型。例如:
int2 a = int2(0.0,0.0);
int2 b = a>>1;
若是使用以下代码,会出现错误提示信息: error C1021:operands to “ shr ” must be integral.
float2 a = int2(0.0,0.0);
float2 b = a>>1;
6.5 Swizzle 操做符
可使用 Cg 语言中的 swizzle 操做符( . )将一个向量的成员取出组成一个新的向量。 swizzle 操做符被 GPU 硬件高效支持。 swizzle 操做符后接 x 、 y 、 z 、 w ,分别表示原始向量的第一个、第二个、第三个、第四个元素; swizzle 操做符后接 r 、 g 、 b 和 a 的含义与前者等同。不过为了程序的易读性,建议对于表示颜色值的向量,使用 swizzle 操做符后接 r 、 g 、 b 和 a 的方式。
举例以下:
float4(a, b, c, d).xyz 等价于 float3(a, b, c)
float4(a, b, c, d).xyy 等价于 float3(a, b, b)
float4(a, b, c, d).wzyx 等价于 float4(d, c, b, a)
float4(a, b, c, d).w 等价于 float d
值得注意的是, Cg 语言中 float a 和 float1 a 是基本等价的,二者能够进行类型转换; float 、 bool 、 half 等基本类型声明的变量也可使用 swizzle 操做符。例如:
float a = 1.0;
float4 b = a.xxxx;
注意: swizzle 操做符只能对结构体和向量使用,不能对数组使用,若是对数组使用 swizzle 操做符则会出现错误信息: error C1010: expression left of . ” x ” is not a struct or array (其实我的以为,提示的错误信息中 array 换成 vector 更加合适)。
要从数组中取值必须使用 [] 符号。例如:
float a[3] = {1.0,1.0,0.0};
float b = a[0]; // 正确
float c = a.x; // 编译会提示错误信息
6.6 条件操做符( Conditional Operators )
条件操做符的语法格式为:
expr1 ? expr2 : expr3;
expr1 的计算结果为 true 或者 flase ,若是是 true, 则 expr2 执行运算,不然 expr3 被计算。
条件操做符为简单的 if-else 语句提供了一种便利的替代方式,例如咱们能够没必要写:
if(a < 0){b = a}
else{c = a}
而改写为:
( a < 0 ) ?(b = a) :( c = a);
Cg 中的条件操做符一个独特的性能是:支持向量运算。即, expr1 的计算结果能够是 bool 型向量, expr2 和 expr3 必须是与 expr1 长度相同的向量。举例以下:
float3 h = float3(-1.0,1.0,1.0);
float3 i = float3(1.0,0.0,0.0);
float3 g = float3(1.0,1.0,0.0);
float3 k;
k = (h < float3(0.0,0.0,0.0))?(i):(g);
三元向量 h 与 float3(0.0, 0.0, 0.0) 作比较运算后结果为( true, false, false ) , 因此 i 的第一个数据赋值给 K 的第一个数据, g 的第二个和第三个数据赋值给 k 的第二个和第三个数据, K 的值为 (1.0, 1.0, 0.0) 。
6.7 操做符优先顺序
Cg 语言中操做符的优先顺序如 表 3 所示,从上到下表示从高级到低级的优先级;同一行的操做符具备同等优先级。该表参考了 Cg 教程 _ 可编程实时图形权威指南第 3.3.1 节。
操做符
|
结合律 |
功能 |
() [] -> . |
从左到右 |
函数调用、数组引用、结构引用、成员选择 |
! ~ ++ - + - * & (type) sizeof |
从右到左 |
一元操做符:取反、增长、减小、正号、负号、间接、地址、转换 |
* / % |
从左到右 |
乘法、除法、余数 |
+ - |
从左到右 |
加法、减法 |
<< >> |
从左到右 |
移位操做符 |
< >= > >= |
从左到右 |
关系操做符 |
== != |
从左到右 |
等于,不等 |
& |
从左到右 |
位操做符与 |
^ |
从左到右 |
位操做符异或 |
| |
从左到右 |
位操做符或 |
&& |
从左到右 |
逻辑与 |
|| |
从左到右 |
逻辑或 |
?: |
从右到左 |
条件表达式 |
= += -= *= /= %= &= ^= != <<= >>= |
从右到左 |
赋值、赋值表达式 |
, |
从左到右 |
逗号操做符 |
表 3 操做符优先级
6.8 控制流语句( Control Flow Statement )
程序最小的独立单元是语句( statement ),语句通常由分号结尾,缺省状况下,语句是顺序执行的,可是当涉及逻辑判断控制时,就要求有控制流程序语句。控制流程序语句分为条件语句和循环语句,在 C 语言中,条件语句有 if 、 if-else 、 switch 等,而循环过程则由 while 、 do-while 和 for 语句支持。 Cg 中的控制流语句和循环语句与 C 语言相似:条件语句有: if 、 if-else ;循环语句有: while 、 for 。 break 语句能够和在 for 语句中使用。
Cg 语言中的控制流语句要求其中的条件表达式返回值都是 bool 类型,这一点是与 C 语言不一样之处( C 语言中,条件表达式返回值能够是 0 、 1 )
vs_2_x, vp30 和 vp40 这些 profile 支持分支指令(又称转移指令, branch instruction ), for 和 while 循环指令在这些 profile 中被彻底支持。在文献【 3 】中提到:
“ In other profiles, for and while loops may only be used if the compiler can fully unroll them (that is, if the compiler can determine the iteration count at compile time) ”。
这句话的意思是“在其余的 profiles 中, for 和 while 循环只有当确切的知道循环次数时才能被使用”。但通过试验,若是使用“在 fp40 和 ps_3_0 以前的” 片断 profiles 编译含义 for, while 语句时会出现错误提示信息: error c6003 : instruction limit of exceeded …… 。所以,若是没有确切的把握,不要在低级的 profiles 中使用循环控制语句。
一样, return 只能做为最后一条语句出现。函数的递归调用( recursion )在 Cg 语言中是被禁止的。 Switch 、 case 和 default 在 Cg 中做为保留关键字存在,可是它们目前不被任何 profile 所支持。