標籤:

[翻譯]Life of a triangle - NVIDIAs logical pipeline

從這篇開始記錄一些簡單基礎些的notes,很早之前看的。這次是GPU相關的基礎,牽扯到GPU的體系結構,我也不是太熟悉另外翻譯也爛,大家輕噴有謬誤還請斧正。

Life of a triangle - NVIDIAs logical pipeline?

developer.nvidia.com圖標

G80開始重用vs和ps的計算單元,但是還是有一系列處理圖元/光柵化的單元。Fermi開始所有的管線全部並行起來,邏輯上的管線會重複使用多個單元。

假設有兩個三角形A和B,它們部分的工作可以在不同的邏輯管線步驟上運行。A已經進行了矩陣變換接下來需要被光柵化。它的其中的一些像素可以運行ps,其他一些像素被z-cull、ps運行完畢需要寫入rt,還有一些需要等待。接著我們就能拿到三角形B。所以當每個三角形需要運行完全部的邏輯管線,大多數的不同步驟之間可以並行處理。把三角形渲染到屏幕這個job可以分為許多小job甚至subtask。當各自的資源可用時就會執行任務。

從Fermi開始架構變得通用了,統稱Giga Thread Engine。GPU分為GPC(Graphics Processing Cluster),每個GPC里有多個SM(Streaming Multiprocessor)以及1個Raster Engine。它們之間有很多內部的鏈接通信,主要是通過Crossbar來進行GPC之間的工作轉移以及其他單元的通信,比如ROP(Render Output Unit)。

Shader是在SM上執行的,它包含很多core,有很多threads來做一些數學運算。其中一個thread可能是vs或者是ps。這些core使用WS(Warp Schedulers)來驅動,WS管理一組32個threads組成的warp,然後交給DU(Dispatch Unit)來執行指令。代碼邏輯是有scheduler控制而不是在core裡面,core中是類似「sum reg4230, reg4234, reg4235」這種由dispatcher發來的機器碼。相比於CPU,GPU的core比較蠢。GPU的高層單元比較聰明,它來控制整體的工作。

每個單元有多少取決於顯卡的規格。GM204有4個GPC,每個GPC4個SM,Tegra X1有1個GPC和2個SM。SM的規格(有多少core/instruction unit/schedulers)也根據顯卡不同。

邏輯管線

簡化起見,我們假設drawcall需要索引的vb和ib已經在GPU的顯存中,而且只使用VS和PS。

1. 程序使用drawcall調用圖形API(DX/GL)。Driver負責做一些驗證工作來檢查狀態是不是「合法」,並將指令編碼到GPU可以讀取的pushbuffer中。其中有很多CPU端的瓶頸,所以程序員調用API需要認真處理。

2. 等一段時間或者顯式的調用flush,驅動處理pushbuffer然後把它送到GPU(需要一些OS的參與)。GPU中的Host Interface拾取這些指令,然後交給Front End來處理。

3. Primitive Distributor開始任務的分配,它處理indexbuffer中的indices來生成triangle的任務分配給多個GPC

4. 在GPC中,SM的Poly Morph Engine從三角形index中獲取vertex數據

5. 得到數據後,32個threads組成的warp開始處理這些vertex

6. SM的warp

scheduler以整個warp為一組順序的發射執行指令。Threads使用lock-step的方式來運行,並使用mask標誌有效的執行thread。比如對於其中幾個thread,if branch判斷的結果為true,而其他的thread為false,就會使用mask。所以大量的divergence會引起warp中的threads花費更多的時間。Thread不能獨自運行,warp可以獨立運行。

7. Warp的指令可能直接完成或者需要幾個來回的dispatch。比如SM的load/store單元比運算單元要少(所以一個warp的load可能需要調用多次,而運算只需要發射一次)

8. 比如類似load memory這種高延遲的操作指令,此時scheduler會切換到不需要等待memory的warp上執行。這是GPU克服memory latency的重要方法,為了讓切換更快,所有scheduler管理的threads在register-file中都有自己的register信息,shader中需要的register越多,能記錄的thread/warp的空間就越少,可以switch的warp也就越少,那麼等待延遲的結果時我們所能做的工作就越少,只能被迫等待

9. 當一個warp完成了vs中所有的指令後,結果被送到VT(Viewport Tranform)中處理。用clipspace的volume來clip三角形,使用L1/L2 cache來傳輸數據。

10. Triangle被切分,並離開目前處理它的GPC。Triangle的boundingbox決定了使用哪些raster engine,因為每個engine覆蓋了屏幕上的一組tiles。WDC(Work Distribution

Crossbar)發送triangle到一個或多個GPC,現在triangle被分割為了多個小的jobs

11. SM中的Attribute Setup用來保證差值屬性的格式,應該對ps是友好的

12. GPC的Raster Engine把triangle光柵化並且產生ps需要的數據(當然也會處理back-face culling以及Z-cull)

13. 然後批處理32個像素或者說處理8個2*2的quad,2*2是ps計算中最小的處理單元。因為2*2才能允許我們計算導數來做mipmap。對於2*2quad中沒有在triangle內的部分使用mask丟棄掉(gl_HelperInvocation)。SM的一個warp scheduler來管理pixel shadig的任務

14. Warp scheduler做ps的任務和之前提到的做vs的過程一樣,lock-step使得ps對2*2quad中所有數據的獲取相當於free,因為所有threads保證每步計算出來的數據都是同步的(NV_Shader_thread_group)。

15. Ps輸出color到rt上,以及depth。這兒會考慮triangle渲染時API的輸入順序,然後發給多個ROP(Render OutPut unit)單元。之後會做depth test,blend等。這些操作需要一次做一個來保證不會有同一個像素同時輸出兩個color/depth。Nv會做一些內存壓縮來減少帶寬壓力。

一方面這方便理解GPU的workflow/dataflow,另一方面可以幫助理解為什麼與CPU的同步這麼低效。一是因為GPU需要等待所有的工作完成並且沒有新任務提交(所有的硬體單元idle),二是新的任務需要等待所有的計算單元全部用到才真正的全部負載。

下面的模型展示了不同的SM或者warp id。這個結果每幀不太一樣因為work distribution每幀不同。場景用了好幾個drawcall,其中幾個可以並行處理。


很簡單的介紹了大致的管線流程,很多硬體上的優化也沒有提及(HiZ/EarlyZ等),後面會詳細的介紹一下內部的細節,話說我這麼不遺餘力的推崇NV,NV有沒有宣傳費啊 _(:з)∠)_


推薦閱讀:

[翻譯]Metal Gear Solid V – Graphics Study
[GDC17] Ghost Recon Wildlands:Terrain Tools and Technology
[GDC16] Assassins Creed Syndicate: London Wasnt Built in a Day
從零開始手敲次世代遊戲引擎(四十二)
[Siggraph15] GPU-Driven Rendering Pipelines

TAG:遊戲引擎 |