Activity的绘制流程(五)

上一篇讲了Activity的绘制流程(四)Surface
//www.greatytc.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放回队列中。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,265评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,078评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,852评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,408评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,445评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,772评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,921评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,688评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,130评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,467评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,617评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,276评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,882评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,740评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,967评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,315评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,486评论 2 348