兩年前收藏的貼子,現在拿來和大家一起重溫一下。
我知道這很長,但是,我堅持看完了.希望有幸看到這文章并對圖形方面有興趣的朋友,也能堅持看完.一定大有收獲.畢竟知道它們到底是怎么"私下勾搭"的.會有利于我們用程序來指揮它們....(這是我加上去的)
原文從這里開始:
要說到設計的復雜程度,那還是CPU了!這個不用討論,很簡單的道理你看看顯卡芯片的更新速度和CPU的更新速度就可見一斑了。還是簡單說說他們的設計原理吧。
CPU:
但是,現在我要問一句:“什么是CPU?”我相信大多數人并不知道什么是CPU。當然,你可以回答CPU是中央處理器,或者來一句英文: Central Processing Unit。是的,沒錯。但,RISC和CISC是什么?什么是“9路超標量設計”、“20級流水線”?什么是“解 碼”,為什么Athlon和PIII的解碼過程需要的時鐘周期大大大于其他的RISC處理器?這些都不是一句“中央處理器”所能夠回答的。
一、 指令系統
要講CPU,就必須先講一下指令系統。指令系統指的是一個CPU所能夠處理的全部指令的集合,是一個CPU的根本屬性。比如我們現在所用的CPU都是 采用x86指令集的,他們都是同一類型的CPU,不管是PIII、Athlon或Joshua。我們也知道,世界上還有比PIII和Athlon快得多的 CPU,比如Alpha,但它們不是用x86指令集,不能使用數量龐大的基于x86指令集的程序,如Windows98。之所以說指令系統是一個CPU的 根本屬性,是因為指令系統決定了一個CPU能夠運行什么樣的程序。所有采用高級語言編出的程序,都需要翻譯(編譯或解釋)成為機器語言后才能運行,這些機 器語言中所包含的就是一條條的指令。
1、 指令的格式
一條指令一般包括兩個部分:操作碼和地址碼。操作碼其實就是指令序列號,用來告訴CPU需要執行的是那一條指令。地址碼則復雜一些,主要包括源操作數地址、目的地址和下一條指令的地址。在某些指令中,地址碼可以部分或全部省略,比如一條空指令就只有操作碼而沒有地址碼。
舉個例子吧,某個指令系統的指令長度為32位,操作碼長度為8位,地址長度也為8位,且第一條指令是加,第二條指令是減。當它收到一個 “00000010000001000000000100000110”的指令時,先取出它的前8位操作碼,即00000010,分析得出這是一個減法操 作,有3個地址,分別是兩個源操作數地址和一個目的地址。于是,CPU就到內存地址00000100處取出被減數,到00000001處取出減數,送到 ALU中進行減法運算,然后把結果送到00000110處。
這只是一個相當簡單化的例子,實際情況要復雜的多。
2、 指令的分類與尋址方式
一般說來,現在的指令系統有以下幾種類型的指令:
(1)算術邏輯運算指令
算術邏輯運算指令包括加減乘除等算術運算指令,以及與或非異或等邏輯運算指令。現在的指令系統還加入了一些十進制運算指令以及字符串運算指令等。
(2)浮點運算指令
用于對浮點數進行運算。浮點運算要大大復雜于整數運算,所以CPU中一般還會有專門負責浮點運算的浮點運算單元。現在的浮點指令中一般還加入了向量指令,用于直接對矩陣進行運算,對于現在的多媒體和3D處理很有用。
(3)位操作指令
學過C的人應該都知道C語言中有一組位操作語句,相對應的,指令系統中也有一組位操作指令,如左移一位右移一位等。對于計算機內部以二進制不碼表示的數據來說,這種操作是非常簡單快捷的。
(4)其他指令
上面三種都是運算型指令,除此之外還有許多非運算的其他指令。這些指令包括:數據傳送指令、堆棧操作指令、轉移類指令、輸入輸出指令和一些比較特殊的指令,如特權指令、多處理器控制指令和等待、停機、空操作等指令。
對于指令中的地址碼,也會有許多不同的尋址(編址)方式,主要有直接尋址,間接尋址,寄存器尋址,基址尋址,變址尋址等,某些復雜的指令系統會有幾十種甚至更多的尋址方式。
3、 CISC與RISC
CISC,Complex Instruction Set Computer,復雜指令系統計算機。RISC, Reduced Instruction Set Computer,精簡指令系統計算機。雖然這兩個名詞是針對計算機的,但下文我們仍然只對指令集進行 研究。
(1)CISC的產生、發展和現狀
一開始,計算機的指令系統只有很少一些基本指令,而其他的復雜指令全靠軟件編譯時通過簡單指令的組合來實現。舉個最簡單的例子,一個a乘以b的操作就 可以轉換為a個b相加來做,這樣就用不著乘法指令了。當然,最早的指令系統就已經有乘法指令了,這是為什么呢?因為用硬件實現乘法比加法組合來得快得多。
由于那時的計算機部件相當昂貴,而且速度很慢,為了提高速度,越來越多的復雜指令被加入了指令系統中。但是,很快又有一個問題:一個指令系統的指令數是受指令操作碼的位數所限制的,如果操作碼為8位,那么指令數最多為256條(2的8次方)。
那么怎么辦呢?指令的寬度是很難增加的,聰明的設計師們又想出了一種方案:操作碼擴展。前面說過,操作碼的后面跟的是地址碼,而有些指令是用不著地址碼或只用少量的地址碼的。那么,就可以把操作碼擴展到這些位置。
舉個簡單的例子,如果一個指令系統的操作碼為2位,那么可以有00、01、10、11四條不同的指令。現在把11作為保留,把操作碼擴展到4位,那么 就可以有00、01、10、1100、1101、1110、1111七條指令。其中1100、1101、1110、1111這四條指令的地址碼必須少兩 位。
然后,為了達到操作碼擴展的先決條件:減少地址碼,設計師們又動足了腦筋,發明了各種各樣的尋址方式,如基址尋址、相對尋址等,用以最大限度的壓縮地址碼長度,為操作碼留出空間。
就這樣,慢慢地,CISC指令系統就形成了,大量的復雜指令、可變的指令長度、多種的尋址方式是CISC的特點,也是CISC的缺點:因為這些都大大 增加了解碼的難度,而在現在的高速硬件發展下,復雜指令所帶來的速度提升早已不及在解碼上浪費點的時間。除了個人PC市場還在用x86指令集外,服務器以 及更大的系統都早已不用CISC了。x86仍然存在的唯一理由就是為了兼容大量的x86平臺上的軟件。
(2)RISC的產生、發展和現狀
1975年,IBM的設計師John Cocke研究了當時的IBM370CISC系統,發現其中占總指令數僅20%的簡單指令卻在程序調用中占了80%,而占指令數80%的復雜指令卻只有20%的機會用到。由此,他提出了RISC的概念。
事實證明,RISC是成功的。80年代末,各公司的RISC CPU如雨后春筍般大量出現,占據了大量的市場。到了90年代,x86的CPU如pentium和k5也開始使用先進的RISC核心。
RISC的最大特點是指令長度固定,指令格式種類少,尋址方式種類少,大多數是簡單指令且都能在一個時鐘周期內完成,易于設計超標量與流水線,寄存器 數量多,大量操作在寄存器之間進行。由于下文所講的CPU核心大部分是講RISC核心,所以這里就不多介紹了,對于RISC核心的設計下面會詳細談到。
RISC目前正如日中天,Intel的Itanium也將最終拋棄x86而轉向RISC結構。
二、CPU內核結構
好吧,下面來看看CPU。CPU內核主要分為兩部分:運算器和控制器。
(一) 運算器
1、 算術邏輯運算單元ALU(Arithmetic and Logic Unit)
ALU主要完成對二進制數據的定點算術運算(加減乘除)、邏輯運算(與或非異或)以及移位操作。在某些CPU中還有專門用于處理移位操作的移位器。
通常ALU由兩個輸入端和一個輸出端。整數單元有時也稱為IEU(Integer Execution Unit)。我們通常所說的“CPU是XX位的”就是指ALU所能處理的數據的位數。
2、 浮點運算單元FPU(Floating Point Unit)
FPU主要負責浮點運算和高精度整數運算。有些FPU還具有向量運算的功能,另外一些則有專門的向量處理單元。
3、通用寄存器組
通用寄存器組是一組最快的存儲器,用來保存參加運算的操作數和中間結果。
在通用寄存器的設計上,RISC與CISC有著很大的不同。CISC的寄存器通常很少,主要是受了當時硬件成本所限。比如x86指令集只有8個通用寄存 器。所以,CISC的CPU執行是大多數時間是在訪問存儲器中的數據,而不是寄存器中的。這就拖慢了整個系統的速度。而RISC系統往往具有非常多的通用 寄存器,并采用了重疊寄存器窗口和寄存器堆等技術使寄存器資源得到充分的利用。
對于x86指令集只支持8個通用寄存器的缺點,Intel和AMD的最新CPU都采用了一種叫做“寄存器重命名”的技術,這種技術使x86CPU的寄 存器可以突破8個的限制,達到32個甚至更多。不過,相對于RISC來說,這種技術的寄存器操作要多出一個時鐘周期,用來對寄存器進行重命名。
4、 專用寄存器
專用寄存器通常是一些狀態寄存器,不能通過程序改變,由CPU自己控制,表明某種狀態。
(二) 控制器
運算器只能完成運算,而控制器用于控制著整個CPU的工作。
1、 指令控制器
指令控制器是控制器中相當重要的部分,它要完成取指令、分析指令等操作,然后交給執行單元(ALU或FPU)來執行,同時還要形成下一條指令的地址。
2、 時序控制器
時序控制器的作用是為每條指令按時間順序提供控制信號。時序控制器包括時鐘發生器和倍頻定義單元,其中時鐘發生器由石英晶體振蕩器發出非常穩定的脈沖信號,就是CPU的主頻;而倍頻定義單元則定義了CPU主頻是存儲器頻率(總線頻率)的幾倍。
3、 總線控制器
總線控制器主要用于控制CPU的內外部總線,包括地址總線、數據總線、控制總線等等。
4、中斷控制器
中斷控制器用于控制各種各樣的中斷請求,并根據優先級的高低對中斷請求進行排隊,逐個交給CPU處理。
(三) CPU核心的設計
CPU的性能是由什么決定的呢?單純的一個ALU速度在一個CPU中并不起決定性作用,因為ALU的速度都差不多。而一個CPU的性能表現的決定性因素就在于CPU內核的設計。
1、超標量(Superscalar)
既然無法大幅提高ALU的速度,有什么替代的方法呢?并行處理的方法又一次產生了強大的作用。所謂的超標量CPU,就是只集成了多個ALU、多個FPU、多個譯碼器和多條流水線的CPU,以并行處理的方式來提高性能。
超標量技術應該是很容易理解的,不過有一點需要注意,就是不要去管“超標量”之前的那個數字,比如“9路超標量”,不同的廠商對于這個數字有著不同的定義,更多的這只是一種商業上的宣傳手段。
2、流水線(Pipeline)
流水線是現代RISC核心的一個重要設計,它極大地提高了性能。
對于一條具體的指令執行過程,通常可以分為五個部分:取指令,指令譯碼,取操作數,運算(ALU),寫結果。其中前三步一般由指令控制器完成,后兩步 則由運算器完成。按照傳統的方式,所有指令順序執行,那么先是指令控制器工作,完成第一條指令的前三步,然后運算器工作,完成后兩步,在指令控制器工作, 完成第二條指令的前三步,在是運算器,完成第二條指令的后兩部……很明顯,當指令控制器工作是運算器基本上在休息,而當運算器在工作時指令控制器卻在休 息,造成了相當大的資源浪費。解決方法很容易想到,當指令控制器完成了第一條指令的前三步后,直接開始第二條指令的操作,運算單元也是。這樣就形成了流水 線系統,這是一條2級流水線。
如果是一個超標量系統,假設有三個指令控制單元和兩個運算單元,那么就可以在完成了第一條指令的取址工作后直接開始第二條指令的取址,這時第一條指令 在進行譯碼,然后第三條指令取址,第二條指令譯碼,第一條指令取操作數……這樣就是一個5級流水線。很顯然,5級流水線的平均理論速度是不用流水線的4 倍。
流水線系統最大限度地利用了CPU資源,使每個部件在每個時鐘周期都工作,大大提高了效率。但是,流水線有兩個非常大的問題:相關和轉移。
在一個流水線系統中,如果第二條指令需要用到第一條指令的結果,這種情況叫做相關。以上面哪個5級流水線為例,當第二條指令需要取操作數時,第一條指 令的運算還沒有完成,如果這時第二條指令就去取操作數,就會得到錯誤的結果。所以,這時整條流水線不得不停頓下來,等待第一條指令的完成。這是很討厭的問 題,特別是對于比較長的流水線,比如20級,這種停頓通常要損失十幾個時鐘周期。目前解決這個問題的方法是亂序執行。亂序執行的原理是在兩條相關指令中插 入不相關的指令,使整條流水線順暢。比如上面的例子中,開始執行第一條指令后直接開始執行第三條指令(假設第三條指令不相關),然后才開始執行第二條指 令,這樣當第二條指令需要取操作數時第一條指令剛好完成,而且第三條指令也快要完成了,整條流水線不會停頓。當然,流水線的阻塞現象還是不能完全避免的, 尤其是當相關指令非常多的時候。
另一個大問題是條件轉移。在上面的例子中,如果第一條指令是一個條件轉移指令,那么系統就會不清楚下面應該執行那一條指令?這時就必須等第一條指令的 判斷結果出來才能執行第二條指令。條件轉移所造成的流水線停頓甚至比相關還要嚴重的多。所以,現在采用分支預測技術來處理轉移問題。雖然我們的程序中充滿 著分支,而且哪一條分支都是有可能的,但大多數情況下總是選擇某一分支。比如一個循環的末尾是一個分支,除了最后一次我們需要跳出循環外,其他的時候我們 總是選擇繼續循環這條分支。根據這些原理,分支預測技術可以在沒有得到結果之前預測下一條指令是什么,并執行它。現在的分支預測技術能夠達到90%以上的 正確率,但是,一旦預測錯誤,CPU仍然不得不清理整條流水線并回到分支點。這將損失大量的時鐘周期。所以,進一步提高分支預測的準確率也是正在研究的一 個課題。
越是長的流水線,相關和轉移兩大問題也越嚴重,所以,流水線并不是越長越好,超標量也不是越多越好,找到一個速度與效率的平衡點才是最重要的。
三、CPU的外核
1、解碼器(Decode Unit)
這是x86CPU才有的東西,它的作用是把長度不定的x86指令轉換為長度固定的類似于RISC的指令,并交給RISC內核。解碼分為硬件解碼和微解 碼,對于簡單的x86指令只要硬件解碼即可,速度較快,而遇到復雜的x86指令則需要進行微解碼,并把它分成若干條簡單指令,速度較慢且很復雜。好在這些 復雜指令很少會用到。
Athlon也好,PIII也好,老式的CISC的x86指令集嚴重制約了他們的性能表現。
2、一級緩存和二級緩存(Cache)
以及緩存和二級緩存是為了緩解較快的CPU與較慢的存儲器之間的矛盾而產生的,以及緩存通常集成在CPU內核,而二級緩存則是以OnDie或OnBoard的方式以較快于存儲器的速度運行。對于一些大數據交換量的工作,CPU的Cache顯得尤為重要。
GPU:
Graphic Processing Unit簡稱GPU距離那場革命已經5年了還記得最早由偉大的nVIDIA在1999年8月31日提出
一,GPU
GPU全稱是Graphic Processing Unit—圖形處理器,其最大的作用就是進行各種繪制計算機圖形所需的運算。包括頂點設置,光影,像 素操作等。GPU實際上是一組圖形函數的集合,而這些函數由硬件實現,主要用于處理3D游戲中物體移動時的坐標轉換及光源處理。以前,這些工作都是由 CPU配合特定的軟件來做的。GPU從某種意義上來講就是為了取代CPU在圖形處理過程中充當主角而出現的,一塊標準的GPU主要包括 2D Engine,3D Engine ,Video Processing Engine,FSAA Engine,顯存管理單元等等,其中,3D運 算中起決定作用的是3D Engine,這是現代3D顯卡的靈魂,也是區別GPU等級的重要標志。3D Engine在各公司的產品中都是宣傳攻勢的重點 照顧對象,名字叫的一個比一個響,像nVidia的nFinitFX系列,CineFX系列,ATI的SmoothVision系列,一個 3D Engine通常包含著T&L單元,Vertex Processing Engine,Setup Engine, Piexl Shader等
二,API
說到API,也許很多人不容易理解。在計算機行業中,所有軟件的程序接口,包括3D圖形程序接口在內,統稱為API (Application Program Interface)—應用程序接口。過去,如果您想讓它們發揮最大功效,必須做的一件事,就是記錄相關硬件 設備的地址。現在,API已成為軟、硬件之間一種連接的橋梁,這道工序就可以省略了。顯卡芯片廠商根據標準來設計自己的硬件產品,以達到在API調用硬件 資源時最優化,獲得更好的性能。有了這個橋梁,便可實現不同廠家的硬件、軟件最大范圍兼容。目前PC游戲與顯卡之間的橋梁主要有兩個—DirecX和 OpenGL。可能會有人認為DriectX是一個專門的圖形API,其實,DirectX并不局限于顯示領域。目前的DirectX中包含有 Direct Graphics(Direct 3D+Direct Draw)、Direct Input、Direct Play、 Direct Sound、Direct Show、Direct Setup、Direct Media Objects等多個組件,它提供了一整套的 多媒體接口方案。其中,Direct Graphics主要負責3D圖形部分
初代的DriectX并不成功,技術上也不成熟,這種情況一直持續DriectX5.0,DirectX 5版本在D3D上有很大改善,對D3D的內容做 了徹底修改,除此之外,許多應用程序接口的細節部分也得到了改進。加入了霧化效果、Alpha混合等3D特效,使3D游戲中的空間感和真實感得以增強。因 此,DirectX發展到DirectX 5才真正走向了成熟。而真正顯現出DirectX的王者霸氣并且的版本是革命的DirectX7.0
DirectX 7.0加入了硬件幾何轉換與光源處理,及T&L技術。雖然OpenGL中已有相關技術,但此前從未在娛樂級顯卡中出現。 T&L技術將多邊形設置,光影轉換等大計量消耗CPU運算能力的工作轉移給了GPU內的T&L單元進行,從而在一定程度上將CPU從繁重 的勞力中解放了出來
隨后的DirectX 8.0中,T&L被Shader所取代,各種Shader單元的應用帶來了圖形特效的質的飛躍,DirectX 8.0使 GPU真正成為了可編程的處理器。而DirectX 9.0則將各種Shader效果帶入了FLOAT運算的時代在GPU出現的以前,顯卡和CPU的關系 有點像“主仆”,簡單的說這時的顯卡就是畫筆,根據各種由CPU發出的指令和數據進行著色,材質的填充,渲染,輸出等等。所以較早的娛樂用3D顯卡又稱 “3D加速卡”,由于大部分坐標處理的工作及光影特效需要由CPU親自來執行,占用了CPU太多的運算時間,從而造成整體畫面不能非常流暢地表現出來。隨 著時間的推移,CPU進行各種光影運算的速度變的越來越無法滿足游戲開發商的要求,更多多邊形以及特效的應用壓榨光了幾乎所有的CPU性能,矛盾產生 了……如果說不堪忍受的游戲速度催生了GPU的話,那么為GPU準備“產床”的則是我們這個世界上唯一的軟件帝國:微軟—當矛盾接近臨界點時, DriectX7.0來了。接著,1999年8月31日,NV10(就是GeForce)誕生了伴隨著DriectX版本的變化,GPU的發展也經歷了3 個階段:
1、剪除,變形,光照—T&L以及第一代GPU
第一代GPU的最重要的特點就是在硬件級別上實現了T&L運算,其代表有:NV10/15(Geforce256/2GTS/MX),R100 (Radeon256/LE),Savage2000等,由于這一代GPU的基本工作原理相同,所以這里我們以Geforce2GTS為例,來看看第一代 的GPU是如何工作的首先,CPU將數據傳遞給GPU進行處理,數據先進入T&L單元中的Transform Engine,在這里,數據將以頂 點的形式接受視野范圍的判斷,當處理單元判斷某部分頂點處于觀察者的視線范圍以外時,Transform Engine將把這部分頂點“剪除”以使其不會 干擾后續的流水線操作, 具個簡單的例子:當你在某FPS游戲中突然打開狙擊槍的狙擊鏡,視野變成了一個圓形的空洞,而其他部分則為黑色,這時 Transform Engine將去除這個圓形視野范圍以外的所有頂點,不過,這里進行的只是視野范圍的判斷,Transform Engine去除在 你的視線范圍內但是被其它東西擋住了的物體,另外,每一個三角形可能被旋轉,放大/縮小,上升,下降,左偏,右移等。 這就是多邊形轉換轉換。 Transform Engine根據你的視角,改變了由程序提供的組成3D物體的頂點的坐標。經過Lighting Engine處理后的圖象經過判斷 處理后的數據將流入T&L單元中的Lighting Engine,根據光源的類型,距離,角度,數目,應用方式等不同參數,每一個多邊形都會有 不同的光影表現和光影關系,因而需要不同的光線函數予以表征,在Lighting Engine中,處理單元將根據軟件提出的光源分布情況為每個頂點計算 出它所具有的光線矢量,以便后續進行的光線紋理貼圖,著色等操作
經過Lighting Engine處理的畫面
其實,經由T&L單元處理過的數據還只是抽象的數據,并不是具體的圖形,上面兩副圖僅僅是方便讀者進行想象的示意圖。
接下來數據將流入Setup Engine,在這里,運算單元將進行三角形的設置工作,這是整個繪圖過程中最重要的一個步驟,Setup Engine甚 至直接影響著一塊GPU的執行效能。三角形的設置過程是由一個一個的多邊形組成的,或者是用更好的三角形代替原來的三角形。在三維圖像中可能會有些三角形 被它前面的三角形擋住,但是在這個階段3D芯片還不知道哪些三角形會被擋住。所以三角形建立單元接收到的是一個個由三個頂點組成的完整三角形。三角形的每 個角(或頂點)都有對應的X軸、Y軸和Z軸坐標值,這些坐標值確定了它們在3D景物中的位置。同時,三角形的設置也確定了像素填充的范圍
經過Setup Engine處理的畫面
最終著色完畢的畫面
在三角形設置完畢后,T&L單元的全部運算就完成了。接下來數據將進入NV15獨有的NSR像素處理單元進行一定的像素處理,接著流入像素流水線 進行后續的紋理像素填充等操作,這部分操作在DriectX7.0中的變化并不明顯,基本的渲染填充過程與過去的顯卡幾無二異
T&L雖然再一定程度上緩解了CPU運算能力的不濟所帶來的瓶頸,使得系統在圖形方面的資源得到了再分配和增強,但同時,T&L也將新的矛盾轉到了GPU上
T&L是一組相對固定的簡單的圖形函數,所實現的特效受到了函數本身語句的限制,雖然這種固定的指令集設計可以帶來比較高的執行效率,但這種設置 使得DX7下所能實現的特效受到了指令集的約束,許多逼真的特效無法實現,程序員的思想也被限定在一個相對狹窄的范圍內。
2、我要看到你飄逸的秀發和迷人的微笑—可編程Shader以及第二代GPU
DriectX8.0在傳統T&L的基礎上加入了兩個新的概念—可編程的Vertex Shader和Piexl Shader,同樣的,第二代 GPU的標志就是硬件級別的可編程Shader運算,代表產品為NV2X(Geforce3/4Ti),R2XX(Radeon8500)等
可編程Shader的復雜程度遠非T&L可比,為了方便大家理解第二代GPU的特點,我們先來認識一下什么是可編程Shader,以及可編程Shader運算單元
可編程Vertex Shader及頂點處理器:
可編程Vertex Shader讓程序員能夠對特定物體,甚至整個畫面的每一個頂點,指定特別的運算程序,卻不需要CPU介入。每一個頂點都攜帶相當多 的信息,比如坐標,重量,法線,顏色,紋理坐標,霧和點大小數據。頂點處理器能夠以簡短的程序來改變上述這些信息。 這些小程序直接由頂點著色引擎本身執 行,不必勞駕CPU。 典型的T&L引擎將程序員限制在3D運算的光影轉換之前, 在有了頂點處理器的支持之后,游戲設計師對游戲場景里的3D物 體能夠為所欲為的操縱變化,而且不需要用到中央處理器。
這導致了一場革新,程序可以改變頂點的坐標,這樣基本上改變物體的形狀,以達到更接近真實的移動、移動殘影、混色、內插(在兩種外型間轉換),以及變形, 比如改變角色臉部的骨骼和皮膚一個產生一個適時的微笑。也可改變頂點上的顏色數據和紋理坐標,物體表面的顏色達到設計師所想要的色彩效果、投影、凹凸貼圖 設置(如Blinn Bump mapping)或者其它投射的紋理。光源也可以為程序員隨心所欲的調整,不再像過去那樣需要對光源的效果進行笨拙的光線 紋理貼圖,而這些在以前是不可想象的。這一切都歸功于可編程Vertex Shader和頂點處理器的出現
Blinn Bump mapping
可編程Piexl Shader以及像素處理器
在NV15中,nVidia曾經嘗試加入一個叫NSR的像素處理單元,它可以在數據進入像素流水線之前對每個像素進行一系列運算操作,雖然同為每像素操 作,但NSR與Piexl Shader可不能同日而語, NSR對于像素的運算只有7種,同T&L一樣,它依然是固定模式的,程序員依然要依照 規定好的條條框框寫出程序,而Piexl Shader則不同,我們可以用許多不同方式去編程,以實現不同的特效,下面就是一般的像素處理器所具備的特 性:
· 陰影貼圖
· 快速紋理載入
· 影像乘法,對稱核心
· 支持4096x4096或512x512x512 紋理
· 立方體貼圖每邊可4096x4096x32-位
· 支持YUYV的紋理(自動轉換成RGB三原色)
· 支持全景貼圖
可以指向任何一個圖像,如背景緩沖區(back buffer),而可直接當作紋理使用
· 邊緣色彩及邊緣紋理
· 硬件同步化讀/寫
對同一張紋理的讀及寫允許全流水線操作。
可以對背景緩沖區著色,然后馬上能當作紋理使用
· Pass through colors
· 支持DX6規格的環境凹凸/亮度貼圖(就是環境凹凸貼圖)
· 簡單的紋理,S,T 在alpha/紅(AB)及藍/綠 (BG)
· 等向的雙方向性反射分布功能光源
· 內積產生色彩貼圖或Z坐標
· 真實反射凹凸貼圖
這看起來似乎有點抽象,簡單的說,可編程Piexl Shader實現了一個非常重要的特效—真實的毛發
古老街道上昏暗燈光中的狼人
在3D渲染中,渲染真實的毛發一直是一件非常困難的事情,大量的多邊形給多邊形生成帶來了嚴峻的考驗,而每一根毛發之間復雜多變的即時光影關系更不是幾個簡單固定的指令所能實現的。Piexl Shader的可編程性和運算能力很好的解決了這個問題
好啦,現在讓我們來看看第二代GPU是如何完整處理一個畫面的吧
首先,來自CPU的各種物理參數進入GPU,Vertex Shader將對頂點數據進行基本的判斷,如果沒有需要處理的Vertex效果,則頂點數據直 接進入Transform&Lighting Unit進行傳統的T&L操作以節約時間提高效率,如果需要處理各種Vertex效果,則 Vertex Shader將先對各種Vertex Programs的指令進行運算,一般的Vertex Programs中往往包含了過去轉換,剪 切,光照運算等所需要實現的效果,故經由Vertex Shader處理的效果一般不需要再進行Transform&Lighting操作;另 外,當遇到涉及到曲面鑲嵌(把曲面,比如弓形轉換成為多邊形或者三角形)的場合時,CPU可以直接將數據交給Vertex Shader進行處理
另外,在DX8.0的Transform過程中,Vertex Shader可以完成Z值的剔除,也就是Back Face Culling—陰面隱去,這就意味著除了視野以外的頂點外,視野內被前面頂點遮住的頂點也會被一并剪除,這大大減輕了需要進行操作的頂點數目
接下來,經由Vertex Shader處理完成的各種數據將流入Setup Engine,在這里一如既往的進行三角形的設置工作,到這里為止,Vertex Shader的工作就完成了
過去,設置好的三角形本來應該帶著各自所有的參數進入像素流水線內進行紋理填充和渲染,但現在則不同,在填充之前我們還需要進行Piexl Shader的操作
其實Piexl Shader并非獨立存在的,它位于紋理填充單元之后,數據流入像素流水線后先進入紋理填充單元進行紋理填充,然后便是 Piexl Shader單元,經由Piexl Shader單元進行各種處理運算之后再進入像素填充單元進行具體的著色,再經由霧化等操作后,一個完整 的畫面就算完成了
值得注意的是,第二代GPU中普遍引入了獨立的顯示數據管理機制,他們位于Vertex Shader,Setup Engine以及像素流水線之間,負 責數據的更有效率的傳輸、組合,各種無效值的剔除,數據的壓縮以及寄存器的管理等工作,這個單元的出現對整個GPU的工作效率的保證其到了至管重要的作 用。
HyperZ系列:HyperZ技術本身就是一種類似nVIDIA的“Z-封閉甄別”的技術,但是比nVIDIA還更進一步。它的主要功能簡單說來就是分 析在Z軸上的場景,被遮擋的就會被忽略掉,只渲染我們能看到的部分場景;然后對渲染過的Z軸場景進行壓縮處理,數據的壓縮可減少他所占用的空間,從而在存 取Z-Buffer數據的時候可以保留更多的顯存帶寬。而且這是一種畫面質量沒有損害的壓縮算法,并不影響畫面質量。最后一步就是把經過渲染的場景中的Z -Buffer信息立刻清除掉,這樣就更加大了顯存帶寬的利用率。
LMA(光速顯存架構)系列:光速顯存架構采用的第一個技術是“顯存交錯控制”技術, LMA中的顯存控制器劃分成了4個獨立的顯存控制單元,每個單元最 大可以進行32bit圖形相關數據的存取工作,并且這4個單元之間以及它們和圖形處理單元之間都保持密切的通訊聯系,并隨時協調平衡各個子單元之間的數據 流量,因此整體來看LMA的顯存控制單元還是可以進行128bit數據的存儲,但是保證了顯存帶寬的充分利用。光速顯存架構采用的第二個技術是“無損Z壓 縮算法”。傳統的圖形芯片對于每個待渲染的圖形象素都要進行Z軸數據的讀寫工作,因此存儲這些數據的Z緩存一向是消耗顯存帶寬的大戶。LMA中集成了硬件 “無損Z壓縮”單元,采用“無損Z壓縮算法”對Z-緩存數據進行4:1的完全無損壓縮。 光速顯存架構采用的第三個技術是“Z-封閉甄別”。排除了圖象中 被遮蓋住而不可見的部分,這樣GPU就不做隱面模型構建(節省處理器的多邊形運算資源),并且渲染管線也不對隱面進行渲染(無需從幀緩存中讀寫隱面資料數 據,節省渲染管線的象素和紋理生成資源并完全消滅了隱面資料對顯存帶寬的占用)。最后,LMA還包括了4組高速Cache,對數據傳輸進行緩沖。
3、夢中的鏡花水月—可編程Shader2.0以及第三代GPU
當你第一次看到3Dmark03中的MotherNature時,你有沒有感覺到震撼?
更加寬泛的色彩范圍能夠使得圖形的逼真度上升,這就是Shader2.0的由來,Shader2.0的核心實際上就是以擴大指令數目以及FLOAT數據形 式的應用來提高色彩表達的精確度,而第三代GPU的Shader單元也由此而具備了高精度FLOAT色彩數據的運算能力。從一般角度來講,第三代GPU同 第二代GPU相比在基本的操作控制形式等方面并沒有本質的區別,但是由于Shader2.0更大的指令長度和指令個數,以及通用程序+子程序調用的程序形 式等使得第三代GPU在處理高精度的龐大指令時效率上有了明顯的提升,同時也使得第三代GPU的可編程性躍上了一個新的臺階
讓我們來看看第三代GPU到底有哪些改進吧
Vexter Shader部分
第三代GPU的頂點處理器部分除了一般的操作功能外還具備流程控制能力,包括循環,跳躍以及子程序調用等,這些控制指令以及更多向量(或標量)寄存器的應 用使得頂點處理器能夠以更高的效率執行Vertex Programs,提高了Vertex的處理速度。同時,加大的指令長度和指令數量使得頂點處理器的 功能得到了進一步的強化。另外,在第三代GPU中,傳統的T&L數據將完全交由頂點處理器來執行,Transform& Lighting Unit將徹底被頂點處理器“吞并”,這也是第三代GPU的一個重要特點
Piexl Shader部分
第二代GPU的Piexl Shader只能實現INT數據的運算,這勢必會帶來最終運算結果的不精確,而數據的不精確導致了顏色表現的不準確,干擾了最 終畫面的質量以及效果的表現,第三代GPU的重點改進就是運算單元和寄存器所支持的運算格式,現在Piexl Shader可以進行更高精度的FLOAT 運算和輸出,從而使得圖形的色彩顯示更加精確
暴光正確的圖象
數據精度不當而無法實現的特種暴光
另外,第三代GPU的像素處理器每周期所能處理的材質以及指令也分別增加了數倍,這些新特性使得第三代GPU可以處理各種復雜程度的效果,營造一個更為真實的3D畫面,比如更加真實的水面效果
INT Piexl Shader所表現的水面效果
FLOAT Piexl Shader所表現的水面效果
傳統的INT無法表現寬泛的波浪效果,程序員害怕數據精度范圍狹窄引起的上溢或者下溢的發生而不得不在一個很小的物理參數范圍內控制漣漪水面所需的波長、 波浪的大小、移動速度以及反射和折射效果等,現在,由于數據精度的提升,像素處理器完全可以處理一個非常寬泛的數據精度范圍,避免數據的溢出,這就使得更 加真實的水面效果得以被表現。第三代GPU的代表是NV3X系列,R3XX系列等,其中R3XX系列的基本處理方式和順序與第二代GPU在本質上基本相 同,僅僅是Vertex Shader和Piexl Shader的具體操作細節和運算精度上有些許不同,而NV3X雖然在基本原理上也與之大略相同,但 從流水線的角度來看則與完全不同,應該算是個“異類”。產生過程,只分析一下NV3X
以NV35為例:
首先,他具有8個紋理帖圖單元,但8個紋理貼圖單元并不在固定分布于每一條Piexl流水線,而是集簇在一起,根據情況來搭配,可以是4*2、8*1。
其次,他具有12條Shader流水線,但沒有全盤采用浮點渲染流水線,而只是把12條Shader流水線中的8條做成具備浮點處理能力;不過全部12條Shader流水線都具備Fixed-Point Shader的執行能力。
另外,NV3X將流水線后部的各種渲染單元,如霧化,Alpha混合等大幅削減,使得流水線在一定程度上公用這些單元
NV30的構架組成形式基本上與之相當,只是數目上略有不同
由于這個構架并不是傳統意義上的4*2或者8*1的固定構架,我們不能象過去那樣說NV35“每個流水線具有2個紋理帖圖單元”或者“每條管線具有3個Shader流水線”……我們只能說“NV35單位周期可以完成8次左右的紋理貼圖或者12次Shader操作”
另外,由于NV3X對于Fixed-Point Shader的支持精度是FP16和FP32,同時NV3X的Shader流水線的單位Fixed- Point Shader處理精度是16位,所以當遇到32位Fixed-Point Shader數據時,能進行Fixed-Point Shader 數據處理的8條Shader流水線也會根據情況進行搭配來運算32位的Fixed-Point Shader數據
Pixel Programs往往是由多條指令構成的,不同的指令需要不同的執行時間來完成,每個像素必須在應用在它“身上”的Pixel Shader 操作完成后才能由像素流水線寫入到幀緩存里。故此,對于應用了Piexl Shader的像素實際上是需要多個以上的周期才能寫入到幀緩存里,如果采用8 條完整的渲染流水線的話, 流水線后面的霧化、色彩混合等單元很多時候都會處在等待階段,這部分單元需要占用的晶體管數量不在少數,如果這樣浪費就怪可惜 的,砍掉后其中的霧化等單元后,對整體的性能雖然有一些影響,但是卻可以把節省下來的晶體管用于加強Pixel Shader的功能和性能上來,同時可以 保證比較高的多重紋理效率,利大于弊。
簡單的,這個有點詭異的體系節省晶體管的同時能確保相對較好的Pixel Shader效能,同時還有極高的多重貼圖效能
nVidia本指望4條Pixel管線+ 12條Shader流水線的設計能夠在現在以及未來較長的一段時間的游戲里提供超過4條甚至8條 Pixel Pipeline顯卡的效能。不過,實際情況卻與nVidia的初衷有些背道而馳,Shader的完美應用帶來的一個結果就是越來越好的非多 紋理光效果,傳統的多紋理貼圖才能表現的很好的光效果現在只需要進行一次貼圖或者直接使用Shader就可以達到,這使得NV3X的設計成為了空架子,實 用意義大大降低,而在單紋理處理過程中由于NV3X的后續效果單元被削減,它的渲染效能注定沒有傳統的完整流水線高,另外,由于DX9中的最終FP精度被 定義為FP24,這導致了NV3X的相對低下的FP效能。最終,本來“先進”的NV3X構架落的個整體效能低下的下場
從本質上來講,圖形數據在NV3X中的實際處理過程依然是沿著頂點處理器—Setup Engine—像素流水線的順序進行的,這與R3XX以及所有的第二代GPU是相同的
天堂的入口—可編程Shader3.0,DriectX Next以及未來的GPU
在微軟剛剛公布的Driect9.0C中,Vertex Shader和Piexl Shader已經具有了幾乎相同的能力,而在nVidia新發布的第 四代GPU—NV40中,我們發現Vertex Shader包含了4個紋理取樣器,可以使用texld指令進行查表操作, NV40可以在一個 shader pass里完成4個紋理的讀取,這個對于通用替換貼圖而言相當的重要,有了vertex texturing功能后, vertex shader就能讀取紋理信息直接映射到頂點上,以實現displacement mapping(位移映射)等等效果,用不同的紋理和較 少的頂點傳輸時間就能實現外形復雜、平滑的模型,這表明GPU中Vertex Shader的功能正在逐漸接近Piexl Shader。隨著GPU的發 展,未來GPU中的Vertex Shader和Piexl Shader最終將被合并成一個統一的處理單元—Intergrated Shader,兩 種處理單元將使用完全相同的語法以及指令集,Shader的統一將帶來完全不同與現在的數據執行處理方式,GPU的內部結構將發生本質的變化, Intergrated Shader帶來了更低晶體管數目的解決方案,以更少的晶體管數目來完成現在需要數億晶體管才能完成的功能,同時統一 Shader將引出類似全通用I/O接口的設計以利資源的更合理的傳輸和分配,同時,為了解決越來越龐大的數據量,虛擬顯存、無限資源訪問以及幀緩沖操作 等技術的引入也勢在必行。另外,我們在DirectX Next中還發現了整數指令集,處理器等特殊的定義,這些新穎的設計為我們勾勒出了未來GPU的輪 廓
整數指令集
在編程中不必在擔心指令限制是一個很大的進步,不過想使得GPU更為通用還需要更多的工作。一個需要提高的主要區域就是整數處理能力。目前基于在著色器中 處理的所有數據都是浮點,這對于大多數顯卡操作而言是沒有問題的,不過不適合動態分支預測、非內插式顯存搜索(如頂點緩沖的索引)等操作。在目前的GPU 中,唯一的內存尋址就是紋理查找,使用的也是浮點值。這樣的情況對于紋理定位而言沒有什么問題,不過對于通用內存尋址而言就不合適了,這里的連續內存塊可 以完全彼此沒有關聯,采用內插式查找沒有任何意義。微軟對于這樣的情況,在4.0版的Shader模型中引入了全新的、完整的整數指令集。拓撲處理器實際 上,目前的顯卡可以在某些情況下新生成三角形,比如在用到直線以及點的時候。大多數的娛樂級顯卡只具備對三角形進行光柵化處理的能力,這也就意味著所有的 點、線就必須轉化為三角形。點和線在最后都將以2個三角形結束,這樣就需要用到2-6個頂點(根據索引方式的不同而變化)。從本質上來說,這樣的做法是有 益處的,通過可編程的管線,顯示先前應該遮蔽的場景也就無需通過CPU,而可以通過微軟的“拓撲處理器”直接完成。從邏輯上來說,這個拓撲處理器和鑲嵌單 元是相互獨立的,這個處理器在兩種操作集中均可以使用。由目前的趨勢來看,未來的GPU將向著高運算能力,高精度,高通用性的方向發展,GPU在工作方式 上將越來越接近CPU,由于高通用性等CPU特性的引入,GPU可能在一定程度上替代一部分CPU在非繪圖領域的工作,也許在未來我們會看到由全GPU組 成的圖形工作站。盡管未來GPU需要面對由于這些改進而帶來得的諸多問題,尤其是通用性導致的效率低下,比如Intergrated Shader的效率 低下,但隨著時間的推移,各種問題都將會得到妥善的解決。