深刻GPU硬件架構及運行機制

 

1、導言

對於大多數圖形渲染開發者,GPU是既熟悉又陌生的部件,熟悉的是天天都須要跟它打交道,陌生的是GPU就如一個黑盒,不知道其內部硬件架構,更無從談及其運行機制。前端

本文以NVIDIA做爲主線,將試圖全面且深刻地剖析GPU的硬件架構及運行機制,主要涉及PC桌面級的GPU,不會覆蓋移動端、專業計算、圖形工做站級別的GPU。git

若要通讀本文,要求讀者有必定圖形學的基礎,瞭解GPU渲染管線,最好寫過HLSL、GLSL等shader代碼。程序員

1.1 爲什麼要了解GPU?

瞭解GPU硬件架構和理解運行機制,筆者認爲好處多多,總結出來有:github

  • 理解GPU其物理結構和運行機制,GPU由黑盒變白盒。
  • 更易找出渲染瓶頸,寫出高效率shader代碼。
  • 緊跟時代潮流,瞭解最前沿渲染技術!
  • 技多不壓身!

1.2 內容要點

本文的內容要點提煉以下:web

  • GPU簡介、歷史、特性。
  • GPU硬件架構。
  • GPU和CPU的協調調度機制。
  • GPU緩存結構。
  • GPU渲染管線。
  • GPU運行機制。
  • GPU優化技巧。

1.3 帶着問題閱讀

適當帶着問題去閱讀技術文章,一般能加深理解和記憶,閱讀本文可帶着如下問題:編程

一、GPU是如何與CPU協調工做的?api

二、GPU也有緩存機制嗎?有幾層?它們的速度差別多少?緩存

三、GPU的渲染流程有哪些階段?它們的功能分別是什麼?性能優化

四、Early-Z技術是什麼?發生在哪一個階段?這個階段還會發生什麼?會產生什麼問題?如何解決?

五、SIMD和SIMT是什麼?它們的好處是什麼?co-issue呢?

六、GPU是並行處理的麼?如果,硬件層是如何設計和實現的?

七、GPC、TPC、SM是什麼?Warp又是什麼?它們和Core、Thread之間的關係如何?

八、頂點着色器(VS)和像素着色器(PS)能夠是同一處理單元嗎?爲何?

九、像素着色器(PS)的最小處理單位是1像素嗎?爲何?會帶來什麼影響?

十、Shader中的if、for等語句會下降渲染效率嗎?爲何?

十一、以下圖,渲染相同面積的圖形,三角形數量少(左)的仍是數量多(右)的效率更快?爲何?

十二、GPU Context是什麼?有什麼做用?

1三、形成渲染瓶頸的問題極可能有哪些?該如何避免或優化它們?

若是閱讀完本文,可以很是清晰地回答以上全部問題,那麼,恭喜你掌握到本文的精髓了!

 

2、GPU概述

2.1 GPU是什麼?

GPU全稱是Graphics Processing Unit,圖形處理單元。它的功能最初與名字一致,是專門用於繪製圖像和處理圖元數據的特定芯片,後來漸漸加入了其它不少功能。

NVIDIA GPU芯片實物圖

咱們平常討論GPU和顯卡時,常常混爲一談,嚴格來講是有所區別的。GPU是顯卡(Video card、Display card、Graphics card)最核心的部件,但除了GPU,顯卡還有扇熱器、通信元件、與主板和顯示器鏈接的各種插槽。

對於PC桌面,生產GPU的廠商主要有兩家:

  • NVIDIA:英偉達,是當今數一數二的圖形渲染技術的引領者和GPU生產商佼佼者。NVIDIA的產品俗稱N卡,表明產品有GeForce系列、GTX系列、RTX系列等。

  • AMD:既是CPU生產商,也是GPU生產商,它家的顯卡俗稱A卡。表明產品有Radeon系列。

固然,NVIDIA和AMD也都生產移動端、圖形工做站類型的GPU。此外,生產移動端顯卡的廠商還有ARM、Imagination Technology、高通等公司。

2.2 GPU歷史

GPU自從上世紀90年代出現雛形以來,通過20多年的發展,已經發展成不只僅是渲染圖形這麼簡單,還包含了數學計算、物理模擬、AI運算等功能。

2.2.1 NV GPU發展史

如下是GPU發展節點表:

  • 1995 – NV1

    NV1的渲染畫面及其特性。

  • 1997 – Riva 128 (NV3), DX3

  • 1998 – Riva TNT (NV4), DX5

    • 32位顏色, 24位Z緩存, 8位模板緩存
    • 雙紋理, 雙線性過濾
    • 每時鐘2像素 (2 ppc)
  • 1999 - GeForce 256(NV10)

    • 固定管線,支持DirectX 7.0
    • 硬件T&L(Transform & lighting,座標變換和光照)
    • 立方體環境圖(Cubemaps)
    • DOT3 – bump mapping
    • 2倍各向異性過濾
    • 三線性過濾
    • DXT紋理壓縮
    • 4ppc
    • 引入「GPU」術語

    NV10的渲染畫面及其特性。

  • 2001 - GeForce 3

    • DirectX 8.0
    • Shader Model 1.0
    • 可編程渲染管線
      • 頂點着色器
      • 像素着色器
    • 3D紋理
    • 硬件陰影圖
    • 8倍各向異性過濾
    • 多采樣抗鋸齒(MSAA)
    • 4 ppc

    NV20的渲染畫面及其特性。

  • 2003 - GeForce FX系列(NV3x)

    • DirectX 9.0
    • Shader Model 2.0
      • 256頂點操做指令
      • 32紋理 + 64算術像素操做指令
    • Shader Model 2.0a
      • 256頂點操做指令
      • 512像素操做指令
    • 着色語言
      • HLSL
      • CGSL
      • GLSL

NV30的渲染畫面及其特性。

  • 2004 - GeForce 6系列 (NV4x)

    • DirectX 9.0c
    • Shader Model 3.0
    • 動態流控制
      • 分支、循環、聲明等
    • 頂點紋理讀取
    • 高動態範圍(HDR)
      • 64位渲染紋理(Render Target)
      • FP16*4 紋理過濾和混合

NV40的渲染畫面及其特性。

  • 2006 - GeForce 8系列 (G8x)

    • DirectX 10.0
    • Shader Model 4.0
      • 幾何着色器(Geometry Shaders)
      • 沒有上限位(No caps bits)
      • 統一的着色器(Unified Shaders)
    • Vista系統全新驅動
    • 基於GPU計算的CUDA問世
    • GPU計算能力以GFLOPS計量。

    NV G80的渲染畫面及其特性。

  • 2010 - GeForce 405(GF119)

    • DirectX 11.0

      • 曲面細分(Tessellation)
        • 外殼着色器(Hull Shader)
        • 鑲嵌單元(tessellator)
        • 域着色器(Domain Shader)
      • 計算着色器(Compute Shader)
        • 支持Stream Output

      DirectX 11的渲染管線。

      • 多線程支持
      • 改進的紋理壓縮
    • Shader Model 5.0

      • 更多指令、存儲單元、寄存器
      • 面向對象着色語言
      • 曲面細分
      • 計算着色器
  • 2014 - GeForceGT 710(GK208)

    • DirectX 12.0
      • 輕量化驅動層
      • 硬件級多線程渲染支持
    • 更完善的硬件資源管理
  • 2016 - GeForceGTX 1060 6GB

    • 首次支持RTX和DXR技術,即支持光線追蹤
    • 引入RT Core(光線追蹤核心)

    支持RTX光線追蹤的顯卡列表。

  • 2018 - TITAN RTX(TU102)

    • DirectX 12.1,OpenGL 4.5

    • 6GPC,36TPC,72SM,72RT Core,...

    • 8K分辨率,1770MHz主頻,24G顯存,384位帶寬

從上面能夠看出來,GPU硬件是伴隨着圖形API標準、遊戲一塊兒發展的,而且它們造成了相互相成、相互促進的良性關係。

2.2.2 NV GPU架構發展史

衆所周知,CPU的發展符合摩爾定律:每18個月速度翻倍。

處理芯片晶體管數量符合摩爾定律,圖右是摩爾本人,Intel的創始人

而NVIDIA創始人黃仁勳在不少年前曾信誓旦旦地說,GPU的速度和功能要超越摩爾定律,每6個月就翻一倍。NV的GPU發展史證實,他確實作到了!GPU的提速幅率遠超CPU:

NVIDIA GPU架構歷經屢次變革,從起初的Tesla發展到最新的Turing架構,發展史可分爲如下時間節點:

  • 2008 - Tesla

    Tesla最初是給計算處理單元使用的,應用於早期的CUDA系列顯卡芯片中,並非真正意義上的普通圖形處理芯片。

  • 2010 - Fermi

    Fermi是第一個完整的GPU計算架構。首款可支持與共享存儲結合純cache層次的GPU架構,支持ECC的GPU架構。

  • 2012 - Kepler

    Kepler相較於Fermi更快,效率更高,性能更好。

  • 2014 - Maxwell

    其全新的立體像素全局光照 (VXGI) 技術首次讓遊戲 GPU 可以提供實時的動態全局光照效果。基於 Maxwell 架構的 GTX 980 和 970 GPU 採用了包括多幀採樣抗鋸齒 (MFAA)、動態超級分辨率 (DSR)、VR Direct 以及超節能設計在內的一系列新技術。

  • 2016 - Pascal

    Pascal 架構將處理器和數據集成在同一個程序包內,以實現更高的計算效率。1080系列、1060系列基於Pascal架構

  • 2017 - Volta

    Volta 配備640 個Tensor 核心,每秒可提供超過100 兆次浮點運算(TFLOPS) 的深度學習效能,比前一代的Pascal 架構快5 倍以上。

  • 2018 - Turing

    Turing 架構配備了名爲 RT Core 的專用光線追蹤處理器,可以以高達每秒 10 Giga Rays 的速度對光線和聲音在 3D 環境中的傳播進行加速計算。Turing 架構將實時光線追蹤運算加速至上一代 NVIDIA Pascal™ 架構的 25 倍,並能以高出 CPU 30 多倍的速度進行電影效果的最終幀渲染。2060系列、2080系列顯卡也是跳過了Volta直接選擇了Turing架構。

下圖是部分GPU架構的發展歷程:

2.3 GPU的功能

現代GPU除了繪製圖形外,還擔當了不少額外的功能,綜合起來以下幾方面:

  • 圖形繪製。

    這是GPU最傳統的拿手好戲,也是最基礎、最核心的功能。爲大多數PC桌面、移動設備、圖形工做站提供圖形處理和繪製功能。

  • 物理模擬。

    GPU硬件集成的物理引擎(PhysX、Havok),爲遊戲、電影、教育、科學模擬等領域提供了成百上千倍性能的物理模擬,使得之前須要長時間計算的物理模擬得以實時呈現。

  • 海量計算。

    計算着色器及流輸出的出現,爲各類能夠並行計算的海量需求得以實現,CUDA就是最好的例證。

  • AI運算。

    近年來,人工智能的崛起推進了GPU集成了AI Core運算單元,反哺AI運算能力的提高,給各行各業帶來了計算能力的提高。

  • 其它計算。

    音視頻編解碼、加解密、科學計算、離線渲染等等都離不開現代GPU的並行計算能力和海量吞吐能力。

 

3、GPU物理架構

3.1 GPU宏觀物理結構

因爲納米工藝的引入,GPU能夠將數以億記的晶體管和電子器件集成在一個小小的芯片內。從宏觀物理結構上看,現代大多數桌面級GPU的大小跟數枚硬幣同等大小,部分甚至比一枚硬幣還小(下圖)。

高通驍龍853顯示芯片比硬幣還小

當GPU結合散熱風扇、PCI插槽、HDMI接口等部件以後,就組成了顯卡(下圖)。

顯卡不能獨立工做,須要裝載在主板上,結合CPU、內存、顯存、顯示器等硬件設備,組成完整的PC機。

搭載了顯卡的主板。

3.2 GPU微觀物理結構

GPU的微觀結構因不一樣廠商、不一樣架構都會有所差別,但核心部件、概念、以及運行機制大同小異。下面將展現部分架構的GPU微觀物理結構。

3.2.1 NVidia Tesla架構

Tesla微觀架構總覽圖如上。下面將闡述它的特性和概念:

  • 擁有7組TPC(Texture/Processor Cluster,紋理處理簇)

  • 每一個TPC有兩組SM(Stream Multiprocessor,流多處理器)
  • 每一個SM包含:
    • 6個SP(Streaming Processor,流處理器)
    • 2個SFU(Special Function Unit,特殊函數單元)
    • L1緩存、MT Issue(多線程指令獲取)、C-Cache(常量緩存)、共享內存
  • 除了TPC核心單元,還有與顯存、CPU、系統內存交互的各類部件。

3.2.2 NVidia Fermi架構

Fermi架構如上圖,它的特性以下:

  • 擁有16個SM
  • 每一個SM:
    • 2個Warp(線程束)
    • 兩組共32個Core
    • 16組加載存儲單元(LD/ST)
    • 4個特殊函數單元(SFU)
  • 每一個Warp:
    • 16個Core
    • Warp編排器(Warp Scheduler)
    • 分發單元(Dispatch Unit)
  • 每一個Core:
    • 1個FPU(浮點數單元)
    • 1個ALU(邏輯運算單元)

3.2.3 NVidia Maxwell架構

採用了Maxwell的GM204,擁有4個GPC,每一個GPC有4個SM,對比Tesla架構來講,在處理單元上有了很大的提高。

3.2.4 NVidia Kepler架構

Kepler除了在硬件有了提高,有了更多處理單元以外,還將SM升級到了SMX。SMX是改進的架構,支持動態建立渲染線程(下圖),以下降延遲。

3.2.5 NVidia Turing架構

上圖是採納了Turing架構的TU102 GPU,它的特色以下:

  • 6 GPC(圖形處理簇)
  • 36 TPC(紋理處理簇)
  • 72 SM(流多處理器)
  • 每一個GPC有6個TPC,每一個TPC有2個SM

  • 4,608 CUDA核
  • 72 RT核
  • 576 Tensor核
  • 288 紋理單元
  • 12x32位 GDDR6內存控制器 (共384位)

單個SM的結構圖以下:

每一個SM包含:

  • 64 CUDA核
  • 8 Tensor核
  • 256 KB寄存器文件

TU102 GPU芯片實物圖:

3.3 GPU架構的共性

縱觀上一節的全部GPU架構,能夠發現它們雖然有所差別,但存在着不少相同的概念和部件:

  • GPC
  • TPC
  • Thread
  • SM、SMX、SMM
  • Warp
  • SP
  • Core
  • ALU
  • FPU
  • SFU
  • ROP
  • Load/Store Unit
  • L1 Cache
  • L2 Cache
  • Memory
  • Register File

以上各個部件的用途將在下一章詳細闡述。

GPU爲何會有這麼多層級且有這麼多雷同的部件?答案是GPU的任務是自然並行的,現代GPU的架構皆是以高度並行能力而設計的。

 

4、GPU運行機制

4.1 GPU渲染總覽

由上一章可得知,現代GPU有着類似的結構,有不少相同的部件,在運行機制上,也有不少共同點。下面是Fermi架構的運行機制總覽圖:

從Fermi開始NVIDIA使用相似的原理架構,使用一個Giga Thread Engine來管理全部正在進行的工做,GPU被劃分紅多個GPCs(Graphics Processing Cluster),每一個GPC擁有多個SM(SMX、SMM)和一個光柵化引擎(Raster Engine),它們其中有不少的鏈接,最顯著的是Crossbar,它能夠鏈接GPCs和其它功能性模塊(例如ROP或其餘子系統)。

程序員編寫的shader是在SM上完成的。每一個SM包含許多爲線程執行數學運算的Core(核心)。例如,一個線程能夠是頂點或像素着色器調用。這些Core和其它單元由Warp Scheduler驅動,Warp Scheduler管理一組32個線程做爲Warp(線程束)並將要執行的指令移交給Dispatch Units。

GPU中實際有多少這些單元(每一個GPC有多少個SM,多少個GPC ......)取決於芯片配置自己。例如,GM204有4個GPC,每一個GPC有4個SM,但Tegra X1有1個GPC和2個SM,它們均採用Maxwell設計。SM設計自己(內核數量,指令單位,調度程序......)也隨着時間的推移而發生變化,並幫助使芯片變得如此高效,能夠從高端臺式機擴展到筆記本電腦移動。

如上圖,對於某些GPU(如Fermi部分型號)的單個SM,包含:

  • 32個運算核心 (Core,也叫流處理器Stream Processor)
  • 16個LD/ST(load/store)模塊來加載和存儲數據
  • 4個SFU(Special function units)執行特殊數學運算(sin、cos、log等)
  • 128KB寄存器(Register File)
  • 64KB L1緩存
  • 全局內存緩存(Uniform Cache)
  • 紋理讀取單元
  • 紋理緩存(Texture Cache)
  • PolyMorph Engine:多邊形引擎負責屬性裝配(attribute Setup)、頂點拉取(VertexFetch)、曲面細分、柵格化(這個模塊能夠理解專門處理頂點相關的東西)。
  • 2個Warp Schedulers:這個模塊負責warp調度,一個warp由32個線程組成,warp調度器的指令經過Dispatch Units送到Core執行。

  • 指令緩存(Instruction Cache)
  • 內部連接網絡(Interconnect Network)

4.2 GPU邏輯管線

瞭解上一節的部件和概念以後,能夠深刻闡述GPU的渲染過程和步驟。下面將以Fermi家族的SM爲例,進行邏輯管線的詳細說明。

一、程序經過圖形API(DX、GL、WEBGL)發出drawcall指令,指令會被推送到驅動程序,驅動會檢查指令的合法性,而後會把指令放到GPU能夠讀取的Pushbuffer中。

二、通過一段時間或者顯式調用flush指令後,驅動程序把Pushbuffer的內容發送給GPU,GPU經過主機接口(Host Interface)接受這些命令,並經過前端(Front End)處理這些命令。

三、在圖元分配器(Primitive Distributor)中開始工做分配,處理indexbuffer中的頂點產生三角形分紅批次(batches),而後發送給多個PGCs。這一步的理解就是提交上來n個三角形,分配給這幾個PGC同時處理。

四、在GPC中,每一個SM中的Poly Morph Engine負責經過三角形索引(triangle indices)取出三角形的數據(vertex data),即圖中的Vertex Fetch模塊。

五、在獲取數據以後,在SM中以32個線程爲一組的線程束(Warp)來調度,來開始處理頂點數據。Warp是典型的單指令多線程(SIMT,SIMD單指令多數據的升級)的實現,也就是32個線程同時執行的指令是如出一轍的,只是線程數據不同,這樣的好處就是一個warp只須要一個套邏輯對指令進行解碼和執行就能夠了,芯片能夠作的更小更快,之因此能夠這麼作是因爲GPU須要處理的任務是自然並行的。

六、SM的warp調度器會按照順序分發指令給整個warp,單個warp中的線程會鎖步(lock-step)執行各自的指令,若是線程碰到不激活執行的狀況也會被遮掩(be masked out)。被遮掩的緣由有不少,例如當前的指令是if(true)的分支,可是當前線程的數據的條件是false,或者循環的次數不同(好比for循環次數n不是常量,或被break提早終止了可是別的還在走),所以在shader中的分支會顯著增長時間消耗,在一個warp中的分支除非32個線程都走到if或者else裏面,不然至關於全部的分支都走了一遍,線程不能獨立執行指令而是以warp爲單位,而這些warp之間纔是獨立的。

七、warp中的指令能夠被一次完成,也可能通過屢次調度,例如一般SM中的LD/ST(加載存取)單元數量明顯少於基礎數學操做單元。

八、因爲某些指令比其餘指令須要更長的時間才能完成,特別是內存加載,warp調度器可能會簡單地切換到另外一個沒有內存等待的warp,這是GPU如何克服內存讀取延遲的關鍵,只是簡單地切換活動線程組。爲了使這種切換很是快,調度器管理的全部warp在寄存器文件中都有本身的寄存器。這裏就會有個矛盾產生,shader須要越多的寄存器,就會給warp留下越少的空間,就會產生越少的warp,這時候在碰到內存延遲的時候就會只是等待,而沒有能夠運行的warp能夠切換。

九、一旦warp完成了vertex-shader的全部指令,運算結果會被Viewport Transform模塊處理,三角形會被裁剪而後準備柵格化,GPU會使用L1和L2緩存來進行vertex-shader和pixel-shader的數據通訊。

十、接下來這些三角形將被分割,再分配給多個GPC,三角形的範圍決定着它將被分配到哪一個光柵引擎(raster engines),每一個raster engines覆蓋了多個屏幕上的tile,這等於把三角形的渲染分配到多個tile上面。也就是像素階段就把按三角形劃分變成了按顯示的像素劃分了。

十一、SM上的Attribute Setup保證了從vertex-shader來的數據通過插值後是pixel-shade是可讀的。

十二、GPC上的光柵引擎(raster engines)在它接收到的三角形上工做,來負責這些這些三角形的像素信息的生成(同時會處理裁剪Clipping、背面剔除和Early-Z剔除)。

1三、32個像素線程將被分紅一組,或者說8個2x2的像素塊,這是在像素着色器上面的最小工做單元,在這個像素線程內,若是沒有被三角形覆蓋就會被遮掩,SM中的warp調度器會管理像素着色器的任務。

1四、接下來的階段就和vertex-shader中的邏輯步驟徹底同樣,可是變成了在像素着色器線程中執行。 因爲不耗費任何性能能夠獲取一個像素內的值,致使鎖步執行很是便利,全部的線程能夠保證全部的指令能夠在同一點。

1五、最後一步,如今像素着色器已經完成了顏色的計算還有深度值的計算,在這個點上,咱們必須考慮三角形的原始api順序,而後纔將數據移交給ROP(render output unit,渲染輸入單元),一個ROP內部有不少ROP單元,在ROP單元中處理深度測試,和framebuffer的混合,深度和顏色的設置必須是原子操做,不然兩個不一樣的三角形在同一個像素點就會有衝突和錯誤。

4.3 GPU技術要點

因爲上一節主要闡述GPU內部的工做流程和機制,爲了簡潔性,省略了不少知識點和過程,本節將對它們作進一步補充說明。

4.3.1 SIMD和SIMT

SIMD(Single Instruction Multiple Data)是單指令多數據,在GPU的ALU單元內,一條指令能夠處理多維向量(通常是4D)的數據。好比,有如下shader指令:

float4 c = a + b; // a, b都是float4類型

對於沒有SIMD的處理單元,須要4條指令將4個float數值相加,彙編僞代碼以下:

ADD c.x, a.x, b.x
ADD c.y, a.y, b.y
ADD c.z, a.z, b.z
ADD c.w, a.w, b.w

但有了SIMD技術,只需一條指令便可處理完:

SIMD_ADD c, a, b

SIMT(Single Instruction Multiple Threads,單指令多線程)是SIMD的升級版,可對GPU中單個SM中的多個Core同時處理同一指令,而且每一個Core存取的數據能夠是不一樣的。

SIMT_ADD c, a, b

上述指令會被同時送入在單個SM中被編組的全部Core中,同時執行運算,但abc的值能夠不同:

4.3.2 co-issue

co-issue是爲了解決SIMD運算單元沒法充分利用的問題。例以下圖,因爲float數量的不一樣,ALU利用率從100%依次降低爲75%、50%、25%。

爲了解決着色器在低維向量的利用率低的問題,能夠經過合併1D與3D或2D與2D的指令。例以下圖,DP3指令用了3D數據,ADD指令只有1D數據,co-issue會自動將它們合併,在同一個ALU只需一個指令週期便可執行完。

可是,對於向量運算單元(Vector ALU),若是其中一個變量既是操做數又是存儲數的狀況,沒法啓用co-issue技術:

因而標量指令着色器(Scalar Instruction Shader)應運而生,它能夠有效地組合任何向量,開啓co-issue技術,充分發揮SIMD的優點。

4.3.3 if - else語句

如上圖,SM中有8個ALU(Core),因爲SIMD的特性,每一個ALU的數據不同,致使if-else語句在某些ALU中執行的是true分支(黃色),有些ALU執行的是false分支(灰藍色),這樣致使不少ALU的執行週期被浪費掉了(即masked out),拉長了整個執行週期。最壞的狀況,同一個SM中只有1/8(8是同一個SM的線程數,不一樣架構的GPU有所不一樣)的利用率。

一樣,for循環也會致使相似的情形,例如如下shader代碼:

void func(int count, int breakNum)
{
    for(int i=0; i<count; ++i)
    {
        if (i == breakNum)
            break;
        else
            // do something
    }
}

因爲每一個ALU的count不同,加上有break分支,致使最快執行完shader的ALU多是最慢的N分之一的時間,但因爲SIMD的特性,最快的那個ALU依然要等待最慢的ALU執行完畢,才能接下一組指令的活!也就白白浪費了不少時間週期。

4.3.4 Early-Z

早期GPU的渲染管線的深度測試是在像素着色器以後才執行(下圖),這樣會形成不少本不可見的像素執行了耗性能的像素着色器計算。

後來,爲了減小像素着色器的額外消耗,將深度測試提至像素着色器以前(下圖),這就是Early-Z技術的由來。

Early-Z技術能夠將不少無效的像素提早剔除,避免它們進入耗時嚴重的像素着色器。Early-Z剔除的最小單位不是1像素,而是像素塊(pixel quad,2x2個像素,詳見4.3.6)。

可是,如下狀況會致使Early-Z失效:

  • 開啓Alpha Test:因爲Alpha Test須要在像素着色器後面的Alpha Test階段比較,因此沒法在像素着色器以前就決定該像素是否被剔除。
  • 開啓Alpha Blend:啓用了Alpha混合的像素不少須要與frame buffer作混合,沒法執行深度測試,也就沒法利用Early-Z技術。
  • 開啓Tex Kill:即在shader代碼中有像素摒棄指令(DX的discard,OpenGL的clip)。
  • 關閉深度測試。Early-Z是創建在深度測試看開啓的條件下,若是關閉了深度測試,也就沒法啓用Early-Z技術。
  • 開啓Multi-Sampling:多采樣會影響周邊像素,而Early-Z階段沒法得知周邊像素是否被裁剪,故沒法提早剔除。
  • 以及其它任何致使須要混合後面顏色的操做。

此外,Early-Z技術會致使一個問題:深度數據衝突(depth data hazard)。

例子要結合上圖,假設數值深度值5已經通過Early-Z即將寫入Frame Buffer,而深度值10恰好處於Early-Z階段,讀取並對比當前緩存的深度值15,結果就是10經過了Early-Z測試,會覆蓋掉比本身小的深度值5,最終frame buffer的深度值是錯誤的結果。

避免深度數據衝突的方法之一是在寫入深度值以前,再次與frame buffer的值進行對比:

4.3.5 統一着色器架構(Unified shader Architecture)

在早期的GPU,頂點着色器和像素着色器的硬件結構是獨立的,它們各有各的寄存器、運算單元等部件。這樣不少時候,會形成頂點着色器與像素着色器之間任務的不平衡。對於頂點數量多的任務,像素着色器空閒狀態多;對於像素多的任務,頂點着色器的空閒狀態多(下圖)。

因而,爲了解決VS和PS之間的不平衡,引入了統一着色器架構(Unified shader Architecture)。用了此架構的GPU,VS和PS用的都是相同的Core。也就是,同一個Core既能夠是VS又能夠是PS。

這樣就解決了不一樣類型着色器之間的不平衡問題,還能夠減小GPU的硬件單元,壓縮物理尺寸和耗電量。此外,VS、PS可還能夠和其它着色器(幾何、曲面、計算)統一爲一體。

4.3.6 像素塊(Pixel Quad)

上一節步驟13提到:

32個像素線程將被分紅一組,或者說8個2x2的像素塊,這是在像素着色器上面的最小工做單元,在這個像素線程內,若是沒有被三角形覆蓋就會被遮掩,SM中的warp調度器會管理像素着色器的任務。

也就是說,在像素着色器中,會將相鄰的四個像素做爲不可分隔的一組,送入同一個SM內4個不一樣的Core。

爲何像素着色器處理的最小單元是2x2的像素塊?

筆者推測有如下緣由:

一、簡化和加速像素分派的工做。

二、精簡SM的架構,減小硬件單元數量和尺寸。

三、下降功耗,提升效能比。

四、無效像素雖然不會被存儲結果,但可輔助有效像素求導函數。詳見4.6 利用擴展例證

這種設計雖然有其優點,但同時,也會激化過繪製(Over Draw)的狀況,損耗額外的性能。好比下圖中,白色的三角形只佔用了3個像素(綠色),按咱們普通的思惟,只須要3個Core繪製3次就能夠了。

可是,因爲上面的3個像素分別佔據了不一樣的像素塊(橙色分隔),實際上須要佔用12個Core繪製12次(下圖)。

這就會額外消耗300%的硬件性能,致使了更加嚴重的過繪製狀況。

更多詳情能夠觀看虛幻官方的視頻教學:實時渲染深刻探究

4.4 GPU資源機制

本節將闡述GPU的內存訪問、資源管理等機制。

4.4.1 內存架構

部分架構的GPU與CPU相似,也有多級緩存結構:寄存器、L1緩存、L2緩存、GPU顯存、系統顯存。

它們的存取速度從寄存器到系統內存依次變慢:

存儲類型 寄存器 共享內存 L1緩存 L2緩存 紋理、常量緩存 全局內存
訪問週期 1 1~32 1~32 32~64 400~600 400~600

因而可知,shader直接訪問寄存器、L一、L2緩存仍是比較快的,但訪問紋理、常量緩存和全局內存很是慢,會形成很高的延遲。

上面的多級緩存結構可被稱爲「CPU-Style」,還存在GPU-Style的內存架構:

這種架構的特色是ALU多,GPU上下文(Context)多,吞吐量高,依賴高帶寬與系統內存交換數據。

4.4.2 GPU Context和延遲

因爲SIMT技術的引入,致使不少同一個SM內的不少Core並非獨立的,當它們當中有部分Core須要訪問到紋理、常量緩存和全局內存時,就會致使很是大的卡頓(Stall)。

例以下圖中,有4組上下文(Context),它們共用同一組運算單元ALU。

假設第一組Context須要訪問緩存或內存,會致使2~3個週期的延遲,此時調度器會激活第二組Context以利用ALU:

當第二組Context訪問緩存或內存又卡住,會依次激活第3、第四組Context,直到第一組Context恢復運行或全部都被激活:

延遲的後果是每組Context的整體執行時間被拉長了:

可是,越多Context可用就越能夠提高運算單元的吞吐量,好比下圖的18組Context的架構能夠最大化地提高吞吐量:

4.4.3 CPU-GPU異構系統

根據CPU和GPU是否共享內存,可分爲兩種類型的CPU-GPU架構:

上圖左是分離式架構,CPU和GPU各自有獨立的緩存和內存,它們經過PCI-e等總線通信。這種結構的缺點在於 PCI-e 相對於二者具備低帶寬和高延遲,數據的傳輸成了其中的性能瓶頸。目前使用很是普遍,如PC、智能手機等。

上圖右是耦合式架構,CPU 和 GPU 共享內存和緩存。AMD 的 APU 採用的就是這種結構,目前主要使用在遊戲主機中,如 PS4。

在存儲管理方面,分離式結構中 CPU 和 GPU 各自擁有獨立的內存,二者共享一套虛擬地址空間,必要時會進行內存拷貝。對於耦合式結構,GPU 沒有獨立的內存,與 GPU 共享系統內存,由 MMU 進行存儲管理。

4.4.4 GPU資源管理模型

下圖是分離式架構的資源管理模型:

  • MMIO(Memory Mapped IO)

    • CPU與GPU的交流就是經過MMIO進行的。CPU 經過 MMIO 訪問 GPU 的寄存器狀態。
    • DMA傳輸大量的數據就是經過MMIO進行命令控制的。
    • I/O端口可用於間接訪問MMIO區域,像Nouveau等開源軟件歷來不訪問它。
  • GPU Context

    • GPU Context表明了GPU計算的狀態。
    • 在GPU中擁有本身的虛擬地址。
    • GPU 中能夠並存多個活躍態下的Context。
  • GPU Channel

    • 任何命令都是由CPU發出。
    • 命令流(command stream)被提交到硬件單元,也就是GPU Channel。
    • 每一個GPU Channel關聯一個context,而一個GPU Context能夠有多個GPU channel。
    • 每一個GPU Context 包含相關channel的 GPU Channel Descriptors , 每一個 Descriptor 都是 GPU 內存中的一個對象。
    • 每一個 GPU Channel Descriptor 存儲了 Channel 的設置,其中就包括 Page Table 。
    • 每一個 GPU Channel 在GPU內存中分配了惟一的命令緩存,這經過MMIO對CPU可見。
    • GPU Context Switching 和命令執行都在GPU硬件內部調度。
  • GPU Page Table

    • GPU Context在虛擬基地空間由Page Table隔離其它的Context 。
    • GPU Page Table隔離CPU Page Table,位於GPU內存中。
    • GPU Page Table的物理地址位於 GPU Channel Descriptor中。
    • GPU Page Table不只僅將 GPU虛擬地址轉換成GPU內存的物理地址,也能夠轉換成CPU的物理地址。所以,GPU Page Table能夠將GPU虛擬地址和CPU內存地址統一到GPU統一虛擬地址空間來。
  • PCI-e BAR

    • GPU 設備經過PCI-e總線接入到主機上。 Base Address Registers(BARs) 是 MMIO的窗口,在GPU啓動時候配置。
    • GPU的控制寄存器和內存都映射到了BARs中。
    • GPU設備內存經過映射的MMIO窗口去配置GPU和訪問GPU內存。
  • PFIFO Engine

    • PFIFO是GPU命令提交經過的一個特殊的部件。
    • PFIFO維護了一些獨立命令隊列,也就是Channel。
    • 此命令隊列是Ring Buffer,有PUT和GET的指針。
    • 全部訪問Channel控制區域的執行指令都被PFIFO 攔截下來。
    • GPU驅動使用Channel Descriptor來存儲相關的Channel設定。
    • PFIFO將讀取的命令轉交給PGRAPH Engine。
  • BO

    • Buffer Object (BO),內存的一塊(Block),可以用於存儲紋理(Texture)、渲染目標(Render Target)、着色代碼(shader code)等等。

    • Nouveau和Gdev常用BO。

      Nouveau是一個自由及開放源代碼顯卡驅動程序,是爲NVidia的顯卡所編寫。

      Gdev是一套豐富的開源軟件,用於NVIDIA的GPGPU技術,包括設備驅動程序。

更多詳細能夠閱讀論文:Data Transfer Matters for GPU Computing

4.4.5 CPU-GPU數據流

下圖是分離式架構的CPU-GPU的數據流程圖:

一、將主存的處理數據複製到顯存中。

二、CPU指令驅動GPU。

三、GPU中的每一個運算單元並行處理。此步會從顯存存取數據。

四、GPU將顯存結果傳回主存。

4.4.6 顯像機制

  • 水平和垂直同步信號

    在早期的CRT顯示器,電子槍從上到下逐行掃描,掃描完成後顯示器就呈現一幀畫面。而後電子槍回到初始位置進行下一次掃描。爲了同步顯示器的顯示過程和系統的視頻控制器,顯示器會用硬件時鐘產生一系列的定時信號。

    當電子槍換行進行掃描時,顯示器會發出一個水平同步信號(horizonal synchronization),簡稱 HSync

    當一幀畫面繪製完成後,電子槍回覆到原位,準備畫下一幀前,顯示器會發出一個垂直同步信號(vertical synchronization),簡稱 VSync

    顯示器一般以固定頻率進行刷新,這個刷新率就是 VSync 信號產生的頻率。雖然如今的顯示器基本都是液晶顯示屏了,但其原理基本一致。

    CPU將計算好顯示內容提交至 GPU,GPU 渲染完成後將渲染結果存入幀緩衝區,視頻控制器會按照 VSync 信號逐幀讀取幀緩衝區的數據,通過數據轉換後最終由顯示器進行顯示。

  • 雙緩衝

    在單緩衝下,幀緩衝區的讀取和刷新都都會有比較大的效率問題,常常會出現相互等待的狀況,致使幀率降低。

    爲了解決效率問題,GPU 一般會引入兩個緩衝區,即 雙緩衝機制。在這種狀況下,GPU 會預先渲染一幀放入一個緩衝區中,用於視頻控制器的讀取。當下一幀渲染完畢後,GPU 會直接把視頻控制器的指針指向第二個緩衝器。

  • 垂直同步

    雙緩衝雖然能解決效率問題,但會引入一個新的問題。當視頻控制器還未讀取完成時,即屏幕內容剛顯示一半時,GPU 將新的一幀內容提交到幀緩衝區並把兩個緩衝區進行交換後,視頻控制器就會把新的一幀數據的下半段顯示到屏幕上,形成畫面撕裂現象:

    爲了解決這個問題,GPU 一般有一個機制叫作垂直同步(簡寫也是V-Sync),當開啓垂直同步後,GPU 會等待顯示器的 VSync 信號發出後,才進行新的一幀渲染和緩衝區更新。這樣能解決畫面撕裂現象,也增長了畫面流暢度,但須要消費更多的計算資源,也會帶來部分延遲。

4.5 Shader運行機制

Shader代碼也跟傳統的C++等語言相似,須要將面向人類的高級語言(GLSL、HLSL、CGSL)經過編譯器轉成面向機器的二進制指令,二進制指令可轉譯成彙編代碼,以便技術人員查閱和調試。

由高級語言編譯成彙編指令的過程一般是在離線階段執行,以減輕運行時的消耗。

在執行階段,CPU端將shader二進制指令經由PCI-e推送到GPU端,GPU在執行代碼時,會用Context將指令分紅若干Channel推送到各個Core的存儲空間。

對現代GPU而言,可編程的階段愈來愈多,包含但不限於:頂點着色器(Vertex Shader)、曲面細分控制着色器(Tessellation Control Shader)、幾何着色器(Geometry Shader)、像素/片元着色器(Fragment Shader)、計算着色器(Compute Shader)、...

這些着色器造成流水線式的並行化的渲染管線。下面將配合具體的例子說明。

下段是計算漫反射的經典代碼:

sampler mySamp;
Texture2D<float3> myTex;
float3 lightDir;

float4 diffuseShader(float3 norm, float2 uv)
{
    float3 kd;
    kd = myTex.Sample(mySamp, uv);
    kd *= clamp( dot(lightDir, norm), 0.0, 1.0);
    return float4(kd, 1.0);
}

通過編譯後成爲彙編代碼:

<diffuseShader>:
sample r0, v4, t0, s0
mul    r3, v0, cb0[0]
madd   r3, v1, cb0[1], r3
madd   r3, v2, cb0[2], r3
clmp   r3, r3, l(0.0), l(1.0)
mul    o0, r0, r3
mul    o1, r1, r3
mul    o2, r2, r3
mov    o3, l(1.0)

在執行階段,以上彙編代碼會被GPU推送到執行上下文(Execution Context),而後ALU會逐條獲取(Detch)、解碼(Decode)彙編指令,並執行它們。

以上示例圖只是單個ALU的執行狀況,實際上,GPU有幾十甚至上百個執行單元在同時執行shader指令:

對於SIMT架構的GPU,彙編指令有所不一樣,變成了SIMT特定指令代碼:

<VEC8_diffuseShader>: 
VEC8_sample vec_r0, vec_v4, t0, vec_s0 
VEC8_mul    vec_r3, vec_v0, cb0[0] 
VEC8_madd   vec_r3, vec_v1, cb0[1], vec_r3 
VEC8_madd   vec_r3, vec_v2, cb0[2], vec_r3
VEC8_clmp   vec_r3, vec_r3, l(0.0), l(1.0) 
VEC8_mul    vec_o0, vec_r0, vec_r3 
VEC8_mul    vec_o1, vec_r1, vec_r3 
VEC8_mul    vec_o2, vec_r2, vec_r3 
VEC8_mov    o3, l(1.0)

而且Context以Core爲單位組成共享的結構,同一個Core的多個ALU共享一組Context:

若是有多個Core,就會有更多的ALU同時參與shader計算,每一個Core執行的數據是不同的,多是頂點、圖元、像素等任何數據:

4.6 利用擴展例證

NV shader thread group提供了OpenGL的擴展,能夠查詢GPU線程、Core、SM、Warp等硬件相關的屬性。若是要開啓次此擴展,須要知足如下條件:

  • OpenGL 4.3+;
  • GLSL 4.3+;
  • 支持OpenGL 4.3+的NV顯卡;

而且此擴展只在NV部分5代着色器內起做用:

This extension interacts with NV_gpu_program5
This extension interacts with NV_compute_program5
This extension interacts with NV_tessellation_program5

下面是具體的字段和表明的意義:

// 開啓擴展
#extension GL_NV_shader_thread_group : require     (or enable)

WARP_SIZE_NV    // 單個線程束的線程數量
WARPS_PER_SM_NV // 單個SM的線程束數量
SM_COUNT_NV     // SM數量

uniform uint  gl_WarpSizeNV;    // 單個線程束的線程數量
uniform uint  gl_WarpsPerSMNV;  // 單個SM的線程束數量
uniform uint  gl_SMCountNV;     // SM數量

in uint  gl_WarpIDNV;       // 當前線程束id
in uint  gl_SMIDNV;         // 當前線程束所在的SM id,取值[0, gl_SMCountNV-1]
in uint  gl_ThreadInWarpNV; // 當前線程id,取值[0, gl_WarpSizeNV-1]

in uint  gl_ThreadEqMaskNV; // 是否等於當前線程id的位域掩碼。
in uint  gl_ThreadGeMaskNV; // 是否大於等於當前線程id的位域掩碼。
in uint  gl_ThreadGtMaskNV; // 是否大於當前線程id的位域掩碼。
in uint  gl_ThreadLeMaskNV; // 是否小於等於當前線程id的位域掩碼。
in uint  gl_ThreadLtMaskNV; // 是否小於當前線程id的位域掩碼。

in bool  gl_HelperThreadNV; // 當前線程是否協助型線程。

上述所說的協助型線程gl_HelperThreadNV是指在處理2x2的像素塊時,那些未被圖元覆蓋的像素着色器線程將被標記爲gl_HelperThreadNV = true,它們的結果將被忽略,也不會被存儲,但可輔助一些計算,如導數dFdxdFdy。爲了防止理解有誤,貼出原文:

The variable gl_HelperThreadNV specifies if the current thread is a helper thread. In implementations supporting this extension, fragment shader invocations may be arranged in SIMD thread groups of 2x2 fragments called "quad". When a fragment shader instruction is executed on a quad, it's possible that some fragments within the quad will execute the instruction even if they are not covered by the primitive. Those threads are called helper threads. Their outputs will be discarded and they will not execute global store functions, but the intermediate values they compute can still be used by thread group sharing functions or by fragment derivative functions like dFdx and dFdy.

利用以上字段,能夠編寫特殊shader代碼轉成顏色信息,以即可視化窺探GPU的工做機制和流程。

利用NV擴展字段,可視化了頂點着色器、像素着色器的SM、Warp id,爲咱們查探GPU的工做機制和流程提供了途徑。

下面正式進入驗證階段,將以Geforce RTX 2060做爲驗證對象,具體信息以下:

操做系統: Windows 10 Pro, 64-bit

DirectX 版本: 12.0
GPU 處理器: GeForce RTX 2060
驅動程序版本: 417.71
Driver Type: Standard
Direct3D API 版本: 12
Direct3D 功能級別:12_1

CUDA 核心: 1920
核心時鐘: 1710 MHz
內存數據速率: 14.00 Gbps
內存接口: 192-位
內存帶寬: 336.05 GB/秒
所有可用的圖形內存:22494MB
專用視頻內存: 6144 MB GDDR6
系統視頻內存: 0MB
共享系統內存: 16350MB
視頻 BIOS 版本: 90.06.3F.00.73
IRQ: Not used
總線: PCI Express x16 Gen3

首先在應用程序建立包含兩個三角形的頂點數據:

// set up vertex data (and buffer(s)) and configure vertex attributes
const float HalfSize = 1.0f;
float vertices[] = {
    -HalfSize, -HalfSize, 0.0f, // left bottom
    HalfSize, -HalfSize, 0.0f,  // right bottom
    -HalfSize,  HalfSize, 0.0f, // top left

    -HalfSize,  HalfSize, 0.0f, // top left
    HalfSize, -HalfSize, 0.0f,  // right bottom
    HalfSize,  HalfSize, 0.0f,  // top right
};

渲染採用的頂點着色器很是簡單:

#version 430 core

layout (location = 0) in vec3 aPos;

void main()
{
    gl_Position = vec4(aPos, 1.0f);
}

片元着色器也是寥寥數行:

#version 430 core

out vec4 FragColor;

void main()
{
    FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}

繪製出來的原始畫面以下:

緊接着,修改片元着色器,加入擴展所需的代碼,並修改顏色計算:

#version 430 core
#extension GL_NV_shader_thread_group : require

uniform uint  gl_WarpSizeNV;    // 單個線程束的線程數量
uniform uint  gl_WarpsPerSMNV;  // 單個SM的線程束數量
uniform uint  gl_SMCountNV;     // SM數量

in uint  gl_WarpIDNV;       // 當前線程束id
in uint  gl_SMIDNV;         // 當前線程所在的SM id,取值[0, gl_SMCountNV-1]
in uint  gl_ThreadInWarpNV; // 當前線程id,取值[0, gl_WarpSizeNV-1]

out vec4 FragColor;

void main()
{
    // SM id
    float lightness = gl_SMIDNV / gl_SMCountNV;
    FragColor = vec4(lightness);
}

由上面的代碼渲染的畫面以下:

從上面可分析出一些信息:

  • 畫面共有32個亮度色階,也就是Geforce RTX 2060有32個SM。
  • 單個SM每次渲染16x16爲單位的像素塊,也就是每一個SM有256個Core。
  • SM之間不是順序分配像素塊,而是無序分配。
  • 不一樣三角形的接縫處出現斷層,說明同一個像素塊若是分屬不一樣的三角形,就會分配到不一樣的SM進行處理。由此推斷,相同面積的區域,若是所屬的三角形越多,就會致使分配給SM的次數越多,消耗的渲染性能也越多

接着修改片元着色器的顏色計算代碼以顯示Warp id:

// warp id
float lightness = gl_WarpIDNV / gl_WarpsPerSMNV;
FragColor = vec4(lightness);

獲得以下畫面:

由此可得出一些信息或推論:

  • 畫面共有32個亮度色階,也就是每一個SM有32個Warp,每一個Warp有8個Core。

  • 每一個色塊像素是4x8,因爲每一個Warp有8個Core,由此推斷每一個Core單次要處理2x2的最小單元像素塊。

  • 也是無序分配像素塊。
  • 三角形接縫處出現斷層,同SM的推斷一致。

再修改片元着色器的顏色計算代碼以顯示線程id:

// thread id
float lightness = gl_ThreadInWarpNV / gl_WarpSizeNV;
FragColor = vec4(lightness);

獲得以下畫面:

爲了方便分析,用Photoshop對中間局部放大10倍,獲得如下畫面:

結合上面兩幅圖,也能夠得出一些結論:

  • 相較SM、線程束,線程分佈圖比較規律。說明同一個Warp的線程分佈是規律的。
  • 三角形接縫處出現紊亂,說明是不一樣的Warp形成了不一樣的線程。
  • 畫面有32個色階,說明單個Warp有32個線程。
  • 每一個像素獨佔一個亮度色階,與周邊相鄰像素都不一樣,說明每一個線程只處理一個像素。

再次說明,以上畫面和結論是基於Geforce RTX 2060,不一樣型號的GPU可能會不同,獲得的結果和推論也會有所不一樣。

更多NV擴展可參見OpenGL官網:NV extensions

 

5、總結

5.1 CPU vs GPU

CPU和GPU的差別能夠描述在下面表格中:

CPU GPU
延遲容忍度
並行目標 任務(Task) 數據(Data)
核心架構 多線程核心 SIMT核心
線程數量級別 10 10000
吞吐量
緩存需求量
線程獨立性

它們之間的差別(緩存、核心數量、內存、線程數等)可用下圖展現出來:

5.2 渲染優化建議

由上章的分析,能夠很容易給出渲染優化建議:

  • 減小CPU和GPU的數據交換:
    • 合批(Batch)
    • 減小頂點數、三角形數
    • 視錐裁剪
      • BVH
      • Portal
      • BSP
      • OSP
    • 避免每幀提交Buffer數據
      • CPU版的粒子、動畫會每幀修改、提交數據,可移至GPU端。
    • 減小渲染狀態設置和查詢
      • 例如:glGetUniformLocation會從GPU內存查詢狀態,耗費不少時間週期。
      • 避免每幀設置、查詢渲染狀態,可在初始化時緩存狀態。
    • 啓用GPU Instance
    • 開啓LOD
    • 避免從顯存讀數據
  • 減小過繪製:
    • 避免Tex Kill操做
    • 避免Alpha Test
    • 避免Alpha Blend
    • 開啓深度測試
      • Early-Z
      • 層次Z緩衝(Hierarchical Z-Buffering,HZB)
    • 開啓裁剪:
      • 背面裁剪
      • 遮擋裁剪
      • 視口裁剪
      • 剪切矩形(scissor rectangle)
    • 控制物體數量
      • 粒子數量多且面積小,因爲像素塊機制,會加重過繪製狀況
      • 植物、沙石、毛髮等也如此
  • Shader優化:
    • 避免if、switch分支語句
    • 避免for循環語句,特別是循環次數可變的
    • 減小紋理採樣次數
    • 禁用clipdiscard操做
    • 減小複雜數學函數調用

更多優化技巧可閱讀:

5.3 GPU的將來

從章節2.2 GPU歷史能夠得出一些結論,也能夠推測GPU發展的趨勢:

  • 硬件升級。更多運算單元,更多存儲空間,更高併發,更高帶寬,更低延時。。。

  • Tile-Based Rendering的集成。基於瓦片的渲染能夠必定程度下降帶寬和提高光照計算效率,目前部分移動端及桌面的GPU已經引入這個技術,將來將有望成爲常態。

  • 3D內存技術。目前大多數傳統的內存是2D的,3D內存則不一樣,在物理結構上是3D的,相似立方體結構,集成於芯片內。可得到幾倍的訪問速度和效能比。

  • GPU越發可編程化。GPU天生是並行且相對固定的,將來將會開放愈來愈多的shader可供編程,而CPU恰好相反,將往並行化發展。也就是說,將來的GPU愈來愈像CPU,而CPU愈來愈像GPU。難道它們應驗了古語:合久必分,分久必合麼?

  • 實時光照追蹤的普及。基於Turing架構的GPU已經加入大量RT Core、HVB、AI降噪等技術,Hybrid Rendering Pipeline就是此架構的光線追蹤渲染管線,可以同時結合光柵化器、RT Core、Compute Core執行混合渲染:

    Hybrid Rendering Pipeline至關於光線追蹤渲染管線和光柵化渲染管線的合體:

  • 數據併發提高、深度神經網絡、GPU計算單元等普及及提高

  • AI降噪和AI抗鋸齒。AI降噪已經在部分RTX系列的光線追蹤版本獲得應用,而AI抗鋸齒(Super Res)可用於超高分辨率的視頻圖像抗鋸齒:

  • 基於任務和網格着色器的渲染管線。基於任務和網格着色器的渲染管線(Graphics Pipeline with Task and Mesh Shaders)與傳統的光柵化渲染光線有着很大的差別,它以線程組(Thread Group)、任務着色器(Task shader)和網格着色器(Mesh shader)爲基礎,造成一種全新的渲染管線:

    關於此技術的更多詳情可閱讀:NVIDIA Turing Architecture Whitepaper

  • 可變速率着色(Variable Rate Shading)。可變利率着色技術可判斷畫面區域的重要性(或由應用程序指定),而後根據畫面區域的重要性程度採用不一樣的着色分辨率精度,能夠顯著下降功耗,提升着色效率。

5.4 結語

本文系統地講解了GPU的歷史、發展、工做流程,以及部分過程的細化說明和用到的各類技術,咱們從中能夠看到GPU架構的動機、機制、瓶頸,以及將來的發展。

但願看完本文,你們能很好地回答導言提出的問題:1.3 帶着問題閱讀。若是不能所有回答,也不要緊,回頭看相關章節,總能找到答案。

若是想更深刻地瞭解GPU的設計細節、實現細節,可閱讀GPU廠商按期發佈的白皮書和各大高校、機構發佈的論文。推薦一個GPU解說視頻:A trip through the Graphics Pipeline 2011: Index,雖然是多年前的視頻,但比較系統、全面地講解了GPU的機制和技術。

 

特別說明

  • 感謝全部參考文獻的做者們!

  • 原創文章,未經許可,禁止轉載!

 

參考文獻

相關文章
相關標籤/搜索