Dive into how chromium compositor works - ds-hwang/wiki GitHub Wiki
Dive into LayerTreeHostImpl
Commit seq.
// on impl
void Scheduler::ProcessScheduledActions() {
...
case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME:
client_->ScheduledActionSendBeginMainFrame();
...
}
// on impl
void ThreadProxy::ScheduledActionSendBeginMainFrame() {
...
Proxy::MainThreadTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ThreadProxy::BeginMainFrame,
main_thread_weak_ptr_,
base::Passed(&begin_main_frame_state)));
...
}
// on main
void ThreadProxy::BeginMainFrame(
scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) {
...
* When the bFAC message runs on the main thread we do the following things:
* Apply any impl-side scrolls to the main thread
* Call the requestAnimationFrame callback
* Perform any pending layout (namely, HTML layout)
* Paint any layers that need to be painted (software rasterization)
// Paint layers!!!
bool updated = layer_tree_host_->UpdateLayers(queue.get());
...
{
...
CompletionEvent completion;
Proxy::ImplThreadTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ThreadProxy::StartCommitOnImplThread,
impl_thread_weak_ptr_,
&completion,
queue.release(),
offscreen_context_provider));
completion.Wait();
// WAIT!!!
...
}
layer_tree_host_->CommitComplete();
layer_tree_host_->DidBeginMainFrame();
}
// on impl
void ThreadProxy::StartCommitOnImplThread(
CompletionEvent* completion,
ResourceUpdateQueue* raw_queue,
scoped_refptr<cc::ContextProvider> offscreen_context_provider) {
..
if (layer_tree_host_->contents_texture_manager()) {
if (layer_tree_host_->contents_texture_manager()->
LinkedEvictedBackingsExist()) {
// Clear any uploads we were making to textures linked to evicted
// resources
queue->ClearUploadsToEvictedResources();
// Some textures in the layer tree are invalid. Kick off another commit
// to fill them again.
SetNeedsCommitOnImplThread(); // Queue COMMIT!!! but if not impl-side painting....
}
layer_tree_host_->contents_texture_manager()->
PushTexturePrioritiesToBackings();
}
commit_completion_event_on_impl_thread_ = completion;
current_resource_update_controller_on_impl_thread_ =
ResourceUpdateController::Create(
this,
Proxy::ImplThreadTaskRunner(),
queue.Pass(),
layer_tree_host_impl_->resource_provider());
current_resource_update_controller_on_impl_thread_->PerformMoreUpdates(
scheduler_on_impl_thread_->AnticipatedDrawTime());
}
// on impl. it looks like impl-side painting abstraction. NEED TO UNDERSTAND!!!!
void ResourceUpdateController::PerformMoreUpdates(
base::TimeTicks time_limit) {
time_limit_ = time_limit;
// Update already in progress.
if (task_posted_)
return;
// Call UpdateMoreTexturesNow() directly unless it's the first update
// attempt. This ensures that we empty the update queue in a finite
// amount of time.
if (!first_update_attempt_)
UpdateMoreTexturesNow();
// Post a 0-delay task when no updates were left. When it runs,
// ReadyToFinalizeTextureUpdates() will be called.
if (!UpdateMoreTexturesIfEnoughTimeRemaining()) {
task_posted_ = true;
task_runner_->PostTask(
FROM_HERE,
base::Bind(&ResourceUpdateController::OnTimerFired,
weak_factory_.GetWeakPtr()));
}
first_update_attempt_ = false;
}
void ResourceUpdateController::OnTimerFired() {
task_posted_ = false;
if (!UpdateMoreTexturesIfEnoughTimeRemaining())
client_->ReadyToFinalizeTextureUpdates();
}
void ThreadProxy::ReadyToFinalizeTextureUpdates() {
DCHECK(IsImplThread());
scheduler_on_impl_thread_->FinishCommit();
}
// a while later on impl
void ThreadProxy::ScheduledActionCommit() {
TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionCommit");
DCHECK(IsImplThread());
...
layer_tree_host_impl_->BeginCommit();
layer_tree_host_->BeginCommitOnImplThread(layer_tree_host_impl_.get());
layer_tree_host_->FinishCommitOnImplThread(layer_tree_host_impl_.get());
layer_tree_host_impl_->CommitComplete();
...
// wake up main thread
commit_completion_event_on_impl_thread_->Signal();
...
// SetVisible kicks off the next scheduler action, so this must be last.
scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible());
}
void LayerTreeHost::FinishCommitOnImplThread(LayerTreeHostImpl* host_impl) {
DCHECK(proxy_->IsImplThread());
...
if (needs_full_tree_sync_)
sync_tree->SetRootLayer(TreeSynchronizer::SynchronizeTrees(
root_layer(), sync_tree->DetachLayerTree(), sync_tree));
{
TRACE_EVENT0("cc", "LayerTreeHost::PushProperties");
TreeSynchronizer::PushProperties(root_layer(), sync_tree->root_layer());
}
...
}
SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
...
if (ShouldDraw()) {
if (readback_state_ == READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK)
return ACTION_DRAW_AND_READBACK;
else 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;
}
...
}
void Scheduler::ProcessScheduledActions() {
...
case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
DrawAndSwapIfPossible();
break;
case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED:
DrawAndSwapForced();
break;
...
}
DrawSwapReadbackResult ThreadProxy::ScheduledActionDrawAndSwapIfPossible() {
TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndSwap");
bool forced_draw = false;
bool swap_requested = true;
bool readback_requested = false;
return DrawSwapReadbackInternal(
forced_draw, swap_requested, readback_requested);
}
// or
DrawSwapReadbackResult ThreadProxy::ScheduledActionDrawAndSwapForced() {
TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndSwapForced");
bool forced_draw = true;
bool swap_requested = true;
bool readback_requested = false;
return DrawSwapReadbackInternal(
forced_draw, swap_requested, readback_requested);
}
DrawSwapReadbackResult ThreadProxy::DrawSwapReadbackInternal(
bool forced_draw,
bool swap_requested,
bool readback_requested) {
DrawSwapReadbackResult result;
result.did_draw = false;
result.did_swap = false;
result.did_readback = false;
DCHECK(IsImplThread());
DCHECK(layer_tree_host_impl_.get());
if (!layer_tree_host_impl_)
return result;
DCHECK(layer_tree_host_impl_->renderer());
if (!layer_tree_host_impl_->renderer())
return result;
base::TimeTicks start_time = base::TimeTicks::HighResNow();
base::TimeDelta draw_duration_estimate = DrawDurationEstimate();
base::AutoReset<bool> mark_inside(&inside_draw_, true);
// Advance our animations.
base::TimeTicks monotonic_time =
layer_tree_host_impl_->CurrentFrameTimeTicks();
base::Time wall_clock_time = layer_tree_host_impl_->CurrentFrameTime();
// TODO(enne): This should probably happen post-animate.
if (layer_tree_host_impl_->pending_tree())
layer_tree_host_impl_->pending_tree()->UpdateDrawProperties();
layer_tree_host_impl_->Animate(monotonic_time, wall_clock_time);
// This method is called on a forced draw, regardless of whether we are able
// to produce a frame, as the calling site on main thread is blocked until its
// request completes, and we signal completion here. If CanDraw() is false, we
// will indicate success=false to the caller, but we must still signal
// completion to avoid deadlock.
// We guard PrepareToDraw() with CanDraw() because it always returns a valid
// frame, so can only be used when such a frame is possible. Since
// DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
// CanDraw() as well.
bool drawing_for_readback =
readback_requested && !!readback_request_on_impl_thread_;
bool can_do_readback = layer_tree_host_impl_->renderer()->CanReadPixels();
LayerTreeHostImpl::FrameData frame;
bool draw_frame = false;
if (layer_tree_host_impl_->CanDraw() &&
(!drawing_for_readback || can_do_readback)) {
// If it is for a readback, make sure we draw the portion being read back.
gfx::Rect readback_rect;
if (drawing_for_readback)
readback_rect = readback_request_on_impl_thread_->rect;
if (layer_tree_host_impl_->PrepareToDraw(&frame, readback_rect) ||
forced_draw)
draw_frame = true;
}
if (draw_frame) {
layer_tree_host_impl_->DrawLayers(
&frame,
scheduler_on_impl_thread_->LastBeginImplFrameTime());
result.did_draw = true;
}
layer_tree_host_impl_->DidDrawAllLayers(frame);
bool start_ready_animations = draw_frame;
layer_tree_host_impl_->UpdateAnimationState(start_ready_animations);
// Check for a pending CompositeAndReadback.
if (drawing_for_readback) {
DCHECK(!swap_requested);
result.did_readback = false;
if (draw_frame && !layer_tree_host_impl_->IsContextLost()) {
layer_tree_host_impl_->Readback(readback_request_on_impl_thread_->pixels,
readback_request_on_impl_thread_->rect);
result.did_readback = true;
}
readback_request_on_impl_thread_->success = result.did_readback;
readback_request_on_impl_thread_->completion.Signal();
readback_request_on_impl_thread_ = NULL;
} else if (draw_frame) {
DCHECK(swap_requested);
result.did_swap = layer_tree_host_impl_->SwapBuffers(frame);
// We don't know if we have incomplete tiles if we didn't actually swap.
if (result.did_swap) {
DCHECK(!frame.has_no_damage);
SetSwapUsedIncompleteTileOnImplThread(frame.contains_incomplete_tile);
}
}
// Tell the main thread that the the newly-commited frame was drawn.
if (next_frame_is_newly_committed_frame_on_impl_thread_) {
next_frame_is_newly_committed_frame_on_impl_thread_ = false;
Proxy::MainThreadTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ThreadProxy::DidCommitAndDrawFrame, main_thread_weak_ptr_));
}
if (draw_frame) {
CheckOutputSurfaceStatusOnImplThread();
base::TimeDelta draw_duration = base::TimeTicks::HighResNow() - start_time;
draw_duration_history_.InsertSample(draw_duration);
base::TimeDelta draw_duration_overestimate;
base::TimeDelta draw_duration_underestimate;
if (draw_duration > draw_duration_estimate)
draw_duration_underestimate = draw_duration - draw_duration_estimate;
else
draw_duration_overestimate = draw_duration_estimate - draw_duration;
UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.DrawDuration",
draw_duration,
base::TimeDelta::FromMilliseconds(1),
base::TimeDelta::FromMilliseconds(100),
50);
UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.DrawDurationUnderestimate",
draw_duration_underestimate,
base::TimeDelta::FromMilliseconds(1),
base::TimeDelta::FromMilliseconds(100),
50);
UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.DrawDurationOverestimate",
draw_duration_overestimate,
base::TimeDelta::FromMilliseconds(1),
base::TimeDelta::FromMilliseconds(100),
50);
}
return result;
}
.
.
.
void TiledLayerImpl::AppendQuads(QuadSink* quad_sink,
AppendQuadsData* append_quads_data) {
DCHECK(tiler_);
DCHECK(!tiler_->has_empty_bounds());
DCHECK(!visible_content_rect().IsEmpty());
...
}