Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android系統教程 >> 安卓省電與加速 >> 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 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的過程。

從前面一文可以知道,在App渲染UI的第一階段,Android WebView的成員函數onDraw會被調用。從前面一文又可以知道,Android WebView在Native層有一個BrowserViewRenderer對象。當Android WebView的成員函數onDraw被調用時,並且App的UI以硬件加速方式渲染時,這個Native層BrowserViewRenderer對象的成員函數OnDrawHardware會被調用,如下所示:

 

bool BrowserViewRenderer::OnDrawHardware(jobject java_canvas) {   
  ......  
  
  scoped_ptr draw_gl_input(new DrawGLInput);  
  ......  
  
  scoped_ptr 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中。

從前面一文可以知道,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 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 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中。

 

從前面一文可以知道,SynchronousCompositorImpl類的成員變量output_surface_指向的是一個SynchronousCompositorOutputSurface對象。SynchronousCompositorImpl類的成員函數DemandDrawHw調用這個SynchronousCompositorOutputSurface對象的成員函數DemandDrawHw繪制網頁的UI,如下所示:

 

scoped_ptr
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繼承下來的。從前面一文可以知道,它指向的是一個LayerTreeHostImpl對象。SynchronousCompositorOutputSurface類的成員函數InvokeComposite調用這個LayerTreeHostImpl對象的成員函數BeginFrame繪制網頁的UI。

從前面一文可以知道,當LayerTreeHostImpl類的成員函數BeginFrame被調用時,它就會CC模塊的調度器執行一個BEGIN_IMPL_FRAME操作,也就是對網頁的CC Layer Tree進行繪制。

由於Android WebView的Render端使用的是Synchronous Compositor,當前線程(也就是App的UI線程)會等待Render端的Compositor線程繪制完成網頁的CC Layer Tree。從前面一文可以知道,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描述的就是網頁的繪制結果。從前面一文可以知道,這個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 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 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中。

 

在前面一文中,我們已經分析過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中。

 

在前面一文中,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中。

從前面一文可以知道,參數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(rendererPtr);
    Functor* functor = reinterpret_cast(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端。

在前面一文中,我們已經分析過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 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 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的窗口中,這樣就可以顯示在屏幕中了。

從前面一文可以知道,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命令。

在前面一文中,我們已經分析過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中。

 

從前面一文可以知道,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(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中。

 

從前面一文可以知道,SingleThreadProxy類的成員變量layer_tree_host_impl_指向的是一個LayerTreeHostImpl對象。SingleThreadProxy類的成員函數DoComposite主要是調用這個LayerTreeHostImpl對象的成員函數PrepareToDraw和DrawLayers繪制Browser端的CC Layer Tree。

LayerTreeHostImpl類的成員函數PrepareToDraw和DrawLayers繪制CC Layer Tree的過程。從前面一文我們還可以知道,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的學習。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved