Android 性能優化之渲染原理

每一次面試準備都是造航母
複製代碼

先來看幾個概念

fps:每秒傳輸的幀數,FPS」也能夠理解爲咱們常說的「刷新率(單位爲Hz)」。
hz:表明屏幕在一秒內刷新的次數,Android手機通常爲60HZ,也就是一秒刷新60幀,大約16.67ms刷新一次
丟幀:原本一秒中畫面須要更新 60 幀,可是若是這期間只更新了 55 幀 , 那麼在用戶看來就是丟幀了 , 主觀感受就是卡了
tearing: 一個屏幕內的數據來自2個不一樣的幀,畫面會出現撕裂感
jank: 繪圖速度過慢,一個幀在屏幕上連續出現2次
lag:從用戶體驗來講,就是點擊下去到呈現效果之間存在延遲
撕裂(screen tearing):當cpu/gpu將數據準備寫入buffer(緩衝區)中,但display還沒來的及顯示,這時cpu/gpu把下一幀數據往buffer寫,還沒寫完,Display開始讀去buffer顯示,(也就是繪圖數度大於顯示速度),這是就會出現顯示的上半部分爲下一幀數據,下半部分爲上一幀數據,如圖所示,這就是撕裂。 android

tearing發生的緣由是display讀buffer同時,buffer被修改,那麼多一個buffer是否是能解決問題,這個時候雙緩衝就誕生了。面試

雙緩衝機制

從性能角度出發,若是隻對一塊緩衝區進行讀寫無疑效率比較低下:一方面屏幕要從該區域去讀,另外一方面顯卡要等待去寫.所以在實際中,其實幀緩衝區實則被劃分爲兩部分:緩存

前緩衝區: 用來緩存要顯示到屏幕的幀數據 後緩衝區: 用來緩存顯卡生成的幀數據. 屏幕只能前緩衝區讀取數據用於顯示,顯卡只能日後緩衝區寫入新生成的幀數據.須要注意的是兩塊緩衝區並不發生實際上的數據拷貝操做,即將後緩衝區的幀數據拷貝到前緩衝區,而是在前緩衝區的幀數據已經推到屏幕上,且新的幀數據被寫入到後臺緩衝區後,進行指針交換操做,將原來的後緩衝區變爲前緩衝區 佈局

但仍是有問題,假如是backbuffer準備完成一幀數據之後就進行,那麼若是此時屏幕尚未完整顯示上一幀內容的話,確定是會出問題的。看來只能是等到屏幕處理完一幀數據後,才能夠執行這一操做了. 當掃描完一個屏幕後,設備須要從新回到第一行以進入下一次的循環,此時有一段時間空隙,稱爲VerticalBlanking Interval(VBI)。你們應該能想到了,這個時間點就是咱們進行緩衝區交換的最佳時間。由於此時屏幕沒有在刷新,也就避免了交換過程當中出現 screentearing的情況。VSync(垂直同步)是VerticalSynchronization的簡寫,它利用VBI時期出現的vertical sync pulse來保證雙緩衝在最佳時間點才進行交換。 因此說V-sync這個概念並非Google獨創的,它在早些年前的PC機領域就已經出現了。不過Android 4.1給它賦予了新的功用,稍後就能夠看到。性能

Android顯示原理

  在一個典型的顯示系統中分爲GPU,CPU,Display(有些言論稱爲顯示器)三部分,Android中LayoutInflater將佈局中的xml標籤轉換爲對象,cpu通過計算將它轉化爲多邊形(Polygons)或Texture(紋理)。gpu對多邊形或者紋理進行柵格化(Rasterization)操做,柵格化後的數據寫入幀緩衝區中等待顯示器顯示。如圖:優化

安卓在4.1作的優化(Project Butter 黃油計劃)

  在Android 4.1以前,界面卡頓是Android中最受詬病的一點.爲了解決界面卡頓問題,Google爲Android引入了Project Butter計劃,即常說的黃油計劃.在該項目中,Google對Android顯示系統進行重構,並引入了三個相當重要的改進:
動畫

VSync加強:VSync不只僅用於避免畫面撕裂現象,如今它還會通知GPU在渲染下一幀以前要等待屏幕完成 逐行繪製.
Triple Buffer: 三緩衝機制
Choreographer: 用於協同nimations,input和drawing一塊兒工做
spa

雙緩衝意味着要使用兩個緩衝區(SharedBufferStack中),其中一個稱爲Front Buffer,另一個稱爲Back Buffer。UI老是先在Back Buffer中繪製,而後再和Front Buffer交換,渲染到顯示設備中,其中Display處理前Front Buffer,CPU、GPU處理Back Buffer.net

須要注意的是Android中一直存在VSync機制(有待考證),只不過早期VSync只是爲了不畫面撕裂(screen tearing)現象.爲了更好的瞭解加強過的VSync和Triple Buffer,咱們先來看一下早期圖像顯示的過程,即VSync只用來避免畫面撕裂的狀況:線程

這個圖中有三個元素,Display是顯示屏幕,GPU和CPU負責渲染幀數據,每一個幀以方框表示,並以數字進行編號,如0、一、2等等。VSync用於指導雙緩衝區的交換。以時間的順序來看下將會發生的異常:

  1. Display顯示第0幀數據,此時CPU和GPU渲染第1幀畫面,並且趕在Display顯示下一幀前完成。
  2. 由於渲染及時,Display在第0幀顯示完成後,也就是第1個VSync後,正常顯示第1幀。
  3. 因爲某些緣由,好比CPU資源被佔用,系統沒有及時地開始處理第2幀,直到第2個VSync快來前纔開始處理
  4. 第2個VSync來時,因爲第2幀數據尚未準備就緒,顯示的仍是第1幀。這種狀況被Android開發組命名爲「Jank」。
  5. 當第2幀數據準備完成後,它並不會立刻被顯示,而是要等待下一個VSync。因此總的來講,就是屏幕無緣無故地多顯示了一次第1幀。緣由你們應該都看到了,就是CPU沒有及時地開始着手處理第2幀的渲染工做,以至「延誤軍機」。

其實總結上面的這個狀況之因此發生,首先的緣由就在於第二幀沒有及時的繪製。那麼如何使得第二幀及時被繪製呢?這就是咱們在Graphic系統中引入VSYNC的緣由,

CPU/GPU根據VSYNC信號同步處理數據,可讓CPU/GPU有完整的16ms時間來處理數據,減小了jank。假如CPU/GPU的FPS(FramesPer Second)高於這個值,那麼這個方案是完美的,顯示效果將很好。 總結,vync同步使得CPU/GPU充分利用了16ms時間,減小jank

Triple Buffer

在雙緩存的基礎上,android又引入了三緩存技術。 首先來看傳統的雙緩衝機制,理想狀況下,其工做狀態以下:

在上圖中,以GPU一行爲例,長方形A和B分別表明兩塊緩衝區域,分別表明前臺緩衝區和後臺緩衝區.開始時A做爲前臺緩衝區,此時GPU會想後臺緩衝區B寫入幀數據;當B緩衝區準備就緒後,A,B交換,B變成前臺緩衝區,A變成後臺緩衝區,一切都很流程,CPU/GPU充分利用每一個16.6ms,在前一個VSync到來時開始準備數據,並在後一個VSync到來時準備好數據.但問題時,咱們沒法確保CPU/GPU都能在16.6ms內可以準備好數據(l可能設備較差,或者界面你叫複雜,cpu/gpu沒法在16秒內處理好數據致使交換延遲)

當CPU/GPU的處理時間超過16ms時,第一個VSync到來時,緩衝區B中的數據尚未準備好,因而只能繼續顯示以前A緩衝區中的內容。而B完成後,又由於缺少VSync pulse信號,它只能等待下一個signal的來臨。因而在這一過程當中,有一大段時間是被浪費的。當下一個VSync出現時,CPU/GPU立刻執行操做,此時它可操做的buffer是A,相應的顯示屏對應的就是B。這時看起來就是正常的。只不過因爲執行時間仍然超過16ms,致使下一次應該執行的緩衝區交換又被推遲了——如此循環反覆,便出現了愈來愈多的「Jank」。

很顯然,第一次的Jank看起來是沒有辦法的,除非升級硬件配置來加快FPS。咱們關注的重點是被CPU/GPU浪費的時間段,怎麼才能充分利用起來呢?Google爲了解決該問題,引入的三緩衝機制,即在原來雙緩衝的機制上加入了第三塊緩衝區.

咱們來逐步分析下這個是否有效。首先和預料中的一致,第一次「Jank」無可厚非。不過讓人欣慰的是,當第一次VSync發生後,CPU不用再等待了,它會使用第三個buffer C來進行下一幀數據的準備工做。雖然對緩衝區C的處理所需時間一樣超過了16ms,但這並不影響顯示屏——第2次VSync到來後,它選擇buffer B進行顯示;而第3次VSync時,它會接着採用C,而不是像double buffering中所看到的狀況同樣只能再顯示一遍B了。這樣子就有效地下降了jank。可是帶來了lag的問題,如上圖所示,A這一幀在第4個vsync來的時候才顯示,若是是雙緩衝,那在第三個vynsc就能夠顯示了。

三緩衝做用: 簡單的說在2個緩存區被GPU和display佔據的時候,開闢一個緩衝區給CPU用,通常來講都是用雙緩衝,須要的時候會開啓3緩衝,三緩衝的好處就是使得動畫更爲流程,可是會致使lag,從用戶體驗來講,就是點擊下去到呈現效果會有延遲。因此默認不開三緩衝,只有在須要的時候自動開啓 一句話總結三緩衝有效利用了等待vysnc的時間,減小了jank,可是帶來了lag

總結: VSync(解決畫面撕裂) 三緩衝(提高CPU/GPU利用率)

谷歌提供了這麼牛逼的機制,爲何你寫的APP還會卡? 1.界面太複雜。 2.主線程太忙。他可能還在處理用戶交互或者其餘事情。

參考:
lionoggo.com/2017/09/12/…
www.jianshu.com/p/0cb06877c…
blog.csdn.net/litefish/ar…

相關文章
相關標籤/搜索