Activity的绘制流程(五)

上一篇讲了Activity的绘制流程(四)Surface
https://www.jianshu.com/p/5315fea34445),本篇主讲(五)RenderThread。
(一)窗口的添加
(二)Choreographer
(三)VSync
(四)Surface
(五)RenderThread
(六)StartingWIndow
(七)窗口切换
从Android4.0开始,系统默认开启硬件加速渲染。Android中的硬件渲染是指Android应用程序通过GPU将图形渲染到GraphicsBuffer的过程。当然除了硬件渲染,还有软件渲染,即使用CPU完成渲染。GPU相对于CPU的渲染优势在于,GPU擅长数学运算,CPU擅长逻辑运算,所以GPU更擅长于图形计算。
初学硬件渲染的时候,经常会看见GPU、OpenGL和OpenGL ES,在这里稍微解释一下三者的区别。GPU是一个硬件,用户空间不可直接使用。OpenGL是一个跨编程语言、跨平台的图形程序接口,GPU厂商按照OpenGL规范实现的驱动来操作GPU。所以Android中的硬件加速渲染,具体是指Android应用程序调用OpenGL接口使用GPU将图形渲染到GraphicsBuffer的过程。而OpenGL ES是OpenGL三维图形API的子集,是OpenGL的嵌入式设备版本。
在上一篇文章提到了BufferQueue、应用端、SurfaceFlinger构成了一个生产者-消费者模型。生产者(应用端)从BufferQueue中取得GraphicsBuffer,将UI绘制到GraphicsBuffer,然后将GraphicsBuffer放回BufferQueue。消费者(SurfaceFlinger)从BufferQueue中取得GraphicsBuffer,进行合成及显示,然后将GraphicsBuffer放回BufferQueue。生产者的工作其实主要是由RenderThread负责的。

一、RenderThread的创建

RenderThread的创建.jpg

从代码中可以看到,Android4.0开始会默认添加flag FLAG_HARDWARE_ACCELERATED,系统开启硬件加速渲染。在代码里还有另外两个flag PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED和PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED,用于开启一个假的硬件加速和强制开启硬件加速。

PackageParser.java
    private boolean parseBaseApplication(Package owner, Resources res,
            XmlResourceParser parser, int flags, String[] outError) {
        ...
        owner.baseHardwareAccelerated = sa.getBoolean(
                com.android.internal.R.styleable.AndroidManifestApplication_hardwareAccelerated,
                owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH);
        if (owner.baseHardwareAccelerated) {
            ai.flags |= ApplicationInfo.FLAG_HARDWARE_ACCELERATED;
        }
        ...
    }

WindowManagerGlobal.java
    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        ...
        if (context != null && (context.getApplicationInfo().flags
                            & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
                wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
         }
         ...
    }

ViewRootImpl.java
    private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
        ...
        final boolean hardwareAccelerated =
                (attrs.flags & WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
        if (hardwareAccelerated) {
            final boolean fakeHwAccelerated = (attrs.privateFlags &
                    WindowManager.LayoutParams.PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED) != 0;
            final boolean forceHwAccelerated = (attrs.privateFlags &
                    WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED) != 0;
            if (fakeHwAccelerated) {
                ...
            } else if (!ThreadedRenderer.sRendererDisabled
                    || (ThreadedRenderer.sSystemRendererDisabled && forceHwAccelerated)) {
                mAttachInfo.mThreadedRenderer = ThreadedRenderer.create(mContext, translucent,
                        attrs.getTitle().toString());
            }
            ...
        }
        ...
    }

开启硬件加速后,会启一个名为RenderThread的线程,RenderThread线程会创建一个EglManager对象,EglManager用于调用OpenGL ES的API函数,如eglCreateWindowSurface创建一个EglSurface对象,不同厂商的实现不一样。

二、EglSurface

EglSurface的创建.jpg

Android使用OpenGL ES(GLES)的API渲染图形。为了创建GLES上下文并为GLES渲染提供窗口系统,Android使用EGL库。在使用 GLES 进行绘制之前,需要创建 GL上下文。在 EGL中,这意味着要创建一个 EGLContext和一个 EGLSurface。 EGLSurface可以是由EGL分配的离屏缓冲区,也可以是由操作系统分配的窗口。调用 eglCreateWindowSurface() 函数可创建EGL窗口Surface,并将其连接到窗口对象的 BufferQueue 的生产方接口。eglCreateWindowSurface() 将“窗口对象”作为参数,在 Android 上,该对象是 Surface。

三、构建DisplayList

构建DisplayList.jpg

其实这部分的工作是在主线程完成,而不是RenderThread线程,在此进行说明是为了更好的梳理RenderThread线程的工作。
Activity的绘制流程(二)Choreographer中讲到了应用接收到Vsync后,向主线程发送一个异步消息,在主线程中执行Choreographer的doFrame函数,一一处理CallbackQueue数组中保存的操作,其中CALLBACK_TRAVERSAL会向WMS请求重新布局该窗口,同时还会对窗口进行测量、布局、绘制。其中绘制就是递归DecorView为根的View树,构建或更新DisplayList。DisplayList主要包含两个重要的对象,一个是deque队列mChildNodes,View对应一个RenderNode,RenderNode被封装在一个RenderNodeDrawable对象中,并加入到该队列,该队列用于后续同步时取得保存的子RenderNode。另一个是DisplayListData对象mDisplayList,该对象中保存了各个Op,一个Op代表一个绘制操作。

四、同步DisplayList

同步DisplayList.jpg

当主线构建或更新DisplayList完毕后,会进入睡眠等待RenderThread线程同步DisplayList,当同步完成后再唤醒主线程。
在同步时,会调度到DisplayList中每个RenderNode上,将RenderNode的mStagingProperties和mStagingDisplayList保存到mProperties和mDisplayList上。mStagingProperties在三、构建DisplayList中调用RenderNode的setStagingDisplayList函数设置。


设置透明度.jpg

而mStagingDisplayList的设置这里以设置透明度举例,调用RenderNode的mutateStagingProperties函数拿到的便是mStagingProperties,将透明度设置到mStagingProperties中。
同步还会判断若UI线程注册动画到Render线程,则由Render线程进行动画的计算和绘制。同步时发现View被设置为LAYER_TYPE_HARDWARE,则会将View转变成一个Layer进行绘制,在GPU上有一个帧缓冲区,不会每一帧都去销毁和重建离屏渲染buffer。

五、绘制

绘制.jpg

RenderThread线程同步了DisplayList后,RenderThread线程会从Surface对应的图形缓冲区队列BufferQueue中申请一块图形缓冲区GraphicBuffer进行绘制,将DisplayList中的各个绘制操作填充进去,最后将该GraphicBuffer放回队列中。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。