硬件渲染是指通过GPU进行渲染,软件渲染是指通过CPU进行渲染。
在Android中,硬件渲染的过程是通过CPU对需要绘制的内容使用指令进行标记,再通过GPU将标记的指令转换为对应的OpenGL指令进行渲染。从Android4.0开始,UI绘制默认开启硬件加速。在Android5.0之前,Android UI线程和渲染线程是同一个线程,但在Android5.0之后,渲染过程在单独的线程中进行,这个线程就是RenderThread。
一.硬件加速渲染的开启
在Android中,硬件渲染环境的初始化是从ViewRootImpl的setView方法开始的。
在ViewRootImpl的setView方法中,主要做了三件事:
1)判断参数中的View是否为RootViewSurfaceTaker。如果为RootViewSurfaceTaker,则调用willYouTakeTheSurface方法,获取SurfaceHolder.Callback2,并保存到mSurfaceHolderCallback中。
2)如果mSurfaceHolderCallback不为空,说明开发者接管了当前Activity的Surface,则创建TakenSurfaceHolder,并保存在mSurfaceHolder中。
3)如果mSurfaceHolder为空,说明开发者没有接管当前Activity的Surface,则调用enableHardwareAcceleration方法开启硬件加速。
当在Activity中调用Window的takeSurface方法接管Activity的Surface后,Activity的渲染会脱离Android的View体系,相当于整个Activity都是SurfaceView。
class TestActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 通过这种方式可以脱离Android View体系,相当于整个Activity都是SurfaceView
window.takeSurface(object : SurfaceHolder.Callback2 {
override fun surfaceCreated(holder: SurfaceHolder) {
}
override fun surfaceChanged(
holder: SurfaceHolder,
format: Int,
width: Int,
height: Int
) {
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
}
override fun surfaceRedrawNeeded(holder: SurfaceHolder) {
}
})
}
}
在ViewRootImpl的enableHardwareAcceleration方法中主要做了三件事:
1)通过ThreadedRenderer的静态方法create创建ThreadedRenderer。
2)将创建的ThreadedRenderer保存到mAttachInfo的mThreadedRenderer字段上。
3)为ThreadedRenderer设置SurfaceControl。
1.ThreadedRenderer的初始化
ThreadedRenderer继承自HardwareRenderer。在ThreadedRenderer的构造方法中,会直接创建ThreadedRenderer并返回。
在HardwareRenderer的构造方法中,主要做了三件事:
1)创建Native层的RootRenderNode,作为窗口的渲染根节点,并返回对应的地址。
2)将返回的地址封装成Java层的RenderNode。
3)创建Native层的RenderProxy并返回对应的地址,RenderProxy负责从UI线程向Render线程发送渲染指令。
2.RenderProxy的创建
HardwareRenderer的nCreateProxy方法对应的Native实现为android_graphics_HardwareRenderer的android_view_ThreadedRenderer_createProxy函数。
在android_view_ThreadedRenderer_createProxy函数中,主要做了两件事:
1)获取Native层的RootRenderNode。
2)会创建RenderProxy,RenderProxy负责从UI线程向Render线程发送渲染指令。
在RenderProxy的构造方法中,会创建RenderThread、CanvasContext和DrawFrameTask。
- RenderThread:负责监听与请求VSync信号,在VSync信号到来时执行任务并请求下一次VSync信号。
- CanvasContext:负责渲染节点的渲染与渲染管线的管理。
- DrawFrameTask:负责硬件渲染中每一帧渲染任务的管理,包括布局的测量构建、多层级的管理等。
二.RenderProxy中组件的初始化
1.RenderThread的创建
RenderThread继承自ThreadBase,ThreadBase继承自Thread。
在RenderThread的getInstance方法中,主要做了两件事:
1)创建RenderThread。
2)并调用RenderThread的start方法启动线程。
在RenderThread的父类ThreadBase的构造方法中,会创建Looper和WorkQueue。Looper用于线程的消息驱动。WorkQueue用于存储RenderThread中执行的任务,WorkQueue中存储的任务类型为WorkItem。
在RenderThread的start方法中,会调用threadLoop方法开始循环执行任务。在RenderThread的threadLoop方法中,主要做了两件事:
1)调用initThreadLocals方法,初始化组件。
2)开启循环,执行任务。
2.CanvasContext的创建
CanvasContext在RenderProxy中创建。RenderProxy将CanvasContext的create方法封装成任务,添加到RenderThread的WorkQueue中等待执行。
在CanvasContext的create方法中,主要做了两件事:
1)根据指定类型创建对应的渲染管线。
2)创建CanvasContext。
3.DrawFrameTask的初始化
DrawFrameTask在RenderProxy中创建,通过setContext方法初始化。在DrawFrameTask的setContext方法中,会保存CanvasContext、RootRenderNode、RenderThread。
三.RenderThread的启动
1.RenderThread中组件的初始化
在RenderThread的initThreadLocals方法中,主要做了三件事:
1)调用initializeChoreographer方法,初始化VSync信号请求接收组件。
2)创建EglManager,EglManager用在初始化Open GL渲染上下文。
3)创建RenderState,RenderState用于记录渲染状态。
在RenderThread的initializeChoreographer方法中,主要做了三件事:
1)创建AChoreographer。AChoreographer是Native层Choreographer的代理类,AChoreographer是对Choreographer指针的强制转换,当需要调用VSync信号相关的方法时,会将AChoreographer强制转换回Choreographer。两者关系与ACanvas和Canvas类似。Native层Choreographer继承自DisplayEventDispatcher。
2)通过向Looper添加文件描述符的方式的监听VSync信号的分发。
3)创建ChoreographerSource。ChoreographerSource是对AChoreographer的封装,用于在RenderThread中请求与接收VSync信号。ChoreographerSource继承自VSyncSource,VSyncSource定义了请求与处理VSync信号的方法。
2.RenderThread中任务的处理
在RenderThread的threadLoop方法中,当组件初始化完成后,会开while启循环处理任务。在while循环中,主要做了三件事:
1)根据上一次任务队列执行完毕后返回的时间,对线程进行阻塞等待。
2)执行任务队列中的任务,并计算等待时间。
3)处理动画帧任务。
waitForWork方法定义在RenderThread的父类ThreadBase中。在ThreadBase的waitForWork方法中,主要做了三件事:
1)获取队列中下一个待任务任务的开始时间。
2)通过减去当前的时间,计算出线程需要阻塞的时间。
3)阻塞线程开启休眠。
3.RenderThread中动画帧的处理
当外部需要执行动画帧任务时,会调用RenderThread的postFrameCallback方法,在RenderThread的postFrameCallback方法中会对任务进行保存。
在RenderThread的threadLoop方法的循环中,在处理完WorkQueue中的任务后,如果发现有需要处理的动画帧任务,会去处理动画帧任务。
关于动画帧任务的处理,主要做了四件事:
1)对未分发的VSync信号进行分发,触发动画帧任务的执行。
2)将mPendingRegistrationFrameCallbacks中的动画帧任务转移到mFrameCallbacks中。
3)清空mPendingRegistrationFrameCallbacks。
4)请求下一次的VSync信号。
在ChoreographerSource的drainPendingEvents方法中,会调用AChoreographer_handlePendingEvents函数分发VSync信号。
3.1 VSync信号的请求
在RenderThread的requestVsync方法中,会调用ChoreographerSource的requestNextVsync方法。requestNextVsync方法内部又调用了AChoreographer_postVsyncCallback函数。
在AChoreographer_postVsyncCallback函数中,将AChoreographer转换为Choreographer,并调用Choreographer的postFrameCallbackDelayed方法。
在Choreographer的postFrameCallbackDelayed方法中,主要做了两件事:
1)将回调封装成FrameCallback并保存。
2)请求VSync信号。
3.2 VSync信号的分发
当VSync信号到来时,RenderThread的Looper会从Choreographer的Fd中检测到Looper::EVENT_INPUT消息,并回调RenderThread静态方法的choreographerCallback。
在RenderThread的静态方法choreographerCallback中,主要做了两件事:
1)获取RenderThread和AChoreographer。
2)调用AChoreographer_handlePendingEvents函数。
在AChoreographer_handlePendingEvents函数中,会调用Choreographer的handleEvent方法。handleEvent方法在Choreographer的父类DisplayEventDispatcher中实现。
在DisplayEventDispatcher的handleEvent方法中,会调用dispatchVsync方法,该方法在子类Choreographer中实现。
在Choreographer的dispatchVsync方法中,主要做了两件事:
1)收集满足时间要求的FrameCallback。
2)调用FrameCallback中的回调方法。
由于RenderThread在请求VSync信号时传入了静态方法extendedFrameCallback。因此当VSync信号到来时会调用RenderThread的静态方法extendedFrameCallback。
在RenderThread的静态方法extendedFrameCallback中,主要做了两件事:
1)获取RenderThread。
2)调用RenderThread的frameCallback方法。
在RenderThread的frameCallback方法中,主要做了两件事:
1)计算动画帧任务执行的目标时间点。
2)对dispatchFrameCallbacks方法进行封装,插入到WorkQueue中,等待到达目标时间点时threadLoop方法的循环任务处理。
当RenderThread唤醒后,会执行任务队列中的任务,会调用dispatchFrameCallbacks方法。在RenderThread的dispatchFrameCallbacks方法中,主要做了两件事:
1)请求VSync信号。
2)执行动画帧任务。
四.Surface的绑定
在ViewRootImpl的performTraversals方法中,会通过relayoutWindow方法创建Surface。当Surface创建好后,会调用ThreadedRenderer的initialize方法进行绑定。
在ThreadedRenderer的initialize方法中,会调用setSurface方法。在ThreadedRenderer的setSurface方法中,会调用父类HardwareRenderer的setSurface方法。
在HardwareRenderer的setSurface方法中,会调用nSetSurface方法。
HardwareRenderer的nSetSurface方法对应Native实现为android_graphics_HardwareRenderer的android_view_ThreadedRenderer_setSurface函数。
在android_view_ThreadedRenderer_setSurface函数中,主要做了三件事:
1)获取RenderProxy。
2)将Java层Surface指针封装成ANativeWindow。
3)为RenderProxy设置Surface。
在RenderProxy的setSurface方法中,会对CanvasContext的setSurface方法封装,添加到RenderThread的WorkQueue中等待执行。
当RenderThread执行任务时,会调用CanvasContext的setSurface方法。在CanvasContext的setSurface方法中,主要做了三件事:
1)将ANativeWindow封装成ReliableSurface,ReliableSurface用于Hook拦截ANativeWindow的方法调用。
2)初始化ReliableSurface。
3)初始化渲染管线。
在CanvasContext的setupPipelineSurface方法中,主要做了两件事:
1)获取ANativeWindow。
2)为渲染管线设置Surface。
五.总结
1.硬件渲染开启流程
硬件渲染的开启发生在ViewRootImpl中。开启硬件渲染会进行两步操作:第一步是ThreadedRenderer的创建,第二步是ThreadedRenderer与Surface的绑定。
2.ThreadedRenderer的创建
ThreadedRenderer的创建会触发Native层RootRenderNode和RenderProxy的创建。RootRenderNode是窗口渲染根节点。RenderProxy负责从UI线程向Render线程发送渲染指令。
2.1 RenderProxy的创建
RenderProxy的创建会触发RenderThread、CanvasContext、DrawFrameTask的创建。RenderThread负责监听与请求VSync信号,在VSync信号到来时执行任务并请求下一次VSync信号。CanvasContext负责渲染节点的渲染与渲染管线的管理。DrawFrameTask负责硬件渲染中每一帧渲染任务的管理,包括布局的测量构建、多层级的管理等。
3.ThreadedRenderer与Surface的绑定
ThreadedRenderer与Surface的绑定本质上是将Surface与CanvasContext中渲染管线的绑定。Java层Surface在进入Native层后会被封装成ANativeWindow。