屏幕卡頓 及 iOS中OpenGL渲染架構分析

屏幕卡頓

屏幕卡頓是指圖形圖像的在顯示時出現了撕裂(即圖片錯位顯示)、掉幀(重復顯示同一幀數據)等問題,導致用戶能直觀的從屏幕上看到的一種異?,F象
為什么會出現這種情況呢?下面就來詳細解說下屏幕卡頓

【高頻面試題】屏幕卡頓的原因

主要有以下三種原因

  • CPU和GPU在渲染的流水線中耗時過長,導致從緩存區獲取位圖顯示時,下一幀的數據還沒有準備好,獲取的仍是上一幀的數據,產生掉幀現象,掉幀就會導致屏幕卡頓
  • 蘋果官方針對屏幕撕裂問題,目前一直使用的方案是垂直同步+雙緩存區,可以從根本上防止和解決屏幕撕裂,但是同時也導致了新的問題掉幀。雖然我們采用了雙緩存區,但是我們并不能解決CPU和GPU處理圖形圖像的速度問題,導致屏幕在接收到垂直信號時,數據尚未準備好,緩存區仍是上一幀的數據,因此導致掉幀
  • 在垂直同步+雙緩存區的方案上,再次進行優化,將雙緩存區,改為三緩存區,這樣其實也并不能從根本上解決掉幀的問題,只是比雙緩存區掉幀的概率小了很多,仍有掉幀的可能性,對于用戶而言,可能是無感知的。

接下來,詳細解析下屏幕撕裂及掉幀問題

屏幕撕裂

如圖所示,屏幕撕裂就類似于這樣的情形

  • 屏幕撕裂展示

在講屏幕撕裂之前,首先說說屏幕是如何成像的,主要的流程是什么

屏幕成像過程

請看下面這張圖,詳細說明了屏幕成像的一個流程

  • 將需要顯示的圖像,經由GPU渲染

  • 將渲染后的結果,存儲到幀緩存區,幀緩存區中存儲的格式是位圖

  • 由視屏控制器從幀緩存區中讀取位圖,交由顯示器,從左上角逐行掃描進行顯示

屏幕撕裂的原因

  • 在屏幕顯示圖形圖像的過程中,是不斷從幀緩存區獲取一幀一幀數據進行顯示的,

  • 然后在渲染的過程中,幀緩存區中仍是舊的數據,屏幕拿到舊的數據去進行顯示,

  • 在舊的數據沒有讀取完時 ,新的一幀數據處理好了,放入了緩存區,這時就會導致屏幕另一部分的顯示是獲取的新數據,從而導致屏幕上呈現圖片不匹配,人物、景象等錯位顯示的情況。
    圖示如下:

蘋果官方的解決方案
蘋果官方針對屏幕撕裂現象,目前一直采用的是 垂直同步+雙緩存,該方案是強制要求同步,且是以掉幀為代價的。

以下是垂直同步+雙緩存的一個圖解過程,如有描述錯誤的地方,歡迎留言指出

  • 垂直同步:是指給幀緩沖加鎖,當電子光束掃描的過程中,只有掃描完成了才會讀取下一幀的數據,而不是只讀取一部分

  • 雙緩沖區:采用兩個幀緩沖區用途GPU處理結果的存儲,當屏幕顯示其中一個緩存區內容時,另一個緩沖區繼續等待下一個緩沖結果,兩個緩沖區依次進行交替

掉幀

采用蘋果的雙緩沖區方案后,又會出現新的問題,掉幀。
什么是掉幀?簡單來說就是 屏幕重復顯示同一幀數據的情況就是掉幀

如圖所示:當前屏幕顯示的是A,在收到垂直信號后,CPU和GPU處理的B還沒有準備好,此時,屏幕顯示的仍然是A(圖有誤,第二個為GPU)

  • 針對掉幀情況,我們可以在蘋果方案的基礎上進行優化,即采用三緩存區,意味著,在屏幕顯示時,后面還準備了3個數據用于顯示。

iOS中的渲染

在iOS中渲染的整體流程如下所示

  • App通過調用CoreGraphics、CoreAnimation、CoreImage等框架的接口觸發圖形渲染操作

  • CoreGraphics、CoreAnimation、CoreImage等框架將渲染交由OpenGL ES,由OpenGL ES來驅動GPU做渲染,最后顯示到屏幕上

  • 由于OpenGL ES 是跨平臺的,所以在他的實現中,是不能有任何窗口相關的代碼,而是讓各自的平臺為OpenGL ES提供載體。在ios中,如果需要使用OpenGL ES,就是通過CoreAnimation提供窗口,讓App可以去調用。

iOS中渲染框架總結

主要由以下六種框架,表格中已經說明了,就不再詳細解釋了

  • 渲染框架總結

View 與 CALayer 的關系

首先分別簡單說下UIView和CALayer各自的作用

UIView

  • UIView屬于UIKIt
  • 負責繪制圖形和動畫操作
  • 用于界面布局和子視圖的管理
  • 處理用戶的點擊事件

CALayer

  • CALayer屬于CoreAnimation
  • 只負責顯示,且顯示的是位圖
  • CALayer既用于UIKit,也用于APPKit,
    ==> UIKit是iOS平臺的渲染框架,APPKit是Mac OSX系統下的渲染框架,
    ==> 由于iOS和Mac兩個系統的界面布局并不是一致的,iOS是基于多點觸控的交互方式,而Mac OSX是基于鼠標鍵盤的交互方式,且分別在對應的框架中做了布局的操作,所以并不需要layer載體去布局,且不用迎合任何布局方式。

【面試題】UIView和CALayer的關系

  • UIView基于UIKit框架,可以處理用戶觸摸事件,并管理子視圖
  • CALayer基于CoreAnimation,而CoreAnimation是基于QuartzCode的。所以CALayer只負責顯示,不能處理用戶的觸摸事件
  • 從父類來說,CALayer繼承的是NSObject,而UIView是直接繼承自UIResponder的,所以UIVIew相比CALayer而言,只是多了事件處理功能,
  • 從底層來說,UIView屬于UIKit的組件,而UIKit的組件到最后都會被分解成layer,存儲到圖層樹中
  • 在應用層面來說,需要與用戶交互時,使用UIView,不需要交互時,使用兩者都可以

UIView和CALayer的渲染

下圖可以說明view 和 layer之間是如何渲染的

  • 界面觸發的方式有兩種
    ==> 通過loadView中子View的drawRect方法觸發:會回調CoreAnimation中監聽Runloop的BeforeWaiting的RunloopObserver,通過RunloopObserver來進一步調用CoreAnimation內部的CA::Transaction::commit(),進而一步步走到drawRect方法
    ==> 用戶點擊事件觸發:喚醒Runloop,由source1處理(__IOHIDEventSystemClientQueueCallback),并且在下一個runloop里由source0轉發給UIApplication(_UIApplicationHandleEventQueue),從而能通過source0里的事件隊列來調用CoreAnimation內部的CA::Transaction::commit();方法,進而一步一步的調用drawRect。
    最終都會走到CoreAnimation中的CA::Transaction::commit()方法,從而來觸發UIView和CALayer的渲染

  • 這時,已經到了CoreAnimation的內部,即調用CA::Transaction::commit();來創建CATrasaction,然后進一步調用 CALayer drawInContext:()

  • 回調CALayer的Delegate(UIView),問UIView沒有需要畫的內容,即回調到drawRect:方法

  • 在drawRect:方法里可以通過CoreGraphics函數或UIKit中對CoreGraphics封裝的方法進行畫圖操作

  • 將繪制好的位圖交由CALayer,由OpenGL ES 傳送到GPU的幀緩沖區

  • 等屏幕接收到垂直信號后,就讀取幀緩沖區的數據,顯示到屏幕上

CoreAnimation

在蘋果官方的描述中,Render、Compose,and animate visual elements,CoreAnimationg中的動畫只是一部分,它其實是一個復合引擎,主要的職責包括 渲染、構建和動畫實現。

ios中CoreAnimation如圖所示

  • ios中基于CoreAnimation構建的框架有兩個:UIKit和APPKit

  • CoreAnimation 又是基于Metal 、CoreGraphics封裝的

蘋果為什么要基于UIView和CALayer提供兩個平行的層級關系(UIKit 和APPKit)?

  • 職責分離,可以避免大量重復代碼
  • 兩個系統交互規則不一致,雖然功能上類似,但實現上有顯著區別

CoreAnimation中的渲染流水線

CoreAnimation中渲染的流程如圖所示

主要分為兩部分:

  • CoreAnimation部分
  • GPU部分

CoreAnimation部分

  • App處理UIView、UIButton等載體的事件,然后通過CPU完成對顯示內容的計算,并將計算后的圖層進行打包,在下一次runloop時,發送到渲染服務器

  • Render Server中主要對收到的準備顯示的內容進行解碼,然后執行OpenGL等相關程序,并調用GPU進行渲染
    ==> Render Server 操作分析

GPU部分

  • GPU中通過頂點著色器、片元著色器完成對顯示內容的渲染,將結果存入幀緩存區
  • GPU通過幀緩存區、視頻控制器等相關部件,將其顯示到屏幕上

OpenGL 渲染架構分析

OpenGL中的渲染架構如圖所示

主要分為兩個模塊

  • Client:是指常見的iOS代碼和OpenGL API方法,這部分是在CPU中運行
  • Server:是指OpenGL底層的渲染等處理,是運行在GPU中的

架構分析

  • 客戶端中通過iOS代碼調用OpenGL API中的方法,將圖形渲染的相關數據通過通道傳遞到服務器中頂點著色器和片元著色器,并交由GPU處理。
  • 服務器通過與客戶端的通道接收傳遞的數據,并交由相應著色器進行渲染處理,并將最終的結果渲染到屏幕上

數據傳遞

從圖上我們可以看出,客戶端和服務器進行數據傳遞的通道有三種

  • Attributes
  • Uniform
  • Texture Data
通道名稱 參數類型 可傳入的著色器
Attributes 經常發生變動的數據 :紋理坐標 、光照法線、頂點坐標 、顏色數據 頂點著色器
Uniform 不經常發生變動的數據 頂點著色器、片元著色器
Texture Data 紋理 頂點著色器、片元著色器

Attributes

  • Attributes通道只能將數據直接傳遞到頂點著色器,不能直接傳遞到片元著色器,但是可以通過頂點著色器間接傳遞給片元著色器。
  • 通過Attributes傳遞的通常是經常發生變化的數據,例如顏色、頂點等。
  • Attribute主要傳遞這些參數:顏色數據、頂點坐標、紋理坐標、光照法線等。

Uniform

  • Uniform通過既可以傳遞到頂點著色器,也可以傳遞到片元著色器。
  • Uniform中傳遞的通常是比較統一的批次數據,不經常發生變動的數據。

Texture Data

  • Texture Data同Unoform一樣,可以將數據傳遞到頂點和片元著色器。
  • 由于頂點著色器主要是處理頂點數據的,我們將紋理數據傳過去并沒有多大的意義。而紋理的處理的邏輯主要是在片元著色器中進行的。
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內容