站在老罗的肩膀上: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。