OpenGL顯卡編程
OpenGL顯卡編程 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
文檔簡述:
隨著顯卡的飛速發展,更快的速度以及越來越多的新功能為硬件所支持,硬件的進步使得圖形程序開發人員可以創造出更加絢麗的視覺效果,現在,電影級動畫的實時渲染已不再是夢想。我們怎么在OpenGL中利用顯卡的新特性呢?答案就是OpenGL擴展。 注:如不作特別說明,本站文章中的顯卡均指面向普通用戶的非專業顯卡。 文檔目錄: OpenGL擴展 顯卡差異 頂點/片斷編程 Cg/RenderMonkey/及其他 文檔內容: OpenGL 擴展 (OpenGL Extensions)OpenGL和Direct3D比較起來,最大的一個長處就是其擴展機制。硬件廠商開發出一個新功能,可以針對新功能開發OpenGL擴展,軟件開發人員通過這個擴展就可以使用新的硬件功能。所以雖然顯卡的發展速度比OpenGL版本更新速度快得多,但程序員仍然可以通過OpenGL使用最新的硬件功能。而Direct3D則沒有擴展機制,硬件的新功能要等到微軟發布新版DirectX后才可能支持。 OpenGL擴展也不是沒有缺點,正因為各個硬件廠商都可以開發自己的擴展,所以擴展的數目比較大,而且有點混亂,有些擴展實現的相同的功能,可因為是不同廠商開發的,接口卻不一樣,所以程序中為了實現這個功能,往往要為不同的顯卡寫不同的程序。這個問題在OpenGL 2.0出來后可能會得到解決,OpenGL 2.0的一個目標就是統一擴展,減少擴展數目。
擴展名
?????????????????????? GL_ARB_multitexture 第一段GL,用來表示針對OpenGL哪部分開發的擴展,有以下幾個值:
第二段ARB,用來表示是誰開發的這個擴展,常見以下幾個值:
第三段multitexture就是真正的擴展名了,如multitexture就是多重紋理擴展。 ? 使用OpenGL擴展
要使用一個OpenGL擴展,首先必須檢查顯卡是否支持這個擴展,以下代碼可以獲取一個顯卡支持的的OpenGL擴展: ??? "GL_ARB_imaging GL_ARB_multitexture GL_ARB_point_parameters …… " ???? OpenGL擴展往往都會新增一些函數,在Windows平臺上,這些函數不是通過.lib庫連接到程序里的,而要在運行時動態獲得函數的指針。我們以GL_ARB_point_parameters擴展為例看看怎么獲得函數指針。 ?? 首先要定義函數指針類型,
???
typedef void (APIENTRY * PFNGLPOINTPARAMETERFARBPROC)(GLenum pname, GLfloat param);
這個工作SGI已經為我們做好,它提供了一個頭文件 glext.h,里面有目前絕大多數擴展的常量和函數指針定義,下載下來放到編譯器的include/GL文件夾下面,然后在程序里面加上: ??? #include <GL/glext.h>就可以在程序中使用常量和函數指針類型了。 ?? 然后要定義函數指針: ??? PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB;??? PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB;
?? ??? int hasPointParams = isExtensionSupported("GL_ARB_point_parameters");
如果支持,就可以用
wglGetProcAddress
函數獲取擴展函數的指針:
??? { ??? if (hasPointParams)
??? {
WGL擴展glGetString( GL_EXTENSIONS )取得的擴展字符串中并不包括針對Windows平臺的WGL擴展,WGL擴展串要通過WGL_ARB_extensions_string擴展來獲得,以下代碼演示了如何獲得WGL擴展串: ??? 定義WGL_ARB_extensions_string擴展新增函數wglGetExtensionsStringARB的函數指針類型,同樣這個工作SGI已經為我們做好,只不過不在glext.h中,而在它提供的另外一個頭文件 wglext.h 中: ??? typedef const char *(APIENTRY * PFNWGLGETEXTENSIONSSTRINGARBPROC)( HDC hdc);
定義函數指針: ??? PFNWGLGETEXTENSIONSSTRINGARBPROC wglGetExtensionsStringARB;
檢查是否支持WGL_ARB_extensions_string擴展,如果不支持,表示這個顯卡不支持WGL擴展,如果支持,則得到wglGetExtensionsStringARB函數的指針,并調用它得到WGL擴展串: ??? int hasWGLext = isExtensionSupported("WGL_ARB_extensions_string"); ??? if (hasWGLext) ??? { ??????? wglGetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) \ wglGetProcAddress( "wglGetExtensionsStringARB" ); ??????? const char *wglExt = wglGetExtensionsStringARB( hdc ); ??????? …… ??? } ??? OpenGL版本一些常用的OpenGL擴展會在新版的OpenGL中加到OpenGL核心中去,成為OpenGL標準的一部分,可以簡化程序開發,程序員使用這些功能時不必做繁瑣的擴展初始化工作。比如多重紋理功能,在OpenGL1.2.1加入到OpenGL核心中,以前要使用多重紋理,要先檢查是否支持GL_ARB_multitexture擴展,然后初始化glActiveTextureARB等函數,很麻煩,而OpenGL1.2后,則可以直接使用glActiveTexture函數。 不過,這種簡化只有Mac/Unix/Linux程序員才能享受到,在Windows平臺上沒有這么簡單。微軟為了維護Direct3D,對OpenGL的支持很消極,其OpenGL實現仍然是1.1。由于Windows上的OpenGL程序最終都會動態鏈接到微軟的OpenGL32.dll,可OpenGL32.dll只支持OpenGL 1.1,使我們不能直接使用新版OpenGL,仍然要用擴展訪問OpenGL1.1以來新增的功能。 ?? OpenGL擴展資料
? All About OpenGL Extensions :
? OpenGL Extension Registry :
? OpenGL Hardware Registry: ??
|
?nVIDIA |
?ATI |
|||
?芯片代號 | 顯卡型號 | ?芯片代號 | 顯卡型號 | |
?NV1 ?NV2 ?NV3 ?NV4? ?NV5? |
NV1 Riva 128 Riva 128ZX Riva TnT Riva TnT2 |
?RAGE(?) |
RAGE PRO RAGE 128 RAGE 128 PRO |
|
?NV10? ?NV11? ?NV15? ?NV17? ?NV18? |
GeForce 256 GeForce2 MX * GeForce2 * GeForce4 MX * GeForce4 MX AGP8X * |
?R100? ?RV200 |
RADEON 7000 RADEON RADEON 7200 RADEON 7500 |
|
?NV20? ?NV25? ?NV28? |
Geforce3 Ti200 GeForce3 GeForce3 Ti500 GeForce4 Ti * GeForce4 Ti AGP 8X * |
?RV250? ?R200? ?RV280? |
RADEON 9000 RADEON 8500 RADEON 9100 RADEON 9200 AGP 8X |
|
?NV34? ?NV31? ?NV30? ?NV35? |
GeForce FX 5200 GeForce FX 5600 GeForce FX 5800 GeForce FX 5900 |
?RV300? ?RV350? ?R300? ?R350? |
RADEON 9500 RADEON 9600 RADEON 9700 RADEON 9800 |
·其中標注 * 的是產品系列,型號還會細分
·通常大家習慣用芯片代號的主版本號來統稱一代芯片,例如用NV20統稱NV20/NV25/NV28,用R200統稱RV250/R200/RV280
·雖然ATI RADEON 7500的芯片型號是RV200,但實際屬于R100檔次的產品
??
我們來看一個執行路徑的例子,idSoftware即將推出的Doom3的執行路徑。
Doom3一共有6條執行路徑:
-
ARB:幾乎不使用擴展,沒有鏡面高光效果,沒有頂點編程(vertex program),保證程序能在低端顯卡上運行
-
NV10:支持所有功能,每幀需要渲染5個pass(five rendering passes,指一個對象多次送入渲染管道,比如第一次渲染漫射光diffuse,第二次渲染鏡面高光specular ……,各次渲染結果通過glBlend混合在一起形成最終效果),沒有頂點編程
-
NV20:支持所有功能,2或3個pass
-
NV30:支持所有功能,1個pass
-
R200:支持所有功能,大部分情況下只需1個pass
-
ARB2:支持所有功能,浮點片斷編程(fragment program),1個pass
nVIDIA顯卡可能執行ARB / NV10 / NV20 / NV30 / ARB2 五條路徑,其中NV10 / NV20 / NV30 專門針對不同檔次的nVIDIA顯卡開發的。
ATI顯卡可能執行 ARB / R200 / ARB2 三條路徑,其中R200是專門針對ATI開發的。
而其他顯卡則根據檔次高低執行ARB或ARB2路徑。ARB用于低端顯卡,ARB2用于高端顯卡。
頂點/片斷編程
1999年底,nVIDIA推出GeForce 256,并開始使用GPU(Graphics Processing Unit)來稱呼顯卡芯片(也有廠商叫VPU(Visual Processing Unit),是一回事)。GeForce 256最大賣點是硬件T&L(Transform&Lighting,變換和光照),這意味著變換和光照計算可以在GPU中進行,大大減輕了CPU的壓力,顯卡開始成為獨立于CPU的一個處理器。
硬件T&L后,GPU最激動人心的進步就是引入了可編程能力。我們知道,OpenGL和Direct3D都有固定的渲染管線,定義光源,送入頂點位置、法線、紋理坐標等,就可以給你渲染出一幅圖像來,程序員對具體的渲染過程無法控制。而OpenGL擴展和DirectX8給渲染管線引入可編程能力,圖形軟件開發人員可以編寫運行于顯卡芯片的匯編程序來控制具體的渲染過程,這給予圖形軟件開發更大的靈活性,并且由于硬件的支持,獲得這些靈活性并不會犧牲性能。GPU的可編程能力對實時圖形渲染會產生深遠的影響。
?
OpenGL支持兩種可編程模型:
-
頂點編程Vertex Program,對應于Direct3D中的Vertex Shader,提供可編程的T&L能力,代替了傳統渲染流水線中的T&L,處理頂點的變換、光照計算
-
片斷編程Fragment Program,對應于Direct3D的Pixel Shader,提供可編程的光柵化操作,代替了傳統流水線中的紋理映射、逐像素顏色及霧效處理
目前頂點編程相關的擴展有:
-
GL_NV_vertex_program :nVIDIA NV10檔次顯卡用軟件模擬,NV20及以上檔次顯卡上硬件支持
-
GL_NV_vertex_program1_1 :nVIDIA NV10檔次顯卡用軟件模擬,NV20及以上檔次顯卡上硬件支持
-
GL_EXT_vertex_shader :在ATI R200及以上檔次顯卡上支持
-
GL_ARB_vertex_program :由上面三個擴展發展而來,支持上面三個擴展的顯卡安裝最新的驅動程序后都會支持此擴展,所以程序中不必支持上面三個擴展,只支持此擴展就可以了。此擴展不支持分支循環
-
GL_NV_vertex_program2 :在nVIDIA NV30及以上檔次顯卡上支持,支持分支循環,估計會成為GL_ARB_vertex_program2擴展的原型
-
實際上ATI R300級別的顯卡已經在頂點編程中支持分支循環(硬件支持DirectX9的vs2.0),但并沒有開發擴展提供給OpenGL程序員使用,估計是在等支持分支循環的GL_ARB_vertex_program2擴展出臺
可見現在使用OpenGL的vertex program,只需支持GL_ARB_vertex_program和GL_NV_vertex_program2兩個擴展。
?
目前片斷編程相關的擴展有:
-
GL_NV_register_combiners :在nVIDIA NV10及以上檔次顯卡上支持,處理逐像素顏色及霧效計算
-
GL_NV_register_combiners2 :在nVIDIA NV20及以上檔次顯卡上支持,對GL_NV_register_combiners作了個簡單的擴展,支持兩個常量寄存器在每級combiner都可以有不同的值
-
GL_NV_texture_shader / GL_NV_texture_shader2 / GL_NV_texture_shader3:在nVIDIA NV20及以上檔次顯卡上支持,提供多種功能強大的紋理提取操作
-
GL_ATI_fragment_shader :在ATI R200及以上檔次顯卡上支持
以上擴展提供的功能不是編寫運行于GPU的匯編碼,而是通過函數調用的方式實現,不如編寫匯編碼直觀方便。下面幾個擴展則可以通過編寫匯編碼來實現片斷編程
-
GL_ATI_text_fragment_shader :實際上就是GL_ATI_fragment_shader的匯編碼版本,到現在還沒看到在PC上的支持信息,看來只會在蘋果機上支持
-
GL_ARB_fragment_program :在nVIDIA NV30 / ATI R300及以上檔次顯卡上支持
-
GL_NV_fragment_program :在nVIDIA NV30及以上檔次顯卡上支持,比GL_ARB_fragment_program更強大
與頂點編程相比,片斷編程要復雜得多:
-
在NV10系列上,只能使用GL_NV_register_combiners提供的部分片斷編程能力
-
在NV20系列上,則可以使用register combiners和texture shader實現片斷編程
-
在NV30系列上,可以使用GL_ARB_fragment_program和GL_NV_fragment_program
-
在ATI R200系列上,使用GL_ATI_fragment_shader
-
在ATI R300系列上,使用GL_ARB_fragment_program
看到這里我們不難理解為什么Doom3會將渲染執行路徑分成ARB、NV10、NV20、NV30、R200、ARB2幾條了:
-
ARB既沒有頂點編程也沒有片斷編程
-
NV10沒有用到頂點編程(雖然NV10支持頂點編程,但是是軟件模擬,而顯卡硬件并不支持),但用到register combiners實現凹凸貼圖(Bump Mapping)
-
NV20使用頂點編程,并用register combiners和texture shader實現片斷編程
-
NV30使用頂點編程,并用GL_NV_fragment_program實現片斷編程
-
R200使用頂點編程,并用GL_ATI_fragment_shader實現片斷編程
-
ARB2使用頂點編程,并用GL_ARB_fragment_program實現片斷編程
???
附表:
nVIDIA顯卡頂點、片斷編程支持情況
芯片代號 | 紋理單元數 | Register Combiner | Texture Shader | Vertex Program | Fragment Program |
?NVX | 2 | X | X | X | X |
?NV10 | 2 | 2 級 | X | NVvp1.1/ARBvp1.0 | RC |
?NV20 | 4 | 8 級 | 支持 | NVvp1.1/ARBvp1.0 | RC/TS |
?NV30 | 4 | 8 級 | 支持 | NVvp2.0/ARBvp1.0 | ARBfp1.0/NVfp |
?
ATI顯卡頂點、片斷編程支持情況
芯片代號 | 紋理單元數 | Vertex Program | Fragment Program |
?RAGE | 2 | X | X |
?R100 | 3 | X | X |
?R200 | 6 | EXTvp/ARBvp1.0 | ATIfp |
?R300 | 8 | EXTvp/ARBvp1.0 | ARBfp1.0 |
直接使用擴展編寫vertex program和fragment program不太方便,要么是函數調用,要么是匯編碼,相當于用x86匯編編寫PC程序,而現在已經有了面向vertex program和fragment program的高級語言,稱為HLSL(高級著色語言,High Level Shading Language)。
Cg是nVIDIA提出的一種高級著色語言,它的語法和C語言類似,可以大大簡化vertex program和fragment program的編寫。用它寫的程序可以:
-
編譯成GL_NV_vertex_program / GL_NV_vertex_program1_1 / GL_ARB_vertex_program / GL_NV_vertex_program2 的匯編碼
-
編譯成GL_ARB_fragment_program / GL_NV_fragment_program的匯編碼
-
編譯成用于nvParse的RC(Register Combiners)及TS(Texture Shader)腳本
-
直接在程序中調用Cg提供的API,運行Cg程序
-
編譯成DirectX的 vertex shader / pixel shader
我們可以看到Cg只是對nVIDIA的產品支持比較好,而其他廠商的產品只有支持GL_ARB_vertex_program/GL_ARB_fragment_program時才能從Cg獲得好處,不支持這兩個ARB擴展的顯卡則不能運行Cg編寫的程序,大大降低了Cg的實用性。雖然Cg提供接口,使其他廠商可以對Cg進行擴展,以支持各個廠商自己的OpenGL擴展,不過Cg畢竟是一個企業的產品,別的廠商不會支持,所以如果要寫通用的圖形程序,Cg并不合適。
況且OpenGL的HLSL——GLslang(OpenGL Shading Language)規范已經被ARB審核通過,估計不久就可以使用GLslang編寫vertex program和fragment program,到時Cg的位置應該會相當尷尬,因為OpenGL和DirectX都已經有了自己的HLSL。不過話說回來,Cg可以同時支持OpenGL和DirectX,這也算是它的一個優勢。
?
RenderMonkey
RenderMonkey并不是一種語言,而是ATI推出的一個編寫調試vertex program和fragment program的集成開發環境,目前只支持DirectX的vertex shader / pixel shader / HLSL,不過ATI正在和3Dlabs合作,不日RenderMonkey也會支持OpenGL vertex program / fragment program / GLslang。另外,RenderMonkey不僅僅是為程序員設計的,美工也可以使用。
nvParse
nvParse是nVIDIA公司推出的一個庫,可以簡化RC(Register Combiners)及TS(Texture Shader)的開發。使用GL_NV_register_combiners和GL_NV_texture_shader擴展實現片斷編程全是函數調用的形式,很不方便,而nVIDIA為了簡化RC和TS程序開發,建立了一種腳本格式,用簡單的腳本代替復雜的GL_NV_register_combiners和GL_NV_texture_shader函數調用,nvParse則提供API用于解釋執行RC和TS腳本。
??
模擬NV30
并非所有程序員都有一塊NV30顯卡,但nVIDIA最新的雷管驅動程序(version 40.41及以后)支持軟件模擬NV30架構,只不過很慢,但對沒有NV30顯卡的程序員已經是個福音了,只要我們有一塊GeForce級的顯卡,安裝最新的雷管驅動程序,然后下載一個NVEmulate.exe (52 KB),運行它,打開NV30模擬,你的顯卡就支持NV30的所有功能了,這樣就算沒有NV30顯卡同樣可以針對NV30開發程序。要注意的是,不需要NV30模擬的時候要記得關掉它,畢竟是軟件模擬,速度很慢。
??
后記
寫這些只是希望為后來的朋友指一個方向,寫得很簡略,因為我自己也在學習,hoho,更多的東西還是需要大家自己多看多寫 :) 我將來也會慢慢放上一些詳細的文章以及源碼,希望能對大家有所幫助。關于這篇文章的問題或建議,可以寫信給我,我的聯系方式。