Core Animation工具用來監測Core Animation性能。它給我們提供了周期性的FPS,并且考慮到了發生在程序之外的動畫(見圖12.4)
Core Animation工具提供了一系列復選框選項來幫助調試渲染瓶頸:
Color Blended Layers(混合和過度繪制)
- 這個選項基于渲染程度對屏幕中的混合區域進行綠到紅的高亮(也就是多個半透明圖層的疊加)。由于重繪的原因,混合對GPU性能會有影響,同時也是滑動或者動畫幀率下降的罪魁禍首之一。
GPU每一幀可以繪制的像素有一個最大限制(就是所謂的fill rate),這個情況下可以輕易地繪制整個屏幕的所有像素。但是如果由于重疊圖層的關系需要不停地重繪同一區域的話,掉幀就可能發生了。
GPU會放棄繪制那些完全被其他圖層遮擋的像素,但是要計算出一個圖層是否被遮擋也是相當復雜并且會消耗處理器資源。同樣,合并不同圖層的透明重疊像素(即混合)消耗的資源也是相當客觀的。所以為了加速處理進程,不到必須時刻不要使用透明圖層。任何情況下,你應該這樣做:
給視圖的backgroundColor屬性設置一個固定的,不透明的顏色
設置opaque屬性為YES
如果用到了圖像,盡量避免透明除非非常必要。如果圖像要顯示在一個固定的背景顏色或是固定的背景圖之前,你沒必要相對前景移動,你只需要預填充背景圖片就可以避免運行時混色了。
如果是文本的話,一個白色背景的UILabel(或者其他顏色)會比透明背景要更高效。
Color Offscreen-Rendered Yellow(離屏渲染)
- 這里會把那些需要離屏渲染的圖層高亮成黃色。這些圖層很可能需要用shadowPath或者shouldRasterize來優化。
當圖層屬性的混合體被指定為在未預合成之前不能直接在屏幕中繪制時,屏幕外渲染就被喚起了。屏幕外渲染并不意味著軟件繪制,但是它意味著圖層必須在被顯示之前在一個屏幕外上下文中被渲染(不論CPU還是GPU)。圖層的以下屬性將會觸發屏幕外繪制:
1、圓角(當和maskToBounds一起使用時)
2、圖層蒙板
3、陰影
屏幕外渲染和我們啟用光柵化時相似,除了它并沒有像光柵化圖層那么消耗大,子圖層并沒有被影響到,而且結果也沒有被緩存,所以不會有長期的內存占用。但是,如果太多圖層在屏幕外渲染依然會影響到性能。
有時候我們可以把那些需要屏幕外繪制的圖層開啟光柵化以作為一個優化方式,前提是這些圖層并不會被頻繁地重繪。
對于那些需要動畫而且要在屏幕外渲染的圖層來說,你可以用CAShapeLayer,contentsCenter或者shadowPath來獲得同樣的表現而且較少地影響到性能。
ColorHitsGreenandMissesRed(光柵化緩存圖層命中情況)
- 當使用shouldRasterizep屬性的時候,耗時的圖層繪制會被緩存,然后當做一個簡單的扁平圖片呈現。當緩存再生的時候這個選項就用紅色對柵格化圖層進行了高亮。如果緩存頻繁再生的話,就意味著柵格化可能會有負面的性能影響了。
光柵化
啟用shouldRasterize屬性會將圖層繪制到一個屏幕之外的圖像。然后這個圖像將會被緩存起來并繪制到實際圖層的contents和子圖層。如果有很多的子圖層或者有復雜的效果應用,這樣做就會比重繪所有事務的所有幀劃得來得多。但是光柵化原始圖像需要時間,而且還會消耗額外的內存。
當我們使用得當時,光柵化可以提供很大的性能優勢,但是一定要避免作用在內容不斷變動的圖層上,否則它緩存方面的好處就會消失,而且會讓性能變的更糟。
Color Copied Images(拷貝的圖片)
- 有時候寄宿圖片的生成意味著Core Animation被強制生成一些圖片,然后發送到渲染服務器,而不是簡單的指向原始指針。這個選項把這些圖片渲染成藍色。復制圖片對內存和CPU使用來說都是一項非常昂貴的操作,所以應該盡可能的避免。
Color Immediately
- 通常Core Animation Instruments以每毫秒10次的頻率更新圖層調試顏色。對某些效果來說,這顯然太慢了。這個選項就可以用來設置每幀都更新(可能會影響到渲染性能,而且會導致幀率測量不準,所以不要一直都設置它)。
Color Misaligned Images(圖片的不正常縮放)
- 這里會高亮那些被縮放或者拉伸以及沒有正確對齊到像素邊界的圖片(也就是非整型坐標)。這些中的大多數通常都會導致圖片的不正常縮放,如果把一張大圖當縮略圖顯示,或者不正確地模糊圖像,那么這個選項將會幫你識別出問題所在。
Color OpenGL Fast Path Blue
- 這個選項會對任何直接使用OpenGL繪制的圖層進行高亮。如果僅僅使用UIKit或者Core Animation的API,那么不會有任何效果。如果使用GLKView或者CAEAGLLayer,那如果不顯示藍色塊的話就意味著你正在強制CPU渲染額外的紋理,而不是繪制到屏幕。
Flash Updated Regions(Core Graphics繪制的圖層)
- 這個選項會對重繪的內容高亮成黃色(也就是任何在軟件層面使用Core Graphics繪制的圖層)。這種繪圖的速度很慢。如果頻繁發生這種情況的話,這意味著有一個隱藏的bug或者說通過增加緩存或者使用替代方案會有提升性能的空間。
一、概念理解
OpenGL中,GPU屏幕渲染有以下兩種方式:
On-Screen Rendering
意為當前屏幕渲染,指的是GPU的渲染操作是在當前用于顯示的屏幕緩沖區中進行。
Off-Screen Rendering
意為離屏渲染,指的是GPU在當前屏幕緩沖區以外新開辟一個緩沖區進行渲染操作。
二、離屏渲染的是是非非
相比于當前屏幕渲染,離屏渲染的代價是很高的,主要體現在兩個方面:
創建新緩沖區
要想進行離屏渲染,首先要創建一個新的緩沖區。
上下文切換
離屏渲染的整個過程,需要多次切換上下文環境:先是從當前屏幕(On-Screen)切換到離屏(Off-Screen);等到離屏渲染結束以后,將離屏緩沖區的渲染結果顯示到屏幕上有需要將上下文環境從離屏切換到當前屏幕。而上下文環境的切換是要付出很大代價的。
三、離屏渲染觸發方式
設置了以下屬性時,都會觸發離屏繪制:
shouldRasterize(光柵化)
masks(遮罩)
shadows(陰影)
edge antialiasing(抗鋸齒)
group opacity(不透明)
需要注意的是,如果shouldRasterize被設置成YES,在觸發離屏繪制的同時,會將光柵化后的內容緩存起來,如果對應的layer及其sublayers沒有發生改變,在下一幀的時候可以直接復用。這將在很大程度上提升渲染性能。
而其它屬性如果是開啟的,就不會有緩存,離屏繪制會在每一幀都發生。
四、另一種特殊的“離屏渲染”
按照之前的說法,如果將不在GPU的當前屏幕緩沖區中進行的渲染都稱為離屏渲染,那么就還有另一種特殊的“離屏渲染”方式:CPU渲染。
如果我們重寫了drawRect方法,并且使用任何Core Graphics的技術進行了繪制操作,就涉及到了CPU渲染。整個渲染過程由CPU在App內同步地完成,渲染得到的bitmap最后再交由GPU用于顯示。
五、Instruments
Instruments的Core Animation工具中有幾個和離屏渲染相關的檢查選項:
Color Offscreen-Rendered Yellow
開啟后會把那些需要離屏渲染的圖層高亮成黃色,這就意味著黃色圖層可能存在性能問題。
Color Hits Green and Misses Red
如果shouldRasterize被設置成YES,對應的渲染結果會被緩存,如果圖層是綠色,就表示這些緩存被復用;如果是紅色就表示緩存會被重復創建,這就表示該處存在性能問題了。
六、如何抉擇
現在擺在我們面前得有三個選擇:當前屏幕渲染、離屏渲染、CPU渲染,該用哪個呢?這需要根據具體的使用場景來決定。
盡量使用當前屏幕渲染
鑒于離屏渲染、CPU渲染可能帶來的性能問題,一般情況下,我們要盡量使用當前屏幕渲染。
離屏渲染 VS CPU渲染
由于GPU的浮點運算能力比CPU強,CPU渲染的效率可能不如離屏渲染;但如果僅僅是實現一個簡單的效果,直接使用CPU渲染的效率又可能比離屏渲染好,畢竟離屏渲染要涉及到緩沖區創建和上下文切換等耗時操作。
總之,具體的選擇應該由性能測試結果來決定。
七、寫在最后
在趙巖同學的點撥下才理解了離屏渲染的概念,在此表示感謝!
如理解有誤還請大家指出。
參考文檔
Getting Pixels onto the Screen(中文翻譯版:繪制像素到屏幕上)
Designing for iOS: Graphics & Performance(中文翻譯版:iOS圖形處理和性能)
a performance minded take on ios design(中文翻譯版:iOS離屏繪制的性能和機制分析)