Layer Tree同步为Pending Layer Tree

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

调用ProxyImpl::ScheduledActionCommit请求Compositor线程将刚刚绘制好的CC Layer Tree同步为CC Pending Layer Tree,如下所示:

void ProxyImpl::ScheduledActionCommit() {
  ...
  host_impl_->BeginCommit();
  blocked_main_commit().layer_tree_host->FinishCommitOnImplThread(
      host_impl_.get());

  ...
  if (commit_completion_waits_for_activation_) {
    ...
    commit_completion_waits_for_activation_ = false;
    activation_completion_event_ = commit_completion_event_;
  } else {
    commit_completion_event_->Signal();
  }
  commit_completion_event_ = nullptr;

  scheduler_->DidCommit();

  // Delay this step until afer the main thread has been released as it's
  // often a good bit of work to update the tree and prepare the new frame.
  host_impl_->CommitComplete();

  SetInputThrottledUntilCommitOnImpl(false);

  next_frame_is_newly_committed_frame_ = true;
}

 首先调用这个LayerTreeHostImpl::BeginCommit创建一个空的CC Pending Layer Tree。

void LayerTreeHostImpl::BeginCommit() {
  if (!CommitToActiveTree())
    CreatePendingTree();
}

调用它的成员函数LayerTreeHost::FinishCommitOnImplThread将刚刚绘制好的CC Layer Tree同步到前面创建的CC Pending Layer Tree中去。

void LayerTreeHost::FinishCommitOnImplThread(
    LayerTreeHostImpl* host_impl) {

  LayerTreeImpl* sync_tree = host_impl->sync_tree();
  ...

  if (needs_full_tree_sync_)
    TreeSynchronizer::SynchronizeTrees(root_layer(), sync_tree);

  ..
  {
    PushPropertyTreesTo(sync_tree);

    PushSurfaceRangesTo(sync_tree);
    TreeSynchronizer::PushLayerProperties(this, sync_tree);

    PushLayerTreePropertiesTo(sync_tree);
    PushLayerTreeHostPropertiesTo(host_impl);

    sync_tree->PassSwapPromises(swap_promise_manager_.TakeSwapPromises());

    sync_tree->set_ui_resource_request_queue(
        ui_resource_manager_->TakeUIResourcesRequests());

    // This must happen after synchronizing property trees and after pushing
    // properties, which updates the clobber_active_value flag.
    // TODO(pdr): Enforce this comment with DCHECKS and a lifecycle state.
    sync_tree->property_trees()->scroll_tree.PushScrollUpdatesFromMainThread(
        property_trees(), sync_tree);

    sync_tree->UpdatePropertyTreeAnimationFromMainThread();

    ..
    mutator_host_->PushPropertiesTo(host_impl->mutator_host());

    sync_tree->lifecycle().AdvanceTo(LayerTreeLifecycle::kNotSyncing);
  }

  // Transfer image decode requests to the impl thread.
  for (auto& request : queued_image_decodes_) {
    int next_id = s_image_decode_sequence_number.GetNext();
    pending_image_decodes_[next_id] = std::move(request.second);
    host_impl->QueueImageDecode(next_id, std::move(request.first));
  }
  queued_image_decodes_.clear();

  micro_benchmark_controller_.ScheduleImplBenchmarks(host_impl);
  property_trees_.ResetAllChangeTracking();
}

 判断成员变量needs_full_tree_sync_的值是否等于true。如果等于true,那么就说明CC Layer Tree的结构发生了变化,也就是增加了Layer,或者减少了Layer。在这种情况下,就需要将CC Layer Tree的结构同步到CC Pending Layer Tree中去。这是通过调用TreeSynchronizer::SynchronizeTrees实现的。

template <typename LayerTreeType>
void SynchronizeTreesInternal(LayerTreeType* source_tree,
                              LayerTreeImpl* tree_impl,
                              PropertyTrees* property_trees) {
  /* using OwnedLayerImplList = std::vector<std::unique_ptr<LayerImpl>>; */
  std::unique_ptr<OwnedLayerImplList> old_layers(tree_impl->DetachLayers());

  OwnedLayerImplMap old_layer_map;
  for (auto& it : *old_layers) {
    old_layer_map[it->id()] = std::move(it);
  }

  PushLayerList(&old_layer_map, source_tree, tree_impl);

  for (int id : property_trees->effect_tree.mask_layer_ids()) {
    std::unique_ptr<LayerImpl> layer_impl(ReuseOrCreateLayerImpl(
        &old_layer_map, source_tree->LayerById(id), tree_impl));
    tree_impl->AddLayer(std::move(layer_impl));
  }
}


template <typename LayerTreeType>
void PushLayerList(OwnedLayerImplMap* old_layers,
                   LayerTreeType* host,
                   LayerTreeImpl* tree_impl) {
  tree_impl->ClearLayerList();
  for (auto* layer : *host) {
    std::unique_ptr<LayerImpl> layer_impl(
        ReuseOrCreateLayerImpl(old_layers, layer, tree_impl));

    tree_impl->AddToLayerList(layer_impl.get());
    tree_impl->AddLayer(std::move(layer_impl));
  }
  tree_impl->OnCanDrawStateChangedForTree();
}

同步过程:host指向对象PictureLayer, 通过operator++遍历整个CC Layer Tree。

template <typename LayerType>
LayerListIterator<LayerType>& LayerListIterator<LayerType>::operator++() {
  // case 0: done
  if (!current_layer_)
    return *this;

  // case 1: descend.
  if (!Children(current_layer_).empty()) {
    current_layer_ = ChildAt(current_layer_, 0);
    list_indices_.push_back(0);
    return *this;
  }

  for (LayerType* parent = Parent(current_layer_); parent;
       parent = Parent(parent)) {
    // We now try and advance in some list of siblings.
    // case 2: Advance to a sibling.
    if (list_indices_.back() + 1 < Children(parent).size()) {
      ++list_indices_.back();
      current_layer_ = ChildAt(parent, list_indices_.back());
      return *this;
    }

    // We need to ascend. We will pop an index off the stack.
    list_indices_.pop_back();
  }

  current_layer_ = nullptr;
  return *this;
}

 然后同步CC Layer Tree的PropertyTrees。

       调用ThreadProxy类的成员函数blocked_main可以获得一个MainThreadOrBlockedMainThread对象。在Render进程启用了Impl Side Painting特性的情况下,当这个MainThreadOrBlockedMainThread对象的成员变量commit_waits_for_activation等于true时,表示CC Layer Tree中的某些Layer请求Compositor线程一直阻塞Main线程,直到前面创建的CC Pending Layer Tree完成光栅化并且激活为CC Active Layer Tree之后,再唤醒Main线程。这些Layer有一个特点,就是不需要Compositor线程为它们执行光栅化操作,例如Texture Layer,本身的内容就是已经光栅化好了的。

       如果需要阻塞Main线程到CC Pending Layer Tree激活为CC Active Layer Tree之后,那么ThreadProxy类的成员函数ScheduledActionCommit就会将保存在前面获得的CompositorThreadOnly对象的成员变量commit_completion_event中的Completion Event转移到另外一个成员变量completion_event_for_commit_held_on_tree_activation中,以便在CC Pending Layer Tree激活为CC Acitve Layer Tree的时候,通过保存在后面这个成员变量中的Completion Event来唤醒Main线程。

       另一方面,如果不需要阻塞Main线程到CC Pending Layer Tree激活为CC Active Layer Tree之后,那么现在就可以唤醒Main线程了,也就是调用保存在前面获得的CompositorThreadOnly对象的成员变量commit_completion_event中的Completion Event的成员函数Signal。

       最后,ThreadProxy类的成员函数ScheduledActionCommit又调用前面获得的CompositorThreadOnly对象的成员变量layer_tree_host_impl指向的LayerTreeHostImpl对象的成员函数CommitComplete为前面已经同步好的CC Pending Layer Tree中的Layer创建分块,以便后面可以对这些分块执行光栅化操作。

       接下来,我们就先分析LayerTreeHostImpl类的成员函数BeginCommit的实现,然后再分析LayerTreeHost类的成员函数FinishCommitOnImplThread以及LayerTreeHostImpl类的成员函数CommitComplete的实现,以便了解CC Layer Tree同步为CC Pending Layer Tree的过程,以及为CC Pending Layer Tree创建分块的过程。

       LayerTreeHostImpl类的成员函数BeginCommit的实现如下所示:

void LayerTreeHostImpl::BeginCommit() {
  if (!CommitToActiveTree())
    CreatePendingTree();
}


void LayerTreeHostImpl::CreatePendingTree() {
  CHECK(!pending_tree_);
  if (recycle_tree_) {
    recycle_tree_.swap(pending_tree_);
  } else {
    pending_tree_ = std::make_unique<LayerTreeImpl>(
        this, active_tree()->page_scale_factor(),
        active_tree()->top_controls_shown_ratio(),
        active_tree()->elastic_overscroll());
  }

  client_->OnCanDrawStateChanged(CanDraw());
  TRACE_EVENT_ASYNC_BEGIN0("cc", "PendingTree:waiting", pending_tree_.get());

  DCHECK(!pending_tree_duration_timer_);
  pending_tree_duration_timer_.reset(new PendingTreeDurationHistogramTimer());
}

LayerTreeImpl类的构造函数主要是将参数layer_tree_host_impl指向的一个LayerTreeHostImpl对象保存在成员变量layer_tree_host_impl_中。

       回到前面分析的ThreadProxy类的成员函数ScheduledActionCommit中,它调用LayerTreeHostImpl类的成员函数BeginCommit创建了一个新的CC Pending Layer Tree之后,接下来就调用LayerTreeHost类的成员函数FinishCommitOnImplThread将之前绘制好的CC Layer Tree同步到刚才创建出来的CC Pending Layer Tree去,如下所示:

void LayerTreeHost::FinishCommitOnImplThread(
    LayerTreeHostImpl* host_impl) {

  LayerTreeImpl* sync_tree = host_impl->sync_tree();
  ...
  if (needs_full_tree_sync_)
    TreeSynchronizer::SynchronizeTrees(root_layer(), sync_tree);
  ...

  {
    TRACE_EVENT0("cc", "LayerTreeHost::PushProperties");

    PushPropertyTreesTo(sync_tree);
    sync_tree->lifecycle().AdvanceTo(LayerTreeLifecycle::kSyncedPropertyTrees);

    PushSurfaceRangesTo(sync_tree);
    TreeSynchronizer::PushLayerProperties(this, sync_tree);
    sync_tree->lifecycle().AdvanceTo(
        LayerTreeLifecycle::kSyncedLayerProperties);

    PushLayerTreePropertiesTo(sync_tree);
    PushLayerTreeHostPropertiesTo(host_impl);

    ...
    sync_tree->UpdatePropertyTreeAnimationFromMainThread();

    ...
    mutator_host_->PushPropertiesTo(host_impl->mutator_host());
  }

  ...
}

接下来就调用TreeSynchronizer类的静态成员函数SynchronizeTrees将前者同步到新的CC Pending Layer Tree去,如下所示:

void TreeSynchronizer::SynchronizeTrees(Layer* layer_root,
                                        LayerTreeImpl* tree_impl) {
  if (!layer_root) {
    tree_impl->DetachLayers();
  } else {
    SynchronizeTreesInternal(layer_root->layer_tree_host(), tree_impl,
                             layer_root->layer_tree_host()->property_trees());
  }
}


template <typename LayerTreeType>
void SynchronizeTreesInternal(LayerTreeType* source_tree,
                              LayerTreeImpl* tree_impl,
                              PropertyTrees* property_trees) {
  DCHECK(tree_impl);

  TRACE_EVENT0("cc", "TreeSynchronizer::SynchronizeTrees");
  std::unique_ptr<OwnedLayerImplList> old_layers(tree_impl->DetachLayers());

  OwnedLayerImplMap old_layer_map;
  for (auto& it : *old_layers) {
    DCHECK(it);
    old_layer_map[it->id()] = std::move(it);
  }

  PushLayerList(&old_layer_map, source_tree, tree_impl);

  for (int id : property_trees->effect_tree.mask_layer_ids()) {
    std::unique_ptr<LayerImpl> layer_impl(ReuseOrCreateLayerImpl(
        &old_layer_map, source_tree->LayerById(id), tree_impl));
    tree_impl->AddLayer(std::move(layer_impl));
  }
}

同步分成两步,第一步同步树的结构,第二步同步属性。(为何要拆成两步?

同步树的结构通过

template <typename LayerTreeType>
void PushLayerList(OwnedLayerImplMap* old_layers,
                   LayerTreeType* host,
                   LayerTreeImpl* tree_impl) {
  tree_impl->ClearLayerList();
  // operator++ is overloaded
  for (auto* layer : *host) {
    std::unique_ptr<LayerImpl> layer_impl(
        ReuseOrCreateLayerImpl(old_layers, layer, tree_impl));
    tree_impl->AddToLayerList(layer_impl.get());
    tree_impl->AddLayer(std::move(layer_impl));
  }
  tree_impl->OnCanDrawStateChangedForTree();
}

重载了operator++,实现树的遍历 

template <typename LayerType>
LayerListIterator<LayerType>& LayerListIterator<LayerType>::operator++() {
  // case 0: done
  if (!current_layer_)
    return *this;

  // case 1: descend.
  if (!Children(current_layer_).empty()) {
    current_layer_ = ChildAt(current_layer_, 0);
    list_indices_.push_back(0);
    return *this;
  }

  for (LayerType* parent = Parent(current_layer_); parent;
       parent = Parent(parent)) {
    // We now try and advance in some list of siblings.
    // case 2: Advance to a sibling.
    if (list_indices_.back() + 1 < Children(parent).size()) {
      ++list_indices_.back();
      current_layer_ = ChildAt(parent, list_indices_.back());
      return *this;
    }

    // We need to ascend. We will pop an index off the stack.
    list_indices_.pop_back();
  }

  current_layer_ = nullptr;
  return *this;
}

TreeSynchronizer类的静态成员函数ReuseOrCreateLayerImpl的实现如下所示:

// 复用没有变化的节点
template <typename LayerType>
std::unique_ptr<LayerImpl> ReuseOrCreateLayerImpl(OwnedLayerImplMap* old_layers,
                                                  LayerType* layer,
                                                  LayerTreeImpl* tree_impl) {
  if (!layer)
    return nullptr;
  std::unique_ptr<LayerImpl> layer_impl = std::move((*old_layers)[layer->id()]);
  if (!layer_impl)
    layer_impl = layer->CreateLayerImpl(tree_impl);
  return layer_impl;
}

参数layer描述的Layer是CC Layer Tree中的一个Layer,实际类型是PictureLayer,如下创建。 

std::unique_ptr<LayerImpl> PictureLayer::CreateLayerImpl(
    LayerTreeImpl* tree_impl) {
  return PictureLayerImpl::Create(tree_impl, id(), mask_type_);
}

第二部开始同步属性,就是同步property_tree: TransformTree, EffectTree, ClipTree, ScrollTree (Need to dig in)

这一步执行完成后,CC Layer Tree就同步到一个新的CC Pending Layer Tree中去了,ProxyImpl::ScheduledActionCommit接下来就会唤醒CrRendererMain线程,并且继续在当前线程,也就是Compositor线程,调用LayerTreeHostImpl::CommitComplete为新的CC Pending Layer Tree中的Layer更新或者创建分块,为以后执行光栅化操作做准备。

       LayerTreeHostImpl::CommitComplete的实现如下所示:

void LayerTreeHostImpl::CommitComplete() {
  ...
  UpdateSyncTreeAfterCommitOrImplSideInvalidation();
  micro_benchmark_controller_.DidCompleteCommit();
}


void LayerTreeHostImpl::UpdateSyncTreeAfterCommitOrImplSideInvalidation() {
  ...
  sync_tree()->set_needs_update_draw_properties();
  sync_tree()->UpdateDrawProperties(update_image_animation_controller);
  ...
}


bool LayerTreeImpl::UpdateDrawProperties(
    bool update_image_animation_controller) {
  ...
  {
    base::ElapsedTimer timer;
    TRACE_EVENT2(
        "cc", "LayerTreeImpl::UpdateDrawProperties::CalculateDrawProperties",
        "IsActive", IsActiveTree(), "SourceFrameNumber", source_frame_number_);
    ...
  }

  {
    TRACE_EVENT2("cc", "LayerTreeImpl::UpdateDrawProperties::Occlusion",
                 "IsActive", IsActiveTree(), "SourceFrameNumber",
                 source_frame_number_);
    ...;
  }

  // Resourceless draw do not need tiles and should not affect existing tile
  // priorities.
  if (!is_in_resourceless_software_draw_mode()) {
    TRACE_EVENT_BEGIN2("cc", "LayerTreeImpl::UpdateDrawProperties::UpdateTiles",
                       "IsActive", IsActiveTree(), "SourceFrameNumber",
                       source_frame_number_);
    ...
      tile_priorities_updated |= layer->UpdateTiles();
    }

    if (tile_priorities_updated)
      DidModifyTilePriorities();
  }

  ...
}
bool PictureLayerImpl::UpdateTiles() {
  ...
  UpdateIdealScales();

  if (!raster_contents_scale_ || ShouldAdjustRasterScale()) {
    RecalculateRasterScales();
    AddTilingsForRasterScale();
  }

  if (layer_tree_impl()->IsActiveTree())
    AddLowResolutionTilingIfNeeded();

  ...
  UpdateViewportRectForTilePriorityInContentSpace();
  ...
  bool updated = tilings_->UpdateTilePriorities(
      viewport_rect_for_tile_priority_in_content_space_, ideal_contents_scale_,
      current_frame_time_in_seconds, occlusion_in_content_space,
      can_require_tiles_for_activation);
  return updated;
}
bool PictureLayerTilingSet::UpdateTilePriorities(
    ...,
    bool can_require_tiles_for_activation) {
  ...
  UpdatePriorityRects(visible_rect_in_layer_space,
                      current_frame_time_in_seconds, ideal_contents_scale);

  for (const auto& tiling : tilings_) {
    tiling->set_can_require_tiles_for_activation(
        can_require_tiles_for_activation);
    tiling->ComputeTilePriorityRects(
        visible_rect_in_layer_space_, skewport_in_layer_space_,
        soon_border_rect_in_layer_space_, eventually_rect_in_layer_space_,
        ideal_contents_scale, occlusion_in_layer_space);
  }
  return true;
}

 PictureLayerImpl类的成员函数UpdateTiles首先调用成员函数UpdateIdealScales更新分块的理想缩放因子,即Ideal Scale,如下所示:

void PictureLayerImpl::UpdateIdealScales() {
  DCHECK(CanHaveTilings());

  float min_contents_scale = MinimumContentsScale();
  DCHECK_GT(min_contents_scale, 0.f);

  ideal_page_scale_ = IsAffectedByPageScale()
                          ? layer_tree_impl()->current_page_scale_factor()
                          : 1.f;
  ideal_device_scale_ = layer_tree_impl()->device_scale_factor();
  ideal_contents_scale_ =
      std::min(kMaxIdealContentsScale,
               std::max(GetIdealContentsScale(), min_contents_scale));
  ideal_source_scale_ =
      ideal_contents_scale_ / ideal_page_scale_ / ideal_device_scale_;
}

 Ideal Scale指的是分块的大小与它实际要显示的大小是1:1的关系。一个分块有4种Ideal Scale:

       1. ideal_device_scale_(Device Scale):设置在显示设备上的缩放因子。

       2. ideal_page_scale_(Page Scale):用户Pinch网页时产生的缩放因子。

       3. ideal_source_scale_(Source Scale):通过Javascript和CSS设置的缩放因子。

       4. ideal_contents_scale_(Contents Scale):上述三种缩放因子相乘之后得到的缩放因子。

       此外,上述4种Ideal Scale还规定了最小值,也就是前面计算出来4种Ideal Scale不能小于各自对应的Min Scale。

       回到PictureLayerImpl类的成员函数UpdateTiles中,更新了分块的Ideal Scale之后,它接下来判断是否需要重新计算分块的光栅化缩放因子,即Raster Scale。通过调用PictureLayerImpl类的成员函数ShouldAdjustRasterScale进行判断,一旦它决定要重新计算网页分块的Raster Scale,那么它就会调用成员函数RecalculateRasterScales进行计算,如下所示:

void PictureLayerImpl::RecalculateRasterScales() {
  ...
  raster_contents_scale_ =
      std::max(raster_contents_scale_, MinimumContentsScale());
  raster_contents_scale_ =
      std::min(raster_contents_scale_, MaximumContentsScale());
  DCHECK_GE(raster_contents_scale_, MinimumContentsScale());
  DCHECK_LE(raster_contents_scale_, MaximumContentsScale());

  // If this layer would create zero or one tiles at this content scale,
  // don't create a low res tiling.
  gfx::Size raster_bounds =
      gfx::ScaleToCeiledSize(raster_source_->GetSize(), raster_contents_scale_);
  gfx::Size tile_size = CalculateTileSize(raster_bounds);
  bool tile_covers_bounds = tile_size.width() >= raster_bounds.width() &&
                            tile_size.height() >= raster_bounds.height();
  if (tile_size.IsEmpty() || tile_covers_bounds) {
    low_res_raster_contents_scale_ = raster_contents_scale_;
    return;
  }

  float low_res_factor =
      layer_tree_impl()->settings().low_res_contents_scale_factor;
  low_res_raster_contents_scale_ =
      std::max(raster_contents_scale_ * low_res_factor, MinimumContentsScale());
}

按照以上步骤调整出来的Raster Contents Scale属于Ideal Raster Content Scale,PictureLayerImpl类的成员函数RecalculateRasterScales接下来还要计算一个Low Res Raster Contents Scale,并且保存在成员变量low_res_raster_contents_scale_中。这个Low Res Raster Contents Scale有什么用呢?原来,一个Layer除了会按照Ideal Raster Content Scale进行分块之外,还会按照Low Res Raster Contents Scale进行分块。这样就可以先快速地显示出缩放因子为Low Res Raster Contents Scale的分块来,尽管这些分块的内容是模糊的,但是也比用户什么也看不到强。在显示缩放因子为Low Res Raster Contents Scale的分块的同时,CC模块也会在背后默默地对缩放因子为Ideal Raster Content Scale的分块进行光栅化操作。等到光栅化操作完成的时候,缩放因子为Ideal Raster Content Scale的分块就可以替换掉缩放因子为Low Res Raster Contents Scale的分块,使得用户最终可以看到清晰的内容。

再回到PictureLayerImpl类的成员函数UpdateTiles中,它重新计算好网页分块的Raster Scale之后,接下来就会按照计算出来的Raster Scale对当前正在处理的Layer创建新的分块划分,这是通过PictureLayerImpl类的成员函数AddTilingsForRasterScale实现的,如下所示:

void PictureLayerImpl::AddTilingsForRasterScale() {
  // Reset all resolution enums on tilings, we'll be setting new values in this
  // function.
  tilings_->MarkAllTilingsNonIdeal();

  PictureLayerTiling* high_res =
      tilings_->FindTilingWithScaleKey(raster_contents_scale_);
  // Note: This function is always invoked when raster scale is recomputed,
  // but not necessarily changed. This means raster translation update is also
  // always done when there are significant changes that triggered raster scale
  // recomputation.
  gfx::Vector2dF raster_translation =
      CalculateRasterTranslation(raster_contents_scale_);
  if (high_res &&
      high_res->raster_transform().translation() != raster_translation) {
    tilings_->Remove(high_res);
    high_res = nullptr;
  }
  if (!high_res) {
    // We always need a high res tiling, so create one if it doesn't exist.
    high_res = AddTiling(
        gfx::AxisTransform2d(raster_contents_scale_, raster_translation));
  } else if (high_res->may_contain_low_resolution_tiles()) {
    // If the tiling we find here was LOW_RESOLUTION previously, it may not be
    // fully rastered, so destroy the old tiles.
    high_res->Reset();
    // Reset the flag now that we'll make it high res, it will have fully
    // rastered content.
    high_res->reset_may_contain_low_resolution_tiles();
  }
  high_res->set_resolution(HIGH_RESOLUTION);

  if (layer_tree_impl()->IsPendingTree()) {
    // On the pending tree, drop any tilings that are non-ideal since we don't
    // need them to activate anyway.
    tilings_->RemoveNonIdealTilings();
  }

  SanityCheckTilingState();
}

Tiling代表一种划分方式, tile代表某种tiling下的具体一个小块。每一个Tiling都通过一个PictureLayerTiling对象描述,并且这些PictureLayerTiling对象保存在PictureLayerImpl类的成员变量tilings_描述的一个PictureLayerTiling Set中。 PictureLayerImpl类的成员函数AddTilingsForRasterScale还会做一件事情,就是对当前正在处理的Layer的所有Tiling进行标记。其中,Raster Scale为High Res Raster Contents Scale的Tiling的类型被标记为HIGH_RESOLUTION,Raster Scale为Low Res Raster Contents Scale的Tiling如果存在,并且与Raster Scale为High Res Raster Contents Scale的Tiling不相同,那么它的类型被标记为LOW_RESOLUTION,(在UpdateTiles中单独为有需要创建的标记LOW_RESOLUTION),其余的Tiling被标记为NON_IDEAL_RESOLUTION。之所以要对Tiling进行这样的标记,是因为后面对分块执行光栅化操作之前,会先对Tiling中的分块设置优先级。优先级越高的分块,它就越优先执行光栅化操作,而分块的优先级,与它们所在的Tiling的类型有关。

接下来我们继续分析PictureLayerImpl类的成员函数AddTiling的实现,以便了解一个新的Tiling的创建过程,如下所示:

PictureLayerTiling* PictureLayerImpl::AddTiling(
    const gfx::AxisTransform2d& contents_transform) {
  return tilings_->AddTiling(contents_transform, raster_source_);
}

PictureLayerTiling* PictureLayerTilingSet::AddTiling(
    const gfx::AxisTransform2d& raster_transform,
    scoped_refptr<RasterSource> raster_source) {
  ...
  tilings_.push_back(std::make_unique<PictureLayerTiling>(
      tree_, raster_transform, raster_source, client_,
      kMaxSoonBorderDistanceInScreenPixels, max_preraster_distance_));
  ...
}

PictureLayerTiling::PictureLayerTiling(
    ...,
    float max_preraster_distance)
    : raster_transform_(raster_transform),
      ...,
      max_preraster_distance_(max_preraster_distance) {
  ...
  gfx::Rect content_bounds_rect =
      EnclosingContentsRectFromLayerRect(gfx::Rect(raster_source_->GetSize()));
  gfx::Size tiling_size = gfx::Size(content_bounds_rect.bottom_right().x(),
                                    content_bounds_rect.bottom_right().y());
  tiling_data_.SetTilingSize(tiling_size);
  gfx::Size tile_size = client_->CalculateTileSize(tiling_size);
  tiling_data_.SetMaxTextureSize(tile_size);
}

PictureLayerTiling类还有一个重要的成员变量tiling_data_,它描述的是一个TilingData对象。这个TilingData对象负责对当前正在创建的Tiling进行分块,CC Layer Tree中的Layer也是通过TilingData类进行分块的。这意味着不管是CC Layer Tree中的Layer和CC Pening Layer Tree中的Layer的分块方式都是一样的,区别只是在于分块的大小一样。

       于是可以开始对于每一个tiling创建具体的tiles,如下所示:

而且并不是所有的tiles都是需要创建的,只有在四个区域内的才需要。

PictureLayerTiling类的成员函数UpdateTilePriorities会根据当前正在处理的Tiling的缩放因子计算出4个区域,如图3所示:

图3 Tiling的区域划分

void PictureLayerTiling::SetTilePriorityRects(
    ...,
    const Occlusion& occlusion_in_layer_space) {
  current_visible_rect_ = visible_rect_in_content_space;
  current_skewport_rect_ = skewport;
  current_soon_border_rect_ = soon_border_rect;
  current_eventually_rect_ = eventually_rect;
  current_occlusion_in_layer_space_ = occlusion_in_layer_space;
  current_content_to_screen_scale_ = content_to_screen_scale;

  gfx::Rect tiling_rect(tiling_size());
  has_visible_rect_tiles_ = tiling_rect.Intersects(current_visible_rect_);
  has_skewport_rect_tiles_ = tiling_rect.Intersects(current_skewport_rect_);
  has_soon_border_rect_tiles_ =
      tiling_rect.Intersects(current_soon_border_rect_);
  has_eventually_rect_tiles_ = tiling_rect.Intersects(current_eventually_rect_);

  ...
}

       这4个区域分别是:   

       1. current_visible_rect_(Visible rect):描述Layer的当前可见区域。

       2. current_skewport_rect_(Skewport):根据Layer的移动方向和速度计算出来的区域。假设Layer按Y轴方向移动,移动前的坐标为old_y,移动后的坐标为new_y,从old_y到new_y耗费的时间为delta秒,那么移动速度就为(new_y - old_y) / delta。按照这个速度移动1秒的时间,就得到Skewport的大小。注意,Skewport是在Visible rect的基础上进行计算的,也就是两者的原点是一样的。还有一点需要注意的是,如果光栅化操作是通过GPU实现的,那么Skewport的大小与Visible rect是一致的。

       3. current_soon_border_rect_ (Border rect):由Visible rect在四周分别扩展312 pixels后得到。

       4. current_eventually_rect_(Eventually rect):一个由128个分块组成的区域,这个区域以Visible rect为中心。

理解了分块的优先级之后,回到PictureLayerTiling::UpdateTilePriorities中,它在设置分块的优先级之前,会调用另外一个成员函数SetLiveTilesRect,用来检查哪些分块是需要创建的,哪些分块是需要移除的,它的实现如下所示:

void PictureLayerTiling::SetLiveTilesRect(
    const gfx::Rect& new_live_tiles_rect) {
  ...
  // Iterate to delete all tiles outside of our new live_tiles rect.
  for (TilingData::DifferenceIterator iter(&tiling_data_, live_tiles_rect_,
                                           new_live_tiles_rect);
       iter; ++iter) {
    TakeTileAt(iter.index_x(), iter.index_y());
  }

  // We don't rasterize non ideal resolution tiles, so there is no need to
  // create any new tiles.
  if (resolution_ == NON_IDEAL_RESOLUTION) {
    live_tiles_rect_.Intersect(new_live_tiles_rect);
    VerifyLiveTilesRect();
    return;
  }

  // Iterate to allocate new tiles for all regions with newly exposed area.
  for (TilingData::DifferenceIterator iter(&tiling_data_, new_live_tiles_rect,
                                           live_tiles_rect_);
       iter; ++iter) {
    Tile::CreateInfo info = CreateInfoForTile(iter.index_x(), iter.index_y());
    if (ShouldCreateTileAt(info))
      CreateTile(info);
  }

  live_tiles_rect_ = new_live_tiles_rect;
  VerifyLiveTilesRect();
}

从前面的调用过程可以知道,参数new_live_tiles_rect描述的是图2所示的Eventually rect。位于这个Eventually rect中的分块都是需要创建的。

       PictureLayerTiling类的成员变量live_tiles_rect_保存的是上一次使用的Eventually rect。注意,这里可以保证位于上一次使用的Eventually rect中的分块都是已经创建好了的。因此,当前需要创建的分块是位于(new_live_tiles_rect - live_tiles_rect_)区域中的。同时也意味着位于(live_tiles_rect_ - new_live_tiles_rect )区域中的分块不再需要了的,它们需要删除,以节省空间。

       PictureLayerTiling类的成员函数SetLiveTilesRect做的第二件事情就是为(new_live_tiles_rect - live_tiles_rect_)区域创建分块,这是通过第二个for循环完成的。在这一个区域中的每一个分块都是通过调用PictureLayerTiling类的成员函数CreateTile创建的。 

Tile* PictureLayerTiling::CreateTile(const Tile::CreateInfo& info) {
  const int i = info.tiling_i_index;
  const int j = info.tiling_j_index;
  TileMapKey key(i, j);
  DCHECK(tiles_.find(key) == tiles_.end());

  if (!raster_source_->CoversRect(info.enclosing_layer_rect))
    return nullptr;

  all_tiles_done_ = false;
  std::unique_ptr<Tile> tile = client_->CreateTile(info);
  Tile* raw_ptr = tile.get();
  tiles_[key] = std::move(tile);
  return raw_ptr;
}

要创建的分块通过参数i和j描述,表示第i行第j列的分块。PictureLayerTiling类的成员函数CreateTile首先根据参数i和j,以及成员变量tiling_data描述的分块信息,计算出即将要创建的分块所占据的区域tile_rect。tiles_描述的Map保存了一个Tiling当前创建的所有的分块。

std::unique_ptr<Tile> TileManager::CreateTile(const Tile::CreateInfo& info,
                                              int layer_id,
                                              int source_frame_number,
                                              int flags,
                                              bool can_use_lcd_text) {
  // We need to have a tile task worker pool to do anything meaningful with
  // tiles.
  DCHECK(tile_task_manager_);
  std::unique_ptr<Tile> tile(new Tile(this, info, layer_id, source_frame_number,
                                      flags, can_use_lcd_text));
  DCHECK(tiles_.find(tile->id()) == tiles_.end());

  tiles_[tile->id()] = tile.get();
  return tile;
}


Tile::Tile(TileManager* tile_manager,
           const CreateInfo& info,
           int layer_id,
           int source_frame_number,
           int flags,
           bool can_use_lcd_text)
    : tile_manager_(tile_manager),
      tiling_(info.tiling),
      content_rect_(info.content_rect),
      enclosing_layer_rect_(info.enclosing_layer_rect),
      raster_transform_(info.raster_transform),
      layer_id_(layer_id),
      source_frame_number_(source_frame_number),
      flags_(flags),
      tiling_i_index_(info.tiling_i_index),
      tiling_j_index_(info.tiling_j_index),
      required_for_activation_(false),
      required_for_draw_(false),
      is_solid_color_analysis_performed_(false),
      can_use_lcd_text_(can_use_lcd_text),
      id_(tile_manager->GetUniqueTileId()),
      invalidated_id_(0),
      scheduled_priority_(0) {}

这一步执行完成之后,CC Pending Layer Tree的分块就创建完毕,并且这些分块已经被赋予了优先级。回到PictureLayerImpl::UpdateTilePriorities中,它接下来就会调用LayerTreeImpl::DidModifyTilePriorities通知调度器CC Pending Layer Tree的分块优先级发生了变化,需要调度执行一个PREPARE_TILES操作,如下所示:  

void LayerTreeImpl::DidModifyTilePriorities() {
  host_impl_->DidModifyTilePriorities();
}

void LayerTreeHostImpl::DidModifyTilePriorities() {
  // Mark priorities as dirty and schedule a PrepareTiles().
  tile_priorities_dirty_ = true;
  tile_manager_.DidModifyTilePriorities();
  client_->SetNeedsPrepareTilesOnImplThread();
}

void SingleThreadProxy::SetNeedsPrepareTilesOnImplThread() {
  TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsPrepareTilesOnImplThread");
  if (scheduler_on_impl_thread_)
    scheduler_on_impl_thread_->SetNeedsPrepareTiles();
}

void Scheduler::SetNeedsPrepareTiles() {
  DCHECK(!IsInsideAction(SchedulerStateMachine::Action::PREPARE_TILES));
  state_machine_.SetNeedsPrepareTiles();
  ProcessScheduledActions();
}

这一步执行完成之后,CC Pending Layer Tree的光栅化操作就准备就绪了。回到前面分析的PictureLayerImpl类的成员函数UpdateTiles中,它还需要执行一个操作,就是将CC Pending Layer Tree中的分块标记为Required For Activation,也就是CC模块正在等待这些分块的光栅化操作执行完成,这一步在PictureLayerTilingSet::UpdateTilePriorities已经完成。

       至此,我们就分析完成了CC Layer Tree同步为CC Pending Layer Tree的过程。这个同步过程是由Compositor线程执行的,但是CrRendererMain线程会处理睡眠状态。Compositor线程完成同步操作后,就会唤醒CrRendererMain线程,让它继续执行其它的工作。与此同时,Compositor线程也会为刚刚得到的CC Pending Layer Tree创建分块,以及给这些分块设置优先级和Required For Activation标记。这些工作完成之后,调度器就可以请求Compositor线程对CC Pending Layer Tree执行光栅化操作了。

 

猜你喜欢

转载自blog.csdn.net/tornmy/article/details/81985939