WWDC心得與延伸:iOS圖形性能

學習與延伸ios

這篇文章主要是學習完Advanced Graphics and Animations for iOS Apps這個session後的總結和相應細節的延伸和細化。主要內容爲圖形性能與測試工具這兩個章節。git

目錄:github

  • Core Animation Pipeline算法

  • UIBlurEffectView緩存

  • 圖形性能性能優化

  • 測試工具微信

  • 總結
    session

Core Animation Pipelineapp

第一部分主要講解了Core Animation的工做流程和渲染過程。less

CoreAnimation的渲染流程能夠用下圖來歸納:

7000.png

在GPU的渲染過程當中,咱們能看到頂點着色器與像素着色器參與到圖像的處理。

在objc.io中有一篇文章進一步地闡明瞭頂點着色器與像素着色器 (GPU 加速下的圖像處理)

UIBlurEffectView

第二部分主要講解了iOS8新引入的UIBlurEffectView,結合第一部分來闡述UIBlurEffectView是如何工做的,以及它們的性能。

事實上,我的以爲有一點頗有趣。就是UIBlurEffectView爲了優化圖像處理效率,並非用普通的模糊算法。雖然Session中沒提到模糊算法,我在這裏簡單地介紹一下簡單的模糊算法。

最簡單模糊的過程便是用中心像素與其周圍像素的顏色算術平均值來表明模糊後的顏色值。咱們能夠在下面兩幅圖看到中心像素值的變化。

233.png

那麼蘋果是怎麼作的呢?最有趣的一點是它並非對原始圖像直接模糊,而是先將圖像縮放以後再進行模糊。這樣的優勢就是模糊算法須要處理的像素點就減小了,處理的效率會更快。

看到這裏的時候我是笑了的,哈哈,以爲很機智。適當的把思惟跳出來,"偷點懶",有時真的會取得很不錯的效果。學習,學習。

其次就是水平模糊與豎直模糊後再合成,添加顏色。

701.png

最後須要關注和有趣的一點是:蘋果爲咱們提供了三個UIBlurEffect styles,

分別爲Extra light, Light, Dark.可是三者的耗費的資源各爲不一樣。

Extra light耗費最多資源, Light其次, Dark最多。 

702.png

我在本身的我的項目裏也有用到UIBlurEffectView來美化界面,優化用戶體驗。兩個項目都已經上架,並完整開源。歡迎去看看。

主要使用在主菜單界面。

用在了實時蒙版,即相似微信二維碼掃描框外的黑色半透明背景,在這裏則是實時模糊,更美觀。

圖形性能

關於圖形性能在以前關注的不夠多,主要是用前人總結好的比較教條式的優化方式。此次借這個Session的學習,繼續往外擴展閱讀學習,好好梳理和學習遺漏點,底層細節,原理與性能優化的工具

1. 關於CALayer的shouldRasterize(光柵化)

開啓shouldRasterize後,CALayer會被光柵化爲bitmap,layer的陰影等效果也會被保存到bitmap中。

當咱們開啓光柵化後,須要注意三點問題。

  • 若是咱們更新已光柵化的layer,會形成大量的offscreen渲染。

所以CALayer的光柵化選項的開啓與否須要咱們仔細衡量使用場景。只能用在圖像內容不變的前提下的:

    ① 用於避免靜態內容的複雜特效的重繪,例如前面講到的UIBlurEffect

    ② 用於避免多個View嵌套的複雜View的重繪。

而對於常常變更的內容,這個時候不要開啓,不然會形成性能的浪費。

例如咱們日程常常打交道的TableViewCell,由於TableViewCell的重繪是很頻繁的(由於Cell的複用),若是Cell的內容不斷變化,則Cell須要不斷重繪,若是此時設置了cell.layer可光柵化。則會形成大量的offscreen渲染,下降圖形性能。

固然,合理利用的話,是可以獲得很多性能的提升的,由於使用shouldRasterize後layer會緩存爲Bitmap位圖,對一些添加了shawdow等效果的耗費資源較多的靜態內容進行緩存,可以獲得性能的提高。

  • 不要過分使用,系統限制了緩存的大小爲2.5X Screen Size.

若是過分使用,超出緩存以後,一樣會形成大量的offscreen渲染。

  • 被光柵化的圖片若是超過100ms沒有被使用,則會被移除

所以咱們應該只對接二連三使用的圖片進行緩存。對於不常使用的圖片緩存是沒有意義,且耗費資源的。

2. 關於offscreen rendering

注意到上面提到的offscreen rendering。咱們須要注意shouldRasterize的地方就是會形成offscreen rendering的地方,那麼爲何須要避免呢?

WWDC 2011 Understanding UIKit Rendering指出通常致使圖形性能的問題大部分都出在了offscreen rendering,所以若是咱們發現列表滾動不流暢,動畫卡頓等問題,就能夠想一想和找出咱們哪部分代碼致使了大量的offscreen 渲染。

首先,什麼是offscreen rendering?

offscreen rendring指的是在圖像在繪製到當前屏幕前,須要先進行一次渲染,以後才繪製到當前屏幕。

那麼爲何offscreen渲染會耗費大量資源呢?

緣由是顯卡須要另外alloc一塊內存來進行渲染,渲染完畢後在繪製到當前屏幕,並且對於顯卡來講,onscreen到offscreen的上下文環境切換是很是昂貴的(涉及到OpenGL的pipelines和barrier等),

備註:

這裏提到的offscreen rendering主要講的是經過GPU執行的offscreen,事實上還有的offscreen rendering是經過CPU來執行的(例如使用Core Graphics, drawRect)。其它相似cornerRadios, masks, shadows等觸發的offscreen是基於GPU的。

許多人有誤區,認爲offscreen rendering就是software rendering,只是純粹地靠CPU運算。實際上並非的,offscreen rendering是個比較複雜,涉及許多方面的內容。

咱們在開發應用,提升性能一般要注意的是避免offscreen rendering。不須要糾結和拘泥於它的定義。

有興趣能夠繼續閱讀Andy Matuschak, 前UIKit team成員關於offscreen rendering的評論。

總之,咱們一般須要避免大量的offscreen rendering.

會形成 offscreen rendering的緣由有:

  • Any layer with a mask (layer.mask)

  • Any layer with layer.masksToBounds being true

  • Any layer with layer.allowsGroupOpacity set to YES and layer.opacity is less than 1.0

  • Any layer with a drop shadow (layer.shadow*).

  • Any layer with layer.shouldRasterize being true

  • Any layer with layer.cornerRadius, layer.edgeAntialiasingMask, layer.allowsEdgeAntialiasing

所以,對於一些須要優化圖像性能的場景,咱們能夠檢查咱們是否觸發了offscreen rendering。 並用更高效的實現手段來替換。

例如:

① 陰影繪製:使用ShadowPath來替代shadowOffset等屬性的設置。

一個如圖的簡單tableView: 

234.png

兩種不一樣方式來繪製陰影:

不使用shadowPath

CALayer *imageViewLayer = cell.imageView.layer;
imageViewLayer.shadowColor = [UIColor blackColor].CGColor;
imageViewLayer.shadowOpacity = 1.0;
imageViewLayer.shadowRadius = 2.0;
imageViewLayer.shadowOffset = CGSizeMake(1.0, 1.0);

使用shadowPath

imageViewLayer.shadowPath = CGPathCreateWithRect(imageRect, NULL);

咱們能夠在下圖看到兩種方式巨大的性能差異。

我的推測的shadowPath高效的緣由是使用shadowPath避免了offscreen渲染,由於僅須要直接繪製路徑便可,不須要提早讀取圖像去渲染。 

235.png

②裁剪圖片爲圓:

如圖爲例

round.png

使用CornerRadius:

1
2
3
CALayer *imageViewLayer = cell.imageView.layer;
imageViewLayer.cornerRadius = imageHeight / 2.0;
imageViewLayer.masksToBounds = YES;

利用一張中間爲透明圓形的圖片來進行遮蓋,雖然會引發blending,但性能仍然高於offerScreen。

根據蘋果測試,第二種方式比第一種方式更高效: 

442.png

以上舉了兩個例子闡明瞭在避免大量的offerScreen渲染後,性能可以獲得很是直觀有效的提升。

③關於blending

前面提到了用透明圓形的圖片來進行遮蓋,會引發blending。blending也會耗費性能。

:) 笑。若是閱讀這篇文章的讀者看到這裏,是否是以爲已經無眼看下去了。哈哈,我本身學習總結到這裏也是感覺到了長路慢慢,可是咱們仍然仍是要不斷上下求索的。 :)

好了 接下來讓咱們來認識一下Blending.

  • 什麼是Blending?

在iOS的圖形處理中,blending主要指的是混合像素顏色的計算。最直觀的例子就是,咱們把兩個圖層疊加在一塊兒,若是第一個圖層的透明的,則最終像素的顏色計算須要將第二個圖層也考慮進來。這一過程即爲Blending。

  • 會致使blending的緣由:

    layer(UIView)的Alpha < 1

    UIImgaeView的image含有Alpha channel(即便UIImageView的alpha是1,但只要image含透明通道,則仍會致使Blending)

  • 爲何Blending會致使性能的損失?

緣由是很直觀的,若是一個圖層是不透明的,則系統直接顯示該圖層的顏色便可。而若是圖層是透明的,則會引入更多的計算,由於須要把下面的圖層也包括進來,進行混合後顏色的計算。

在瞭解完Blending以後,咱們就知道爲何不少優化準則都須要咱們儘可能使用不透明圖層了。接下來就是在開發中留意和進行優化了。

測試工具

在出現圖像性能問題,滑動,動畫不夠流暢以後,咱們首先要作的就是定位出問題的所在。而這個過程並非只靠經驗和窮舉法探索,咱們應該用有脈絡,有順序的科學的手段進行探索。

首先,咱們要有一個定位問題的模式。咱們能夠按照這樣的順序來逐步定位,發現問題。

  1. 定位幀率,爲了給用戶流暢的感覺,咱們須要保持幀率在60幀左右。當遇到問題後,咱們首先檢查一下幀率是否保持在60幀。

  2. 定位瓶頸,到底是CPU仍是GPU。咱們但願佔用率越少越好,一是爲了流暢性,二也節省了電力。

  3. 檢查有沒有作無必要的CPU渲染,例若有些地方咱們重寫了drawRect,而實際上是咱們不須要也不該該的。咱們但願GPU負責更多的工做。

  4. 檢查有沒有過多的offscreen渲染,這會耗費GPU的資源,像前面已經分析的到的。offscreen 渲染會致使GPU須要不斷地onScreen和offscreen進行上下文切換。咱們但願有更少的offscreen渲染。

  5. 檢查咱們有無過多的Blending,GPU渲染一個不透明的圖層更省資源。

  6. 檢查圖片的格式是否爲經常使用格式,大小是否正常。若是一個圖片格式不被GPU所支持,則只能經過CPU來渲染。通常咱們在iOS開發中都應該用PNG格式,以前閱讀過的一些資料也有指出蘋果特地爲PNG格式作了渲染和壓縮算法上的優化。

  7. 檢查是否有耗費資源多的View或效果。咱們須要合理有節制的使用。像以前提到的UIBlurEffect就是一個例子。

  8. 最後,咱們須要檢查在咱們View層級中是否有不正確的地方。例若有時咱們不斷的添加或移除View,有時就會在不經意間致使bug的發生。像我以前就遇到過不斷添加View的一個低級錯誤。咱們但願在View層級中只包含了咱們想要的東西。

OK,當咱們有了一套模式以後,就可使用蘋果爲咱們提供的優秀測試工具來進行測試了。

對於圖形性能問題的地位。通常咱們有下列測試工具:

Instruments裏的:

  • Core Animation instrument

  • OpenGL ES Driver instrument

模擬器中的:

  • Color debug options View debugging

還有Xcode的:

  • View debugging

而後咱們來根據上面定位問題的模式來選擇相應測試工具:

  • 定位幀率

  • 定位瓶頸

  • 檢查有無必要的CPU渲染

以上三點咱們可使用CoreAnimation instrument來測試。

236.png

237.png

CoreAnimation instrument包含了兩個模塊。第一幅圖展現了檢測幀率。第二幅圖展現了檢測CPU調用。咱們可以經過它們來進行上述三個問題的檢測。注意到第二幅圖左下角,那是CPU 的call stack.咱們就是在這裏檢測咱們有沒有作無必要的drawRect,有沒有在主線程作太多事務致使阻塞了UI更新。
關於GPU的瓶頸問題,咱們能夠經過OpenGL ES Driver instrument來得到更詳細的信息。例如GPU的佔用率。能夠看到下圖左下角有顯示Device utilization。

33.png

4.  檢查有無過多offscreen渲染
5.  檢查有無過多Blending
6.  檢查有無不正確圖片格式,圖片是否被放縮,像素是否對齊。
7.  檢查有無使用複雜的圖形效果。
以上這四點咱們一樣使用CoreAnimation instrument來測試。

238.png

咱們能夠看到上圖右下角的Debug options有多個選項。咱們經過勾選這些選項來觸發Color Debug。下面逐個對這些選項進行分析。

  • Color Blended layers

239.png

如圖,勾選這個選項後,blended layer 就會被顯示爲紅色,而不透明的layer則是綠色。咱們但願越少紅色區域越好。

  • Color Hits Green and Misses Red

這個選項主要是檢測咱們有無濫用或正確使用layer的shouldRasterize屬性.成功被緩存的layer會標註爲綠色,沒有成功緩存的會標註爲紅色。

在測試的過程當中,第一次加載時,開啓光柵化的layer會顯示爲紅色,這是很正常的,由於尚未緩存成功。可是若是在接下來的測試,例如咱們來回滾動TableView時,咱們仍然發現有許多紅色區域,那就須要謹慎對待了。由於像咱們前面討論過的,這會引發offscreen rendering。

檢查一下是否有濫用該屬性,由於系統規定的緩存大小是屏幕大小的2.5倍,若是使用過分,超出了緩存大小,會引發offscreen rendering。檢測layer是否內容不斷更新,內容的更新會致使緩存失效和大量的offscreen rendering.

  • Color copied images

這個選項主要檢查咱們有無使用不正確圖片格式,如果GPU不支持的色彩格式的圖片則會標記爲青色,則只能由CPU來進行處理。咱們不但願在滾動視圖的時候,CPU實時來進行處理,由於有可能會阻塞主線程。

  • Color misaligned images

這個選項檢查了圖片是否被放縮,像素是否對齊。被放縮的圖片會被標記爲黃色,像素不對齊則會標註爲紫色。

  • Color offscreen-rendered yellow

這個選項將須要offscreen渲染的的layer標記爲黃色。

240.png

以上圖爲例子,NavigationBar和ToolBar被標記爲黃色。由於它們須要模糊背後的內容,這須要offscreen渲染。可是這是咱們須要的。而圖片也是被標記爲黃色,那是由於陰影的緣故。我前面已經提到了這一點,若是此時咱們用shadowPath來替代的話,就可以避免offscreen渲染帶來的巨大開銷。

  • Color OpenGL fast path blue

這個選項勾選後,由OpenGL compositor進行繪製的圖層會標記爲藍色。這是一個好的結果。

  • Flash updated regions

會標記屏幕上被快速更新的部分爲黃色,咱們但願只是更新的部分被標記完黃色。

好啦,終於完整介紹完這些調試選項了,咱們總結一下。

咱們須要重點注意的是

①Color Blended layers

②Color Hits Green and Misses Red

③Color offscreen-rendered yellow這三個選項。

由於這三個部分對性能的影響最大。

8.  檢查View層級是否正確。

241.png

咱們能夠在上圖清楚地看到View的層級關係。能夠檢查View的層級是否正確。

小提示(應用運行後,在這裏打開):從左往右第七個圖

242.png

總結

關於圖形性能還有許多細節和底層能夠深刻,不過通過這一次總結與學習,基本把握了iOS圖形性能的優化細節和工具。但願也可以對你有一點幫助。

在學習和探索的過程當中,我的感覺最深的是兩點。

1.  一類事情背後都會有必定的原理,弄清楚了原理就能更好地把握這一類事務。

在以前的iOS開發中,對圖形界面的優化主要處於用前人總結的教條來優化。而通過此次學習以後,明白這些教條背後的原理,像最影響性能的offscreen rendering和blending。更能有針對性的優化和分析。

2.  檢測問題不該該是盲目的,有必定的模式和工具會更清晰。

像對圖形性能的問題定位,咱們不該該一上來就開始找問題,看代碼。而是應該逐步定位。而是像前面總結的同樣,定位幀率,摸清瓶頸,逐個問題擊破。再配合合適的工具進行測試和定位,必定可以提高效率和準確度。

相關文章
相關標籤/搜索