Android HWUI硬體加速模組淺析

來源:互聯網
上載者:User

標籤:android   硬體加速   移動開發   

關鍵詞:RenderNode,ThreadedRenderer,DisplayList,UvMapper,FontRenderer

什麼是硬體加速(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

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進行分批或合并,在一定程度上提升了繪製的效能。

建立紋理集

AssetAtlasService對資源的載入在做了專門的管理,它為了減少圖片資源上傳至GPU的操作,對對各資源進行合并,打包成單張紋理進行上傳,通過UvMapper重新對應紋理座標,使UI依然能夠正確繪製。

如果裝置支援OpenGL ES 3.0,Android會使用PixelBufferObject綁定實現紋理的非同步上傳,這樣做的好處在於通過映射方式(glMapBuffer)更加高效的上傳紋理資料至GPU。下面這段代碼來自於案頭端的實現,移動端的實現差異不大。

// 綁定紋理單元和PBOglBindTexture(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. Efficient text rendering with OpenGL ES
  2. Rendering Text in Metal with Signed-Distance Fields
  3. 老羅的Android之旅
  4. How about some Android graphics true facts?
  5. Introduction to the Android Graphics Pipeline

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

Android HWUI硬體加速模組淺析

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.