Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

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

$
0
0

      Android WebView作为App UI的一部分,当App UI以硬件加速方式渲染时,它也是以硬件加速方式渲染的。Android WebView的UI来自于网页,是通过Chromium渲染的。Chromium渲染网页UI的机制与Android App渲染UI的机制是不一样的。不过,它们会一起协作完成网页UI的渲染。本文接下来就详细分析Android WebView硬件加速渲染网页UI的过程。

老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注!

《Android系统源代码情景分析》一书正在进击的程序员网(http://0xcc0xcd.com)中连载,点击进入!

      从前面Android应用程序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,它的渲染也是按照上述三个阶段进行的,如下所示:


图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的过程。

       从前面Android应用程序UI硬件加速渲染的Display List构建过程分析一文可以知道,在App渲染UI的第一阶段,Android WebView的成员函数onDraw会被调用。从前面Android WebView执行GPU命令的过程分析一文又可以知道,Android WebView在Native层有一个BrowserViewRenderer对象。当Android WebView的成员函数onDraw被调用时,并且App的UI以硬件加速方式渲染时,这个Native层BrowserViewRenderer对象的成员函数OnDrawHardware会被调用,如下所示:

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);  
}  

       这个函数定义在文件external/chromium_org/android_webview/browser/browser_view_renderer.cc中。

       从前面Android WebView执行GPU命令的过程分析一文可以知道,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的过程,如下所示:

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();
}
      这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_impl.cc中。

      从前面Android WebView执行GPU命令的过程分析一文可以知道,SynchronousCompositorImpl类的成员变量output_surface_指向的是一个SynchronousCompositorOutputSurface对象。SynchronousCompositorImpl类的成员函数DemandDrawHw调用这个SynchronousCompositorOutputSurface对象的成员函数DemandDrawHw绘制网页的UI,如下所示:

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();
}
       这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_output_surface.cc中。

       SynchronousCompositorOutputSurface类的成员函数DemandDrawHw调用另外一个成员函数InvokeComposite绘制网页的UI。绘制完成后,就会得到一个Compositor Frame。这个Compositor Frame保存在SynchronousCompositorOutputSurface类的成员变量frame_holder_中。因此,SynchronousCompositorOutputSurface类的成员函数DemandDrawHw可以将这个成员变量frame_holder_指向的Compositor Frame返回给调用者。

       SynchronousCompositorOutputSurface类的成员函数InvokeComposite的实现如下所示:

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());

  ......
}
       这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_output_surface.cc中。

       SynchronousCompositorOutputSurface类的成员变量client_是从父类OutputSurface继承下来的。从前面Chromium网页绘图表面(Output Surface)创建过程分析一文可以知道,它指向的是一个LayerTreeHostImpl对象。SynchronousCompositorOutputSurface类的成员函数InvokeComposite调用这个LayerTreeHostImpl对象的成员函数BeginFrame绘制网页的UI。 

       从前面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的过程分析这三篇文章。

       由于Android WebView的Render端使用的是Synchronous Compositor,当前线程(也就是App的UI线程)会等待Render端的Compositor线程绘制完成网页的CC Layer Tree。从前面Chromium硬件加速渲染的UI合成过程分析一文可以知道,Compositor线程在绘制完成网页的CC Layer Tree的时候,会调用网页的Output Surface的成员函数SwapBuffers。

       在我们这个情景中,网页的Output Surface是一个Synchronous Compositor Output Surface。这意味着当Compositor线程在绘制完成网页的CC Layer Tree时,会调用SynchronousCompositorOutputSurface类的成员函数SwapBuffers,如下所示:

void SynchronousCompositorOutputSurface::SwapBuffers(
    cc::CompositorFrame* frame) {
  ......

  frame_holder_.reset(new cc::CompositorFrame);
  frame->AssignTo(frame_holder_.get());

  ......
}
       这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_output_surface.cc中。

       参数frame指向的Compositor Frame描述的就是网页的绘制结果。从前面Chromium硬件加速渲染的UI合成过程分析一文可以知道,这个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实现的,如下所示:

void SharedRendererState::SetDrawGLInput(scoped_ptr<DrawGLInput> input) {
  ......
  draw_gl_input_ = input.Pass();
}
      这个函数定义在文件external/chromium_org/android_webview/browser/shared_renderer_state.cc中。

      SharedRendererState类的成员函数SetDrawGLInput将参数input指向的一个DrawGLInput对象保存成员变量draw_gl_input_中。

      这一步执行完成后,再回到前面分析的BrowserViewRenderer类的成员函数OnDrawHardware中,接下来它会调用成员变量client_指向的一个Native层AwContents对象的成员函数RequestDrawGL请求在参数java_canvas描述的一个Hardware Canvas中增加一个DrawFunctorOp操作,如下所示:

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);
}
       这个函数定义在文件external/chromium_org/android_webview/native/aw_contents.cc中。

       在前面Android WebView执行GPU命令的过程分析一文中,我们已经分析过Native层AwContents类的成员函数RequestDrawGL的实现了,它主要就是调用Java层的AwContents类的成员函数requestDrawGL请求在参数canvas描述的Hardware Canvas中增加一个DrawFunctorOp操作。

       Java层的AwContents类的成员函数requestDrawGL最终会调用到DrawGLFunctor类的成员函数requestDrawGL在参数canvas描述的Hardware Canvas中增加一个DrawFunctorOp操作,如下所示:

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;
    }

    ......
}
       这个函数定义在文件frameworks/webview/chromium/java/com/android/webview/chromium/DrawGLFunctor.java中。

       在前面Android WebView执行GPU命令的过程分析一文中,DrawGLFunctor类的成员函数requestDrawGL是在Render端光栅化网页UI的过程中调用的。这时候参数canvas的值等于null,因此DrawGLFunctor类的成员函数requestDrawGL会通过调用参数viewRootImpl指向的一个ViewRootImpl对象的成员函数invokeFunctor直接请求App的Render Thread执行GPU命令。

       现在,当DrawGLFunctor类的成员函数requestDrawGL被调用时,它的参数canvas的值不等于null,指向了一个Hardware Canvas。在这种情况下,DrawGLFunctor类的成员函数requestDrawGL将会调用这个Hardware Canvas的成员函数callDrawGLFunction,将一个Native层DrawGLFunctor对象封装成一个DrawFunctorOp操作,写入到它描述一个Display List中去。

       被封装的Native层DrawGLFunctor对象,保存在Java层DrawGLFunctor类的成员变量mDestroyRunnable指向的一个DestroyRunnable对象的成员变量mNativeDrawGLFunctor中。这一点可以参考前面Android WebView执行GPU命令的过程分析一文。

       从前面Android应用程序UI硬件加速渲染的Display List渲染过程分析一文可以知道,参数canvas描述的Hardware Canvas是通过一个GLES20Canvas对象描述的,因此接下来它的成员函数callDrawGLFunction会被调用,用来将一个Native层DrawGLFunctor对象封装成一个DrawFunctorOp操作写入它描述一个Display List中去,如下所示:

class GLES20Canvas extends HardwareCanvas {
    ......

    @Override
    public int callDrawGLFunction(long drawGLFunction) {
        return nCallDrawGLFunction(mRenderer, drawGLFunction);
    }

    ......
}
       这个函数定义在文件frameworks/base/core/java/android/view/GLES20Canvas.java中。

       GLES20Canvas类的成员函数callDrawGLFunction调用另外一个成员函数nCallDrawGLFunction将参数drawGLFunction描述的一个Native层DrawGLFunctor对象封装成一个DrawFunctorOp操作写入到当前正在处理的GLES20Canvas对象描述一个Display List中去。

       GLES20Canvas类的成员函数nCallDrawGLFunction是一个JNI方法,它由C++层的函数android_view_GLES20Canvas_callDrawGLFunction实现,如下所示:

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);
}
       这个函数定义在文件frameworks/base/core/jni/android_view_GLES20Canvas.cpp中。

       参数rendererPtr描述的是一个Native层的DisplayListRenderer对象。这个DisplayListRenderer对象负责构造App UI的Display List。函数android_view_GLES20Canvas_callDrawGLFunction所做的事情就是调用这个DisplayListRenderer对象的成员函数callDrawFunction将参数functionPtr描述的一个Native层DrawGLFunctor对象封装成一个DrawFunctorOp操作写入到App UI的Display List中去,如下所示:

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
}
       这个函数定义在文件frameworks/base/libs/hwui/DisplayListRenderer.cpp中。

       DisplayListRenderer类的成员变量mDisplayListData指向的是一个DisplayListData对象。这个DisplayListData对象描述的就是App UI的Display List。因此,DisplayListRenderer对象的成员函数callDrawFunction就会将参数functor描述的一个Native层DrawGLFunctor对象封装成一个DrawFunctorOp操作写入到它里面去。

       这一步执行完成后,Android WebView就在App渲染一个帧的第一个阶段通知Render端绘制完成了网页的UI,并且往App UI的Display List写入了一个DrawFunctorOp操作。在第二阶段,App UI的Display List就会从App的UI线程同步给App的Render Thread。从前面Android应用程序UI硬件加速渲染的Display List渲染过程分析一文可以知道,在同步的过程中,RenderNode类的成员函数pushStagingDisplayListChanges地被调用,如下所示:

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);
            }
        }
        ......
    }
}
       这个函数定义在文件frameworks/base/libs/hwui/RenderNode.cpp中。

       这时候包含在App UI的Display List中的每一个DrawFunctorOp操作关联的Native层DrawGLFunctor对象的重载操作符函数()都会被调用,目的是让它执行一些同步操作。在我们这个情景中,就是将Render端绘制出来的UI同步到给Browser端。

       在前面Android WebView执行GPU命令的过程分析一文中,我们已经分析过Native层DrawGLFunctor对象的重载操作符函数()的实现了,它最终会调用到Native层的AwContents类DrawGL将Render端绘制出来的UI同步到给Browser端,如下所示:

void AwContents::DrawGL(AwDrawGLInfo* draw_info) {
  if (draw_info->mode == AwDrawGLInfo::kModeSync) {
    if (hardware_renderer_)
      hardware_renderer_->CommitFrame();
    return;
  }

  ......
}
      这个函数定义在文件external/chromium_org/android_webview/native/aw_contents.cc中。

      这时候App的Render Thread处于AwDrawGLInfo::kModeSync状态,因此AwContents类的成员函数DrawGL接下来将会调用成员变量hardware_renderer_指向的一个HardwareRenderer对象的成员函数CommitFrame将Render端绘制出来的UI同步到给Browser端,如下所示:

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());
  }
}
      这个函数定义在文件external/chromium_org/android_webview/browser/hardware_renderer.cc中。

      从前面的分析可以知道,Render端在第一阶段已经将绘制出来的网页UI,保存在一个DrawGLInput对象中。这个DrawGLInput又保存在一个SharedRendererState对象中。HardwareRenderer类的成员变量shared_renderer_state_描述的就是这个SharedRendererState对象。因此,HardwareRenderer类的成员函数CommitFrame可以通过调用这个SharedRendererState对象的成员函数PassDrawGLInput获得保存在它内部的DrawGLInput对象,如下所示:

scoped_ptr<DrawGLInput> SharedRendererState::PassDrawGLInput() {
  base::AutoLock lock(lock_);
  return draw_gl_input_.Pass();
}
      这个函数定义在文件external/chromium_org/android_webview/browser/shared_renderer_state.cc中。

      从前面的分析可以知道,用来描述Render端在第一阶段绘制出来的网页UI的DrawGLInput对象就保存在SharedRendererState类的成员变量draw_gl_input_中,因此SharedRendererState类的成员函数PassDrawGLInput就可以将这个员变量draw_gl_input_指向的DrawGLInput对象返回给调用者。

       回到前面分析的HardwareRenderer类的成员函数CommitFrame中,这时候它获得了一个Render端在第一阶段绘制出来的UI,也就是一个DrawGLInput对象,接下来它就会判断之前是否已经为Browser端的CC Layer Tree创建过一个Delegated Renderer Layer。

       如果还没有创建,或者以前创建过,但是现在Android WebView的大小发生了变化,那么HardwareRenderer类的成员函数CommitFrame就会创建用前面获得的DrawGLInput对象创建一个Delegated Renderer Layer,并且作为Browser端的CC Layer Tree的根节点的子节点。

       另一方面,如果已经创建,并且Android WebView的大小没有发生变化,那么HardwareRenderer类的成员函数CommitFrame就会使用前面获得的DrawGLInput对象更新Delegated Renderer Layer的内容。

       这一步执行完成后,Android WebView就在App渲染一个帧的第二个阶段将Render端绘制出来的网页UI同步给了Browser端。在第三阶段,Browser端就会将网页的UI合成在App的窗口中,这样就可以显示在屏幕中了。

       从前面Android应用程序UI硬件加速渲染的Display List渲染过程分析一文可以知道,App的Render Thread在第三阶段会通过一个OpenGL Renderer渲染从App的UI线程同步过来的Display List,也就是执行它里面包含的渲染操作。从前面的分析可以知道,Android WebView在第一阶段往这个Display List写入了一个DrawFunctorOp操作,OpenGL Renderer会通过调用它的成员函数callDrawGLFunction执行这个操作,如下所示:

status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) {
    ......

    mRenderState.invokeFunctor(functor, DrawGlInfo::kModeDraw, &info);
    ......

    return DrawGlInfo::kStatusDrew;
}
      这个函数定义在文件frameworks/base/libs/hwui/OpenGLRenderer.cpp中。

      参数funtor描述的就是与当前要执行的DrawFunctorOp操作关联的Native层DrawGLFunctor对象。OpenGLRenderer类的成员函数callDrawGLFunction会通过调用成员变量mRenderState指向的一个RenderState对象的成员函数invokeFunctor调用这个Native层DrawGLFunctor对象的重载操作符函数(),告知它App的Render Thread当前处于第三阶段,也就是DrawGlInfo::kModeDraw状态,它可以执行相应的GPU命令。

      在前面Android WebView执行GPU命令的过程分析一文中,我们已经分析过RenderState类的成员函数invokeFunctor的实现了,它最终会调用到Native层的AwContents类DrawGL将绘制Browser端的CC Layer Tree,如下所示:

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);
  ......
}
       这个函数定义在文件external/chromium_org/android_webview/native/aw_contents.cc中。

       由于当前App的Render Thread处于AwDrawGlInfo::kModeDraw状态,因此AwContents类DrawGL会调用成员变量hardware_renderer_指向的一个HardwareRenderer对象的成员函数DrawGL,用来绘制Browser端的CC Layer Tree,如下所示:

void HardwareRenderer::DrawGL(bool stencil_enabled,
                              int framebuffer_binding_ext,
                              AwDrawGLInfo* draw_info) {
  ......

  {
    ......
    layer_tree_host_->Composite(gfx::FrameTime::Now());
  }

  ......
}
      这个函数定义在文件external/chromium_org/android_webview/browser/hardware_renderer.cc中。

      从前面Android WebView执行GPU命令的过程分析一文可以知道,HardwareRenderer类的成员变量layer_tree_host_指向的是一个LayerTreeHost对象。这个LayerTreeHost对象描述的就是Browser端的CC Layer Tree。HardwareRenderer类的成员函数DrawGL将会调用这个LayerTreeHost对象的成员函数Composite,以便绘制Browser端的CC Layer Tree,如下所示:

void LayerTreeHost::Composite(base::TimeTicks frame_begin_time) {
  ......
  SingleThreadProxy* proxy = static_cast<SingleThreadProxy*>(proxy_.get());

  .....

  proxy->CompositeImmediately(frame_begin_time);
}
      这个函数定义在文件external/chromium_org/cc/trees/layer_tree_host.cc中。

      从前面Android WebView执行GPU命令的过程分析一文可以知道,当前正在处理的LayerTreeHost对象的成员变量proxy_指向的是一个SingleThreadProxy对象,LayerTreeHost类的成员函数Composite调用这个SingleThreadProxy对象的成员函数CompositeImmediately绘制Browser端的CC Layer Tree,如下所示:

void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) {
  ......

  LayerTreeHostImpl::FrameData frame;
  if (DoComposite(frame_begin_time, &frame)) {
    {
      ......
    }
    ......
  }
}
       这个函数定义在文件external/chromium_org/cc/trees/single_thread_proxy.cc中。

       SingleThreadProxy类的成员函数CompositeImmediately主要是调用另外一个成员函数DoComposite绘制Browser端的CC Layer Tree,如下所示:

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);
      ......
    }
    
    ......
  }

  ......
} 
       这个函数定义在文件external/chromium_org/cc/trees/single_thread_proxy.cc中。

       从前面Android WebView执行GPU命令的过程分析一文可以知道,SingleThreadProxy类的成员变量layer_tree_host_impl_指向的是一个LayerTreeHostImpl对象。SingleThreadProxy类的成员函数DoComposite主要是调用这个LayerTreeHostImpl对象的成员函数PrepareToDraw和DrawLayers绘制Browser端的CC Layer Tree。

       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的窗口中了。

      至此,我们就分析完成了Android WebView硬件加速渲染网页UI的过程,也完成了对Android基于Chromium实现的WebView的学习。重新学习可以参考Android WebView简要介绍和学习计划一文。更多的学习信息可以关注老罗的新浪微博:http://weibo.com/shengyangluo

作者:Luoshengyang 发表于2016/12/19 0:58:18 原文链接
阅读:32975 评论:4 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles