1. 程式人生 > >Android WebView硬體加速渲染網頁UI的過程分析

Android WebView硬體加速渲染網頁UI的過程分析

      Android WebView作為App UI的一部分,當App UI以硬體加速方式渲染時,它也是以硬體加速方式渲染的。Android WebView的UI來自於網頁,是通過Chromium渲染的。Chromium渲染網頁UI的機制與Android App渲染UI的機制是不一樣的。不過,它們會一起協作完成網頁UI的渲染。本文接下來就詳細分析Android WebView硬體加速渲染網頁UI的過程。

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

       由於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