android 多线程渲染,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/hwuivcD4NCjxwcmUgY2xhc3M9"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进行分批或合并,在一定程度上提升了绘制的性能。

创建纹理集

// 绑定纹理单元和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流畅性可以进一步提升。

你可能感兴趣的:(android,多线程渲染)