摘抄「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 所支持。