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

Nicy 8年前發布 | 9K 次閱讀 安卓開發 Android開發 移動開發

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

從前面 Android應用程序UI硬件加速渲染技術簡要介紹和學習計劃 這個系列的文章可以知道,Android App在渲染UI一幀的過程中,經歷以下三個階段:

1. 在UI線程中構建一個Display List,這個Display List包含了每一個View的繪制命令。

2. 將前面構建的Display List同步給Render Thread。

3. Render Thread對同步得到的Display List進行渲染,也就是使用GPU執行Display List的繪制命令。

上述三個階段如果能夠在16ms內完成,那么App的UI給用戶的感受就是流暢的。為了盡量地在16ms內渲染完成App的一幀UI,Android使用了以上方式對App的UI進行渲染。這種渲染機制的好處是UI線程和Render Thread可以并發執行,也就是Render Thread在渲染當前幀的Display List的時候,UI線程可以準備下一幀的Display List。它們唯一需要同步的地方發生第二階段。不過,這個階段是可以很快完成的。因此,UI線程和Render Thread可以認為是并發執行的。

Android WebView既然是App UI的一部分,也就是其中的一個View,它的渲染也是按照上述三個階段進行的,如下所示:

圖1 Android WebView硬件加速渲染網頁UI的過程

在第一階段,Android WebView會對Render端的CC Layer Tree進行繪制。這個CC Layer Tree描述的就是網頁的UI,它會通過一個Synchronous Compositor繪制在一個Synchronous Compositor Output Surface上,最終得到一個Compositor Frame。這個Compositor Frame會保存在一個SharedRendererState對象中。

在第二階段,保存在上述SharedRendererState對象中的Compositor Frame會同步給Android WebView會對Browser端的CC Layer Tree。Browser端的CC Layer Tree只有兩個節點。一個是根節點,另一個是根節點的子節點,稱為一個Delegated Renderer Layer。Render端繪制出來的Compositor Frame就是作為這個Delegated Renderer Layer的輸入的。

在第三階段,Android WebView會通過一個Hardware Renderer將Browser端的CC Layer Tree渲染在一個Parent Output Surface上,實際上就是通過GPU命令將Render端繪制出來的UI合成顯示在App的UI窗口中。

接下來,我們就按照以上三個階段分析Android WebView硬件加速渲染網頁UI的過程。

從前面 Android應用程序UI硬件加速渲染的Display List構建過程分析 一文可以知道,在App渲染UI的第一階段,Android WebView的成員函數onDraw會被調用。從前面 Android WebView執行GPU命令的過程分析 一文又可以知道,Android WebView在Native層有一個BrowserViewRenderer對象。當Android WebView的成員函數onDraw被調用時,并且App的UI以硬件加速方式渲染時,這個Native層BrowserViewRenderer對象的成員函數OnDrawHardware會被調用,如下所示:

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

  scoped_ptr<DrawGLInput> draw_gl_input(new DrawGLInput);  
  ......  

  scoped_ptr<cc::CompositorFrame> frame =  
      compositor_->DemandDrawHw(surface_size,  
                                gfx::Transform(),  
                                viewport,  
                                clip,  
                                viewport_rect_for_tile_priority,  
                                transform_for_tile_priority);  
  ......  

  frame->AssignTo(&draw_gl_input->frame);
  ......
  shared_renderer_state_->SetDrawGLInput(draw_gl_input.Pass()); 

  ......  
  return client_->RequestDrawGL(java_canvas, false);  
}

這個函數定義在文件external/chromium_org/android_webview/browser/browser_view_renderer.cc中。

從前面 Android WebView執行GPU命令的過程分析 一文可以知道,BrowserViewRenderer類的成員變量compositor_指向的是一個SynchronousCompositorImpl對象。BrowserViewRenderer對象的成員函數OnDrawHardware會調用這個SynchronousCompositorImpl對象的成員函數DemandDrawHw對網頁的UI進行繪制。

繪制的結果是得到一個Compositor Frame。這個Compositor Frame會保存在一個DrawGLInput對象中。這個DrawGLInput對象又會保存在BrowserViewRenderer類的成員變量shared_renderer_state_指向的一個SharedRendererState對象中。這是通過調用SharedRendererState類的成員函數SetDrawGLInput實現的。

BrowserViewRenderer類的成員變量client_指向的是一個AwContents對象。BrowserViewRenderer對象的成員函數OnDrawHardware最后會調用這個AwContents對象的成員函數RequestDrawGL請求在參數java_canvas描述的一個Hardware Canvas中增加一個DrawFunctorOp操作。這個DrawFunctorOp操作最終會包含在App的UI線程構建的Display List中。

接下來,我們首先分析SynchronousCompositorImpl類的成員函數DemandDrawHw繪制網頁的UI的過程,如下所示:

scoped_ptr<cc::CompositorFrame> SynchronousCompositorImpl::DemandDrawHw(
    gfx::Size surface_size,
    const gfx::Transform& transform,
    gfx::Rect viewport,
    gfx::Rect clip,
    gfx::Rect viewport_rect_for_tile_priority,
    const gfx::Transform& transform_for_tile_priority) {
  ......

  scoped_ptr<cc::CompositorFrame> frame =
      output_surface_->DemandDrawHw(surface_size,
                                    transform,
                                    viewport,
                                    clip,
                                    viewport_rect_for_tile_priority,
                                    transform_for_tile_priority);
  ......
  return frame.Pass();
}

這個函數定義在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_impl.cc中。

從前面 Android WebView執行GPU命令的過程分析 一文可以知道,SynchronousCompositorImpl類的成員變量output_surface_指向的是一個SynchronousCompositorOutputSurface對象。SynchronousCompositorImpl類的成員函數DemandDrawHw調用這個SynchronousCompositorOutputSurface對象的成員函數DemandDrawHw繪制網頁的UI,如下所示:

scoped_ptr<cc::CompositorFrame>
SynchronousCompositorOutputSurface::DemandDrawHw(
    gfx::Size surface_size,
    const gfx::Transform& transform,
    gfx::Rect viewport,
    gfx::Rect clip,
    gfx::Rect viewport_rect_for_tile_priority,
    const gfx::Transform& transform_for_tile_priority) {
  ......

  InvokeComposite(transform,
                  viewport,
                  clip,
                  viewport_rect_for_tile_priority,
                  transform_for_tile_priority,
                  true);

  return frame_holder_.Pass();
}

這個函數定義在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_output_surface.cc中。

SynchronousCompositorOutputSurface類的成員函數DemandDrawHw調用另外一個成員函數InvokeComposite繪制網頁的UI。繪制完成后,就會得到一個Compositor Frame。這個Compositor Frame保存在SynchronousCompositorOutputSurface類的成員變量frame_holder_中。因此,SynchronousCompositorOutputSurface類的成員函數DemandDrawHw可以將這個成員變量frame_holder_指向的Compositor Frame返回給調用者。

SynchronousCompositorOutputSurface類的成員函數InvokeComposite的實現如下所示:

void SynchronousCompositorOutputSurface::InvokeComposite(
    const gfx::Transform& transform,
    gfx::Rect viewport,
    gfx::Rect clip,
    gfx::Rect viewport_rect_for_tile_priority,
    gfx::Transform transform_for_tile_priority,
    bool hardware_draw) {
  ......

  client_->BeginFrame(cc::BeginFrameArgs::CreateForSynchronousCompositor());

  ......
}

這個函數定義在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_output_surface.cc中。

SynchronousCompositorOutputSurface類的成員變量client_是從父類OutputSurface繼承下來的。從前面 Chromium網頁繪圖表面(Output Surface)創建過程分析 一文可以知道,它指向的是一個LayerTreeHostImpl對象。SynchronousCompositorOutputSurface類的成員函數InvokeComposite調用這個LayerTreeHostImpl對象的成員函數BeginFrame繪制網頁的UI。 

從前面 Chromium網頁渲染調度器(Scheduler)實現分析 一文可以知道,當LayerTreeHostImpl類的成員函數BeginFrame被調用時,它就會CC模塊的調度器執行一個BEGIN_IMPL_FRAME操作,也就是對網頁的CC Layer Tree進行繪制。繪制的過程可以參考 Chromium網頁Layer Tree繪制過程分析 、 Chromium網頁Layer Tree同步為Pending Layer Tree的過程分析 和 Chromium網頁Pending Layer Tree激活為Active Layer Tree的過程分析 這三篇文章。

由于Android WebView的Render端使用的是Synchronous Compositor,當前線程(也就是App的UI線程)會等待Render端的Compositor線程繪制完成網頁的CC Layer Tree。從前面 Chromium硬件加速渲染的UI合成過程分析 一文可以知道,Compositor線程在繪制完成網頁的CC Layer Tree的時候,會調用網頁的Output Surface的成員函數SwapBuffers。

在我們這個情景中,網頁的Output Surface是一個Synchronous Compositor Output Surface。這意味著當Compositor線程在繪制完成網頁的CC Layer Tree時,會調用SynchronousCompositorOutputSurface類的成員函數SwapBuffers,如下所示:

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

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

  ......
}

這個函數定義在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_output_surface.cc中。

參數frame指向的Compositor Frame描述的就是網頁的繪制結果。從前面 Chromium硬件加速渲染的UI合成過程分析 一文可以知道,這個Compositor Frame包含了一系列的Render Pass。每一個Render Pass都包含了若干個紋理,以及每一個紋理的繪制參數。這些紋理是在Render端光柵化網頁時產生的。Browser端的Hardware Renderer所要做的事情就是將這些紋理渲染在屏幕上。這個過程也就是Browser端合成網頁UI的過程。

SynchronousCompositorOutputSurface類的成員函數SwapBuffers會將參數frame描述的Compositor Frame的內容拷貝一份到一個新創建的Compositor Frame中去。這個新創建的Compositor Frame會保存在SynchronousCompositorOutputSurface類的成員變量frame_hodler_中。因此,前面分析的SynchronousCompositorOutputSurface類的成員函數InvokeComposite返回給調用者的就是當前繪制的網頁的內容。

這一步執行完成后,回到前面分析的BrowserViewRenderer類的成員函數OnDrawHardware中,這時候它就獲得了一個Render端繪制網頁的結果,也就是一個Compositor Frame。這個Compositor Frame會保存在一個DrawGLInput對象中。這個DrawGLInput對象又會保存在BrowserViewRenderer類的成員變量shared_renderer_state_指向的一個SharedRendererState對象中。這是通過調用SharedRendererState類的成員函數SetDrawGLInput實現的,如下所示:

void SharedRendererState::SetDrawGLInput(scoped_ptr<DrawGLInput> input) {
  ......
  draw_gl_input_ = input.Pass();
}

這個函數定義在文件external/chromium_org/android_webview/browser/shared_renderer_state.cc中。

SharedRendererState類的成員函數SetDrawGLInput將參數input指向的一個DrawGLInput對象保存成員變量draw_gl_input_中。

這一步執行完成后,再回到前面分析的BrowserViewRenderer類的成員函數OnDrawHardware中,接下來它會調用成員變量client_指向的一個Native層AwContents對象的成員函數RequestDrawGL請求在參數java_canvas描述的一個Hardware Canvas中增加一個DrawFunctorOp操作,如下所示:

bool AwContents::RequestDrawGL(jobject canvas, bool wait_for_completion) {
  ......

  JNIEnv* env = AttachCurrentThread();
  ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
  if (obj.is_null())
    return false;
  return Java_AwContents_requestDrawGL(
      env, obj.obj(), canvas, wait_for_completion);
}

這個函數定義在文件external/chromium_org/android_webview/native/aw_contents.cc中。

在前面 Android WebView執行GPU命令的過程分析 一文中,我們已經分析過Native層AwContents類的成員函數RequestDrawGL的實現了,它主要就是調用Java層的AwContents類的成員函數requestDrawGL請求在參數canvas描述的Hardware Canvas中增加一個DrawFunctorOp操作。

Java層的AwContents類的成員函數requestDrawGL最終會調用到DrawGLFunctor類的成員函數requestDrawGL在參數canvas描述的Hardware Canvas中增加一個DrawFunctorOp操作,如下所示:

class DrawGLFunctor {
    ......

    public boolean requestDrawGL(HardwareCanvas canvas, ViewRootImpl viewRootImpl,
            boolean waitForCompletion) {
        ......

        if (canvas == null) {
            viewRootImpl.invokeFunctor(mDestroyRunnable.mNativeDrawGLFunctor, waitForCompletion);
            return true;
        }

        canvas.callDrawGLFunction(mDestroyRunnable.mNativeDrawGLFunctor);
        ......

        return true;
    }

    ......
}

這個函數定義在文件frameworks/webview/chromium/java/com/android/webview/chromium/DrawGLFunctor.java中。

在前面 Android WebView執行GPU命令的過程分析 一文中,DrawGLFunctor類的成員函數requestDrawGL是在Render端光柵化網頁UI的過程中調用的。這時候參數canvas的值等于null,因此DrawGLFunctor類的成員函數requestDrawGL會通過調用參數viewRootImpl指向的一個ViewRootImpl對象的成員函數invokeFunctor直接請求App的Render Thread執行GPU命令。

現在,當DrawGLFunctor類的成員函數requestDrawGL被調用時,它的參數canvas的值不等于null,指向了一個Hardware Canvas。在這種情況下,DrawGLFunctor類的成員函數requestDrawGL將會調用這個Hardware Canvas的成員函數callDrawGLFunction,將一個Native層DrawGLFunctor對象封裝成一個DrawFunctorOp操作,寫入到它描述一個Display List中去。

被封裝的Native層DrawGLFunctor對象,保存在Java層DrawGLFunctor類的成員變量mDestroyRunnable指向的一個DestroyRunnable對象的成員變量mNativeDrawGLFunctor中。

從前面 Android應用程序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。在同步的過程中,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的學習。

 

來自:http://blog.csdn.net/luoshengyang/article/details/53366272

 

 本文由用戶 Nicy 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!