圖像顯示及屏幕渲染

1肮帐、圖像顯示原理
2咖驮、UI卡頓、掉幀
3训枢、異步繪制
4托修、離屏渲染

圖像顯示原理

圖像的顯示實際上要經(jīng)過CPU的布局、計算恒界,GPU的繪制渲染等操作才能顯示到屏幕上睦刃。
CPU GPU 這兩個硬件實際上是是由總線連接起來的, CPU 中輸出的往往是一個位圖(像素數(shù)組) 在經(jīng)由總線上傳給GPU十酣, GPU在拿到這個位圖時會做相應位圖的渲染 紋理的合成涩拙, 然后把結(jié)果放入幀緩沖區(qū)中, 由視頻控制器提取對應顯示內(nèi)容交給顯示器顯示耸采。


圖像顯示原理.png
CPU工作流程.png
  • layout:UI布局frame兴泥,文本計算label的size計算等。
  • display:繪制過程drawRect方法虾宇。
  • prepare:圖片解碼搓彻。
  • commit:提交位圖。
GPU渲染管線.png

UI卡頓嘱朽、掉幀

一般來說旭贬,頁面滑動的流暢性是60FPS,代表著每秒鐘有六十幀畫面更新搪泳,也就是每一幀畫面的生成時間在1/60秒即16.7ms以內(nèi)就不會卡頓稀轨。在16.7毫秒內(nèi)需要CPU和GPU共同來生成一幀的數(shù)據(jù)。如果時間超過了16.7ms就會產(chǎn)生卡頓森书。


UI 卡頓、掉幀.png

掉幀原因:
在 VSync 信號到來后,系統(tǒng)圖形服務會通過 CADisplayLink 等機制通知 App凛膏,App 主線程開始在 CPU 中計算顯示內(nèi)容杨名,比如視圖的創(chuàng)建、布局計算猖毫、圖片解碼台谍、文本繪制等。隨后 CPU 會將計算好的位圖提交到 GPU 去吁断,由 GPU拿到位圖后 進行變換趁蕊、合成、渲染仔役。隨后 GPU 會把渲染結(jié)果提交到幀緩沖區(qū)去掷伙,等待下一次 VSync 信號到來時顯示到屏幕上。由于垂直同步的機制又兵,如果在一個 VSync 時間內(nèi)任柜,CPU 或者 GPU 沒有完成內(nèi)容提交,則那一幀就會被丟棄沛厨,等待下一次機會再顯示宙地,而這時顯示屏會保留之前的內(nèi)容不變。這就是界面卡頓的原因逆皮。

從上面的圖中可以看到宅粥,CPU 和 GPU 不論哪個阻礙了顯示流程,都會造成掉幀現(xiàn)象电谣。所以開發(fā)時秽梅,也需要分別對 CPU 和 GPU 壓力進行評估和優(yōu)化。

滑動優(yōu)化

CPU (放到子線程操作)
對象的創(chuàng)建辰企、調(diào)整风纠、銷毀
預排版(布局計算、文本計算)
預渲染(文本等異步繪制牢贸,圖片編解碼等)

GPU
紋理渲染(避免離屏渲染济榨,同時可以依托CPU的異步繪制 減輕 GPU的壓力)
視圖混合(減少視圖層級)

UI 視圖繪制原理及異步繪制

繪制流程.png

通過這個繪制流程圖我們來看UIView的繪制過程:
當調(diào)用[UIView setNeedsDisplay]時赴涵,實際上并沒有立馬進行當前視圖的繪制工作,而是在之后的某一時間才進行當前視圖的實際繪制工作。
當調(diào)用[UIView setNeedsDisplay]之后从橘,系統(tǒng)會立馬調(diào)用layer的同名方法setNeedsDisplay,之后相當于在layer上打上一個臟標記指孤,然后當當前的runloop將要結(jié)束時狈蚤,調(diào)用[CALayer display]進行當前視圖的真正繪制流程。
[CALayer display]內(nèi)部會先判斷這個layer的delegate是否會響應displayLayer:方法整陌,如果不響應就會進入系統(tǒng)繪制流程中拗窃。如果能夠響應瞎领,實際上是提供了異步繪制的入口,也就是給我們進行異步繪制留有余地随夸。

  • 系統(tǒng)繪制流程
    在drawRectangle:方法當中九默,可以通過上下文堆棧當中取出棧頂?shù)腸ontext,拿到的就是當前控件或者視圖的上下文或者backingStore宾毒,然后layer會判斷它是否有delegate驼修,如果沒有的話,會調(diào)用drawInContext诈铛;如果有的話乙各,會調(diào)用layer的代理方法drawLayer: inContext:,然后做當前視圖的繪制工作幢竹,這一部分發(fā)生在系統(tǒng)內(nèi)部耳峦,然后在一個合適的時機給我們一個回調(diào)方法,即[UIView drawRect:]方法妨退,這個方法默認什么都不做妇萄,而是給我們開個口子,是允許在系統(tǒng)繪制的基礎(chǔ)上再做一些其他的繪制操作咬荷。
    無論是哪種分支冠句,之中都是由CALayer上傳到對應backingStore到GPU,這里的backingStore可以理解為最終的位圖幸乒,之后就結(jié)束了系統(tǒng)默認的繪制流程懦底。


    系統(tǒng)繪制.png
  • 異步繪制流程
    實際上就是基于系統(tǒng)開的口子,layer的delegate罕扎,如果遵從了displayLayer方法聚唐,或者說實現(xiàn)了這個方法的話,我們就可以進入到異步繪制的流程當中腔召,在異步繪制當中就需要代理去負責生成對應的bitmap杆查,同時需要我們把位圖作為layer的content屬性提交到layer的content屬性當中。

通過實現(xiàn)layer的代理方法displayLayer
- 代理負責生成對應的bitmap
- 設(shè)置該bitmap作為layer.contents屬性的值


異步繪制.png

左側(cè)是一個主隊列臀蛛,右側(cè)是一個全局并發(fā)隊列亲桦,假如在某一時機調(diào)用了setNeedsDisplay,在當前runloop將要結(jié)束的時候會由系統(tǒng)調(diào)用視圖所對應layer的display方法浊仆,然后如果代理實現(xiàn)了displayLayer函數(shù)的時候客峭,會調(diào)用代理的displayerLayer函數(shù)方法,然后會通過子線程的切換抡柿,在子線程當中去做位圖的繪制舔琅,此時主線程可以做一些其他的工作。
在全局并發(fā)隊列子線程當中所做的工作主要有這么幾個步驟洲劣,第一個是通過CGBitmapContextCreate() 來創(chuàng)建位圖的上下文备蚓,然后通過CoreGraphic的相關(guān)API做當前UI的一些繪制工作课蔬,之后我們再通過CoreGraphic的相關(guān)函數(shù)CGBitmapContextCreateImage來根據(jù)當前所繪制的上下文生成一張CGImage圖片,再回到主隊列當中郊尝,提交這個位圖购笆,設(shè)置給 CALayer 的content屬性,這樣的話就完成了一個UI控件的異步繪制過程虚循。

離屏渲染

什么是離屏渲染?你對離屏渲染是怎么理解的样傍?

  • On-Screen Rendering
    意為當前屏幕渲染横缔,指的是GPU的渲染操作是在當前用于顯示的屏幕緩沖區(qū)中進行
  • Off-Screen Rendering
    意為離屏渲染,指的是GPU在當前屏幕緩沖區(qū)以外新開辟一個緩沖區(qū)進行渲染操作

用一個比較通俗的語言解釋離屏渲染:也就是當我們設(shè)置某一些UI視圖的圖層屬性衫哥,如果說指定成在被未預合成之前茎刚,不能用于直接被顯示的時候,那么就觸發(fā)了離屏渲染撤逢。典型的比如我們設(shè)置視圖的圓角屬性膛锭,包括一些蒙層遮罩。

什么場景下會觸發(fā)離屏渲染蚊荣?

  • 圓角(和maskToBounds一起使用時)

  • 圖層蒙版

  • 陰影

  • 光柵化

    • 為何要避免離屏渲染初狰?
      CPU和GPU在進行具體的視圖繪制渲染的過程中做了大量的工作。而離屏渲染是發(fā)生在GPU層面的互例,由于離屏渲染使GPU層面上觸發(fā)了OpenGL的多通道渲染管線奢入,產(chǎn)生了額外的開銷,所以需要避免離屏渲染媳叨。

在觸發(fā)離屏渲染時會增加GPU的工作量腥光,而增加GPU的工作量很有可能導致CPU和GPU工作耗時超出16.7ms,可能導致UI的卡頓和掉幀糊秆,所以需要避免離屏渲染武福。

  • 創(chuàng)建新的渲染緩沖區(qū)
  • 上下文切換
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市痘番,隨后出現(xiàn)的幾起案子捉片,更是在濱河造成了極大的恐慌,老刑警劉巖夫偶,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件界睁,死亡現(xiàn)場離奇詭異,居然都是意外死亡兵拢,警方通過查閱死者的電腦和手機翻斟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來说铃,“玉大人访惜,你說我怎么就攤上這事嘹履。” “怎么了债热?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵砾嫉,是天一觀的道長。 經(jīng)常有香客問我窒篱,道長焕刮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任墙杯,我火速辦了婚禮配并,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘高镐。我一直安慰自己溉旋,他們只是感情好,可當我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布嫉髓。 她就那樣靜靜地躺著观腊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪算行。 梳的紋絲不亂的頭發(fā)上梧油,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天,我揣著相機與錄音州邢,去河邊找鬼婶溯。 笑死,一個胖子當著我的面吹牛偷霉,可吹牛的內(nèi)容都是我干的迄委。 我是一名探鬼主播,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼类少,長吁一口氣:“原來是場噩夢啊……” “哼叙身!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起硫狞,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤信轿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后残吩,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體财忽,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年泣侮,在試婚紗的時候發(fā)現(xiàn)自己被綠了即彪。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡活尊,死狀恐怖隶校,靈堂內(nèi)的尸體忽然破棺而出漏益,到底是詐尸還是另有隱情,我是刑警寧澤深胳,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布绰疤,位于F島的核電站,受9級特大地震影響舞终,放射性物質(zhì)發(fā)生泄漏轻庆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一敛劝、第九天 我趴在偏房一處隱蔽的房頂上張望榨了。 院中可真熱鬧,春花似錦攘蔽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至作岖,卻和暖如春唆垃,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背痘儡。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工辕万, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人沉删。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓渐尿,卻偏偏與公主長得像,于是被迫代替她去往敵國和親矾瑰。 傳聞我的和親對象是個殘疾皇子砖茸,可洞房花燭夜當晚...
    茶點故事閱讀 44,969評論 2 355

推薦閱讀更多精彩內(nèi)容