1 // Copyright 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/trees/single_thread_proxy.h"
7 #include "base/auto_reset.h"
8 #include "base/profiler/scoped_tracker.h"
9 #include "base/trace_event/trace_event.h"
10 #include "cc/debug/benchmark_instrumentation.h"
11 #include "cc/debug/devtools_instrumentation.h"
12 #include "cc/output/context_provider.h"
13 #include "cc/output/output_surface.h"
14 #include "cc/quads/draw_quad.h"
15 #include "cc/scheduler/commit_earlyout_reason.h"
16 #include "cc/scheduler/compositor_timing_history.h"
17 #include "cc/scheduler/scheduler.h"
18 #include "cc/trees/layer_tree_host.h"
19 #include "cc/trees/layer_tree_host_single_thread_client.h"
20 #include "cc/trees/layer_tree_impl.h"
21 #include "cc/trees/scoped_abort_remaining_swap_promises.h"
25 scoped_ptr
<Proxy
> SingleThreadProxy::Create(
26 LayerTreeHost
* layer_tree_host
,
27 LayerTreeHostSingleThreadClient
* client
,
28 scoped_refptr
<base::SingleThreadTaskRunner
> main_task_runner
,
29 scoped_ptr
<BeginFrameSource
> external_begin_frame_source
) {
30 return make_scoped_ptr(new SingleThreadProxy(
34 external_begin_frame_source
.Pass()));
37 SingleThreadProxy::SingleThreadProxy(
38 LayerTreeHost
* layer_tree_host
,
39 LayerTreeHostSingleThreadClient
* client
,
40 scoped_refptr
<base::SingleThreadTaskRunner
> main_task_runner
,
41 scoped_ptr
<BeginFrameSource
> external_begin_frame_source
)
42 : Proxy(main_task_runner
, NULL
),
43 layer_tree_host_(layer_tree_host
),
45 external_begin_frame_source_(external_begin_frame_source
.Pass()),
46 next_frame_is_newly_committed_frame_(false),
48 inside_impl_frame_(false),
51 defer_commits_(false),
52 animate_requested_(false),
53 commit_requested_(false),
54 inside_synchronous_composite_(false),
55 output_surface_creation_requested_(false),
57 TRACE_EVENT0("cc", "SingleThreadProxy::SingleThreadProxy");
58 DCHECK(Proxy::IsMainThread());
59 DCHECK(layer_tree_host
);
61 if (layer_tree_host
->settings().single_thread_proxy_scheduler
&&
62 !scheduler_on_impl_thread_
) {
63 SchedulerSettings
scheduler_settings(
64 layer_tree_host
->settings().ToSchedulerSettings());
65 scheduler_settings
.commit_to_active_tree
= CommitToActiveTree();
67 scoped_ptr
<CompositorTimingHistory
> compositor_timing_history(
68 new CompositorTimingHistory(
69 CompositorTimingHistory::BROWSER_UMA
,
70 layer_tree_host
->rendering_stats_instrumentation()));
72 scheduler_on_impl_thread_
= Scheduler::Create(
73 this, scheduler_settings
, layer_tree_host_
->id(),
74 MainThreadTaskRunner(), external_begin_frame_source_
.get(),
75 compositor_timing_history
.Pass());
79 void SingleThreadProxy::Start() {
80 DebugScopedSetImplThread
impl(this);
81 layer_tree_host_impl_
= layer_tree_host_
->CreateLayerTreeHostImpl(this);
84 SingleThreadProxy::~SingleThreadProxy() {
85 TRACE_EVENT0("cc", "SingleThreadProxy::~SingleThreadProxy");
86 DCHECK(Proxy::IsMainThread());
87 // Make sure Stop() got called or never Started.
88 DCHECK(!layer_tree_host_impl_
);
91 void SingleThreadProxy::FinishAllRendering() {
92 TRACE_EVENT0("cc", "SingleThreadProxy::FinishAllRendering");
93 DCHECK(Proxy::IsMainThread());
95 DebugScopedSetImplThread
impl(this);
96 layer_tree_host_impl_
->FinishAllRendering();
100 bool SingleThreadProxy::IsStarted() const {
101 DCHECK(Proxy::IsMainThread());
102 return layer_tree_host_impl_
;
105 bool SingleThreadProxy::CommitToActiveTree() const {
106 // With SingleThreadProxy we skip the pending tree and commit directly to the
111 void SingleThreadProxy::SetLayerTreeHostClientReady() {
112 TRACE_EVENT0("cc", "SingleThreadProxy::SetLayerTreeHostClientReady");
113 // Scheduling is controlled by the embedder in the single thread case, so
115 DCHECK(Proxy::IsMainThread());
116 DebugScopedSetImplThread
impl(this);
117 if (scheduler_on_impl_thread_
) {
118 scheduler_on_impl_thread_
->SetCanStart();
119 scheduler_on_impl_thread_
->SetVisible(layer_tree_host_impl_
->visible());
123 void SingleThreadProxy::SetVisible(bool visible
) {
124 TRACE_EVENT1("cc", "SingleThreadProxy::SetVisible", "visible", visible
);
125 DebugScopedSetImplThread
impl(this);
127 layer_tree_host_impl_
->SetVisible(visible
);
129 if (scheduler_on_impl_thread_
)
130 scheduler_on_impl_thread_
->SetVisible(layer_tree_host_impl_
->visible());
131 // Changing visibility could change ShouldComposite().
134 void SingleThreadProxy::SetThrottleFrameProduction(bool throttle
) {
135 TRACE_EVENT1("cc", "SingleThreadProxy::SetThrottleFrameProduction",
136 "throttle", throttle
);
137 DebugScopedSetImplThread
impl(this);
138 if (scheduler_on_impl_thread_
)
139 scheduler_on_impl_thread_
->SetThrottleFrameProduction(throttle
);
142 void SingleThreadProxy::RequestNewOutputSurface() {
143 DCHECK(Proxy::IsMainThread());
144 DCHECK(layer_tree_host_
->output_surface_lost());
145 output_surface_creation_callback_
.Cancel();
146 if (output_surface_creation_requested_
)
148 output_surface_creation_requested_
= true;
149 layer_tree_host_
->RequestNewOutputSurface();
152 void SingleThreadProxy::SetOutputSurface(
153 scoped_ptr
<OutputSurface
> output_surface
) {
154 DCHECK(Proxy::IsMainThread());
155 DCHECK(layer_tree_host_
->output_surface_lost());
156 DCHECK(output_surface_creation_requested_
);
157 renderer_capabilities_for_main_thread_
= RendererCapabilities();
161 DebugScopedSetMainThreadBlocked
main_thread_blocked(this);
162 DebugScopedSetImplThread
impl(this);
163 success
= layer_tree_host_impl_
->InitializeRenderer(output_surface
.Pass());
167 layer_tree_host_
->DidInitializeOutputSurface();
168 if (scheduler_on_impl_thread_
)
169 scheduler_on_impl_thread_
->DidCreateAndInitializeOutputSurface();
170 else if (!inside_synchronous_composite_
)
172 output_surface_creation_requested_
= false;
174 // DidFailToInitializeOutputSurface is treated as a RequestNewOutputSurface,
175 // and so output_surface_creation_requested remains true.
176 layer_tree_host_
->DidFailToInitializeOutputSurface();
180 const RendererCapabilities
& SingleThreadProxy::GetRendererCapabilities() const {
181 DCHECK(Proxy::IsMainThread());
182 DCHECK(!layer_tree_host_
->output_surface_lost());
183 return renderer_capabilities_for_main_thread_
;
186 void SingleThreadProxy::SetNeedsAnimate() {
187 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsAnimate");
188 DCHECK(Proxy::IsMainThread());
189 client_
->ScheduleAnimation();
190 if (animate_requested_
)
192 animate_requested_
= true;
193 DebugScopedSetImplThread
impl(this);
194 if (scheduler_on_impl_thread_
)
195 scheduler_on_impl_thread_
->SetNeedsBeginMainFrame();
198 void SingleThreadProxy::SetNeedsUpdateLayers() {
199 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsUpdateLayers");
200 DCHECK(Proxy::IsMainThread());
204 void SingleThreadProxy::DoCommit() {
205 TRACE_EVENT0("cc", "SingleThreadProxy::DoCommit");
206 DCHECK(Proxy::IsMainThread());
208 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509 is
210 tracked_objects::ScopedTracker
tracking_profile1(
211 FROM_HERE_WITH_EXPLICIT_FUNCTION("461509 SingleThreadProxy::DoCommit1"));
212 layer_tree_host_
->WillCommit();
213 devtools_instrumentation::ScopedCommitTrace
commit_task(
214 layer_tree_host_
->id());
216 // Commit immediately.
218 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
220 tracked_objects::ScopedTracker
tracking_profile2(
221 FROM_HERE_WITH_EXPLICIT_FUNCTION(
222 "461509 SingleThreadProxy::DoCommit2"));
223 DebugScopedSetMainThreadBlocked
main_thread_blocked(this);
224 DebugScopedSetImplThread
impl(this);
226 // This CapturePostTasks should be destroyed before CommitComplete() is
227 // called since that goes out to the embedder, and we want the embedder
228 // to receive its callbacks before that.
229 commit_blocking_task_runner_
.reset(new BlockingTaskRunner::CapturePostTasks(
230 blocking_main_thread_task_runner()));
232 layer_tree_host_impl_
->BeginCommit();
234 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
236 tracked_objects::ScopedTracker
tracking_profile6(
237 FROM_HERE_WITH_EXPLICIT_FUNCTION(
238 "461509 SingleThreadProxy::DoCommit6"));
239 if (layer_tree_host_impl_
->EvictedUIResourcesExist())
240 layer_tree_host_
->RecreateUIResources();
242 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
244 tracked_objects::ScopedTracker
tracking_profile7(
245 FROM_HERE_WITH_EXPLICIT_FUNCTION(
246 "461509 SingleThreadProxy::DoCommit7"));
247 layer_tree_host_
->FinishCommitOnImplThread(layer_tree_host_impl_
.get());
250 // In the single-threaded case, the scale and scroll deltas should never be
251 // touched on the impl layer tree.
252 scoped_ptr
<ScrollAndScaleSet
> scroll_info
=
253 layer_tree_host_impl_
->ProcessScrollDeltas();
254 DCHECK(!scroll_info
->scrolls
.size());
255 DCHECK_EQ(1.f
, scroll_info
->page_scale_delta
);
258 if (scheduler_on_impl_thread_
)
259 scheduler_on_impl_thread_
->DidCommit();
261 layer_tree_host_impl_
->CommitComplete();
263 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
265 tracked_objects::ScopedTracker
tracking_profile8(
266 FROM_HERE_WITH_EXPLICIT_FUNCTION(
267 "461509 SingleThreadProxy::DoCommit8"));
268 // Commit goes directly to the active tree, but we need to synchronously
269 // "activate" the tree still during commit to satisfy any potential
270 // SetNextCommitWaitsForActivation calls. Unfortunately, the tree
271 // might not be ready to draw, so DidActivateSyncTree must set
272 // the flag to force the tree to not draw until textures are ready.
273 NotifyReadyToActivate();
277 void SingleThreadProxy::CommitComplete() {
278 // Commit complete happens on the main side after activate to satisfy any
279 // SetNextCommitWaitsForActivation calls.
280 DCHECK(!layer_tree_host_impl_
->pending_tree())
281 << "Activation is expected to have synchronously occurred by now.";
282 DCHECK(commit_blocking_task_runner_
);
284 DebugScopedSetMainThread
main(this);
285 commit_blocking_task_runner_
.reset();
286 layer_tree_host_
->CommitComplete();
287 layer_tree_host_
->DidBeginMainFrame();
289 next_frame_is_newly_committed_frame_
= true;
292 void SingleThreadProxy::SetNeedsCommit() {
293 DCHECK(Proxy::IsMainThread());
294 client_
->ScheduleComposite();
295 if (commit_requested_
)
297 commit_requested_
= true;
298 DebugScopedSetImplThread
impl(this);
299 if (scheduler_on_impl_thread_
)
300 scheduler_on_impl_thread_
->SetNeedsBeginMainFrame();
303 void SingleThreadProxy::SetNeedsRedraw(const gfx::Rect
& damage_rect
) {
304 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsRedraw");
305 DCHECK(Proxy::IsMainThread());
306 DebugScopedSetImplThread
impl(this);
307 client_
->ScheduleComposite();
308 SetNeedsRedrawRectOnImplThread(damage_rect
);
311 void SingleThreadProxy::SetNextCommitWaitsForActivation() {
312 // Activation always forced in commit, so nothing to do.
313 DCHECK(Proxy::IsMainThread());
316 void SingleThreadProxy::SetDeferCommits(bool defer_commits
) {
317 DCHECK(Proxy::IsMainThread());
318 // Deferring commits only makes sense if there's a scheduler.
319 if (!scheduler_on_impl_thread_
)
321 if (defer_commits_
== defer_commits
)
325 TRACE_EVENT_ASYNC_BEGIN0("cc", "SingleThreadProxy::SetDeferCommits", this);
327 TRACE_EVENT_ASYNC_END0("cc", "SingleThreadProxy::SetDeferCommits", this);
329 defer_commits_
= defer_commits
;
330 scheduler_on_impl_thread_
->SetDeferCommits(defer_commits
);
333 bool SingleThreadProxy::CommitRequested() const {
334 DCHECK(Proxy::IsMainThread());
335 return commit_requested_
;
338 bool SingleThreadProxy::BeginMainFrameRequested() const {
339 DCHECK(Proxy::IsMainThread());
340 // If there is no scheduler, then there can be no pending begin frame,
341 // as all frames are all manually initiated by the embedder of cc.
342 if (!scheduler_on_impl_thread_
)
344 return commit_requested_
;
347 void SingleThreadProxy::Stop() {
348 TRACE_EVENT0("cc", "SingleThreadProxy::stop");
349 DCHECK(Proxy::IsMainThread());
351 DebugScopedSetMainThreadBlocked
main_thread_blocked(this);
352 DebugScopedSetImplThread
impl(this);
354 BlockingTaskRunner::CapturePostTasks
blocked(
355 blocking_main_thread_task_runner());
356 scheduler_on_impl_thread_
= nullptr;
357 layer_tree_host_impl_
= nullptr;
359 layer_tree_host_
= NULL
;
362 void SingleThreadProxy::OnCanDrawStateChanged(bool can_draw
) {
364 "cc", "SingleThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw
);
365 DCHECK(Proxy::IsImplThread());
366 if (scheduler_on_impl_thread_
)
367 scheduler_on_impl_thread_
->SetCanDraw(can_draw
);
370 void SingleThreadProxy::NotifyReadyToActivate() {
371 TRACE_EVENT0("cc", "SingleThreadProxy::NotifyReadyToActivate");
372 DebugScopedSetImplThread
impl(this);
373 if (scheduler_on_impl_thread_
)
374 scheduler_on_impl_thread_
->NotifyReadyToActivate();
377 void SingleThreadProxy::NotifyReadyToDraw() {
378 TRACE_EVENT0("cc", "SingleThreadProxy::NotifyReadyToDraw");
379 DebugScopedSetImplThread
impl(this);
380 if (scheduler_on_impl_thread_
)
381 scheduler_on_impl_thread_
->NotifyReadyToDraw();
384 void SingleThreadProxy::SetNeedsRedrawOnImplThread() {
385 client_
->ScheduleComposite();
386 if (scheduler_on_impl_thread_
)
387 scheduler_on_impl_thread_
->SetNeedsRedraw();
390 void SingleThreadProxy::SetNeedsAnimateOnImplThread() {
391 client_
->ScheduleComposite();
392 if (scheduler_on_impl_thread_
)
393 scheduler_on_impl_thread_
->SetNeedsAnimate();
396 void SingleThreadProxy::SetNeedsPrepareTilesOnImplThread() {
397 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsPrepareTilesOnImplThread");
398 if (scheduler_on_impl_thread_
)
399 scheduler_on_impl_thread_
->SetNeedsPrepareTiles();
402 void SingleThreadProxy::SetNeedsRedrawRectOnImplThread(
403 const gfx::Rect
& damage_rect
) {
404 layer_tree_host_impl_
->SetViewportDamage(damage_rect
);
405 SetNeedsRedrawOnImplThread();
408 void SingleThreadProxy::SetNeedsCommitOnImplThread() {
409 client_
->ScheduleComposite();
410 if (scheduler_on_impl_thread_
)
411 scheduler_on_impl_thread_
->SetNeedsBeginMainFrame();
414 void SingleThreadProxy::SetVideoNeedsBeginFrames(bool needs_begin_frames
) {
415 TRACE_EVENT1("cc", "SingleThreadProxy::SetVideoNeedsBeginFrames",
416 "needs_begin_frames", needs_begin_frames
);
417 // In tests the layer tree is destroyed after the scheduler is.
418 if (scheduler_on_impl_thread_
)
419 scheduler_on_impl_thread_
->SetVideoNeedsBeginFrames(needs_begin_frames
);
422 void SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread(
423 scoped_ptr
<AnimationEventsVector
> events
) {
425 "cc", "SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread");
426 DCHECK(Proxy::IsImplThread());
427 DebugScopedSetMainThread
main(this);
428 layer_tree_host_
->SetAnimationEvents(events
.Pass());
431 bool SingleThreadProxy::IsInsideDraw() { return inside_draw_
; }
433 void SingleThreadProxy::DidActivateSyncTree() {
434 // Synchronously call to CommitComplete. Resetting
435 // |commit_blocking_task_runner| would make sure all tasks posted during
436 // commit/activation before CommitComplete.
440 void SingleThreadProxy::WillPrepareTiles() {
441 DCHECK(Proxy::IsImplThread());
442 if (scheduler_on_impl_thread_
)
443 scheduler_on_impl_thread_
->WillPrepareTiles();
446 void SingleThreadProxy::DidPrepareTiles() {
447 DCHECK(Proxy::IsImplThread());
448 if (scheduler_on_impl_thread_
)
449 scheduler_on_impl_thread_
->DidPrepareTiles();
452 void SingleThreadProxy::DidCompletePageScaleAnimationOnImplThread() {
453 layer_tree_host_
->DidCompletePageScaleAnimation();
456 void SingleThreadProxy::UpdateRendererCapabilitiesOnImplThread() {
457 DCHECK(IsImplThread());
458 renderer_capabilities_for_main_thread_
=
459 layer_tree_host_impl_
->GetRendererCapabilities().MainThreadCapabilities();
462 void SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() {
463 TRACE_EVENT0("cc", "SingleThreadProxy::DidLoseOutputSurfaceOnImplThread");
465 DebugScopedSetMainThread
main(this);
466 // This must happen before we notify the scheduler as it may try to recreate
467 // the output surface if already in BEGIN_IMPL_FRAME_STATE_IDLE.
468 layer_tree_host_
->DidLoseOutputSurface();
470 client_
->DidAbortSwapBuffers();
471 if (scheduler_on_impl_thread_
)
472 scheduler_on_impl_thread_
->DidLoseOutputSurface();
475 void SingleThreadProxy::CommitVSyncParameters(base::TimeTicks timebase
,
476 base::TimeDelta interval
) {
477 if (scheduler_on_impl_thread_
)
478 scheduler_on_impl_thread_
->CommitVSyncParameters(timebase
, interval
);
481 void SingleThreadProxy::SetEstimatedParentDrawTime(base::TimeDelta draw_time
) {
482 if (scheduler_on_impl_thread_
)
483 scheduler_on_impl_thread_
->SetEstimatedParentDrawTime(draw_time
);
486 void SingleThreadProxy::SetMaxSwapsPendingOnImplThread(int max
) {
487 if (scheduler_on_impl_thread_
)
488 scheduler_on_impl_thread_
->SetMaxSwapsPending(max
);
491 void SingleThreadProxy::DidSwapBuffersOnImplThread() {
492 TRACE_EVENT0("cc", "SingleThreadProxy::DidSwapBuffersOnImplThread");
493 if (scheduler_on_impl_thread_
)
494 scheduler_on_impl_thread_
->DidSwapBuffers();
495 client_
->DidPostSwapBuffers();
498 void SingleThreadProxy::DidSwapBuffersCompleteOnImplThread() {
499 TRACE_EVENT0("cc,benchmark",
500 "SingleThreadProxy::DidSwapBuffersCompleteOnImplThread");
501 if (scheduler_on_impl_thread_
)
502 scheduler_on_impl_thread_
->DidSwapBuffersComplete();
503 layer_tree_host_
->DidCompleteSwapBuffers();
506 void SingleThreadProxy::OnDrawForOutputSurface() {
507 NOTREACHED() << "Implemented by ThreadProxy for synchronous compositor.";
510 void SingleThreadProxy::PostFrameTimingEventsOnImplThread(
511 scoped_ptr
<FrameTimingTracker::CompositeTimingSet
> composite_events
,
512 scoped_ptr
<FrameTimingTracker::MainFrameTimingSet
> main_frame_events
) {
513 layer_tree_host_
->RecordFrameTimingEvents(composite_events
.Pass(),
514 main_frame_events
.Pass());
517 void SingleThreadProxy::LayoutAndUpdateLayers() {
518 if (layer_tree_host_
->output_surface_lost()) {
519 RequestNewOutputSurface();
520 // RequestNewOutputSurface could have synchronously created an output
521 // surface, so check again before returning.
522 if (layer_tree_host_
->output_surface_lost())
526 layer_tree_host_
->Layout();
527 layer_tree_host_
->UpdateLayers();
530 void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time
) {
531 TRACE_EVENT0("cc,benchmark", "SingleThreadProxy::CompositeImmediately");
532 DCHECK(Proxy::IsMainThread());
534 DCHECK(!inside_impl_frame_
);
536 base::AutoReset
<bool> inside_composite(&inside_synchronous_composite_
, true);
538 if (layer_tree_host_
->output_surface_lost()) {
539 RequestNewOutputSurface();
540 // RequestNewOutputSurface could have synchronously created an output
541 // surface, so check again before returning.
542 if (layer_tree_host_
->output_surface_lost())
546 BeginFrameArgs
begin_frame_args(BeginFrameArgs::Create(
547 BEGINFRAME_FROM_HERE
, frame_begin_time
, base::TimeTicks(),
548 BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL
));
550 // Start the impl frame.
552 DebugScopedSetImplThread
impl(this);
553 WillBeginImplFrame(begin_frame_args
);
556 // Run the "main thread" and get it to commit.
559 DCHECK(inside_impl_frame_
);
561 DoBeginMainFrame(begin_frame_args
);
564 DCHECK_EQ(0u, layer_tree_host_
->num_queued_swap_promises())
565 << "Commit should always succeed and transfer promises.";
568 // Finish the impl frame.
570 DebugScopedSetImplThread
impl(this);
571 layer_tree_host_impl_
->ActivateSyncTree();
573 !layer_tree_host_impl_
->active_tree()->needs_update_draw_properties());
574 layer_tree_host_impl_
->PrepareTiles();
575 layer_tree_host_impl_
->SynchronouslyInitializeAllTiles();
577 // TODO(danakj): Don't do this last... we prepared the wrong things. D:
578 layer_tree_host_impl_
->Animate();
580 LayerTreeHostImpl::FrameData frame
;
583 // DoComposite could abort, but because this is a synchronous composite
584 // another draw will never be scheduled, so break remaining promises.
585 layer_tree_host_impl_
->active_tree()->BreakSwapPromises(
586 SwapPromise::SWAP_FAILS
);
588 DidFinishImplFrame();
592 void SingleThreadProxy::ForceSerializeOnSwapBuffers() {
594 DebugScopedSetImplThread
impl(this);
595 if (layer_tree_host_impl_
->renderer()) {
596 DCHECK(!layer_tree_host_
->output_surface_lost());
597 layer_tree_host_impl_
->renderer()->DoNoOp();
602 bool SingleThreadProxy::SupportsImplScrolling() const {
606 bool SingleThreadProxy::ShouldComposite() const {
607 DCHECK(Proxy::IsImplThread());
608 return layer_tree_host_impl_
->visible() &&
609 layer_tree_host_impl_
->CanDraw();
612 void SingleThreadProxy::ScheduleRequestNewOutputSurface() {
613 if (output_surface_creation_callback_
.IsCancelled() &&
614 !output_surface_creation_requested_
) {
615 output_surface_creation_callback_
.Reset(
616 base::Bind(&SingleThreadProxy::RequestNewOutputSurface
,
617 weak_factory_
.GetWeakPtr()));
618 MainThreadTaskRunner()->PostTask(
619 FROM_HERE
, output_surface_creation_callback_
.callback());
623 DrawResult
SingleThreadProxy::DoComposite(LayerTreeHostImpl::FrameData
* frame
) {
624 TRACE_EVENT0("cc", "SingleThreadProxy::DoComposite");
625 DCHECK(!layer_tree_host_
->output_surface_lost());
627 DrawResult draw_result
;
630 DebugScopedSetImplThread
impl(this);
631 base::AutoReset
<bool> mark_inside(&inside_draw_
, true);
633 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
635 tracked_objects::ScopedTracker
tracking_profile1(
636 FROM_HERE_WITH_EXPLICIT_FUNCTION(
637 "461509 SingleThreadProxy::DoComposite1"));
639 // We guard PrepareToDraw() with CanDraw() because it always returns a valid
640 // frame, so can only be used when such a frame is possible. Since
641 // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
642 // CanDraw() as well.
643 if (!ShouldComposite()) {
644 return DRAW_ABORTED_CANT_DRAW
;
647 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
649 tracked_objects::ScopedTracker
tracking_profile2(
650 FROM_HERE_WITH_EXPLICIT_FUNCTION(
651 "461509 SingleThreadProxy::DoComposite2"));
652 draw_result
= layer_tree_host_impl_
->PrepareToDraw(frame
);
653 draw_frame
= draw_result
== DRAW_SUCCESS
;
655 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
657 tracked_objects::ScopedTracker
tracking_profile3(
658 FROM_HERE_WITH_EXPLICIT_FUNCTION(
659 "461509 SingleThreadProxy::DoComposite3"));
660 layer_tree_host_impl_
->DrawLayers(frame
);
662 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
664 tracked_objects::ScopedTracker
tracking_profile4(
665 FROM_HERE_WITH_EXPLICIT_FUNCTION(
666 "461509 SingleThreadProxy::DoComposite4"));
667 layer_tree_host_impl_
->DidDrawAllLayers(*frame
);
669 bool start_ready_animations
= draw_frame
;
670 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
672 tracked_objects::ScopedTracker
tracking_profile5(
673 FROM_HERE_WITH_EXPLICIT_FUNCTION(
674 "461509 SingleThreadProxy::DoComposite5"));
675 layer_tree_host_impl_
->UpdateAnimationState(start_ready_animations
);
677 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
679 tracked_objects::ScopedTracker
tracking_profile7(
680 FROM_HERE_WITH_EXPLICIT_FUNCTION(
681 "461509 SingleThreadProxy::DoComposite7"));
685 DebugScopedSetImplThread
impl(this);
687 // This CapturePostTasks should be destroyed before
688 // DidCommitAndDrawFrame() is called since that goes out to the
690 // and we want the embedder to receive its callbacks before that.
691 // NOTE: This maintains consistent ordering with the ThreadProxy since
692 // the DidCommitAndDrawFrame() must be post-tasked from the impl thread
693 // there as the main thread is not blocked, so any posted tasks inside
694 // the swap buffers will execute first.
695 DebugScopedSetMainThreadBlocked
main_thread_blocked(this);
697 BlockingTaskRunner::CapturePostTasks
blocked(
698 blocking_main_thread_task_runner());
699 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
701 tracked_objects::ScopedTracker
tracking_profile8(
702 FROM_HERE_WITH_EXPLICIT_FUNCTION(
703 "461509 SingleThreadProxy::DoComposite8"));
704 layer_tree_host_impl_
->SwapBuffers(*frame
);
706 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509 is
708 tracked_objects::ScopedTracker
tracking_profile9(
709 FROM_HERE_WITH_EXPLICIT_FUNCTION(
710 "461509 SingleThreadProxy::DoComposite9"));
711 DidCommitAndDrawFrame();
716 void SingleThreadProxy::DidCommitAndDrawFrame() {
717 if (next_frame_is_newly_committed_frame_
) {
718 DebugScopedSetMainThread
main(this);
719 next_frame_is_newly_committed_frame_
= false;
720 layer_tree_host_
->DidCommitAndDrawFrame();
724 bool SingleThreadProxy::MainFrameWillHappenForTesting() {
725 if (layer_tree_host_
->output_surface_lost())
727 if (!scheduler_on_impl_thread_
)
729 return scheduler_on_impl_thread_
->MainFrameForTestingWillHappen();
732 void SingleThreadProxy::SetChildrenNeedBeginFrames(
733 bool children_need_begin_frames
) {
734 scheduler_on_impl_thread_
->SetChildrenNeedBeginFrames(
735 children_need_begin_frames
);
738 void SingleThreadProxy::SetAuthoritativeVSyncInterval(
739 const base::TimeDelta
& interval
) {
740 scheduler_on_impl_thread_
->SetAuthoritativeVSyncInterval(interval
);
743 void SingleThreadProxy::WillBeginImplFrame(const BeginFrameArgs
& args
) {
745 DCHECK(!inside_impl_frame_
)
746 << "WillBeginImplFrame called while already inside an impl frame!";
747 inside_impl_frame_
= true;
749 layer_tree_host_impl_
->WillBeginImplFrame(args
);
752 void SingleThreadProxy::ScheduledActionSendBeginMainFrame() {
753 TRACE_EVENT0("cc", "SingleThreadProxy::ScheduledActionSendBeginMainFrame");
754 // Although this proxy is single-threaded, it's problematic to synchronously
755 // have BeginMainFrame happen after ScheduledActionSendBeginMainFrame. This
756 // could cause a commit to occur in between a series of SetNeedsCommit calls
757 // (i.e. property modifications) causing some to fall on one frame and some to
758 // fall on the next. Doing it asynchronously instead matches the semantics of
759 // ThreadProxy::SetNeedsCommit where SetNeedsCommit will not cause a
760 // synchronous commit.
762 DCHECK(inside_impl_frame_
)
763 << "BeginMainFrame should only be sent inside a BeginImplFrame";
765 const BeginFrameArgs
& begin_frame_args
=
766 layer_tree_host_impl_
->CurrentBeginFrameArgs();
768 MainThreadTaskRunner()->PostTask(
769 FROM_HERE
, base::Bind(&SingleThreadProxy::BeginMainFrame
,
770 weak_factory_
.GetWeakPtr(), begin_frame_args
));
773 void SingleThreadProxy::SendBeginMainFrameNotExpectedSoon() {
774 layer_tree_host_
->BeginMainFrameNotExpectedSoon();
777 void SingleThreadProxy::BeginMainFrame(const BeginFrameArgs
& begin_frame_args
) {
778 commit_requested_
= false;
779 animate_requested_
= false;
781 if (defer_commits_
) {
782 TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit",
783 TRACE_EVENT_SCOPE_THREAD
);
784 BeginMainFrameAbortedOnImplThread(
785 CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT
);
789 // This checker assumes NotifyReadyToCommit in this stack causes a synchronous
791 ScopedAbortRemainingSwapPromises
swap_promise_checker(layer_tree_host_
);
793 if (!layer_tree_host_
->visible()) {
794 TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD
);
795 BeginMainFrameAbortedOnImplThread(
796 CommitEarlyOutReason::ABORTED_NOT_VISIBLE
);
800 if (layer_tree_host_
->output_surface_lost()) {
801 TRACE_EVENT_INSTANT0(
802 "cc", "EarlyOut_OutputSurfaceLost", TRACE_EVENT_SCOPE_THREAD
);
803 BeginMainFrameAbortedOnImplThread(
804 CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST
);
808 // Prevent new commits from being requested inside DoBeginMainFrame.
809 // Note: We do not want to prevent SetNeedsAnimate from requesting
811 commit_requested_
= true;
813 DoBeginMainFrame(begin_frame_args
);
816 void SingleThreadProxy::DoBeginMainFrame(
817 const BeginFrameArgs
& begin_frame_args
) {
818 layer_tree_host_
->WillBeginMainFrame();
819 layer_tree_host_
->BeginMainFrame(begin_frame_args
);
820 layer_tree_host_
->AnimateLayers(begin_frame_args
.frame_time
);
821 layer_tree_host_
->Layout();
823 // New commits requested inside UpdateLayers should be respected.
824 commit_requested_
= false;
826 layer_tree_host_
->UpdateLayers();
828 // TODO(enne): SingleThreadProxy does not support cancelling commits yet,
829 // search for CommitEarlyOutReason::FINISHED_NO_UPDATES inside
831 if (scheduler_on_impl_thread_
) {
832 scheduler_on_impl_thread_
->NotifyBeginMainFrameStarted();
833 scheduler_on_impl_thread_
->NotifyReadyToCommit();
837 void SingleThreadProxy::BeginMainFrameAbortedOnImplThread(
838 CommitEarlyOutReason reason
) {
839 DebugScopedSetImplThread
impl(this);
840 DCHECK(scheduler_on_impl_thread_
->CommitPending());
841 DCHECK(!layer_tree_host_impl_
->pending_tree());
843 layer_tree_host_impl_
->BeginMainFrameAborted(reason
);
844 scheduler_on_impl_thread_
->BeginMainFrameAborted(reason
);
847 DrawResult
SingleThreadProxy::ScheduledActionDrawAndSwapIfPossible() {
848 DebugScopedSetImplThread
impl(this);
849 LayerTreeHostImpl::FrameData frame
;
850 return DoComposite(&frame
);
853 DrawResult
SingleThreadProxy::ScheduledActionDrawAndSwapForced() {
855 return INVALID_RESULT
;
858 void SingleThreadProxy::ScheduledActionCommit() {
859 DebugScopedSetMainThread
main(this);
863 void SingleThreadProxy::ScheduledActionAnimate() {
864 TRACE_EVENT0("cc", "ScheduledActionAnimate");
865 DebugScopedSetImplThread
impl(this);
866 layer_tree_host_impl_
->Animate();
869 void SingleThreadProxy::ScheduledActionActivateSyncTree() {
870 DebugScopedSetImplThread
impl(this);
871 layer_tree_host_impl_
->ActivateSyncTree();
874 void SingleThreadProxy::ScheduledActionBeginOutputSurfaceCreation() {
875 DebugScopedSetMainThread
main(this);
876 DCHECK(scheduler_on_impl_thread_
);
877 // If possible, create the output surface in a post task. Synchronously
878 // creating the output surface makes tests more awkward since this differs
879 // from the ThreadProxy behavior. However, sometimes there is no
881 if (Proxy::MainThreadTaskRunner()) {
882 ScheduleRequestNewOutputSurface();
884 RequestNewOutputSurface();
888 void SingleThreadProxy::ScheduledActionPrepareTiles() {
889 TRACE_EVENT0("cc", "SingleThreadProxy::ScheduledActionPrepareTiles");
890 DebugScopedSetImplThread
impl(this);
891 layer_tree_host_impl_
->PrepareTiles();
894 void SingleThreadProxy::ScheduledActionInvalidateOutputSurface() {
898 void SingleThreadProxy::DidFinishImplFrame() {
899 layer_tree_host_impl_
->DidFinishImplFrame();
901 DCHECK(inside_impl_frame_
)
902 << "DidFinishImplFrame called while not inside an impl frame!";
903 inside_impl_frame_
= false;
907 void SingleThreadProxy::SendBeginFramesToChildren(const BeginFrameArgs
& args
) {
908 layer_tree_host_
->SendBeginFramesToChildren(args
);