Add ICU message format support
[chromium-blink-merge.git] / cc / trees / single_thread_proxy.cc
blobbf03378246811e78226c911a557a513f4843223d
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"
23 namespace cc {
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(
31 layer_tree_host,
32 client,
33 main_task_runner,
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),
44 client_(client),
45 external_begin_frame_source_(external_begin_frame_source.Pass()),
46 next_frame_is_newly_committed_frame_(false),
47 #if DCHECK_IS_ON()
48 inside_impl_frame_(false),
49 #endif
50 inside_draw_(false),
51 defer_commits_(false),
52 animate_requested_(false),
53 commit_requested_(false),
54 inside_synchronous_composite_(false),
55 output_surface_creation_requested_(false),
56 weak_factory_(this) {
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
107 // active tree.
108 return true;
111 void SingleThreadProxy::SetLayerTreeHostClientReady() {
112 TRACE_EVENT0("cc", "SingleThreadProxy::SetLayerTreeHostClientReady");
113 // Scheduling is controlled by the embedder in the single thread case, so
114 // nothing to do.
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_)
147 return;
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();
159 bool success;
161 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
162 DebugScopedSetImplThread impl(this);
163 success = layer_tree_host_impl_->InitializeRenderer(output_surface.Pass());
166 if (success) {
167 layer_tree_host_->DidInitializeOutputSurface();
168 if (scheduler_on_impl_thread_)
169 scheduler_on_impl_thread_->DidCreateAndInitializeOutputSurface();
170 else if (!inside_synchronous_composite_)
171 SetNeedsCommit();
172 output_surface_creation_requested_ = false;
173 } else {
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_)
191 return;
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());
201 SetNeedsCommit();
204 void SingleThreadProxy::DoAnimate() {
205 // Don't animate if there is no root layer.
206 // TODO(mithro): Both Animate and UpdateAnimationState already have a
207 // "!active_tree_->root_layer()" check?
208 if (!layer_tree_host_impl_->active_tree()->root_layer()) {
209 return;
212 layer_tree_host_impl_->Animate(
213 layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time);
215 // If animations are not visible, update the animation state now as it
216 // won't happen in DoComposite.
217 if (!layer_tree_host_impl_->AnimationsAreVisible()) {
218 layer_tree_host_impl_->UpdateAnimationState(true);
222 void SingleThreadProxy::DoCommit() {
223 TRACE_EVENT0("cc", "SingleThreadProxy::DoCommit");
224 DCHECK(Proxy::IsMainThread());
226 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509 is
227 // fixed.
228 tracked_objects::ScopedTracker tracking_profile1(
229 FROM_HERE_WITH_EXPLICIT_FUNCTION("461509 SingleThreadProxy::DoCommit1"));
230 layer_tree_host_->WillCommit();
231 devtools_instrumentation::ScopedCommitTrace commit_task(
232 layer_tree_host_->id());
234 // Commit immediately.
236 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
237 // is fixed.
238 tracked_objects::ScopedTracker tracking_profile2(
239 FROM_HERE_WITH_EXPLICIT_FUNCTION(
240 "461509 SingleThreadProxy::DoCommit2"));
241 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
242 DebugScopedSetImplThread impl(this);
244 // This CapturePostTasks should be destroyed before CommitComplete() is
245 // called since that goes out to the embedder, and we want the embedder
246 // to receive its callbacks before that.
247 commit_blocking_task_runner_.reset(new BlockingTaskRunner::CapturePostTasks(
248 blocking_main_thread_task_runner()));
250 layer_tree_host_impl_->BeginCommit();
251 layer_tree_host_->BeginCommitOnImplThread(layer_tree_host_impl_.get());
253 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
254 // is fixed.
255 tracked_objects::ScopedTracker tracking_profile6(
256 FROM_HERE_WITH_EXPLICIT_FUNCTION(
257 "461509 SingleThreadProxy::DoCommit6"));
258 if (layer_tree_host_impl_->EvictedUIResourcesExist())
259 layer_tree_host_->RecreateUIResources();
261 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
262 // is fixed.
263 tracked_objects::ScopedTracker tracking_profile7(
264 FROM_HERE_WITH_EXPLICIT_FUNCTION(
265 "461509 SingleThreadProxy::DoCommit7"));
266 layer_tree_host_->FinishCommitOnImplThread(layer_tree_host_impl_.get());
268 #if DCHECK_IS_ON()
269 // In the single-threaded case, the scale and scroll deltas should never be
270 // touched on the impl layer tree.
271 scoped_ptr<ScrollAndScaleSet> scroll_info =
272 layer_tree_host_impl_->ProcessScrollDeltas();
273 DCHECK(!scroll_info->scrolls.size());
274 DCHECK_EQ(1.f, scroll_info->page_scale_delta);
275 #endif
277 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
278 // is fixed.
279 tracked_objects::ScopedTracker tracking_profile8(
280 FROM_HERE_WITH_EXPLICIT_FUNCTION(
281 "461509 SingleThreadProxy::DoCommit8"));
282 // Commit goes directly to the active tree, but we need to synchronously
283 // "activate" the tree still during commit to satisfy any potential
284 // SetNextCommitWaitsForActivation calls. Unfortunately, the tree
285 // might not be ready to draw, so DidActivateSyncTree must set
286 // the flag to force the tree to not draw until textures are ready.
287 NotifyReadyToActivate();
291 void SingleThreadProxy::CommitComplete() {
292 DCHECK(!layer_tree_host_impl_->pending_tree())
293 << "Activation is expected to have synchronously occurred by now.";
294 DCHECK(commit_blocking_task_runner_);
296 if (scheduler_on_impl_thread_)
297 scheduler_on_impl_thread_->DidCommit();
299 // Notify commit complete on the impl side after activate to satisfy any
300 // SetNextCommitWaitsForActivation calls.
301 layer_tree_host_impl_->CommitComplete();
303 DebugScopedSetMainThread main(this);
304 commit_blocking_task_runner_.reset();
305 layer_tree_host_->CommitComplete();
306 layer_tree_host_->DidBeginMainFrame();
308 next_frame_is_newly_committed_frame_ = true;
311 void SingleThreadProxy::SetNeedsCommit() {
312 DCHECK(Proxy::IsMainThread());
313 client_->ScheduleComposite();
314 if (commit_requested_)
315 return;
316 commit_requested_ = true;
317 DebugScopedSetImplThread impl(this);
318 if (scheduler_on_impl_thread_)
319 scheduler_on_impl_thread_->SetNeedsBeginMainFrame();
322 void SingleThreadProxy::SetNeedsRedraw(const gfx::Rect& damage_rect) {
323 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsRedraw");
324 DCHECK(Proxy::IsMainThread());
325 DebugScopedSetImplThread impl(this);
326 client_->ScheduleComposite();
327 SetNeedsRedrawRectOnImplThread(damage_rect);
330 void SingleThreadProxy::SetNextCommitWaitsForActivation() {
331 // Activation always forced in commit, so nothing to do.
332 DCHECK(Proxy::IsMainThread());
335 void SingleThreadProxy::SetDeferCommits(bool defer_commits) {
336 DCHECK(Proxy::IsMainThread());
337 // Deferring commits only makes sense if there's a scheduler.
338 if (!scheduler_on_impl_thread_)
339 return;
340 if (defer_commits_ == defer_commits)
341 return;
343 if (defer_commits)
344 TRACE_EVENT_ASYNC_BEGIN0("cc", "SingleThreadProxy::SetDeferCommits", this);
345 else
346 TRACE_EVENT_ASYNC_END0("cc", "SingleThreadProxy::SetDeferCommits", this);
348 defer_commits_ = defer_commits;
349 scheduler_on_impl_thread_->SetDeferCommits(defer_commits);
352 bool SingleThreadProxy::CommitRequested() const {
353 DCHECK(Proxy::IsMainThread());
354 return commit_requested_;
357 bool SingleThreadProxy::BeginMainFrameRequested() const {
358 DCHECK(Proxy::IsMainThread());
359 // If there is no scheduler, then there can be no pending begin frame,
360 // as all frames are all manually initiated by the embedder of cc.
361 if (!scheduler_on_impl_thread_)
362 return false;
363 return commit_requested_;
366 void SingleThreadProxy::Stop() {
367 TRACE_EVENT0("cc", "SingleThreadProxy::stop");
368 DCHECK(Proxy::IsMainThread());
370 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
371 DebugScopedSetImplThread impl(this);
373 BlockingTaskRunner::CapturePostTasks blocked(
374 blocking_main_thread_task_runner());
375 scheduler_on_impl_thread_ = nullptr;
376 layer_tree_host_impl_ = nullptr;
378 layer_tree_host_ = NULL;
381 void SingleThreadProxy::OnCanDrawStateChanged(bool can_draw) {
382 TRACE_EVENT1(
383 "cc", "SingleThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw);
384 DCHECK(Proxy::IsImplThread());
385 if (scheduler_on_impl_thread_)
386 scheduler_on_impl_thread_->SetCanDraw(can_draw);
389 void SingleThreadProxy::NotifyReadyToActivate() {
390 TRACE_EVENT0("cc", "SingleThreadProxy::NotifyReadyToActivate");
391 DebugScopedSetImplThread impl(this);
392 if (scheduler_on_impl_thread_)
393 scheduler_on_impl_thread_->NotifyReadyToActivate();
396 void SingleThreadProxy::NotifyReadyToDraw() {
397 TRACE_EVENT0("cc", "SingleThreadProxy::NotifyReadyToDraw");
398 DebugScopedSetImplThread impl(this);
399 if (scheduler_on_impl_thread_)
400 scheduler_on_impl_thread_->NotifyReadyToDraw();
403 void SingleThreadProxy::SetNeedsRedrawOnImplThread() {
404 client_->ScheduleComposite();
405 if (scheduler_on_impl_thread_)
406 scheduler_on_impl_thread_->SetNeedsRedraw();
409 void SingleThreadProxy::SetNeedsAnimateOnImplThread() {
410 client_->ScheduleComposite();
411 if (scheduler_on_impl_thread_)
412 scheduler_on_impl_thread_->SetNeedsAnimate();
415 void SingleThreadProxy::SetNeedsPrepareTilesOnImplThread() {
416 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsPrepareTilesOnImplThread");
417 if (scheduler_on_impl_thread_)
418 scheduler_on_impl_thread_->SetNeedsPrepareTiles();
421 void SingleThreadProxy::SetNeedsRedrawRectOnImplThread(
422 const gfx::Rect& damage_rect) {
423 layer_tree_host_impl_->SetViewportDamage(damage_rect);
424 SetNeedsRedrawOnImplThread();
427 void SingleThreadProxy::SetNeedsCommitOnImplThread() {
428 client_->ScheduleComposite();
429 if (scheduler_on_impl_thread_)
430 scheduler_on_impl_thread_->SetNeedsBeginMainFrame();
433 void SingleThreadProxy::SetVideoNeedsBeginFrames(bool needs_begin_frames) {
434 TRACE_EVENT1("cc", "SingleThreadProxy::SetVideoNeedsBeginFrames",
435 "needs_begin_frames", needs_begin_frames);
436 // In tests the layer tree is destroyed after the scheduler is.
437 if (scheduler_on_impl_thread_)
438 scheduler_on_impl_thread_->SetVideoNeedsBeginFrames(needs_begin_frames);
441 void SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread(
442 scoped_ptr<AnimationEventsVector> events) {
443 TRACE_EVENT0(
444 "cc", "SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread");
445 DCHECK(Proxy::IsImplThread());
446 DebugScopedSetMainThread main(this);
447 layer_tree_host_->SetAnimationEvents(events.Pass());
450 bool SingleThreadProxy::IsInsideDraw() { return inside_draw_; }
452 void SingleThreadProxy::DidActivateSyncTree() {
453 // Synchronously call to CommitComplete. Resetting
454 // |commit_blocking_task_runner| would make sure all tasks posted during
455 // commit/activation before CommitComplete.
456 CommitComplete();
459 void SingleThreadProxy::WillPrepareTiles() {
460 DCHECK(Proxy::IsImplThread());
461 if (scheduler_on_impl_thread_)
462 scheduler_on_impl_thread_->WillPrepareTiles();
465 void SingleThreadProxy::DidPrepareTiles() {
466 DCHECK(Proxy::IsImplThread());
467 if (scheduler_on_impl_thread_)
468 scheduler_on_impl_thread_->DidPrepareTiles();
471 void SingleThreadProxy::DidCompletePageScaleAnimationOnImplThread() {
472 layer_tree_host_->DidCompletePageScaleAnimation();
475 void SingleThreadProxy::UpdateRendererCapabilitiesOnImplThread() {
476 DCHECK(IsImplThread());
477 renderer_capabilities_for_main_thread_ =
478 layer_tree_host_impl_->GetRendererCapabilities().MainThreadCapabilities();
481 void SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() {
482 TRACE_EVENT0("cc", "SingleThreadProxy::DidLoseOutputSurfaceOnImplThread");
484 DebugScopedSetMainThread main(this);
485 // This must happen before we notify the scheduler as it may try to recreate
486 // the output surface if already in BEGIN_IMPL_FRAME_STATE_IDLE.
487 layer_tree_host_->DidLoseOutputSurface();
489 client_->DidAbortSwapBuffers();
490 if (scheduler_on_impl_thread_)
491 scheduler_on_impl_thread_->DidLoseOutputSurface();
494 void SingleThreadProxy::CommitVSyncParameters(base::TimeTicks timebase,
495 base::TimeDelta interval) {
496 if (scheduler_on_impl_thread_)
497 scheduler_on_impl_thread_->CommitVSyncParameters(timebase, interval);
500 void SingleThreadProxy::SetEstimatedParentDrawTime(base::TimeDelta draw_time) {
501 if (scheduler_on_impl_thread_)
502 scheduler_on_impl_thread_->SetEstimatedParentDrawTime(draw_time);
505 void SingleThreadProxy::SetMaxSwapsPendingOnImplThread(int max) {
506 if (scheduler_on_impl_thread_)
507 scheduler_on_impl_thread_->SetMaxSwapsPending(max);
510 void SingleThreadProxy::DidSwapBuffersOnImplThread() {
511 TRACE_EVENT0("cc", "SingleThreadProxy::DidSwapBuffersOnImplThread");
512 if (scheduler_on_impl_thread_)
513 scheduler_on_impl_thread_->DidSwapBuffers();
514 client_->DidPostSwapBuffers();
517 void SingleThreadProxy::DidSwapBuffersCompleteOnImplThread() {
518 TRACE_EVENT0("cc,benchmark",
519 "SingleThreadProxy::DidSwapBuffersCompleteOnImplThread");
520 if (scheduler_on_impl_thread_)
521 scheduler_on_impl_thread_->DidSwapBuffersComplete();
522 layer_tree_host_->DidCompleteSwapBuffers();
525 void SingleThreadProxy::OnDrawForOutputSurface() {
526 NOTREACHED() << "Implemented by ThreadProxy for synchronous compositor.";
529 void SingleThreadProxy::PostFrameTimingEventsOnImplThread(
530 scoped_ptr<FrameTimingTracker::CompositeTimingSet> composite_events,
531 scoped_ptr<FrameTimingTracker::MainFrameTimingSet> main_frame_events) {
532 layer_tree_host_->RecordFrameTimingEvents(composite_events.Pass(),
533 main_frame_events.Pass());
536 void SingleThreadProxy::LayoutAndUpdateLayers() {
537 if (layer_tree_host_->output_surface_lost()) {
538 RequestNewOutputSurface();
539 // RequestNewOutputSurface could have synchronously created an output
540 // surface, so check again before returning.
541 if (layer_tree_host_->output_surface_lost())
542 return;
545 layer_tree_host_->Layout();
546 layer_tree_host_->UpdateLayers();
549 void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) {
550 TRACE_EVENT0("cc,benchmark", "SingleThreadProxy::CompositeImmediately");
551 DCHECK(Proxy::IsMainThread());
552 #if DCHECK_IS_ON()
553 DCHECK(!inside_impl_frame_);
554 #endif
555 base::AutoReset<bool> inside_composite(&inside_synchronous_composite_, true);
557 if (layer_tree_host_->output_surface_lost()) {
558 RequestNewOutputSurface();
559 // RequestNewOutputSurface could have synchronously created an output
560 // surface, so check again before returning.
561 if (layer_tree_host_->output_surface_lost())
562 return;
565 BeginFrameArgs begin_frame_args(BeginFrameArgs::Create(
566 BEGINFRAME_FROM_HERE, frame_begin_time, base::TimeTicks(),
567 BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL));
569 // Start the impl frame.
571 DebugScopedSetImplThread impl(this);
572 WillBeginImplFrame(begin_frame_args);
575 // Run the "main thread" and get it to commit.
577 #if DCHECK_IS_ON()
578 DCHECK(inside_impl_frame_);
579 #endif
580 DoBeginMainFrame(begin_frame_args);
581 DoCommit();
583 DCHECK_EQ(0u, layer_tree_host_->num_queued_swap_promises())
584 << "Commit should always succeed and transfer promises.";
587 // Finish the impl frame.
589 DebugScopedSetImplThread impl(this);
590 layer_tree_host_impl_->ActivateSyncTree();
591 DCHECK(
592 !layer_tree_host_impl_->active_tree()->needs_update_draw_properties());
593 layer_tree_host_impl_->PrepareTiles();
594 layer_tree_host_impl_->SynchronouslyInitializeAllTiles();
596 DoAnimate();
598 LayerTreeHostImpl::FrameData frame;
599 DoComposite(&frame);
601 // DoComposite could abort, but because this is a synchronous composite
602 // another draw will never be scheduled, so break remaining promises.
603 layer_tree_host_impl_->active_tree()->BreakSwapPromises(
604 SwapPromise::SWAP_FAILS);
606 DidFinishImplFrame();
610 void SingleThreadProxy::ForceSerializeOnSwapBuffers() {
612 DebugScopedSetImplThread impl(this);
613 if (layer_tree_host_impl_->renderer()) {
614 DCHECK(!layer_tree_host_->output_surface_lost());
615 layer_tree_host_impl_->renderer()->DoNoOp();
620 bool SingleThreadProxy::SupportsImplScrolling() const {
621 return false;
624 bool SingleThreadProxy::ShouldComposite() const {
625 DCHECK(Proxy::IsImplThread());
626 return layer_tree_host_impl_->visible() &&
627 layer_tree_host_impl_->CanDraw();
630 void SingleThreadProxy::ScheduleRequestNewOutputSurface() {
631 if (output_surface_creation_callback_.IsCancelled() &&
632 !output_surface_creation_requested_) {
633 output_surface_creation_callback_.Reset(
634 base::Bind(&SingleThreadProxy::RequestNewOutputSurface,
635 weak_factory_.GetWeakPtr()));
636 MainThreadTaskRunner()->PostTask(
637 FROM_HERE, output_surface_creation_callback_.callback());
641 DrawResult SingleThreadProxy::DoComposite(LayerTreeHostImpl::FrameData* frame) {
642 TRACE_EVENT0("cc", "SingleThreadProxy::DoComposite");
643 DCHECK(!layer_tree_host_->output_surface_lost());
645 DrawResult draw_result;
646 bool draw_frame;
648 DebugScopedSetImplThread impl(this);
649 base::AutoReset<bool> mark_inside(&inside_draw_, true);
651 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
652 // is fixed.
653 tracked_objects::ScopedTracker tracking_profile1(
654 FROM_HERE_WITH_EXPLICIT_FUNCTION(
655 "461509 SingleThreadProxy::DoComposite1"));
657 // We guard PrepareToDraw() with CanDraw() because it always returns a valid
658 // frame, so can only be used when such a frame is possible. Since
659 // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
660 // CanDraw() as well.
661 if (!ShouldComposite()) {
662 return DRAW_ABORTED_CANT_DRAW;
665 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
666 // is fixed.
667 tracked_objects::ScopedTracker tracking_profile2(
668 FROM_HERE_WITH_EXPLICIT_FUNCTION(
669 "461509 SingleThreadProxy::DoComposite2"));
670 draw_result = layer_tree_host_impl_->PrepareToDraw(frame);
671 draw_frame = draw_result == DRAW_SUCCESS;
672 if (draw_frame) {
673 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
674 // is fixed.
675 tracked_objects::ScopedTracker tracking_profile3(
676 FROM_HERE_WITH_EXPLICIT_FUNCTION(
677 "461509 SingleThreadProxy::DoComposite3"));
678 layer_tree_host_impl_->DrawLayers(frame);
680 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
681 // is fixed.
682 tracked_objects::ScopedTracker tracking_profile4(
683 FROM_HERE_WITH_EXPLICIT_FUNCTION(
684 "461509 SingleThreadProxy::DoComposite4"));
685 layer_tree_host_impl_->DidDrawAllLayers(*frame);
687 bool start_ready_animations = draw_frame;
688 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
689 // is fixed.
690 tracked_objects::ScopedTracker tracking_profile5(
691 FROM_HERE_WITH_EXPLICIT_FUNCTION(
692 "461509 SingleThreadProxy::DoComposite5"));
693 layer_tree_host_impl_->UpdateAnimationState(start_ready_animations);
695 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
696 // is fixed.
697 tracked_objects::ScopedTracker tracking_profile7(
698 FROM_HERE_WITH_EXPLICIT_FUNCTION(
699 "461509 SingleThreadProxy::DoComposite7"));
702 if (draw_frame) {
703 DebugScopedSetImplThread impl(this);
705 // This CapturePostTasks should be destroyed before
706 // DidCommitAndDrawFrame() is called since that goes out to the
707 // embedder,
708 // and we want the embedder to receive its callbacks before that.
709 // NOTE: This maintains consistent ordering with the ThreadProxy since
710 // the DidCommitAndDrawFrame() must be post-tasked from the impl thread
711 // there as the main thread is not blocked, so any posted tasks inside
712 // the swap buffers will execute first.
713 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
715 BlockingTaskRunner::CapturePostTasks blocked(
716 blocking_main_thread_task_runner());
717 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
718 // is fixed.
719 tracked_objects::ScopedTracker tracking_profile8(
720 FROM_HERE_WITH_EXPLICIT_FUNCTION(
721 "461509 SingleThreadProxy::DoComposite8"));
722 layer_tree_host_impl_->SwapBuffers(*frame);
724 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509 is
725 // fixed.
726 tracked_objects::ScopedTracker tracking_profile9(
727 FROM_HERE_WITH_EXPLICIT_FUNCTION(
728 "461509 SingleThreadProxy::DoComposite9"));
729 DidCommitAndDrawFrame();
731 return draw_result;
734 void SingleThreadProxy::DidCommitAndDrawFrame() {
735 if (next_frame_is_newly_committed_frame_) {
736 DebugScopedSetMainThread main(this);
737 next_frame_is_newly_committed_frame_ = false;
738 layer_tree_host_->DidCommitAndDrawFrame();
742 bool SingleThreadProxy::MainFrameWillHappenForTesting() {
743 if (layer_tree_host_->output_surface_lost())
744 return false;
745 if (!scheduler_on_impl_thread_)
746 return false;
747 return scheduler_on_impl_thread_->MainFrameForTestingWillHappen();
750 void SingleThreadProxy::SetChildrenNeedBeginFrames(
751 bool children_need_begin_frames) {
752 scheduler_on_impl_thread_->SetChildrenNeedBeginFrames(
753 children_need_begin_frames);
756 void SingleThreadProxy::SetAuthoritativeVSyncInterval(
757 const base::TimeDelta& interval) {
758 scheduler_on_impl_thread_->SetAuthoritativeVSyncInterval(interval);
761 void SingleThreadProxy::WillBeginImplFrame(const BeginFrameArgs& args) {
762 #if DCHECK_IS_ON()
763 DCHECK(!inside_impl_frame_)
764 << "WillBeginImplFrame called while already inside an impl frame!";
765 inside_impl_frame_ = true;
766 #endif
767 layer_tree_host_impl_->WillBeginImplFrame(args);
770 void SingleThreadProxy::ScheduledActionSendBeginMainFrame() {
771 TRACE_EVENT0("cc", "SingleThreadProxy::ScheduledActionSendBeginMainFrame");
772 // Although this proxy is single-threaded, it's problematic to synchronously
773 // have BeginMainFrame happen after ScheduledActionSendBeginMainFrame. This
774 // could cause a commit to occur in between a series of SetNeedsCommit calls
775 // (i.e. property modifications) causing some to fall on one frame and some to
776 // fall on the next. Doing it asynchronously instead matches the semantics of
777 // ThreadProxy::SetNeedsCommit where SetNeedsCommit will not cause a
778 // synchronous commit.
779 #if DCHECK_IS_ON()
780 DCHECK(inside_impl_frame_)
781 << "BeginMainFrame should only be sent inside a BeginImplFrame";
782 #endif
783 const BeginFrameArgs& begin_frame_args =
784 layer_tree_host_impl_->CurrentBeginFrameArgs();
786 MainThreadTaskRunner()->PostTask(
787 FROM_HERE, base::Bind(&SingleThreadProxy::BeginMainFrame,
788 weak_factory_.GetWeakPtr(), begin_frame_args));
791 void SingleThreadProxy::SendBeginMainFrameNotExpectedSoon() {
792 layer_tree_host_->BeginMainFrameNotExpectedSoon();
795 void SingleThreadProxy::BeginMainFrame(const BeginFrameArgs& begin_frame_args) {
796 commit_requested_ = false;
797 animate_requested_ = false;
799 if (defer_commits_) {
800 TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit",
801 TRACE_EVENT_SCOPE_THREAD);
802 BeginMainFrameAbortedOnImplThread(
803 CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT);
804 return;
807 // This checker assumes NotifyReadyToCommit in this stack causes a synchronous
808 // commit.
809 ScopedAbortRemainingSwapPromises swap_promise_checker(layer_tree_host_);
811 if (!layer_tree_host_->visible()) {
812 TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD);
813 BeginMainFrameAbortedOnImplThread(
814 CommitEarlyOutReason::ABORTED_NOT_VISIBLE);
815 return;
818 if (layer_tree_host_->output_surface_lost()) {
819 TRACE_EVENT_INSTANT0(
820 "cc", "EarlyOut_OutputSurfaceLost", TRACE_EVENT_SCOPE_THREAD);
821 BeginMainFrameAbortedOnImplThread(
822 CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST);
823 return;
826 // Prevent new commits from being requested inside DoBeginMainFrame.
827 // Note: We do not want to prevent SetNeedsAnimate from requesting
828 // a commit here.
829 commit_requested_ = true;
831 DoBeginMainFrame(begin_frame_args);
834 void SingleThreadProxy::DoBeginMainFrame(
835 const BeginFrameArgs& begin_frame_args) {
836 layer_tree_host_->WillBeginMainFrame();
837 layer_tree_host_->BeginMainFrame(begin_frame_args);
838 layer_tree_host_->AnimateLayers(begin_frame_args.frame_time);
839 layer_tree_host_->Layout();
841 // New commits requested inside UpdateLayers should be respected.
842 commit_requested_ = false;
844 layer_tree_host_->UpdateLayers();
846 // TODO(enne): SingleThreadProxy does not support cancelling commits yet,
847 // search for CommitEarlyOutReason::FINISHED_NO_UPDATES inside
848 // thread_proxy.cc
849 if (scheduler_on_impl_thread_) {
850 scheduler_on_impl_thread_->NotifyBeginMainFrameStarted();
851 scheduler_on_impl_thread_->NotifyReadyToCommit();
855 void SingleThreadProxy::BeginMainFrameAbortedOnImplThread(
856 CommitEarlyOutReason reason) {
857 DebugScopedSetImplThread impl(this);
858 DCHECK(scheduler_on_impl_thread_->CommitPending());
859 DCHECK(!layer_tree_host_impl_->pending_tree());
861 layer_tree_host_impl_->BeginMainFrameAborted(reason);
862 scheduler_on_impl_thread_->BeginMainFrameAborted(reason);
865 DrawResult SingleThreadProxy::ScheduledActionDrawAndSwapIfPossible() {
866 DebugScopedSetImplThread impl(this);
867 LayerTreeHostImpl::FrameData frame;
868 return DoComposite(&frame);
871 DrawResult SingleThreadProxy::ScheduledActionDrawAndSwapForced() {
872 NOTREACHED();
873 return INVALID_RESULT;
876 void SingleThreadProxy::ScheduledActionCommit() {
877 DebugScopedSetMainThread main(this);
878 DoCommit();
881 void SingleThreadProxy::ScheduledActionAnimate() {
882 TRACE_EVENT0("cc", "ScheduledActionAnimate");
883 DebugScopedSetImplThread impl(this);
884 DoAnimate();
887 void SingleThreadProxy::ScheduledActionActivateSyncTree() {
888 DebugScopedSetImplThread impl(this);
889 layer_tree_host_impl_->ActivateSyncTree();
892 void SingleThreadProxy::ScheduledActionBeginOutputSurfaceCreation() {
893 DebugScopedSetMainThread main(this);
894 DCHECK(scheduler_on_impl_thread_);
895 // If possible, create the output surface in a post task. Synchronously
896 // creating the output surface makes tests more awkward since this differs
897 // from the ThreadProxy behavior. However, sometimes there is no
898 // task runner.
899 if (Proxy::MainThreadTaskRunner()) {
900 ScheduleRequestNewOutputSurface();
901 } else {
902 RequestNewOutputSurface();
906 void SingleThreadProxy::ScheduledActionPrepareTiles() {
907 TRACE_EVENT0("cc", "SingleThreadProxy::ScheduledActionPrepareTiles");
908 DebugScopedSetImplThread impl(this);
909 layer_tree_host_impl_->PrepareTiles();
912 void SingleThreadProxy::ScheduledActionInvalidateOutputSurface() {
913 NOTREACHED();
916 void SingleThreadProxy::DidFinishImplFrame() {
917 layer_tree_host_impl_->DidFinishImplFrame();
918 #if DCHECK_IS_ON()
919 DCHECK(inside_impl_frame_)
920 << "DidFinishImplFrame called while not inside an impl frame!";
921 inside_impl_frame_ = false;
922 #endif
925 void SingleThreadProxy::SendBeginFramesToChildren(const BeginFrameArgs& args) {
926 layer_tree_host_->SendBeginFramesToChildren(args);
929 } // namespace cc