一、CPU 和 GPU
CPU 是計算機整個系統(tǒng)的運算核?咕缎、控制核?珠十。CPU 內部采用的是流水線結構, 使其擁有一定程度的并行計算能力。CPU 擅長分支預測等復雜操作凭豪。
GPU 是可進行繪圖運算工作的專用微處理器焙蹭,是一個被高度優(yōu)化設計的用來并發(fā)計算的硬件單元。GPU擅長對大量數據進行大量并行的工作嫂伞,GPU 各個單元依懶性非常低孔厉。
1.1 CPU 和 GPU異構系統(tǒng)
在實際應用中 CPU 和 GPU 有兩種異構系統(tǒng)來協(xié)同工作
- 左邊是分離式架構系統(tǒng),CPU 和 GPU 擁有各自存儲系統(tǒng)帖努。CPU 的內存也是我們所說的手機或是電腦內存撰豺,GPU 的內存是顯存(幀緩沖)也就是圖形頂點數據存儲的位置。這種結構的缺點在于 PCI-e 相對于兩者具有低帶寬和高延遲然磷,數據的傳輸成了其中的性能瓶頸郑趁。目前使用非常廣泛,如PC姿搜、智能手機等寡润。
- 右邊是耦合式架構系統(tǒng),CPU 和 GPU 共享內存和緩存舅柜。主要應用在游戲主機中梭纹,如 PS4。
1.2 CPU 和 GPU工作流程
當 CPU 遇到圖像處理的需求時致份,會調用 GPU 進行處理变抽,主要流程是這樣:
- 將主存的處理數據復制到顯存中
- CPU 指令驅動 GPU
- GPU 中的每個運算單元并行處理
- GPU 將顯存結果傳回主存
1.3 GPU 圖形渲染流程
GPU 圖形渲染流程具體可以分為六個步驟:
- 頂點著色器
- 圖元裝配
- 幾何著色器
- 光柵化
- 片元著色器
- 測試與混合
開發(fā)人員可以使用 GLSL 語言進行對頂點著色器和片元著色器修改,這也是唯一能對圖形修改的地方氮块,片元著色器主要是對圖形的飽和度進行修改绍载。
二、圖像顯示方式和原理
隨機掃描顯示
在隨機掃描方式中滔蝉,電子束能在屏幕上進行隨機移動击儡,軌跡隨顯示內容變化而變化,只在需要顯示字符和圖形的地方掃描蝠引,而不是全屏掃描阳谍。一般用于高清晰度的專用圖形顯示器中蛀柴。特點:
- 顯示速度快、畫面清晰矫夯、線條輪廓十分光滑
- 控制方式復雜鸽疾,只能用于字符和圖形顯示,不適用于顯示隨機圖像
光柵掃描顯示
在光柵掃描方式中训貌,電子束在水平和垂直同步信號的控制下有規(guī)律的掃描整個屏幕制肮。特點:
- 控制方式簡單
- 畫面質量較好和穩(wěn)定
- 對掃描頻率要求高
那為什么人眼感覺不到屏幕在刷新呢?這里有個專有名詞"視覺暫留"旺订,人眼在觀察景物的時候弄企,光信號傳入大腦神經,需經過一段短暫的時間区拳,光的作用結束后拘领,視覺形象并不會立即消失。在人眼中1秒16幀的畫面就是連續(xù)的了樱调。
圖像顯示流程
CPU 計算好顯示內容提交至 GPU约素,GPU 渲染完成后將渲染結果存入幀緩沖區(qū),視頻控制器會按照 VSync 信號逐幀讀取幀緩沖區(qū)的數據(位圖)笆凌,經過數模轉換(數字信號->模擬信號)后最終由顯示器(逐行掃描)進行顯示.
幀緩沖和垂直同步
為了效率問題圣猎,GPU 通常會引入兩個緩沖區(qū),即雙緩沖機制乞而。在這種情況下送悔,GPU 會預先渲染一幀放入一個緩沖區(qū)中,用于視頻控制器的讀取爪模。當下一幀渲染完畢后欠啤,GPU 會直接把視頻控制器的指針指向第二個緩沖區(qū)。
雙緩沖雖然能解決效率問題屋灌,但會引入一個新的問題洁段。造成畫面撕裂現象,原因是視頻控制器還未讀取完 A 幀緩沖區(qū)數據時共郭,顯示到屏幕一半的畫面祠丝,當GPU 將新的一幀數據提交到 B 幀緩沖區(qū)并且交換緩沖區(qū)后,視頻控制器就會把新的一幀數據的下半段顯示到屏幕上除嘹,就會出現畫面撕裂的現象写半。
為了解決這個問題,GPU 通常有一個機制叫做垂直同步尉咕,垂直同步技術相當于在幀緩沖區(qū)加鎖操作污朽,當電子束都掃描完成以后才去讀取數據。當開啟垂直同步后龙考,GPU 會等待顯示器的 VSync 信號發(fā)出后蟆肆,才進行新的一幀渲染和緩沖區(qū)更新。這樣能解決畫面撕裂現象晦款,也增加了畫面流暢度炎功,但需要消費更多的計算資源,也會帶來部分延遲缓溅。
iOS 設備會始終使用垂直同步+雙緩存區(qū)的策略蛇损。
掉幀
垂直同步+雙緩存區(qū)解決了畫面撕裂問題,但是有出現了一個新的問題——掉幀坛怪。掉幀是重復渲染同一幀數據淤齐。屏幕顯示 A 緩沖區(qū)的數據,當垂直同步信號到來時袜匿,B 緩沖區(qū)的數據還沒有準備好更啄,屏幕繼續(xù)顯示 A 緩存區(qū)的數據,等到 B 緩沖區(qū)數據準備完成后居灯,交換緩沖區(qū)祭务,按照這個方式一直執(zhí)行下去,就會造成卡頓怪嫌。
大致的流程是這樣:
接收垂直同步信號 -> CPU 和 GPU 還沒有準備好數據 -> 視頻控制器就拿不到 FrameBuffer 里面的數據 -> 重復渲染同一幀數據
為了解決這個問題义锥,提出了三緩存區(qū)機制,合理使用 CPU 和 GPU 的閑置時間岩灭,三緩存區(qū)也會存在掉幀問題拌倍,但是它能減少掉幀次數。這樣的話卡頓的原因也就找到了:
- CPU 和 GPU 渲染流水線耗時過長——掉幀
- 垂直同步+雙緩沖區(qū)是以掉幀為代價解決屏幕撕裂問題
三噪径、iOS系統(tǒng)圖像渲染流程
圖形圖形渲染框架介紹
- UIKit 主要提供界面呈現能力柱恤、事件響應能力、驅動 RunLoop 運行與系統(tǒng)內核通信熄云。簡單來說就是主要負責界面展示膨更、事件響應以及是 RunLoop 的需求方。
- CoreAnimation 來自于 QuartzCore 框架缴允,提供了圖形處理和視頻圖像處理的能力荚守。不要認為 CoreAnimation 只是負責核心動畫,還負責通過調用 OpenGL ES 把我們用代碼構建的界面顯示到屏幕上练般。
- CoreGraphics 提供了非常強大的輕量級2D渲染能力矗漾。CoreGraphics 負責創(chuàng)建顯示到屏幕上的數據模型。
三者的關系是通過界面展示以及動畫的創(chuàng)建薄料、執(zhí)行關聯(lián)起來的敞贡,所以它們之間是協(xié)作而不是從屬的關系。
UIView 與 CALayer(CoreAnimation Layer) 關系
1. UIView 可以響應事件摄职,CALayer 不可以
查看 UIKit 框架可以得知 UIView 是繼承 UIResponder誊役,這也就說明 UIView 有接收事件和響應事件處理的能力获列。CALayer 是繼承 NSObject 所以說 CALayer 沒有接收和響應事件處理的能力。
2. UIView 的屬性與 CALayer 的屬性是映射關系
一個 CALayer 的 frame 是由 anchorPoint蛔垢、position击孩、bounds、transform 共同決定的鹏漆,對于一個 UIView 的 frame 只是簡單返回 CALayer 的 frame 而已巩梢。同樣的 UIView 的 center、bounds 也是返回 CALayer 的一些屬性艺玲。
3. UIView 主要負責管理 CALayer 时鸵,CALayer 負責繪制
重寫 [view drawRect:rect] 和 [layer display] 可以看出 UIView 是 CALayer 的代理绷落,從而繪制出視圖內容左敌。
4. 執(zhí)行動畫的時候止潘,是 CALayer 在為 UIView 做隱式動畫
CALayer 修改屬性是默認支持隱式動畫的,在給 UIView 的 Layer 做動畫的時候若治,UIView 作為 CALayer 的代理慨蓝,CALayer 通過 actionForLayer:forKey: 向 UIView 請求相應的 action(動畫行為)。
CALayer 內部維護著三種圖層樹端幼,分別是 presentLayer Tree(動畫樹)礼烈,modeLayer Tree(模型樹), Render Tree(渲染樹)婆跑,在做動畫的時候此熬,我們其實修改的是 presentLayer Tree ,展示在界面上是 modelLayer Tree滑进。
渲染流程
App 本身并不負責渲染任務犀忱,負責渲染任務是一個獨立的進程—— Render Server。App 通過 IPC (進程間通信) 將渲染任務和相關數據提交給 Render Server扶关。Render Server 處理完數據提交給 GPU阴汇。最后 GPU 渲染完成后把這一幀畫面放到 FrameBuffer,等到 Vsync 信號到來节槐,視頻控制器就會把這一幀畫面顯示到屏幕上搀庶。
CoreAnimation 在 RunLoop 中注冊了一個 Observer,監(jiān)聽 RunLoop 即將休眠(BeforeWaiting)和退出(Exit)事件铜异。如果調整 UIView / CALayer 視圖層級哥倔、屬性設置,或是手動調用 UIView / CALayer 的 setNeedsLayout / setNeedsDisplay 方法后揍庄,這些操作都會被 CALayer 標記咆蒿,并通過 CATransaction 提交到一個全局容器(Backing Store)去。當 RunLoop 即將休眠或是退出時,關注該事件的 Observer 就會在回調中把所有待處理的 UIView / CALayer 執(zhí)行實際的繪制和調整沃测,最終交給 GPU 進行渲染缭黔。如果圖層有動畫,通過 CADisplayLink 穩(wěn)定的刷新機制會不斷喚醒 RunLoop蒂破,使得不斷觸發(fā) Observer 回調试浙,從而根據動畫時間來更新屬性值并繪制出來。
在方法調用棧中可以很清晰的看出來每一個方法是做什么的寞蚌,其中還包括了 UIView 與 CALayer 的關系。