手機,現在已經是人手一部甚至兩部了,餐廳酒吧、地鐵巴士、馬路街邊隨處可見的低頭族大家早就見慣不怪,在飯桌上如果你發現沒有人低頭看手機的話反而會懷疑自己是不是到了外星球。
吸引人們對手機目不轉睛的自然是它顯示的內容, 相對於個人電腦剛剛問世時候只能呈現有限的文字以及低分辨率的畫面而言,現在的智慧手機已經可以在巴掌大的螢幕上做到高達3840×2160 的分辨率,能呈現非常豐富的畫面元素。
台式機和智慧手機雖然存在較大的性能分野,但是兩者間一直在互相借鑒,例如操作系統界面都採用了硬體三維加速來強化用戶體驗:豐富元素的表現力以及實現界面的視覺擴展(例如窗口的旋轉切換),而實現這些三維硬體加速的正是許多手機、電腦文章報導中的GPU,比如說Qualcomm(高通)的Adreno、蘋果的PowerVR、ARM的Mali。
因為應用上的相似性,行動端的GPU和台式機GPU發展最近這幾年幾乎都是齊頭並進,理論上如果將行動端的GPU放大後也是可以拿到台式機上使用的。
(NVIDIA推出的NV10)
GPU的全稱是Graphics Processing Unit,也即是圖形處理單元的意思。這個概念的最早確定是NVIDIA(英偉達)公司在1999年發布型號為GeForce (代號NV10)的三維芯片時首次提出,當時的定義是:
三角形變換能力達到每秒一千萬個三角形以上的三維芯片。
時至今日,當年NVIDIA提出的GPU定義相信已經很少人記得,GPU這個名詞因為微軟DirectX 7採用而普及,此後NVIDIA、微軟、ATI(後來的AMD)、Intel以及幾乎整個相關行業、媒體大量採用而成為大家非常熟悉的名詞,不管是台式機、伺服器、工作站還是遊戲機、行動設備,它已經是無處不在。
相較於GPU的定義,GPU 到底是怎麼一回事,它是如何實現三維渲染以及為何後來可以勝任非圖形計算,知道的人就更少了,本文嘗試在這方面做一些簡單的介紹。
GPU到底是如何實現三維渲染呢?要了解GPU是如何進行渲染操作其實並不難,宏觀角度來可以將其簡化為下面的樣子:
應用程序->幾何處理->光柵處理
在圖形處理中,應用程序執行的相關操作包括了碰撞偵測、全局加速算法、動畫處理、物理模擬等。
幾何處理就是對圖元進行處理,所謂圖元是指點、線、面這類幾何體,而光柵化則是將確定了位置、大小和光照的幾何體映射到螢幕空間柵格化後的處理,例如像素著色、貼圖、混合。
在沒有圖形芯片(顯卡)之前,幾何處理、光柵處理都是由CPU 或者FPU(浮點單元)、SIMD (單指令多數據)單元協助來完成,隨著芯片技術的進步,其中的幾何處理、光柵處理開始逐步放到專門的芯片上執行,之後這些專用芯片又被集成到一塊,逐漸形成了現在的GPU。行動處理器同樣經歷PC這一過程,比如說高通最早的處理器MSM7225/7625就沒有集成GPU ,甚至是2D處理都是交由CPU完成。
(智慧手機與PC一樣,經歷過無GPU時代)
應用程序把需要進行三維渲染或者計算的數據和指令遞交給GPU,由GPU來執行幾何處理以及光柵處理,這樣的處理方式被稱作流水線(pipeline)。
採用流水線的方式可以將工作拆分為若干個處理環節,也就是所謂的工位(stage)或者功能階段,這些工位本身也可以繼續拆分成若干部分,也可以實現(部分的)並行化。
幾何處理階段執行的是頂點、多邊形級別的處理。這一步可以拆解為5 個工位或者說5 個步驟:
•對模型及視圖進行變換(transform)
•頂點著色
•投影
•裁剪
•屏幕映射
模型及視圖的變換
模型變換
由於每個模型都有自己的坐標,因此在成為屏幕上的畫面對象之前,模型需要變換為多個空間或者坐標系。
作為對象的模型空間(Model Space,或者叫模型自空間)的坐標被稱作模型坐標,在經過坐標變換後,模型就會處於世界坐標或者世界空間(World Space)裡,也就是確定了該模型在場景中的方向、位置。
我們允許在場景中存在多個模型的拷貝(被稱作引用),這些大小一樣的引用可以在同一個場景中有不同的位置、方向。
視圖(Viewport,或者視口)變換
現在的實時渲染場景中包含的對象(模型)可以有很多個,但是只有被攝像機(或者說觀察者,也即是設定的視角覆蓋)的區域才會被渲染。這個攝像機在世界空間裡有一個用來擺放的位置和面向的方向。
為了實現接下來的投影、裁剪處理,攝像機和模型都需要進行視圖變換這個操作,目的是將攝像機放置在坐標原點上,使其正對的方向為Z 軸(負向),Y 軸指向上(上圖是從攝像機正上方俯視,所以沒法給出Y 軸),X 軸指向右。
頂點著色
所謂著色就是指確定光照在物料上所呈現效果的操作,這類操作既可能運行於幾何階段的模型頂點上,也可能運行於光柵階段的各個像素上,也就是所謂的頂點著色和像素著色。
在頂點著色的時候,各個頂點需要存放若干個相關的物料數據,例如頂點位置、法線、色彩以及其他任何進行著色處理計算相關的數位信息。
頂點著色的計算結果(可以是色彩、向量、紋理坐標以及任何其他著色數據)會被發送到光柵化階段進行插值處理。
投影
在完成了著色處理後,渲染系統會把可視體轉換為一個位於(-1, -1, -1)到(1, 1, 1)的單元立方體(unit-cube)中,這個立方體被稱作正則觀察體(canonical view volume),使用到的投影方式一般有兩種:平行投影和透視投影。
前一種主要在CAD 等軟體中使用,後一種因為模擬了我們人類的視覺體驗,所以在遊戲或者虛擬現實中經常使用:
上圖分別是一部iPhone 6s Plus 以平行投影和透視投影的方式呈現在螢幕上的效果。
三角形裁剪
只有在可視體內的圖元會被傳送到在屏幕上繪製這些圖元的光柵階段,在進行裁剪動作的時候,如果圖元有頂點落在可視體之外,裁剪的時候就會將可視體之外的這部分剪切掉並且在可視體與圖元相交的位置生成新的頂點,而位於立方體外部的舊圖元就會被拋棄掉。
螢幕映射
經過上一步裁剪後的位於可視體內的圖元會被傳遞到螢幕映射階段,此時的坐標信息依然是三維的。圖元的X、Y 坐標被變換到螢幕坐標系,螢幕坐標再加上Z 軸坐標就被稱作窗口坐標。
我們假定場景要渲染到一個最小角落坐標為(x1, y1)和最大角落坐標為(x2, y2)的窗口中,也就是x1 < x2,y1 < y2。此時,螢幕映射執行的是一個縮放處理後的轉換操作。Z 軸坐標並不受此操作的影響。
現在,新的x 軸、 y 軸坐標就是螢幕坐標,有對應的螢幕像素位置,不再是之前投影處理後的那個立方體所採用的映像坐標系統。
光柵處理階段要幹些什麼呢?
在獲得了經過變換和投影處理的頂點及其相關聯的著色信息後,光柵化處理階段的目的就是計算並設置好被對象覆蓋區域的像素顏色。這個處理被稱作光柵化或者掃描轉換,也就是把二維坐標上包含深度(Z 軸)信息和各種相關著色信息的頂點到螢幕上像素的轉換。
這個處理階段一般可以拆分為4 個工位:
1、三角形設定
2、三角形遍歷
3、像素著色
4、輸出合併
三角形設定
這一步會進行三角形表面的微分以及其他關於三角形表面數據的計算,計算出來的數據會被用於掃描轉換以及幾何階段所產生的各種著色數據的插值處理。在GPU上這一步會採用固定硬件功能單元來實現。
三角形遍歷
這一步用作確定像素的中心是否被三角形覆蓋,如果該像素被三角形覆蓋的話,就會生成對應的片元(fragment)。
查找哪些樣本或者像素是否位於三角形內通常被稱作三角形遍歷或者掃描轉換。
每個三角形對應片元的屬性都是由該三角形的三個頂點數據插值而成,例如片元的深度值以及來自幾何階段的著色數據。
像素著色
所有的逐像素(per-pixel)著色計算都在這一步執行,使用的輸入數據是之前插值的著色數據。像素著色發送到下一個工位的計算的結果可能是一個色彩值也可能是多個色彩值。
和三角形設定以及三角形遍歷不同採用固定硬件功能單元不同的是,現在的像素著色都是由可編程的GPU內核執行。
在像素著色所依賴的眾多技術中最為重要的就是貼圖(texturing),所謂貼圖就是把一張或者多張圖片“貼”到對像上。
輸出合併
在這一步執行的操作主要是將之前步驟生成的色彩信息進行合併形成最終輸出的像素色彩。
用於存放像素色彩信息的緩存被稱作色彩緩存,一般情況下是以紅、綠、藍三個色元的方式存放,此外還有一個用於存放像素對應深度信息值的深度緩存(一般採用Z-Buffer)。
在GPU中實現這一步的功能單元有幾種叫法,例如ROP、Output Merger 或者Back-End。
在這個階段,Output Merger 會根據深度緩存(depth buffer 或者Z-buffer)存放的深度信息判斷是否更新色彩緩存中的色彩值。
例如當前像素計算出來的深度值(例如是0.1)比深度緩存中對應像素的值小(例如是0.2),則表示當前像素的三角形比色彩緩存存放的像素所對應的三角形更靠近“攝像頭”,於是GPU會對該圖元的色彩進行計算並把新計算出來的色彩值和深度值更新到色彩緩存和深度緩存中,否則的話就不會更新當前像素的緩存。
在整個場景完成渲染後,色彩緩存中存放的都是從攝像機視角位置看到的可視圖元色彩值。
這樣處理的好處是三角形可以使用任意次序來渲染,但是如果圖元或者說三角形是部分透明的話,則必須依照從遠到近的三角形層次進行渲染。這是Z-Buffer 的主要缺點之一。
像素除了色彩緩存和深度緩存外,還有其他利用通道或者緩存的技術來用於過濾和捕捉片元(fragmet)信息。
通常和色彩一起存放於色彩緩存的阿爾法通道(Alpha Channel)包含了每個像素的相對不透明值,開發人員可以在進行深度測試之前對到來的片元先執行名為阿爾法測試(Alpha Test)的操作。如果片元的alpha 值測試(一般是等於、大於等簡單的操作)為“假”,那麼這個像素的後續處理操作就會被省略掉。這個操作通常用於確保完全透明的片元不會對Z-buffer 構成影響。
此外,還可能會涉及到名為蠟板緩存(Stencil Buffer)的技術。Stencil Buffer 作為一個離屏緩存一般用於存放已渲染圖元的位置,它通常用於進行一些特殊效果的處理,例如將一個“實心”圓存放到蠟板緩存中,之後配合其他操作,就可以將被覆蓋圖元的色彩值控制為只有在位於這個實心圓中的時候才被呈現,相當於一個遮罩的作用。
以上這些緩存都被統稱為幀緩存,但是在一般情況下,幀緩存特指色彩緩存和深度緩存。由於畫面渲染是需要時間的,為了保證出到顯示器或者顯示螢幕的時候圖元都是已經完成渲染的,人們引入了雙緩存技術,渲染中的被稱為後台緩存(back buffer),完成渲染的稱作前台緩存(front buffer),在後台緩存完成渲染後,馬上變成前台緩存,而前台緩存就切換為後台緩存,以此類推。(以上未完待續)
以上文章來自http://www.evolife.cn/html/2016/87798_5.html
GPU想必大家都耳熟能想,但有些人說GPU的效能過剩,這我是不能同意的,因為圖形處理包羅萬象。你每做任何一項動作它都需要映射。這麼一來效能是遠遠的不足。不然為何HTC 的M9+所使用的GPU並沒有很高級跑大形游戲就會有跑不動的現像。這是因為圖形處理無法應付它的需求。
片元(fragmet)和像素(pixel)的區別?
上文中我們提到了片元和像素,像素是相對容易理解的,嚴格來說,像素就是對應屏幕上的一個點,它有表示屏幕位置的x、y 坐標以及顏色的紅綠藍(RGB)值(像素是沒有Alpha 通道值的),圖形流水線所作的所有事情都是為了給輸入的圖元計算在屏幕上像素的顏色。
那麼,片元又是怎麼一回事呢?
在三角形遍歷和輸出合併之間計算的柵格數據就是片元,它們是像素的前身,在遍歷的時候由頂點內插而成。片元除了具備像素的x、y 坐標外,還有表示深度的z 坐標以及頂點的屬性信息(顏色、片元法線、紋理坐標)。
正如前面所說的,深度坐標記錄的是圖元的相對距離,在深度測試的時候被遮蔽(或者阿爾法測試中為透明)的圖元會在輸出合併階段被拋棄掉,。
片元這個說法是OpenGL 或者大多數實時圖形渲染文獻中的概念,而D3D 則沒有這麼嚴格的區分,片元和像素都統稱為像素。
我們這裡討論的都是以實時三角形渲染為例,除此以外還有其他三維渲染流水線形式,例如micropolygon(微型多邊形)、Voxel(體素) 渲染。
現在的GPU流水線也是遵照這樣的圖形流水線來設計,在一段時間裡,出於成本效益的考慮,GPU 的各個功能單元都是有專門的電路來實現的。
不過在新式的GPU中,可編程部分(例如頂點程序、片元程序)由於指令集得以統一,所以都採用了同樣的計算單元來跑。
公認必須採用固定功能硬件單元來實現的主要是三角形設置、遍歷以及輸出合併單元,英特爾曾經試圖在名為Larrabee 的GPU項目裡將這些工位採用通用單元來執行,但是最終結果是不了了之,至少說明現階段或者在未來可見的較長時期裡,三角形設置/遍歷以及輸出合併的最合理實現方式還是使用固定功能硬體單元。
(Intel Larrabee)
在現實中GPU並不僅僅是上面討論的三維處理、計算單元,廣義的GPU還應該包括視頻編解碼單元、掃描輸出單元、總線單元、存儲單元,手機GPU現在都和CPU、基帶、周邊等單元集成到同一個芯片裡,這樣的芯片被稱作SoC(片上系統),SoC 並非是手機獨有的,在此之前的單片機(例如洗衣機等裡就有,一般幾塊錢一顆)其實就是SoC的一種實現方式。
GPU 最初是為三維遊戲加速設計的,所以它最拿手的自然是三維遊戲加速,現在無論是安卓、iOS 都有不少三維遊戲大作,例如:勞拉Go、FIFA 系列、真人快打X、Hitman Sniper、Marvel Future Fight、Godfire: Rise of Promotheus、Over Kill、Implosion、Battle supremacy 等等。
除了遊戲渲染加速外,智能手機的操作系統界面也是採用了GPU硬件加速的,例如選單的彈出、桌面平移等。和桌面操作系統使用三維加速相比,移動操作系統由於受到屏幕空間小的約束,因此三維加速體驗帶來的空間感拓展是更加不可或缺的。從安卓4.0系統開始,不少用戶就感覺到系統流暢性大幅度提高正是因為從系統層面上線了GPU硬件加速。
通用計算加速原本也是在非移動應用上的技術,不過隨著智能手機的高速發展,已經有了不少開發人員利用GPU的通用計算能力來進行一些有意義的加速。
例如在蘋果機上有一款名為極拍的APP,利用蘋果手機的GPU對攝像頭拍攝的視頻進行實時降噪處理,可以將蘋果手機的夜間視頻達到單反攝像機的夜間視頻拍攝效果,這是非常具有實用意義的。
另一個典型是高通驍龍處理器,ATI是最早提倡通用計算加速的GPU製造商,而Adreno 200 GPU正源自ATI Imageon項目。發展至今,在高通驍龍820上的Adreno 530已經能實現輔助全景照片合成、幫助“認知計算平台”Zeroth識別物體。
(“認知計算平台”Zeroth演示)
GPU 在這三方面的作用對我們手機的日常應用產生了直接的影響,許多手機媒體口頭整天掛著的使用體驗,其實都離不開GPU。
在下篇文章中SIMD、Core、GPU 中的線程、統一著色器、紋理單元這些GPU常見術語對一般讀者來說都是相當陌生或者容易產生困擾,在此先進行淺析。
SIMD:
Single Instruction Multiple Data,單指令多數據流,目前所有的GPU在基本功能單元層面都屬於SIMD(業界也接受NVIDIA提出的SIMT——單指令多線程),一般是16路SIMD或者32路SIMD。
“內核”或者core:
目前在GPU行業或者GPU行銷上被嚴重濫用的名詞,它被用作指代SIMD一條Lane(計算通道)上的單元集合,裡面可能有一個單週期32位FMA(積和熔加運算)運算器、一個雙週期64位FMA運算器等等,GPU廠商把GPU裡的SIMD Lane數加起來就對外宣稱有多少個內核。
這樣的說法是否屬於錯誤宣傳還真不好說,因為目前並沒有什麼法律文件規定怎樣的集合才算是一個內核。
不過對於計算機科學來說,微架構裡對內核約定俗成的看法是它必須有一個PC(程序計算器,它是一個寄存器,其中存放的一般是指向該內核要執行的下一條指令的地址)。
這樣的話,一個GPU內核顯然不能是SIMD單元中的一個Lane,它的層級至少應該高一級。
所以,GPU上相對嚴格的“內核”概念單元對應的應該是類似與AMD GCN的Compute Unite、NVIDIA Maxwell中的SMM、PowerVR Series 6/7的USC等名詞命名的單元集合,在OpenCL中,這個層級的單元集合被稱作Compute Unit(計算單元,簡稱CU,AMD的GCN微架構也採用Compute Unit這個術語,完全對應OpenCL的Compute Unit),而GPU廠商的行銷術語“內核” 或者“core” 在OpenCL中被稱作Process Element,簡稱PE。
GPU中的線程:
現在的GPU都採用了多層次線程技術,按照硬件開發商提供的文檔,對應SIMD Lane的被稱作thread(OpenCL中稱作work-item,在圖形渲染的時候你可以將其看作是屏幕上的一個像素),是最小的線程單位;
往上的一層線程單位在新的OpenCL被稱作sub-group,NVIDIA稱作warp 或者thread warp,AMD稱作wavefront,屬於GPU執行調度的最小硬件線程單位。再往上就是workgroup(NVIDIA 稱之為thread block)和NDRange(NVIDIA稱之為Grid,由若干個workgroup或者thread block組成)。
Workgroup的對應GPU硬件關係是Compute Unit,同一時間裡Compute Unit跑的都是一個workgroup,而Grid則對應GPU的一個partition(分區,在設備或者說加速器允許的情況下,OpenCL可以把一個設備分成若干個分區來使用)。
你可以把飯粒比作是work-item,而每一口飯則算是一個sub-group,一碗飯看作是一個workgroup,飯煲看作是NDRange(sorry,我的比喻未必很恰當)。
統一著色器
在DX10以後,由於幾何、像素的指令格式一樣,使得幾何和像素處理可以在同樣的單元上執行,自此以後台式GPU都採用了統一著色器設計,以確保著色器的利用率提高。
紋理單元
紋理單元或者說紋理映射單元是GPU中計算紋理坐標和獲得紋理樣本的單元。在繪製某個對象的時候,每個紋理單元進行一個紋理取樣動作,不同的繪製對象每次的取樣動作都可以更改使用的紋理。紋理單元的性能指標一般用TexOps/s 來表示,表示每秒的紋理操作數,不同的紋理格式和不同的紋理過濾算法以及硬件實現、內存帶寬都會對這個指標產生影響。紋理單元一般和若干個著色器綁定在一起。
以上是全篇的內容,非常抱歉要分開寫,因為文章太長了,超過字數限制。所以只好分開,下一集繼續介紹GPU下集。
紹英 發表於 2016-7-10 16:18
大大真厲害,好詳細的內容,不過因該有很多人有看沒有懂吧!
歡迎光臨 HTC論壇 (https://community.htc.com/tw/) | Powered by Discuz! X3.1 |