标签:chromium webview android l webgl
摘要:从Android KitKat系统第一个采用Chromium内核的WebView开始,Android WebView一直在持续演进中,自Chromium M38开始,WebView在硬件渲染模式方面发生了较大的变化,最明显的变化莫过于WebGL的支持以及ubercompositor的使用,同时为了吻合Android L的渲染模型变化,DrawGL函数是在Android系统的渲染线程中执行的。
对于Chromium WebView来说,首先它是单进程模型的,至少在使用CommandBuffer时可以省去不必要的跨进程IPC开销,尽管IPC开销并没有想象中那么大(根据性能评测,大概占了不超过5%的开销)。更为重要的是,WebView必须是Android窗口中一个普通的View,与窗口其他View共享同一个Android Surface绘制表面,因此,
Android 4.4系统中,在绘制View层次时,显示列表的更新记录以及重放都发生在UI线程上,相应地,WebView.onDraw事件的处理中,页面的层合成,以及通过DrawGL函数将合成的内容绘制到HardwareCanvas,都是在UI线程执行的。当WebView收到invalidate消息后,ViewRoot会遍历整个View树决定向哪些View派送onDraw事件,WebView响应onDraw事件时,会直接请求HardwareCanvas执行DrawGL回调函数,DrawGL再请求同步合成器以硬件加速方式合成新的一帧内容,并将这个新的内容通过GL命令绘制到HardwareCanvas上。这里没有特别提到Blink线程,原因是Blink线程相对来说还是比较独立的,在Blink线程启动后,会逐步执行DOM解析和排版,JS代码的执行,以及渲染层的状态信息计算等工作,这些工作运行完毕之后,如果Compositor内部状态机发现页面还需要继续更新内容,执行动画,Blink线程会通知UI线程(即Compositing线程)将WebView置为失效(invalidate)状态,继而触发onDraw事件,再把上述过程走一遍。具体过程可参考如下图示:
必要的解释:
这里还需要特别说明的是,Android 4.4系统中WebView是没有单独的GPU线程执行GL命令的,所有的一切都发生在UI线程上,导致很难再提供WebGL的支持了,就算是花些力气支持了WebGL,估计也是吃力不讨好,因为性能是个大问题,在UI线程上执行WebGL很可能导致UI根本不会有响应。
Chromium WebView的演进速度还是相当的快。从最新发布的Android L开发者预览版来看,在页面渲染的流水线和线程模型都有不少改进,如下图所示:
简单的来说,ubercompositor是一个大一统的合成器,不管Chromium系统中存在几个合成器,但最终的合成总是由一个称为Parent Compositor完成,其他的Compositor唯一要做的事情是将自己管理的GPU资源打包为CompositorFrame发送给Parent Compositor,由Parent Compositor根据CompositorFrame包含的RenderPass列表和元数据等,执行合成操作将最后的内容写到Native窗口上,当Parent Compositor完成合成操作,它会通知Child compositor可以执行资源的清理工作了,如下图所示:
为了吻合Android L引入的渲染线程(注:为了和Android系统的渲染线程作区分,Chromium的渲染线程称为Blink线程),将Chromium渲染流程无缝整合到Android L系统中,WebView新的架构中引入了两级合成器:
与Android 4.4系统不同的是,在Android L系统上WebView处理onDraw事件逻辑上可以分解为两个步骤:
注:关于DrawGL回调函数是如何分派到Android渲染线程上执行的,由于AndroidL的源代码尚未完全公开,还不能100%确定上述描述是否完全正确。从已有掌握的信息分析来看,UI线程会向HardwareCanvas发起DrawGL调用请求,此时可能不会立即执行DrawGL,而是作为drawOp先保存在HardwareCanvas中,当渲染线程开始重放HardwareCanvas显示列表时,再调用DrawGL。
上述两个步骤与Android L采用的渲染线程模型完全吻合,这也是要引入两级合成器的原因。AwContents::DrawGL是将Chromium图形系统整合到Android中的一个极其关键的方法,它是Android L渲染线程进入Chromium图形系统的唯一入口,DrawGL是在Android L在渲染线程为HardwareCanvas对象重放显示列表被调用的,而另一方面,Chromium只能被动地由渲染线程调用DrawGL操作,唯一能够获取的信息是当前HardwareCanvas后端的FBO对象,然后所有的内容都绘制到这个Canvas上,其他信息诸如消息队列,异步执行任务的能力,都难以获取,这就导致Chromium会在DrawGL中,只能一次性地将任务队列中所有的任务,例如等待SyncPoint,刷新CommandBuffer等,全部执行完毕,这也就是为什么下面提到的WebGL要在一个专门的GPU线程中执行的原因。
此外,WebView这个新型的渲染模型与Android4.4系统是不兼容的,也就是从AndroidL编译出来的libwebviewchromium.so是不能够在Android 4.4系统运行的。
以WebGL为例,WebView为渲染WebGL还创建 了专门的GPU线程,WebGL程序中所有的GL命令都发生在这个线程上。渲染WebGL的egl上下文就是这个线程上创建的,然而,这个egl上下文是一个独立的上下文,不与WebView进程内任何其他上下文共享资源,即与AndroidView系统的上下文不在同一个share group。关于Chromium中上下文和share group相关技术细节,可参阅ChromiumGraphics: 3D上下文及其虚拟化一文。Android View系统的上下文指的是调用DrawGL绘制HardwareCanvas时的上下文,因此,要将WebGL的内容绘制到HardwareCanvas上,需要解决将WebGL上下文和AndroidView系统上下文之间的texture共享和同步问题。首先,这两个上下文都属于同一进程,因此可以利用EGLImage进行跨线程的texture共享,再次,Chromium图形栈提供的信箱texture(mailbox texture)机制有助于解决texture共享。Mailbox texture机制为每个生成的texture生成一个64字节的唯一名字,并建立名字到texture id的全局映射表,所以不管在哪个上下文创建的texture,都可以通过mailbox的名字检索到对应的texture id,mailbox机制的好处就是在一个支持多上下文的环境提供了textureid的全局别名系统,换句话说,有了这个别名系统,所有上下文看起来都属于“同一个share group”。
那么,渲染WebGL是如何使用EGLImage和mailbox texture机制实现资源共享的呢?
Chromium中WebGL的内容是通过离屏的framebuffer对象渲染到texture中的,在GPU线程的WebGL上下文创建这个texture时将其绑定一个唯一的mailbox名字,还会调用eglCreateImageKHR为这个texture id创建一个可以被其他上下文共享的EGLImage,当AndroidView系统的渲染线程在另一个上下文中执行DrawGL函数,通过mailbox名字可确定GPU线程中的EGLImage,将其绑定到该上下文的一个texture便可以直接使用WebGL上下文的texture了,至此解决了texture共享问题。这里还有一个问题需要交代一下,在多个上下文中共享texture时,必须处理好生产者和消费者之间的同步问题,即执行DrawGL函数绘制新的一帧时,要确保WebGL上下文的所有GL命令都已经执行完毕。Chromium同样提供了一套同步点(syncpoint)机制,来保证多个上下文(Chromium里也称CommandBuffer)之间GL命令的执行次序,在上下文A中插入一个同步点,然后在上下文B中等待这个同步点,可以保证上下文B中的GL命令必须等待上下文同步点A之前所有的GL命令全部执行完毕之后,才能开始执行。
所以,当WebGL将新的一帧内容生成完毕后,会插入一个同步点,而DrawGL时AndroidView系统上下文会等待这个同步点,只有当前WebGL所有GL命令都提交给GPU驱动之后,才开始使用WebGL的内容,从而保证了WebGL内容和DrawGL的同步。关于同步点机制的细节,请参阅ChromiumGraphics: GPU客户端之间同步机制的原理和实现分析一文。
WebView Shell构建在核心类AwContents之上,AwContents在功能基本上可以等同于android.webkit.WebView类。Chromium M30的代码库中只能编译出仅支持软件渲染模式的WebViewShell,从Chromium M38开始,WebView Shell也支持硬件加速渲染了,主要改进的地方是,使用GLSurfaceView作为最后的渲染目的地,如上所述,DrawGL回调函数可以在非UI线程上调用,而GLSurfaceView正好也内建性地支持在单独的线程中被渲染。
Chromium Graphics: 再谈Chromium WebView硬件渲染模式的演进
标签:chromium webview android l webgl
原文地址:http://blog.csdn.net/hongbomin/article/details/40896313