離屏渲染介紹
GPU屏幕渲染有以下兩種方式:
On-Screen Rendering
意為當(dāng)前屏幕渲染,指的是GPU的渲染操作是在當(dāng)前用于顯示的屏幕緩沖區(qū)中進(jìn)行。Off-Screen Rendering
意為離屏渲染,指的是GPU在當(dāng)前屏幕緩沖區(qū)以外新開辟一個緩沖區(qū)進(jìn)行渲染操作。
設(shè)置了圖層的以下屬性時,都會觸發(fā)離屏渲染:
- shouldRasterize(光柵化)
- masks(遮罩)
- shadows(陰影)
- edge antialiasing(抗鋸齒)
- group opacity(組透明)
- cornerRadius+maskToBounds(圓角)
當(dāng)使用圓角、陰影、遮罩的時候,最終的圖層效果在未預(yù)合成之前不能直接在屏幕中繪制,所以就需要屏幕外渲染被喚起--離屏渲染。
當(dāng)使用離屏渲染的時候會很容易造成性能消耗,因?yàn)槠聊煌饩彌_區(qū)跟當(dāng)前屏幕緩沖區(qū)上下文切換是很耗性能的。離屏渲染會導(dǎo)致GPU利用率不到100%,幀率卻很低(切換上下文會產(chǎn)生idle time)。
渲染過程--遮罩(Mask)
- 渲染layer的mask紋理;
- 渲染layer的content紋理;
- Compositing操作,合并1、2的紋理;
渲染過程--高斯模糊
使用UIBlurEffect,應(yīng)該是盡可能小的view,因?yàn)樾阅芟木薮蟆?/p>
光柵化
把視圖的內(nèi)容渲染成紋理并緩存,可以通過CALayer的shouldRasterize屬性開啟光柵化。注意,光柵化的元素,總大小限制為2.5倍的屏幕。更新內(nèi)容時,會啟用離屏渲染,所以更新代價(jià)較大,只能用于靜態(tài)內(nèi)容;而且如果光柵化的元素100ms沒有被使用將被移除,故而不常用元素的光柵化并不會優(yōu)化顯示。
組透明度
CALayer的allowsGroupOpacity屬性,UIView 的alpha屬性等同于 CALayer opacity屬性。GroupOpacity=YES,子 layer 在視覺上的透明度的上限是其父 layer 的opacity。當(dāng)父視圖的layer.opacity != 1.0時,會開啟離屏渲染;layer.opacity == 1.0時,父視圖不用管子視圖,只需顯示當(dāng)前視圖即可。
為了讓子視圖與父視圖保持同樣的透明度,從 iOS 7 以后默認(rèn)全局開啟了這個功能。
性能優(yōu)化
這個是WWDC推薦的檢查項(xiàng)目:
1、幀率一般在多少?
60幀每秒;(TimeProfiler)
2、是否存在CPU和GPU瓶頸? (查看占有率)
更少的使用CPU和GPU可以有效的保存電量;
3、額外的使用CPU來進(jìn)行渲染?
重寫了drawRect會導(dǎo)致CPU渲染;在CPU進(jìn)行渲染時,GPU大多數(shù)情況是處于等待狀態(tài);
4、是否存在過多離屏渲染?
越少越好;離屏渲染會導(dǎo)致上下文切換,GPU產(chǎn)生idle;
5、是否渲染過多視圖?
視圖越少越好;透明度為1的視圖更受歡迎;
6、使用奇怪的圖片格式和大小?
避免格式轉(zhuǎn)換和調(diào)整圖片大小;一個圖片如果不被GPU支持,那么需要CPU來轉(zhuǎn)換。(Xcode有對PNG圖片進(jìn)行特殊的算法優(yōu)化)
7、使用昂貴的特效?
理解特效的消耗,同時調(diào)整合適的大小;例如前面提到的UIBlurEffect;
8、視圖樹上不必要的元素?
理解視圖樹上所有點(diǎn)的必要性,去掉不必要的元素;忘記remove視圖是很常見的事情,特別是當(dāng)View的類比較大的時候。
以上,是8個問題對應(yīng)的工具。遇到性能問題,先分析、定位問題所在,而不是埋頭鉆進(jìn)代碼的海洋。
性能優(yōu)化實(shí)踐
- 陰影優(yōu)化
通過指定shadowPath減少陰影計(jì)算量。
- 圓角優(yōu)化
不要使用不必要的masksToBounds,如果圓角沒有裁剪到內(nèi)容,可以僅設(shè)置cornerRadius,這樣不會觸發(fā)離屏渲染。
可以預(yù)處理圖片為圓形,比如可以用CoreGraphic將圖片繪制在圓形區(qū)域,即CPU渲染。當(dāng)然CPU渲染也比較耗時,但是CoreGraphic是線程安全的,可以放到后臺線程中去繪制。
可以添加中間為圓形透明的白色背景視圖。即使添加額外的視圖,會導(dǎo)致額外的計(jì)算,但仍然會快一點(diǎn),因?yàn)橄鄬τ谇袚Q上下文,GPU更擅長渲染。
- 光柵化緩存
label.layer.cornerRadius = 5.0f;
label.layer.masksToBounds = YES;
label.layer.shouldRasterize = YES;
label.layer.rasterizationScale = label.layer.contentsScale;
簡單的說,光柵化一種緩存機(jī)制,它將離屏渲染的結(jié)果緩存起來,防止頻繁的重復(fù)渲染。因此光柵化適合靜態(tài)不變的內(nèi)容,一旦內(nèi)容發(fā)生變化,也會觸發(fā)離屏渲染。
- 檢測工具
使用instruments的CoreAnimation工具來檢查離屏渲染,黃色是我們不希望看到的顏色。
使用真機(jī)來調(diào)試,因?yàn)槟M器使用的CALayer是OSX的CALayer,不是iOS的CALayer。如果用模擬器調(diào)試,會發(fā)現(xiàn)所有的視圖都是黃色。