收藏 分销(赏)

Chromium网页绘图表面(Output-Surface)创建过程分析.doc

上传人:仙人****88 文档编号:11739783 上传时间:2025-08-11 格式:DOC 页数:24 大小:210.50KB 下载积分:10 金币
下载 相关 举报
Chromium网页绘图表面(Output-Surface)创建过程分析.doc_第1页
第1页 / 共24页
Chromium网页绘图表面(Output-Surface)创建过程分析.doc_第2页
第2页 / 共24页


点击查看更多>>
资源描述
Chromium网页绘图表面(Output Surface)创建过程分析 在Chromium中,Render进程在绘制网页之前,要为网页创建一个绘图表面。绘图表面描述的是网页经过渲染之后得到的输出。这个输出需要交给Browser进程处理,才能显示在屏幕上。在硬件加速渲染条件下,这个输出有可能是一个OpenGL纹理,也有可能是一系列需要进一步进行绘制的OpenGL纹理,取决于Render进程使用直接渲染器还是委托渲染器。本文接下来就对网页的绘图表面的创建过程进行详细分析。 关于网页绘图表面的更详细描述,可以参考一文。本文的重点是分析Chromium的CC模块是如何触发网页绘图表面的创建的,以作为一文的补充。 网页绘图表面是由CC模块的调度器触发创建的,如图1所示: CC模块内部的状态机一旦检测到网页的Layer Tree创建和初始化完毕,就会通知调度器触发一个创建绘图表面的操作。CC模块在为网页创建 绘图表面的过程中,也有伴随着网页分块管理器、资源池和光栅化工作者线程池等基础设施的创建。一旦这些基础设施准备完毕,网页才能开 始进行绘制,也就是在图1中,第1步完成后,第2到第6步才可以周而复始地执行。 从前面一文可以知道,当网页的Graphics Layer Tree的根节点创建出来之后,WebKit就会通知Chromium的Content层初始化一个CC Layer Tree,如下所示: [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 void RenderWidget::initializeLayerTreeView() { compositor_ = RenderWidgetCompositor::Create( this, is_threaded_compositing_enabled_); ...... if (init_complete_) StartCompositor(); } 这个函数定义在文件external/chromium_org/content/renderer/render_widget.cc中。 初始化CC Layer Tree的工作是通过调用RenderWidgetCompositor类的静态成员函数Create实现的。在前面一文中,我们分析了此时 RenderWidget类的成员变量init_complete_的值等于true,因此接下来RenderWidget类的成员函数initializeLayerTreeView会调用另外一个成 员函数StartCompositor为网页创建绘图表面。 RenderWidget类的成员函数StartCompositor的实现如下所示: [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 void RenderWidget::StartCompositor() { ...... compositor_->setSurfaceReady(); } 这个函数定义在文件external/chromium_org/content/renderer/render_widget.cc中。 RenderWidget类的成员变量compositor_指向的是一个RenderWidgetCompositor对象,RenderWidget类的成员函数StartCompositor调用 这个RenderWidgetCompositor对象的成员函数setSurfaceReady,用来通知它可以为网页创建绘图表面了。 RenderWidgetCompositor类的成员函数setSurfaceReady的实现如下所示: [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 void RenderWidgetCompositor::setSurfaceReady() { layer_tree_host_->SetLayerTreeHostClientReady(); } 这个函数定义在文件external/chromium_org/content/renderer/gpu/render_widget_compositor.cc中。 RenderWidgetCompositor类的成员变量layer_tree_host_指向的是一个LayerTreeHost对象。这个LayerTreeHost对象就是用来管理CC Layer Tree的。RenderWidgetCompositor类的成员函数setSurfaceReady调用这个LayerTreeHost对象的成员函数SetLayerTreeHostClientReady ,用来通知调度器为网页创建绘图表面。 LayerTreeHost类的成员函数SetLayerTreeHostClientReady的实现如下所示: [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 void LayerTreeHost::SetLayerTreeHostClientReady() { proxy_->SetLayerTreeHostClientReady(); } 这个函数定义在文件external/chromium_org/cc/trees/layer_tree_host.cc中。 LayerTreeHost类的成员变量proxy_指向的是一个ThreadProxy对象,LayerTreeHost类的成员函数SetLayerTreeHostClientReady调用这 个ThreadProxy对象的成员函数SetLayerTreeHostClientReady,用来调度器为网页创建绘图表面。 ThreadProxy类的成员函数SetLayerTreeHostClientReady的实现如下所示: [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 void ThreadProxy::SetLayerTreeHostClientReady() { ...... Proxy::ImplThreadTaskRunner()->PostTask( FROM_HERE, base::Bind(&ThreadProxy::SetLayerTreeHostClientReadyOnImplThread, impl_thread_weak_ptr_)); } 这个函数定义在文件external/chromium_org/cc/trees/thread_proxy.cc中。 ThreadProxy类的成员函数SetLayerTreeHostClientReady向Compositor线程的消息队列发送一个Task。这个Task绑定了ThreadProxy类 的成员函数SetLayerTreeHostClientReadyOnImplThread。因此接下来ThreadProxy类的成员函数SetLayerTreeHostClientReadyOnImplThread就 会在Compositor线程中执行。 ThreadProxy类的成员函数SetLayerTreeHostClientReadyOnImplThread的实现如下所示: [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 void ThreadProxy::SetLayerTreeHostClientReadyOnImplThread() { ...... impl().scheduler->SetCanStart(); } 这个函数定义在文件external/chromium_org/cc/trees/thread_proxy.cc中。 ThreadProxy类的成员函数SetLayerTreeHostClientReadyOnImplThread将调度器设置为启动状态,这是通过调用Scheduler类的成员函 数SetCanStart实现的,如下所示: [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 void Scheduler::SetCanStart() { state_machine_.SetCanStart(); ProcessScheduledActions(); } 这个函数定义在文件external/chromium_org/cc/scheduler/scheduler.cc中。 Scheduler类的成员函数SetCanStart首先将内部的状态机设置为启动状态,这是通过调用SchedulerStateMachine类的成员函数 SetCanStart实现的,如下所示: [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 class CC_EXPORT SchedulerStateMachine { public: ...... // Set that we can create the first OutputSurface and start the scheduler. void SetCanStart() { can_start_ = true; } ...... }; 这个函数定义在文件external/chromium_org/cc/scheduler/scheduler_state_machine.h中。 SchedulerStateMachine类的成员函数SetCanStart将成员变量can_start_的值设置为true,这样就会触发调度器为网页创建绘图表面。 回到Scheduler类的成员函数SetCanStart中,它将内部的状态机设置为启动状态之后,接着调用另外一个成员函数 ProcessScheduledActions检查下一个要执行的操作,这个操作即为创建绘图表面。 Scheduler类的成员函数ProcessScheduledActions的实现如下所示: [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 void Scheduler::ProcessScheduledActions() { ...... SchedulerStateMachine::Action action; do { action = state_machine_.NextAction(); ...... state_machine_.UpdateState(action); ...... switch (action) { ...... case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION: client_->ScheduledActionBeginOutputSurfaceCreation(); break; ...... } } while (action != SchedulerStateMachine::ACTION_NONE); SetupNextBeginFrameIfNeeded(); ...... if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) { ...... ScheduleBeginImplFrameDeadline(base::TimeTicks()); } } 这个函数定义在文件external/chromium_org/cc/scheduler/scheduler_state_machine.cc中。 Scheduler类的成员函数ProcessScheduledAction的详细实现可以参考前面一文,这里 我们只关注它是如何触发网页绘图表面的创建的。 Scheduler类的成员函数ProcessScheduledAction首先调用SchedulerStateMachine类的成员函数NextAction询问状态机下一个应该执行 的操作,后者的实现如下所示: [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { if (ShouldUpdateVisibleTiles()) return ACTION_UPDATE_VISIBLE_TILES; if (ShouldActivatePendingTree()) return ACTION_ACTIVATE_PENDING_TREE; if (ShouldCommit()) return ACTION_COMMIT; if (ShouldAnimate()) return ACTION_ANIMATE; if (ShouldDraw()) { if (PendingDrawsShouldBeAborted()) return ACTION_DRAW_AND_SWAP_ABORT; else if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW) return ACTION_DRAW_AND_SWAP_FORCED; else return ACTION_DRAW_AND_SWAP_IF_POSSIBLE; } if (ShouldManageTiles()) return ACTION_MANAGE_TILES; if (ShouldSendBeginMainFrame()) return ACTION_SEND_BEGIN_MAIN_FRAME; if (ShouldBeginOutputSurfaceCreation()) return ACTION_BEGIN_OUTPUT_SURFACE_CREATION; return ACTION_NONE; } 这个函数定义在文件external/chromium_org/cc/scheduler/scheduler_state_machine.cc中。 在我们这个情景中,SchedulerStateMachine类的成员函数NextAction在调用到另外一个成员函数ShouldBeginOutputSurfaceCreation时 得到的返回值为true,后者的实现如下所示: [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 bool SchedulerStateMachine::ShouldBeginOutputSurfaceCreation() const { // Don't try to initialize too early. if (!can_start_) return false; // We only want to start output surface initialization after the // previous commit is complete. if (commit_state_ != COMMIT_STATE_IDLE) return false; // Make sure the BeginImplFrame from any previous OutputSurfaces // are complete before creating the new OutputSurface. if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_IDLE) return false; // We want to clear the pipline of any pending draws and activations // before starting output surface initialization. This allows us to avoid // weird corner cases where we abort draws or force activation while we // are initializing the output surface. if (active_tree_needs_first_draw_ || has_pending_tree_) return false; // We need to create the output surface if we don't have one and we haven't // started creating one yet. return output_surface_state_ == OUTPUT_SURFACE_LOST; } 这个函数定义在文件external/chromium_org/cc/scheduler/scheduler_state_machine.cc中。 SchedulerStateMachine类的成员函数ShouldBeginOutputSurfaceCreation返回true要满足以下六个条件: 1. 网页的CC Layer Tree已经创建和初始化完成。这时候SchedulerStateMachine类的成员变量can_start_的值等于true。 2. 状态机的CommitState状态等于COMMIT_STATE_IDLE。这意味着当前Main线程不是正在提交变化给Compositor线程渲染。 3. 状态机的BeginImplFrameState状态等于BEGIN_IMPL_FRAME_STATE_IDLE。这意味着调度器已经向Compositor线程发出了一个渲染请 求。 4. Compositor线程的CC Pending Layer Tree已经激活为CC Active Layer Tree。这时候SchedulerStateMachine类的成员变量 has_pending_tree_的值等于false。 5. Compositor线程的CC Active Layer Tree被激活后,已经被执行过至少一次渲染操作了。这时候SchedulerStateMachine类的成员变 量active_tree_needs_first_draw_的值等于false。 6. 状态机的OutputSurfaceState状态等于OUTPUT_SURFACE_LOST。 从前面的分析可以知道,第1个条件是满足的。由于这时候状态机也是刚刚初始化完成,因此后面五个条件也得到满足的。因此 SchedulerStateMachine类的成员函数ShouldBeginOutputSurfaceCreation会返回true值给调用者。 同时,从SchedulerStateMachine类的成员函数ShouldBeginOutputSurfaceCreation的实现也可以看出,如果网页绘图表面在创建之后 ,由于其它原因失效了,那么要等到网页的渲染管线达到一个稳定状态之后,才可以重新创建。失效的原因可以参考Chromium网页渲染调度器 (Scheduler)实现分析一文。稳定状态指的是Main线程已经将当前的网页变化提交给了Compositor线程,而Compositor线程也已经处理这些变 化引起的渲染工作。总的来说,就是图1所示的第2到第6个操作均已经连贯执行完成。 回到SchedulerStateMachine类的成员函数NextAction中,当调用另外一个成员函数ShouldBeginOutputSurfaceCreation得到的返回值 等于true的时候,它会返回一个ACTION_BEGIN_OUTPUT_SURFACE_CREATION值给调用者,也就是调度器,表示现在需要为网页创建绘图表面。 回到Scheduler类的成员函数ProcessScheduledActions中,它知道了下一个要执行的操作是ACTION_BEGIN_OUTPUT_SURFACE_CREATION之 后,接下来会先调用SchedulerStateMachine类的成员函数UpdateState更新状态机的状态,如下所示: [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 void SchedulerStateMachine::UpdateState(Action action) { switch (action) { ...... case ACTION_BEGIN_OUTPUT_SURFACE_CREATION: ...... output_surface_state_ = OUTPUT_SURFACE_CREATING; ...... return; ...... } } 这个函数定义在文件external/chromium_org/cc/scheduler/scheduler_state_machine.cc中。 当调度器接下要执行的操作是ACTION_BEGIN_OUTPUT_SURFACE_CREATION时,SchedulerStateMachine类的成员函数UpdateState主要就是 修改状态机的OutputSurfaceState状态,也就是将它的状态从OUTPUT_SURFACE_LOST迁移至OUTPUT_SURFACE_CREATING,表示正在为网页创建绘 图表面。 回到Scheduler类的成员函数ProcessScheduledActions中,它更新了状态机的OutputSurfaceState状态之后,接下来就会调用成员变量 client_指向的一个ThreadProxy对象的成员函数ScheduledActionBeginOutputSurfaceCreation为网页创建绘图表面。 ThreadProxy类的成员函数ScheduledActionBeginOutputSurfaceCreation的实现如下所示: [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 void ThreadProxy::ScheduledActionBeginOutputSurfaceCreation() { ...... Proxy::MainThreadTaskRunner()->PostTask( FROM_HERE, base::Bind(&ThreadProxy::CreateAndInitializeOutputSurface, main_thread_weak_ptr_)); } 这个函数定义在文件external/chromium_org/cc/trees/thread_proxy.cc中。 ThreadProxy类的成员函数ScheduledActionBeginOutputSurfaceCreation向Main线程的消息队列发送了一个Task,这个Task绑定了 ThreadProxy类的成员函数CreateAndInitializeOutputSurface。因此,接下来ThreadProxy类的成员函数CreateAndInitializeOutputSurface 就会在Main线程中执行。 ThreadProxy类的成员函数CreateAndInitializeOutputSurface的实现如下所示: [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 void ThreadProxy::CreateAndInitializeOutputSurface() { ...... DCHECK(IsMainThread()); scoped_ptr<OutputSurface> output_surface = layer_tree_host()->CreateOutputSurface(); if (output_surface) { Proxy::ImplThreadTaskRunner()->PostTask( FROM_HERE, base::Bind(&ThreadProxy::InitializeOutputSurfaceOnImplThread, impl_thread_weak_ptr_, base::Passed(&output_surface))); return; } ...... } 这个函数定义在文件external/chromium_org/cc/trees/thread_proxy.cc中。 ThreadProxy类的成员函数CreateAndInitializeOutputSurface首先调用另外一个成员函数layer_tree_host获得一个LayerTreeHost对 象。然后再调用这个LayerTreeHost对象的成员函数CreateOutputSurface为网页创建绘图表面。 ThreadProxy类的成员函数CreateAndInitializeOutputSurface接下来又向Compositor线程的消息队列发送一个Task。这个Task绑定的 函数是ThreadProxy类的成员函数InitializeOutputSurfaceOnImplThread,用来在Compositor线程中初始化前面创建好的绘图表面。 接下来我们先分析LayerTreeHost类的成员函数CreateOutputSurface的实现,接着再分析ThreadProxy类的成员函数 InitializeOutputSurfaceOnImplThread的实现。 LayerTreeHost类的成员函数CreateOutputSurface的实现如下所示: [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 scoped_ptr<OutputSurface> LayerTreeHost::CreateOutputSurface() { return client_->CreateOutputSurface(num_failed_recreate_attempts_ >= 4); } 这个函数定义在文件external/chromium_org/cc/trees/layer_tree_host.cc中。 从前面一文可以知道,LayerTreeHost类的成员变量client_指向的是一个RenderWidgetCompositor对象。LayerTreeHost类的成员函数 CreateOutputSurface调用这个RenderWidgetCompositor对象的成员函数CreateOutputSurface为网页创建绘图表面。 RenderWidgetCompositor类的成员函数CreateOutputSurface的实现如下所示: [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 scoped_ptr<cc::OutputSurface> RenderWidgetCompositor::CreateOutputSurface( bool fallback) { return widget_->CreateOutputSurface(fallback); } 这个函数定义在文件external/chromium_org/content/renderer/gpu/render_widget_compositor.cc中。 从前面一文可以知道,RenderWidgetCompositor类的成员变量widget_指向的是一个RenderViewImpl对象。RenderWidgetCompositor类 的成员函数CreateOutputSurface调用这个RenderViewImpl对象的成员函数CreateOutputSurface为网页创建绘图表面。 RenderViewImpl类的成员函数CreateOutputSurface是从父类RenderWidget继承下来的。RenderWidget类的成员函数 CreateOutputSurface为网页创建绘图表面的过程可以参考前面一文。这个过程实际上就是Render进程请求与GPU进程建立GPU通道的过程。GPU 通道建立起来之后,Render进程就可以发送GPU命令给GPU进程执行了。注意,在Render进程中加载的每一个网页都会与GPU进程建立一个GPU通 道,并且每一个GPU通道在GPU进程又对应有一个OpenGL上下文。我们也可以认为Render进程的一个绘图表面对应于GPU进程中的一个OpenGL上下 文。 假设网页A与GPU进程建立的GPU通道为G1,并且GPU通道为G1在GPU进程中对应的OpenGL上下文C1。当Render进程要渲染网页A的UI时,它 就会通过GPU通道G1向GPU进程发送相应的GPU命令。GPU进程接收到这些GPU命令之后,就会激活OpenGL上下文C1,然后执行接收到的GPU命令。 通过这种方式,GPU进程就可以同时接收不同网页的渲染命令,并且它们不会互相干扰,因为不同网页的渲染命令都是在各自的OpenGL上下文中 执行的。这些都是Chromium硬件加速渲染机制相关的知识,可以参考前面这个系列的文章。 回到ThreadProxy类的成员函数CreateAndInitializeOutputSurface中,它调用LayerTreeHost类的成员函数CreateOutputSurface为网页 创建了一个绘图表面之后,接下来会请求Compositor线程初始化这个绘图表面。这是通过在Compositor线程中调用ThreadProxy类的成员函数 InitializeOutputSurfaceOnImplThread实现的。 ThreadProxy类的成员函数InitializeOutputSurfaceOnImplThread的实现如下所示: [cpp] view plain copy 在CODE上查看代码片派生到我的代码片 void ThreadProxy::InitializeOutputSurfaceOnImplThread( scoped_ptr<OutputSurface> output_surface) { ...... DCHECK(IsImplThread()); LayerTreeHostImpl* host_impl = impl().layer_tree_host_impl.get(); bool success = host_impl->InitializeRenderer(output_surface.Pass()); ...... if (success) impl().scheduler->DidCreateAndInitializeOutputSurface(); } 这个函数定义在文件external/chromium_org/cc/trees/thread_proxy.cc。 ThreadProxy类的成员函数InitializeOutputSurfaceOnImplThread首先获得一个LayerTreeHostImpl对象,接着调用这个 LayerTreeHostImpl对象的成员函数InitializeRenderer初始化参数output_surface描述的绘图表面。从前面一文可以知道,参数 output_surface指向的实际上是一个CompositorOutputSurface对象。也就是说,网页的绘图表面是通过一个CompositorOutputSurf
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 包罗万象 > 大杂烩

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服