Android硬件渲染环境初始化

543 阅读9分钟

    硬件渲染是指通过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方法开启硬件加速。

UML 图_edit_352496095980587.jpg     当在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。

UML 图 (1)_edit_352761436747734.jpg

1.ThreadedRenderer的初始化

    ThreadedRenderer继承自HardwareRenderer。在ThreadedRenderer的构造方法中,会直接创建ThreadedRenderer并返回。

    在HardwareRenderer的构造方法中,主要做了三件事:

1)创建Native层的RootRenderNode,作为窗口的渲染根节点,并返回对应的地址。

2)将返回的地址封装成Java层的RenderNode。

3)创建Native层的RenderProxy并返回对应的地址,RenderProxy负责从UI线程向Render线程发送渲染指令。

UML 图 (2)_edit_352669084827957.jpg

2.RenderProxy的创建

    HardwareRenderer的nCreateProxy方法对应的Native实现为android_graphics_HardwareRenderer的android_view_ThreadedRenderer_createProxy函数。

    在android_view_ThreadedRenderer_createProxy函数中,主要做了两件事:

1)获取Native层的RootRenderNode。

2)会创建RenderProxy,RenderProxy负责从UI线程向Render线程发送渲染指令。

UML 图 (3)_edit_352593841245156.jpg     在RenderProxy的构造方法中,会创建RenderThread、CanvasContext和DrawFrameTask。

  • RenderThread:负责监听与请求VSync信号,在VSync信号到来时执行任务并请求下一次VSync信号。
  • CanvasContext:负责渲染节点的渲染与渲染管线的管理。
  • DrawFrameTask:负责硬件渲染中每一帧渲染任务的管理,包括布局的测量构建、多层级的管理等。

UML 图 (4)_edit_352545875992559.jpg

二.RenderProxy中组件的初始化

1.RenderThread的创建

    RenderThread继承自ThreadBase,ThreadBase继承自Thread。

    在RenderThread的getInstance方法中,主要做了两件事:

1)创建RenderThread。

2)并调用RenderThread的start方法启动线程。

UML 图 (5)_edit_352533964261831.jpg     在RenderThread的父类ThreadBase的构造方法中,会创建Looper和WorkQueue。Looper用于线程的消息驱动。WorkQueue用于存储RenderThread中执行的任务,WorkQueue中存储的任务类型为WorkItem。

UML 图 (6)_edit_352527392374332.jpg     在RenderThread的start方法中,会调用threadLoop方法开始循环执行任务。在RenderThread的threadLoop方法中,主要做了两件事:

1)调用initThreadLocals方法,初始化组件。

2)开启循环,执行任务。

UML 图 (7)_edit_352515096546209.jpg

2.CanvasContext的创建

    CanvasContext在RenderProxy中创建。RenderProxy将CanvasContext的create方法封装成任务,添加到RenderThread的WorkQueue中等待执行。

    在CanvasContext的create方法中,主要做了两件事:

1)根据指定类型创建对应的渲染管线。

2)创建CanvasContext。

UML 图 (8)_edit_352508506618606.jpg

3.DrawFrameTask的初始化

    DrawFrameTask在RenderProxy中创建,通过setContext方法初始化。在DrawFrameTask的setContext方法中,会保存CanvasContext、RootRenderNode、RenderThread。

UML 图 (9)_edit_352502460229024.jpg

三.RenderThread的启动

1.RenderThread中组件的初始化

    在RenderThread的initThreadLocals方法中,主要做了三件事:

1)调用initializeChoreographer方法,初始化VSync信号请求接收组件。

2)创建EglManager,EglManager用在初始化Open GL渲染上下文。

3)创建RenderState,RenderState用于记录渲染状态。

UML 图 (10)_edit_352751055722215.jpg     在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信号的方法。

UML 图 (11)_edit_352744640983674.jpg

2.RenderThread中任务的处理

    在RenderThread的threadLoop方法中,当组件初始化完成后,会开while启循环处理任务。在while循环中,主要做了三件事:

1)根据上一次任务队列执行完毕后返回的时间,对线程进行阻塞等待。

2)执行任务队列中的任务,并计算等待时间。

3)处理动画帧任务。

UML 图 (12)_edit_352738388709196.jpg     waitForWork方法定义在RenderThread的父类ThreadBase中。在ThreadBase的waitForWork方法中,主要做了三件事:

1)获取队列中下一个待任务任务的开始时间。

2)通过减去当前的时间,计算出线程需要阻塞的时间。

3)阻塞线程开启休眠。

UML 图 (13)_edit_352732144968051.jpg

3.RenderThread中动画帧的处理

    当外部需要执行动画帧任务时,会调用RenderThread的postFrameCallback方法,在RenderThread的postFrameCallback方法中会对任务进行保存。

UML 图 (14)_edit_352711736888367.jpg     在RenderThread的threadLoop方法的循环中,在处理完WorkQueue中的任务后,如果发现有需要处理的动画帧任务,会去处理动画帧任务。

    关于动画帧任务的处理,主要做了四件事:

1)对未分发的VSync信号进行分发,触发动画帧任务的执行。

2)将mPendingRegistrationFrameCallbacks中的动画帧任务转移到mFrameCallbacks中。

3)清空mPendingRegistrationFrameCallbacks。

4)请求下一次的VSync信号。

UML 图 (15)_edit_352700410019618.jpg     在ChoreographerSource的drainPendingEvents方法中,会调用AChoreographer_handlePendingEvents函数分发VSync信号。

UML 图 (16)_edit_352692824244620.jpg

3.1 VSync信号的请求

    在RenderThread的requestVsync方法中,会调用ChoreographerSource的requestNextVsync方法。requestNextVsync方法内部又调用了AChoreographer_postVsyncCallback函数。

UML 图 (17)_edit_352686811672225.jpg     在AChoreographer_postVsyncCallback函数中,将AChoreographer转换为Choreographer,并调用Choreographer的postFrameCallbackDelayed方法。

UML 图 (18)_edit_352680997508163.jpg     在Choreographer的postFrameCallbackDelayed方法中,主要做了两件事:

1)将回调封装成FrameCallback并保存。

2)请求VSync信号。

UML 图 (19)_edit_352675351117539.jpg

3.2 VSync信号的分发

    当VSync信号到来时,RenderThread的Looper会从Choreographer的Fd中检测到Looper::EVENT_INPUT消息,并回调RenderThread静态方法的choreographerCallback。

    在RenderThread的静态方法choreographerCallback中,主要做了两件事:

1)获取RenderThread和AChoreographer。

2)调用AChoreographer_handlePendingEvents函数。

UML 图 (20)_edit_352663362925353.jpg     在AChoreographer_handlePendingEvents函数中,会调用Choreographer的handleEvent方法。handleEvent方法在Choreographer的父类DisplayEventDispatcher中实现。

    在DisplayEventDispatcher的handleEvent方法中,会调用dispatchVsync方法,该方法在子类Choreographer中实现。

UML 图 (21)_edit_352652805838376.jpg     在Choreographer的dispatchVsync方法中,主要做了两件事:

1)收集满足时间要求的FrameCallback。

2)调用FrameCallback中的回调方法。

UML 图 (22)_edit_352646891314418.jpg     由于RenderThread在请求VSync信号时传入了静态方法extendedFrameCallback。因此当VSync信号到来时会调用RenderThread的静态方法extendedFrameCallback。

    在RenderThread的静态方法extendedFrameCallback中,主要做了两件事:

1)获取RenderThread。

2)调用RenderThread的frameCallback方法。

UML 图 (23)_edit_352640581171711.jpg     在RenderThread的frameCallback方法中,主要做了两件事:

1)计算动画帧任务执行的目标时间点。

2)对dispatchFrameCallbacks方法进行封装,插入到WorkQueue中,等待到达目标时间点时threadLoop方法的循环任务处理。

UML 图 (24)_edit_352634073809212.jpg     当RenderThread唤醒后,会执行任务队列中的任务,会调用dispatchFrameCallbacks方法。在RenderThread的dispatchFrameCallbacks方法中,主要做了两件事:

1)请求VSync信号。

2)执行动画帧任务。

UML 图 (25)_edit_352628024718588.jpg

四.Surface的绑定

    在ViewRootImpl的performTraversals方法中,会通过relayoutWindow方法创建Surface。当Surface创建好后,会调用ThreadedRenderer的initialize方法进行绑定。

UML 图 (26)_edit_352621933176922.jpg     在ThreadedRenderer的initialize方法中,会调用setSurface方法。在ThreadedRenderer的setSurface方法中,会调用父类HardwareRenderer的setSurface方法。

UML 图 (27)_edit_352615057482131.jpg     在HardwareRenderer的setSurface方法中,会调用nSetSurface方法。

UML 图 (28)_edit_352609182806612.jpg     HardwareRenderer的nSetSurface方法对应Native实现为android_graphics_HardwareRenderer的android_view_ThreadedRenderer_setSurface函数。

    在android_view_ThreadedRenderer_setSurface函数中,主要做了三件事:

1)获取RenderProxy。

2)将Java层Surface指针封装成ANativeWindow。

3)为RenderProxy设置Surface。

UML 图 (29)_edit_352603037021196.jpg     在RenderProxy的setSurface方法中,会对CanvasContext的setSurface方法封装,添加到RenderThread的WorkQueue中等待执行。

UML 图 (30)_edit_352570200746201.jpg     当RenderThread执行任务时,会调用CanvasContext的setSurface方法。在CanvasContext的setSurface方法中,主要做了三件事:

1)将ANativeWindow封装成ReliableSurface,ReliableSurface用于Hook拦截ANativeWindow的方法调用。

2)初始化ReliableSurface。

3)初始化渲染管线。

UML 图 (31)_edit_352558504808182.jpg     在CanvasContext的setupPipelineSurface方法中,主要做了两件事:

1)获取ANativeWindow。

2)为渲染管线设置Surface。

UML 图 (32)_edit_352551948850891.jpg

五.总结

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。