chromium:LoadUrl之后会发生那些事情之OnDraw
2015-07-25 16:37
369 查看
一 综述
自从Android系统WebView内核使用chromium以来,其渲染机制一直在持续不断演进,本文将以M42内核分析WebView的渲染架构以及相关代码分析。
先从代码流程进行分析,当WebView需要重新绘制时会调用:
WebView.OnDraw(Canvas canvas)
--->WebViewChromium.onDraw(Canvas canvas)
-->AwContents.onDraw(Canvas canvas)
在AwContents中,通过native方法(nativewOnDraw)继续进入C++层,AwContents::OnDraw(),在这里会决定是软件渲染,还是硬件渲染。当硬件渲染时,调用
BrowserViewRenderer::OnDrawHardware()。
在代码中,我们看到BrowserViewRenderer的解释是Interface for all the WebView-specific content rendering operations.,可知它是专门为Android WebView渲染机制而生的。
这里继续分析发现最新的Chromium WebView渲染机制采用了两级合成器,分别是SynchronousCompositor和ParentCompositor,它们分别运行在UI线程和Renderer线程,
通过SharedRendererState进行跨线程数据同步和共享。
二 SynchronousCompositor
当WebView发生任何需要绘制时,这是在UI线程,它会走到同步合成器:SynchronousCompositor。
SynchronousCompositor是虚基类,它的实现类对象是SynchronousCompositorImp通过DidInitializeCompositor()直接将其传到BrowserViewRenderer中。
当需要硬件渲染时,在BrowserViewRenderer::OnDrawHardware()
会调用BrowserViewRenderer::CompositeHw()
--->SynchronousCompositorImp::DemandDrawHw()
--->SynchronousCompositorOutputSurface::DemandDrawHw()
--->SynchronousCompositorOutputSurface::InvokeComposite()
---->SynchronousCompositorExternalBeginFrameSource::BeginFrame()
接着就到达cc中的ThreadProxy::BeginMainFrame(), 然后就如之前 五、六、七、八四篇中所述那样进行网页重新Layout, UpdateLayers,DrawLayers,最后将收集好的所有绘制命令PrepareSendToParent()。
三 ParentCompositor
前面的SynchronousCompositor,相对于ParentCompositor也可以叫child compositor。ParentCompositor是在HardwareRenderer中创建的, 它也有相应的OutputSurface,叫
ParentOutputSurface。
来看看渲染线程的compositor,在HardwareRenderer中,首先会创建root_layer_、layer_tree_host_、output_surface_以及SingleThreadProxy,另外,root_layer_的子树是一个DelegatedRendererLayer,有且只有一个子树,由此可见这颗Tree是非常简单的。这样就构成了完整的渲染线程合成器。
四 绘制
在UI线程,BrowserViewRenderer::OnDrawHardware()得到网页的合成结果CompositeFrame后,调用shared_renderer_state_.SetCompositorFrameOnUI(frame.Pass(), false);
将CompositeFrame传给SharedRendererState,以便渲染线程的合成器使用。
在Renderer线程,HardwareRenderer::DrawGL()首先会
#1 调用HardwareRenderer::CommitFrame(),将UI线程中保存在SharedRendererState中的CompositeFrame同步过来,即
committed_frame_ = shared_renderer_state_->PassCompositorFrameOnRT();
#2 调用HardwareRenderer::SetFrameData(),将committed_frame_传给合成器,代码如下:
171 void HardwareRenderer::SetFrameData() {
172 if (!committed_frame_.get())
173 return;
174
175 scoped_ptr<cc::CompositorFrame> frame = committed_frame_.Pass();
176 gfx::Size frame_size =
177 frame->delegated_frame_data->render_pass_list.back()->output_rect.size();
178 bool size_changed = frame_size != frame_size_;
179 frame_size_ = frame_size;
180
181 if (!frame_provider_.get() || size_changed) {
182 if (delegated_layer_.get()) {
183 delegated_layer_->RemoveFromParent();
184 }
185
186 frame_provider_ = new cc::DelegatedFrameProvider(
187 resource_collection_.get(), frame->delegated_frame_data.Pass());
188
189 delegated_layer_ = cc::DelegatedRendererLayer::Create(frame_provider_);
190 delegated_layer_->SetBounds(frame_size_);
191 delegated_layer_->SetIsDrawable(true);
192
193 root_layer_->AddChild(delegated_layer_);
194 } else {
195 frame_provider_->SetFrameData(frame->delegated_frame_data.Pass());
196 }
197 }
#3 绑定当前FBO,合成器进行合成操作,代码如下:
246 gl_surface_->SetBackingFrameBufferObject(framebuffer_binding_ext);
247 {
248 base::AutoReset<bool> frame_resetter(&viewport_clip_valid_for_dcheck_,
249 true);
250 layer_tree_host_->SetNeedsRedrawRect(clip_);
251 layer_tree_host_->Composite(gfx::FrameTime::Now());
252 }
253 gl_surface_->ResetBackingFrameBufferObject();
254 }
#4 composite合成操作流程
LayerTreeHost::Composite()
-->SingleThreadProxy::CompositeImmediately()
--->SingleThreadProxy::DoComposite()
---->LayerTreeHostImpl::DrawLayers()
---->GLRenderer::DrawFrame()
---->DirectRenderer::DrawFrame()
---->DirectRenderer::DrawRenderPass()
---->GLRenderer::DoDrawQuad()
五 总结
硬件渲染逻辑分解为两个步骤:
#1 在UI线程上调用Synchronous Compositor合成操作生成新的CompositorFrame,再向Android系统请求执行DrawGL回调函数,但此时DrawGL并不会立即执行。
UI线程负责为发生invalidate操作的View生成显示列表,再将这个显示列表同步给渲染线程上的HardwareRenderer;
#2 Android View系统在渲染线程上将显示列表提交给GPU驱动,绘制View层次的内容,在绘制显示列表的过程中,DrawGL函数将会被调用,在渲染线程上请求
Parent Compositor将合成的页面内容绘制到HardwareCanvas上。
上述整个过程可以用下图来表示。
![](http://img.blog.csdn.net/20150725164105880?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
Android WebView渲染流程图
自从Android系统WebView内核使用chromium以来,其渲染机制一直在持续不断演进,本文将以M42内核分析WebView的渲染架构以及相关代码分析。
先从代码流程进行分析,当WebView需要重新绘制时会调用:
WebView.OnDraw(Canvas canvas)
--->WebViewChromium.onDraw(Canvas canvas)
-->AwContents.onDraw(Canvas canvas)
在AwContents中,通过native方法(nativewOnDraw)继续进入C++层,AwContents::OnDraw(),在这里会决定是软件渲染,还是硬件渲染。当硬件渲染时,调用
BrowserViewRenderer::OnDrawHardware()。
在代码中,我们看到BrowserViewRenderer的解释是Interface for all the WebView-specific content rendering operations.,可知它是专门为Android WebView渲染机制而生的。
这里继续分析发现最新的Chromium WebView渲染机制采用了两级合成器,分别是SynchronousCompositor和ParentCompositor,它们分别运行在UI线程和Renderer线程,
通过SharedRendererState进行跨线程数据同步和共享。
二 SynchronousCompositor
当WebView发生任何需要绘制时,这是在UI线程,它会走到同步合成器:SynchronousCompositor。
SynchronousCompositor是虚基类,它的实现类对象是SynchronousCompositorImp通过DidInitializeCompositor()直接将其传到BrowserViewRenderer中。
当需要硬件渲染时,在BrowserViewRenderer::OnDrawHardware()
会调用BrowserViewRenderer::CompositeHw()
--->SynchronousCompositorImp::DemandDrawHw()
--->SynchronousCompositorOutputSurface::DemandDrawHw()
--->SynchronousCompositorOutputSurface::InvokeComposite()
---->SynchronousCompositorExternalBeginFrameSource::BeginFrame()
接着就到达cc中的ThreadProxy::BeginMainFrame(), 然后就如之前 五、六、七、八四篇中所述那样进行网页重新Layout, UpdateLayers,DrawLayers,最后将收集好的所有绘制命令PrepareSendToParent()。
三 ParentCompositor
前面的SynchronousCompositor,相对于ParentCompositor也可以叫child compositor。ParentCompositor是在HardwareRenderer中创建的, 它也有相应的OutputSurface,叫
ParentOutputSurface。
来看看渲染线程的compositor,在HardwareRenderer中,首先会创建root_layer_、layer_tree_host_、output_surface_以及SingleThreadProxy,另外,root_layer_的子树是一个DelegatedRendererLayer,有且只有一个子树,由此可见这颗Tree是非常简单的。这样就构成了完整的渲染线程合成器。
四 绘制
在UI线程,BrowserViewRenderer::OnDrawHardware()得到网页的合成结果CompositeFrame后,调用shared_renderer_state_.SetCompositorFrameOnUI(frame.Pass(), false);
将CompositeFrame传给SharedRendererState,以便渲染线程的合成器使用。
在Renderer线程,HardwareRenderer::DrawGL()首先会
#1 调用HardwareRenderer::CommitFrame(),将UI线程中保存在SharedRendererState中的CompositeFrame同步过来,即
committed_frame_ = shared_renderer_state_->PassCompositorFrameOnRT();
#2 调用HardwareRenderer::SetFrameData(),将committed_frame_传给合成器,代码如下:
171 void HardwareRenderer::SetFrameData() {
172 if (!committed_frame_.get())
173 return;
174
175 scoped_ptr<cc::CompositorFrame> frame = committed_frame_.Pass();
176 gfx::Size frame_size =
177 frame->delegated_frame_data->render_pass_list.back()->output_rect.size();
178 bool size_changed = frame_size != frame_size_;
179 frame_size_ = frame_size;
180
181 if (!frame_provider_.get() || size_changed) {
182 if (delegated_layer_.get()) {
183 delegated_layer_->RemoveFromParent();
184 }
185
186 frame_provider_ = new cc::DelegatedFrameProvider(
187 resource_collection_.get(), frame->delegated_frame_data.Pass());
188
189 delegated_layer_ = cc::DelegatedRendererLayer::Create(frame_provider_);
190 delegated_layer_->SetBounds(frame_size_);
191 delegated_layer_->SetIsDrawable(true);
192
193 root_layer_->AddChild(delegated_layer_);
194 } else {
195 frame_provider_->SetFrameData(frame->delegated_frame_data.Pass());
196 }
197 }
#3 绑定当前FBO,合成器进行合成操作,代码如下:
246 gl_surface_->SetBackingFrameBufferObject(framebuffer_binding_ext);
247 {
248 base::AutoReset<bool> frame_resetter(&viewport_clip_valid_for_dcheck_,
249 true);
250 layer_tree_host_->SetNeedsRedrawRect(clip_);
251 layer_tree_host_->Composite(gfx::FrameTime::Now());
252 }
253 gl_surface_->ResetBackingFrameBufferObject();
254 }
#4 composite合成操作流程
LayerTreeHost::Composite()
-->SingleThreadProxy::CompositeImmediately()
--->SingleThreadProxy::DoComposite()
---->LayerTreeHostImpl::DrawLayers()
---->GLRenderer::DrawFrame()
---->DirectRenderer::DrawFrame()
---->DirectRenderer::DrawRenderPass()
---->GLRenderer::DoDrawQuad()
五 总结
硬件渲染逻辑分解为两个步骤:
#1 在UI线程上调用Synchronous Compositor合成操作生成新的CompositorFrame,再向Android系统请求执行DrawGL回调函数,但此时DrawGL并不会立即执行。
UI线程负责为发生invalidate操作的View生成显示列表,再将这个显示列表同步给渲染线程上的HardwareRenderer;
#2 Android View系统在渲染线程上将显示列表提交给GPU驱动,绘制View层次的内容,在绘制显示列表的过程中,DrawGL函数将会被调用,在渲染线程上请求
Parent Compositor将合成的页面内容绘制到HardwareCanvas上。
上述整个过程可以用下图来表示。
Android WebView渲染流程图
相关文章推荐
- poj 3225 Help with Intervals(线段树区间更新)
- RTTI
- hdoj 2816 I Love You Too
- 以太网帧格式、IP数据报格式、TCP段格式+UDP段格式 详解
- A*算法—第K短路
- Android 四大组件学习之BroadcastReceiver一
- 应届毕业生外包公司体验
- rabbitmq技术的一些感悟(一)
- C++栈的顺序存储和链式存储的实现
- N个鸡蛋从M楼层摔(2个鸡蛋从100层摔)
- OC__内存管理初级
- 十个Android Material Design库
- ios学习整理(二)使用drawRect:方法自定义绘图和UIBezierPath类
- Java基础之异常、io流
- iOS开发-UITableView单选多选/复选实现1
- [题解]铺地毯
- 一些shell简单脚本
- chromium:LoadUrl之后会发生那些事情之 cc::drawLayers
- (C++)STL排序函数sort和qsort的用法与区别
- Leetcode: Product of Array Except Self