轉:https://blog.csdn.net/p23onzq/article/details/79609629
在GPU出現以前,顯卡和CPU的關系有點像“主仆”,簡單地說這時的顯卡就是畫筆,根據各種有CPU發出的指令和數據進行着色,材質的填充、渲染、輸出等。
較早的娛樂用的3D顯卡又稱“3D加速卡”,由於大部分坐標處理的工作及光影特效需要由CPU親自處理,占用了CPU太多的運算時間,從而造成整體畫面不能非常流暢地表現出來。
例如,渲染一個復雜的三維場景,需要在一秒內處理幾千萬個三角形頂點和光柵化幾十億的像素。早期的3D游戲,顯卡只是為屏幕上顯示像素提供一個緩存,所有的圖形處理都是由CPU單獨完成。圖形渲染適合並行處理,擅長於執行串行工作的CPU實際上難以勝任這項任務。所以,那時在PC上實時生成的三維圖像都很粗糙。不過在某種意義上,當時的圖形繪制倒是完全可編程的,只是由CPU來擔綱此項重任,速度上實在是達不到要求。
隨着時間的推移,CPU進行各種光影運算的速度變得越來越無法滿足游戲開發商的要求,更多多邊形以及特效的應用榨干了幾乎所有的CPU性能,矛盾產生了······
GPU的誕生
NVIDIA公司在1999年8月31日發布GeForce 256圖形處理芯片時首先提出GPU的概念。
GPU之所以被稱為圖形處理器,最主要的原因是因為它可以進行幾乎全部與計算機圖形有關的數據運算,而這些在過去是CPU的專利。
目前,計算機圖形學正處於前所未有的發展時期。近年來,GPU技術以令人驚異的速度在發展。渲染速率每6個月就翻一番。性能自99年,多年來翻番了十倍百倍,也就是(2的10次方比2)提高了上千倍!與此同時,不僅性能得到了提高,計算質量和圖形編程的靈活性也逐漸得以改善。
以前,PC和計算機工作站只有圖形加速器,沒有圖形處理器(GPU),而圖形加速器只能簡單的加速圖形渲染。而GPU取代了圖形加速器之后,我們就應該摒棄圖形加速器的舊觀念。
GPU的結構
GPU全稱是Graphic Processing Unit--圖形處理器,其最大的作用就是進行各種繪制計算機圖形所需的運算,包括頂點設置、光影、像素操作等。GPU實際上是一組圖形函數的集合,而這些函數由硬件實現。以前,這些工作都是有CPU配合特定軟件進行的,GPU從某種意義上講就是為了在圖形處理過程中充當主角而出現的。
一個簡單的GPU結構示意圖包含一塊標准的GPU主要包括2D Engine、3D Engine、VideoProcessing Engine、FSAA Engine、顯存管理單元等。其中,3D運算中起決定作用的是3DEngine,這是現代3D顯卡的靈魂,也是區別GPU等級的重要標志。3DEngine在各公司的產品中都是宣傳攻勢的重點照顧對象,名字一個比一個響,像NVIDIA的nFjnjtFX系列、CineFX系列,AMD的SmoothVision系列。一個3DEngine通常包含着T&L單元、VertexProeessingEngine、SetupEngine、PiexlShader等部分。
GPU的工作原理
GPU中數據的處理流程
現在讓我們來看看第二代GPU是如何完整處理一個畫面的吧!首先,來自CPU的各種物理參數進入GPU,Vertex shader將對頂點數據進行基本的判斷。如果沒有需要處理的Vertex 效果,則頂點數據直接進入T&L Unit 進行傳統的T&L操作以節約時間提高效率。如果需要處理各種Vertex 效果,則Vertex shader將先對各種Vertex Programs的指令進行運算,一般的Vertex Programs中往往包含了過去轉換、剪切、光照運算等所需要實現的效果,故經由Vertex shader處理的效果一般不需要再進行T&L操作。另外,當遇到涉及到曲面鑲嵌(把曲面,比如弓形轉換成為多邊形或三角形)的場合時。CPU可以直接將數據交給Vertex shader進行處理。
另外,在DireetX的Transform過程中,Vertex shader可以完成Z值的剔除,也就是Back Face Culling――陰面隱去。這就意味粉除了視野以外的頂點,視野內坡前面項點遮住的頂點也會被一並剪除,這大大減輕了需要進行操作的頂點數目。
接下來,經由VertexShader處理完成的各種數據將流入SetupEngine,在這里,運算單元將進行三角形的設置工作,這是整個繪圖過程中最重要的一個步驟,Setup Engine甚至直接影響着一塊GPU的執行效能。三角形的設置過程是由一個個多邊形組成的,或者是用更好的三角形代替原來的三角形。在三維圖象中可能會有些三角形被它前面的三角形擋住,但是在這個階段3D芯片還不知道哪些三角形會被擋住,所以三角形建立單元接收到是一個個由3個頂點組成的完整三角形。三角形的每個角(或頂點)都有對應的X軸、Y軸、Z軸坐標值,這些坐標值確定了它們在3D景物中的位置。同時,三角形的設置也確定了像素填充的范圍。,至此,VertexShader的工作就完成了。
過去[第一代],設置好的三角形本來應該帶着各自所有的參數進入像素流水線內進行紋理填充和演染,但現在則不同,在填充之前我們還播要進行PiexlShader的操作。其實,PieXIShader並非獨立存在的,它位於紋理填充單元之后,數據流入像紊流水線后先進入紋理填充單元進行紋理填充,然后便是Piex!Shader單元,經由PiexlShader單元進行各種處理運算之后再進入像素填充單元進行具體的粉色,再經由霧化等操作后,一個完整的畫面就算完成了。值得注意的是,第二代GPU中普遮引入了獨立的顯示數據管理機制,它們位於VertexShader、SetuPEngine以及像素流水線之間,負資數據更有效率地傳輸和組合、各種無效值的剔除、數據的壓縮以及寄存器的管理等工作,這個單元的出現對整個GPU工作效率的保證起到了至關重要的作用。
簡而言之,GPU的圖形(處理)流水線完成如下的工作:(並不一定是按照如下順序)
頂點處理:這階段GPU讀取描述3D圖形外觀的頂點數據並根據頂點數據確定3D圖形的形狀及位置關系,建立起3D圖形的骨架。在支持DX系列規格的GPU中,這些工作由硬件實現的Vertex Shader(定點着色器)完成。
光柵化計算:顯示器實際顯示的圖像是由像素組成的,我們需要將上面生成的圖形上的點和線通過一定的算法轉換到相應的像素點。把一個矢量圖形轉換為一系列像素點的過程就稱為光柵化。例如,一條數學表示的斜線段,最終被轉化成階梯狀的連續像素點。
紋理帖圖:頂點單元生成的多邊形只構成了3D物體的輪廓,而紋理映射(texture mapping)工作完成對多變形表面的帖圖,通俗的說,就是將多邊形的表面貼上相應的圖片,從而生成“真實”的圖形。TMU(Texture mapping unit)即是用來完成此項工作。
像素處理:這階段(在對每個像素進行光柵化處理期間)GPU完成對像素的計算和處理,從而確定每個像素的最終屬性。在支持DX8和DX9規格的GPU中,這些工作由硬件實現的Pixel Shader(像素着色器)完成。
最終輸出:由ROP(光柵化引擎)最終完成像素的輸出,1幀渲染完畢后,被送到顯存幀緩沖區。
總結:GPU的工作通俗的來說就是完成3D圖形的生成,將圖形映射到相應的像素點上,對每個像素進行計算確定最終顏色並完成輸出。
GPU流程示意圖
CPU與GPU的數據處理關系
如今的顯卡圖形,單單從圖象的生成來說大概需要下面四個步驟:
1、Homogeneouscoordinates(齊次坐標)
2、Shadingmodels(陰影建模)
3、Z-Buffering(Z-緩沖)
4、Texture-Mapping(材質貼圖)
在這些步驟中,顯示部分(GPU)只負責完成第三、四步,而前兩個步驟主要是依靠 CPU 來完成。而且,這還僅僅只是3D圖象的生成,還沒有包括圖形中復雜的AI運算。場景切換運算等等……無疑,這些元素還需要CPU去完成。
接下來,讓我們簡單的看一下CPU和GPU之間的數據是如何交互的。
首先從硬盤中讀取模型, CPU分類后將多邊形信息交給GPU,GPU再時時處理成屏幕上可見的多邊形,但是沒有紋理只有線框。
模型出來后,GPU將模型數據放進顯存,顯卡同時也為模型貼材質,給模型上顏色。CPU相應從顯存中獲取多邊形的信息。然后CPU計算光照后產生的影子的輪廓。等CPU計算出后,顯卡的工作又有了,那就是為影子中填充深的顏色
這一點要注意的是,無論多牛的顯卡,光影都是CPU計算的,GPU只有2個工作,1多邊形生成。2為多邊形上顏色。
傳統GPU指令的執行
傳統的GPU基於SIMD的架構。SIMD即SingleInstruction Multiple Data,單指令多數據。其實這很好理解,傳統的VS和PS中的ALU(算術邏輯單元,通常每個VS或PS中都會有一個ALU,但這不是一定的)都能夠在一個周期內(即同時)完成對矢量4個通道的運算。比如執行一條4D指令,PS或VS中的ALU對指令對應定點和像素的4個屬性數據都進行了相應的計算。這便是SIMD的由來。這種ALU我們暫且稱它為4DALU。
需要注意的是,4D SIMD架構雖然很適合處理4D指令,但遇到1D指令的時候效率便會降為原來的1/4。此時ALU 3/4的資源都被閑置。為了提高PS VS執行1D 2D 3D指令時的資源利用率,DirectX9時代的GPU通常采用1D+3D或2D+2DALU。這便是Co-issue技術。這種ALU對4D指令的計算時仍然效能與傳統的ALU相同,但當遇到1D 2D 3D指令時效率則會高不少,例如如下指令:
ADD R0.xyz , R0,R1 //此指令是將R0,R1矢量的x,y,z值相加 結果賦值給R0
ADD R3.x , R2,R3 //此指令是將R2 R3矢量的w值相加 結果賦值給R3
對於傳統的4D ALU,顯然需要兩個周期才能完成,第一個周期ALU利用率75% ,第二個周期利用率25%。而對於1D+3D的ALU,這兩條指令可以融合為一條4D指令,因而只需要一個周期便可以完成,ALU利用率100%。 當然,即使采用co-issue,ALU利用率也不可能總達到100%,這涉及到指令並行的相關性等問題,而且,更直觀的,上述兩條指令顯然不能被2D+2DALU一周期完成,而且同樣,兩條2D指令也不能被1D+3DALU一周期完成。傳統GPU在對非4D指令的處理顯然不是很靈活。
GPU的多線程及並行計算
GPU的功能更新很迅速,平均每一年多便有新一代的GPU誕生,運算速度也越來越快。GPU的運算速度如此之快,主要得益於GPU是對圖形實時渲染量身定制的,具有兩點主要特征:超長流水線與並行計算。
多線程機制
GPU的執行速度很快,但是當運行從內存中獲取紋理數據這樣的指令時(由於內存訪問是瓶頸,此操作比較緩慢),整個流水線便出現長時間停頓。在CPU內部,使用多級Cache來提高訪問內存的速度。GPU中也使用Cache,不過Cache命中率不高,只用Cache解決不了這個問題。所以,為了保持流水線保持忙碌,GPU的設計者使用了多線程機制(multi-threading)。當像素着色器針對某個像素的線程A遇到存取紋理的指令時,GPU會馬上切換到另外一個線程B,對另一個像素進行處理。等到紋理從內存中取回時,可再切換到線程A。
例如:如果裝配一台汽車需要,10個時間單元,將它分成10個流水線階段,每個階段分配一個時間單元,那么一條裝配線每一個時間單元就可以生產一輛汽車。顯然流水線模式的生產在理想狀況下要比串行方式快了十倍。
但是使用這種方法有一個前提,線程A與線程B沒有數據依賴性,也就是說兩線程之間無需通訊。如果線程B需要線程A提供某些數據,那么即使切換到線程B,線程B仍是無法運行,流水線還是處於空閑狀態。不過幸運的是,圖形渲染本質上是一個並行任務。
並行計算
無論是CPU送給GPU的頂點數據,還是GPU光柵生成器產生的像素數據都是互不相關的,可以並行地獨立處理。而且頂點數據(xyzw),像素數據(RGBA)一般都用四元數表示,適合於並行計算。在GPU中專門設置了SIMD指令來處理向量,一次可同時處理四路數據。SIMD指令使用起來非常簡潔。此外,紋理片要么只能讀取,要么只能寫入,不允許可讀可寫,從而解決了存貯器訪問的讀寫沖突。GPU這種對內存使用的約束也進一步保證了並行處理的順利完成。
為了進一步提高並行度,可以增加流水線的條數。在GPU中,有多達16組像素着色器流水線,6組頂點着色器流水線。多條流水線可以在單一控制部件的集中控制下運行,也可以獨立運行。在單指令多數據流(SIMD)的結構中,GPU通過單指令多數據(SIMD)指令類型來支持數據並行計算。在單指令多數據流的結構中,單一控制部件向每條流水線分派指令,同樣的指令被所有處理部件同時執行。例如NVIDIA顯卡中包含有14組多處理器(MultiProcessor),每組處理器有8個處理單元(Processor),但每組多處理器只包含一個指令單元(InstruetionUnit)。
另外一種控制結構是多指令多數據流(MIMD),每條流水線都能夠獨立於其他流水線執行不同的程序。顯卡的頂點着色器流水線使用MIMD方式控制,像素着色器流水線使用SIMD結構。MIMD能比較有效率地執行分支程序,而SIMD體系結構運行條件語句時會造成很低的資源利用率。不過SIMD需要硬件少,這是一個優勢。
CPU中大部分晶體管主要用於構建控制電路(象分支預測等)和Cache,只有少部分的晶體管來完成實際的運算工作。而GPU的控制相對簡單,而且對Cache的需求小,所以大部分晶體管可以組成各類專用電路、多條流水線,使得GPU的計算速度有了突破性的飛躍,擁有了驚人的處理浮點運算的能力。現在CPU的技術進步正在慢於摩爾定律,而GPU(視頻卡上的圖形處理器)的運行速度已超過摩爾定律,每6個月其性能加倍。