1003--圖像渲染初步理解

說到圖像渲染,那么先提一下CPU和GPU

  • CPU(Central Processing Unit):現(xiàn)代計算機的三大核心部分之一,作為整個系統(tǒng)的運算和控制單元。CPU 內(nèi)部的流水線結(jié)構(gòu)使其擁有一定程度的并行計算能力。
  • GPU(Graphics Processing Unit):一種可進行繪圖運算工作的專用微處理器。GPU 能夠生成 2D/3D 的圖形圖像和視頻,從而能夠支持基于窗口的操作系統(tǒng)、圖形用戶界面、視頻游戲、可視化圖像應(yīng)用和視頻播放。GPU 具有非常強的并行計算能力。

使用 GPU 渲染圖形的根本原因就是:速度。GPU 的并行計算能力使其能夠快速將圖形結(jié)果計算出來并在屏幕的所有像素中進行顯示。

iOS 圖形渲染技術(shù)棧

下圖所示為 iOS App 的圖形渲染技術(shù)棧,App 使用 Core Graphics、Core Animation、Core Image 等框架來繪制可視化內(nèi)容,這些軟件框架相互之間也有著依賴關(guān)系。這些框架都需要通過 OpenGL 來調(diào)用 GPU 進行繪制,最終將內(nèi)容顯示到屏幕之上。

iOS渲染過程.jpg

通常來說,計算機系統(tǒng)中 CPU、GPU、顯示器是以上面這種方式協(xié)同工作的。CPU 計算好顯示內(nèi)容提交到 GPU,GPU 渲染完成后將渲染結(jié)果放入幀緩沖區(qū),隨后視頻控制器會按照 VSync 信號如下圖所示,逐行讀取幀緩沖區(qū)的數(shù)據(jù),經(jīng)過可能的數(shù)模轉(zhuǎn)換傳遞給顯示器顯示。


垂直同步.jpg

在 VSync 信號到來后,系統(tǒng)圖形服務(wù)會通過 CADisplayLink 等機制通知 App,App 主線程開始在 CPU 中計算顯示內(nèi)容,比如視圖的創(chuàng)建、布局計算、圖片解碼、文本繪制等。隨后 CPU 會將計算好的內(nèi)容提交到 GPU 去,由 GPU 進行變換、合成、渲染。隨后 GPU 會把渲染結(jié)果提交到幀緩沖區(qū)去,等待下一次 VSync 信號到來時顯示到屏幕上。由于垂直同步的機制,如果在一個 VSync 時間內(nèi),CPU 或者 GPU 沒有完成內(nèi)容提交,則那一幀就會被丟棄,等待下一次機會再顯示,而這時顯示屏?xí)A糁暗膬?nèi)容不變。這就是界面卡頓的原因。從上圖中可以看到,CPU 和 GPU 不論哪個阻礙了顯示流程,都會造成掉幀現(xiàn)象。所以開發(fā)時,也需要分別對 CPU 和 GPU 壓力進行評估和優(yōu)化。

垂直同步到圖像.jpg

iOS 的顯示系統(tǒng)是由 VSync 信號驅(qū)動的,VSync 信號由硬件時鐘生成,每秒鐘發(fā)出 60 次(這個值取決設(shè)備硬件,比如 iPhone 真機上通常是 59.97)。iOS 圖形服務(wù)接收到 VSync 信號后,會通過 IPC 通知到 App 內(nèi)。App 的 Runloop 在啟動后會注冊對應(yīng)的 CFRunLoopSource 通過 mach_port 接收傳過來的時鐘信號通知,隨后 Source 的回調(diào)會驅(qū)動整個 App 的動畫與顯示。

Core Animation 在 RunLoop 中注冊了一個 Observer,監(jiān)聽了 BeforeWaiting 和 Exit 事件。當(dāng)一個觸摸事件到來時,RunLoop 被喚醒,App 中的代碼會執(zhí)行一些操作,比如創(chuàng)建和調(diào)整視圖層級、設(shè)置 UIView 的 frame、修改 CALayer 的透明度、為視圖添加一個動畫;這些操作最終都會被 CALayer 標(biāo)記,并通過 CATransaction 提交到一個中間狀態(tài)去。當(dāng)上面所有操作結(jié)束后,RunLoop 即將進入休眠(或者退出)時,關(guān)注該事件的 Observer 都會得到通知。這時 Core Animation 注冊的那個 Observer 就會在回調(diào)中,把所有的中間狀態(tài)合并提交到 GPU 去顯示;如果此處有動畫,通過 DisplayLink 穩(wěn)定的刷新機制會不斷的喚醒runloop,使得不斷的有機會觸發(fā)observer回調(diào),從而根據(jù)時間來不斷更新這個動畫的屬性值并繪制出來。

為了不阻塞主線程,Core Animation 的核心是 OpenGL ES 的一個抽象物,所以大部分的渲染是直接提交給GPU來處理。 而Core Graphics/Quartz 2D的大部分繪制操作都是在主線程和CPU上同步完成的,比如自定義UIView的drawRect里用CGContext來畫圖。

渲染時機

上面已經(jīng)提到過:Core Animation 在 RunLoop 中注冊了一個 Observer 監(jiān)聽 BeforeWaiting(即將進入休眠) 和 Exit (即將退出Loop) 事件 。當(dāng)在操作 UI 時,比如改變了 Frame、更新了 UIView/CALayer 的層次時,或者手動調(diào)用了 UIView/CALayer 的 setNeedsLayout/setNeedsDisplay方法后,這個 UIView/CALayer 就被標(biāo)記為待處理,并被提交到一個全局的容器去。當(dāng)Oberver監(jiān)聽的事件到來時,回調(diào)執(zhí)行函數(shù)中會遍歷所有待處理的UIView/CAlayer 以執(zhí)行實際的繪制和調(diào)整,并更新 UI 界面。

GPU 圖形渲染流水線

GPU 圖形渲染流水線的主要工作可以被劃分為兩個部分:

  • 把 3D 坐標(biāo)轉(zhuǎn)換為 2D 坐標(biāo)
  • 把 2D 坐標(biāo)轉(zhuǎn)變?yōu)閷嶋H的有顏色的像素

第一階段,頂點著色器。該階段的輸入是 頂點數(shù)據(jù)(Vertex Data) 數(shù)據(jù),比如以數(shù)組的形式傳遞 3 個 3D 坐標(biāo)用來表示一個三角形。頂點數(shù)據(jù)是一系列頂點的集合。頂點著色器主要的目的是把 3D 坐標(biāo)轉(zhuǎn)為另一種 3D 坐標(biāo),同時頂點著色器可以對頂點屬性進行一些基本處理。

第二階段,形狀(圖元)裝配。該階段將頂點著色器輸出的所有頂點作為輸入,并將所有的點裝配成指定圖元的形狀。圖中則是一個三角形。圖元(Primitive) 用于表示如何渲染頂點數(shù)據(jù),如:點、線、三角形。

第三階段,幾何著色器。該階段把圖元形式的一系列頂點的集合作為輸入,它可以通過產(chǎn)生新頂點構(gòu)造出新的(或是其它的)圖元來生成其他形狀。例子中,它生成了另一個三角形。

第四階段,光柵化。該階段會把圖元映射為最終屏幕上相應(yīng)的像素,生成片段。片段(Fragment) 是渲染一個像素所需要的所有數(shù)據(jù)。

第五階段,片段著色器。該階段首先會對輸入的片段進行 裁切(Clipping)。裁切會丟棄超出視圖以外的所有像素,用來提升執(zhí)行效率。

第六階段,測試與混合。該階段會檢測片段的對應(yīng)的深度值(z 坐標(biāo)),判斷這個像素位于其它物體的前面還是后面,決定是否應(yīng)該丟棄。此外,該階段還會檢查 alpha 值( alpha 值定義了一個物體的透明度),從而對物體進行混合。因此,即使在片段著色器中計算出來了一個像素輸出的顏色,在渲染多個三角形的時候最后的像素顏色也可能完全不同。

參考 :
iOS 事件處理機制與圖像渲染過程
iOS 圖像渲染原理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容