最近在學(xué)習(xí) UI 性能優(yōu)化方面的內(nèi)容,總結(jié)一下自己對(duì)離屏渲染的理解。很早就聽(tīng)過(guò)離屏渲染的概念,也查閱過(guò)資料,但一直沒(méi)有一個(gè)系統(tǒng)化的理解。這里通過(guò)幾個(gè)問(wèn)題,梳理了下自己對(duì)離屏渲染的理解。
1.什么是離屏渲染
2.如何觸發(fā)離屏渲染
3.離屏渲染的代價(jià)是什么
4.離屏渲染有沒(méi)有好處
1.什么是離屏渲染
離屏渲染(offscreen-rendering)顧名思義為屏幕外的渲染,即渲染的結(jié)果不會(huì)直接呈現(xiàn)到當(dāng)前屏幕上,而是等待合適的時(shí)機(jī)才會(huì)被顯示。
正常情況下,在當(dāng)前屏幕顯示的內(nèi)容,由 GPU 渲染完成后放到當(dāng)前屏幕的幀緩存區(qū),不需要額外的渲染空間。我們知道 iPhone 的屏幕刷新率是 60Hz,也就是刷新一幀的時(shí)間是 16.67 ms,每隔這段時(shí)間視頻控制器就會(huì)去讀一次緩存區(qū)的內(nèi)容來(lái)顯示。
假如 GPU 遇到性能瓶頸,導(dǎo)致無(wú)法在一幀內(nèi)更新渲染結(jié)果到幀緩存區(qū),那么從緩存區(qū)讀到的會(huì)是上一幀的內(nèi)容,導(dǎo)致幀率降低界面卡頓。
蘋果對(duì)于頁(yè)面流暢度的要求是非??量痰模绻?yè)面布局比較復(fù)雜,硬件遇到瓶頸,不能任由它卡頓。離屏渲染的機(jī)制就被引入,它會(huì)觸發(fā)比較消耗性能的視圖提前渲染。
2.如何觸發(fā)離屏渲染
有兩種觸發(fā)離屏渲染的方式,分別是被動(dòng)觸發(fā)和主動(dòng)觸發(fā)。
圓角,陰影,遮罩(mask),模糊,以及 iOS 9 之前圖片的圓角,圓角單純的設(shè)置 cornerRadius 并不會(huì)觸發(fā)離屏渲染,需要配合 masksToBounds 切割邊緣之外的子視圖。重寫-drawRect方法,視圖只要設(shè)置背景顏色,也會(huì)觸發(fā)離屏渲染。
主動(dòng)觸發(fā)離屏渲染的方式是利用 CALayer.shouldRasterize 屬性,開(kāi)啟光柵化。光柵化是一個(gè)比較抽象的概念,它的作用是強(qiáng)制將 CALayer 以 bitmap 的形式進(jìn)行緩存,等價(jià)于屏幕外的緩存,也屬于離屏渲染的概念。
被動(dòng)觸發(fā)離屏渲染的方式看起來(lái)毫無(wú)規(guī)律,但其實(shí)它們有一個(gè)共同的特征,就是含有透明度。含有透明度的視圖,在顯示前需要進(jìn)行圖層的合成,即對(duì)重疊視圖的每個(gè)像素的 R,G,B,A 值進(jìn)行重計(jì)算,最終顯示組合的效果。對(duì)于完全不透明的視圖,遮擋住父視圖的內(nèi)容,直接顯示最上層(葉節(jié)點(diǎn))的色值,就沒(méi)有組合的開(kāi)銷。
視圖的合成計(jì)算是非常消耗 GPU 性能,多層級(jí)大尺寸視圖尤為明顯。體現(xiàn)在代碼成面, GPU 是否進(jìn)行視圖的合成依據(jù)是 CALayer 的 opaque 屬性,如果為 YES 就不會(huì)進(jìn)行圖層的合成。然而,視圖透明度是由 alpha 屬性決定的,所以在修改 alpha 小于 1 時(shí),最好將 opaque 設(shè)為 NO,否則會(huì)出現(xiàn)無(wú)法預(yù)料的效果,這一點(diǎn)很容易被忽略。
3.離屏渲染的代價(jià)是什么
離屏渲染需要在屏幕外開(kāi)辟內(nèi)存空間,提前使用 CPU 渲染復(fù)雜的視圖,保證視頻控制器能夠及時(shí)地從緩存區(qū)讀到新的渲染結(jié)果。它在 GPU 面臨性能瓶頸時(shí),將壓力轉(zhuǎn)移一部分給比較空閑的 CPU,然而 CPU 的渲染能力遠(yuǎn)沒(méi)有 GPU 高效,有點(diǎn)殺雞出牛刀的意思。
同時(shí)這也是一種以空間換取時(shí)間的策略。
視頻控制器要讀取離屏渲染的結(jié)果,需要把渲染上下文從當(dāng)前屏幕緩存區(qū)切到屏幕外緩存區(qū),當(dāng)要顯示非離屏渲染視圖的時(shí)候又要切換回來(lái),然而不可能在一屏上所有的元素都是離屏渲染的,所以視頻控制器上下文需要不停地來(lái)回切換。而這種上下文切換的代價(jià)非常昂貴。
所以離屏渲染會(huì)帶來(lái)各方面的開(kāi)銷,要盡可能的避免。
4.離屏渲染有沒(méi)有好處
離屏渲染并不是一無(wú)是處的,雖然會(huì)造成很多額外的開(kāi)銷,但也是為了充分利用設(shè)備的資源來(lái)保證界面的流暢。發(fā)生離屏渲染時(shí),是為了引起開(kāi)發(fā)者對(duì)性能的關(guān)注,減少不必要的透明視圖層級(jí)。如果不可避免的要觸發(fā)離屏渲染,并且發(fā)生離屏渲染視圖內(nèi)容不會(huì)頻繁的變化,可以利用 CALayer.shouldRasterize 開(kāi)啟光柵化,將離屏渲染的內(nèi)容以位圖的形式緩存,減少?gòu)?fù)雜視圖頻繁渲染的開(kāi)銷。然而,這個(gè)緩存的時(shí)效是 100ms,也就是刷新 6 幀的時(shí)間,如果視圖內(nèi)容更新頻繁,緩存就會(huì)不停的刷新,導(dǎo)致無(wú)法命中,開(kāi)啟光柵化并沒(méi)有什么作用。
參考
1.理解什么是離屏渲染
http://www.10tiao.com/html/585/201803/2654061295/1.html
2.離屏渲染詳解
http://www.itdecent.cn/p/57e2ec17585b