Android WebView硬件加速渲染网页UI的过程分析

Nicy 8年前
   <p>Android WebView作为App UI的一部分,当App UI以硬件加速方式渲染时,它也是以硬件加速方式渲染的。Android WebView的UI来自于网页,是通过Chromium渲染的。Chromium渲染网页UI的机制与Android App渲染UI的机制是不一样的。不过,它们会一起协作完成网页UI的渲染。本文接下来就详细分析Android WebView硬件加速渲染网页UI的过程。</p>    <p>从前面 Android应用程序UI硬件加速渲染技术简要介绍和学习计划 这个系列的文章可以知道,Android App在渲染UI一帧的过程中,经历以下三个阶段:</p>    <p>1. 在UI线程中构建一个Display List,这个Display List包含了每一个View的绘制命令。</p>    <p>2. 将前面构建的Display List同步给Render Thread。</p>    <p>3. Render Thread对同步得到的Display List进行渲染,也就是使用GPU执行Display List的绘制命令。</p>    <p>上述三个阶段如果能够在16ms内完成,那么App的UI给用户的感受就是流畅的。为了尽量地在16ms内渲染完成App的一帧UI,Android使用了以上方式对App的UI进行渲染。这种渲染机制的好处是UI线程和Render Thread可以并发执行,也就是Render Thread在渲染当前帧的Display List的时候,UI线程可以准备下一帧的Display List。它们唯一需要同步的地方发生第二阶段。不过,这个阶段是可以很快完成的。因此,UI线程和Render Thread可以认为是并发执行的。</p>    <p>Android WebView既然是App UI的一部分,也就是其中的一个View,它的渲染也是按照上述三个阶段进行的,如下所示:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/124d8502a66fbf0f4eb41a93b52ab087.png"></p>    <p>图1 Android WebView硬件加速渲染网页UI的过程</p>    <p>在第一阶段,Android WebView会对Render端的CC Layer Tree进行绘制。这个CC Layer Tree描述的就是网页的UI,它会通过一个Synchronous Compositor绘制在一个Synchronous Compositor Output Surface上,最终得到一个Compositor Frame。这个Compositor Frame会保存在一个SharedRendererState对象中。</p>    <p>在第二阶段,保存在上述SharedRendererState对象中的Compositor Frame会同步给Android WebView会对Browser端的CC Layer Tree。Browser端的CC Layer Tree只有两个节点。一个是根节点,另一个是根节点的子节点,称为一个Delegated Renderer Layer。Render端绘制出来的Compositor Frame就是作为这个Delegated Renderer Layer的输入的。</p>    <p>在第三阶段,Android WebView会通过一个Hardware Renderer将Browser端的CC Layer Tree渲染在一个Parent Output Surface上,实际上就是通过GPU命令将Render端绘制出来的UI合成显示在App的UI窗口中。</p>    <p>接下来,我们就按照以上三个阶段分析Android WebView硬件加速渲染网页UI的过程。</p>    <p>从前面 Android应用程序UI硬件加速渲染的Display List构建过程分析 一文可以知道,在App渲染UI的第一阶段,Android WebView的成员函数onDraw会被调用。从前面 Android WebView执行GPU命令的过程分析 一文又可以知道,Android WebView在Native层有一个BrowserViewRenderer对象。当Android WebView的成员函数onDraw被调用时,并且App的UI以硬件加速方式渲染时,这个Native层BrowserViewRenderer对象的成员函数OnDrawHardware会被调用,如下所示:</p>    <pre>  <code class="language-java">bool BrowserViewRenderer::OnDrawHardware(jobject java_canvas) {       ......          scoped_ptr<DrawGLInput> draw_gl_input(new DrawGLInput);      ......          scoped_ptr<cc::CompositorFrame> frame =          compositor_->DemandDrawHw(surface_size,                                    gfx::Transform(),                                    viewport,                                    clip,                                    viewport_rect_for_tile_priority,                                    transform_for_tile_priority);      ......        frame->AssignTo(&draw_gl_input->frame);    ......    shared_renderer_state_->SetDrawGLInput(draw_gl_input.Pass());        ......      return client_->RequestDrawGL(java_canvas, false);    }</code></pre>    <p>这个函数定义在文件external/chromium_org/android_webview/browser/browser_view_renderer.cc中。</p>    <p>从前面 Android WebView执行GPU命令的过程分析 一文可以知道,BrowserViewRenderer类的成员变量compositor_指向的是一个SynchronousCompositorImpl对象。BrowserViewRenderer对象的成员函数OnDrawHardware会调用这个SynchronousCompositorImpl对象的成员函数DemandDrawHw对网页的UI进行绘制。</p>    <p>绘制的结果是得到一个Compositor Frame。这个Compositor Frame会保存在一个DrawGLInput对象中。这个DrawGLInput对象又会保存在BrowserViewRenderer类的成员变量shared_renderer_state_指向的一个SharedRendererState对象中。这是通过调用SharedRendererState类的成员函数SetDrawGLInput实现的。</p>    <p>BrowserViewRenderer类的成员变量client_指向的是一个AwContents对象。BrowserViewRenderer对象的成员函数OnDrawHardware最后会调用这个AwContents对象的成员函数RequestDrawGL请求在参数java_canvas描述的一个Hardware Canvas中增加一个DrawFunctorOp操作。这个DrawFunctorOp操作最终会包含在App的UI线程构建的Display List中。</p>    <p>接下来,我们首先分析SynchronousCompositorImpl类的成员函数DemandDrawHw绘制网页的UI的过程,如下所示:</p>    <pre>  <code class="language-java">scoped_ptr<cc::CompositorFrame> SynchronousCompositorImpl::DemandDrawHw(      gfx::Size surface_size,      const gfx::Transform& transform,      gfx::Rect viewport,      gfx::Rect clip,      gfx::Rect viewport_rect_for_tile_priority,      const gfx::Transform& transform_for_tile_priority) {    ......      scoped_ptr<cc::CompositorFrame> frame =        output_surface_->DemandDrawHw(surface_size,                                      transform,                                      viewport,                                      clip,                                      viewport_rect_for_tile_priority,                                      transform_for_tile_priority);    ......    return frame.Pass();  }</code></pre>    <p>这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_impl.cc中。</p>    <p>从前面 Android WebView执行GPU命令的过程分析 一文可以知道,SynchronousCompositorImpl类的成员变量output_surface_指向的是一个SynchronousCompositorOutputSurface对象。SynchronousCompositorImpl类的成员函数DemandDrawHw调用这个SynchronousCompositorOutputSurface对象的成员函数DemandDrawHw绘制网页的UI,如下所示:</p>    <pre>  <code class="language-java">scoped_ptr<cc::CompositorFrame>  SynchronousCompositorOutputSurface::DemandDrawHw(      gfx::Size surface_size,      const gfx::Transform& transform,      gfx::Rect viewport,      gfx::Rect clip,      gfx::Rect viewport_rect_for_tile_priority,      const gfx::Transform& transform_for_tile_priority) {    ......      InvokeComposite(transform,                    viewport,                    clip,                    viewport_rect_for_tile_priority,                    transform_for_tile_priority,                    true);      return frame_holder_.Pass();  }</code></pre>    <p>这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_output_surface.cc中。</p>    <p>SynchronousCompositorOutputSurface类的成员函数DemandDrawHw调用另外一个成员函数InvokeComposite绘制网页的UI。绘制完成后,就会得到一个Compositor Frame。这个Compositor Frame保存在SynchronousCompositorOutputSurface类的成员变量frame_holder_中。因此,SynchronousCompositorOutputSurface类的成员函数DemandDrawHw可以将这个成员变量frame_holder_指向的Compositor Frame返回给调用者。</p>    <p>SynchronousCompositorOutputSurface类的成员函数InvokeComposite的实现如下所示:</p>    <pre>  <code class="language-java">void SynchronousCompositorOutputSurface::InvokeComposite(      const gfx::Transform& transform,      gfx::Rect viewport,      gfx::Rect clip,      gfx::Rect viewport_rect_for_tile_priority,      gfx::Transform transform_for_tile_priority,      bool hardware_draw) {    ......      client_->BeginFrame(cc::BeginFrameArgs::CreateForSynchronousCompositor());      ......  }</code></pre>    <p>这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_output_surface.cc中。</p>    <p>SynchronousCompositorOutputSurface类的成员变量client_是从父类OutputSurface继承下来的。从前面 Chromium网页绘图表面(Output Surface)创建过程分析 一文可以知道,它指向的是一个LayerTreeHostImpl对象。SynchronousCompositorOutputSurface类的成员函数InvokeComposite调用这个LayerTreeHostImpl对象的成员函数BeginFrame绘制网页的UI。 </p>    <p>从前面 Chromium网页渲染调度器(Scheduler)实现分析 一文可以知道,当LayerTreeHostImpl类的成员函数BeginFrame被调用时,它就会CC模块的调度器执行一个BEGIN_IMPL_FRAME操作,也就是对网页的CC Layer Tree进行绘制。绘制的过程可以参考 Chromium网页Layer Tree绘制过程分析 、 Chromium网页Layer Tree同步为Pending Layer Tree的过程分析 和 Chromium网页Pending Layer Tree激活为Active Layer Tree的过程分析 这三篇文章。</p>    <p>由于Android WebView的Render端使用的是Synchronous Compositor,当前线程(也就是App的UI线程)会等待Render端的Compositor线程绘制完成网页的CC Layer Tree。从前面 Chromium硬件加速渲染的UI合成过程分析 一文可以知道,Compositor线程在绘制完成网页的CC Layer Tree的时候,会调用网页的Output Surface的成员函数SwapBuffers。</p>    <p>在我们这个情景中,网页的Output Surface是一个Synchronous Compositor Output Surface。这意味着当Compositor线程在绘制完成网页的CC Layer Tree时,会调用SynchronousCompositorOutputSurface类的成员函数SwapBuffers,如下所示:</p>    <pre>  <code class="language-java">void SynchronousCompositorOutputSurface::SwapBuffers(      cc::CompositorFrame* frame) {    ......      frame_holder_.reset(new cc::CompositorFrame);    frame->AssignTo(frame_holder_.get());      ......  }</code></pre>    <p>这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_output_surface.cc中。</p>    <p>参数frame指向的Compositor Frame描述的就是网页的绘制结果。从前面 Chromium硬件加速渲染的UI合成过程分析 一文可以知道,这个Compositor Frame包含了一系列的Render Pass。每一个Render Pass都包含了若干个纹理,以及每一个纹理的绘制参数。这些纹理是在Render端光栅化网页时产生的。Browser端的Hardware Renderer所要做的事情就是将这些纹理渲染在屏幕上。这个过程也就是Browser端合成网页UI的过程。</p>    <p>SynchronousCompositorOutputSurface类的成员函数SwapBuffers会将参数frame描述的Compositor Frame的内容拷贝一份到一个新创建的Compositor Frame中去。这个新创建的Compositor Frame会保存在SynchronousCompositorOutputSurface类的成员变量frame_hodler_中。因此,前面分析的SynchronousCompositorOutputSurface类的成员函数InvokeComposite返回给调用者的就是当前绘制的网页的内容。</p>    <p>这一步执行完成后,回到前面分析的BrowserViewRenderer类的成员函数OnDrawHardware中,这时候它就获得了一个Render端绘制网页的结果,也就是一个Compositor Frame。这个Compositor Frame会保存在一个DrawGLInput对象中。这个DrawGLInput对象又会保存在BrowserViewRenderer类的成员变量shared_renderer_state_指向的一个SharedRendererState对象中。这是通过调用SharedRendererState类的成员函数SetDrawGLInput实现的,如下所示:</p>    <pre>  <code class="language-java">void SharedRendererState::SetDrawGLInput(scoped_ptr<DrawGLInput> input) {    ......    draw_gl_input_ = input.Pass();  }</code></pre>    <p>这个函数定义在文件external/chromium_org/android_webview/browser/shared_renderer_state.cc中。</p>    <p>SharedRendererState类的成员函数SetDrawGLInput将参数input指向的一个DrawGLInput对象保存成员变量draw_gl_input_中。</p>    <p>这一步执行完成后,再回到前面分析的BrowserViewRenderer类的成员函数OnDrawHardware中,接下来它会调用成员变量client_指向的一个Native层AwContents对象的成员函数RequestDrawGL请求在参数java_canvas描述的一个Hardware Canvas中增加一个DrawFunctorOp操作,如下所示:</p>    <pre>  <code class="language-java">bool AwContents::RequestDrawGL(jobject canvas, bool wait_for_completion) {    ......      JNIEnv* env = AttachCurrentThread();    ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);    if (obj.is_null())      return false;    return Java_AwContents_requestDrawGL(        env, obj.obj(), canvas, wait_for_completion);  }</code></pre>    <p>这个函数定义在文件external/chromium_org/android_webview/native/aw_contents.cc中。</p>    <p>在前面 Android WebView执行GPU命令的过程分析 一文中,我们已经分析过Native层AwContents类的成员函数RequestDrawGL的实现了,它主要就是调用Java层的AwContents类的成员函数requestDrawGL请求在参数canvas描述的Hardware Canvas中增加一个DrawFunctorOp操作。</p>    <p>Java层的AwContents类的成员函数requestDrawGL最终会调用到DrawGLFunctor类的成员函数requestDrawGL在参数canvas描述的Hardware Canvas中增加一个DrawFunctorOp操作,如下所示:</p>    <pre>  <code class="language-java">class DrawGLFunctor {      ......        public boolean requestDrawGL(HardwareCanvas canvas, ViewRootImpl viewRootImpl,              boolean waitForCompletion) {          ......            if (canvas == null) {              viewRootImpl.invokeFunctor(mDestroyRunnable.mNativeDrawGLFunctor, waitForCompletion);              return true;          }            canvas.callDrawGLFunction(mDestroyRunnable.mNativeDrawGLFunctor);          ......            return true;      }        ......  }</code></pre>    <p>这个函数定义在文件frameworks/webview/chromium/java/com/android/webview/chromium/DrawGLFunctor.java中。</p>    <p>在前面 Android WebView执行GPU命令的过程分析 一文中,DrawGLFunctor类的成员函数requestDrawGL是在Render端光栅化网页UI的过程中调用的。这时候参数canvas的值等于null,因此DrawGLFunctor类的成员函数requestDrawGL会通过调用参数viewRootImpl指向的一个ViewRootImpl对象的成员函数invokeFunctor直接请求App的Render Thread执行GPU命令。</p>    <p>现在,当DrawGLFunctor类的成员函数requestDrawGL被调用时,它的参数canvas的值不等于null,指向了一个Hardware Canvas。在这种情况下,DrawGLFunctor类的成员函数requestDrawGL将会调用这个Hardware Canvas的成员函数callDrawGLFunction,将一个Native层DrawGLFunctor对象封装成一个DrawFunctorOp操作,写入到它描述一个Display List中去。</p>    <p>被封装的Native层DrawGLFunctor对象,保存在Java层DrawGLFunctor类的成员变量mDestroyRunnable指向的一个DestroyRunnable对象的成员变量mNativeDrawGLFunctor中。</p>    <p>从前面 Android应用程序UI硬件加速渲染的Display List渲染过程分析 一文可以知道,参数canvas描述的Hardware Canvas是通过一个GLES20Canvas对象描述的,因此接下来它的成员函数callDrawGLFunction会被调用,用来将一个Native层DrawGLFunctor对象封装成一个DrawFunctorOp操作写入它描述一个Display List中去,如下所示:</p>    <pre>  <code class="language-java">class GLES20Canvas extends HardwareCanvas {      ......        @Override      public int callDrawGLFunction(long drawGLFunction) {          return nCallDrawGLFunction(mRenderer, drawGLFunction);      }        ......  }</code></pre>    <p>这个函数定义在文件frameworks/base/core/java/android/view/GLES20Canvas.java中。</p>    <p>GLES20Canvas类的成员函数callDrawGLFunction调用另外一个成员函数nCallDrawGLFunction将参数drawGLFunction描述的一个Native层DrawGLFunctor对象封装成一个DrawFunctorOp操作写入到当前正在处理的GLES20Canvas对象描述一个Display List中去。</p>    <p>GLES20Canvas类的成员函数nCallDrawGLFunction是一个JNI方法,它由C++层的函数android_view_GLES20Canvas_callDrawGLFunction实现,如下所示:</p>    <pre>  <code class="language-java">static jint android_view_GLES20Canvas_callDrawGLFunction(JNIEnv* env, jobject clazz,          jlong rendererPtr, jlong functorPtr) {      DisplayListRenderer* renderer = reinterpret_cast<DisplayListRenderer*>(rendererPtr);      Functor* functor = reinterpret_cast<Functor*>(functorPtr);      android::uirenderer::Rect dirty;      return renderer->callDrawGLFunction(functor, dirty);  }</code></pre>    <p>这个函数定义在文件frameworks/base/core/jni/android_view_GLES20Canvas.cpp中。</p>    <p>参数rendererPtr描述的是一个Native层的DisplayListRenderer对象。这个DisplayListRenderer对象负责构造App UI的Display List。函数android_view_GLES20Canvas_callDrawGLFunction所做的事情就是调用这个DisplayListRenderer对象的成员函数callDrawFunction将参数functionPtr描述的一个Native层DrawGLFunctor对象封装成一个DrawFunctorOp操作写入到App UI的Display List中去,如下所示:</p>    <pre>  <code class="language-java">status_t DisplayListRenderer::callDrawGLFunction(Functor *functor, Rect& dirty) {      // Ignore dirty during recording, it matters only when we replay      addDrawOp(new (alloc()) DrawFunctorOp(functor));      mDisplayListData->functors.add(functor);      return DrawGlInfo::kStatusDone; // No invalidate needed at record-time  }</code></pre>    <p>这个函数定义在文件frameworks/base/libs/hwui/DisplayListRenderer.cpp中。</p>    <p>DisplayListRenderer类的成员变量mDisplayListData指向的是一个DisplayListData对象。这个DisplayListData对象描述的就是App UI的Display List。因此,DisplayListRenderer对象的成员函数callDrawFunction就会将参数functor描述的一个Native层DrawGLFunctor对象封装成一个DrawFunctorOp操作写入到它里面去。</p>    <p>这一步执行完成后,Android WebView就在App渲染一个帧的第一个阶段通知Render端绘制完成了网页的UI,并且往App UI的Display List写入了一个DrawFunctorOp操作。在第二阶段,App UI的Display List就会从App的UI线程同步给App的Render Thread。在同步的过程中,RenderNode类的成员函数pushStagingDisplayListChanges地被调用,如下所示:</p>    <pre>  <code class="language-java">void RenderNode::pushStagingDisplayListChanges(TreeInfo& info) {      if (mNeedsDisplayListDataSync) {          mNeedsDisplayListDataSync = false;          ......          if (mDisplayListData) {              for (size_t i = 0; i < mDisplayListData->functors.size(); i++) {                  (*mDisplayListData->functors[i])(DrawGlInfo::kModeSync, NULL);              }          }          ......      }  }</code></pre>    <p>这个函数定义在文件frameworks/base/libs/hwui/RenderNode.cpp中。</p>    <p>这时候包含在App UI的Display List中的每一个DrawFunctorOp操作关联的Native层DrawGLFunctor对象的重载操作符函数()都会被调用,目的是让它执行一些同步操作。在我们这个情景中,就是将Render端绘制出来的UI同步到给Browser端。</p>    <p>在前面 Android WebView执行GPU命令的过程分析 一文中,我们已经分析过Native层DrawGLFunctor对象的重载操作符函数()的实现了,它最终会调用到Native层的AwContents类DrawGL将Render端绘制出来的UI同步到给Browser端,如下所示:</p>    <pre>  <code class="language-java">void AwContents::DrawGL(AwDrawGLInfo* draw_info) {    if (draw_info->mode == AwDrawGLInfo::kModeSync) {      if (hardware_renderer_)        hardware_renderer_->CommitFrame();      return;    }      ......  }</code></pre>    <p>这个函数定义在文件external/chromium_org/android_webview/native/aw_contents.cc中。</p>    <p>这时候App的Render Thread处于AwDrawGLInfo::kModeSync状态,因此AwContents类的成员函数DrawGL接下来将会调用成员变量hardware_renderer_指向的一个HardwareRenderer对象的成员函数CommitFrame将Render端绘制出来的UI同步到给Browser端,如下所示:</p>    <pre>  <code class="language-java">void HardwareRenderer::CommitFrame() {    scoped_ptr<DrawGLInput> input = shared_renderer_state_->PassDrawGLInput();    ......      if (!frame_provider_ || size_changed) {      ......        frame_provider_ = new cc::DelegatedFrameProvider(          resource_collection_.get(), input->frame.delegated_frame_data.Pass());        delegated_layer_ = cc::DelegatedRendererLayer::Create(frame_provider_);      ......        root_layer_->AddChild(delegated_layer_);    } else {      frame_provider_->SetFrameData(input->frame.delegated_frame_data.Pass());    }  }</code></pre>    <p>这个函数定义在文件external/chromium_org/android_webview/browser/hardware_renderer.cc中。</p>    <p>从前面的分析可以知道,Render端在第一阶段已经将绘制出来的网页UI,保存在一个DrawGLInput对象中。这个DrawGLInput又保存在一个SharedRendererState对象中。HardwareRenderer类的成员变量shared_renderer_state_描述的就是这个SharedRendererState对象。因此,HardwareRenderer类的成员函数CommitFrame可以通过调用这个SharedRendererState对象的成员函数PassDrawGLInput获得保存在它内部的DrawGLInput对象,如下所示:</p>    <pre>  <code class="language-java">scoped_ptr<DrawGLInput> SharedRendererState::PassDrawGLInput() {    base::AutoLock lock(lock_);    return draw_gl_input_.Pass();  }</code></pre>    <p>这个函数定义在文件external/chromium_org/android_webview/browser/shared_renderer_state.cc中。</p>    <p>从前面的分析可以知道,用来描述Render端在第一阶段绘制出来的网页UI的DrawGLInput对象就保存在SharedRendererState类的成员变量draw_gl_input_中,因此SharedRendererState类的成员函数PassDrawGLInput就可以将这个员变量draw_gl_input_指向的DrawGLInput对象返回给调用者。</p>    <p>回到前面分析的HardwareRenderer类的成员函数CommitFrame中,这时候它获得了一个Render端在第一阶段绘制出来的UI,也就是一个DrawGLInput对象,接下来它就会判断之前是否已经为Browser端的CC Layer Tree创建过一个Delegated Renderer Layer。</p>    <p>如果还没有创建,或者以前创建过,但是现在Android WebView的大小发生了变化,那么HardwareRenderer类的成员函数CommitFrame就会创建用前面获得的DrawGLInput对象创建一个Delegated Renderer Layer,并且作为Browser端的CC Layer Tree的根节点的子节点。</p>    <p>另一方面,如果已经创建,并且Android WebView的大小没有发生变化,那么HardwareRenderer类的成员函数CommitFrame就会使用前面获得的DrawGLInput对象更新Delegated Renderer Layer的内容。</p>    <p>这一步执行完成后,Android WebView就在App渲染一个帧的第二个阶段将Render端绘制出来的网页UI同步给了Browser端。在第三阶段,Browser端就会将网页的UI合成在App的窗口中,这样就可以显示在屏幕中了。</p>    <p>从前面 Android应用程序UI硬件加速渲染的Display List渲染过程分析 一文可以知道,App的Render Thread在第三阶段会通过一个OpenGL Renderer渲染从App的UI线程同步过来的Display List,也就是执行它里面包含的渲染操作。从前面的分析可以知道,Android WebView在第一阶段往这个Display List写入了一个DrawFunctorOp操作,OpenGL Renderer会通过调用它的成员函数callDrawGLFunction执行这个操作,如下所示:</p>    <pre>  <code class="language-java">status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {      ......        mRenderState.invokeFunctor(functor, DrawGlInfo::kModeDraw, &info);      ......        return DrawGlInfo::kStatusDrew;  }</code></pre>    <p>这个函数定义在文件frameworks/base/libs/hwui/OpenGLRenderer.cpp中。</p>    <p>参数funtor描述的就是与当前要执行的DrawFunctorOp操作关联的Native层DrawGLFunctor对象。OpenGLRenderer类的成员函数callDrawGLFunction会通过调用成员变量mRenderState指向的一个RenderState对象的成员函数invokeFunctor调用这个Native层DrawGLFunctor对象的重载操作符函数(),告知它App的Render Thread当前处于第三阶段,也就是DrawGlInfo::kModeDraw状态,它可以执行相应的GPU命令。</p>    <p>在前面 Android WebView执行GPU命令的过程分析 一文中,我们已经分析过RenderState类的成员函数invokeFunctor的实现了,它最终会调用到Native层的AwContents类DrawGL将绘制Browser端的CC Layer Tree,如下所示:</p>    <pre>  <code class="language-java">void AwContents::DrawGL(AwDrawGLInfo* draw_info) {    if (draw_info->mode == AwDrawGLInfo::kModeSync) {      ......      return;    }      ......      if (draw_info->mode != AwDrawGLInfo::kModeDraw) {      ......      return;    }      ......      hardware_renderer_->DrawGL(state_restore.stencil_enabled(),                               state_restore.framebuffer_binding_ext(),                               draw_info);    ......  }</code></pre>    <p>这个函数定义在文件external/chromium_org/android_webview/native/aw_contents.cc中。</p>    <p>由于当前App的Render Thread处于AwDrawGlInfo::kModeDraw状态,因此AwContents类DrawGL会调用成员变量hardware_renderer_指向的一个HardwareRenderer对象的成员函数DrawGL,用来绘制Browser端的CC Layer Tree,如下所示:</p>    <pre>  <code class="language-java">void HardwareRenderer::DrawGL(bool stencil_enabled,                                int framebuffer_binding_ext,                                AwDrawGLInfo* draw_info) {    ......      {      ......      layer_tree_host_->Composite(gfx::FrameTime::Now());    }      ......  }</code></pre>    <p>这个函数定义在文件external/chromium_org/android_webview/browser/hardware_renderer.cc中。</p>    <p>从前面 Android WebView执行GPU命令的过程分析 一文可以知道,HardwareRenderer类的成员变量layer_tree_host_指向的是一个LayerTreeHost对象。这个LayerTreeHost对象描述的就是Browser端的CC Layer Tree。HardwareRenderer类的成员函数DrawGL将会调用这个LayerTreeHost对象的成员函数Composite,以便绘制Browser端的CC Layer Tree,如下所示:</p>    <pre>  <code class="language-java">void LayerTreeHost::Composite(base::TimeTicks frame_begin_time) {    ......    SingleThreadProxy* proxy = static_cast<SingleThreadProxy*>(proxy_.get());      .....      proxy->CompositeImmediately(frame_begin_time);  }</code></pre>    <p>这个函数定义在文件external/chromium_org/cc/trees/layer_tree_host.cc中。</p>    <p>从前面 Android WebView执行GPU命令的过程分析 一文可以知道,当前正在处理的LayerTreeHost对象的成员变量proxy_指向的是一个SingleThreadProxy对象,LayerTreeHost类的成员函数Composite调用这个SingleThreadProxy对象的成员函数CompositeImmediately绘制Browser端的CC Layer Tree,如下所示:</p>    <pre>  <code class="language-java">void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) {    ......      LayerTreeHostImpl::FrameData frame;    if (DoComposite(frame_begin_time, &frame)) {      {        ......      }      ......    }  }</code></pre>    <p>这个函数定义在文件external/chromium_org/cc/trees/single_thread_proxy.cc中。</p>    <p>SingleThreadProxy类的成员函数CompositeImmediately主要是调用另外一个成员函数DoComposite绘制Browser端的CC Layer Tree,如下所示:</p>    <pre>  <code class="language-java">bool SingleThreadProxy::DoComposite(      base::TimeTicks frame_begin_time,      LayerTreeHostImpl::FrameData* frame) {    ......      bool lost_output_surface = false;    {      ......        if (!layer_tree_host_impl_->IsContextLost()) {        layer_tree_host_impl_->PrepareToDraw(frame);        layer_tree_host_impl_->DrawLayers(frame, frame_begin_time);        ......      }            ......    }      ......  }</code></pre>    <p>这个函数定义在文件external/chromium_org/cc/trees/single_thread_proxy.cc中。</p>    <p>从前面 Android WebView执行GPU命令的过程分析 一文可以知道,SingleThreadProxy类的成员变量layer_tree_host_impl_指向的是一个LayerTreeHostImpl对象。SingleThreadProxy类的成员函数DoComposite主要是调用这个LayerTreeHostImpl对象的成员函数PrepareToDraw和DrawLayers绘制Browser端的CC Layer Tree。</p>    <p>LayerTreeHostImpl类的成员函数PrepareToDraw和DrawLayers绘制CC Layer Tree的过程可以参考前面 Chromium硬件加速渲染的UI合成过程分析 一文。从前面 Chromium硬件加速渲染的UI合成过程分析 一文我们还可以知道,Chromium的Browser端在内部是通过一个Direct Renderer绘制CC Layer Tree的,而Render端是通过一个Delegated Renderer绘制CC Layer Tree的。Delegated Renderer并不是真的绘制CC Layer Tree,而只是将CC Layer Tree的绘制命令收集起来,放在一个Compositor Frame中。这个Compositor Frame最终会交给Browser端的Direct Renderer处理。Direct Renderer直接调用OpenGL函数执行保存在Compositor Frame的绘制命令。因此,当Browser端绘制完成自己的CC Layer Tree之后,加载在Android WebView中的网页UI就会合成显示在App的窗口中了。</p>    <p>至此,我们就分析完成了Android WebView硬件加速渲染网页UI的过程,也完成了对Android基于Chromium实现的WebView的学习。</p>    <p> </p>    <p>来自:http://blog.csdn.net/luoshengyang/article/details/53366272</p>    <p> </p>