Android窗口管理分析(五)-——-硬件加速和软件加速的区别

Android窗口管理分析(五) —— 硬件加速和软件加速的区别

硬件加速直观上说是依赖GPU实现图形绘制加速,软硬件加速的区别是指图形绘制究竟是GPU来处理还是CPU,如果是GPU就认为是硬件加速,反之用CPU就是软件绘制。

主要分为两部分分析:

  1. 前期策略:如何构建需要绘制的区域
  2. 后期绘制:单独渲染线程,依赖GPU进行绘制

硬/软件加速有什么异同点?

相同点

  1. 绘制内存的分配都是类似的,都是需要请求SurfaceFlinger服务分配一块内存
  2. 绘制都是在APP端,绘制后同样需要通知SurfaceFlinger进行合成

不同点

  1. 硬件加速有可能FrameBuffer硬件缓冲区直接分配内存,软件加速都是SurfaceFlinger分配的内存
  2. 在App端的绘制流程不同

软硬件加速的分歧点在哪?

在ViewRootImpl的draw方法开始分歧,有个判断点如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private void draw(boolean fullRedrawNeeded) {
...
if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
<!--关键点1 是否开启硬件加速-->
if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
...
dirty.setEmpty();
mBlockResizeBuffer = false;
<!--关键点2 硬件加速绘制-->
mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this);
} else {
...
<!--关键点3 软件绘制-->
if (!drawSoftware(surface, mAttachInfo, xOffset, yOffset, scalingRequired, dirty)) {
return;
}
...
  1. 4.+的手机一般都是支持硬件加速
  2. 在添加窗口时,ViewRootImpl会enableHardwareAcceleration开启硬件加速,并初始化硬件加速环境
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {

<!--根据配置,获取硬件加速的开关-->
// Try to enable hardware acceleration if requested
final boolean hardwareAccelerated =
(attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
if (hardwareAccelerated) {
...
<!--新建硬件加速图形渲染器-->
mAttachInfo.mHardwareRenderer = HardwareRenderer.create(mContext, translucent);
if (mAttachInfo.mHardwareRenderer != null) {
mAttachInfo.mHardwareRenderer.setName(attrs.getTitle().toString());
mAttachInfo.mHardwareAccelerated =
mAttachInfo.mHardwareAccelerationRequested = true;
}
...

需要硬件加速就利用HardwareRenderer进行draw,否则走软件绘制流程的drawSoftware,就是上一篇讲过的利用Surface.lockCanvas, 向SurfaceFlinger申请一块匿名共享内存分配,同时获取一个普通的SkiaCanvas(2d),用于调用Skia库,并进行图形绘制。

软件绘制如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private boolean drawSoftware(Surface surface, AttachInfo attachInfo, int xoff, int yoff,
boolean scalingRequired, Rect dirty) {
final Canvas canvas;
try {
<!--关键点1 -->
canvas = mSurface.lockCanvas(dirty);
..
<!--关键点2 绘制-->
mView.draw(canvas);
..
关键点3 通知SurfaceFlinger进行图层合成
surface.unlockCanvasAndPost(canvas);
} ...
return true;
}

硬件加速分为哪两个阶段?

  1. 构建阶段 ,递归遍历所有视图,将需要的操作缓存下来,之后再交给单独的Render线程利用OpenGL渲染。
  2. 绘制阶段 ,View视图被抽象成一个个DrawOp(DisplayListOp),比如View中drawLine,构建中就会被抽象成一个DrawLintOp,每个DrawOp有对应的OpenGL绘制命令,同时内部也握着绘图所需要的数据。

如下图所示:

绘制上硬件加速有什么优势?

绘制时,软件绘制,View一般都在主线程中完成绘制。而硬件加速,一般都是在单独线程中完成绘制,如此一来,就分担了主线程很多压力,提高了UI线程的响应速度。

硬件加速的HardWareRenderer是如何构建DrawOp集的?

HardWareRenderer是硬件加速绘制的入口,实现是一个ThreadedRenderer对象,跟一个Render线程息息相关,不过ThreadedRenderer是在UI线程中创建的,作用如下:

    1. 在UI线程中完成DrawOp集的构建
    1. 负责跟渲染线程通信

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合成和显示

总结

软件绘制同硬件合成的区别主要是在绘制上,内存分配、合成等整体流程是一样的,只不过硬件加速相比软件绘制算法更加合理,同时减轻了主线程的负担。