Android窗口管理分析(五) —— 硬件加速和软件加速的区别
硬件加速直观上说是依赖GPU实现图形绘制加速,软硬件加速的区别是指图形绘制究竟是GPU来处理还是CPU,如果是GPU就认为是硬件加速,反之用CPU就是软件绘制。
主要分为两部分分析:
- 前期策略:如何构建需要绘制的区域
- 后期绘制:单独渲染线程,依赖GPU进行绘制
硬/软件加速有什么异同点?
相同点
- 绘制内存的分配都是类似的,都是需要请求SurfaceFlinger服务分配一块内存
- 绘制都是在APP端,绘制后同样需要通知SurfaceFlinger进行合成
不同点
- 硬件加速有可能FrameBuffer硬件缓冲区直接分配内存,软件加速都是SurfaceFlinger分配的内存
- 在App端的绘制流程不同
软硬件加速的分歧点在哪?
在ViewRootImpl的draw方法开始分歧,有个判断点如下:
1 | private void draw(boolean fullRedrawNeeded) { |
- 4.+的手机一般都是支持硬件加速
- 在添加窗口时,ViewRootImpl会enableHardwareAcceleration开启硬件加速,并初始化硬件加速环境
1 | private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) { |
需要硬件加速就利用HardwareRenderer进行draw,否则走软件绘制流程的drawSoftware,就是上一篇讲过的利用Surface.lockCanvas, 向SurfaceFlinger申请一块匿名共享内存分配,同时获取一个普通的SkiaCanvas(2d),用于调用Skia库,并进行图形绘制。
软件绘制如下:
1 | private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff, |
硬件加速分为哪两个阶段?
- 构建阶段 ,递归遍历所有视图,将需要的操作缓存下来,之后再交给单独的Render线程利用OpenGL渲染。
- 绘制阶段 ,View视图被抽象成一个个DrawOp(DisplayListOp),比如View中drawLine,构建中就会被抽象成一个DrawLintOp,每个DrawOp有对应的OpenGL绘制命令,同时内部也握着绘图所需要的数据。
如下图所示:
绘制上硬件加速有什么优势?
绘制时,软件绘制,View一般都在主线程中完成绘制。而硬件加速,一般都是在单独线程中完成绘制,如此一来,就分担了主线程很多压力,提高了UI线程的响应速度。
硬件加速的HardWareRenderer是如何构建DrawOp集的?
HardWareRenderer是硬件加速绘制的入口,实现是一个ThreadedRenderer对象,跟一个Render线程息息相关,不过ThreadedRenderer是在UI线程中创建的,作用如下:
- 在UI线程中完成DrawOp集的构建
- 负责跟渲染线程通信
ThreadedRenderer RenderProxy ——> RenderThread 单例线程,不会出现多线程并发访问冲突的问题 ——> ThreadedRenderer的draw函数 ——> updateRootDisplayList构建RootDisplayList,构建View的DrawOp树 ——> 递归完成DrawOp树的构建
DisplayListCanvas及RenderNode类图如下:
完成DrawOp树构建之后,可以利用RenderProxy向RenderThread发送消息,请求OpenGL线程进行渲染。
RenderThread如何渲染UI到Graphic Buffer?
在DrawOp树构建完毕之后,开始渲染,大致流程如下:
- 首先进行DrawOp的合并
- 接着绘制特殊的Layer
- 最后绘制其余所有的DrawOpList
- 调用swapBuffers将前面已经绘制好的图形缓冲区提交给Surface Flinger合成和显示
总结
软件绘制同硬件合成的区别主要是在绘制上,内存分配、合成等整体流程是一样的,只不过硬件加速相比软件绘制算法更加合理,同时减轻了主线程的负担。