Android4.4 browser 渲染架构分析
发布日期:2021-11-09 22:50:33 浏览次数:5 分类:技术文章

本文共 4335 字,大约阅读时间需要 14 分钟。

Android4.4 browser 渲染架构分析

1. 整体分析

Android4.4browser与之前版本最大的不同就是在保持webview控件接口不变的情况下,将内核换成了chromium32。随之,它的硬件加速渲染架构也与之前版本和chromium本身都有一定差别,相当于androidbrowser与chromium的一个融合。

它们都使用chromium的核心,直观来看最大的区别在于,android4.4使用webview来显示网页,而chromium使用surfaceview来显示网页。

仅仅是两个用来显示网页的控件不同,会造成什么区别呢?大家知道SurfaceView是一个比较特别的控件。一是,它允许用户自己来控制渲染,而不必受到androidview系统的限制;二是,它独立的与surfaceflinger交互,并可以方便的得到交互客户端ANativeWindow。基于这两点,chromium使用SurfaceView后完全能够自由发挥,而与androidView系统隔离开来。所以它的硬件加速绘制完全与系统无关,要说有关系的话,那就是它的绘制结果直接以opengl的形式绘制在ANativeWindow与surfaceflinger关联的共享内存上。这个过程可以参见我之前的文档《深入理解surface系统》

而webview则不同,它是一个普通的view控件,我们对它的定制只能重写其onDraw函数。而内容也必须绘制到onDraw的传入参数提供的canvas上。当启用硬件加速时,传入的canvas为GLES20Canvas。这就与android系统的硬件加速部分相关了。

Chromium对于系统来说是一个纯粹的第三方应用,它只是使用了SurfaceView控件来显示内容。Android4.4browser则是一个系统组件,它担负了WebView控件本身的实现。

下面我们分别来分析一下chromium和android4.4browser的渲染流程,特别关注它们与系统相关的部分。先从较熟悉的chromium说起。

2. chromium31渲染流程分析

下图描述的是chromium31的大致渲染流程,比之chromium24有了较大的不同。但一些基本的设计没有改变。我们这里说chromium31的渲染流程实际上指的是SurfaceView所包含的网页内容的渲染流程,这部分的渲染是完全由chromium这个第三方的应用来进行的,与系统的关联很少。

由于缺少chromium关于该部分的顶层设计文档,并且也并非这方面的专业人士。所以对渲染流程的很多地方还有疑问,不清楚,甚至看不懂的地方。受时间,精力,能力所限只能给出一个大致的渲染流程和一些个人理解。

大体说一下这几个步骤。

第一步,webkit绘制。这一步是webkit在接收到网页数据后自发进行的。在不同的平台需要重载GraphicsLayer类来实现各自的绘制。在chromium31中是将绘制步骤放到SkPicture中存储。

第二步,CC线程会将SkPicture中存储的绘制绘制步骤真正执行,生成SkBitmap。(注:图中CC线程与impl线程是指同一个线程)将真正绘制的任务放在CC线程也是为了减轻webkit线程的负担,使其能更快响应请求。

第三步,合成SkBitmap后CC还要进行一些处理。比如同步两个线程的layer树结构,划分tile等。

第四步,开始请求GPU将SkBitmap渲染程opengl纹理,这个过程现在需要垂直同步信号来驱动。当然光有这个信号还不够,还需要配合CC内部状态机来决定是否进行。

第五步,绘制到TextureImageTransportSurface,该surface对应于一个内存中的离线framebuffer。而真正的目标framebuffer(实际上它也不是系统帧缓冲)在存在主线程和GPU之间的PassThroughImageTransportSurface。如下图:

第六步,render进程的渲染工作已经完成,给主进程发送信号,让主进程进行下一步操作

第七步,这一步没有太理解,但其中一个重要的步骤是获得TextureImageTransportSurface的内容。

第八步,现在实际内容已经在PassThroughImageTransportSurface,该surface连接的时间内存是surfaceflinger的一块共享内存。主线程处理后向GPU发送消息

第九步,GPU调用swapbuffer,将绘制上内容的buffer交给surfaceflinger处理。

现在我们关注一下整个渲染过程与系统相关的部分,实际上就是一个ANativewindow。该对象有两个身份:一是,该对象随着SurfaceView而创建的,用来与surfaceflinger交互,它属于SurfaceView。二是,该对象又被chromium得到(有相关接口),并且作为chromium绘制的本地窗口。这样就相当于chromium直接向surfaceflinger的一块共享内存填充数据,然后交给surfaceflinger处理。

Chromium使用eglCreateWindowSurface来与ANativewindow关联,使用EGL的一套机制来建立渲染平台,以便绘制。详细内容可见《深入理解surface系统》。

3. android4.4browser渲染流程分析

androidbrowser与chromium不同,它算是一个系统级的应用(而不是一个第三方应用),因为它负责系统控件webview的实现。所以说起它的渲染,我们就从androidview系统draw函数的调用根源说起。如下图所示,列出了从view系统内部performTraversals函数发起渲染动作开始,一直到我们所关心的webview调用onDraw来绘制自己。这个onDraw函数自然由browser来实现。

在上图中有一个分支,即软件渲染和硬件渲染会产生不同的canvas,之后view的绘制都是基于该canvas的。软件渲染的canvas产生我们比较清楚,lockCanvas函数最终会去申请SurfaceFlinger与Surface之间共享内存管理类BufferQueue的一块内存,并将这块内存作为该canvas的bitmap。这样canvas绘制的内容实际上是直接绘制在BufferQueue管理的一块共享内存上。然后SurfaceFlinger再进行合成处理。对于这个过程不清楚的同学可以翻看之前的文档《深入理解Surface系统》。

再来看看硬件渲染分支做了什么事情,HardwareRenderer的真正实现类是GlRenderer。在它初始化的时候会初始化EGL,创建绘图表面Surface并创建画布GLES20Canvas。在创建Surface时会调用eglCreateWindowSurface函数。这个函数会熟悉,在介绍chromium的渲染流程时已经介绍过。

大家可能已经猜到,chromium和androidbrowser同样使用EGL的方式与surfaceflinger的共享内存(GraphicsBuffer)相关联。区别是,chromium需要自己完成EGL渲染平台相关工作,它的SurfaceView对应的是一块完整的内存(GraphicsBuffer)。Androidbrowser的EGL相关工作由系统代劳了,它的整个界面对应于一块内存,所以WebView只是其中的一部分。

到了webview::onDraw函数,下面的过程就需要我们browser自己来实现了。下图是browser内部的调用流程。可以看到根据传入的canvas是否支持硬件加速,browser也走了不同的渲染流程(注意虽然整个browser使用的是同一块canvas,但canvas传递到webview已经进行了裁剪,以适应webview的尺寸)。我们这里关注硬件加速的渲染流程,可以看到最终调用了某个函数,这个函数是在DrawGLFunctor类中得到的。

这个渲染函数是怎么得到的呢,我们继续看下图:DrawGLFunctor最终得到的函数又是由getStatics函数经过一系列调用设置进去的。

最终,我们在下面这个流程中找到了渲染函数,就是InProcessViewRenderer::DrawGL函数。

这里需要说明一下,android系统硬件加速有一个DisplayList机制,就是说当GUI框架接收到View重绘的请求后,框架跟之前一样,回调View的onDraw方法,并传入一个Canvas,但是跟之前不同的是,这个Canvas只是用于记录View的绘图指令到View本身的DisplayList中,并没有真正执行。

当整个View的DisplayList树都更新完毕后,框架就会执行该DisplayList树,所谓执行,实际上就是把缓存的2DCanvas绘图指令转换成OpenGL的方法来执行。

DisplayList中可以嵌入Functor,Functor是一个用于回调的函数子,DisplayList把嵌入的Functor也当作一条绘图指令缓存起来

也就是说上述的DrawGL函数会被当做一条绘图指令缓存起来,这个绘图指令的作用就是绘制webview的内容。

可见,渲染流程应该还是遵循chromium的固有流程,具体实现有所不同。

4. 总结

Chromium31使用了交换缓冲方式渲染,由EGL作为opengles与系统本地窗口之间的接口,使用openges来直接绘制到系统本地窗口ANativeWindow上。

android browser从总体来看也使用相同的交互缓冲方式渲染,但EGL相关部分由系统来完成。它的chromium核心的作用是完成webview的渲染,使用了FBO扩展机制,来实现渲染到纹理。它没有使用EGL,也没有本地窗口等概念(对于webview来说)。所以两者同样使用了chromium的核心,但chromium核心的功能有所差别,渲染方式也并不相同。

如上图所示由于SurfaceView所对应的GraphicsBuffer应用可以直接获得(通过ANativeWindow)所以browser可以为其单独建立渲染环境。而WebView不能够单独渲染,所以browser要做的就是将webview的渲染命令嵌入到系统的DisplayList中,其他任务就由系统来完成。

转载地址:https://blog.csdn.net/Danlinan/article/details/38896395 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:web.py学习记录
下一篇:关于Android的DEX文件

发表评论

最新留言

感谢大佬
[***.8.128.20]2024年04月05日 08时11分04秒