iOS中離屏渲染觸發(fā)機制

iOS系統(tǒng)中離屏渲染利與弊

閱讀需要約8分鐘

前言

性能的優(yōu)化相信是每一個APP工程師所追求的遵岩,而離屏渲染就是一個繞不開的知識點”┲簦現(xiàn)在提出幾個問題幫助大家更快的理解:

  1. 什么情況下會觸發(fā)離屏渲染,為什么?
  2. 利柴我、弊都有哪些榕茧?
  • 離屏渲染是如何發(fā)生的

先通過模擬器來看看是情況下會發(fā)生離屏渲染咐蝇。
打開模擬器 - Debug - Color Off-screen Rendered開關


提起離屏渲染特姐,下意識的就是會想到cornerRadius這個屬性,設置圓角就會導致離屏渲染浮梢,事實是這樣嗎跛十?

        let view1 = UIView(frame: rect)
        view1.backgroundColor = UIColor.red
        view1.layer.cornerRadius = 50
        view1.layer.borderWidth = 2
        view.addSubview(view1)

沒有觸發(fā)離屏渲染


我們先來看看蘋果官方文檔對于cornerRadius的描述:

Setting the radius to a value greater than 0.0 causes the layer to begin drawing rounded corners on its background. By default, the corner radius does not apply to the image in the layer’s contents property; it applies only to the background color and border of the layer. However, setting the masksToBounds property to true causes the content to be clipped to the rounded corners.

我們發(fā)現(xiàn)設置cornerRadius大于0時,只為layer的backgroundColorborder設置圓角秕硝;而不會對layer的contents設置圓角芥映,除非同時設置了layer.masksToBounds為true或者UIView的clipsToBounds屬性。那我們設置這兩個屬性看一下。

        let view1 = UIView(frame: rect)
        view1.backgroundColor = UIColor.red
        view1.layer.cornerRadius = 50
        view1.layer.borderWidth = 2
        view1.layer.masksToBounds = true
        view1.clipsToBounds = true
        view.addSubview(view1)


事實上還是沒有觸發(fā)離屏渲染,這就很奇怪了奈偏。


這時候就需要了解一下幾個屬性的關系了


發(fā)現(xiàn)其實圖中3個屬性坞嘀,對應了3個圖層。我們看到的圖像其實是這3個圖層的合并霎苗,這面會涉及到一個畫家算法姆吭,下一節(jié)會說到。原來contents是單獨的個圖層唁盏,那我們設置它看一下内狸。

        let view1 = UIView(frame: rect)
        view1.backgroundColor = UIColor.red
        view1.layer.cornerRadius = 50
        view1.layer.borderWidth = 2
        view1.layer.contents = UIImage(named: s)?.cgImage
        view1.layer.masksToBounds = true
        view1.clipsToBounds = true
        view.addSubview(view1)

在當同時設置了backgroundColor|borderWidth,cornerRadius,contents,masksToBounds這四個屬性時,導致了離屏渲染厘擂。


我們設置了content后觸發(fā)了離屏渲染昆淡,如果我們只設置content看看會不會觸發(fā)呢?

        let view1 = UIView(frame: rect)
        view1.layer.cornerRadius = 50
        view1.layer.contents = UIImage(named: s)?.cgImage
        view1.layer.masksToBounds = true
        view1.clipsToBounds = true
        view.addSubview(view1)

在其他設置都沒有變的情況下刽严,只設置了content并沒有觸發(fā)離屏渲染昂灵。有沒有隱約感覺到一點觸發(fā)規(guī)律:

  1. 設置了cornerRadius
  2. 同時設置了backgroundColor或者borderWidthcontent
  3. 設置了masksToBounds或者clipsToBounds**

可是為什么呢?想要搞清楚就需要了解畫家算法舞萄。

畫家算法

所謂畫家算法是計算機將多個圖層由遠到近進行繪制的一種算法眨补。先的圖層會被后的圖層所覆蓋。
這里接涉及到計算機渲染的原理倒脓,其中非常重要的一個點就是:圖層被渲染到畫布上之后撑螺,當前圖層就會被永久銷毀,所以面對多個圖層時從遠到近繪制崎弃,保證了可視范圍內容的完整甘晤,最后保存到幀緩存區(qū)等待讀取。

  • 離屏渲染產生的原理


需要在額外的內存中完成多圖層組合繪制工作

GPU中的離屏渲染

現(xiàn)在我對上圖中增加一個圓角饲做,而上圖是由3個圖層組成的线婚,且圖層渲染到畫布后就會被銷毀,導致GPU沒辦法一次性拿到所有圖層來進行圓角切割. 所以現(xiàn)在就需要創(chuàng)建一塊空間盆均,將3個圖層都保存起來后完成圓角切割塞弊。而這個單獨的空間就叫做offSet-buffer,離屏渲染就這樣產生了泪姨,當然這個圖層繪制一般是由GPU完成的居砖,也有些特殊情況下CPU也會參與繪制。

CPU中的“離屏渲染”
  • 在CoreAnimation 渲染流程中Display流程的視圖層繪制中提過驴娃,如果開啟drawRect:方法就會觸發(fā)CPU的“離屏渲染”,該方法里的所有代碼都是在CPU中進行執(zhí)行循集,知道完成bitmap唇敞,轉存到幀緩存區(qū)中。但是根據(jù)蘋果工程師的說法,CPU的渲染并不是真正意義的離屏渲染疆柔,當然通過Xcode調試也能看出來咒精,該區(qū)域并沒有被標記為黃色,說明Xcode也認為這不屬于離屏渲染旷档。

label沒有觸發(fā)xcode離屏渲染模叙,所以推測繪制文字的 layer (UILabel, CATextLayer, Core Text 等)是使用CPU來進行的渲染,說一下我這樣的猜測的理由:文字渲染更多涉及邏輯計算所以CPU更加適合做這件事鞋屈。

  • 常見離屏渲染場景分析

1. cornerRadius+clipsToBounds

同時打開backgroundColor|borderWidth,cornerRadius,contents,masksToBounds這個情況前面已經分析過了范咨,屬性的打開會導致多個圖層的裁剪,所以必須在offset-buffer中完成全圖圖層裁剪后才可以放入幀緩存區(qū)中厂庇。當然還有其他方法設置圓角但不會觸發(fā)離屏渲染UIBezierPath渠啊。

UIBezierPath會涉及到CoreGraphics,在渲染流程
中負責圖層的繪制权旷√骝龋可知使用了UIBezierPath在每一個單圖層繪制的計算中就已經處理了每個圖層的圓角,這時畫在畫布上的圖層就已經是圓角了拄氯,估避免了離屏渲染躲查。

2. shadow

開啟shadow后會增加一個額外的圖層,這個圖層是在最先被繪制的译柏,可是這時并不知道content的大小镣煮,所以還是沒法分開繪制,需要offSet-buffer的支持艇纺。
也可以使用shadowPath提前告知陰影路勁就可以避免離屏渲染怎静。

3. group opacity(組透明度)

這個很好理解,多個圖層都帶著透明度黔衡,在重疊位置會造成顏色的混合蚓聘。重疊后的顏色需要計算,而上一層已經被銷毀了盟劫,計算機并不知道其顏色所以無法計算夜牡。這時就需要把所有圖層都存到offset-Buffer,不可避免的觸發(fā)了離屏渲染侣签。

4. mask

增加mask涉及到多圖層的重疊塘装,而且有些圖層是有透明度的,原理和group opacity類似影所。

5. shouldRasterize(光柵化)

及時離屏渲染消耗很大蹦肴,但是面對復雜圖層,好不容易繪制好了為什么不想辦法復用它呢?這時蘋果大大就提供了shouldRasterize這個屬性猴娩,打開這個屬性造成離屏渲染阴幌,但是渲染好的內容會被緩存起來勺阐,一定條件下就可以復用。如果合理使用這個屬性就可以將性能消耗降到最低矛双。
滿足這幾個條件就可以使用shouldRasterize:

  • layer的內容(包括子layer)必須是靜態(tài)的渊抽,因為一旦發(fā)生變化,之前辛苦處理得到的緩存就失效了议忽。如果這件事頻繁發(fā)生懒闷,我們就又回到了“每一幀都需要離屏渲染”的情景,而這正是開發(fā)者需要極力避免的栈幸。針對這種情況愤估,Xcode提供了“Color Hits Green and Misses Red”的選項,幫助我們查看緩存的使用是否符合預期
  • 由于系統(tǒng)提供的offset-buffer的空間是有限的:屏幕尺寸的2.5倍侦镇。所以無法長時間占用灵疮,系統(tǒng)只提供了100ms,如果100ms沒被使用依舊會被釋放壳繁。
6. 文字以及drawRect

CPU的'離屏渲染'時已經說明震捣,不在贅述。

后續(xù)

最初的兩個問題在文中已經有明確的答案闹炉,耐心閱讀可能會有新發(fā)現(xiàn)蒿赢。

推薦閱讀:
極客技術團隊-關于iOS離屏渲染的深入研究

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市渣触,隨后出現(xiàn)的幾起案子羡棵,更是在濱河造成了極大的恐慌,老刑警劉巖嗅钻,帶你破解...
    沈念sama閱讀 212,029評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件皂冰,死亡現(xiàn)場離奇詭異,居然都是意外死亡养篓,警方通過查閱死者的電腦和手機秃流,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來柳弄,“玉大人舶胀,你說我怎么就攤上這事”套ⅲ” “怎么了嚣伐?”我有些...
    開封第一講書人閱讀 157,570評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長萍丐。 經常有香客問我轩端,道長,這世上最難降的妖魔是什么逝变? 我笑而不...
    開封第一講書人閱讀 56,535評論 1 284
  • 正文 為了忘掉前任基茵,我火速辦了婚禮刻撒,結果婚禮上,老公的妹妹穿的比我還像新娘耿导。我一直安慰自己,他們只是感情好态贤,可當我...
    茶點故事閱讀 65,650評論 6 386
  • 文/花漫 我一把揭開白布舱呻。 她就那樣靜靜地躺著,像睡著了一般悠汽。 火紅的嫁衣襯著肌膚如雪箱吕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,850評論 1 290
  • 那天柿冲,我揣著相機與錄音茬高,去河邊找鬼。 笑死假抄,一個胖子當著我的面吹牛怎栽,可吹牛的內容都是我干的。 我是一名探鬼主播宿饱,決...
    沈念sama閱讀 39,006評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼熏瞄,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了谬以?” 一聲冷哼從身側響起强饮,我...
    開封第一講書人閱讀 37,747評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎为黎,沒想到半個月后邮丰,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 44,207評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡铭乾,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,536評論 2 327
  • 正文 我和宋清朗相戀三年剪廉,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片片橡。...
    茶點故事閱讀 38,683評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡妈经,死狀恐怖,靈堂內的尸體忽然破棺而出捧书,到底是詐尸還是另有隱情吹泡,我是刑警寧澤,帶...
    沈念sama閱讀 34,342評論 4 330
  • 正文 年R本政府宣布经瓷,位于F島的核電站爆哑,受9級特大地震影響,放射性物質發(fā)生泄漏舆吮。R本人自食惡果不足惜揭朝,卻給世界環(huán)境...
    茶點故事閱讀 39,964評論 3 315
  • 文/蒙蒙 一队贱、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧潭袱,春花似錦柱嫌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至彤悔,卻和暖如春嘉抓,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背晕窑。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評論 1 266
  • 我被黑心中介騙來泰國打工抑片, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人杨赤。 一個月前我還...
    沈念sama閱讀 46,401評論 2 360
  • 正文 我出身青樓敞斋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親望拖。 傳聞我的和親對象是個殘疾皇子渺尘,可洞房花燭夜當晚...
    茶點故事閱讀 43,566評論 2 349