在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
摘抄“GPU Programming And Cg Language Primer 1rd Edition” 中文名“GPU编程与CG语言之阳春白雪下里巴人”
在上一章中,我们已经介绍了 Cg 语言的基础数据类型( 7 种)、内置数据类型,以及数组、结构、接口等类型,本章将在此基础上讨论 Cg 中的表达式,表达式由操作符( operator )关联一个或多个操作数( operand )构成,我们首先阐述各种类型的操作符,并结合数据类型讲解操作符的具体使用方法。 Cg 中的操作符与 C 语言中的类似(操作符的功能和写法与 C 相同,但用法不尽相同),按照操作符的功能可以划分为:关系操作符、逻辑操作符、条件操作符。 Cg 中有一类较为独特的操作符,称为 Swizzle 操作符, 这个操作符用于取出向量类型变量中的分量。此外,与 C 语言不同的是, Cg 允许在向量类型变量上使用操作符,例如 > 操作符可以用来比较两个向量各个分量的大小关系。 Cg 中的表达式还有很多与 C 语言不同的细节之处,将在本章中一一分说。 6.1 关系操作符( Comparison Operators ) 关系操作符,用于比较同类型数据(不同类型的基础数据需要进行类型转换,不同长度的向量,不能进行比较)之间的大小关系或者等价关系。 Cg 中有 6 种关系操作符,如 表 1 所示 , 关系操作符运算后的返回类型均为 bool 类型。
表 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 类型。
表 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 节。
表 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 所支持。 |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论