分享

Layer Tree 创建

 wusiqi111 2019-10-29

站在老罗的肩膀上:https://blog.csdn.net/luoshengyang/article/details/50941980

网页的Graphics Layer Tree是根据Paint Layer Tree创建的,而Graphics Layer Tree与CC模块创建的Layer Tree的节点是一一对应的关系,如图1所示:

图1 Graphics Layer Tree与CC Layer Tree的关系

     也就是说,每一个Graphics Layer都对应有一个CC Layer。不过,Graphics Layer与CC Layer不是直接的一一对应的,它们是透过另外两个Layer才对应起来的,如图2所示:

图2 Graphics Layer与CC Layer的对应关系

       中间的两个Layer分别是WebContentLayerImpl和WebLayerImpl,它们是属于Content层的对象。Graphics Layer与CC Layer的对应关系,是在Graphics Layer的创建过程中建立起来的,接下来我们就通过源码分析这种对应关系的建立过程。

GraphicsLayer::GraphicsLayer(GraphicsLayerClient& client)
    : client_(client),
      ... {
  ...
  layer_ = cc::PictureLayer::Create(this);
  layer_->SetIsDrawable(draws_content_ && contents_visible_);
  layer_->SetLayerClient(weak_ptr_factory_.GetWeakPtr());
}                                                    

Graphics Layer通过GraphicsLayer::AddChild形成父子关系的(从而形成Graphics Layer Tree),如下所示:

void GraphicsLayer::AddChild(GraphicsLayer* child_layer) {
  AddChildInternal(child_layer);
  UpdateChildList();
}

首先调用成员函数AddChildInternal将参数childLayer描述的一个Graphics Layer作为当前正在处理的Graphics Layer的子Graphics Layer,如下所示: 

void GraphicsLayer::AddChildInternal(GraphicsLayer* child_layer) {
  ...  if (child_layer->Parent())
    child_layer->RemoveFromParent();

  child_layer->SetParent(this);
  children_.push_back(child_layer);
}

这一步执行完成后,Graphics Layer之间就建立了父子关系。回到GraphicsLayer类的成员函数AddChild中,它接下来还会调用另外一个成员函数UpdateChildList,用来在CC Layer之间建立父子关系,从而形CC Layer Tree。

void GraphicsLayer::UpdateChildList() {  // child_host point to PictureLayer
  cc::Layer* child_host = layer_.get();
  child_host->RemoveAllChildren();

  ...  for (size_t i = 0; i < children_.size(); ++i)
    child_host->AddChild(children_[i]->CcLayer());  for (size_t i = 0; i < link_highlights_.size(); ++i)
    child_host->AddChild(link_highlights_[i]->Layer());
}

其中child_host指向的是当前Graphics Layer对应的一个PictureLayer对象,并把它所有的Child Graphics Layer对应的PictureLayer调用AddChild添加到它的子节点,AddChild调用InsertChild实现如下

void Layer::AddChild(scoped_refptr<Layer> child) {
  InsertChild(child, inputs_.children.size());
}


void Layer::InsertChild(scoped_refptr<Layer> child, size_t index) {
  DCHECK(IsPropertyChangeAllowed());
  child->RemoveFromParent();
  AddDrawableDescendants(child->NumDescendantsThatDrawContent() +
                         (child->DrawsContent() ? 1 : 0));
  child->SetParent(this);
  child->SetSubtreePropertyChanged();

  index = std::min(index, inputs_.children.size());
  inputs_.children.insert(inputs_.children.begin() + index, child);
  SetNeedsFullTreeSync();
}

Layer类的成员函数InsertChild所做的第一件事情是将当前正在处理的Picture Layer设置为参数child描述的Pictrue Layer的父Picture Layer,并且将参数child描述的Pictrue Layer保存在当前正在处理的Picture Layer的子Picture Layer列表中。Layer类的成员函数InsertChild所做的第二件事情是调用另外一个成员函数SetNeedsFullTreeSync发出一个通知,要在CC Layer Tree与CC Pending Layer Tree之间做一个Tree结构同步。

      Layer类的成员函数SetNeedsFullTreeSync的实现如下所示:

void Layer::SetNeedsFullTreeSync() {  if (!layer_tree_host_)    return;

  layer_tree_host_->SetNeedsFullTreeSync();
}void LayerTreeHost::SetNeedsFullTreeSync() {
  needs_full_tree_sync_ = true;
  property_trees_.needs_rebuild = true;
  SetNeedsCommit();
}

Layer类的成员变量layer_tree_host_指向的是一个LayerTreeHost对象,用来管理CC Layer Tree的。Layer类的成员函数SetNeedsFullTreeSync所做的事情就是调用这个LayerTreeHost对象的成员函数SetNeedsFullTreeSync通知它CC Layer Tree结构发生了变化,需要将这个变化同步到CC Pending Layer Tree中去。

       这一步执行完成之后,就可以在CC模块中得到一个Layer Tree,这个Layer Tree与Blink中的Graphics Layer Tree在结构上是完全同步的,并且这个同步过程是由Blink控制的。这个同步过程之所以要由Blink控制,是因为CC Layer Tree是根据Graphics Layer Tree创建的,而Graphics Layer Tree又是由Blink管理的。

       Blink现在还需要做的另外一件重要的事情是告诉CC模块,哪一个Picture Layer是CC Layer Tree的根节点,这样CC模块才可以对整个CC Layer Tree进行管理。Blink会在创建Graphics Layer Tree的根节点的时候,将该根节点对应的Picture Layer设置到CC模块中去,以便后者将其作为CC Layer Tree的根节点。

       Graphics Layer Tree的根节点是什么时候创建的呢?从前面Chromium网页加载过程简要介绍和学习计划这个系列的文章可以知道,Graphics Layer Tree的根节点对应于Paint Layer Tree的根节点,Paint Layer Tree的根节点又对应于Layout Object Tree的根节点,因此我们就从Layout Object Tree的根节点的创建过程开始,分析Graphics Layer Tree的根节点的创建过程。

      Document调用SetStyle给Layout Object Tree的节点设置CSS属性,RebuildLayoutTree会创建相应的Layout Layer。在设置Paint Layer Tree的根节点的CSS属性的过程中,会触发Graphics Layer Tree的根节点的创建,因此接下来我们继续分析Paint Layer类的成员函数StyleDidChange的实现,如下所示:

void PaintLayer::StyleDidChange(StyleDifference diff,                                const ComputedStyle* old_style) {
  UpdateScrollableArea();  if (AttemptDirectCompositingUpdate(diff, old_style))    return;  if (PaintLayerStackingNode::StyleDidChange(this, old_style))
    MarkAncestorChainForDescendantDependentFlagsUpdate();
  ...
}
bool PaintLayerStackingNode::StyleDidChange(PaintLayer* paint_layer,                                            const ComputedStyle* old_style) {
  ...  // Need to force requirements update, due to change of stacking order.
  paint_layer->SetNeedsCompositingRequirementsUpdate();
  DirtyStackingContextZOrderLists(paint_layer);  if (paint_layer->StackingNode()) {    if (should_be_stacking_context)
      paint_layer->StackingNode()->DirtyZOrderLists();    else
      paint_layer->StackingNode()->ClearZOrderLists();
  }  if (was_stacked != should_be_stacked) {    if (!paint_layer->GetLayoutObject().DocumentBeingDestroyed() &&
        !paint_layer->IsRootLayer() && paint_layer->Compositor()) {
      paint_layer->Compositor()->SetNeedsCompositingUpdate(
          kCompositingUpdateRebuildTree);
    }
  }  return true;
}

在从非Stacking Context变为Stacking Context的情况下,DirtyStackingContextZOrderLists将Stacking Context标记为Dirty状态,这样以后在需要的时候就会根据该Stacking Context的子元素的z-index重新构建Graphics Layer Tree。

void PaintLayerStackingNode::DirtyStackingContextZOrderLists(
    PaintLayer* layer) {  if (PaintLayerStackingNode* stacking_node =
          AncestorStackingContextNode(layer))
    stacking_node->DirtyZOrderLists();
}


void PaintLayerStackingNode::DirtyZOrderLists() {  if (pos_z_order_list_)
    pos_z_order_list_->clear();  if (neg_z_order_list_)
    neg_z_order_list_->clear();
  z_order_lists_dirty_ = true;  if (!Layer()->GetLayoutObject().DocumentBeingDestroyed() && Compositor())
    Compositor()->SetNeedsCompositingUpdate(kCompositingUpdateRebuildTree);
}


void PaintLayerCompositor::SetNeedsCompositingUpdate(
    CompositingUpdateType update_type) {
  DCHECK_NE(update_type, kCompositingUpdateNone);
  pending_update_type_ = std::max(pending_update_type_, update_type);  if (Page* page = GetPage())
    page->Animator().ScheduleVisualUpdate(layout_view_.GetFrame());
  Lifecycle().EnsureStateAtMost(DocumentLifecycle::kLayoutClean);
}

DirtyZOrderLists首先是将用来保存子元素的两个列表清空。其中一个列表用来保存z-index为正数的子元素,另一个列表用来保存z-index为负数的子元素。这些子元素在各自的列表中均是按照从小到大的顺序排列的。有了这个顺序之后,Graphics Layer Tree就可以方便地按照z-index顺序创建出来。接下来将成员变量m_zOrderListsDirty的值设置为true,就将自己的状态标记为Dirty,以后就会重新根据子元素的z-index值,将它们分别保存在对应的列表中。最后判断当前加载的网页有没有被销毁。如果没有被销毁,就会调用另外一个成员函数Compositor,获得一个PaintLayerCompositor对象。该对象是用来管理当前加载的网页的Graphics Layer Tree的。调用它的成员函数SetNeedsCompositingUpdate,用来通知它需要重建Graphics Layer Tree。

      回到 Document::UpdateStyleAndLayout在更新layout时,会调用EnableCompositingModeIfNeeded将网页的Render Layer Tree的根节点设置为一个Compositing Layer,也就是要为它创建一个Graphics Layer。       

void PaintLayerCompositor::EnableCompositingModeIfNeeded() {
  ...  if (RootShouldAlwaysComposite()) {
    ...
    SetNeedsCompositingUpdate(kCompositingUpdateRebuildTree);
    SetCompositingModeEnabled(true);
  }
}

     只有在采用硬件加速渲染网页的情况下,才需要创建Graphics Layer。在两种情况下,需要为Render Layer Tree的根节点创建Graphics Layer。第一种情况是当前网页加载在Main Frame中。第二种情况是当前网页不是加载在Main Frame,例如是通过iframe嵌入在Main Frame中,但是它是可滚动的,通过RootShouldAlwaysComposite判断。

       我们假设当前网页是加载在Main Frame中的,由于刚打开,PaintLayerCompositor类的成员变量layout_view_是刚刚创建的,这意味它需要执行一个Layout操作,因此EnableCompositingModeIfNeeded为Paint Layer Tree的根节点创建一个Graphics Layer,作为Graphics Layer Tree的根节点。

void PaintLayerCompositor::SetCompositingModeEnabled(bool enable) {  if (enable == compositing_)    return;

  compositing_ = enable;  if (compositing_)
    EnsureRootLayer();  else
    DestroyRootLayer();
    ...
}
void PaintLayerCompositor::EnsureRootLayer() {  if (root_layer_attachment_ != kRootLayerUnattached)    return;  // intention of this step isif (IsMainFrame())
    GetVisualViewport().CreateLayerTree();

  AttachCompositorTimeline();
  AttachRootLayer();
}

通过AttachRootLayer将Graphics Layer Tree的根节点设置给Blink的使用者,即Chromium的Content层

void PaintLayerCompositor::AttachRootLayer() {  // In Slimming Paint v2, PaintArtifactCompositor is responsible for the root
  // layer.
  if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled())    return;  if (layout_view_.GetFrame()->IsLocalRoot()) {
    root_layer_attachment_ = kRootLayerPendingAttachViaChromeClient;
  } else {
    ...
    root_layer_attachment_ = kRootLayerAttachedViaEnclosingFrame;
  }
}

由此,对于Paint Layer在更新时也会AttachRootGraphicsLayer, 最终会在LayerTreeHost::SetRootLayer中设置根节点。

void PaintLayerCompositor::UpdateIfNeeded(
    DocumentLifecycle::LifecycleState target_state,
    CompositingReasonsStats& compositing_reasons_stats) {
    ...    if (root_layer_attachment_ == kRootLayerPendingAttachViaChromeClient) {      if (Page* page = layout_view_.GetFrame()->GetPage()) {
        page->GetChromeClient().AttachRootGraphicsLayer(RootGraphicsLayer(),
                                                      layout_view_.GetFrame());
        root_layer_attachment_ = kRootLayerAttachedViaChromeClient;
    }
    ...
}
void ChromeClientImpl::AttachRootGraphicsLayer(GraphicsLayer* root_layer,
                                               LocalFrame* local_frame) {
  ...
  WebLocalFrameImpl* web_frame =
      WebLocalFrameImpl::FromFrame(local_frame)->LocalRoot();
  ...  if (web_frame->FrameWidgetImpl())
    web_frame->FrameWidgetImpl()->SetRootGraphicsLayer(root_layer);
}


void WebViewFrameWidget::SetRootGraphicsLayer(GraphicsLayer* layer) {
  web_view_->SetRootGraphicsLayer(layer);
}



void WebViewImpl::SetRootGraphicsLayer(GraphicsLayer* graphics_layer) {
  ...  if (graphics_layer) {    // assign root of CCLayer 
    root_layer_ = root_graphics_layer_->CcLayer();
    UpdateDeviceEmulationTransform();
    layer_tree_view_->SetRootLayer(root_layer_);
    ...
}



void LayerTreeView::SetRootLayer(scoped_refptr<cc::Layer> layer) {
  layer_tree_host_->SetRootLayer(std::move(layer));
}

void LayerTreeHost::SetRootLayer(scoped_refptr<Layer> root_layer) {
  ...
  root_layer_ = root_layer;  if (root_layer_.get()) {
    DCHECK(!root_layer_->parent());
    root_layer_->SetLayerTreeHost(this);
  }
}

void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) {
  Layer::SetLayerTreeHost(host);
  ...
}


void Layer::SetLayerTreeHost(LayerTreeHost* host) {
  ...

  layer_tree_host_ = host;
  InvalidatePropertyTreesIndices();

  ...
}

从这里就会调用前面提到的成员函数StartCompositor激活调度器


前面说Layer类的成员变量layer_tree_host_指向的是一个LayerTreeHost对象,用来管理CC Layer Tree的,现在来看它的创建过程,

通过前面的RenderWidget::InitializeLayerTreeView 调用,走多线程分支

void LayerTreeView::Initialize(    const cc::LayerTreeSettings& settings,
    std::unique_ptr<cc::UkmRecorderFactory> ukm_recorder_factory) {
  ...  if (!is_threaded) {    // Single-threaded layout tests, and unit tests.
    layer_tree_host_ = cc::LayerTreeHost::CreateSingleThreaded(this, &params);
  } else {
    layer_tree_host_ =
        cc::LayerTreeHost::CreateThreaded(compositor_thread_, &params);
  }
}


std::unique_ptr<LayerTreeHost> LayerTreeHost::CreateThreaded(
    scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
    InitParams* params) {
  ...
  std::unique_ptr<LayerTreeHost> layer_tree_host(      new LayerTreeHost(params, CompositorMode::THREADED));
  layer_tree_host->InitializeThreaded(params->main_task_runner,
                                      impl_task_runner);  return layer_tree_host;
}


void LayerTreeHost::InitializeThreaded(
    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
    scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
  task_runner_provider_ =
      TaskRunnerProvider::Create(main_task_runner, impl_task_runner);
  std::unique_ptr<ProxyMain> proxy_main =
      std::make_unique<ProxyMain>(this, task_runner_provider_.get());
  InitializeProxy(std::move(proxy_main));
}
void LayerTreeHost::InitializeProxy(std::unique_ptr<Proxy> proxy) {
  TRACE_EVENT0("cc", "LayerTreeHost::InitializeForReal");
  DCHECK(task_runner_provider_);

  proxy_ = std::move(proxy);
  proxy_->Start();
  ...
}


void ProxyMain::Start() {
  {
    ...
    CompletionEvent completion;
    ImplThreadTaskRunner()->PostTask(
        FROM_HERE, base::BindOnce(&ProxyMain::InitializeOnImplThread,
                                  base::Unretained(this), &completion));
    completion.Wait();
  }

  started_ = true;
}

这里创建了一个ProxyMain对象,保存在成员变量proxy_中, 调用Start向Compositor线程的消息队列发送了一个Task,并且等待这个Task完成。这个Task绑定了ProxyMain类的成员函数InitializeImplOnImplThread,因此接下来ProxyMain类的成员函数InitializeImplOnImplThread就会在Compositor线程中执行,如下所示:

 ThreadProxy类的成员函数InitializeImplOnImplThread主要是做了三件事情。

      1. 调用前面创建的LayerTreeHost对象的成员函数CreateLayerTreeHostImpl函数创建了一个LayerTreeHostImpl对象,并且保存在内部的一个CompositorThreadOnly对象的成员变量layer_tree_host_impl中。前面创建的LayerTreeHost对象可以通过调用成员函数layer_tree_host_获得。内部的CompositorThreadOnly对象可以通过调用成员函数impl获得。创建出来的LayerTreeHostImpl对象以后负责管理CC Pending Layer Tree和CC Active Layer Tree

    2. 调用Scheduler类的静态成员函数Create创建了一个Scheduler对象。这个Scheduler对象以后就负责在Main线程与Compositor线程之间调度渲染工作。

      3. 将参数completion描述的Completion Event设置为有信号,这样正在等待的Main线程就可以唤醒继续执行其它工作了。

      LayerTreeHost类的成员函数CreateLayerTreeHostImpl创建LayerTreeHostImpl对象的过程,如下所示:

std::unique_ptr<LayerTreeHostImpl>
LayerTreeHost::CreateLayerTreeHostImpl(
    LayerTreeHostImplClient* client) {
  ...  std::unique_ptr<MutatorHost> mutator_host_impl =
      mutator_host_->CreateImplInstance(supports_impl_scrolling);  std::unique_ptr<LayerTreeHostImpl> host_impl = LayerTreeHostImpl::Create(
      settings_, client, task_runner_provider_.get(),
      rendering_stats_instrumentation_.get(), task_graph_runner_,      std::move(mutator_host_impl), id_, std::move(image_worker_task_runner_));
  ...  return host_impl;
}std::unique_ptr<LayerTreeHostImpl> LayerTreeHostImpl::Create(    const LayerTreeSettings& settings,
    LayerTreeHostImplClient* client,
    TaskRunnerProvider* task_runner_provider,
    RenderingStatsInstrumentation* rendering_stats_instrumentation,
    TaskGraphRunner* task_graph_runner,    std::unique_ptr<MutatorHost> mutator_host,    int id,
    scoped_refptr<base::SequencedTaskRunner> image_worker_task_runner) {  return base::WrapUnique(new LayerTreeHostImpl(
      settings, client, task_runner_provider, rendering_stats_instrumentation,
      task_graph_runner, std::move(mutator_host), id,      std::move(image_worker_task_runner)));
}


LayerTreeHostImpl::LayerTreeHostImpl(    const LayerTreeSettings& settings,
    LayerTreeHostImplClient* client,
    TaskRunnerProvider* task_runner_provider,
    RenderingStatsInstrumentation* rendering_stats_instrumentation,
    TaskGraphRunner* task_graph_runner,    std::unique_ptr<MutatorHost> mutator_host,    int id,
    scoped_refptr<base::SequencedTaskRunner> image_worker_task_runner)
    : client_(client),
      task_runner_provider_(task_runner_provider),
      ...
      tile_manager_(this,
                    GetTaskRunner(),                    std::move(image_worker_task_runner),
                    is_synchronous_single_threaded_
                        ? std::numeric_limits<size_t>::max()
                        : settings.scheduled_raster_task_limit,
                    settings.ToTileManagerSettings()),
      ...
      task_graph_runner_(task_graph_runner),
      ...,
      is_animating_for_snap_(false) {
  ...
  active_tree_ = std::make_unique<LayerTreeImpl>(      this, new SyncedProperty<ScaleGroup>, new SyncedBrowserControls,      new SyncedElasticOverscroll);
  active_tree_->property_trees()->is_active = true;
  ...
}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多