FrameSink(原网页绘图表面Output Surface)创建

本文详细介绍了Chromium浏览器中,从检测到网页Layer Tree创建完成到触发绘图表面(FrameSink)创建的过程,包括涉及到的状态机、调度器、基础设施建立,以及从开始创建到初始化完成的关键步骤。在理解这一过程后,有助于深入理解Chromium的渲染机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

站在老罗的肩膀上:https://blog.youkuaiyun.com/luoshengyang/article/details/50995124

CC模块内部的状态机一旦检测到网页的Layer Tree创建和初始化完毕,就会通知调度器触发一个创建绘图表面的操作。CC模块在为网页创建绘图表面的过程中,也有伴随着网页分块管理器、资源池和光栅化工作者线程池等基础设施的创建。一旦这些基础设施准备完毕,网页才能开始进行绘制

当网页的Graphics Layer Tree的根节点创建出来之后,Blink就会通知Chromium的Content层初始化一个CC Layer Tree,如下所示:

blink::WebLayerTreeView* RenderWidget::InitializeLayerTreeView() {
  DCHECK(!host_closing_);

  layer_tree_view_ = std::make_unique<LayerTreeView>(
      this, compositor_deps_->GetCompositorMainThreadTaskRunner(),
      compositor_deps_->GetCompositorImplThreadTaskRunner(),
      compositor_deps_->GetTaskGraphRunner(),
      compositor_deps_->GetWebMainThreadScheduler());
  layer_tree_view_->Initialize(
      GenerateLayerTreeSettings(compositor_deps_, for_oopif_,
                                screen_info_.rect.size(),
                                screen_info_.device_scale_factor),
      compositor_deps_->CreateUkmRecorderFactory());
  ...
  StartCompositor();
  ...
  return layer_tree_view_.get();
}

StartCompositror会PostTask告诉Compositor线程,CCLayer已经创建完毕,可以开始compositing

void ProxyMain::SetVisible(bool visible) {
  TRACE_EVENT1("cc", "ProxyMain::SetVisible", "visible", visible);
  ImplThreadTaskRunner()->PostTask(
      FROM_HERE, base::BindOnce(&ProxyImpl::SetVisibleOnImpl,
                                base::Unretained(proxy_impl_.get()), visible));
}

ProxyMain::SetVisible向Compositor线程的消息队列发送一个Task。这个Task绑定了ProxyImpl::SetVisibleOnImpl,接下来就会在Compositor线程中执行。ProxyImpl::SetVisibleOnImpl实现如下所示:

void ProxyImpl::SetVisibleOnImpl(bool visible) {
  TRACE_EVENT1("cc", "ProxyImpl::SetVisibleOnImplThread", "visible", visible);
  DCHECK(IsImplThread());
  host_impl_->SetVisible(visible);
  scheduler_->SetVisible(visible);
}

然后启调度器, 打开状态机

void ProxyImpl::SetVisibleOnImpl(bool visible) {
  TRACE_EVENT1("cc", "ProxyImpl::SetVisibleOnImplThread", "visible", visible);
  DCHECK(IsImplThread());
  host_impl_->SetVisible(visible);
  scheduler_->SetVisible(visible);
}

void Scheduler::SetVisible(bool visible) {
  // Turn on state machine
  state_machine_.SetVisible(visible);
  UpdateCompositorTimingHistoryRecordingEnabled();
  // Turn on drawing
  ProcessScheduledActions();
}


void Scheduler::ProcessScheduledActions() {
  ...
  SchedulerStateMachine::Action action;
  do {
    action = state_machine_.NextAction();
    base::AutoReset<SchedulerStateMachine::Action> mark_inside_action(
        &inside_action_, action);
    switch (action) {
      ...
      case SchedulerStateMachine::Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION:
        state_machine_.WillBeginLayerTreeFrameSinkCreation();
        client_->ScheduledActionBeginLayerTreeFrameSinkCreation();
        break;
      ...
  } while (action != SchedulerStateMachine::Action::NONE);

  ScheduleBeginImplFrameDeadline();

  PostPendingBeginFrameTask();
  StartOrStopBeginFrames();
}

其首先会计算NextAction 

SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
  ...
  if (ShouldBeginLayerTreeFrameSinkCreation())
    return Action::BEGIN_LAYER_TREE_FRAME_SINK_CREATION;
  ...
  return Action::NONE;
}


bool SchedulerStateMachine::ShouldBeginLayerTreeFrameSinkCreation() const {
  if (!visible_)
    return false;

  // We only want to start output surface initialization after the
  // previous commit is complete.
  if (begin_main_frame_state_ != BeginMainFrameState::IDLE) {
    return false;
  }

  // Make sure the BeginImplFrame from any previous LayerTreeFrameSinks
  // are complete before creating the new LayerTreeFrameSink.
  if (begin_impl_frame_state_ != BeginImplFrameState::IDLE)
    return false;

  // We want to clear the pipeline 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 layer_tree_frame_sink_state_ == LayerTreeFrameSinkState::NONE;
}

SchedulerStateMachine类的成员函数ShouldBeginLayerTreeFrameSinkCreation返回true要满足以下条件:

       1. 网页的CC Layer Tree已经创建和初始化完成。这时候SchedulerStateMachine类的成员变量visible_的值等于true。

       2. 确保上一次commit已经完成。状态机的begin_main_frame_state_ 等于BeginMainFrameState::IDLE。

       3. 调度器已经向Compositor线程发出了一个渲染请,状态机的begin_impl_frame_state_ 等于 BeginImplFrameState::IDLE。

       4. Compositor线程的CC Pending Layer Tree已经激活为CC Active Layer Tree。这时候SchedulerStateMachine类的成员变量has_pending_tree_的值等于false。或者 Compositor线程的CC Active Layer Tree被激活后,已经被执行过至少一次渲染操作了。这时候SchedulerStateMachine类的成员变量active_tree_needs_first_draw_的值等于false。

       5. 状态机处于等待创建状态,layer_tree_frame_sink_state_等于LayerTreeFrameSinkState::NONE,。

       从前面的分析可以知道,第1个条件是满足的。由于这时候状态机也是刚刚初始化完成,因此后面五个条件也得到满足的。

  回到Scheduler类的成员函数ProcessScheduledActions中,它知道了下一个要执行的操作是BEGIN_LAYER_TREE_FRAME_SINK_CREATION之后,接下来会先调用SchedulerStateMachine::WillBeginLayerTreeFrameSinkCreation更新状态机的状态从LayerTreeFrameSinkState::NONE到LayerTreeFrameSinkState::CREATING,表示正在为网页创建绘图表面,如下所示:

void SchedulerStateMachine::WillBeginLayerTreeFrameSinkCreation() {
  DCHECK_EQ(layer_tree_frame_sink_state_, LayerTreeFrameSinkState::NONE);
  layer_tree_frame_sink_state_ = LayerTreeFrameSinkState::CREATING;
}

接下来就会调用成员变量client_指向的一个ProxyImpl对象的成员函数ScheduledActionBeginOutputSurfaceCreation为网页创建绘图表面。

void ProxyImpl::ScheduledActionBeginLayerTreeFrameSinkCreation() {
  ...
  MainThreadTaskRunner()->PostTask(
      FROM_HERE, base::BindOnce(&ProxyMain::RequestNewLayerTreeFrameSink,
                                proxy_main_weak_ptr_));
}

ThreadProxy类的成员函数ScheduledActionBeginLayerTreeFrameSinkCreation向Main线程的消息队列发送了一个Task,这个Task绑定了ProxyMain类的成员函数RequestNewLayerTreeFrameSink。因此,就从Compositor线程切换到CrRendererMain线程中执行。


ProxyImpl类和ProxyMain类作用:

// This class aggregates all the interactions that the main side of the
// compositor needs to have with the impl side.
// The class is created and lives on the impl thread.
class CC_EXPORT ProxyImpl : public LayerTreeHostImplClient,
                            public SchedulerClient {...}



// This class aggregates all interactions that the impl side of the compositor
// needs to have with the main side.
// The class is created and lives on the main thread.
class CC_EXPORT ProxyMain : public Proxy {...}

 ProxyMain::RequestNewLayerTreeFrameSink实现如下所示:

void ProxyMain::RequestNewLayerTreeFrameSink() {
  TRACE_EVENT0("cc", "ProxyMain::RequestNewLayerTreeFrameSink");
  DCHECK(IsMainThread());
  layer_tree_host_->RequestNewLayerTreeFrameSink();
}

void LayerTreeHost::RequestNewLayerTreeFrameSink() {
  client_->RequestNewLayerTreeFrameSink();
}


void LayerTreeView::RequestNewLayerTreeFrameSink() {
  // If the host is closing, then no more compositing is possible.  This
  // prevents shutdown races between handling the close message and
  // the CreateLayerTreeFrameSink task.
  if (delegate_->IsClosing())
    return;
  // should contain PostTask, haven't encounter yet, need more check
  delegate_->RequestNewLayerTreeFrameSink(base::BindOnce(
      &LayerTreeView::SetLayerTreeFrameSink, weak_factory_.GetWeakPtr()));
}


void RenderWidget::RequestNewLayerTreeFrameSink(
    LayerTreeFrameSinkCallback callback) {
  ...
  RenderThreadImpl::current()->RequestNewLayerTreeFrameSink(
      routing_id_, frame_swap_message_queue_, GetURLForGraphicsContext3D(),
      std::move(callback), std::move(client_request), std::move(ptr));
}

最终调用RenderThreadImpl::RequestNewLayerTreeFrameSink创建绘图。其中绑定了LayerTreeView::SetLayerTreeFrameSink

void LayerTreeView::SetLayerTreeFrameSink(
    std::unique_ptr<cc::LayerTreeFrameSink> layer_tree_frame_sink) {
  if (!layer_tree_frame_sink) {
    DidFailToInitializeLayerTreeFrameSink();
    return;
  }
  layer_tree_host_->SetLayerTreeFrameSink(std::move(layer_tree_frame_sink));
}

void LayerTreeHost::SetLayerTreeFrameSink(
    std::unique_ptr<LayerTreeFrameSink> surface) {
  ...
  new_layer_tree_frame_sink_ = std::move(surface);
  proxy_->SetLayerTreeFrameSink(new_layer_tree_frame_sink_.get());
}


void ProxyMain::SetLayerTreeFrameSink(
    LayerTreeFrameSink* layer_tree_frame_sink) {
  ImplThreadTaskRunner()->PostTask(
      FROM_HERE,
      base::BindOnce(&ProxyImpl::InitializeLayerTreeFrameSinkOnImpl,
                     base::Unretained(proxy_impl_.get()), layer_tree_frame_sink,
                     frame_sink_bound_weak_factory_.GetWeakPtr()));
}

通知Compositor线程调用ProxyImpl::InitializeLayerTreeFrameSinkOnImpl初始化LayerTreeFrameSink,然后通知crMainRenderer线程已经完成初始化,如果初始化成功,修改状态机状态

void ProxyImpl::InitializeLayerTreeFrameSinkOnImpl(
    LayerTreeFrameSink* layer_tree_frame_sink,
    base::WeakPtr<ProxyMain> proxy_main_frame_sink_bound_weak_ptr) {
  ...
  LayerTreeHostImpl* host_impl = host_impl_.get();
  bool success = host_impl->InitializeFrameSink(layer_tree_frame_sink);
  MainThreadTaskRunner()->PostTask(
      FROM_HERE, base::BindOnce(&ProxyMain::DidInitializeLayerTreeFrameSink,
                                proxy_main_weak_ptr_, success));
  if (success)
    scheduler_->DidCreateAndInitializeLayerTreeFrameSink();
}

 其中初始化会做如下方向工作:资源池和光栅化工作者线程池网页分块管理器等。

bool LayerTreeHostImpl::InitializeFrameSink(
    LayerTreeFrameSink* layer_tree_frame_sink) {
  ...
  ReleaseLayerTreeFrameSink();
  if (!layer_tree_frame_sink->BindToClient(this)) {
    // Avoid recreating tree resources because we might not have enough
    // information to do this yet (eg. we don't have a TileManager at this
    // point).
    return false;
  }

  layer_tree_frame_sink_ = layer_tree_frame_sink;
  has_valid_layer_tree_frame_sink_ = true;

  auto* context_provider = layer_tree_frame_sink_->context_provider();
  if (context_provider) {
    max_texture_size_ =
        context_provider->ContextCapabilities().max_texture_size;
  } else {
    // Pick an arbitrary limit here similar to what hardware might.
    max_texture_size_ = 16 * 1024;
  }

  resource_pool_ = std::make_unique<ResourcePool>(
      &resource_provider_, context_provider, GetTaskRunner(),
      ResourcePool::kDefaultExpirationDelay,
      settings_.disallow_non_exact_resource_reuse);

  auto* context = layer_tree_frame_sink_->worker_context_provider();
  if (context) {
    viz::RasterContextProvider::ScopedRasterContextLock hold(context);
    use_oop_rasterization_ = context->ContextCapabilities().supports_oop_raster;
  } else {
    use_oop_rasterization_ = false;
  }

  // Since the new context may be capable of MSAA, update status here. We don't
  // need to check the return value since we are recreating all resources
  // already.
  SetNeedUpdateGpuRasterizationStatus();
  UpdateGpuRasterizationStatus();

  // See note in LayerTreeImpl::UpdateDrawProperties, new LayerTreeFrameSink
  // means a new max texture size which affects draw properties. Also, if the
  // draw properties were up to date, layers still lost resources and we need to
  // UpdateDrawProperties() after calling RecreateTreeResources().
  active_tree_->set_needs_update_draw_properties();
  if (pending_tree_)
    pending_tree_->set_needs_update_draw_properties();

  CreateTileManagerResources();
  RecreateTileResources();

  client_->OnCanDrawStateChanged(CanDraw());
  SetFullViewportDamage();
  // There will not be anything to draw here, so set high res
  // to avoid checkerboards, typically when we are recovering
  // from lost context.
  // TODO(crbug.com/469175): Replace with RequiresHighResToDraw.
  SetRequiresHighResToDraw();

  return true;
}

 这一步执行完成之后,网页的绘图表面就初始化完成了。回到ProxyImpl::InitializeLayerTreeFrameSinkOnImpl中,它接下来就会调用Scheduler类的成员函数DidCreateAndInitializeLayerTreeFrameSink通知调度器修改状态机的状态,把状态机由LayerTreeFrameSinkState::CREATING改成LayerTreeFrameSinkState::WAITING_FOR_FIRST_COMMIT如下所示:

void Scheduler::DidCreateAndInitializeLayerTreeFrameSink() {
  TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeLayerTreeFrameSink");
  DCHECK(!observing_begin_frame_source_);
  DCHECK(begin_impl_frame_deadline_task_.IsCancelled());
  state_machine_.DidCreateAndInitializeLayerTreeFrameSink();
  compositor_timing_history_->DidCreateAndInitializeLayerTreeFrameSink();
  UpdateCompositorTimingHistoryRecordingEnabled();
  ProcessScheduledActions();
}

将会触发调度器尽快执行一个ACTION_SEND_BEGIN_MAIN_FRAME。这个操作将会请求crRendererMain线程绘制CC Layer Tree的内容。CC Layer Tree的内容绘制好之后,将会被同步到CC Pending Layer Tree中去执行光栅化操作,然后激活为CC Active Layer Tree。这个CC Active Layer Tree经过Compositor渲染后就得到网页的UI。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值