AndroidWebView硬件加速渲染⽹页UI的过程分析
WebView作为App UI的⼀部分,当App UI以硬件加速⽅式渲染时,它也是以硬件加速⽅式渲染的。Android WebView的UI来⾃于⽹页,是通过Chromium渲染的。Chromium渲染⽹页UI的机制与Android App渲染UI的机制是不⼀样的。不过,它们会⼀起协作完成⽹页UI的渲染。本⽂接下来就详细分析Android WebView硬件加速渲染⽹页UI的过程。
从前⾯这个系列的⽂章可以知道,Android App在渲染UI⼀帧的过程中,经历以下三个阶段:
1. 在UI线程中构建⼀个Display List,这个Display List包含了每⼀个View的绘制命令。
2. 将前⾯构建的Display List同步给Render Thread。
3. Render Thread对同步得到的Display List进⾏渲染,也就是使⽤GPU执⾏Display List的绘制命令。
上述三个阶段如果能够在16ms内完成,那么App的UI给⽤户的感受就是流畅的。为了尽量地在16ms内渲染完成App的⼀帧UI,Android使⽤了以上⽅式对App的UI进⾏渲染。这种渲染机制的好处是UI线程和Render Thread可以并发执⾏,也就是Render Thread在渲染当前帧的Display List的时候,UI线程可以准备下⼀帧的Display List。它们唯⼀需要同步的地⽅发⽣第⼆阶段。不过,这个阶段是可以很快完成的。因此,UI线程和Render Thread可以认为是并发执⾏的。
Android WebView既然是App UI的⼀部分,也就是其中的⼀个View,它的渲染也是按照上述三个阶段进⾏的,如下所⽰:
网页app图1 Android WebView硬件加速渲染⽹页UI的过程
在第⼀阶段,Android WebView会对Render端的CC Layer Tree进⾏绘制。这个CC Layer Tree描述的就是⽹页的UI,它会通过⼀个Synchronous Compositor绘制在⼀个Synchronous Compositor Output Surface上,最终得到⼀个Compositor Frame。这个Compositor Frame会保存在⼀个SharedRendererState对象中。
在第⼆阶段,保存在上述SharedRendererState对象中的Compositor Frame会同步给Android WebView会对Browser端的CC Layer Tree。Browser端的CC Layer Tree只有两个节点。⼀个是根节点,另⼀个是根节点的⼦节点,称为⼀个Delegated Renderer Layer。Render端绘制出来的Compositor Frame就是作为这个Delegated Renderer Layer的输⼊的。
在第三阶段,Android WebView会通过⼀个Hardware Renderer将Browser端的CC Layer Tree渲染在⼀个Parent Output Surface上,实际上就是通过GPU命令将Render端绘制出来的UI合成显⽰在App的UI窗⼝中。
接下来,我们就按照以上三个阶段分析Android WebView硬件加速渲染⽹页UI的过程。
从前⾯⼀⽂可以知道,在App渲染UI的第⼀阶段,Android WebView的成员函数onDraw会被调⽤。从前
⾯⼀⽂⼜可以知道,Android WebView在Native层有⼀个BrowserViewRenderer对象。当Android WebView的成员函数onDraw被调⽤时,并且App的UI以硬件加速⽅式渲染时,这个Native层BrowserViewRenderer对象的成员函数OnDrawHardware会被调⽤,如下所⽰:
[cpp]
1. bool BrowserViewRenderer::OnDrawHardware(jobject java_canvas) {
2.  ......
3.
4.  scoped_ptr<DrawGLInput> draw_gl_input(new DrawGLInput);
5.  ......
6.
7.  scoped_ptr<cc::CompositorFrame> frame =
8.      compositor_->DemandDrawHw(surface_size,
9.                                gfx::Transform(),
10.                                viewport,
11.                                clip,
12.                                viewport_rect_for_tile_priority,
13.                                transform_for_tile_priority);
14.  ......
15.
16.  frame->AssignTo(&draw_gl_input->frame);
17.  ......
18.  shared_renderer_state_->SetDrawGLInput(draw_gl_input.Pass());
19.
20.  ......
21.  return client_->RequestDrawGL(java_canvas, false);
22. }
这个函数定义在⽂件external/chromium_org/android_webview/browser/browser_中。
从前⾯⼀⽂可以知道,BrowserViewRenderer类的成员变量compositor_指向的是⼀个SynchronousCompositorImpl对象。BrowserViewRenderer对象的成员函数OnDrawHardware会调⽤这个SynchronousCompositorImpl对象的成员函数DemandDrawHw对⽹页的UI进⾏绘制。
绘制的结果是得到⼀个Compositor Frame。这个Compositor Frame会保存在⼀个DrawGLInput对象中。这个DrawGLInput对象⼜会保存在BrowserViewRenderer类的成员变量shared_renderer_state_指向的⼀个SharedRendererState对象中。这是通过调⽤SharedRendererState类的成员函数SetDrawGLInput实现的。
BrowserViewRenderer类的成员变量client_指向的是⼀个AwContents对象。BrowserViewRenderer对象的成员函数OnDrawHardware最后会调⽤这个AwContents对象的成员函数RequestDrawGL请求在参数java_canvas描述的⼀个Hardware Canvas中增加⼀个DrawFunctorOp操作。这个DrawFunctorOp操作
最终会包含在App的UI线程构建的Display List中。
接下来,我们⾸先分析SynchronousCompositorImpl类的成员函数DemandDrawHw绘制⽹页的UI的过程,如下所⽰:
[cpp]
1. scoped_ptr<cc::CompositorFrame> SynchronousCompositorImpl::DemandDrawHw(
2.    gfx::Size surface_size,
3.    const gfx::Transform& transform,
4.    gfx::Rect viewport,
5.    gfx::Rect clip,
6.    gfx::Rect viewport_rect_for_tile_priority,
7.    const gfx::Transform& transform_for_tile_priority) {
8.  ......
9.
10.  scoped_ptr<cc::CompositorFrame> frame =
11.      output_surface_->DemandDrawHw(surface_size,
12.                                    transform,
13.                                    viewport,
14.                                    clip,
15.                                    viewport_rect_for_tile_priority,
16.                                    transform_for_tile_priority);
17.  ......
18.  return frame.Pass();
19. }
这个函数定义在⽂件external/chromium_org/content/browser/android/in_process/synchronous_中。
从前⾯⼀⽂可以知道,SynchronousCompositorImpl类的成员变量output_surface_指向的是⼀个SynchronousCompositorOutputSurface对象。SynchronousCompositorImpl类的成员函数DemandDrawHw调⽤这个SynchronousCompositorOutputSurface对象的成员函数DemandDrawHw绘制⽹页的UI,如下所⽰:
[cpp]
1. scoped_ptr<cc::CompositorFrame>
2. SynchronousCompositorOutputSurface::DemandDrawHw(
3.    gfx::Size surface_size,
4.    const gfx::Transform& transform,
5.    gfx::Rect viewport,
6.    gfx::Rect clip,
7.    gfx::Rect viewport_rect_for_tile_priority,
8.    const gfx::Transform& transform_for_tile_priority) {
9.  ......
10.
11.  InvokeComposite(transform,
12.                  viewport,
13.                  clip,
14.                  viewport_rect_for_tile_priority,
15.                  transform_for_tile_priority,
16.                  true);
17.
18.  return frame_holder_.Pass();
19. }
这个函数定义在⽂件external/chromium_org/content/browser/android/in_process/synchronous_compositor_中。
SynchronousCompositorOutputSurface类的成员函数DemandDrawHw调⽤另外⼀个成员函数InvokeComposite绘制⽹页的UI。绘制完成后,就会得到⼀个Compositor Frame。这个Compositor Frame保存在SynchronousCompositorOutputSurface类的成员变量frame_holder_中。因
此,SynchronousCompositorOutputSurface类的成员函数DemandDrawHw可以将这个成员变量frame_holder_指向的Compositor Frame返回给调⽤者。
SynchronousCompositorOutputSurface类的成员函数InvokeComposite的实现如下所⽰:
[cpp]
1. void SynchronousCompositorOutputSurface::InvokeComposite(
2.    const gfx::Transform& transform,
3.    gfx::Rect viewport,
4.    gfx::Rect clip,
5.    gfx::Rect viewport_rect_for_tile_priority,
6.    gfx::Transform transform_for_tile_priority,
7.    bool hardware_draw) {
8.  ......
9.
10.  client_->BeginFrame(cc::BeginFrameArgs::CreateForSynchronousCompositor());
11.
12.  ......
13. }
这个函数定义在⽂件external/chromium_org/content/browser/android/in_process/synchronous_compositor_中。
SynchronousCompositorOutputSurface类的成员变量client_是从⽗类OutputSurface继承下来的。从前⾯⼀⽂可以知道,它指向的是⼀个LayerTreeHostImpl对象。SynchronousCompositorOutputSurface类的成员函数InvokeComposite调⽤这个LayerTreeHostImpl对象的成员函数BeginFrame绘制⽹页的UI。
从前⾯⼀⽂可以知道,当LayerTreeHostImpl类的成员函数BeginFrame被调⽤时,它就会CC模块的调度器执⾏⼀个BEGIN_IMPL_FRAME操作,也就是对⽹页的CC Layer Tree进⾏绘制。绘制的过程可以参考、和这三篇⽂章。
由于Android WebView的Render端使⽤的是Synchronous Compositor,当前线程(也就是App的UI线程)会等待Render端的Compositor线程绘制完成⽹页的CC Layer Tree。从前⾯⼀⽂可以知道,Compositor线程在绘制完成⽹页的CC Layer Tree的时候,会调⽤⽹页的Output Surface的成员函数SwapBuffers。
在我们这个情景中,⽹页的Output Surface是⼀个Synchronous Compositor Output Surface。这意味着当Compositor线程在绘制完成⽹页的CC Layer Tree时,会调⽤SynchronousCompositorOutputSurface类的成员函数SwapBuffers,如下所⽰:
[cpp]
1. void SynchronousCompositorOutputSurface::SwapBuffers(
2.    cc::CompositorFrame* frame) {
3.  ......
4.
5.  frame_holder_.reset(new cc::CompositorFrame);
6.  frame->AssignTo(frame_holder_.get());
7.
8.  ......
9. }
这个函数定义在⽂件external/chromium_org/content/browser/android/in_process/synchronous_compositor_中。
参数frame指向的Compositor Frame描述的就是⽹页的绘制结果。从前⾯⼀⽂可以知道,这个Compositor Frame包含了⼀系列的Render Pass。每⼀个Render Pass都包含了若⼲个纹理,以及每⼀个纹理的绘制参数。这些纹理是在Render端光栅化⽹页时产⽣的。Browser端的Hardware Renderer所要做的事情就是将这些纹理渲染在屏幕上。这个过程也就是Browser端合成⽹页UI的过程。
SynchronousCompositorOutputSurface类的成员函数SwapBuffers会将参数frame描述的Compositor Frame的内容拷贝⼀份到⼀个新创建的Compositor Frame中去。这个新创建的Compositor Frame会保存在SynchronousCompositorOutputSurface类的成员变量frame_hodler_中。因此,前⾯分析的SynchronousCompositorOutputSurface类的成员函数InvokeComposite返回给调⽤者的就是当前绘制的⽹页的内容。
这⼀步执⾏完成后,回到前⾯分析的BrowserViewRenderer类的成员函数OnDrawHardware中,这时候它就获得了⼀个Render端绘制⽹页的结果,也就是⼀个Compositor Frame。这个Compositor Frame会
保存在⼀个DrawGLInput对象中。这个DrawGLInput对象⼜会保存在BrowserViewRenderer类的成员变量shared_renderer_state_指向的⼀个SharedRendererState对象中。这是通过调⽤SharedRendererState类的成员函数SetDrawGLInput实现的,如下所⽰:
[cpp]
1. void SharedRendererState::SetDrawGLInput(scoped_ptr<DrawGLInput> input) {
2.  ......
3.  draw_gl_input_ = input.Pass();
4. }
这个函数定义在⽂件external/chromium_org/android_webview/browser/shared_中。
SharedRendererState类的成员函数SetDrawGLInput将参数input指向的⼀个DrawGLInput对象保存成员变量draw_gl_input_中。
这⼀步执⾏完成后,再回到前⾯分析的BrowserViewRenderer类的成员函数OnDrawHardware中,接下
来它会调⽤成员变量client_指向的⼀个Native 层AwContents对象的成员函数RequestDrawGL请求在参数java_canvas描述的⼀个Hardware Canvas中增加⼀个DrawFunctorOp操作,如下所⽰:
[cpp]
1. bool AwContents::RequestDrawGL(jobject canvas, bool wait_for_completion) {
2.  ......
3.
4.  JNIEnv* env = AttachCurrentThread();
5.  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
6.  if (obj.is_null())
7.    return false;
8.  return Java_AwContents_requestDrawGL(
9.      env, obj.obj(), canvas, wait_for_completion);
10. }
这个函数定义在⽂件external/chromium_org/android_webview/native/中。
在前⾯⼀⽂中,我们已经分析过Native层AwContents类的成员函数RequestDrawGL的实现了,它主要就是调⽤层的AwContents类的成员函数requestDrawGL请求在参数canvas描述的Hardware Canvas中增加⼀个DrawFunctorOp操作。
Java层的AwContents类的成员函数requestDrawGL最终会调⽤到DrawGLFunctor类的成员函数requestDrawGL在参数canvas描述的Hardware Canvas中增加⼀个DrawFunctorOp操作,如下所⽰:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。