onScreen和offScreen渲染(一)

版本記錄

版本號 時間
V1.0 2017.06.15

前言

我們要在界面上看到東西,是因為控件被渲染到屏幕上的原因娩贷,說到渲染大家都知道包括當屏渲染和離屏渲染,這里就和大家說一下onScreen和offScreen。

onScreen渲染

顧名思義棍好,就是將視圖直接渲染到屏幕上。onscreen render指的是GPU在當前用于顯示的屏幕緩沖區(qū)進行渲染允耿。


offScreen渲染

一借笙、基本概念

offscreen rendring指的是在圖像在繪制到當前屏幕前,需要先進行一次渲染,之后才繪制到當前屏幕。 那么為什么offscreen渲染會耗費大量資源呢较锡? 原因是顯卡需要另外alloc一塊內(nèi)存來進行渲染业稼,渲染完畢后在繪制到當前屏幕,而且對于顯卡來說蚂蕴,onscreen到offscreen的上下文環(huán)境切換是非常昂貴的(涉及到OpenGL的pipelines和barrier等)低散。
??與當前屏幕渲染相比,離屏渲染的代價是很高的骡楼,主要體現(xiàn)在兩個方面:

  • 創(chuàng)建新緩沖區(qū):要想進行離屏渲染熔号,首先要創(chuàng)建一個新的緩沖區(qū)。
  • 上下文切換:離屏渲染的整個過程鸟整,需要多次切換上下文環(huán)境跨嘉。先是從當前屏幕(On-Screen)切換到離屏(Off-Screen);等到離屏渲染結(jié)束以后吃嘿,將離屏緩沖區(qū)的渲染結(jié)果顯示到屏幕上又需要將上下文環(huán)境從離屏切換到當前屏幕祠乃。但是,上下文環(huán)境的切換是要付出很大代價的兑燥。

二亮瓷、離屏渲染的幾種情況

  • Any layer with a mask (layer.mask)
  • Any layer with layer.masksToBounds / view.clipsToBounds being true
  • Any layer with layer.allowsGroupOpacity set to YES and layer.opacity is less than 1.0
  • Any layer with a drop shadow (layer.shadow*).
  • Any layer with layer.shouldRasterize being true
  • Any layer with layer.cornerRadius, layer.edgeAntialiasingMask, layer.allowsEdgeAntialiasing
    Text (any kind, including UILabel, CATextLayer, Core Text, etc).
  • Most of the drawing you do with CGContext in drawRect:. Even an empty implementation will be rendered offscreen.

下面我就給大家翻一下,英語不好降瞳,翻譯不對的地方請指出嘱支。

  • 帶有遮罩的layer
  • layer.masksToBounds和view.clipsToBounds設(shè)置為YES
  • layer.allowsGroupOpacity設(shè)置為YES或者layer.opacity<1.0
  • layer帶有陰影shadow
  • layer.shouldRasterize設(shè)置為YES
    • layer設(shè)置shouldRasterize=Y(jié)ES之后蚓胸,會把被光柵化的圖層保存成位圖并緩存起來,其中圓角或者陰影之類的效果也是直接保存到位圖當中除师,當需要渲染到屏幕上的時候只需要到緩存中去取對應的位圖進行顯示就行了沛膳,加快了整個渲染過程⊙淳郏可以通過勾選instruments core animation中的Color Hits Green and Misses Red選項來查看圖層是否被緩存了锹安,如果圖層顯示為綠色則表示已經(jīng)被緩存起來了,也就是這個緩沖區(qū)的內(nèi)容被復用了倚舀,不用在去重新創(chuàng)建緩沖區(qū)叹哭,反之則是用紅色標示。設(shè)置shouldRasterize之后痕貌,如果滑動過程中發(fā)現(xiàn)都是紅色的證明就有問題了风罩。也可以這么表述:如果在設(shè)置為YES后,在快速滾動的時候舵稠,綠色較少超升,而紅色較多,說明并不可觀哺徊,表示不建議使用光柵化廓俭。相反,如果在快速滾動的時候唉工,基本都是綠色的研乒,只有極少數(shù)偶爾出現(xiàn)紅色,那么使用光柵化來優(yōu)化是可以達到很好的效果的淋硝。
  • layer設(shè)置了 layer.cornerRadius, layer.edgeAntialiasingMask, layer.allowsEdgeAntialiasing Text(任何種類雹熬,包括UILabel、CATextLayer谣膳、CoreText等)
  • 在drawRect中利用上下文CGContext繪圖竿报,即使什么都沒畫,只是空的實現(xiàn)也會導致離屏渲染继谚。

大家都知道離屏渲染多了烈菌,系統(tǒng)性能就會降低,變的很卡花履。所以要盡量避免以下幾點:

  • 盡量將視圖背景色和superView的背景色一致/背景色不要為clearColor(會引起圖層混合)芽世。

  • 假如最上層的view是不透明的,那直接使用這個view的對應顏色之就可以诡壁,但如果view是透明的济瓢,在計算像素的顏色值時就需要計算它下面圖層,透明的視圖越多妹卿,計算量就越大旺矾,因此也會對圖形的性能產(chǎn)生一定的影響蔑鹦,所以可以的話也盡量減少透明圖層的數(shù)目。

  • 光柵化對于那些有很多子view嵌套在一起箕宙、view的層級復雜或者有很復雜特效效果的圖層有很明顯的提升嚎朽,因為這些內(nèi)容都被緩存到位圖當中了。但是使用光柵化需要注意一些內(nèi)容:

    • 適用于內(nèi)容基本不變的圖層
      假如圖層的內(nèi)容經(jīng)常變化柬帕,比如cell里面有涉及到動畫之類的哟忍,那么緩存的內(nèi)容就無效了,GPU需要重新創(chuàng)建緩存區(qū)雕崩,導致離屏渲染,這又涉及到OpenGL的上下文環(huán)境切換融撞,反而降低性能盼铁。
    • 不要過度使用
      緩存區(qū)的大小被設(shè)置為屏幕大小的2.5倍,假如過分使用同樣會導致大量的離屏渲染尝偎。
    • 如果緩存的內(nèi)容超過100ms沒有被使用則會被回收饶火。
  • 避免離屏渲染。將圖層的alpha設(shè)為1(如何其不為1致扯,圖層合成過程中肤寝,將引起大量的計算),uiview的圓角抖僵,遮罩 也會引起離屏渲染鲤看。

  • 減少不必要的drawrect()操作。

  • 處理好UIView 與 CALayer的關(guān)系耍群。UIView層次不要太多义桂。因為這樣會加多合成。

  • 將線程安全的操作挪到非主線程蹈垢。比如繪制圖片等慷吊。

三、界面卡頓的原因

可能大家有所疑惑曹抬,為什么有的時候說性能低界面卡溉瓶,到底是什么原因,其實可以從軟硬件結(jié)合的角度講谤民。

原因:GPU垂直同步信號(VSync堰酿,硬件產(chǎn)生的),固定1/60S發(fā)出一次张足。在此時間間隔內(nèi)胞锰,CPU、GPU需要準備好數(shù)據(jù)兢榨。在 VSync 信號到來后嗅榕,系統(tǒng)圖形服務會通過 CADisplayLink 等機制通知 App顺饮,App 主線程開始在 CPU 中計算顯示內(nèi)容,比如視圖的創(chuàng)建凌那、布局計算兼雄、圖片解碼、文本繪制等帽蝶。隨后 CPU 會將計算好的內(nèi)容提交到 GPU 去赦肋,由 GPU 進行變換、合成励稳、渲染佃乘。隨后 GPU 會把渲染結(jié)果提交到幀緩沖區(qū)去,等待下一次 VSync 信號到來時顯示到屏幕上驹尼。由于垂直同步的機制趣避,如果在一個 VSync 時間內(nèi),CPU 或者 GPU 沒有完成內(nèi)容提交新翎,則那一幀就會被丟棄程帕,等待下一次機會再顯示,而這時顯示屏會保留之前的內(nèi)容不變地啰。這就是界面卡頓的原因愁拭。即FPS降低。

  • CPU做的工作:對象的創(chuàng)建亏吝;調(diào)整岭埠;layout;布局的計算蔚鸥;文本的計算枫攀,渲染;圖片的渲染株茶,解碼来涨,渲染等。
  • GPU做的工作:紋理的渲染启盛,圖形混合蹦掐,圖形生成。(離屏渲染發(fā)生在GPU中)僵闯。

四卧抗、離屏渲染的分類

離屏渲染分為兩種:一種是CPU的渲染,另外一種就是GPU渲染鳖粟。

CPU離屏渲染

使用CPU來完成渲染操縱社裆,通常在你使用:

  • drawRect (如果沒有自定義繪制的任務就不要在子類中寫一個空的drawRect方法,因為只要實現(xiàn)了該方法向图,就會為視圖分配一個寄宿圖泳秀,這個寄宿圖的像素尺寸等于視圖大小乘以 contentsScale的值标沪,造成資源浪費)。
  • 使用Core Graphics嗜傅。

上面的兩種情況使用的就是CPU離屏渲染金句,首先分配一塊內(nèi)存,然后進行渲染操作生成一份bitmap位圖吕嘀,整個渲染過程會在你的應用中同步的進行违寞,接著再將位圖打包發(fā)送到iOS里一個單獨的進程--render server,理想情況下偶房,render server將內(nèi)容交給GPU直接顯示到屏幕上趁曼。

GPU離屏渲染

使用GPU在當前屏幕緩沖區(qū)以外開辟一個新的緩沖區(qū)進行繪制,通常發(fā)生的情況有:

  • 設(shè)置cornerRadius, masks, shadows,edge antialiasing(抗鋸齒)等
  • 設(shè)置layer.shouldRasterize = YES

具體的渲染過程如下圖所示棕洋。

渲染過程圖

通常大家說的離屏渲染指的是GPU這塊(當然CPU這塊也會有影響挡闰,也需要消耗一定的資源),比如修改了layer的陰影或者圓角拍冠,GPU需要做額外的渲染操作尿这。通常GPU在做渲染的時候是很快的簇抵,但是涉及到offscreen-render的時候情況就可能有些不同庆杜,因為需要額外開辟一個新的緩沖區(qū)進行渲染,然后繪制到當前屏幕的過程需要做onscreen跟offscreen上下文之間的切換碟摆,這個過程的消耗會比較昂貴晃财,涉及到OpenGL的pipeline跟barrier,而且offscreen-render在每一幀都會涉及到典蜕,因此處理不當肯定會對性能產(chǎn)生一定的影響断盛,所以可以的話盡量減少offscreen-render的圖層,查看哪些圖層需要離屏渲染可以用Instruments的Core Animation工具進行檢測愉舔,Color Offscreen-Rendered Yellow選項會將對應的圖層標記為黃色钢猛。

五、提高性能的幾種方式

  • 對于圓角可以使用一張中間圓形透明的圖覆蓋在上面轩缤,雖然這會引入blending操作命迈,但是大部分情況下性能會比離屏渲染好。
  • 讓你的view層次結(jié)構(gòu)平坦一些火的,因為OpenGL在渲染layer的時候壶愤,在碰到有子層級layer的時候可能需要停下來把兩者合成到一個buffer里再接著渲染。(When the OpenGL renderer goes to draw each layer, it may have to stop for some subhierarchies and composite them into a single buffer).
  • 延遲加載圖片
    有時候在邊滾動邊設(shè)置圖片的時候可能會有一定的影響馏鹤,因此可以在滾動的時候imageview不執(zhí)行setimage的操作征椒,滾動停止的時候才加載圖片,由于滾動的時候NSRunloop是處于UITrackingRunLoopMode模式下湃累,可以采用如下的方式勃救,將設(shè)置圖片放到NSDefaultRunLoopMode模式下才進行:
UIImage *downloadedImage = ...;
  [self.avatarImageView performSelector:@selector(setImage:)
                             withObject:downloadedImage
                             afterDelay:0
                                inModes:@[NSDefaultRunLoopMode]];

圖片加載的極限優(yōu)化方式:FastImageCache

五碍讨、offScreen檢測

??利用instruments可以檢測offScreen,在Instruments->Core Animation下剪芥,如下圖垄开。

offScreen檢測

注意:要在真機上才可以。

參考文章

1.iOS app性能優(yōu)化的那些事(二)

后記

未完税肪,待續(xù)溉躲,希望大家能喜歡~~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市益兄,隨后出現(xiàn)的幾起案子锻梳,更是在濱河造成了極大的恐慌,老刑警劉巖净捅,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疑枯,死亡現(xiàn)場離奇詭異,居然都是意外死亡蛔六,警方通過查閱死者的電腦和手機荆永,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來国章,“玉大人具钥,你說我怎么就攤上這事∫菏蓿” “怎么了骂删?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長四啰。 經(jīng)常有香客問我宁玫,道長,這世上最難降的妖魔是什么柑晒? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任欧瘪,我火速辦了婚禮,結(jié)果婚禮上匙赞,老公的妹妹穿的比我還像新娘佛掖。我一直安慰自己,他們只是感情好罚屋,可當我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布苦囱。 她就那樣靜靜地躺著,像睡著了一般脾猛。 火紅的嫁衣襯著肌膚如雪撕彤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天,我揣著相機與錄音羹铅,去河邊找鬼蚀狰。 笑死,一個胖子當著我的面吹牛职员,可吹牛的內(nèi)容都是我干的麻蹋。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼焊切,長吁一口氣:“原來是場噩夢啊……” “哼扮授!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起专肪,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤刹勃,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后嚎尤,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體荔仁,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年芽死,在試婚紗的時候發(fā)現(xiàn)自己被綠了乏梁。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡关贵,死狀恐怖遇骑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情坪哄,我是刑警寧澤质蕉,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布势篡,位于F島的核電站翩肌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏禁悠。R本人自食惡果不足惜念祭,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望碍侦。 院中可真熱鬧粱坤,春花似錦、人聲如沸瓷产。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽濒旦。三九已至株旷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背晾剖。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工锉矢, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人齿尽。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓沽损,卻偏偏與公主長得像,于是被迫代替她去往敵國和親循头。 傳聞我的和親對象是個殘疾皇子绵估,可洞房花燭夜當晚...
    茶點故事閱讀 45,500評論 2 359

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

  • 相比于當前屏幕渲染,離屏渲染的代價是很高的卡骂,這也是iOS移動端優(yōu)化的必要部分壹士。 OpenGL中,GPU屏幕渲染有以...
    一個人在路上走下去閱讀 8,863評論 0 74
  • 一偿警、概述 OpenGL ES是一套多功能開放標準的用于嵌入系統(tǒng)的C-based的圖形庫躏救,用于2D和3D數(shù)據(jù)的可視化...
    灣里有桃樹閱讀 527評論 0 0
  • 離屏渲染 通常來說,計算機系統(tǒng)中 CPU螟蒸、GPU盒使、顯示器是以上面這種方式協(xié)同工作的。CPU 計算好顯示內(nèi)容提交到 ...
    Colleny_Z閱讀 1,025評論 0 2
  • CALayer與UIView iOS界面中七嫌,看到的界面元素基本都是UIView少办,例如按鈕,文本诵原,圖片等都是集成自U...
    conowen閱讀 1,367評論 0 2
  • 卷首語 歡迎來到 objc.io 的第三期英妓! 這一期都是關(guān)于視圖層的。當然視圖層有很多方面绍赛,我們需要把它們縮小到幾...
    評評分分閱讀 1,770評論 0 18