iOS中的渲染流程解析及屏幕卡頓

iOS中的渲染

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


App通過調(diào)用CoreGraphics商叹、CoreAnimation悴能、CoreImage等框架的接口觸發(fā)圖形渲染操作

CoreGraphics萧诫、CoreAnimation伐庭、CoreImage等框架將渲染交由OpenGL ES,由OpenGL ES來驅(qū)動GPU做渲染狼荞,最后顯示到屏幕上

由于OpenGL ES 是跨平臺的由蘑,所以在他的實現(xiàn)中闽寡,是不能有任何窗口相關(guān)的代碼,而是讓各自的平臺為OpenGL ES提供載體尼酿。在ios中爷狈,如果需要使用OpenGL ES,就是通過CoreAnimation提供窗口裳擎,讓App可以去調(diào)用涎永。

iOS中渲染框架總結(jié)

主要由以下六種框架,表格中已經(jīng)說明了鹿响,就不再詳細解釋了

View 與 CALayer 的關(guān)系

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

UIView

UIView屬于UIKIt

負責繪制圖形和動畫操作

用于界面布局和子視圖的管理

處理用戶的點擊事件

CALayer

CALayer屬于CoreAnimation

只負責顯示羡微,且顯示的是位圖

CALayer既用于UIKit,也用于APPKit抢野,

==> UIKit是iOS平臺的渲染框架,APPKit是Mac OSX系統(tǒng)下的渲染框架各墨,

==> 由于iOS和Mac兩個系統(tǒng)的界面布局并不是一致的指孤,iOS是基于多點觸控的交互方式,而Mac OSX是基于鼠標鍵盤的交互方式贬堵,且分別在對應(yīng)的框架中做了布局的操作恃轩,所以并不需要layer載體去布局,且不用迎合任何布局方式黎做。

【面試題】UIView和CALayer的關(guān)系

UIView基于UIKit框架叉跛,可以處理用戶觸摸事件,并管理子視圖

CALayer基于CoreAnimation蒸殿,而CoreAnimation是基于QuartzCode的筷厘。所以CALayer只負責顯示,不能處理用戶的觸摸事件

從父類來說宏所,CALayer繼承的是NSObject酥艳,而UIView是直接繼承自UIResponder的,所以UIVIew相比CALayer而言爬骤,只是多了事件處理功能充石,

從底層來說,UIView屬于UIKit的組件霞玄,而UIKit的組件到最后都會被分解成layer骤铃,存儲到圖層樹中

在應(yīng)用層面來說拉岁,需要與用戶交互時,使用UIView惰爬,不需要交互時喊暖,使用兩者都可以

UIView和CALayer的渲染

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


界面觸發(fā)的方式有兩種

==> 通過loadView中子View的drawRect方法觸發(fā):會回調(diào)CoreAnimation中監(jiān)聽Runloop的BeforeWaiting的RunloopObserver,通過RunloopObserver來進一步調(diào)用CoreAnimation內(nèi)部的CA::Transaction::commit()补鼻,進而一步步走到drawRect方法

==> 用戶點擊事件觸發(fā):喚醒Runloop哄啄,由source1處理(__IOHIDEventSystemClientQueueCallback),并且在下一個runloop里由source0轉(zhuǎn)發(fā)給UIApplication(_UIApplicationHandleEventQueue)风范,從而能通過source0里的事件隊列來調(diào)用CoreAnimation內(nèi)部的CA::Transaction::commit();方法咨跌,進而一步一步的調(diào)用drawRect。

最終都會走到CoreAnimation中的CA::Transaction::commit()方法硼婿,從而來觸發(fā)UIView和CALayer的渲染

這時锌半,已經(jīng)到了CoreAnimation的內(nèi)部,即調(diào)用CA::Transaction::commit();來創(chuàng)建CATrasaction寇漫,然后進一步調(diào)用CALayer drawInContext:()

回調(diào)CALayer的Delegate(UIView)刊殉,問UIView沒有需要畫的內(nèi)容,即回調(diào)到drawRect:方法

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

界面觸發(fā)的方式有兩種

==> 通過loadView中子View的drawRect方法觸發(fā):會回調(diào)CoreAnimation中監(jiān)聽Runloop的BeforeWaiting的RunloopObserver州胳,通過RunloopObserver來進一步調(diào)用CoreAnimation內(nèi)部的CA::Transaction::commit()记焊,進而一步步走到drawRect方法

==> 用戶點擊事件觸發(fā):喚醒Runloop,由source1處理(__IOHIDEventSystemClientQueueCallback)栓撞,并且在下一個runloop里由source0轉(zhuǎn)發(fā)給UIApplication(_UIApplicationHandleEventQueue)遍膜,從而能通過source0里的事件隊列來調(diào)用CoreAnimation內(nèi)部的CA::Transaction::commit();方法,進而一步一步的調(diào)用drawRect瓤湘。

最終都會走到CoreAnimation中的CA::Transaction::commit()方法瓢颅,從而來觸發(fā)UIView和CALayer的渲染

這時,已經(jīng)到了CoreAnimation的內(nèi)部弛说,即調(diào)用CA::Transaction::commit();來創(chuàng)建CATrasaction挽懦,然后進一步調(diào)用CALayer drawInContext:()

回調(diào)CALayer的Delegate(UIView),問UIView沒有需要畫的內(nèi)容木人,即回調(diào)到drawRect:方法

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

CoreAnimation

在蘋果官方的描述中信柿,Render、Compose醒第,and animate visual elements角塑,CoreAnimationg中的動畫只是一部分,它其實是一個復(fù)合引擎淘讥,主要的職責包括 渲染圃伶、構(gòu)建和動畫實現(xiàn)。

ios中CoreAnimation如圖所示


ios中基于CoreAnimation構(gòu)建的框架有兩個:UIKit和APPKit

CoreAnimation 又是基于Metal 、CoreGraphics封裝的

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

職責分離搀罢,可以避免大量重復(fù)代碼

兩個系統(tǒng)交互規(guī)則不一致,雖然功能上類似侥猩,但實現(xiàn)上有顯著區(qū)別

CoreAnimation中的渲染流水線

CoreAnimation中渲染的流程如圖所示


主要分為兩部分:

CoreAnimation部分

GPU部分

CoreAnimation部分

App處理UIView榔至、UIButton等載體的事件,然后通過CPU完成對顯示內(nèi)容的計算欺劳,并將計算后的圖層進行打包唧取,在下一次runloop時,發(fā)送到渲染服務(wù)器

Render Server中主要對收到的準備顯示的內(nèi)容進行解碼划提,然后執(zhí)行OpenGL等相關(guān)程序枫弟,并調(diào)用GPU進行渲染

==> Render Server 操作分析


GPU部分

GPU中通過頂點著色器、片元著色器完成對顯示內(nèi)容的渲染鹏往,將結(jié)果存入幀緩存區(qū)

GPU通過幀緩存區(qū)淡诗、視頻控制器等相關(guān)部件,將其顯示到屏幕上

屏幕卡頓

屏幕卡頓是指圖形圖像的在顯示時出現(xiàn)了撕裂(即圖片錯位顯示)伊履、掉幀(重復(fù)顯示同一幀數(shù)據(jù))等問題韩容,導(dǎo)致用戶能直觀的從屏幕上看到的一種異常現(xiàn)象

為什么會出現(xiàn)這種情況呢唐瀑?下面就來詳細解說下屏幕卡頓

屏幕卡頓的原因

主要有以下三種原因

1.CPU和GPU在渲染的流水線中耗時過長群凶,導(dǎo)致從緩存區(qū)獲取位圖顯示時,下一幀的數(shù)據(jù)還沒有準備好哄辣,獲取的仍是上一幀的數(shù)據(jù)请梢,產(chǎn)生掉幀現(xiàn)象,掉幀就會導(dǎo)致屏幕卡頓

2.蘋果官方針對屏幕撕裂問題柔滔,目前一直使用的方案是垂直同步+雙緩存區(qū)溢陪,可以從根本上防止和解決屏幕撕裂萍虽,但是同時也導(dǎo)致了新的問題掉幀睛廊。雖然我們采用了雙緩存區(qū),但是我們并不能解決CPU和GPU處理圖形圖像的速度問題杉编,導(dǎo)致屏幕在接收到垂直信號時超全,數(shù)據(jù)尚未準備好,緩存區(qū)仍是上一幀的數(shù)據(jù)邓馒,因此導(dǎo)致掉幀

3.在垂直同步+雙緩存區(qū)的方案上嘶朱,再次進行優(yōu)化,將雙緩存區(qū)光酣,改為三緩存區(qū)疏遏,這樣其實也并不能從根本上解決掉幀的問題,只是比雙緩存區(qū)掉幀的概率小了很多,仍有掉幀的可能性财异,對于用戶而言倘零,可能是無感知的。

屏幕撕裂

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


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

屏幕成像過程

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


將需要顯示的圖像袖瞻,經(jīng)由GPU渲染

將渲染后的結(jié)果,存儲到幀緩存區(qū)拆吆,幀緩存區(qū)中存儲的格式是位圖

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

屏幕撕裂的原因

在屏幕顯示圖形圖像的過程中锈拨,是不斷從幀緩存區(qū)獲取一幀一幀數(shù)據(jù)進行顯示的砌庄,

然后在渲染的過程中,幀緩存區(qū)中仍是舊的數(shù)據(jù)奕枢,屏幕拿到舊的數(shù)據(jù)去進行顯示娄昆,

在舊的數(shù)據(jù)沒有讀取完時 ,新的一幀數(shù)據(jù)處理好了缝彬,放入了緩存區(qū)萌焰,這時就會導(dǎo)致屏幕另一部分的顯示是獲取的線數(shù)據(jù),從而導(dǎo)致屏幕上呈現(xiàn)圖片不匹配谷浅,人物扒俯、景象等錯位顯示的情況。

圖示如下:


蘋果官方的解決方案

蘋果官方針對屏幕撕裂現(xiàn)象一疯,目前一直采用的是?垂直同步+雙緩存撼玄,該方案是強制要求同步,且是以掉幀為代價的墩邀。

以下是垂直同步+雙緩存的一個圖解過程掌猛,


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

雙緩沖區(qū):采用兩個幀緩沖區(qū)用途GPU處理結(jié)果的存儲,當屏幕顯示其中一個緩存區(qū)內(nèi)容時竹海,另一個緩沖區(qū)繼續(xù)等待下一個緩沖結(jié)果慕蔚,兩個緩沖區(qū)依次進行交替

掉幀

采用蘋果的雙緩沖區(qū)方案后,又會出現(xiàn)新的問題斋配,掉幀孔飒。

什么是掉幀灌闺?簡單來說就是 屏幕重復(fù)顯示同一幀數(shù)據(jù)的情況就是掉幀

如圖所示:當前屏幕顯示的是A,在收到垂直信號后坏瞄,CPU和GPU處理的B還沒有準備好菩鲜,此時,屏幕顯示的仍然是A


針對掉幀情況惦积,我們可以在蘋果方案的基礎(chǔ)上進行優(yōu)化接校,即采用三緩存區(qū),意味著狮崩,在屏幕顯示時蛛勉,后面還準備了3個數(shù)據(jù)用于顯示。

文章內(nèi)容和圖片引用來自:Style_月月

文章源地址

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末睦柴,一起剝皮案震驚了整個濱河市诽凌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌坦敌,老刑警劉巖侣诵,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異狱窘,居然都是意外死亡杜顺,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門蘸炸,熙熙樓的掌柜王于貴愁眉苦臉地迎上來躬络,“玉大人,你說我怎么就攤上這事搭儒∏畹保” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵淹禾,是天一觀的道長馁菜。 經(jīng)常有香客問我,道長铃岔,這世上最難降的妖魔是什么汪疮? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮德撬,結(jié)果婚禮上铲咨,老公的妹妹穿的比我還像新娘躲胳。我一直安慰自己蜓洪,他們只是感情好,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布坯苹。 她就那樣靜靜地躺著隆檀,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上恐仑,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天泉坐,我揣著相機與錄音,去河邊找鬼裳仆。 笑死腕让,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的歧斟。 我是一名探鬼主播纯丸,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼静袖!你這毒婦竟也來了觉鼻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤队橙,失蹤者是張志新(化名)和其女友劉穎坠陈,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捐康,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡仇矾,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了解总。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片若未。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖倾鲫,靈堂內(nèi)的尸體忽然破棺而出粗合,到底是詐尸還是另有隱情,我是刑警寧澤乌昔,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布隙疚,位于F島的核電站,受9級特大地震影響磕道,放射性物質(zhì)發(fā)生泄漏供屉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一溺蕉、第九天 我趴在偏房一處隱蔽的房頂上張望伶丐。 院中可真熱鬧,春花似錦疯特、人聲如沸哗魂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽录别。三九已至朽色,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間组题,已是汗流浹背葫男。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留崔列,地道東北人梢褐。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像赵讯,于是被迫代替她去往敵國和親利职。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359