老罗的Android之旅

爱生活,爱Android

Android WebView执行GPU命令的过程分析

       Android WebView使用的Chromium引擎,虽然没有自己的GPU进程或者线程,但是却可以执行GPU命令。原来,Android WebView会给它提供一个In-Process Command Buffer GL接口。通过这个接口,Chromium引擎就可以将GPU命令提交给App的Render Thread执行。本文接下来就详细分析Android WebView执行GPU命令的过程。

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

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

       从前面Chromium硬件加速渲染的OpenGL命令执行过程分析这篇文章可以知道,Chromium渲染引擎在有自己的GPU进程或者线程的情况下,是通过一个Command Buffer GL接口执行GPU命令的。这个Command Buffer GL接口通过一个GLES2Implementation类描述。Android WebView给Chromium引擎提供的In-Process Command Buffer GL接口,同样是通过GLES2Implementation类描述的。这样,Chromium渲染引擎就不用关心它发出的GPU命令是如何执行的。

       在Chromium渲染引擎中,需要执行GPU命令的是Render端和Browser端。Render端执行GPU命令是为渲染网页的UI,而Browser端执行GPU命令是为了将Render端渲染的网页UI合成显示在屏幕上。对Android WebView来说,它的Render端会将网页抽象成一个CC Layer Tree,然后使用一个Synchronous Compositor将它渲染在一个Synchronous Compositor Output Surface上,如图1所示:


图1 Android WebView的Render端渲染网页UI的示意图

       Android WebView的Browser端同样会将自己要合成的UI抽象为一个CC Layer Tree,然后使用一个Hardware Renderer将它渲染在一个Parent Output Surface上,如图2所示:


图2 Android WebView的Browser端合成网页UI的示意图

       Browser端的CC Layer Tree比较特别,它只有两个节点。一个是根节点,另一个是根节点的子节点,称为Delegated Render Layer,它要渲染的内容来自于Render端的渲染输出。从前面Chromium硬件加速渲染的UI合成过程分析一文可以知道,Render端的渲染输出是一系列的Render Pass。每一个Render Pass都包含了若干个纹理。这些纹理是在Render端光栅化网页时产生的。Browser端的Hardware Renderer所要做的事情就是将这些纹理渲染在屏幕上。这个过程也就是Browser端合成网页UI的过程。

       不管是Render端,还是Browser端,当它们执行GPU命令的时候,都是通过GLES2Implementation类描述的一个In-Process Command Buffer GL接口写入到一个Command Buffer中去的。只不过在Android WebView的情况下,这些GPU命令会被一个DeferredGpuCommandService服务提交给App的Render Thread执行,如图3所示:


图3 Android WebView执行GPU命令的过程

       Render端和Browser端将要执行的GPU命令写入到Command Buffer之后,就会请求DeferredGpuCommandService服务在App的Render Thread中调度执行一个Task。这个Task绑定了InProcessCommandBuffer类的成员函数FlushOnGpuThread。InProcessCommandBuffer类的成员函数FlushOnGpuThread又是通过一个Gpu Scheduler按照上下文来执行请求的GPU命令,并且这些GPU命令在执行之前,先要经过一个GLES2 Decoder进行解码。这个过程可以参考前面Chromium硬件加速渲染的OpenGL命令执行过程分析一文。

       对于Browser端来说,它本来就是在App的Render Thread中请求执行GPU命令的。这时候DeferredGpuCommandService服务会直接在当前线程中调用InProcessCommandBuffer类的成员函数FlushOnGpuThread,以便执行请求的GPU命令。

       对于Render端来说,它在两种情景下需要请求执行GPU命令。第一种情景是光栅化网页的UI,第二种情景是绘制网页的UI。这两种情景都是发生在Render端的Compositor线程中。关于Render端的Compositor线程,以及网页UI的光栅化和绘制操作,可以参考前面Chromium网页渲染机制简要介绍和学习计划这个系列的文章。

       上述两种情景都会将要执行的GPU操作抽象为一个DrawGLFunctor对象。对于第一个情景,DrawGLFunctor对象会通过App的UI线程直接提交给App的Render Thread。App的Render Thread再通知该DrawGLFunctor对象执行GPU操作。

       对于第二个情景,DrawGLFunctor对象会被App的UI线程封装为一个DrawFunctorOp操作,并且写入到App UI的Display List中。 接下来App的UI线程会将Display List同步给App的Render Thread。随后这个Display List就会被App的Render Thread通过一个OpenGL Renderer进行Replay,这时候Display List中包含的DrawFunctorOp操作就会被执行。在执行的过程中,与它关联的DrawGLFunctor对象获得通知。DrawGLFunctor对象获得通知以后就会执行之前Render端请求的GPU操作了。

       DrawGLFunctor对象在执行GPU操作的时候,会调用到一个DrawGL函数。这个DrawGL函数是Android WebView在启动Chromium渲染引擎时注册的。它在执行的过程中,就会通过Browser端的Hardware Renderer通知DeferredGpuCommandService服务执行此前请求调度的Task。这时候InProcessCommandBuffer类的成员函数FlushOnGpuThread就会被调用,这时候Render端之前请求的GPU命令就会被执行。

       接下来,我们就结合源码,分析Chromium渲染引擎的Render端和Browser端创建In-Process Command Buffer GL接口的过程,以及以Render端使用GPU光栅化网页的过程为例,分析Chromium渲染引擎通过In-Process Command Buffer GL接口执行GPU命令的过程。不过,在分析这些过程之前,我们首先分析Android WebView向Chromium渲染引擎注册DrawGL函数的过程。这个过程发生在Android WebView启动Chromium渲染引擎的Browser端的过程中。

       从前面Android WebView启动Chromium渲染引擎的过程分析一文可以知道,Android WebView在启动Chromium渲染引擎的Browser端的过程中,会调用到WebViewChromiumFactoryProvider类的成员函数startChromiumLocked,如下所示:

public class WebViewChromiumFactoryProvider implements WebViewFactoryProvider {
    ......

    private void startChromiumLocked() {
        ......

        initPlatSupportLibrary();
        AwBrowserProcess.start(ActivityThread.currentApplication());
    
        ......
    }

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

       在调用AwBrowserProcess类的静态成员函数start动Chromium渲染引擎的Browser端之前,WebViewChromiumFactoryProvider类的成员函数startChromiumLocked先会调用成员函数initPlatSupportLibrary向Chromium渲染引擎注册一个DrawGL函数,如下所示:

public class WebViewChromiumFactoryProvider implements WebViewFactoryProvider {
    ......

    private void initPlatSupportLibrary() {
        DrawGLFunctor.setChromiumAwDrawGLFunction(AwContents.getAwDrawGLFunction());
        ......
    }

    ......
}

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

       WebViewChromiumFactoryProvider类的成员函数startChromiumLocked首先会调用AwContents类的静态成员函数getAwDrawGLFunction获得要注册的DrawGL函数,然后再调用DrawGLFunctor类的静态成员函数setChromiumAwDrawGLFunction将它注册到Chromium渲染引擎中。

       接下来,我们首先分析AwContents类的静态成员函数getAwDrawGLFunction获取要注册的DrawGL函数的过程,然后再分析DrawGLFunctor类的静态成员函数setChromiumAwDrawGLFunction注册DrawGL函数到Chromium渲染引擎的过程。

       AwContents类的静态成员函数getAwDrawGLFunction的实现如下所示:

public class AwContents {
    ......

    public static long getAwDrawGLFunction() {
        return nativeGetAwDrawGLFunction();
    }

    ......
}
       这个函数定义在文件external/chromium_org/android_webview/java/src/org/chromium/android_webview/AwContents.java中。

       AwContents类的静态成员函数getAwDrawGLFunction调用另外一个静态成员函数AwContents类的静态成员函数获取要注册的的DrawGL函数的过程。

       AwContents类的静态成员函数AwContents类的静态成员函数是一个JNI方法,它由C++层的函数Java_com_android_org_chromium_android_1webview_AwContents_nativeGetAwDrawGLFunction实现,如下所示:

__attribute__((visibility("default")))
jlong
    Java_com_android_org_chromium_android_1webview_AwContents_nativeGetAwDrawGLFunction(JNIEnv*
    env, jclass jcaller) {
  return GetAwDrawGLFunction(env, jcaller);
}
       这个函数定义在文件out/target/product/generic/obj/GYP/shared_intermediates/android_webview/jni/AwContents_jni.h中。

       函数Java_com_android_org_chromium_android_1webview_AwContents_nativeGetAwDrawGLFunction又通过调用另外一个函数GetAwDrawGLFunction获取要注册的DrawGL函数,如下所示:

static jlong GetAwDrawGLFunction(JNIEnv* env, jclass) {
  return reinterpret_cast<intptr_t>(&DrawGLFunction);
}
      这个函数定义在文件external/chromium_org/android_webview/native/aw_contents.cc中。

      函数GetAwDrawGLFunction返回的是定义在同文件中的函数DrawGLFunction。这个函数的地址将会返回到前面分析的WebViewChromiumFactoryProvider类的成员函数initPlatSupportLibrary向Chromium,后者再调用DrawGLFunctor类的静态成员函数setChromiumAwDrawGLFunction将它注册到Chromium渲染引擎中,如下所示:

class DrawGLFunctor {
    ......

    public static void setChromiumAwDrawGLFunction(long functionPointer) {
        nativeSetChromiumAwDrawGLFunction(functionPointer);
    }

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

       DrawGLFunctor类的静态成员函数setChromiumAwDrawGLFunction调用另外一个静态成员函数nativeSetChromiumAwDrawGLFunction将前面获得的函数DrawGLFunction注册在Chromium渲染引擎中。

       DrawGLFunctor类的静态成员函数nativeSetChromiumAwDrawGLFunction是一个JNI方法,它由C++层的函数SetChromiumAwDrawGLFunction实现,如下所示:

AwDrawGLFunction* g_aw_drawgl_function = NULL;

......

void SetChromiumAwDrawGLFunction(JNIEnv*, jclass, jlong draw_function) {
  g_aw_drawgl_function = reinterpret_cast<AwDrawGLFunction*>(draw_function);
}
      这个函数定义在文件frameworks/webview/chromium/plat_support/draw_gl_functor.cpp中。

      函数SetChromiumAwDrawGLFunction将参数draw_function描述的函数DrawGLFunction的地址保存在全局变量g_aw_drawgl_function中。这样,Android WebView就在启动Chromium渲染引擎的Browser端的过程中,向Chromium渲染引擎注册了一个DrawGL函数。

      接下来,我们分析Chromium渲染引擎为Render端创建In-Process Command Buffer GL接口的过程。Chromium渲染引擎为Render端创建的In-Process Command Buffer GL接口是封装在绘图表面(Output Surface)里面的。在Chromium中,每一个网页都关联一个Output Surface。在分析Render端的In-Process Command Buffer GL接口的创建之前,我们首先分析网页的Output Surface的创建过程。

      从前面Chromium网页绘图表面(Output Surface)创建过程分析Chromium的GPU进程启动过程分析这两篇文章可以知道,Render端在加载了网页之后,会为网页创建一个绘图表面,即一个Output Surface,最终是通过调用RenderWidget类的成员函数CreateOutputSurface进行创建的,如下所示:

scoped_ptr<cc::OutputSurface> RenderWidget::CreateOutputSurface(bool fallback) {
  ......

#if defined(OS_ANDROID)
  if (SynchronousCompositorFactory* factory =
      SynchronousCompositorFactory::GetInstance()) {
    return factory->CreateOutputSurface(routing_id());
  }
#endif

  ......
}
       这个函数定义在文件external/chromium_org/content/renderer/render_widget.cc中。

       在Android平台上,RenderWidget类的成员函数CreateOutputSurface首先会调用SynchronousCompositorFactory类的静态成员函数GetInstance检查当前进程是否存在一个用来创建Output Surface的工厂对象。如果存在,那么就会调用它的成员函数CreateOutputSurface为当前加载的网页创建一个Output Surface。

       SynchronousCompositorFactory类的静态成员函数GetInstance的实现如下所示:

SynchronousCompositorFactory* g_instance = NULL;

......

void SynchronousCompositorFactory::SetInstance(
    SynchronousCompositorFactory* instance) {
  ......

  g_instance = instance;
}

SynchronousCompositorFactory* SynchronousCompositorFactory::GetInstance() {
  return g_instance;
}

       这两个函数定义在文件external/chromium_org/content/renderer/android/synchronous_compositor_factory.cc。

       SynchronousCompositorFactory类的静态成员函数GetInstance返回的是全局变量g_instance指向的一个SynchronousCompositorFactoryImpl对象。这个SynchronousCompositorFactoryImpl对象是通过SynchronousCompositorFactory类的静态成员数SetInstance设置给全局变量g_instance的。

       这个SynchronousCompositorFactoryImpl对象是什么时候设置给全局变量g_instance的呢?回忆前面Android WebView启动Chromium渲染引擎的过程分析一文,Android WebView在启动Chromium渲染引擎的过程,会创建一个DeferredGpuCommandService服务,并且将这个DeferredGpuCommandService服务保存在一个SynchronousCompositorFactoryImpl对象的成员变量service_中。这个SynchronousCompositorFactoryImpl对象在创建的过程中,就会通过调用SynchronousCompositorFactory类的静态成员数SetInstance将自己保存在上述全局变量g_instance中,如下所示:

SynchronousCompositorFactoryImpl::SynchronousCompositorFactoryImpl()
    : record_full_layer_(true),
      num_hardware_compositors_(0) {
  SynchronousCompositorFactory::SetInstance(this);
}
      这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_factory_impl.cc中。

      回到前面分析的RenderWidget类的成员函数CreateOutputSurface中,这时候它调用SynchronousCompositorFactory类的静态成员函数GetInstance就会获得一个SynchronousCompositorFactoryImpl对象。有了这个SynchronousCompositorFactoryImpl对象之后,RenderWidget类的成员函数CreateOutputSurface就会调用它的成员函数CreateOutputSurface为当前正在加载的网页创建一个Output Surface,如下所示:

scoped_ptr<cc::OutputSurface>
SynchronousCompositorFactoryImpl::CreateOutputSurface(int routing_id) {
  scoped_ptr<SynchronousCompositorOutputSurface> output_surface(
      new SynchronousCompositorOutputSurface(routing_id));
  return output_surface.PassAs<cc::OutputSurface>();
}
      这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_factory_impl.cc中。

      SynchronousCompositorFactoryImpl类的成员函数CreateOutputSurface创建一个类型为Synchronous Compositor的Output Surface返回给调用者。从前面Chromium网页绘图表面(Output Surface)创建过程分析一文可以知道,这个Synchronous Compositor Output Surface将会返回给ThreadProxy类的成员函数CreateAndInitializeOutputSurface,如下所示:

void ThreadProxy::CreateAndInitializeOutputSurface() {  
  ......    
  
  scoped_ptr<OutputSurface> output_surface =  
      layer_tree_host()->CreateOutputSurface();  
  
  if (output_surface) {  
    Proxy::ImplThreadTaskRunner()->PostTask(  
        FROM_HERE,  
        base::Bind(&ThreadProxy::InitializeOutputSurfaceOnImplThread,  
                   impl_thread_weak_ptr_,  
                   base::Passed(&output_surface)));  
    return;  
  }  
  
  ......  
}  
       这个函数定义在文件external/chromium_org/cc/trees/thread_proxy.cc中。

       ThreadProxy类的成员函数CreateAndInitializeOutputSurface又会将这个Synchronous Compositor Output Surface传递给Render端的Compositor线程,让后者对它进行初始化。这个初始化操作是通过在Render端的Compositor线程中调用ThreadProxy类的成员函数InitializeOutputSurfaceOnImplThread实现的。

       从前面Chromium网页绘图表面(Output Surface)创建过程分析一文可以知道,ThreadProxy类的成员函数InitializeOutputSurfaceOnImplThread在初始化Synchronous Compositor Output Surface的过程中,会调用它的成员函数BindToClient,表示它已经被设置给一个网页使用。

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

bool SynchronousCompositorOutputSurface::BindToClient(
    cc::OutputSurfaceClient* surface_client) {
  ......

  SynchronousCompositorOutputSurfaceDelegate* delegate = GetDelegate();
  if (delegate)
    delegate->DidBindOutputSurface(this);

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

       SynchronousCompositorOutputSurface类的成员函数BindToClient会调用另外一个成员函数GetDelegate获得一个Delegate对象,如下所示:

SynchronousCompositorOutputSurfaceDelegate*
SynchronousCompositorOutputSurface::GetDelegate() {
  return SynchronousCompositorImpl::FromRoutingID(routing_id_);
}
       这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_output_surface.cc中。

       SynchronousCompositorOutputSurface类的成员函数GetDelegate通过调用SynchronousCompositorImpl类的静态成员函数FromRoutingID获得一个Delegate对象,如下所示:

SynchronousCompositorImpl* SynchronousCompositorImpl::FromRoutingID(
    int routing_id) {
  return FromID(GetInProcessRendererId(), routing_id);
}
       这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_impl.cc中。

       SynchronousCompositorImpl类的静态成员函数FromRoutingID首先会调用静态成员函数GetInProcessRendererId获得当前正在处理的Render端的ID。有了这个ID之后,连同参数routing_id描述的网页ID,传递给SynchronousCompositorImpl类的另外一个静态成员函数FromID,如下所示:

SynchronousCompositorImpl* SynchronousCompositorImpl::FromID(int process_id,
                                                             int routing_id) {
  ......
  RenderViewHost* rvh = RenderViewHost::FromID(process_id, routing_id);
  ......
  WebContents* contents = WebContents::FromRenderViewHost(rvh);
  ......
  return FromWebContents(contents);
}
       这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_impl.cc中。

       SynchronousCompositorImpl类的静态成员函数FromID首先通过调用RenderViewHost类的静态成员函数FromID获得与参数process_id和routing_id对应的一个RenderViewHost对象。这个RenderViewHost对象用来在Browser端描述的一个网页。这个网页就是当前正在Android WebView中加载的网页。

       获得了与当前正在加载的网页对应的RenderViewHost对象之后,就可以调用WebContents类的静态成员函数FromRenderViewHost获得一个WebContents对象。在Chromium中,每一个网页在Content层又都是通过一个WebContents对象描述的。这个WebContents对象的创建过程可以参考前面Android WebView启动Chromium渲染引擎的过程分析一文。

       获得了用来描述当前正在加载的网页的WebContents对象之后,SynchronousCompositorImpl类的静态成员函数FromID就可以调用另外一个静态成员函数FromWebContents获得一个SynchronousCompositorImpl对象。这个SynchronousCompositorImpl对象的创建过程可以参考前面Android WebView启动Chromium渲染引擎的过程分析一文,它是负责用来渲染在Android WebView中加载的网页的UI的。

       SynchronousCompositorImpl类的静态成员函数FromID最后会将获得的SynchronousCompositorImpl对象返回给调用者,也就是前面分析的SynchronousCompositorOutputSurface类的成员函数BindToClient。SynchronousCompositorOutputSurface类的成员函数BindToClient接下来会调用这个SynchronousCompositorImpl对象的成员函数DidBindOutputSurface,表示它现在已经与一个Synchronous Compositor Output Surface建立了绑定关系,这样以后它就可以将网页的UI渲染在这个Synchronous Compositor Output Surface之上。

       SynchronousCompositorImpl类的成员函数DidBindOutputSurface的实现如下所示:

void SynchronousCompositorImpl::DidBindOutputSurface(
      SynchronousCompositorOutputSurface* output_surface) {
  ......
  output_surface_ = output_surface;
  if (compositor_client_)
    compositor_client_->DidInitializeCompositor(this);
}
       这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_impl.cc中。

       SynchronousCompositorImpl类的成员函数DidBindOutputSurface首先将参数output_surface描述的Synchronous Compositor Output Surface保存在成员变量output_surface_中。

       从前面Android WebView启动Chromium渲染引擎的过程分析一文可以知道,SynchronousCompositorImpl类的成员变量compositor_client_指向的是一个BrowserViewRenderer对象。SynchronousCompositorImpl类的成员函数DidBindOutputSurface最后会调用这个BrowserViewRenderer对象的成员函数DidInitializeCompositor,表示Chromium渲染引擎已经为它创建了一个用来渲染网页UI的Synchronous Compositor,如下所示:

void BrowserViewRenderer::DidInitializeCompositor(
    content::SynchronousCompositor* compositor) {
  ......

  compositor_ = compositor;
}
       这个函数定义在文件external/chromium_org/android_webview/browser/browser_view_renderer.cc中。

       BrowserViewRenderer类的成员函数DidInitializeCompositor会将参数compositor指向的一个SynchronousCompositorImpl对象保存在成员变量compositor_中。

       这一步执行完成之后,Chromium渲染引擎就为在Render端加载的网页创建了一个Synchronous Compositor Output Surface,并且会将这个Synchronous Compositor Output Surface设置给一个Synchronous Compositor。这个Synchronous Compositor又会设置给一个BrowserViewRenderer对象。这个BrowserViewRenderer对象负责绘制Android WebView的UI。

       接下来我们就开始分析Chromium渲染引擎为Render端创建In-Process Command Buffer GL接口的过程。这个In-Process Command Buffer GL接口是在Android WebView第一次执行硬件加速渲染之前创建的。从前面Android WebView启动Chromium渲染引擎的过程分析一文可以知道,Android WebView每次被绘制时,它在Chromium的android_webview模块中对应的AwContents对象的成员函数OnDraw都会被调用,如下所示:

bool AwContents::OnDraw(JNIEnv* env,
                        jobject obj,
                        jobject canvas,
                        jboolean is_hardware_accelerated,
                        jint scroll_x,
                        jint scroll_y,
                        jint visible_left,
                        jint visible_top,
                        jint visible_right,
                        jint visible_bottom) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  if (is_hardware_accelerated)
    InitializeHardwareDrawIfNeeded();
  return browser_view_renderer_.OnDraw(
      canvas,
      is_hardware_accelerated,
      gfx::Vector2d(scroll_x, scroll_y),
      gfx::Rect(visible_left,
                visible_top,
                visible_right - visible_left,
                visible_bottom - visible_top));
}
      这个函数定义在文件external/chromium_org/android_webview/native/aw_contents.cc。

      如果执行的是硬件加速渲染,那么AwContents类的成员函数OnDraw首先会调用另外一个成员函数InitializeHardwareDrawIfNeeded检查当前是否已经创建了一个DeferredGpuCommandService服务。如果还没有创建,那么就会进行创建。这个DeferredGpuCommandService服务的创建过程可以参考前面Android WebView启动Chromium渲染引擎的过程分析一文。

      AwContents类的成员函数OnDraw接下来会调用成员变量browser_view_renderer_描述的一个BrowserViewRenderer对象的成员函数OnDraw执行硬件加速渲染,如下所示:

bool BrowserViewRenderer::OnDraw(jobject java_canvas,
                                 bool is_hardware_canvas,
                                 const gfx::Vector2d& scroll,
                                 const gfx::Rect& global_visible_rect) {
  ......

  if (is_hardware_canvas && attached_to_window_)
    return OnDrawHardware(java_canvas);
  // Perform a software draw
  return OnDrawSoftware(java_canvas);
}
       这个函数定义在文件external/chromium_org/android_webview/browser/browser_view_renderer.cc中。

       在执行硬件加速渲染的情况下,BrowserViewRenderer对象的成员函数OnDraw会调用成员函数OnDrawHardware对Android WebView进行绘制,如下所示:

bool BrowserViewRenderer::OnDrawHardware(jobject java_canvas) {
  ......

  if (!hardware_enabled_) {
    hardware_enabled_ = compositor_->InitializeHwDraw();
    ......
  }

  ......

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

  shared_renderer_state_->SetDrawGLInput(draw_gl_input.Pass());
  ......
  return client_->RequestDrawGL(java_canvas, false);
}
       这个函数定义在文件external/chromium_org/android_webview/browser/browser_view_renderer.cc中。

       当BrowserViewRenderer类的成员变量hardware_enabled_的值等于false时,表示Android WebView是第一次启用硬件加速渲染。在这种情况下,BrowserViewRenderer类的函数OnDraw首先会初始化一个硬件加速渲染环境,然后再对Android WebView进行绘制。

       从前面的分析可以知道,BrowserViewRenderer类的成员变量compositor_指向的是一个SynchronousCompositorImpl对象。BrowserViewRenderer类的函数OnDraw就是通过调用这个SynchronousCompositorImpl对象的成员函数InitializeHwDraw初始化一个硬件加速渲染环境的。在初始化这个硬件加速渲染环境的过程中,就会创建一个In-Process Command Buffer GL接口。

       接下来,我们就继续分析SynchronousCompositorImpl类的成员函数InitializeHwDraw初始化创建In-Process Command Buffer GL接口的过程。在接下来一篇文章中,我们再分析BrowserViewRenderer类的函数OnDraw绘制Android WebView的过程。

       SynchronousCompositorImpl类的成员函数InitializeHwDraw的实现如下所示:

base::LazyInstance<SynchronousCompositorFactoryImpl>::Leaky g_factory =
    LAZY_INSTANCE_INITIALIZER;

......

bool SynchronousCompositorImpl::InitializeHwDraw() {
  ......

  scoped_refptr<cc::ContextProvider> onscreen_context =
      g_factory.Get().CreateOnscreenContextProviderForCompositorThread();

  bool success = output_surface_->InitializeHwDraw(onscreen_context);

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

       全局变量指向的就是前面提到的用来为网页创建Output Surface的SynchronousCompositorFactoryImpl对象。SynchronousCompositorImpl类的成员函数InitializeHwDraw调用这个SynchronousCompositorFactoryImpl对象的成员函数CreateOnscreenContextProviderForCompositorThread创建一个硬件加速渲染环境。

       创建出来的硬件加速渲染环境是通过一个ContextProviderInProcess对象描述的。这个ContextProviderInProcess对象又会设置给SynchronousCompositorImpl类的成员变量output_surface_描述的一个Synchronous Compositor Output Surface。Synchronous Compositor Output Surface有了硬件加速渲染环境之后,就可以执行GPU命令了。

       接下来,我们首先分析SynchronousCompositorFactoryImpl类的成员函数CreateOnscreenContextProviderForCompositorThread创建硬件加速渲染环境的过程,如下所示:

scoped_refptr<cc::ContextProvider> SynchronousCompositorFactoryImpl::
    CreateOnscreenContextProviderForCompositorThread() {
  ......
  return webkit::gpu::ContextProviderInProcess::Create(
      WrapContext(CreateContext(service_, share_context_.get())),
      "Child-Compositor");
}
       这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_factory_impl.cc中。

       SynchronousCompositorFactoryImpl类的成员函数CreateOnscreenContextProviderForCompositorThread首先调有函数CreateContext创建一个In-Process Command Buffer GL接口,然后再调用另外一个函数WrapContext将这个In-Process Command Buffer GL接口封装在一个WebGraphicsContext3DInProcessCommandBufferImpl对象,最后调用ContextProviderInProcess类的静态成员函数Create将该WebGraphicsContext3DInProcessCommandBufferImpl对象封装在一个ContextProviderInProcess对象中。

       从前面Android WebView启动Chromium渲染引擎的过程分析一文可以知道,SynchronousCompositorFactoryImpl类的成员变量service_指向的就是一个DeferredGpuCommandService服务。函数CreateContext在创建In-Process Command Buffer GL接口的时候,会使用到这个DeferredGpuCommandService服务,如下所示:

scoped_ptr<gpu::GLInProcessContext> CreateContext(
    scoped_refptr<gpu::InProcessCommandBuffer::Service> service,
    gpu::GLInProcessContext* share_context) {
  ......

  scoped_ptr<gpu::GLInProcessContext> context(
      gpu::GLInProcessContext::Create(service,
                                      NULL /* surface */,
                                      false /* is_offscreen */,
                                      gfx::kNullAcceleratedWidget,
                                      gfx::Size(1, 1),
                                      share_context,
                                      false /* share_resources */,
                                      in_process_attribs,
                                      gpu_preference));
  return context.Pass();
}
       这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_factory_impl.cc中。 

       函数调用GLInProcessContext类的静态成员函数Create创建了一个In-Process Command Buffer GL接口,如下所示:

GLInProcessContext* GLInProcessContext::Create(
    scoped_refptr<gpu::InProcessCommandBuffer::Service> service,
    scoped_refptr<gfx::GLSurface> surface,
    bool is_offscreen,
    gfx::AcceleratedWidget window,
    const gfx::Size& size,
    GLInProcessContext* share_context,
    bool use_global_share_group,
    const GLInProcessContextAttribs& attribs,
    gfx::GpuPreference gpu_preference) {
  ......

  scoped_ptr<GLInProcessContextImpl> context(new GLInProcessContextImpl());
  if (!context->Initialize(surface,
                           is_offscreen,
                           use_global_share_group,
                           share_context,
                           window,
                           size,
                           attribs,
                           gpu_preference,
                           service))
    return NULL;

  return context.release();
}
       这个函数定义在文件external/chromium_org/gpu/command_buffer/client/gl_in_process_context.cc中。

       GLInProcessContext类的静态成员函数Create首先创建了一个GLInProcessContextImpl对象,然后调用这个GLInProcessContextImpl对象的成员函数Initialize对其进行初始化。在初始化的过程中,就会创建一个In-Process Command Buffer GL接口,如下所示:

bool GLInProcessContextImpl::Initialize(
    scoped_refptr<gfx::GLSurface> surface,
    bool is_offscreen,
    bool use_global_share_group,
    GLInProcessContext* share_context,
    gfx::AcceleratedWidget window,
    const gfx::Size& size,
    const GLInProcessContextAttribs& attribs,
    gfx::GpuPreference gpu_preference,
    const scoped_refptr<InProcessCommandBuffer::Service>& service) {
  ......

  command_buffer_.reset(new InProcessCommandBuffer(service));
  ......

  if (!command_buffer_->Initialize(surface,
                                   is_offscreen,
                                   window,
                                   size,
                                   attrib_vector,
                                   gpu_preference,
                                   wrapped_callback,
                                   share_command_buffer)) {
    ......
    return false;
  }

  // Create the GLES2 helper, which writes the command buffer protocol.
  gles2_helper_.reset(new gles2::GLES2CmdHelper(command_buffer_.get()));
  ......

  // Create the object exposing the OpenGL API.
  gles2_implementation_.reset(new gles2::GLES2Implementation(
      gles2_helper_.get(),
      share_group,
      transfer_buffer_.get(),
      bind_generates_resources,
      attribs.lose_context_when_out_of_memory > 0,
      command_buffer_.get()));
  ......

  return true;
}
       这个函数定义在文件external/chromium_org/gpu/command_buffer/client/gl_in_process_context.cc中。

       GLInProcessContextImpl类的成员函数Initialize创建In-Process Command Buffer GL接口的过程与前面Chromium硬件加速渲染的OpenGL命令执行过程分析一文提到的Command Buffer GL接口的创建过程是类似的。首先是创建一个Command Buffer,然后再将该Command Buffer封装在一个GLES2CmdHelper对象中。以后通过个GLES2CmdHelper对象就可以将要执行的GPU命令写入到它封装的Command Buffer中去。最后又会使用前面封装得到的GLES2CmdHelper对象创建一个GLES2Implementation对象。这个GLES2Implementation对象就用来描述的一个In-Process Command Buffer GL或者Command Buffer GL接口。

       In-Process Command Buffer GL接口与Command Buffer GL接口的最大区别就在于它们使用了不同的Command Buffer。In-Process Command Buffer GL使用的Command Buffer是一个In-Process Command Buffer,而Command Buffer GL接口使用的Command Buffer是一个Command Buffer Proxy。In-Process Command Buffer会将要执行的GPU命令发送给App的Render Thread处理,而Command Buffer Proxy会将要执行的GPU命令发送给Chromium的GPU进程/线程处理。

       接下来,我们就重点分析In-Process Command Buffer的创建过程,以便后面可以更好地理解它是怎么将要执行的GPU命令发送给App的Render Thread处理的。

       从前面的调用过程可以知道,参数service描述的是一个DeferredGpuCommandService服务。这个DeferredGpuCommandService服务将会用来创建In-Process Command Buffer,如下所示:

InProcessCommandBuffer::InProcessCommandBuffer(
    const scoped_refptr<Service>& service)
    : ......,
      service_(service.get() ? service : GetDefaultService()),
      ...... {
  ......
}
       这个函数定义在文件external/chromium_org/gpu/command_buffer/service/in_process_command_buffer.cc中。

       在创建In-Process Command Buffer的过程中,如果指定了一个Service,那么以后就会通过这个Service执行GPU命令。在我们这个情景中,指定的Service即为一个DeferredGpuCommandService服务。因此,这时候InProcessCommandBuffer类的成员变量service_指向的是一个DeferredGpuCommandService服务。

       如果在创建In-Process Command Buffer的过程中,没有指定一个Service,那么InProcessCommandBuffer的构造函数就会通过调用另外一个成员函数GetDefaultService获得一个默认的Service,用来执行GPU命令。这个默认的Service实际上就是一个自行创建的GPU线程。

       回到GLInProcessContextImpl类的成员函数Initialize中,它创建了一个In-Process Command Buffer之后,接下来还会调用这个InProcessCommandBuffer类的成员函数Initialize对它进行初始化,如下所示:

bool InProcessCommandBuffer::Initialize(
    scoped_refptr<gfx::GLSurface> surface,
    bool is_offscreen,
    gfx::AcceleratedWidget window,
    const gfx::Size& size,
    const std::vector<int32>& attribs,
    gfx::GpuPreference gpu_preference,
    const base::Closure& context_lost_callback,
    InProcessCommandBuffer* share_group) {
  ......

  gpu::Capabilities capabilities;
  InitializeOnGpuThreadParams params(is_offscreen,
                                     window,
                                     size,
                                     attribs,
                                     gpu_preference,
                                     &capabilities,
                                     share_group);

  base::Callback<bool(void)> init_task =
      base::Bind(&InProcessCommandBuffer::InitializeOnGpuThread,
                 base::Unretained(this),
                 params);

  base::WaitableEvent completion(true, false);
  bool result = false;
  QueueTask(
      base::Bind(&RunTaskWithResult<bool>, init_task, &result, &completion));
  completion.Wait();

  ......
  return result;
}
       这个函数定义在文件external/chromium_org/gpu/command_buffer/service/in_process_command_buffer.cc中。

       InProcessCommandBuffer类的成员函数Initialize所做的事情就是通过成员变量service_指向的DeferredGpuCommandService服务请求在App的Render Thread中调用InProcessCommandBuffer类的成员函数InitializeOnGpuThread,以便对当前正在创建的In-Process Command Buffer进行初始化。

       后面分析Render端执行的GPU命令的过程时,我们就会清楚地看到DeferredGpuCommandService服务是如何请求在App的Render Thread执行一个操作的。现在我们主要关注In-Process Command Buffer的初始化过程,也就是InProcessCommandBuffer类的成员函数InitializeOnGpuThread的实现,如下所示:

bool InProcessCommandBuffer::InitializeOnGpuThread(
    const InitializeOnGpuThreadParams& params) {
  ......

  scoped_ptr<CommandBufferService> command_buffer(
      new CommandBufferService(transfer_buffer_manager_.get()));
  command_buffer->SetPutOffsetChangeCallback(base::Bind(
      &InProcessCommandBuffer::PumpCommands, gpu_thread_weak_ptr_));
  ......

  decoder_.reset(gles2::GLES2Decoder::Create(
      params.context_group
          ? params.context_group->decoder_->GetContextGroup()
          : new gles2::ContextGroup(NULL,
                                    NULL,
                                    NULL,
                                    service_->shader_translator_cache(),
                                    NULL,
                                    bind_generates_resource)));

  gpu_scheduler_.reset(
      new GpuScheduler(command_buffer.get(), decoder_.get(), decoder_.get()));
  ......
  command_buffer_ = command_buffer.Pass();

  decoder_->set_engine(gpu_scheduler_.get());

  ......
}
       这个函数定义在文件external/chromium_org/gpu/command_buffer/service/in_process_command_buffer.cc中。

       InProcessCommandBuffer类的成员函数InitializeOnGpuThread首先是创建了一个Command Buffer Service,并且保存在成员变量command_buffer_中。这个Command Buffer Service负责管理Command Buffer的状态,例如第一个等待执行的GPU命令的位置,以及最新写入的GPU命令的位置,等等。

       InProcessCommandBuffer类的成员函数InitializeOnGpuThread创建了一个Command Buffer Service,会调用它的成员函数SetPutOffsetChangeCallback,用来设置一个Put Offset Change Callback,如下所示:

void CommandBufferService::SetPutOffsetChangeCallback(
    const base::Closure& callback) {
  put_offset_change_callback_ = callback;
}
       这个函数定义在文件external/chromium_org/gpu/command_buffer/service/command_buffer_service.cc中。

       这个Callback指定为当前正在创建的In-Process Command Buffer的成员函数PumpCommands。当我们往Command Buffer写入了新的GPU命令时,这个Callback就会被执行,也就是InProcessCommandBuffer类的成员函数PumpCommands会被调用。

       InProcessCommandBuffer类的成员函数PumpCommands在调用的过程中,就会通过一个Gpu Scheduler和一个GLES2 Decoder执行新写入到Command Buffer中的GPU命令。Gpu Scheduler在执行一个GPU命令之前,会将当前的OpenGL上下文切换至该GPU命令所属的OpenGL上下文,这样它就可以同时支持多个OpenGL上下文。GLES2 Decoder负责从Command Buffer中解析出每一个待执行的GPU命令及其携带的参数,这样就可以通过调用对应的OpenGL函数执行它们。关于Gpu Scheduler和一个GLES2 Decoder执行GPU命令的过程,可以参考前面Chromium硬件加速渲染的OpenGL命令执行过程分析一文。

       回到前面分析的InProcessCommandBuffer类的成员函数InitializeOnGpuThread中,上述Gpu Scheduler和GLES2 Decoder也是在InProcessCommandBuffer类的成员函数InitializeOnGpuThread中创建的。创建出来之后,就分别保存在InProcessCommandBuffer类的成员变量gpu_scheduler_和decoder_中。

       这一步执行完成后,回到前面分析的SynchronousCompositorFactoryImpl类的成员函数CreateOnscreenContextProviderForCompositorThread中,这时候它就获得了一个In-Process Command Buffer GL接口。这个In-Process Command Buffer GL接口是封装在一个GLInProcessContextImpl对象中的。这个GLInProcessContextImpl对象接下来又会通过函数WrapContext封装在一个WebGraphicsContext3DInProcessCommandBufferImpl对象中,如下所示:

scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> WrapContext(
    scoped_ptr<gpu::GLInProcessContext> context) {
  ......

  return scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>(
      WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
          context.Pass(), GetDefaultAttribs()));
}
       这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_factory_impl.cc中。

       函数WrapContext通过调用WebGraphicsContext3DInProcessCommandBufferImpl类的静态成员函数WrapContext将一个GLInProcessContextImpl对象封装在一个WebGraphicsContext3DInProcessCommandBufferImpl对象中,如下所示:

scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl>
WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
    scoped_ptr< ::gpu::GLInProcessContext> context,
    const blink::WebGraphicsContext3D::Attributes& attributes) {
  bool lose_context_when_out_of_memory = false;  // Not used.
  bool is_offscreen = true;                      // Not used.
  return make_scoped_ptr(new WebGraphicsContext3DInProcessCommandBufferImpl(
      context.Pass(),
      attributes,
      lose_context_when_out_of_memory,
      is_offscreen,
      gfx::kNullAcceleratedWidget /* window. Not used. */));
}
       这个函数定义在文件external/chromium_org/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc中。

       WebGraphicsContext3DInProcessCommandBufferImpl类的构造函数会将要封装的GLInProcessContextImpl对象保存在成员变量context_中,如下所示:

WebGraphicsContext3DInProcessCommandBufferImpl::
    WebGraphicsContext3DInProcessCommandBufferImpl(
        scoped_ptr< ::gpu::GLInProcessContext> context,
        const blink::WebGraphicsContext3D::Attributes& attributes,
        bool lose_context_when_out_of_memory,
        bool is_offscreen,
        gfx::AcceleratedWidget window)
    : ......,
      context_(context.Pass()) {
  ......
}
       这个函数定义在文件external/chromium_org/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc中。

       这一步执行完成后,继续回到前面分析的SynchronousCompositorFactoryImpl类的成员函数CreateOnscreenContextProviderForCompositorThread中,这时候它就获得了一个WebGraphicsContext3DInProcessCommandBufferImpl对象。这个WebGraphicsContext3DInProcessCommandBufferImpl对象通过一个GLInProcessContextImpl对象间接地保存了前面创建的In-Process Command Buffer GL接口

       SynchronousCompositorFactoryImpl类的成员函数CreateOnscreenContextProviderForCompositorThread最后又会调用ContextProviderInProcess类的静态成员函数Create将上述WebGraphicsContext3DInProcessCommandBufferImpl对象封装在一个ContextProviderInProcess对象中,如下所示:

scoped_refptr<ContextProviderInProcess> ContextProviderInProcess::Create(
    scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d,
    const std::string& debug_name) {
  ......
  return new ContextProviderInProcess(context3d.Pass(), debug_name);
}
       这个函数定义在文件external/chromium_org/webkit/common/gpu/context_provider_in_process.cc中。

       ContextProviderInProcess对象会将要封装的WebGraphicsContext3DInProcessCommandBufferImpl对象保存在成员变量context_中,如下所示:

ContextProviderInProcess::ContextProviderInProcess(
    scoped_ptr<WebGraphicsContext3DInProcessCommandBufferImpl> context3d,
    const std::string& debug_name)
    : context3d_(context3d.Pass()),
      ...... {
  ......
}
      这个函数定义在文件external/chromium_org/webkit/common/gpu/context_provider_in_process.cc中。

      这一步执行完成后,SynchronousCompositorImpl类的成员函数InitializeHwDraw,这时候它就是初始化了一个硬件加速渲染环境。这个硬件加速渲染环境就是通过前面创建的ContextProviderInProcess对象描述。这个ContextProviderInProcess对象接来会设置给SynchronousCompositorImpl类的成员变量output_surface_描述的一个Synchronous Compositor Output Surface。这是通过调用SynchronousCompositorOutputSurface类的成员函数InitializeHwDraw实现的,如下所示:

bool SynchronousCompositorOutputSurface::InitializeHwDraw(
    scoped_refptr<cc::ContextProvider> onscreen_context_provider) {
  ......

  return InitializeAndSetContext3d(onscreen_context_provider);
}
       这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_output_surface.cc中。

       SynchronousCompositorOutputSurface类的成员函数InitializeHwDraw会调用另外一个成员函数InitializeAndSetContext3d将参数onscreen_context_provider指向的ContextProviderInProcess对象保存在内部。以后通过这个ContextProviderInProcess对象,就可以获得前面创建的In-Process Command Buffer GL接口了。

       SynchronousCompositorOutputSurface类的成员函数InitializeAndSetContext3d是从父类OutputSurface继承下来的,它的实现如下所示:

bool OutputSurface::InitializeAndSetContext3d(
    scoped_refptr<ContextProvider> context_provider) {
  ......

  bool success = false;
  if (context_provider->BindToCurrentThread()) {
    context_provider_ = context_provider;
    ......
    success = true;
  }

  ......

  return success;
}
       这个函数定义在文件external/chromium_org/cc/output/output_surface.cc中。

       OutputSurface类的成员函数InitializeAndSetContext3d首先会调用参数context_provider指向的ContextProviderInProcess对象的成员函数BindToCurrentThread将其引用的In-Process Command Buffer GL接口设置为当前线程所使用的GL接口。当前线程即为Render端的Compositor线程。有了这个GL接口之后,Render端的Compositor线程就可以执行GPU操作了。

       成功将参数context_provider指向的ContextProviderInProcess对象引用的In-Process Command Buffer GL接口设置为当前线程所使用的GL接口之后,该ContextProviderInProcess对象就会保存在OutputSurface类的成员变量context_provider_中。

       接下来我们继续分析ContextProviderInProcess类的成员函数BindToCurrentThread为当前线程设置Process Command Buffer GL接口的过程,如下所示:

bool ContextProviderInProcess::BindToCurrentThread() {
  ......

  if (!context3d_->makeContextCurrent())
    return false;

  ......
  return true;
}
       这个函数定义在文件external/chromium_org/webkit/common/gpu/context_provider_in_process.cc中。

       从前面的分析可以知道,ContextProviderInProcess类的成员变量context3d_指向的是一个WebGraphicsContext3DInProcessCommandBufferImpl对象。ContextProviderInProcess类的成员函数BindToCurrentThread会调用这个WebGraphicsContext3DInProcessCommandBufferImpl对象的成员函数makeContextCurrent将前面创建的In-Process Command Buffer GL接口设置为当前线程所使用的GL接口,如下所示:

bool WebGraphicsContext3DInProcessCommandBufferImpl::makeContextCurrent() {
  if (!MaybeInitializeGL())
    return false;
  ::gles2::SetGLContext(GetGLInterface());
  return context_ && !isContextLost();
}
       这个函数定义在文件external/chromium_org/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc中。

       WebGraphicsContext3DInProcessCommandBufferImpl类的成员函数makeContextCurrent首先调用成员函数MaybeInitializeGL检查是否已经为当前线程初始化过GL接口了。如果还没有初始化,那么就会进行初始化,如下所示:

bool WebGraphicsContext3DInProcessCommandBufferImpl::MaybeInitializeGL() {
  if (initialized_)
    return true;
  ......

  real_gl_ = context_->GetImplementation();
  setGLInterface(real_gl_);

  ......

  initialized_ = true;
  return true;
}
       这个函数定义在文件external/chromium_org/webkit/common/gpu/webgraphicscontext3d_in_process_command_buffer_impl.cc中。

       当WebGraphicsContext3DInProcessCommandBufferImpl类的成员变量initialized_的值等于true的时候,就表示当前线程初始化过GL接口了。另一方面,如果当前线程还没有初始化过GL接口,那么WebGraphicsContext3DInProcessCommandBufferImpl类的成员函数MaybeInitializeGL就会进行初始化。

       从前面的分析可以知道,WebGraphicsContext3DInProcessCommandBufferImpl类的成员变量context_指向的是一个GLInProcessContextImpl对象。调用这个GLInProcessContextImpl对象的成员函数可以获得它内部封装一个GLES2Implementation对象。这个GLES2Implementation对象描述的就是一个In-Process Command Buffer GL接口。

       WebGraphicsContext3DInProcessCommandBufferImpl类的成员函数MaybeInitializeGL获得了上述In-Process Command Buffer GL接口之后,会调用另外一个成员函数setGLInterface将其保存起来。

       WebGraphicsContext3DInProcessCommandBufferImpl类的成员函数setGLInterface是从父类WebGraphicsContext3DImpl继承下来的,它的实现如下所示:

class WEBKIT_GPU_EXPORT WebGraphicsContext3DImpl  
    : public NON_EXPORTED_BASE(blink::WebGraphicsContext3D) {  
 public:  
  ......  
  
  ::gpu::gles2::GLES2Interface* GetGLInterface() {  
    return gl_;  
  }  
  
 protected:  
  ......  
  
  void setGLInterface(::gpu::gles2::GLES2Interface* gl) {  
    gl_ = gl;  
  }  
  
  ......  
  
  ::gpu::gles2::GLES2Interface* gl_;  
  ......  
};  
       这个函数定义在文件external/chromium_org/webkit/common/gpu/webgraphicscontext3d_impl.h中。

       WebGraphicsContext3DImpl类的成员函数setGLInterface将参数描述的In-Process Command Buffer GL接口保存在成员变量gl_中。这个In-Process Command Buffer GL接口可以通过调用WebGraphicsContext3DImpl类的另外一个成员函数GetGLInterface获得。

       这一步执行完成后,回到前面分析的WebGraphicsContext3DInProcessCommandBufferImpl类的成员函数makeContextCurrent,它接下来又会调用从父类WebGraphicsContext3DImpl继承下来的成员函数GetGLInterface获得前面所保存的In-Process Command Buffer GL接口,并且将该In-Process Command Buffer GL接口设置为当前线程的GL接口,也就是OpenGL调用接口。这是通过调用函数gles2::SetGLContext实现的,如下所示:

static gpu::ThreadLocalKey g_gl_context_key;   

......
 
gpu::gles2::GLES2Interface* GetGLContext() {  
  return static_cast<gpu::gles2::GLES2Interface*>(  
    gpu::ThreadLocalGetValue(g_gl_context_key));  
}
 
void SetGLContext(gpu::gles2::GLES2Interface* context) {  
  gpu::ThreadLocalSetValue(g_gl_context_key, context);  
}  
       这两个函数定义在文件external/chromium_org/gpu/command_buffer/client/gles2_lib.cc中。

       参数context描述的In-Process Command Buffer GL接口将被保存在全局变量g_gl_context_key所描述的一个线程局部储存中,作为当前线程所使用的OpenGL接口。以后通过调用另外一个函数gles2::GetGLContext就可以获得保存在这个线程局部储存中的In-Process Command Buffer GL接口。

       这一步执行完成后,以后Render端的Compositor线程直接调用OpenGL函数glXXX时,就会通过In-Process Command Buffer GL接口执行指定的GPU的操作。从OpenGL函数glXXX调用到In-Process Command Buffer GL接口的原理可以参考前面Chromium网页GPU光栅化原理分析一文。

       Render端的Compositor线程除了可以通过OpenGL函数glXXX使用In-Process Command Buffer GL接口,还可以通过它为网页创建的Synchronous Compositor Output Surface使用In-Process Command Buffer GL接口。接下来,我们就以Render端的Compositor线程执行GPU光栅化操作为例,说明它执行GPU命令的过程。

       从前面Chromium网页GPU光栅化原理分析一文可以知道,当Render端的Compositor线程是通过一个Skia Canvas对网页UI进行GPU光栅化操作的。这个Skia Canvas又是通过一个类型为SkSurface_Gpu的Skia Surface获得的。这个类型为SkSurface_Gpu的Skia Surface是通过调用DirectRasterBuffer类的成员函数CreateSurface创建的,如下所示:

skia::RefPtr<SkSurface> ResourceProvider::DirectRasterBuffer::CreateSurface() {  
  skia::RefPtr<SkSurface> surface;  
  switch (resource()->type) {  
    case GLTexture: {  
      ......  
      class GrContext* gr_context = resource_provider()->GrContext();  
      if (gr_context) {  
        GrBackendTextureDesc desc;  
        ......
 
        skia::RefPtr<GrTexture> gr_texture =  
            skia::AdoptRef(gr_context->wrapBackendTexture(desc));  
        ......
  
        surface = skia::AdoptRef(SkSurface::NewRenderTargetDirect(  
            gr_texture->asRenderTarget(), text_render_mode));  
      }  
      break;  
    }  
    ......
  }  
  return surface;  
}
       这个函数定义在文件external/chromium_org/cc/resources/resource_provider.cc中。

       DirectRasterBuffer类的成员函数CreateSurface的详细实现可以参考前面Chromium网页GPU光栅化原理分析一文。这里我们所关注的重点是它通过调用ResourceProvider类的成员函数GrContext获得一个In-Process Command Buffer GL接口的过程。这个In-Process Command Buffer GL接口会传递给这里所创建的类型为SkSurface_Gpu的Skia Surface。有了In-Process Command Buffer GL接口之后,类型为SkSurface_Gpu的Skia Surface就可以通过GPU对网页的UI进行光栅化了。

       DirectRasterBuffer类的成员函数CreateSurface首先是调用成员函数resource_provider获得一个ResourceProvider对象。这个ResourceProvider对象负责管理网页在渲染过程中所要使用到的资源。有这个ResourceProvider对象之后,就可以调用它的成员函数GrContext获得一个In-Process Command Buffer GL接口,如下所示:

class GrContext* ResourceProvider::GrContext() const {
  ContextProvider* context_provider = output_surface_->context_provider();
  return context_provider ? context_provider->GrContext() : NULL;
}
      这个函数定义在文件external/chromium_org/cc/resources/resource_provider.cc中。

      ResourceProvider类的成员变量output_surface_指向的就是一个SynchronousCompositorOutputSurface对象。ResourceProvider类的成员函数GrContext会调用这个SynchronousCompositorOutputSurface对象的成员函数context_provider获得一个Context Provider。

      SynchronousCompositorOutputSurface对象的成员函数context_provider是从父类OutputSurface继承下来的,它的实现如下所示:

class CC_EXPORT OutputSurface {
  ......

  scoped_refptr<ContextProvider> context_provider() const {
    return context_provider_.get();
  }

  ......
};
       这个函数定义在文件external/chromium_org/cc/output/output_surface.h中。

       从前面的分析可以知道,此时OutputSurface类的成员变量context_provider_指向的是一个ContextProviderInProcess对象。OutputSurface类的成员函数context_provider将这个ContextProviderInProcess对象返回给调用者。

       回到前面分析的ResourceProvider类的成员函数GrContext中,这时候它就获得了一个ContextProviderInProcess对象。接下来它继续调用这个ContextProviderInProcess对象的成员函数GrContext获得一个GrContextForWebGraphicsContext3D对象,如下所示:

class GrContext* ContextProviderInProcess::GrContext() {
  ......

  if (gr_context_)
    return gr_context_->get();

  gr_context_.reset(
      new webkit::gpu::GrContextForWebGraphicsContext3D(context3d_.get()));
  return gr_context_->get();
}
       这个函数定义在文件external/chromium_org/webkit/common/gpu/context_provider_in_process.cc中。

       ContextProviderInProcess类的成员函数GrContext首先判断成员变量gr_context_是否指向了一个GrContextForWebGraphicsContext3D对象。如果已经指向,那么就会将该GrContextForWebGraphicsContext3D对象返回给调用者。

       另一方面,如果ContextProviderInProcesGrContextForWebGraphicsContext3Ds类的成员变量gr_context_还没有指向一个GrContextForWebGraphicsContext3D对象,那么ContextProviderInProcess类的成员函数GrContext就会先创建该GrContextForWebGraphicsContext3D对象,然后再将它返回给调用者。

       在创建GrContextForWebGraphicsContext3D对象的时候,会使用到ContextProviderInProcess类的成员变量context3d_。从前面的分析可以知道,ContextProviderInProcess类的成员变量context3d_指向的是一个WebGraphicsContext3DInProcessCommandBufferImpl对象。这个WebGraphicsContext3DInProcessCommandBufferImpl对象内部封装了一个In-Process Command Buffer GL接口。

       因此,ContextProviderInProcess类的成员函数GrContext创建出来的GrContextForWebGraphicsContext3D对象也会间接地引用了一个In-Process Command Buffer GL接口。前面创建的类型为SkSurface_Gpu的Skia Surface在光栅化网页UI的时候,就会使用到这个In-Process Command Buffer GL接口,也就是会将要执行的GPU命令写入到一个In-Process Command Buffer中去。

       写入到In-Process Command Buffer中的命令会被周期性地提交给DeferredGpuCommandService服务处理。这是通过调用InProcessCommandBuffer类的成员函数Flush实现的。或者我们也可以主动地调用In-Process Command Buffer GL接口提供的成员函数Flush将写入在In-Process Command Buffer中的命令会被周期性地提交给DeferredGpuCommandService服务。这个主动提交的操作最终也是通过调用InProcessCommandBuffer类的成员函数Flush实现的。这一点可以参考前面Chromium硬件加速渲染的OpenGL命令执行过程分析一文。

       接下来,我们就从InProcessCommandBuffer类的成员函数Flush开始,分析Render端在使用GPU光栅化网页UI的过程中,是如何执行GPU命令的,如下所示:

void InProcessCommandBuffer::Flush(int32 put_offset) {
  ......

  last_put_offset_ = put_offset;
  base::Closure task = base::Bind(&InProcessCommandBuffer::FlushOnGpuThread,
                                  gpu_thread_weak_ptr_,
                                  put_offset);
  QueueTask(task);
}
       这个函数定义在文件external/chromium_org/gpu/command_buffer/service/in_process_command_buffer.cc中。

       参数put_offset表示最新写入的GPU命令在In-Process Command Buffer中的位置。InProcessCommandBuffer类的成员函数Flush首先将这个位置记录在成员变量last_put_offset_中。

       InProcessCommandBuffer类的成员函数Flush接下来创建了一个Task。这个Task绑定了InProcessCommandBuffer类的成员函数FlushOnGpuThread。接下来这个Task会被提交给DeferredGpuCommandService服务处理。这是通过调用InProcessCommandBuffer类的成员函数QueueTask实现的,如下所示:

class GPU_EXPORT InProcessCommandBuffer : public CommandBuffer,
                                          public GpuControl {
 ......

 private:
  ......

  void QueueTask(const base::Closure& task) { service_->ScheduleTask(task); }

  ......
}
      这个函数定义在文件external/chromium_org/gpu/command_buffer/service/in_process_command_buffer.h中。

      从前面的分析可以知道,InProcessCommandBuffer类的成员变量service_描述的就是一个DeferredGpuCommandService服务。InProcessCommandBuffer类的成员函数QueueTask通过调用这个DeferredGpuCommandService服务的成员函数ScheduleTask调度执行参数task描述的Task。

      DeferredGpuCommandService类的成员函数ScheduleTask的实现如下所示:

void DeferredGpuCommandService::ScheduleTask(const base::Closure& task) {
  {
    base::AutoLock lock(tasks_lock_);
    tasks_.push(task);
  }
  if (ScopedAllowGL::IsAllowed()) {
    RunTasks();
  } else {
    RequestProcessGL();
  }
}
       这个函数定义在文件external/chromium_org/android_webview/browser/deferred_gpu_command_service.cc中。

       DeferredGpuCommandService类的成员函数ScheduleTask首先将参数task描述的Task保存在成员变量tasks_描述的一个std::queue中。

       DeferredGpuCommandService类的成员函数ScheduleTask接下来通过调用ScopedAllowGL类的静态成员函数IsAllowed判断当前线程是否允许直接执行GPU命令,也就是当前线程是否是一个GPU线程。如果是的话,那么就会调用成员函数RunTasks执行参数task描述的Task,如下所示:

void DeferredGpuCommandService::RunTasks() {
  bool has_more_tasks;
  {
    base::AutoLock lock(tasks_lock_);
    has_more_tasks = tasks_.size() > 0;
  }

  while (has_more_tasks) {
    base::Closure task;
    {
      base::AutoLock lock(tasks_lock_);
      task = tasks_.front();
      tasks_.pop();
    }
    task.Run();
    {
      base::AutoLock lock(tasks_lock_);
      has_more_tasks = tasks_.size() > 0;
    }
  }
}
       这个函数定义在文件external/chromium_org/android_webview/browser/deferred_gpu_command_service.cc中。

       DeferredGpuCommandService类的成员函数RunTasks会依次执行保存在成员变量tasks_描述的std::queue中的每一个Task。从前面的分析可以知道,这个std::queue保存了一个Task。这个Task绑定了InProcessCommandBuffer类的成员函数FlushOnGpuThread。因此,当该Task被执行的时候,InProcessCommandBuffer类的成员函数FlushOnGpuThread就会被调用。在调用的过程中,就会执行那些新写入到In-Process Command Buffer的GPU命令。

       DeferredGpuCommandService类的成员函数ScheduleTask可以直接调用成员函数RunTasks执行GPU命令的情况发生在Browser端合成网页UI的过程中。这时候Browser端运行在App的Render Thread中,并且它会通过ScopedAllowGL类标记App的Render Thread可以执行GPU命令。这样DeferredGpuCommandService类的成员函数ScheduleTask就可以知道它可以直接执行GPU命令了。

       在我们这个情景中,正在执行的是网页UI的光栅化操作。这个操作是发生在Render端的Compositor线程中的。Render端的Compositor线程不是一个GPU线程,因此这时候DeferredGpuCommandService类的成员函数ScheduleTask就不能直接调用成员函数RunTasks执行GPU命令,而是要通过调用另外一个成员函数RequestProcessGL请求App的Render Thread执行。

       另外一个情景,也就是Render端绘制网页UI的情景,也是发生在Render端的Compositor线程。这时候DeferredGpuCommandService类的成员函数ScheduleTask也需要调用成员函数RequestProcessGL请求App的Render Thread执行绘制网页UI所需要执行的GPU命令。

       接下来,我们就继续分析DeferredGpuCommandService类的成员函数RequestProcessGL,以便了解它请求App的Render Thread执行GPU命令的过程,如下所示:

void DeferredGpuCommandService::RequestProcessGL() {
  SharedRendererState* renderer_state =
      GLViewRendererManager::GetInstance()->GetMostRecentlyDrawn();
  ......
  renderer_state->ClientRequestDrawGL();
}
       这个函数定义在文件external/chromium_org/android_webview/browser/deferred_gpu_command_service.cc中。

       我们在前面Android WebView启动Chromium渲染引擎的过程分析一文中提到,在Chromium渲染引擎中,存在一个GLViewRendererManager单例对象。这个GLViewRendererManager单例对象记录了当前有哪些WebView是采用硬件加速方式绘制的。通过调用这个GLViewRendererManager对象的成员函数GetMostRecentlyDrawn可以获得一个SharedRendererState对象。这个SharedRendererState对象的创建过程可以参考前面Android WebView启动Chromium渲染引擎的过程分析一文,它记录了当前正在绘制的Android WebView的状态。

       获得了与当前正在绘制的Android WebView关联的一个SharedRendererState对象之后,DeferredGpuCommandService类的成员函数RequestProcessGL就可以调用它的成员函数ClientRequestDrawGL请求App的Render Thread执行GPU命令,如下所示:

void SharedRendererState::ClientRequestDrawGL() {
  if (ui_loop_->BelongsToCurrentThread()) {
    ......
    ClientRequestDrawGLOnUIThread();
  } else {
    ......
    base::Closure callback;
    {
      base::AutoLock lock(lock_);
      callback = request_draw_gl_closure_;
    }
    ui_loop_->PostTask(FROM_HERE, callback);
  }
}
       这个函数定义在文件external/chromium_org/android_webview/browser/shared_renderer_state.cc中。

       从前面Android WebView启动Chromium渲染引擎的过程分析一文可以知道,SharedRendererState类的成员变量ui_loop_描述的就是Chromium的Browser端的Native UI Message Loop。通过这个Native UI Message Loop可以判断当前线程是否就是App的UI线程。如果是的话,那么SharedRendererState类的成员函数ClientRequestDrawGL就会直接调用另外一个成员函数ClientRequestDrawGLOnUIThread请求App的Render Thread执行GPU命令。

       如果当前线程不是App的UI线程,那么SharedRendererState类的成员函数ClientRequestDrawGL就会向Chromium的Browser端的Native UI Message Loop发送一个Task。这个Task由SharedRendererState类的成员变量request_draw_gl_closure_描述,它绑定的函数为SharedRendererState类的成员函数ClientRequestDrawGLOnUIThread。这样做的目的是让SharedRendererState类的成员函数ClientRequestDrawGLOnUIThread运行在App的UI线程中,以便可以通过App的UI线程来请求App的Render Thread执行GPU命令。

       SharedRendererState类的成员函数ClientRequestDrawGLOnUIThread的实现如下所示:

void SharedRendererState::ClientRequestDrawGLOnUIThread() {
  ......

  if (!client_on_ui_->RequestDrawGL(NULL, false)) {
    ......
  }
}
       这个函数定义在文件external/chromium_org/android_webview/browser/shared_renderer_state.cc中。

       从前面Android WebView启动Chromium渲染引擎的过程分析一文可以知道,SharedRendererState类的成员变量client_on_ui_指向的是一个Native层的AwContents对象。SharedRendererState类的成员函数ClientRequestDrawGLOnUIThread通过调用这个AwContents对象的成员函数RequestDrawGL请求App的Render Thread执行GPU命令,如下所示:

bool AwContents::RequestDrawGL(jobject canvas, bool wait_for_completion) {
  ......
  JNIEnv* env = AttachCurrentThread();
  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
  .......
  return Java_AwContents_requestDrawGL(
      env, obj.obj(), canvas, wait_for_completion);
}
       这个函数定义在文件external/chromium_org/android_webview/native/aw_contents.cc中。

       从前面Android WebView启动Chromium渲染引擎的过程分析一文可以知道,每一个Native层的AwContents对象在Java层都有一个对应的AwContents对象。这个Java层的AwContents对象就保存在Native层的AwContents对象的成员变量java_ref_中。AwContents类的成员函数RequestDrawGL通过JNI方法Java_AwContents_requestDrawGL调用上述的Java层AwContents对象的成员函数requestDrawGL,用来请求App的Render Thread执行GPU命令。

       Java层的AwContents类的成员函数requestDrawGL的实现如下所示:

public class AwContents {
    ......

    @CalledByNative
    private boolean requestDrawGL(Canvas canvas, boolean waitForCompletion) {
        return mNativeGLDelegate.requestDrawGL(canvas, waitForCompletion, mContainerView);
    }

    ......
}
      这个函数定义在文件external/chromium_org/android_webview/java/src/org/chromium/android_webview/AwContents.java中。

      从前面Android WebView启动Chromium渲染引擎的过程分析一文可以知道,AwContents类的成员变量mNativeGLDelegate指向的是一个WebViewNativeGLDelegate对象。AwContents类的成员函数requestDrawGL调用这个WebViewNativeGLDelegate对象的成员函数requestDrawGL请求App的Render Thread执行GPU命令,如下所示:

class WebViewChromium implements WebViewProvider,
          WebViewProvider.ScrollDelegate, WebViewProvider.ViewDelegate {
    ......

    private DrawGLFunctor mGLfunctor;
    ......

    private class WebViewNativeGLDelegate implements AwContents.NativeGLDelegate {
        @Override
        public boolean requestDrawGL(Canvas canvas, boolean waitForCompletion,
                View containerView) {
            if (mGLfunctor == null) {
                mGLfunctor = new DrawGLFunctor(mAwContents.getAwDrawGLViewContext());
            }
            return mGLfunctor.requestDrawGL(
                    (HardwareCanvas) canvas, containerView.getViewRootImpl(), waitForCompletion);
        }

        ......
    }

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

       WebViewNativeGLDelegate类的成员函数requestDrawGL首先判断外部类WebViewChromium的成员变量mGLFunctor是否指向了一个DrawGLFunctor对象。如果指向了,那么就会调用它的成员函数requestDrawGL请求App的Render Thread执行GPU命令。

       另一方面,如果WebViewChromium类的成员变量mGLFunctor还没有指向一个DrawGLFunctor对象,那么WebViewNativeGLDelegate类的成员函数requestDrawGL就会创建这个DrawGLFunctor对象。创建过程如下所示:

class DrawGLFunctor {
    ......

    public DrawGLFunctor(long viewContext) {
        mDestroyRunnable = new DestroyRunnable(nativeCreateGLFunctor(viewContext));
        ......
    }

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

      DrawGLFunctor类的构造函数首先会调用成员函数nativeCreateGLFunctor获得一个Native层的DrawGLFunctor对象,然后再使用这个Native层的DrawGLFunctor对象创建一个DestroyRunnable对象,如下所示:

class DrawGLFunctor {
    ......

    private static final class DestroyRunnable implements Runnable {
        ......
        long mNativeDrawGLFunctor;
        DestroyRunnable(long nativeDrawGLFunctor) {
            mNativeDrawGLFunctor = nativeDrawGLFunctor;
        }

        ......
    }

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

      DestroyRunnable类的构造函数主要就是将参数nativeDrawGLFunctor描述的Native层DrawGLFunctor对象保存在成员变量mNativeDrawGLFunctor中。

      接下来我们继续分析Native层的DrawGLFunctor对象的创建过程,也就是DrawGLFunctor类的成员函数nativeCreateGLFunctor的实现。wGLFunctor类的成员函数nativeCreateGLFunctor是一个JNI方法,它由C++层的函数CreateGLFunctor实现,如下所示:

jlong CreateGLFunctor(JNIEnv*, jclass, jlong view_context) {
  RaiseFileNumberLimit();
  return reinterpret_cast<jlong>(new DrawGLFunctor(view_context));
}
      这个函数定义在文件frameworks/webview/chromium/plat_support/draw_gl_functor.cpp中。

      从这里可以看到,函数CreateGLFunctor创建的是一个Native层的DrawGLFunctor对象。这个DrawGLFunctor对象是用来描述Chromium渲染引擎请求App的Render Thread执行的GPU操作集合。

      这一步执行完成后,回到前面分析的WebViewNativeGLDelegate类的成员函数requestDrawGL中,接下来我们继续分析它调用外部类WebViewChromium类的成员变量mGLFunctor指向一个Java层的DrawGLFunctor对象的成员函数requestDrawGL请求App的Render Thread执行GPU命令,如下所示:

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中。

       从前面的调用过程可以知道,参数canvas的值为null,另外一个参数waitForCompletion的值等于false。

       当参数canvas的值为null的时候,表示Chromium渲染引擎直接请求App的Render Thread执行GPU命令。这种情况一般就是发生在Render端光栅化网页UI的过程中。

       当参数canvas的值不等于null时,它指向一个Hardware Canvas,表示Chromium渲染引擎请求App的UI线程先将要执行的GPU命令记录在App UI的Display List中。等到该Display List同步给App的Render Thread,并且被App的Render Thread重放的时候,再执行请求的GPU命令。这种情况发生在Render端绘制网页UI的过程中。

       另外一个参数waitForCompletion表示App的UI线程是否需要同步等待App的Render Thread执行完成请求的GPU命令。

       在我们这个情景中,DrawGLFunctor类的成员函数requestDrawGL将会直接请求App的Render Thread执行GPU命令。这是通过调用参数viewRootImpl指向的一个ViewRootImpl对象的成员函数invokeFunctor实现的,如下所示:

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
    ......

    public void invokeFunctor(long functor, boolean waitForCompletion) {
        ThreadedRenderer.invokeFunctor(functor, waitForCompletion);
    }

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

       ViewRootImpl类的成员函数invokeFunctor会调用ThreadedRenderer类的静态成员函数invokeFunctor请求App的Render Thread执行GPU命令,如下所示:

public class ThreadedRenderer extends HardwareRenderer {
    ......

    static void invokeFunctor(long functor, boolean waitForCompletion) {
        nInvokeFunctor(functor, waitForCompletion);
    }

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

       ThreadedRenderer类的静态成员函数invokeFunctor调用另外一个静态成员函数nInvokeFunctor请求App的Render Thread执行GPU命令。

       ThreadedRenderer类的静态成员函数nInvokeFunctor是一个JNI方法,它由C++层的函数android_view_ThreadedRenderer_invokeFunctor实现,如下所示:

static void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz,
        jlong functorPtr, jboolean waitForCompletion) {
    Functor* functor = reinterpret_cast<Functor*>(functorPtr);
    RenderProxy::invokeFunctor(functor, waitForCompletion);
}
       这个函数定义在文件frameworks/base/core/jni/android_view_ThreadedRenderer.cpp中。

       从前面的分析可以知道,参数functorPtr描述的是一个Native层的DrawGLFunctor对象。这个DrawGLFunctor对象是从Functor类继承下来的,因此函数android_view_ThreadedRenderer_invokeFunctor可以将它转换为一个Functor对象。这个Functor对象会通过RenderProxy类的静态成员函数invokeFunctor提交给App的Render Thread处理,如下所示:

CREATE_BRIDGE2(invokeFunctor, RenderThread* thread, Functor* functor) {
    CanvasContext::invokeFunctor(*args->thread, args->functor);
    return NULL;
}

void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) {
    ATRACE_CALL();
    RenderThread& thread = RenderThread::getInstance();
    SETUP_TASK(invokeFunctor);
    args->thread = &thread;
    args->functor = functor;
    if (waitForCompletion) {
        // waitForCompletion = true is expected to be fairly rare and only
        // happen in destruction. Thus it should be fine to temporarily
        // create a Mutex
        Mutex mutex;
        Condition condition;
        SignalingRenderTask syncTask(task, &mutex, &condition);
        AutoMutex _lock(mutex);
        thread.queue(&syncTask);
        condition.wait(mutex);
    } else {
        thread.queue(task);
    }
}
       这个函数定义在文件frameworks/base/libs/hwui/renderthread/RenderProxy.cpp中。

       App的Render Thread可以通过调用RenderThread类的静态成员函数getInstance获得。获得了App的Render Thread之后,RenderProxy类的静态成员函数invokeFunctor就可以往它的消息队列发送一个Task。这个Task封装参数funtor描述的一个Native层的DrawGLFunctor对象,并且它绑定了由宏CREATE_BRIDGE2定义的函数invokeFunctor。

       这意味着当上述Task被App的Render Thread调度执行的时候,函数invokeFunctor就会在App的Render Thread中执行,它主要就是通过调用CanvasContext类的静态成员函数invokeFunctor通知参数参数funtor描述的Native层DrawGLFunctor对象,现在可以执行GPU命令了。

       从前面的调用过程可以知道,参数waitForCompletion的值等于false,表示当前线程(也就是App的UI线程)不用等待App的Render Thread执行完成请求的GPU命令,于是它就可以马上返回。

       接下来我们就继续分析CanvasContext类的静态成员函数invokeFunctor的实现,如下所示:

void CanvasContext::invokeFunctor(RenderThread& thread, Functor* functor) {
    ATRACE_CALL();
    DrawGlInfo::Mode mode = DrawGlInfo::kModeProcessNoContext;
    if (thread.eglManager().hasEglContext()) {
        thread.eglManager().requireGlContext();
        mode = DrawGlInfo::kModeProcess;
    }

    thread.renderState().invokeFunctor(functor, mode, NULL);
}
       这个函数定义在文件frameworks/base/libs/hwui/renderthread/CanvasContext.cpp中。

       CanvasContext类的静态成员函数invokeFunctor主要就是通过调用一个RenderState对象的成员函数invokeFunctor通知参数funtor描述的一个Native层DrawGLFunctor对象执行GPU命令。这个RenderState对象记录了App的Render Thread的当前渲染状态,它可以通过调用参数thread描述的一个RenderThread对象的成员函数renderState获得。

       如果此时App的Render Thread已经初始化好了OpenGL环境,那么RenderState类的成员函数invokeFunctor将会通知参数funtor描述的Native层DrawGLFunctor对象以DrawGlInfo::kModeProcess的模式执行GPU命令。否则的话,就以DrawGlInfo::kModeProcessNoContext的模式行。由于App的Render Thread一开始就会初始化OpenGL环境,因此我们将认为RenderState类的成员函数invokeFunctor将会通知参数funtor描述的Native层DrawGLFunctor对象以DrawGlInfo::kModeProcess的模式执行GPU命令。

       RenderState类的成员函数invokeFunctor的实现如下所示:

void RenderState::invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlInfo* info) {
    interruptForFunctorInvoke();
    (*functor)(mode, info);
    resumeFromFunctorInvoke();
}
       这个函数定义在文件frameworks/base/libs/hwui/RenderState.cpp中。

       RenderState类的成员函数invokeFunctor主要就是调用了参数functor描述的一个Native层DrawGLFunctor对象的重载操作符函数(),用来通知它执行GPU命令,如下所示:

AwDrawGLFunction* g_aw_drawgl_function = NULL;

class DrawGLFunctor : public Functor {
 public:
  ......

  // Functor
  virtual status_t operator ()(int what, void* data) {
    ......

    AwDrawGLInfo aw_info;
    aw_info.version = kAwDrawGLInfoVersion;
    switch (what) {
      case DrawGlInfo::kModeDraw: {
        aw_info.mode = AwDrawGLInfo::kModeDraw;
        ......
        break;
      }
      case DrawGlInfo::kModeProcess:
        aw_info.mode = AwDrawGLInfo::kModeProcess;
        break;
      case DrawGlInfo::kModeProcessNoContext:
        aw_info.mode = AwDrawGLInfo::kModeProcessNoContext;
        break;
      case DrawGlInfo::kModeSync:
        aw_info.mode = AwDrawGLInfo::kModeSync;
        break;
      default:
        ALOGE("Unexpected DrawGLInfo type %d", what);
        return DrawGlInfo::kStatusDone;
    }

    // Invoke the DrawGL method.
    g_aw_drawgl_function(view_context_, &aw_info, NULL);

    return DrawGlInfo::kStatusDone;
  }

  ......
};
       这个函数定义在文件frameworks/webview/chromium/plat_support/draw_gl_functor.cpp中。

       DrawGLFunctor类的重载操作符函数()主要就是调用全局变量g_aw_drawgl_function描述的一个DrawGL函数执行GPU命令,并且告知该DrawGL函数,App的Render Thread当前处于什么状态。这个状态由参数what描述的GPU执行模式决定。

       App的Render Thread有四种状态:

       1. AwDrawGLInfo::kModeDraw:表示App的Render Thread正在重放App UI的Display List。

       2. DrawGlInfo::kModeProcess:表示App的Render Thread正在执行外界请求的GPU命令,并且App的Render Thread当前具有OpenGL上下文。

       3. AwDrawGLInfo::kModeProcessNoContext:表示App的Render Thread正在执行外界请求的GPU命令,但是App的Render Thread当前没有OpenGL上下文。

       4, AwDrawGLInfo::kModeSync:表示App的Render Thread正在同步的App的UI线程的Display List。

       在我们这个情景中,App的Render Thread正处于第2种状态。第3种状态几乎不会出现,我们不予考虑。第1种和第4种状态我们在接下来一篇文章分析Android WebView渲染网页UI的过程中再详细分析。

       从前面的分析可以知道,全局变量g_aw_drawgl_function描述的DrawGL函数是由Android WebView在启动Chromium渲染引擎时注册的,它指向的函数为DrawGLFunction,它的实现如下所示:

static void DrawGLFunction(long view_context,
                           AwDrawGLInfo* draw_info,
                           void* spare) {
  // |view_context| is the value that was returned from the java
  // AwContents.onPrepareDrawGL; this cast must match the code there.
  reinterpret_cast<android_webview::AwContents*>(view_context)
      ->DrawGL(draw_info);
}
      这个函数定义在文件external/chromium_org/android_webview/native/aw_contents.cc中。

      参数view_context描述的是一个Native层的AwContents对象。函数DrawGLFunction主要就是调用这个AwContents对象的成员函数DrawGL执行GPU命令,如下所示:

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

  ......

  ScopedAllowGL allow_gl;
  ......

  if (draw_info->mode != AwDrawGLInfo::kModeDraw) {
    ......
    return;
  }

  if (!hardware_renderer_) {
    hardware_renderer_.reset(new HardwareRenderer(&shared_renderer_state_));
    hardware_renderer_->CommitFrame();
  }

  hardware_renderer_->DrawGL(state_restore.stencil_enabled(),
                             state_restore.framebuffer_binding_ext(),
                             draw_info);
  ......
}

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

       AwContents类的成员函数DrawGL根据App的Render Thread的当前不同的状态执行不同的操作。在分析这些操作之前,我们首先介绍AwContents类的成员变量hardware_renderer_。如果它的值不等于NULL,那么它就是指向一个HardwareRenderer对象。这个HardwareRenderer对象是Browser端用来合成网页UI的。

       如果App的Render Thread的当前状态是AwDrawGLInfo::kModeSync,并且当前AwContents类的成员变量hardware_renderer_指向了一个HardwareRenderer对象,那么AwContents类的成员函数DrawGL就会调用这个HardwareRenderer对象的成员函数CommitFrame将Render端上一次绘制出来的网页UI同步到Browser端。

       如果App的Render Thread的当前状态是AwDrawGLInfo::kModeProcess,那么AwContents类的成员函数DrawGL就会构造一个ScopedAllowGL对象。这个ScopedAllowGL对象在构造的过程中,就会通知DeferredGpuCommandService服务执行Render端之前请求执行的GPU命令。

       如果App的Render Thread的当前状态是AwDrawGLInfo::kModeDraw,那么AwContents类的成员函数DrawGL同样先通过上述构造的ScopedAllowGL对象通知DeferredGpuCommandService服务执行Render端之前请求执行的GPU命令。此外,AwContents类的成员函数DrawGL还会调用成员变量hardware_renderer_指向了一个HardwareRenderer对象的成员函数DrawGL将从Render端同步过来的网页UI合成显示在屏幕中。如果这个HardwareRenderer对象还没有创建,那么就会进行创建,并且会在创建后将Render端上一次绘制出来的网页UI同步到Browser端来,以便接下来可以将它合成显示在屏幕中。

       从前面的分析可以知道,App的Render Thread的当前状态是AwDrawGLInfo::kModeProcess,因此接下来AwContents类的成员函数DrawGL就会通过构造一个ScopedAllowGL对象来通知DeferredGpuCommandService服务执行Render端之前请求执行的GPU命令。这些GPU命令是用来光栅化网页的UI的。

       ScopedAllowGL对象的构造过程如下所示:

base::LazyInstance<scoped_refptr<DeferredGpuCommandService> >
    g_service = LAZY_INSTANCE_INITIALIZER;
......

base::LazyInstance<base::ThreadLocalBoolean> ScopedAllowGL::allow_gl;
......

bool ScopedAllowGL::IsAllowed() {
  return allow_gl.Get().Get();
}

ScopedAllowGL::ScopedAllowGL() {
  DCHECK(!allow_gl.Get().Get());
  allow_gl.Get().Set(true);

  if (g_service.Get())
    g_service.Get()->RunTasks();
}
       这个函数定义在文件external/chromium_org/android_webview/browser/deferred_gpu_command_service.cc中。

       ScopedAllowGL类的构造函数首先是通过ScopedAllowGL类的静态成员变量allow_gl描述的一个线程局存储将当前线程标记为一个GPU线程,这样当前线程就可以直接执行GPU命令了。

       全局变量g_service描述的就是一个DeferredGpuCommandService服务。ScopedAllowGL类的构造函数接下来就会调用这个DeferredGpuCommandService服务的成员函数RunTasks调度执行保存在它内部的一个Task队列中的Task了。DeferredGpuCommandService类的成员函数RunTasks我们在前面已经分析过了,这里不再复述。

       从前面的分析可以知道,DeferredGpuCommandService服务内部的Task队列保存了一个Task。这个Task绑定了InProcessCommandBuffer类的成员函数FlushOnGpuThread。这意味着接下来InProcessCommandBuffer类的成员函数FlushOnGpuThread会在App的Render Thread中调用,它的实现如下所示:

void InProcessCommandBuffer::FlushOnGpuThread(int32 put_offset) {
  ......

  command_buffer_->Flush(put_offset);

  ......
}
       这个函数定义在文件external/chromium_org/gpu/command_buffer/service/in_process_command_buffer.cc中。

       从前面的分析可以知道,InProcessCommandBuffer类的成员变量command_buffer_指向的是一个CommandBufferService对象。InProcessCommandBuffer类的成员函数FlushOnGpuThread调用这个CommandBufferService对象的成员函数Flush执行GPU命令,如下所示:

void CommandBufferService::Flush(int32 put_offset) {
  ......

  put_offset_ = put_offset;

  if (!put_offset_change_callback_.is_null())
    put_offset_change_callback_.Run();
}
       这个函数定义在文件external/chromium_org/gpu/command_buffer/service/command_buffer_service.cc中。

       参数表示put_offset表示最新写入的GPU命令在Command Buffer中的位置。CommandBufferService类的成员函数Flush首先将这个位置记录在成员变量put_offset_中。

       CommandBufferService类的成员函数Flush接下来又会检查成员变量put_offset_change_callback_是否指向了一个Callback。如果指向了一个Callback,那么就会调用它所绑定的函数来执行GPU命令。

       从前面的分析可以知道,CommandBufferService类的成员变量put_offset_change_callback_指向了一个Callback。这个Callback绑定的函数为InProcessCommandBuffer类的成员函数PumpCommands。因此,接下来InProcessCommandBuffer类的成员函数PumpCommands会被调用。在调用期间,就会执行前面写入在Command Buffer中的GPU命令,如下所示:

void InProcessCommandBuffer::PumpCommands() {
  ......

  gpu_scheduler_->PutChanged();
}
       这个函数定义在文件external/chromium_org/gpu/command_buffer/service/in_process_command_buffer.cc中。

       从前面的分析可以知道,InProcessCommandBuffer类的成员变量gpu_scheduler_描述的是一个Gpu Scheduler。InProcessCommandBuffer类的成员函数PumpCommands调用这个Gpu Scheduler的成员函数PutChanged,用来通知它Command Buffer有新的GPU命令需要处理。这个Gpu Scheduler获得这个通知后,就会从Command Buffer中读出新写入的GPU命令,并且调用相应的OpenGL函数进行处理。这个处理过程可以参考前面Chromium硬件加速渲染的OpenGL命令执行过程分析一文。

       这样,我们就以Render端使用GPU光栅化网页UI的情景为例,分析了Android WebView的Render端执行GPU命令的过程。其它的情景,Render端也是通过In-Process Command Buffer GL接口请求App的Render Thread来执行GPU命令。

       最后,我们分析Android WebView为Browser端创建In-Process Command Buffer GL接口的过程。有了In-Process Command Buffer GL接口之后,Browser端就可以像Render端一样,在App的Render Thread中执行GPU命令了。

       Android WebView的Browser端的主要任务是将网页的UI合成在屏幕中。为了完成这个任务,Browser端会创建一个Hardware Renderer。Hardware Renderer又会为Browser端创建一个CC Layer Tree,目的是为了可以使用Chromium的CC模块来完成合成网页UI的任务。

      Hardware Renderer会将它为Browser端创建的CC Layer Tree绘制在一个Parent Output Surface上。这个Parent Output Surface内部封装了一个In-Process Command Buffer GL接口。以后Chromium的CC模块就会通过这个In-Process Command Buffer GL接口合成网页的UI。

      接下来,我们就从Browser端创建Hardware Renderer的过程开始,分析Browser端用来合成网页UI的In-Process Command Buffer GL接口的创建过程。

      前面分析,App的Render Thread在AwContents类的成员函数DrawGL时提到,当App的Render Thread的处于AwDrawGLInfo::kModeDraw状态时,会检查Android WebView的Browser端是否已经创建了一个Hardware Renderer。如果还没有创建,那么就会进行创建。创建过程如下所示:

HardwareRenderer::HardwareRenderer(SharedRendererState* state)
    : ......,
      root_layer_(cc::Layer::Create()),
      ...... {
  ......

  layer_tree_host_ =
      cc::LayerTreeHost::CreateSingleThreaded(this, this, NULL, settings);
  layer_tree_host_->SetRootLayer(root_layer_);
  ......
}
       这个函数定义在文件external/chromium_org/android_webview/browser/hardware_renderer.cc中。

       HardwareRenderer类的构造函数主要就是为Browser端创建一个LayerTreeHost对象,并且保存成员变量layer_tree_host_中。这个LayerTreeHost对象描述的就是一个CC Layer Tree。这个CC Layer Tree是通过调用LayerTreeHost类的静态成员函数CreateSingleThreaded创建的,并且会将这个CC Layer Tree的Client指定为当前正在创建的Hardware Renderer,如下所示:

scoped_ptr<LayerTreeHost> LayerTreeHost::CreateSingleThreaded(
    LayerTreeHostClient* client,
    LayerTreeHostSingleThreadClient* single_thread_client,
    SharedBitmapManager* manager,
    const LayerTreeSettings& settings) {
  scoped_ptr<LayerTreeHost> layer_tree_host(
      new LayerTreeHost(client, manager, settings));
  layer_tree_host->InitializeSingleThreaded(single_thread_client);
  return layer_tree_host.Pass();
}
       这个函数定义在文件external/chromium_org/cc/trees/layer_tree_host.cc中。

       LayerTreeHost类的静态成员函数CreateSingleThreaded首先是创建了一个LayerTreeHost对象。这个LayerTreeHost对象描述的就是一个CC Layer Tree,它的创建过程如下所示:

LayerTreeHost::LayerTreeHost(LayerTreeHostClient* client,
                             SharedBitmapManager* manager,
                             const LayerTreeSettings& settings)
    : ......,
      client_(client),
      ...... {
  ......
}
       这个函数定义在文件external/chromium_org/cc/trees/layer_tree_host.cc中。

       LayerTreeHost类的构造函数主要是将参数client描述的一个HardwareRenderer对象保存成员变量client_中,作为当前正在创建的CC Layer Tree的Client。以后当前正在创建的CC Layer Tree将会通过这个Client为自己创建一个Output Surface。

       回到前面分析的LayerTreeHost类的静态成员函数CreateSingleThreaded中,它接下来又会调用前面创建的LayerTreeHost对象的成员函数InitializeSingleThreaded,用来执行初始化工作,如下所示:

void LayerTreeHost::InitializeSingleThreaded(
    LayerTreeHostSingleThreadClient* single_thread_client) {
  InitializeProxy(SingleThreadProxy::Create(this, single_thread_client));
}
       这个函数定义在文件external/chromium_org/cc/trees/layer_tree_host.cc中。

       LayerTreeHost类的成员函数InitializeSingleThreaded首先是调用SingleThreadProxy类的静态成员函数Create创建了一个SingleThreadProxy对象,如下所示:

scoped_ptr<Proxy> SingleThreadProxy::Create(
    LayerTreeHost* layer_tree_host,
    LayerTreeHostSingleThreadClient* client) {
  return make_scoped_ptr(
      new SingleThreadProxy(layer_tree_host, client)).PassAs<Proxy>();
}
       这个函数定义在文件external/chromium_org/cc/trees/single_thread_proxy.cc中。

       从这里可以看到,SingleThreadProxy类的静态成员函数Create创建的是一个SingleThreadProxy对象。这个SingleThreadProxy对象在创建的过程中,会将参数layer_tree_host指向的一个LayerTreeHost对象保存在自己的成员变量layer_tree_host_中,如下所示:

SingleThreadProxy::SingleThreadProxy(LayerTreeHost* layer_tree_host,
                                     LayerTreeHostSingleThreadClient* client)
    : Proxy(NULL),
      layer_tree_host_(layer_tree_host),
      ...... {
  ......
}
       这个函数定义在文件external/chromium_org/cc/trees/single_thread_proxy.cc中。

       回到前面分析的LayerTreeHost类的成员函数InitializeSingleThreaded中,它获得了一个SingleThreadProxy对象之后,就会调用另外一个成员函数InitializeProxy对该SingleThreadProxy进行初始化,如下所示:

void LayerTreeHost::InitializeProxy(scoped_ptr<Proxy> proxy) {
  ......

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

      LayerTreeHost类的成员函数InitializeProxy首先将参数proxy指向的一个SingleThreadProxy对象保存在成员变量proxy_中,然后再调用这个SingleThreadProxy对象的成员函数
Start创建一个LayerTreeHostImpl对象,如下所示:

void SingleThreadProxy::Start() {
  ......
  layer_tree_host_impl_ = layer_tree_host_->CreateLayerTreeHostImpl(this);
}
       这个函数定义在文件external/chromium_org/cc/trees/single_thread_proxy.cc中。

       从前面的分析可以知道,SingleThreadProxy类的成员变量layer_tree_host_指向的是一个LayerTreeHost对象。SingleThreadProxy类的成员函数
Start调用这个LayerTreeHost对象的成员函数CreateLayerTreeHostImpl创建了一个LayerTreeHostImpl对象,并且保存在成员变量layer_tree_host_impl_。

       从前面的分析就可以知道,Hardware Renderer在为Browser端创建CC Layer Tree的过程中,一共创建了LayerTreeHost、SingleThreadProxy和LayerTreeHostImpl三个对象。这三个对象一起描述了一个CC Layer Tree。

       从前面Chromium网页渲染机制简要介绍和学习计划这个系列的文章可以知道,Render端的CC Layer Tree是通过调用LayerTreeHost类的静态成员函数CreateThreaded创建的。在创建的过程中,同样会创建一个LayerTreeHost对象和一个LayerTreeHostImpl对象。不过,它不会创建一个SingleThreadProxy对象,而是一个ThreadProxy对象。这三个对象同样是描述了一个CC Layer Tree。

       ThreadProxy类和SingleThreadProxy类都是从Proxy类继承下来的。它们的最大区别在于前者描述的CC Layer Tree在绘制的过程中,会使用到两个线程。一个称为Main线程,另一个称为Compositor线程。这两个线程通过一个CC调度器进行协作,完成绘制网页UI的任务。后者描述的CC Layer Tree在绘制的过程中,只会使用一个线程,因此它不需要使用到CC调度器。

       从前面Chromium网页渲染机制简要介绍和学习计划这个系列的文章可以知道,对于复杂的UI来说,使用两个线程绘制效率会更高。不过,对Android WebView的Browser端来说,它的UI结构是非常简单的(CC Layer Tree只包含两个节点),因此,它就不需要使用两个线程来绘制了。

       回到前面分析的HardwareRenderer类的构造函数中,它除了为Browser端创建一个CC Layer Tree,还会调用Layer类的静态成员函数Create0创建一个CC Layer。这个CC Layer就作为Browser端的CC Layer Tree的根节点。

       确保Android WebView的Browser端已经具有一个Hardware Renderer之后,前面分析的AwContents类的成员函数DrawGL就会调用这个Hardware Renderer的成员函数DrawGL来合成网页的UI,如下所示:

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中。

       从前面的分析可以知道,HardwareRenderer类的成员变量layer_tree_host_指向的是一个LayerTreeHost对象。HardwareRenderer类的成员函数DrawGL调用这个LayerTreeHost对象的成员函数Composite合成网页的UI,如下所示:

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

  if (output_surface_lost_)
    proxy->CreateAndInitializeOutputSurface();
  ......

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

        LayerTreeHost类的成员变量output_surface_lost_是一个布尔变量。当它的值等于true的时候,就表示CC模块还没有为当前正在处理的LayerTreeHost对象描述的CC Layer Tree创建过Output Surface,或者以前创建过,但是现在失效了。在这种情况下,LayerTreeHost类的成员函数Composite合成网页UI之前,先创建创建一个Output Surface。

       从前面的分析可以知道,LayerTreeHost类的成员变量proxy_指向的是一个SingleThreadProxy对象。LayerTreeHost类的成员函数Composite就是通过调用这个SingleThreadProxy对象的成员函数CreateAndInitializeOutputSurface为当前正在处理的LayerTreeHost对象描述的CC Layer Tree创建Output Surface的。

       有了Output Surface之后,LayerTreeHost类的成员函数Composite再调用上述SingleThreadProxy对象的成员函数CompositeImmediately合成网页的UI。这个过程我们在接下来一篇文章中再详细分析。

       接下来,我们继续分析SingleThreadProxy类的成员函数CreateAndInitializeOutputSurface为Browser端的CC Layer Tree创建Output Surface的过程。在创建的过程中,就会创建一个In-Process Command Buffer GL接口,如下所示:

void SingleThreadProxy::CreateAndInitializeOutputSurface() {
  ......

  scoped_ptr<OutputSurface> output_surface =
      layer_tree_host_->CreateOutputSurface();

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

       从前面的分析可以知道,SingleThreadProxy类的成员变量layer_tree_host_指向的是一个LayerTreeHost对象。SingleThreadProxy类的成员函数CreateAndInitializeOutputSurface调用这个LayerTreeHost对象的成员函数CreateOutputSurface为Browser端的CC Layer Tree创建一个Output Surface,如下所示:

scoped_ptr<OutputSurface> LayerTreeHost::CreateOutputSurface() {
  return client_->CreateOutputSurface(num_failed_recreate_attempts_ >= 4);
}
       这个函数定义在文件external/chromium_org/cc/trees/layer_tree_host.cc中。

       从前面的分析可以知道,LayerTreeHost类的成员变量client_指向的是一个HardwareRenderer对象。LayerTreeHost类的成员函数CreateOutputSurfaceBrowser调用这个HardwareRenderer对象的成员函数CreateOutputSurface为Browser端的CC Layer Tree创建一个Output Surface,如下所示:

scoped_ptr<cc::OutputSurface> HardwareRenderer::CreateOutputSurface(
    bool fallback) {
  ......

  scoped_refptr<cc::ContextProvider> context_provider =
      CreateContext(gl_surface_,
                    DeferredGpuCommandService::GetInstance(),
                    shared_renderer_state_->GetSharedContext());
  scoped_ptr<ParentOutputSurface> output_surface_holder(
      new ParentOutputSurface(context_provider));
  output_surface_ = output_surface_holder.get();
  return output_surface_holder.PassAs<cc::OutputSurface>();
}
       这个函数定义在文件external/chromium_org/android_webview/browser/hardware_renderer.cc。

       HardwareRenderer类的成员函数CreateOutputSurface为Browser端的CC Layer Tree创建的是一个Parent Output Surface。相应地,Render端的CC Layer Tree使用的Synchronous Compositor Output Surface也称为Child Output Surface。之所以将Render端的CC Layer Tree的Output Surface称为Child,而将Browser端的CC Layer Tree创建的是一个Parent,是因为Render端的CC Layer Tree的绘制结果会输出为Browser端的CC Layer Tree的一个节点的内容。这一点我们在接下来一篇文章分析Android WebView渲染网页UI的过程就会清楚地看到。

       HardwareRenderer类的成员函数CreateOutputSurface在为Browser端的CC Layer Tree创建Parent Output Surface的时候,需要用到一个ContextProvider对象。这个ContextProvider对象是通过调用函数CreateContext创建的,如下所示:

scoped_refptr<cc::ContextProvider> CreateContext(
    scoped_refptr<gfx::GLSurface> surface,
    scoped_refptr<gpu::InProcessCommandBuffer::Service> service,
    gpu::GLInProcessContext* share_context) {
  ......

  scoped_ptr<gpu::GLInProcessContext> context(
      gpu::GLInProcessContext::Create(service,
                                      surface,
                                      surface->IsOffscreen(),
                                      gfx::kNullAcceleratedWidget,
                                      surface->GetSize(),
                                      share_context,
                                      false /* share_resources */,
                                      in_process_attribs,
                                      gpu_preference));
  ......

  return webkit::gpu::ContextProviderInProcess::Create(
      WebGraphicsContext3DInProcessCommandBufferImpl::WrapContext(
          context.Pass(), attributes),
      "Parent-Compositor");
}
       这个函数定义在文件external/chromium_org/android_webview/browser/hardware_renderer.cc。

       函数ContextProvider首先是调用GLInProcessContext类的静态成员函数Create创建了一个In-Process Command Buffer GL接口。

       上述In-Process Command Buffer GL接口又会通过WebGraphicsContext3DInProcessCommandBufferImpl类的静态成员函数WrapContext封装在一个WebGraphicsContext3DInProcessCommandBufferImpl对象中。

       最后,前面得到的WebGraphicsContext3DInProcessCommandBufferImpl对象又会通过ContextProviderInProcess类的静态成员函数Create封装在一个ContextProviderInProcess对象中返回给调用者。调用者有了这个ContextProviderInProcess对象之后,就可以创建一个Output Surface了。

       GLInProcessContext类的静态成员函数Create、WebGraphicsContext3DInProcessCommandBufferImpl类的静态成员函数WrapContext和ContextProviderInProcess类的静态成员函数Create的实现,前面在分析Render端的CC Layer Tree使用的Synchronous Compositor Output Surface的创建过程时,已经分析过了,这里就不再复述。

       这样,我们就可以知道,Browser端的CC Layer Tree使用的Output Surface里面包含了一个In-Process Command Buffer GL接口。CC模块在绘制Browser端的CC Layer Tree时,就会通过这个In-Process Command Buffer GL接口来执行GPU命令。这与我们前面分析的Render端执行GPU命令的过程是一致的。

       至此,我们就分析了Android WebView为Render端和Browser端创建In-Process Command Buffer GL接口的过程,并且以Render端光栅化网页UI的情景为例,分析了Render端通过In-Process Command Buffer GL接口请求App的Render Thread执行GPU命令的过程。Browser端执行GPU命令的过程与Render端也是类似的。一旦Render端和Browser可以执行GPU命令,它们就可以使用硬件加速的方式渲染网页的UI。在接下来一篇文章中,我们就详细分析Android WebView使用硬件加速方式渲染网页UI的过程。敬请关注!更多的信息也可以关注老罗的新浪微博:http://weibo.com/shengyangluo

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Luoshengyang/article/details/53296819
个人分类: Android
所属专栏: 老罗的Android之旅
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

Android WebView执行GPU命令的过程分析

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭