【iOS】介面優化

weixin_33912246發表於2016-07-06

本文是在前人總結的基礎上進行高度概括,簡單介紹造成介面卡頓的原因和解決思路。


螢幕成像原理
2280423-b50222e2974e36cb.png
螢幕成像原理.png

首先從過去的 CRT 顯示器原理說起。CRT 的電子槍按照上面方式,從上到下一行行掃描,掃描完成後顯示器就呈現一幀畫面,隨後電子槍回到初始位置繼續下一次掃描。為了把顯示器的顯示過程和系統的視訊控制器進行同步,顯示器(或者其他硬體)會用硬體時鐘產生一系列的定時訊號。當電子槍換到新的一行,準備進行掃描時,顯示器會發出一個水平同步訊號(horizonal synchronization),簡稱 HSync;而當一幀畫面繪製完成後,電子槍回覆到原位,準備畫下一幀前,顯示器會發出一個垂直同步訊號(vertical synchronization),簡稱 VSync。顯示器通常以固定頻率進行重新整理,這個重新整理率就是 VSync 訊號產生的頻率。儘管現在的裝置大都是液晶螢幕了,但原理仍然沒有變。

2280423-0443182a8a94db88.png
計算機.png

通常來說,計算機系統中 CPU、GPU、顯示器是以上面這種方式協同工作的。CPU 計算好顯示內容提交到 GPU,GPU 渲染完成後將渲染結果放入幀緩衝區,隨後視訊控制器會按照 VSync 訊號逐行讀取幀緩衝區的資料,經過可能的數模轉換傳遞給顯示器顯示。

在最簡單的情況下,幀緩衝區只有一個,這時幀緩衝區的讀取和重新整理都都會有比較大的效率問題。為了解決效率問題,顯示系統通常會引入兩個緩衝區,即雙緩衝機制。在這種情況下,GPU 會預先渲染好一幀放入一個緩衝區內,讓視訊控制器讀取,當下一幀渲染好後,GPU 會直接把視訊控制器的指標指向第二個緩衝器。如此一來效率會有很大的提升。

雙緩衝雖然能解決效率問題,但會引入一個新的問題。當視訊控制器還未讀取完成時,即螢幕內容剛顯示一半時,GPU 將新的一幀內容提交到幀緩衝區並把兩個緩衝區進行交換後,視訊控制器就會把新的一幀資料的下半段顯示到螢幕上,造成畫面撕裂現象,如下圖:

2280423-592a4d7a978afda2.jpg
ios_vsync_off.jpg

為了解決這個問題,GPU 通常有一個機制叫做垂直同步(簡寫也是 V-Sync),當開啟垂直同步後,GPU 會等待顯示器的 VSync 訊號發出後,才進行新的一幀渲染和緩衝區更新。這樣能解決畫面撕裂現象,也增加了畫面流暢度,但需要消費更多的計算資源,也會帶來部分延遲。

那麼目前主流的移動裝置是什麼情況呢?從網上查到的資料可以知道,iOS 裝置會始終使用雙快取,並開啟垂直同步。而安卓裝置直到 4.1 版本,Google 才開始引入這種機制,目前安卓系統是三快取+垂直同步。

卡頓產生的原因和解決方案
2280423-2f14d85702118855.png
ios_frame_drop.png

在 VSync 訊號到來後,系統圖形服務會通過 CADisplayLink 等機制通知 App,App 主執行緒開始在 CPU 中計算顯示內容,比如檢視的建立、佈局計算、圖片解碼、文字繪製等。隨後 CPU 會將計算好的內容提交到 GPU 去,由 GPU 進行變換、合成、渲染。隨後 GPU 會把渲染結果提交到幀緩衝區去,等待下一次 VSync 訊號到來時顯示到螢幕上。由於垂直同步的機制,如果在一個 VSync 時間內,CPU 或者 GPU 沒有完成內容提交,則那一幀就會被丟棄,等待下一次機會再顯示,而這時螢幕會保留之前的內容不變。這就是介面卡頓的原因。

從上面的圖中可以看到,CPU 和 GPU 不論哪個阻礙了顯示流程,都會造成掉幀現象。所以開發時,也需要分別對 CPU 和 GPU 壓力進行評估和優化。


綜上所述,實際專案中,一般可以將佈局資訊提前計算好並快取,滑動tableview的時候儘量減少cpu計算佈局資訊的使用。

更多優化方法請移步
iOS 保持介面流暢的技巧

相關文章