計算機那些事(8)——圖形渲染原理

原文連接html

最近在 iOS 開發中作了較多動畫相關的編程工做。所以想借此機會深刻了解了一下 iOS 動畫及渲染相關原理。隨着對相關方面的深刻了解,發現這裏面涉及到從硬件底層到軟件框架等一系列相關知識。ios

本文將從相對底層的角度對計算圖形渲染原理進行簡要介紹,以做爲後續的知識儲備。git

引言

做爲程序員,咱們或多或少知道可視化應用程序都是由 CPU 和 GPU 協做執行的。那麼咱們就先來了解一下二者的基本概念:程序員

  • CPU(Central Processing Unit):現代計算機的三大核心部分之一,做爲整個系統的運算和控制單元。CPU 內部的流水線結構使其擁有必定程度的並行計算能力。
  • GPU(Graphics Processing Unit):一種可進行繪圖運算工做的專用微處理器。GPU 可以生成 2D/3D 的圖形圖像和視頻,從而可以支持基於窗口的操做系統、圖形用戶界面、視頻遊戲、可視化圖像應用和視頻播放。GPU 具備很是強的並行計算能力。

這時候可能會產生一個問題:CPU 難道不能代替 GPU 來進行圖形渲染嗎?答案固然是確定的,不過在看了下面這個視頻就明白爲何要用 GPU 來進行圖形渲染了。github

GPU CPU 模擬繪圖視頻spring

使用 GPU 渲染圖形的根本緣由就是:速度。GPU 的並行計算能力使其可以快速將圖形結果計算出來並在屏幕的全部像素中進行顯示。編程

那麼像素是如何繪製在屏幕上的?計算機將存儲在內存中的形狀轉換成實際繪製在屏幕上的對應的過程稱爲 渲染。渲染過程當中最經常使用的技術就是 光柵化segmentfault

關於光柵化的概念,如下圖爲例,假若有一道綠光與存儲在內存中的一堆三角形中的某一個在三維空間座標中存在相交的關係。那麼這些處於相交位置的像素都會被繪製到屏幕上。固然這些三角形在三維空間中的先後關係也會以遮擋或部分遮擋的形式在屏幕上呈現出來。一句話總結:光柵化就是將數據轉化成可見像素的過程。數組

GPU 則是執行轉換過程的硬件部件。因爲這個過程涉及到屏幕上的每個像素,因此 GPU 被設計成了一個高度並行化的硬件部件。緩存

下面,咱們來簡單瞭解一下 GPU 的歷史。

GPU 歷史

GPU 還未出現前,PC 上的圖形操做是由 視頻圖形陣列(VGA,Video Graphics Array) 控制器完成。VGA 控制器由鏈接到必定容量的DRAM上的存儲控制器和顯示產生器構成。

1997 年,VGA 控制器開始具有一些 3D 加速功能,包括用於 三角形生成光柵化紋理貼圖陰影

2000 年,一個單片處圖形處理器繼承了傳統高端工做站圖形流水線的幾乎每個細節。所以誕生了一個新的術語 GPU 用來表示圖形設備已經變成了一個處理器。

隨着時間的推移,GPU 的可編程能力愈發強大,其做爲可編程處理器取代了固定功能的專用邏輯,同時保持了基本的 3D 圖形流水線組織。

近年來,GPU 增長了處理器指令和存儲器硬件,以支持通用編程語言,並創立了一種編程環境,從而容許使用熟悉的語言(包括 C/C++)對 GPU 進行編程。

現在,GPU 及其相關驅動實現了圖形處理中的 OpenGLDirectX 模型,從而容許開發者可以輕易地操做硬件。OpenGL 嚴格來講並非常規意義上的 API,而是一個第三方標準(由 khronos 組織制定並維護),其嚴格定義了每一個函數該如何執行,以及它們的輸出值。至於每一個函數內部具體是如何實現的,則由 OpenGL 庫的開發者自行決定。實際 OpenGL 庫的開發者一般是顯卡的生產商。DirectX 則是由 Microsoft 提供一套第三方標準。

GPU 圖形渲染流水線

GPU 圖形渲染流水線的主要工做能夠被劃分爲兩個部分:

  • 把 3D 座標轉換爲 2D 座標
  • 把 2D 座標轉變爲實際的有顏色的像素

GPU 圖形渲染流水線的具體實現可分爲六個階段,以下圖所示。

  • 頂點着色器(Vertex Shader)
  • 形狀裝配(Shape Assembly),又稱 圖元裝配
  • 幾何着色器(Geometry Shader)
  • 光柵化(Rasterization)
  • 片斷着色器(Fragment Shader)
  • 測試與混合(Tests and Blending)

第一階段,頂點着色器。該階段的輸入是 頂點數據(Vertex Data) 數據,好比以數組的形式傳遞 3 個 3D 座標用來表示一個三角形。頂點數據是一系列頂點的集合。頂點着色器主要的目的是把 3D 座標轉爲另外一種 3D 座標,同時頂點着色器能夠對頂點屬性進行一些基本處理。

第二階段,形狀(圖元)裝配。該階段將頂點着色器輸出的全部頂點做爲輸入,並將全部的點裝配成指定圖元的形狀。圖中則是一個三角形。圖元(Primitive) 用於表示如何渲染頂點數據,如:點、線、三角形。

第三階段,幾何着色器。該階段把圖元形式的一系列頂點的集合做爲輸入,它能夠經過產生新頂點構造出新的(或是其它的)圖元來生成其餘形狀。例子中,它生成了另外一個三角形。

第四階段,光柵化。該階段會把圖元映射爲最終屏幕上相應的像素,生成片斷。片斷(Fragment) 是渲染一個像素所須要的全部數據。

第五階段,片斷着色器。該階段首先會對輸入的片斷進行 裁切(Clipping)。裁切會丟棄超出視圖之外的全部像素,用來提高執行效率。

第六階段,測試與混合。該階段會檢測片斷的對應的深度值(z 座標),判斷這個像素位於其它物體的前面仍是後面,決定是否應該丟棄。此外,該階段還會檢查 alpha 值( alpha 值定義了一個物體的透明度),從而對物體進行混合。所以,即便在片斷着色器中計算出來了一個像素輸出的顏色,在渲染多個三角形的時候最後的像素顏色也可能徹底不一樣。

關於混合,GPU 採用以下公式進行計算,並得出最後的顏色。

R = S + D * (1 - Sa)
複製代碼

關於公式的含義,假設有兩個像素 S(source) 和 D(destination),S 在 z 軸方向相對靠前(在上面),D 在 z 軸方向相對靠後(在下面),那麼最終的顏色值就是 S(上面像素) 的顏色 + D(下面像素) 的顏色 * (1 - S(上面像素) 顏色的透明度)

上述流水線以繪製一個三角形爲進行介紹,能夠爲每一個頂點添加顏色來增長圖形的細節,從而建立圖像。可是,若是讓圖形看上去更加真實,須要足夠多的頂點和顏色,相應也會產生更大的開銷。爲了提升生產效率和執行效率,開發者常常會使用 紋理(Texture) 來表現細節。紋理是一個 2D 圖片(甚至也有 1D 和 3D 的紋理)紋理 通常能夠直接做爲圖形渲染流水線的第五階段的輸入。

最後,咱們還須要知道上述階段中的着色器事實上是一些程序,它們運行在 GPU 中成千上萬的小處理器核中。這些着色器容許開發者進行配置,從而能夠高效地控制圖形渲染流水線中的特定部分。因爲它們運行在 GPU 中,所以能夠下降 CPU 的負荷。着色器可使用多種語言編寫,OpenGL 提供了 GLSL(OpenGL Shading Language) 着色器語言。

GPU 存儲系統

早期的 GPU,不一樣的着色器對應有着不一樣的硬件單元。現在,GPU 流水線則使用一個統一的硬件來運行全部的着色器。此外,nVidia 還提出了 CUDA(Compute Unified Device Architecture) 編程模型,能夠容許開發者經過編寫 C 代碼來訪問 GPU 中全部的處理器核,從而深度挖掘 GPU 的並行計算能力。

下圖所示爲 GPU 內部的層級結構。最底層是計算機的系統內存,其次是 GPU 的內部存儲,而後依次是兩級 cache:L2 和 L1,每一個 L1 cache 鏈接至一個 流處理器(SM,stream processor)

  • SM L1 Cache 的存儲容量大約爲 16 至 64KB。
  • GPU L2 Cache 的存儲容量大約爲幾百 KB。
  • GPU 的內存最大爲 12GB。

GPU 上的各級存儲系統與對應層級的計算機存儲系統相比要小很多。

此外,GPU 內存並不具備一致性,也就意味着並不支持併發讀取和併發寫入。

GPU 流處理器

下圖所示爲 GPU 中每一個流處理器的內部結構示意圖。每一個流處理器集成了一個 L1 Cache。頂部是處理器核共享的寄存器堆。

CPU-GPU 異構系統

至此,咱們大體瞭解了 GPU 的工做原理和內部結構,那麼實際應用中 CPU 和 GPU 又是如何協同工做的呢?

下圖所示爲兩種常見的 CPU-GPU 異構架構。

左圖是分離式的結構,CPU 和 GPU 擁有各自的存儲系統,二者經過 PCI-e 總線進行鏈接。這種結構的缺點在於 PCI-e 相對於二者具備低帶寬和高延遲,數據的傳輸成了其中的性能瓶頸。目前使用很是普遍,如PC、智能手機等。

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

注意,目前不少 SoC 都是集成了CPU 和 GPU,事實上這僅僅是在物理上進行了集成,並不意味着它們使用的就是耦合式結構,大多數採用的仍是分離式結構。耦合式結構是在系統上進行了集成。

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

圖形應用程序調用 OpenGLDirect3D API 功能,將 GPU 做爲協處理器使用。API 經過面向特殊 GPU 優化的圖形設備驅動向 GPU 發送命令、程序、數據。

GPU 資源管理模型

下圖所示爲分離式異構系統中 GPU 的資源管理模型示意圖。

  1. MMIO(Memory-Mapped I/O)
  • CPU 經過 MMIO 訪問 GPU 的寄存器狀態。
  • 經過 MMIO 傳送數據塊傳輸命令,支持 DMA 的硬件能夠實現塊數據傳輸。
  1. GPU Context
  • 上下文表示 GPU 的計算狀態,在 GPU 中佔據部分虛擬地址空間。多個活躍態下的上下文能夠在 GPU 中並存。
  1. CPU Channel
  • 來自 CPU 操做 GPU 的命令存儲在內存中,並提交至 GPU channel 硬件單元。
  • 每一個 GPU 上下文可擁有多個 GPU Channel。每一個 GPU 上下文都包含 GPU channel 描述符(GPU 內存中的內存對象)。
  • 每一個 GPU Channel 描述符存儲了channel 的配置,如:其所在的頁表。
  • 每一個 GPU Channel 都有一個專用的命令緩衝區,該緩衝區分配在 GPU 內存中,經過 MMIO 對 CPU 可見。
  1. GPU 頁表
  • GPU 上下文使用 GPU 頁表進行分配,該表將虛擬地址空間與其餘地址空間隔離開來。
  • GPU 頁表與 CPU 頁表分離,其駐留在 GPU 內存中,物理地址位於 GPU 通道描述符中。 經過 GPU channel 提交的全部命令和程序都在對應的 GPU 虛擬地址空間中執行。
  • GPU 頁表將 GPU 虛擬地址不只轉換爲 GPU 設備物理地址,還轉換爲主機物理地址。這使得 GPU 頁面表可以將 GPU 存儲器和主存儲器統一到統一的 GPU 虛擬地址空間中,從而構成一個完成的虛擬地址空間。
  1. PFIFO Engine
  • PFIFO 是一個提交 GPU 命令的特殊引擎。
  • PFIFO 維護多個獨立的命令隊列,即 channel。
  • 命令隊列是帶有 put 和 get 指針的環形緩衝器。
  • PFIFO 引擎會攔截多有對通道控制區域的訪問以供執行。
  • GPU 驅動使用一個通道描述符來存儲關聯通道的設置。
  1. BO
  • 緩衝對象(Buffer Object)。一塊內存,能夠用來存儲紋理,渲染對象,着色器代碼等等。

CPU-GPU 工做流

下圖所示爲 CPU-GPU 異構系統的工做流,當 CPU 遇到圖像處理的需求時,會調用 GPU 進行處理,主要流程能夠分爲如下四步:

  1. 將主存的處理數據複製到顯存中
  2. CPU 指令驅動 GPU
  3. GPU 中的每一個運算單元並行處理
  4. GPU 將顯存結果傳回主存

屏幕圖像顯示原理

介紹屏幕圖像顯示的原理,須要先從 CRT 顯示器原理提及,以下圖所示。CRT 的電子槍從上到下逐行掃描,掃描完成後顯示器就呈現一幀畫面。而後電子槍回到初始位置進行下一次掃描。爲了同步顯示器的顯示過程和系統的視頻控制器,顯示器會用硬件時鐘產生一系列的定時信號。當電子槍換行進行掃描時,顯示器會發出一個水平同步信號(horizonal synchronization),簡稱 HSync;而當一幀畫面繪製完成後,電子槍回覆到原位,準備畫下一幀前,顯示器會發出一個垂直同步信號(vertical synchronization),簡稱 VSync。顯示器一般以固定頻率進行刷新,這個刷新率就是 VSync 信號產生的頻率。雖然如今的顯示器基本都是液晶顯示屏了,但其原理基本一致。

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

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

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

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

參考

  1. GPU Architecture and Models
  2. 計算機組成與設計:硬件、軟件接口
  3. 歡迎來到OpenGL的世界
  4. AMD APU Series
  5. 一文詳解GPU結構及工做原理
  6. Revisting Co-Processing for Hash Joins on the Coupled CPU-GPU Architecture
  7. GPU Architecture Overview
  8. CUDA
  9. iOS 保持界面流程的技巧
  10. iOS 開發:繪製像素到屏幕

擴展閱讀

  1. Rendering pipeline: The hardware side
  2. Graphics Processing Unit(GPU) Memory Hierarchy
  3. Graphics Processing Unit Architecture(GPU Arch) With a focus on NVIDIA GeForce 6800 GPU
  4. iOS動畫篇:核心動畫
  5. The iPhone 5s Review
  6. A Look Inside Apple’s Custom GPU for the iPhone
  7. One Apple GPU, one giant leap in graphics for iPhone 8
相關文章
相關標籤/搜索