cg profiles,什麼是profiles,以及如何使用CGC編譯Cg語言
計算機只能理解和執行由0、1序列(電壓序列)構成的機器語言,所以組合語言 和高階語言程式都需要進行翻譯才能被計算機所理解,擔負這一任務的程式稱為語言處理程式,通常也被稱為編譯程式。例如C或者C++ 編寫的程式,需要首先編譯成可執行檔案(.exe檔案),然後才能在GPU上執行,且一旦編譯後,除非改變程式程式碼,否則不需要重新編譯,這種方式稱為靜 態編譯(static coompilation)。靜態編譯最重要的特徵是:一旦編譯為可執行檔案,在可執行檔案執行期間不再需要原始碼資訊。而動態編譯(dynamic compilation)與之相反,編譯程式和原始碼都要參與到程式的執行過程中。
Cg語言通常採用動態編譯的方式,即,在宿主程式執行時利用Cg執行庫( Cg Runtime library)動態編譯Cg程式碼,使用動態編譯的方式,可以將Cg程式當作一個指令碼,隨時修改隨時執行,節省大量的時間,在OGRE圖形引擎中就是採用 這樣的方法。在文獻[2]的1.4.2章節中提到Cg語言同樣支援靜態編譯方式,即,Cg原始碼編譯成彙編程式碼後,這部分目的碼被連結到宿主程式最後的可 執行程式中。使用靜態編譯的好處是隻要釋出可執行檔案即可,原始碼不會被公開。
Cg編譯器首先將Cg程式翻譯成可被圖形API(OpenGL和Direct3D)所接受的形式,然後應用程式使用適當的OpenGL和Direct3D 命令將翻譯後的Cg程式傳遞給圖形處理器,OpenGL和Direct3D驅動程式最後把它翻譯成圖形處理器所需要的硬體可執行格式。NVIDIA提供的 Cg編譯器為cgc.exe。
Cg程式的編譯不但依賴於宿主程式所使用的三維程式設計介面,而且依賴於圖形硬體環境,因為圖形硬體自身的限制,不一定支援某種Cg語句,例如,如果你所使用 的GPU並不支援迴圈控制指令,那麼在Cg程式中編寫的迴圈控制語句將無法通過編譯。被特定的圖形硬體環境或AIP所支援的Cg語言子集,被稱為Cg Profiles。需要注意的是: profile分為頂點程式的profile和片段程式的profile,這是因為頂點著色器和片段著色器原本就不是工作在同一個硬體。
Cg Profiles是Cg語言的重要組成部分,在使用Cg語言編寫著色程式時,首先要考慮的一點就是“當前的圖形硬體環境支援那個Cg Profile”,這直接關係到您所編寫的著色程式是否可以在當前的圖形硬體上執行。
4.3.1 CGC編譯命令
如果Cg Toolkit安裝正確,在NVIDIA Corporation/Cg/bin資料夾下會看到cgc.exe檔案。首先開啟命令列視窗,輸入“cgc –h”(引號不用輸入),如果安裝正確,則會出現圖 12所示的提示資訊。
Cg程式編譯的命令形式為:
cgc [options] file
[options]表示可選配置項,file表示Cg程式檔名。可選配置項包括編譯時選擇使用的profile、著色程式的入口函式名稱,以及著色程式檔名。比較典型的編譯方式是:
cgc –profile glslv –entry main_v test.cg
-profile是profile配置項名;glslv是當前所使用的profile名稱;-entry著色程式的入口函式名稱配置項;main_v是頂 點著色程式的入口函式名;test.cg是當前的著色程式檔名。編譯器指定的著色程式入口函式名預設為main,通常為了將頂點/片段著色程式入口函式 名區別開來,而並不使用預設名稱。在下面所有的例子中,main_v表示頂點著色程式入口函式名,main_f表示片段著色程式入口函式名。
需要強調如下幾點:
1. 著色程式分為頂點著色程式和片段著色程式,profile也分為頂點profile和片段profile,所以編譯頂點著色程式時必須選用當前圖形硬體支 持的頂點profile,同理,編譯片段著色程式時必須選用當前圖形硬體支援的片段profile。下面所示使用片段profile fp20編譯頂點著色程式是不對的。
cgc –profile fp20 glslv –entry main_v test.cg
所以,如果您的著色程式中同時存在頂點著色程式和片段著色程式,在編譯前切記分別選擇各自的profile。
2. 選擇profile 如果不被當前圖形硬體所支援,編譯時會出現錯誤。被編譯的著色程式中,如果存在不被所選擇的profile所支援的語句,則編譯時會出現錯誤。例 如,tex2D(sampler2D tex , float3 sz ,float2 dsdx , float2 dsdy )不被fp20所支援,如果你的編譯形式為:
cgc –profile fp20 –entry main_f test.cg
則會出現錯誤提示資訊:
error C3004: function “tex2D” not supported in this profile。
改用fp30,進行編譯就會通過。
cgc –profile fp30 –entry main_f test.cg
尤其需要注意的是,迴圈語句for,while只被vs_2_x, vp30, vp40,fp40等少量的profiles所支援。在CgUsersManual中提到:
“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迴圈只有當確切的知道迴圈次數時才能被使用”。但經過試驗,通常在其他profiles編譯含義for,while語句時會出現錯誤提示資訊:
error c6003:instruction limit of exceeded……
因此,如果沒有確切的把握,不要在低階的profiles中使用迴圈控制語句。
3. 被編譯的著色程式檔名必須加上.cg字尾。如果沒有加字尾,寫成如下的形式:
cgc –profile glslv –entry main_v test
則會出現錯誤提示資訊:fatal error C9999: Can’t open file:test
4. 另外cgc還提供一種比較特殊的功能:就是將Cg語言所寫的著色程式轉換為使用GLSL或HLSL所編寫的程式。例如,將程式碼寫成如下形式,表示編譯檔案 test.cg中的頂點著色程式,入口函式名為main_v,並將頂點著色程式轉換為glsl程式,然後儲存成檔案direct.glsl。
cgc –profile glslv –o direct.glsl –entry main_v test.cg
5. 還有一個非常隱蔽的編譯情況是:如果著色程式中的某些變數並沒有為最終的輸出做出貢獻,則編譯時會將該部分程式碼忽略(會檢查語法錯誤,但並不編譯成彙編代 碼)。通常這一點不會造成太大的影響,但是如果這些變數剛好是從外部宿主程式中傳入的變數,並且在著色程式中沒有被使用,則宿主程式傳入變數的介面函式可 能會報錯“找不到該變數”。這種情況比較少遇到,但並非不存在,且一旦遇上問題的原因難以查明,故而我在此寫上,希望可以有所幫助。
基於GPU程式設計,最令人崩潰的一點是:無法跟蹤除錯著色程式!這一點目前還沒有解決方案出現。對於一個著色程式,語法錯誤可以通過編譯器發現,而程式碼邏輯 錯誤只能是人為查詢。常會遇到這種情況,一段程式碼編譯通過,但是執行結果不在預期之中,如果是C++/JAVA程式就可以進行跟蹤除錯,但是著色程式不能 被除錯,只能一行程式碼一行程式碼的進行邏輯分析。
所以,編譯著色程式要非常注意邏輯的嚴密性,和程式碼的組織結構,這是為了更加容易的暴露錯誤和維護程式碼。一個良好的習慣是加入註釋語句。
4.4 CG Profiles
Profile在英文中的意思是“側面、輪廓”, 文獻[1]第三頁寫到:A Cg profile defines a subset of the full Cg language that is supported on a particular hardware platform or API(CgUsersManual 21頁)。
即一個Cg profile定義了一個“被特定圖形硬體或API所支援的Cg語言子集”,從前面的分析我們可以知道,任意一種shader language都是基於可程式設計圖形硬體的(暫存器、指令集等),這也就意味著:不同的圖形硬體對應著不同的功能子集。Profile按照功能可以劃分為 頂點Profile和片斷Profile,而頂點profile和片段profile又基於OpenGL和DirectX的不同版本或擴充套件,劃分為各種版 本。從某種意義上而言,OpenGL和DirectX的發展歷程成就了Cg語言。
當前Cg compiler所支援的profiles有:
OpenGL ARB vertex programs
Runtime profile: CG_PROFILE_ARBVP1
Compiler option: _profile arbvp1
OpenGL ARB fragment programs
Runtime profile: CG_PROFILE_ARBFP1
Compiler option: _profile arbfp1
OpenGL NV40 vertex programs
Runtime profile: CG_PROFILE_VP40
Compiler option: _profile vp40
OpenGL NV40 fragment programs
Runtime profile: CG_PROFILE_FP40
Compiler option: _profile fp40
OpenGL NV30 vertex programs
Runtime profile: CG_PROFILE_VP30
Compiler option: _profile vp30
OpenGL NV30 fragment programs
Runtime profile: CG_PROFILE_FP30
Compiler option: _profile fp30
OpenGL NV2X vertex programs
Runtime profile: CG_PROFILE_VP20
Compiler option: _profile vp20
OpenGL NV2X fragment programs
Runtime profile: CG_PROFILE_FP20
Compiler option: _profile fp20
DirectX 9 vertex shaders
Runtime profiles: CG_PROFILE_VS_2_X
CG_PROFILE_VS_2_0
Compiler options:-profile vs_2_x
-profile vs_2_0
DirectX 9 pixel shaders
Runtime profiles: CG_PROFILE_PS_2_X
CG_PROFILE_PS_2_0
Compiler options: -profile ps_2_x
-profile ps_2_0
DirectX 8 vertex shaders
Runtime profiles: CG_PROFILE_VS_1_1
Compiler options:-profile vs_1_1
DirectX 8 pixel shaders
Runtime profiles: CG_PROFILE_PS_1_3
CG_PROFILE_PS_1_2
CG_PROFILE_PS_1_1
Compiler options: -profile ps_1_3
-profile ps_1_2
-profile ps_1_2
-profile ps_1_1
附:截止到2009年10月,出現的profile已經不止上面這些種類了,尤其是現在DirectX已經出到了11的版本。上面的profile是可以在當前大多數機器上使用的。