離屏渲染

屏幕上最終顯示的數(shù)據(jù)有兩種加載流程

正常渲染加載流程
離屏渲染加載流程


image.png

從圖上看,他們之間的區(qū)別就是離屏渲染比正常渲染多了一個(gè)離屏緩沖區(qū),這個(gè)緩沖區(qū)的作用是什么呢檀何?下面來仔細(xì)說說

首先,說說正常渲染流程

正常渲染流程

APP中的數(shù)據(jù)經(jīng)過CPU計(jì)算和GPU渲染后,將結(jié)果存放在幀緩沖區(qū)愕把,利用視頻控制器從幀緩沖區(qū)中取出拣凹,并顯示到屏幕上。

在GPU的渲染流程中恨豁,顯示到屏幕上的圖像是遵循大畫家算法按照由遠(yuǎn)及近的順序嚣镜,依次將結(jié)果存儲(chǔ)到幀緩沖區(qū)
視屏控制器從幀緩沖區(qū)中讀取一幀數(shù)據(jù),將其顯示到屏幕上后圣絮,會(huì)立即丟棄這幀數(shù)據(jù)祈惶,不會(huì)做任何保留,這樣做的目的是可以節(jié)省空間扮匠,且在屏幕上是各自顯示各自的捧请,互相不影響。

image.png

離屏渲染流程

當(dāng)App需要進(jìn)行額外的渲染和合并時(shí)棒搜,例如按鈕設(shè)置圓角疹蛉,我們是需要對(duì)UIButton這個(gè)控件中的所有圖層都進(jìn)行圓角+裁剪,然后再將合并后的結(jié)果存入幀緩存區(qū)力麸,再?gòu)膸彺嬷腥〕鼋挥善聊伙@示可款,這時(shí),在正常的渲染流程中克蚂,我們是無法做到對(duì)所有圖層進(jìn)行圓角裁剪的闺鲸,因?yàn)樗怯靡粋€(gè)丟一個(gè)。所以我們需要提前將處理好的結(jié)果放入離屏緩沖區(qū)埃叭,最后將幾個(gè)圖層進(jìn)行疊加合并摸恍,存放到站緩沖區(qū),最后屏幕上就是我們想實(shí)現(xiàn)的效果赤屋。

離屏緩存區(qū)就是一個(gè)臨時(shí)的緩沖區(qū)立镶,用來存放在后續(xù)操作使用,但目前并不使用的數(shù)據(jù)类早。

離屏渲染再給我們帶來方便的同時(shí)媚媒,也帶來了嚴(yán)重的性能問題。由于離屏渲染中的離屏緩沖區(qū)涩僻,是額外開辟的一個(gè)存儲(chǔ)空間缭召,當(dāng)它將數(shù)據(jù)轉(zhuǎn)存到Frame Buffer時(shí),也是需要耗費(fèi)時(shí)間的逆日,所以在轉(zhuǎn)存的過程中恼琼,仍有掉幀的可能。
離屏緩沖區(qū)的空間并不是無限大的屏富, 它是又上限的晴竞,最大只能是屏幕的2.5倍
那為什么我們明知有性能問題時(shí),還是要使用離屏渲染呢狠半?

可以處理一些特殊的效果噩死,這種效果并不能一次就完成颤难,需要使用離屏緩沖區(qū)來保存中間狀態(tài),不得不使用離屏渲染已维,這種情況下的離屏渲染是系統(tǒng)自動(dòng)觸發(fā)的行嗤,例如經(jīng)常使用的圓角、陰影垛耳、高斯模糊栅屏、光柵化等
可以提升渲染的效率,如果一個(gè)效果是多次實(shí)現(xiàn)的堂鲜,可以提前渲染栈雳,保存到離屏緩沖區(qū),以達(dá)到復(fù)用的目的缔莲。這種情況是需要開發(fā)者手動(dòng)觸發(fā)的哥纫。

離屏渲染的另一個(gè)原因:光柵化

When the value of this property is YES, the layer is rendered as a bitmap in its local coordinate space and then composited to the destination with any other content.
當(dāng)我們開啟光柵化時(shí),會(huì)將layer渲染成位圖保存在緩存中痴奏,這樣在下次使用時(shí)蛀骇,就可以直接復(fù)用,提高效率读拆。
針對(duì)光柵化的使用擅憔,有以下幾個(gè)建議:

如果layer不能被復(fù)用,則沒有必要開啟光柵化
如果layer不是靜態(tài)檐晕,需要被頻繁修改(例如動(dòng)畫過程中)暑诸,此時(shí)開啟光柵化反而影響效率
離屏渲染緩存內(nèi)容有時(shí)間限制,如果100ms內(nèi)沒有被使用棉姐,那么就會(huì)丟棄屠列,無法進(jìn)行復(fù)用
離屏渲染的緩存空間有限啦逆,是屏幕的2.5倍伞矩,超過2.5倍屏幕像素大小的話也會(huì)失效,無法實(shí)現(xiàn)復(fù)用
圓角中離屏渲染的觸發(fā)時(shí)機(jī)

圓角設(shè)置不生效問題夏志!

在平常寫代碼時(shí)乃坤,比如UIButton設(shè)置圓角,當(dāng)設(shè)置好按鈕的image沟蔑、cornerRadius湿诊、borderWidth、borderColor等屬性后瘦材,運(yùn)行發(fā)現(xiàn)并沒有實(shí)現(xiàn)我們想要的效果

  let btn0 = UIButton(type: .custom)
     btn0.frame = CGRect(x: 100, y: 60, width: 100, height: 100)
     //設(shè)置圓角
     btn0.layer.cornerRadius = 50
     //設(shè)置border寬度和顏色
     btn0.layer.borderWidth = 2
     btn0.layer.borderColor = UIColor.red.cgColor
     self.view.addSubview(btn0)
     //設(shè)置背景圖片
     btn0.setImage(UIImage(named: "mouse"), for: .normal)

此時(shí)的效果就是這樣的厅须,可以發(fā)現(xiàn),我們?cè)O(shè)置的按鈕圖片還是方方正正的

針對(duì)上面的這個(gè)問題食棕,我相信99%的人都能信手拈來朗和,知道必須要設(shè)置masksToBounds為 true错沽,才會(huì)得到我們想要的效果。解決的方法很簡(jiǎn)單眶拉,但原理是大部人都沒有去仔細(xì)研究的千埃。

下面是蘋果官方文檔針對(duì)圓角設(shè)置的一些說明:


image.png

官方文檔告訴我們,設(shè)置cornerRadius只會(huì)對(duì)CALayer中的backgroundColor 和 boder設(shè)置圓角忆植,不會(huì)設(shè)置contents的圓角放可,如果contents需要設(shè)置圓角,需要同時(shí)將maskToBounds / clipsToBounds設(shè)置為true朝刊。

所以我們可以理解為圓角不生效的根本原因是沒有對(duì)contents設(shè)置圓角耀里,而按鈕設(shè)置的image是放在contents里面的,所以看到的界面上的就是image沒有進(jìn)行圓角裁剪坞古。

下面我們通過幾段代碼來說明 圓角設(shè)置中什么時(shí)候會(huì)離屏渲染觸發(fā)
首先备韧,需要打開模擬器的離屏渲染顏色標(biāo)記

image.png

1、按鈕 僅設(shè)置背景顏色+border

    let btn01 = UIButton(type: .custom)
    btn01.frame = CGRect(x: 100, y: 200, width: 100, height: 100)
    //設(shè)置圓角
    btn01.layer.cornerRadius = 50
    //設(shè)置border寬度和顏色
    btn01.layer.borderWidth = 4
    btn01.layer.borderColor = UIColor.red.cgColor
    self.view.addSubview(btn01)
    //設(shè)置背景顏色
    btn01.backgroundColor = UIColor.green

在這種情況下痪枫,無論是使用默認(rèn)的maskToBounds / clipsToBounds(false)织堂,還是將其修改為true,都不會(huì)觸發(fā)離屏渲染奶陈,究其根本原因是 contents中沒有需要圓角處理的layer易阳。

image.png

情況2:按鈕設(shè)置背景圖片+boder

    let btn0 = UIButton(type: .custom)
    btn0.frame = CGRect(x: 100, y: 60, width: 100, height: 100)
    //設(shè)置圓角
    btn0.layer.cornerRadius = 50
    //設(shè)置border寬度和顏色
    btn0.layer.borderWidth = 2
    btn0.layer.borderColor = UIColor.red.cgColor
    self.view.addSubview(btn0)
    //設(shè)置背景圖片
    btn0.setImage(UIImage(named: "mouse"), for: .normal)

使用默認(rèn)的maskToBounds / clipsToBounds(false)
這種情況就是最開始我們講到的圓角設(shè)置不生效的情況,就不再多做說明了

maskToBounds / clipsToBounds 修改為true

image.png

<article class="_2rhmJa">

從屏幕的顯示上可以看出吃粒,此時(shí)觸發(fā)了離屏渲染潦俺,是因?yàn)閳A角的設(shè)置是需要對(duì)所有l(wèi)ayer都進(jìn)行裁剪的,而maskToBounds裁剪是應(yīng)用到所有l(wèi)ayer上的徐勃。如果從正常渲染的角度來說事示,一個(gè)個(gè)layer是用完即扔的。而現(xiàn)在我們的圓角設(shè)置需要3個(gè)layer疊加合并的僻肖,所以將先處理好的layer保存在離屏緩沖區(qū)肖爵,等到最后一個(gè)layer處理完,合并進(jìn)行圓角+裁剪臀脏,所以才會(huì)觸發(fā)離屏渲染

總結(jié)

  • 當(dāng)只設(shè)置backgroundColor劝堪、border,而contents中沒有子視圖時(shí)揉稚,無論maskToBounds / clipsToBoundstrue還是false秒啦,都不會(huì)觸發(fā)離屏渲染
  • 當(dāng)contents中有子視圖時(shí),此時(shí)設(shè)置 cornerRadius+maskToBounds / clipsToBounds,就會(huì)觸發(fā)離屏渲染搀玖,但是這種情況在UIImageView中并不適用余境,當(dāng)UIImageView中只設(shè)置圖片+maskToBounds / clipsToBounds是不會(huì)觸發(fā)離屏渲染,蘋果對(duì)UIImageView優(yōu)化我想也只是將image直接畫在了contents上面這樣不設(shè)置背景色其實(shí)只需要渲染一個(gè)layer,所以不需要用到離屏緩沖區(qū),,所以不會(huì)產(chǎn)生離屏渲染芳来,如果此時(shí)再加上背景色暴氏,就會(huì)觸發(fā)離屏渲染。

離屏渲染是否觸發(fā)绣张,在于我們是否需要使用離屏緩沖區(qū)答渔。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市侥涵,隨后出現(xiàn)的幾起案子沼撕,更是在濱河造成了極大的恐慌,老刑警劉巖芜飘,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件务豺,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡嗦明,警方通過查閱死者的電腦和手機(jī)笼沥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來娶牌,“玉大人奔浅,你說我怎么就攤上這事∈迹” “怎么了汹桦?”我有些...
    開封第一講書人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)鉴裹。 經(jīng)常有香客問我舞骆,道長(zhǎng),這世上最難降的妖魔是什么径荔? 我笑而不...
    開封第一講書人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任督禽,我火速辦了婚禮,結(jié)果婚禮上总处,老公的妹妹穿的比我還像新娘狈惫。我一直安慰自己,他們只是感情好辨泳,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開白布虱岂。 她就那樣靜靜地躺著玖院,像睡著了一般菠红。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上难菌,一...
    開封第一講書人閱讀 51,462評(píng)論 1 302
  • 那天试溯,我揣著相機(jī)與錄音,去河邊找鬼郊酒。 笑死遇绞,一個(gè)胖子當(dāng)著我的面吹牛键袱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播摹闽,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蹄咖,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了付鹿?” 一聲冷哼從身側(cè)響起澜汤,我...
    開封第一講書人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎舵匾,沒想到半個(gè)月后俊抵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡坐梯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年徽诲,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吵血。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡谎替,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蹋辅,到底是詐尸還是另有隱情院喜,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布晕翠,位于F島的核電站喷舀,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏淋肾。R本人自食惡果不足惜硫麻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望樊卓。 院中可真熱鬧拿愧,春花似錦、人聲如沸碌尔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽唾戚。三九已至柳洋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間叹坦,已是汗流浹背熊镣。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人绪囱。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓测蹲,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親鬼吵。 傳聞我的和親對(duì)象是個(gè)殘疾皇子扣甲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354