Android WebView硬件加速渲染网页UI的过程分析
Nicy
8年前
<p>Android WebView作为App UI的一部分,当App UI以硬件加速方式渲染时,它也是以硬件加速方式渲染的。Android WebView的UI来自于网页,是通过Chromium渲染的。Chromium渲染网页UI的机制与Android App渲染UI的机制是不一样的。不过,它们会一起协作完成网页UI的渲染。本文接下来就详细分析Android WebView硬件加速渲染网页UI的过程。</p> <p>从前面 Android应用程序UI硬件加速渲染技术简要介绍和学习计划 这个系列的文章可以知道,Android App在渲染UI一帧的过程中,经历以下三个阶段:</p> <p>1. 在UI线程中构建一个Display List,这个Display List包含了每一个View的绘制命令。</p> <p>2. 将前面构建的Display List同步给Render Thread。</p> <p>3. Render Thread对同步得到的Display List进行渲染,也就是使用GPU执行Display List的绘制命令。</p> <p>上述三个阶段如果能够在16ms内完成,那么App的UI给用户的感受就是流畅的。为了尽量地在16ms内渲染完成App的一帧UI,Android使用了以上方式对App的UI进行渲染。这种渲染机制的好处是UI线程和Render Thread可以并发执行,也就是Render Thread在渲染当前帧的Display List的时候,UI线程可以准备下一帧的Display List。它们唯一需要同步的地方发生第二阶段。不过,这个阶段是可以很快完成的。因此,UI线程和Render Thread可以认为是并发执行的。</p> <p>Android WebView既然是App UI的一部分,也就是其中的一个View,它的渲染也是按照上述三个阶段进行的,如下所示:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/124d8502a66fbf0f4eb41a93b52ab087.png"></p> <p>图1 Android WebView硬件加速渲染网页UI的过程</p> <p>在第一阶段,Android WebView会对Render端的CC Layer Tree进行绘制。这个CC Layer Tree描述的就是网页的UI,它会通过一个Synchronous Compositor绘制在一个Synchronous Compositor Output Surface上,最终得到一个Compositor Frame。这个Compositor Frame会保存在一个SharedRendererState对象中。</p> <p>在第二阶段,保存在上述SharedRendererState对象中的Compositor Frame会同步给Android WebView会对Browser端的CC Layer Tree。Browser端的CC Layer Tree只有两个节点。一个是根节点,另一个是根节点的子节点,称为一个Delegated Renderer Layer。Render端绘制出来的Compositor Frame就是作为这个Delegated Renderer Layer的输入的。</p> <p>在第三阶段,Android WebView会通过一个Hardware Renderer将Browser端的CC Layer Tree渲染在一个Parent Output Surface上,实际上就是通过GPU命令将Render端绘制出来的UI合成显示在App的UI窗口中。</p> <p>接下来,我们就按照以上三个阶段分析Android WebView硬件加速渲染网页UI的过程。</p> <p>从前面 Android应用程序UI硬件加速渲染的Display List构建过程分析 一文可以知道,在App渲染UI的第一阶段,Android WebView的成员函数onDraw会被调用。从前面 Android WebView执行GPU命令的过程分析 一文又可以知道,Android WebView在Native层有一个BrowserViewRenderer对象。当Android WebView的成员函数onDraw被调用时,并且App的UI以硬件加速方式渲染时,这个Native层BrowserViewRenderer对象的成员函数OnDrawHardware会被调用,如下所示:</p> <pre> <code class="language-java">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); }</code></pre> <p>这个函数定义在文件external/chromium_org/android_webview/browser/browser_view_renderer.cc中。</p> <p>从前面 Android WebView执行GPU命令的过程分析 一文可以知道,BrowserViewRenderer类的成员变量compositor_指向的是一个SynchronousCompositorImpl对象。BrowserViewRenderer对象的成员函数OnDrawHardware会调用这个SynchronousCompositorImpl对象的成员函数DemandDrawHw对网页的UI进行绘制。</p> <p>绘制的结果是得到一个Compositor Frame。这个Compositor Frame会保存在一个DrawGLInput对象中。这个DrawGLInput对象又会保存在BrowserViewRenderer类的成员变量shared_renderer_state_指向的一个SharedRendererState对象中。这是通过调用SharedRendererState类的成员函数SetDrawGLInput实现的。</p> <p>BrowserViewRenderer类的成员变量client_指向的是一个AwContents对象。BrowserViewRenderer对象的成员函数OnDrawHardware最后会调用这个AwContents对象的成员函数RequestDrawGL请求在参数java_canvas描述的一个Hardware Canvas中增加一个DrawFunctorOp操作。这个DrawFunctorOp操作最终会包含在App的UI线程构建的Display List中。</p> <p>接下来,我们首先分析SynchronousCompositorImpl类的成员函数DemandDrawHw绘制网页的UI的过程,如下所示:</p> <pre> <code class="language-java">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(); }</code></pre> <p>这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_impl.cc中。</p> <p>从前面 Android WebView执行GPU命令的过程分析 一文可以知道,SynchronousCompositorImpl类的成员变量output_surface_指向的是一个SynchronousCompositorOutputSurface对象。SynchronousCompositorImpl类的成员函数DemandDrawHw调用这个SynchronousCompositorOutputSurface对象的成员函数DemandDrawHw绘制网页的UI,如下所示:</p> <pre> <code class="language-java">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(); }</code></pre> <p>这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_output_surface.cc中。</p> <p>SynchronousCompositorOutputSurface类的成员函数DemandDrawHw调用另外一个成员函数InvokeComposite绘制网页的UI。绘制完成后,就会得到一个Compositor Frame。这个Compositor Frame保存在SynchronousCompositorOutputSurface类的成员变量frame_holder_中。因此,SynchronousCompositorOutputSurface类的成员函数DemandDrawHw可以将这个成员变量frame_holder_指向的Compositor Frame返回给调用者。</p> <p>SynchronousCompositorOutputSurface类的成员函数InvokeComposite的实现如下所示:</p> <pre> <code class="language-java">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()); ...... }</code></pre> <p>这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_output_surface.cc中。</p> <p>SynchronousCompositorOutputSurface类的成员变量client_是从父类OutputSurface继承下来的。从前面 Chromium网页绘图表面(Output Surface)创建过程分析 一文可以知道,它指向的是一个LayerTreeHostImpl对象。SynchronousCompositorOutputSurface类的成员函数InvokeComposite调用这个LayerTreeHostImpl对象的成员函数BeginFrame绘制网页的UI。 </p> <p>从前面 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的过程分析 这三篇文章。</p> <p>由于Android WebView的Render端使用的是Synchronous Compositor,当前线程(也就是App的UI线程)会等待Render端的Compositor线程绘制完成网页的CC Layer Tree。从前面 Chromium硬件加速渲染的UI合成过程分析 一文可以知道,Compositor线程在绘制完成网页的CC Layer Tree的时候,会调用网页的Output Surface的成员函数SwapBuffers。</p> <p>在我们这个情景中,网页的Output Surface是一个Synchronous Compositor Output Surface。这意味着当Compositor线程在绘制完成网页的CC Layer Tree时,会调用SynchronousCompositorOutputSurface类的成员函数SwapBuffers,如下所示:</p> <pre> <code class="language-java">void SynchronousCompositorOutputSurface::SwapBuffers( cc::CompositorFrame* frame) { ...... frame_holder_.reset(new cc::CompositorFrame); frame->AssignTo(frame_holder_.get()); ...... }</code></pre> <p>这个函数定义在文件external/chromium_org/content/browser/android/in_process/synchronous_compositor_output_surface.cc中。</p> <p>参数frame指向的Compositor Frame描述的就是网页的绘制结果。从前面 Chromium硬件加速渲染的UI合成过程分析 一文可以知道,这个Compositor Frame包含了一系列的Render Pass。每一个Render Pass都包含了若干个纹理,以及每一个纹理的绘制参数。这些纹理是在Render端光栅化网页时产生的。Browser端的Hardware Renderer所要做的事情就是将这些纹理渲染在屏幕上。这个过程也就是Browser端合成网页UI的过程。</p> <p>SynchronousCompositorOutputSurface类的成员函数SwapBuffers会将参数frame描述的Compositor Frame的内容拷贝一份到一个新创建的Compositor Frame中去。这个新创建的Compositor Frame会保存在SynchronousCompositorOutputSurface类的成员变量frame_hodler_中。因此,前面分析的SynchronousCompositorOutputSurface类的成员函数InvokeComposite返回给调用者的就是当前绘制的网页的内容。</p> <p>这一步执行完成后,回到前面分析的BrowserViewRenderer类的成员函数OnDrawHardware中,这时候它就获得了一个Render端绘制网页的结果,也就是一个Compositor Frame。这个Compositor Frame会保存在一个DrawGLInput对象中。这个DrawGLInput对象又会保存在BrowserViewRenderer类的成员变量shared_renderer_state_指向的一个SharedRendererState对象中。这是通过调用SharedRendererState类的成员函数SetDrawGLInput实现的,如下所示:</p> <pre> <code class="language-java">void SharedRendererState::SetDrawGLInput(scoped_ptr<DrawGLInput> input) { ...... draw_gl_input_ = input.Pass(); }</code></pre> <p>这个函数定义在文件external/chromium_org/android_webview/browser/shared_renderer_state.cc中。</p> <p>SharedRendererState类的成员函数SetDrawGLInput将参数input指向的一个DrawGLInput对象保存成员变量draw_gl_input_中。</p> <p>这一步执行完成后,再回到前面分析的BrowserViewRenderer类的成员函数OnDrawHardware中,接下来它会调用成员变量client_指向的一个Native层AwContents对象的成员函数RequestDrawGL请求在参数java_canvas描述的一个Hardware Canvas中增加一个DrawFunctorOp操作,如下所示:</p> <pre> <code class="language-java">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); }</code></pre> <p>这个函数定义在文件external/chromium_org/android_webview/native/aw_contents.cc中。</p> <p>在前面 Android WebView执行GPU命令的过程分析 一文中,我们已经分析过Native层AwContents类的成员函数RequestDrawGL的实现了,它主要就是调用Java层的AwContents类的成员函数requestDrawGL请求在参数canvas描述的Hardware Canvas中增加一个DrawFunctorOp操作。</p> <p>Java层的AwContents类的成员函数requestDrawGL最终会调用到DrawGLFunctor类的成员函数requestDrawGL在参数canvas描述的Hardware Canvas中增加一个DrawFunctorOp操作,如下所示:</p> <pre> <code class="language-java">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; } ...... }</code></pre> <p>这个函数定义在文件frameworks/webview/chromium/java/com/android/webview/chromium/DrawGLFunctor.java中。</p> <p>在前面 Android WebView执行GPU命令的过程分析 一文中,DrawGLFunctor类的成员函数requestDrawGL是在Render端光栅化网页UI的过程中调用的。这时候参数canvas的值等于null,因此DrawGLFunctor类的成员函数requestDrawGL会通过调用参数viewRootImpl指向的一个ViewRootImpl对象的成员函数invokeFunctor直接请求App的Render Thread执行GPU命令。</p> <p>现在,当DrawGLFunctor类的成员函数requestDrawGL被调用时,它的参数canvas的值不等于null,指向了一个Hardware Canvas。在这种情况下,DrawGLFunctor类的成员函数requestDrawGL将会调用这个Hardware Canvas的成员函数callDrawGLFunction,将一个Native层DrawGLFunctor对象封装成一个DrawFunctorOp操作,写入到它描述一个Display List中去。</p> <p>被封装的Native层DrawGLFunctor对象,保存在Java层DrawGLFunctor类的成员变量mDestroyRunnable指向的一个DestroyRunnable对象的成员变量mNativeDrawGLFunctor中。</p> <p>从前面 Android应用程序UI硬件加速渲染的Display List渲染过程分析 一文可以知道,参数canvas描述的Hardware Canvas是通过一个GLES20Canvas对象描述的,因此接下来它的成员函数callDrawGLFunction会被调用,用来将一个Native层DrawGLFunctor对象封装成一个DrawFunctorOp操作写入它描述一个Display List中去,如下所示:</p> <pre> <code class="language-java">class GLES20Canvas extends HardwareCanvas { ...... @Override public int callDrawGLFunction(long drawGLFunction) { return nCallDrawGLFunction(mRenderer, drawGLFunction); } ...... }</code></pre> <p>这个函数定义在文件frameworks/base/core/java/android/view/GLES20Canvas.java中。</p> <p>GLES20Canvas类的成员函数callDrawGLFunction调用另外一个成员函数nCallDrawGLFunction将参数drawGLFunction描述的一个Native层DrawGLFunctor对象封装成一个DrawFunctorOp操作写入到当前正在处理的GLES20Canvas对象描述一个Display List中去。</p> <p>GLES20Canvas类的成员函数nCallDrawGLFunction是一个JNI方法,它由C++层的函数android_view_GLES20Canvas_callDrawGLFunction实现,如下所示:</p> <pre> <code class="language-java">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); }</code></pre> <p>这个函数定义在文件frameworks/base/core/jni/android_view_GLES20Canvas.cpp中。</p> <p>参数rendererPtr描述的是一个Native层的DisplayListRenderer对象。这个DisplayListRenderer对象负责构造App UI的Display List。函数android_view_GLES20Canvas_callDrawGLFunction所做的事情就是调用这个DisplayListRenderer对象的成员函数callDrawFunction将参数functionPtr描述的一个Native层DrawGLFunctor对象封装成一个DrawFunctorOp操作写入到App UI的Display List中去,如下所示:</p> <pre> <code class="language-java">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 }</code></pre> <p>这个函数定义在文件frameworks/base/libs/hwui/DisplayListRenderer.cpp中。</p> <p>DisplayListRenderer类的成员变量mDisplayListData指向的是一个DisplayListData对象。这个DisplayListData对象描述的就是App UI的Display List。因此,DisplayListRenderer对象的成员函数callDrawFunction就会将参数functor描述的一个Native层DrawGLFunctor对象封装成一个DrawFunctorOp操作写入到它里面去。</p> <p>这一步执行完成后,Android WebView就在App渲染一个帧的第一个阶段通知Render端绘制完成了网页的UI,并且往App UI的Display List写入了一个DrawFunctorOp操作。在第二阶段,App UI的Display List就会从App的UI线程同步给App的Render Thread。在同步的过程中,RenderNode类的成员函数pushStagingDisplayListChanges地被调用,如下所示:</p> <pre> <code class="language-java">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); } } ...... } }</code></pre> <p>这个函数定义在文件frameworks/base/libs/hwui/RenderNode.cpp中。</p> <p>这时候包含在App UI的Display List中的每一个DrawFunctorOp操作关联的Native层DrawGLFunctor对象的重载操作符函数()都会被调用,目的是让它执行一些同步操作。在我们这个情景中,就是将Render端绘制出来的UI同步到给Browser端。</p> <p>在前面 Android WebView执行GPU命令的过程分析 一文中,我们已经分析过Native层DrawGLFunctor对象的重载操作符函数()的实现了,它最终会调用到Native层的AwContents类DrawGL将Render端绘制出来的UI同步到给Browser端,如下所示:</p> <pre> <code class="language-java">void AwContents::DrawGL(AwDrawGLInfo* draw_info) { if (draw_info->mode == AwDrawGLInfo::kModeSync) { if (hardware_renderer_) hardware_renderer_->CommitFrame(); return; } ...... }</code></pre> <p>这个函数定义在文件external/chromium_org/android_webview/native/aw_contents.cc中。</p> <p>这时候App的Render Thread处于AwDrawGLInfo::kModeSync状态,因此AwContents类的成员函数DrawGL接下来将会调用成员变量hardware_renderer_指向的一个HardwareRenderer对象的成员函数CommitFrame将Render端绘制出来的UI同步到给Browser端,如下所示:</p> <pre> <code class="language-java">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()); } }</code></pre> <p>这个函数定义在文件external/chromium_org/android_webview/browser/hardware_renderer.cc中。</p> <p>从前面的分析可以知道,Render端在第一阶段已经将绘制出来的网页UI,保存在一个DrawGLInput对象中。这个DrawGLInput又保存在一个SharedRendererState对象中。HardwareRenderer类的成员变量shared_renderer_state_描述的就是这个SharedRendererState对象。因此,HardwareRenderer类的成员函数CommitFrame可以通过调用这个SharedRendererState对象的成员函数PassDrawGLInput获得保存在它内部的DrawGLInput对象,如下所示:</p> <pre> <code class="language-java">scoped_ptr<DrawGLInput> SharedRendererState::PassDrawGLInput() { base::AutoLock lock(lock_); return draw_gl_input_.Pass(); }</code></pre> <p>这个函数定义在文件external/chromium_org/android_webview/browser/shared_renderer_state.cc中。</p> <p>从前面的分析可以知道,用来描述Render端在第一阶段绘制出来的网页UI的DrawGLInput对象就保存在SharedRendererState类的成员变量draw_gl_input_中,因此SharedRendererState类的成员函数PassDrawGLInput就可以将这个员变量draw_gl_input_指向的DrawGLInput对象返回给调用者。</p> <p>回到前面分析的HardwareRenderer类的成员函数CommitFrame中,这时候它获得了一个Render端在第一阶段绘制出来的UI,也就是一个DrawGLInput对象,接下来它就会判断之前是否已经为Browser端的CC Layer Tree创建过一个Delegated Renderer Layer。</p> <p>如果还没有创建,或者以前创建过,但是现在Android WebView的大小发生了变化,那么HardwareRenderer类的成员函数CommitFrame就会创建用前面获得的DrawGLInput对象创建一个Delegated Renderer Layer,并且作为Browser端的CC Layer Tree的根节点的子节点。</p> <p>另一方面,如果已经创建,并且Android WebView的大小没有发生变化,那么HardwareRenderer类的成员函数CommitFrame就会使用前面获得的DrawGLInput对象更新Delegated Renderer Layer的内容。</p> <p>这一步执行完成后,Android WebView就在App渲染一个帧的第二个阶段将Render端绘制出来的网页UI同步给了Browser端。在第三阶段,Browser端就会将网页的UI合成在App的窗口中,这样就可以显示在屏幕中了。</p> <p>从前面 Android应用程序UI硬件加速渲染的Display List渲染过程分析 一文可以知道,App的Render Thread在第三阶段会通过一个OpenGL Renderer渲染从App的UI线程同步过来的Display List,也就是执行它里面包含的渲染操作。从前面的分析可以知道,Android WebView在第一阶段往这个Display List写入了一个DrawFunctorOp操作,OpenGL Renderer会通过调用它的成员函数callDrawGLFunction执行这个操作,如下所示:</p> <pre> <code class="language-java">status_t OpenGLRenderer::callDrawGLFunction(Functor* functor, Rect& dirty) { ...... mRenderState.invokeFunctor(functor, DrawGlInfo::kModeDraw, &info); ...... return DrawGlInfo::kStatusDrew; }</code></pre> <p>这个函数定义在文件frameworks/base/libs/hwui/OpenGLRenderer.cpp中。</p> <p>参数funtor描述的就是与当前要执行的DrawFunctorOp操作关联的Native层DrawGLFunctor对象。OpenGLRenderer类的成员函数callDrawGLFunction会通过调用成员变量mRenderState指向的一个RenderState对象的成员函数invokeFunctor调用这个Native层DrawGLFunctor对象的重载操作符函数(),告知它App的Render Thread当前处于第三阶段,也就是DrawGlInfo::kModeDraw状态,它可以执行相应的GPU命令。</p> <p>在前面 Android WebView执行GPU命令的过程分析 一文中,我们已经分析过RenderState类的成员函数invokeFunctor的实现了,它最终会调用到Native层的AwContents类DrawGL将绘制Browser端的CC Layer Tree,如下所示:</p> <pre> <code class="language-java">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); ...... }</code></pre> <p>这个函数定义在文件external/chromium_org/android_webview/native/aw_contents.cc中。</p> <p>由于当前App的Render Thread处于AwDrawGlInfo::kModeDraw状态,因此AwContents类DrawGL会调用成员变量hardware_renderer_指向的一个HardwareRenderer对象的成员函数DrawGL,用来绘制Browser端的CC Layer Tree,如下所示:</p> <pre> <code class="language-java">void HardwareRenderer::DrawGL(bool stencil_enabled, int framebuffer_binding_ext, AwDrawGLInfo* draw_info) { ...... { ...... layer_tree_host_->Composite(gfx::FrameTime::Now()); } ...... }</code></pre> <p>这个函数定义在文件external/chromium_org/android_webview/browser/hardware_renderer.cc中。</p> <p>从前面 Android WebView执行GPU命令的过程分析 一文可以知道,HardwareRenderer类的成员变量layer_tree_host_指向的是一个LayerTreeHost对象。这个LayerTreeHost对象描述的就是Browser端的CC Layer Tree。HardwareRenderer类的成员函数DrawGL将会调用这个LayerTreeHost对象的成员函数Composite,以便绘制Browser端的CC Layer Tree,如下所示:</p> <pre> <code class="language-java">void LayerTreeHost::Composite(base::TimeTicks frame_begin_time) { ...... SingleThreadProxy* proxy = static_cast<SingleThreadProxy*>(proxy_.get()); ..... proxy->CompositeImmediately(frame_begin_time); }</code></pre> <p>这个函数定义在文件external/chromium_org/cc/trees/layer_tree_host.cc中。</p> <p>从前面 Android WebView执行GPU命令的过程分析 一文可以知道,当前正在处理的LayerTreeHost对象的成员变量proxy_指向的是一个SingleThreadProxy对象,LayerTreeHost类的成员函数Composite调用这个SingleThreadProxy对象的成员函数CompositeImmediately绘制Browser端的CC Layer Tree,如下所示:</p> <pre> <code class="language-java">void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) { ...... LayerTreeHostImpl::FrameData frame; if (DoComposite(frame_begin_time, &frame)) { { ...... } ...... } }</code></pre> <p>这个函数定义在文件external/chromium_org/cc/trees/single_thread_proxy.cc中。</p> <p>SingleThreadProxy类的成员函数CompositeImmediately主要是调用另外一个成员函数DoComposite绘制Browser端的CC Layer Tree,如下所示:</p> <pre> <code class="language-java">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); ...... } ...... } ...... }</code></pre> <p>这个函数定义在文件external/chromium_org/cc/trees/single_thread_proxy.cc中。</p> <p>从前面 Android WebView执行GPU命令的过程分析 一文可以知道,SingleThreadProxy类的成员变量layer_tree_host_impl_指向的是一个LayerTreeHostImpl对象。SingleThreadProxy类的成员函数DoComposite主要是调用这个LayerTreeHostImpl对象的成员函数PrepareToDraw和DrawLayers绘制Browser端的CC Layer Tree。</p> <p>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的窗口中了。</p> <p>至此,我们就分析完成了Android WebView硬件加速渲染网页UI的过程,也完成了对Android基于Chromium实现的WebView的学习。</p> <p> </p> <p>来自:http://blog.csdn.net/luoshengyang/article/details/53366272</p> <p> </p>