Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android系統教程 >> 安卓省電與加速 >> Android應用程序UI硬件加速渲染技術簡要介紹和學習計劃

Android應用程序UI硬件加速渲染技術簡要介紹和學習計劃

編輯:安卓省電與加速

Android系統的流暢性一直被拿來與iOS比較,並且認為不如後者。這一方面與Android設備硬件質量參差不齊有關,另一方面也與Android系統的實現有關。例如在3.0前,Android應用程序UI繪制不支持硬件加速。不過從4.0開始,Android系統一直以“run fast, smooth, and responsively”為目標對UI進行優化。本文對這些優化進行簡要介紹和制定學習計劃。

 

注意,上面我們說Android系統不支持硬件加速的UI 繪制,針對的是Android應用程序2D UI繪制。對於3D UI,例如游戲,一直是支持硬件加速渲染的。此外,從前面Android應用程序與SurfaceFlinger服務的關系概述和學習計劃、Android系統Surface機制的SurfaceFlinger服務簡要介紹和學習計劃和Android應用程序窗口(Activity)實現框架簡要介紹和學習計劃這三個系列的文章可以知道,Android系統的UI從繪制到顯示到屏幕是分兩步進行的:第一步是在Android應用程序進程這一側進行的;第二步是在SurfaceFlinger進程這一側進行的。前一步將UI繪制一個圖形緩沖區中,並且將該圖形緩沖區交給後一步進行合成以及顯示在屏幕中。其中,後一步的UI合成一直都是以硬件加速方式完成的。

在支持Android應用程序UI硬件加速渲染之前,Android應用程序UI的繪制是以軟件方式進行的,為了更好地理解Android應用程序UI硬件加速渲染技術,我們先回顧在Android應用程序窗口(Activity)實現框架簡要介紹和學習計劃這個系列的文章提及的軟件渲染技術,如圖1所示:

/

圖1 Android應用程序UI軟件渲染過程

在Android應用程序進程這一側,每一個窗口都關聯有一個Surface。每當窗口需要繪制UI時,就會調用其關聯的Surface的成員函數lock獲得一個Canvas,其本質上是向SurfaceFlinger服務Dequeue一個Graphic Buffer。Canvas封裝了由Skia提供的2D UI繪制接口,並且都是在前面獲得的Graphic Buffer上面進行繪制的。繪制完成之後,Android應用程序進程再調用前面獲得的Canvas的成員函數unlockAndPost請求顯示顯示在屏幕中,其本質上是向SurfaceFlinger服務Queue一個Graphic Buffer,以便SurfaceFlinger服務可以對Graphic Buffer的內容進行合成,以及顯示到屏幕上去。

接下來我們再來看Android應用程序UI硬件加速渲染技術,如圖2所示:

/

圖2 Android應用程序UI硬件加速渲染過程

這這裡我們首先要明確什麼是硬件加速渲染,其實就是通過GPU來進行渲染。GPU作為一個硬件,用戶空間是不可以直接使用的,它是由GPU廠商按照Open GL規范實現的驅動間接進行使用的。也就是說,如果一個設備支持GPU硬件加速渲染,那麼當Android應用程序調用Open GL接口來繪制UI時,Android應用程序的UI就是通過硬件加速技術進行渲染的。因此,在接下來的描述中,我們提及到GPU、硬件加速和Open GL時,它們表達的意思都是等價的。

從圖2可以看到,硬件加速渲染和軟件渲染一樣,在開始渲染之前,都是要先向SurfaceFlinger服務Dequeue一個Graphic Buffer。不過對硬件加速渲染來說,這個Graphic Buffer會被封裝成一個ANativeWindow,並且傳遞給Open GL進行硬件加速渲染環境初始化。在Android系統中,ANativeWindow和Surface可以是認為等價的,只不過是ANativeWindow常用於Native層中,而Surface常用於Java層中。另外,我們還可以將ANativeWindow和Surface看作是像Skia和Open GL這樣圖形渲染庫與操作系統底層的圖形系統建立連接的一個橋梁。

Open GL獲得了一個ANativeWindow,並且進行了硬件加速渲染環境初始化工作之後,Android應用程序就可以調用Open GL提供的API進行UI繪制了,繪制出來內容就保存在前面獲得的Graphic Buffer中。當繪制完畢,Android應用程序再調用libegl庫提供的一個eglSwapBuffer接口請求將繪制好的UI顯示到屏幕中,其本質上與軟件渲染過程是一樣的,都是向SurfaceFlinger服務Queue一個Graphic Buffer,以便SurfaceFlinger服務可以對Graphic Buffer的內容進行合成,以及顯示到屏幕上去。

關於Android應用程序UI的硬件加速渲染過程中涉及到Open GL環境初始化和繪制的簡化版本,可以參考前面Android系統的開機畫面顯示過程分析一文提到的Android系統開機動畫的實現。在Android系統的開機畫面顯示過程分析這篇文章中,開機動畫其實是由一個/system/bin/bootanimation程序實現的。這個程序可以看成是一個沒有使用Android SDK來開發的一個Native應用程序。

在這個系列的文章中,我們將通過Android 5.0的源碼來分析Android應用程序UI的硬件加速渲染技術。不過為了更好地理解Android 5.0的硬件加速渲染實現,我們有必要先了解從Android 3.0以來,Android應用程序UI硬件加速渲染的進化歷史:

1. Android 3.0,也就是Honeycomb版本,開始引用OpenGLRenderer圖形渲染庫,支持Android應用程序UI可選地使用硬件加速渲染。

2. Android 4.0,也就是Ice Cream Sandwich版本,要求設備默認支持Android應用程序UI硬件加速渲染,並且增加一個TextureView控件,該控件直接支持以Open GL紋理的形式來繪制UI。

3. Android 4.1、4.2和4.3,也就是Jelly Bean版本,加入了Project Butter(黃油計劃)的特性,包括:A. 通過Vsync信號來同步UI繪制和動畫,使得它們可以獲得一個達到60fps的固定的幀率;B. 三緩沖支持,改善GPU和CPU之間繪制節奏不一致的問題;C. 將用戶輸入,例如touch event,同步到下一個Vsync信號到來時再處理;D. 預測用戶的touch行為,以獲得更好的交互響應;E. 每次用戶touch屏幕時,進行CPU Input Boost,以便減少處理延時。

4. Android 4.4,也就是KitKat版本,一方面通過優化內存使用,另一方面是可選地支持使用ART運行時替換Dalvik虛擬機,來提高應用程序的運行效率,使得其UI更流暢。

5. Android 5.0,也就是Lollipop版本,ART運行時引進了Compacting GC,進一步優化了Android應用程序的內存使用,並且ART運行時正式替換了Dalvik虛擬機,同時,Android應用程序增加了一個Render Thread,專門負責UI渲染和動畫顯示。

從Android應用程序UI硬件加速渲染的進化歷史可以看出,Android系統確實是在踐行run fast, smooth, and responsively的宏偉計劃,並且也是做到了。

有了前面的基礎知識之後,我們接下來再來Android 5.0的窗口和動畫是如何通過硬件加速技術來渲染的,如圖3所示:

/

圖3 Android應用程序窗口和動畫的硬件加速渲染框架

在Android應用程序窗口中,每一個View都抽象為一個Render Node,而且如果一個View設置有Background,這個Background也被抽象為一個Render Node。這是由於在OpenGLRenderer庫中,並沒有View的概念,所有的一切可繪制的元素都抽象為一個Render Node。

每一個Render Node都關聯有一個Display List Renderer。這裡又涉及到另外一個概念——Display List。注意,這個Display List不是Open GL裡面的Display List,不過它們在概念上是差不多的。Display List是一個繪制命令緩沖區。也就是說,當View的成員函數onDraw被調用時,我們調用通過參數傳遞進來的Canvas的drawXXX成員函數繪制圖形時,我們實際上只是將對應的繪制命令以及參數保存在一個Display List中。接下來再通過Display List Renderer執行這個Display List的命令,這個過程稱為Display List Replay。

引進Display List的概念有什麼好處呢?主要是兩個好處。第一個好處是在下一幀繪制中,如果一個View的內容不需要更新,那麼就不用重建它的Display List,也就是不需要調用它的onDraw成員函數。第二個好處是在下一幀中,如果一個View僅僅是一些簡單的屬性發生變化,例如位置和Alpha值發生變化,那麼也無需要重建它的Display List,只需要在上一次建立的Display List中修改一下對應的屬性就可以了,這也意味著不需要調用它的onDraw成員函數。這兩個好處使用在繪制應用程序窗口的一幀時,省去執行很多的應用程序代碼,也就是大大地節省了CPU的執行時間。

注意,只有使用硬件加速渲染的View,才會關聯有Render Node,也就才會使用到Display List。我們知道,目前並不是所有的2D UI繪制命令都是GPU可以支持的。這一點具體可以參考官方說明文檔:http://developer.android.com/guide/topics/graphics/hardware-accel.html。對於使用了GPU不支持的2D UI繪制命令的View,只能通過軟件方式來渲染。具體的做法是將創建一個新的Canvas,這個Canvas的底層是一個Bitmap,也就是說,繪制都發生在這個Bitmap上。繪制完成之後,這個Bitmap再被記錄在其Parent View的Display List中。而當Parent View的Display List的命令被執行時,記錄在裡面的Bitmap再通過Open GL命令來繪制。

另一方面,對於前面提到的在Android 4.0引進的TextureView,它也不是通過Display List來繪制。由於它的底層實現直接就是一個Open GL紋理,因此就可以跳過Display List這一中間層,從而提高效率。這個Open GL紋理的繪制通過一個Layer Renderer來封裝。Layer Renderer和Display List Renderer可以看作是同一級別的概念,它們都是通過Open GL命令來繪制UI元素的。只不過前者操作的是Open GL紋理,而後者操作的是Display List。

我們知道,Android應用程序窗口的View是通過樹形結構來組織的。這些View不管是通過硬件加速渲染還是軟件渲染,或者是一個特殊的TextureView,在它們的成員函數onDraw被調用期間,它們都是將自己的UI繪制在Parent View的Display List中。其中,最頂層的Parent View是一個Root View,它關聯的Root Node稱為Root Render Node。也就是說,最終Root Render Node的Display List將會包含有一個窗口的所有繪制命令。在繪制窗口的下一幀時,Root Render Node的Display List都會通過一個Open GL Renderer真正地通過Open GL命令繪制在一個Graphic Buffer中。最後這個Graphic Buffer被交給SurfaceFlinger服務進行合成和顯示。

上面分析的應用程序UI繪制機制還沒有涉及到動畫。當一個View需要以動畫的形式顯示時,我們可以通過調用這個View的成員函數animate獲得一個ViewPropertyAnimator。ViewPropertyAnimator像View一樣,也被抽象為一個Render Node。不過這個Render Node的處理方式與View的Render Node的處理方式不同,它們會被注冊到Android應用程序的Render Thread中,然後由Render Thread負責執行它所蘊含著的動畫,直到動畫結束為止。這樣就不需要Android應用程序的主線程處理動畫了,使得Android應用程序的主線程可以更專注地處理用戶輸入,從而使用Android應用程序UI具有更好的響應性。

更進一步地,如果我們調用了ViewPropertyAnimator的成員函數withLayer,那麼目標View的動畫可以得到更一步的優化。回憶TextureView的特點,它是直接通過Open GL紋理來繪制,這樣可以省去Display List這一中間步驟。同樣的,當我們調用了ViewPropertyAnimator的成員函數withLayer時,目標View的Layer Type將被臨時修改為LAYER_TYPE_HARDWARE。對於Layer Type為LAYER_TYPE_HARDWARE的View,它將直接通過Open GL的Frame Buffer Object(FBO)來實現,這樣也是可以提高渲染效率。等到動畫結束的時候,目標View的Layer Type將恢復為原來設置的類型。

以上就是Android應用程序窗口和動畫的硬件加速渲染框架,裡面提到的Render Thread還需要進一步解釋。Render Thread是在Android 5.0中引進的,它用來分擔Android應用程序的Main Thread的工作。在Android 5.0之前,Android應用程序的Main Thread不僅負責渲染UI,還負責處理用戶輸入。通過引進Render Thread,我們就可以將Main Thread從UI渲染工作中釋放出來,交由Render Thread來處理,從而也使得Main Thread可以更高專注高效地處理用戶輸入,這樣使得在提高UI繪制效率的同時,也使得UI具有有更高的響應性。

Main Thread與Render Thread的交互模型如圖4所示:

/

圖4 Android應用程序Main Thread與Render Thread的交互模型

Main Thread主要是負責調用View的成員函數onDraw來構造它們的Display List,然後在下一個Vsync信號到來時,再通過一個Redner Proxy對象向Render Thread發出一個drawFrame命令。Render Thread內部有一個Task Queue,從Main Thread發送過來的drawFrame命令就會保存在Render Thread的Task Queue,等待Render Thread處理。

對於動畫顯示,Main Thread與Render Thread的交互模型如圖5所示:

/

圖5 Android應用程序Main Thread與Render Thread的動畫交互模型

在Java層,通過Render Node來實現的動畫抽象為一個Render Node Animator。這個Render Node Animator將一個代表動畫的Render Node注冊到Render Thread中,實現上是將該Render Node附加在Android應用程序窗口的Root Render Node中。Render Thread在內部再將該Render Node封裝成一個Animator Handle對象,並且負責執行它所描述的動畫,直到該動畫結束為止。

至此,Android應用程序UI的硬件加速渲染涉及到的關鍵概念我們就介紹完成了,接下來我們還會按照以下四個情景進一步分析它的實現:

1. Android應用程序UI硬件加速渲染的環境初始化過程分析;

2. Android應用程序UI硬件加速渲染的Display List構建過程分析;

3. Android應用程序UI硬件加速渲染的Display List重放過程分析;

4. Android應用程序UI硬件加速渲染的動畫執行過程分析。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved