Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android系統教程 >> 安卓省電與加速 >> Android HWUI硬件加速模塊淺析

Android HWUI硬件加速模塊淺析

編輯:安卓省電與加速

 


什麼是硬件加速(What)

傳統軟件的UI繪制是依靠CPU來完成的,硬件加速就是將繪制任務交由GPU來執行。GPU相比CPU更加適合完成光柵化、動畫變換等耗時任務,在移動設備上比起使用CPU來完成這些任務,GPU會更加省電些,帶來的用戶體驗也會更佳。

為什麼要硬件加速(Why)

Android的硬件加速的底層實現是基於OpenGL ES接口向GPU提交指令來完成繪制的。相對於CPU實現的軟繪制,硬件加速的幀率會高於CPU,效能更高。屏幕分辨率越大(尤其對於高清電視而言),硬件加速的優勢更加明顯。

下圖是Android 5.0的HWUI繪制執行流程:

這裡寫圖片描述

源碼位於目錄android/platform/framework/base/libs/hwui<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwcmUgY2xhc3M9"brush:java;"> public class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource { ...... public void buildLayer() { ...... final AttachInfo attachInfo = mAttachInfo; ...... switch (mLayerType) { case LAYER_TYPE_HARDWARE: updateDisplayListIfDirty(); if (attachInfo.mHardwareRenderer != null && mRenderNode.isValid()) { attachInfo.mHardwareRenderer.buildLayer(mRenderNode); } break; case LAYER_TYPE_SOFTWARE: buildDrawingCache(true); break; } } ...... }

當View的LayerType設置為HARDWARE時,View就會綁定到一個OpenGL ES的FrameBufferObject上去,如果要對這個View進行Animation(Alpha,Rotation,etc.),會將這個FrameBufferObject渲染至Texture(2D),然後再進行動畫的渲染,這樣有一個壞處,消耗的內存增加了。

硬件加速的實現(How)

獨立的渲染線程

在Android 5上,ThreadedRenderer的出現減輕了主線程的負擔,可以更快的響應用戶的操作。

Deferred Display List

這裡寫圖片描述

DisplayList記錄了繪制操作和狀態,主線程將它們提交至OpenGL渲染器,由渲染器執行最終的DrawCall。

Android 4.4之後,HWUI模塊引入了Deferred Display List,它在Display List的基礎上做了一些優化,比如剔除過繪制的區域、對DrawCall進行分批或合並,在一定程度上提升了繪制的性能。

創建紋理集

這裡寫圖片描述seo8L3N0cm9uZz6jrMq5VUnSwMi7xNy5u9X9yLe75tbGoaM8L3A+DQo8L2Jsb2NrcXVvdGU+DQo8cD7I57n7yeixuNans9ZPcGVuR0wgRVMgMy4wo6xBbmRyb2lku+HKudPDPHN0cm9uZz5QaXhlbEJ1ZmZlck9iamVjdLDztqg8L3N0cm9uZz7Ktc/WzsbA7bXE0uyyvcnPtKujrNXi0fnX9rXEusO0ptTa09rNqLn907PJ5Le9yr2jqGdsTWFwQnVmZmVyo6m4/LzTuN/Qp7XEyc+0q87GwO3K/b7d1sFHUFWho8/Cw+bV4rbOtPrC68C019TT2tfAw+a2y7XEyrXP1qOs0sa2r7bLtcTKtc/Wsu7S7LK7tPOhozwvcD4NCjxwcmUgY2xhc3M9"brush:java;"> // 綁定紋理單元和PBO glBindTexture(GL_TEXTURE_2D, textureId); glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pboIds[index]); // 將PBO的像素復制到紋理中去 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, WIDTH, HEIGHT, GL_BGRA, GL_UNSIGNED_BYTE, 0); //准備上傳下一份紋理 glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pboIds[nextIndex]); //這裡如果直接調用glMapBuffer會引起OpenGL狀態機的一個同步檢查(開銷較大),但是使用BufferData的話就不會,他可以直接分配完數據返回 glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, DATA_SIZE, 0, GL_STREAM_DRAW_ARB); //將GPU數據映射至內存 GLubyte* ptr = (GLubyte*)glMapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, GL_WRITE_ONLY_ARB); if(ptr) { updatePixels(ptr, DATA_SIZE); //直接更新紋理數據 glUnmapBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB); // 釋放映射的緩沖區 } glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0);

ATLAS的使用減少了GPU顯存的消耗,以及紋理單元(Texture Unit)綁定調用(Resource Binding)的開銷。

合並DrawCall

這裡寫圖片描述

Android硬件加速的過程中並沒有啟用深度測試(DepthTest),所有的UI繪制都是按照繪制的次序展示在屏幕上。由於OpenGL ES的驅動實現的復雜性,每個GL的綁定調用以及GL狀態的切換都是昂貴的,所以才引入了Deferred Display List對DrawCall合並以及分批,相關類,如上圖。

字體繪制

這裡寫圖片描述

文字的渲染也是一個令人頭疼的問題,APP的文字渲染不像游戲中那樣的簡單,通常游戲發布的時候可以預先將固定的文字轉換成單張的紋理,渲染文字時直接映射紋理坐標即可。Android底層對文字字形紋理數據進行了Cache。Android使用了Skia和第三方開源字體庫(FreeType)對字體進行柵格化。

這裡寫圖片描述

硬件加速的改進

iOS的UI繪制使用了Multiple GL Context,在iOS 8之後又引入了Metal Framework,原生支持多線程UI渲染,Android由於GL驅動以及GPU廠商實現的差異無法很好地搾干GPU的機能,但是在下一代的圖形API(Vulkan,驅動變薄、支持多線程)普及之後,仍然有較大的優化空間,UI流暢性可以進一步提升。

 

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