cc: Adding DidFinishImplFrame to LTHI.
[chromium-blink-merge.git] / cc / trees / single_thread_proxy.cc
blob117af5d4b93001c375eaa21a476cd59d6795c44a
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/resources/prioritized_resource_manager.h"
16 #include "cc/resources/resource_update_controller.h"
17 #include "cc/scheduler/commit_earlyout_reason.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"
22 #include "ui/gfx/frame_time.h"
24 namespace cc {
26 scoped_ptr<Proxy> SingleThreadProxy::Create(
27 LayerTreeHost* layer_tree_host,
28 LayerTreeHostSingleThreadClient* client,
29 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
30 scoped_ptr<BeginFrameSource> external_begin_frame_source) {
31 return make_scoped_ptr(new SingleThreadProxy(
32 layer_tree_host,
33 client,
34 main_task_runner,
35 external_begin_frame_source.Pass()));
38 SingleThreadProxy::SingleThreadProxy(
39 LayerTreeHost* layer_tree_host,
40 LayerTreeHostSingleThreadClient* client,
41 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
42 scoped_ptr<BeginFrameSource> external_begin_frame_source)
43 : Proxy(main_task_runner, NULL),
44 layer_tree_host_(layer_tree_host),
45 client_(client),
46 timing_history_(layer_tree_host->rendering_stats_instrumentation()),
47 next_frame_is_newly_committed_frame_(false),
48 #if DCHECK_IS_ON()
49 inside_impl_frame_(false),
50 #endif
51 inside_draw_(false),
52 defer_commits_(false),
53 animate_requested_(false),
54 commit_requested_(false),
55 inside_synchronous_composite_(false),
56 output_surface_creation_requested_(false),
57 weak_factory_(this) {
58 TRACE_EVENT0("cc", "SingleThreadProxy::SingleThreadProxy");
59 DCHECK(Proxy::IsMainThread());
60 DCHECK(layer_tree_host);
62 if (layer_tree_host->settings().single_thread_proxy_scheduler &&
63 !scheduler_on_impl_thread_) {
64 SchedulerSettings scheduler_settings(
65 layer_tree_host->settings().ToSchedulerSettings());
66 // SingleThreadProxy should run in main thread low latency mode.
67 scheduler_settings.main_thread_should_always_be_low_latency = true;
68 scheduler_on_impl_thread_ = Scheduler::Create(
69 this, scheduler_settings, layer_tree_host_->id(),
70 MainThreadTaskRunner(), external_begin_frame_source.Pass());
74 void SingleThreadProxy::Start() {
75 DebugScopedSetImplThread impl(this);
76 layer_tree_host_impl_ = layer_tree_host_->CreateLayerTreeHostImpl(this);
79 SingleThreadProxy::~SingleThreadProxy() {
80 TRACE_EVENT0("cc", "SingleThreadProxy::~SingleThreadProxy");
81 DCHECK(Proxy::IsMainThread());
82 // Make sure Stop() got called or never Started.
83 DCHECK(!layer_tree_host_impl_);
86 void SingleThreadProxy::FinishAllRendering() {
87 TRACE_EVENT0("cc", "SingleThreadProxy::FinishAllRendering");
88 DCHECK(Proxy::IsMainThread());
90 DebugScopedSetImplThread impl(this);
91 layer_tree_host_impl_->FinishAllRendering();
95 bool SingleThreadProxy::IsStarted() const {
96 DCHECK(Proxy::IsMainThread());
97 return layer_tree_host_impl_;
100 bool SingleThreadProxy::CommitToActiveTree() const {
101 // With SingleThreadProxy we skip the pending tree and commit directly to the
102 // active tree.
103 return true;
106 void SingleThreadProxy::SetLayerTreeHostClientReady() {
107 TRACE_EVENT0("cc", "SingleThreadProxy::SetLayerTreeHostClientReady");
108 // Scheduling is controlled by the embedder in the single thread case, so
109 // nothing to do.
110 DCHECK(Proxy::IsMainThread());
111 DebugScopedSetImplThread impl(this);
112 if (scheduler_on_impl_thread_) {
113 scheduler_on_impl_thread_->SetCanStart();
114 scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible());
118 void SingleThreadProxy::SetVisible(bool visible) {
119 TRACE_EVENT1("cc", "SingleThreadProxy::SetVisible", "visible", visible);
120 DebugScopedSetImplThread impl(this);
121 layer_tree_host_impl_->SetVisible(visible);
122 if (scheduler_on_impl_thread_)
123 scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible());
124 // Changing visibility could change ShouldComposite().
127 void SingleThreadProxy::SetThrottleFrameProduction(bool throttle) {
128 TRACE_EVENT1("cc", "SingleThreadProxy::SetThrottleFrameProduction",
129 "throttle", throttle);
130 DebugScopedSetImplThread impl(this);
131 if (scheduler_on_impl_thread_)
132 scheduler_on_impl_thread_->SetThrottleFrameProduction(throttle);
135 void SingleThreadProxy::RequestNewOutputSurface() {
136 DCHECK(Proxy::IsMainThread());
137 DCHECK(layer_tree_host_->output_surface_lost());
138 output_surface_creation_callback_.Cancel();
139 if (output_surface_creation_requested_)
140 return;
141 output_surface_creation_requested_ = true;
142 layer_tree_host_->RequestNewOutputSurface();
145 void SingleThreadProxy::SetOutputSurface(
146 scoped_ptr<OutputSurface> output_surface) {
147 DCHECK(Proxy::IsMainThread());
148 DCHECK(layer_tree_host_->output_surface_lost());
149 DCHECK(output_surface_creation_requested_);
150 renderer_capabilities_for_main_thread_ = RendererCapabilities();
152 bool success;
154 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
155 DebugScopedSetImplThread impl(this);
156 layer_tree_host_->DeleteContentsTexturesOnImplThread(
157 layer_tree_host_impl_->resource_provider());
158 success = layer_tree_host_impl_->InitializeRenderer(output_surface.Pass());
161 if (success) {
162 layer_tree_host_->DidInitializeOutputSurface();
163 if (scheduler_on_impl_thread_)
164 scheduler_on_impl_thread_->DidCreateAndInitializeOutputSurface();
165 else if (!inside_synchronous_composite_)
166 SetNeedsCommit();
167 output_surface_creation_requested_ = false;
168 } else {
169 // DidFailToInitializeOutputSurface is treated as a RequestNewOutputSurface,
170 // and so output_surface_creation_requested remains true.
171 layer_tree_host_->DidFailToInitializeOutputSurface();
175 const RendererCapabilities& SingleThreadProxy::GetRendererCapabilities() const {
176 DCHECK(Proxy::IsMainThread());
177 DCHECK(!layer_tree_host_->output_surface_lost());
178 return renderer_capabilities_for_main_thread_;
181 void SingleThreadProxy::SetNeedsAnimate() {
182 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsAnimate");
183 DCHECK(Proxy::IsMainThread());
184 client_->ScheduleAnimation();
185 if (animate_requested_)
186 return;
187 animate_requested_ = true;
188 DebugScopedSetImplThread impl(this);
189 if (scheduler_on_impl_thread_)
190 scheduler_on_impl_thread_->SetNeedsCommit();
193 void SingleThreadProxy::SetNeedsUpdateLayers() {
194 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsUpdateLayers");
195 DCHECK(Proxy::IsMainThread());
196 SetNeedsCommit();
199 void SingleThreadProxy::DoAnimate() {
200 // Don't animate if there is no root layer.
201 // TODO(mithro): Both Animate and UpdateAnimationState already have a
202 // "!active_tree_->root_layer()" check?
203 if (!layer_tree_host_impl_->active_tree()->root_layer()) {
204 return;
207 layer_tree_host_impl_->Animate(
208 layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time);
210 // If animations are not visible, update the animation state now as it
211 // won't happen in DoComposite.
212 if (!layer_tree_host_impl_->AnimationsAreVisible()) {
213 layer_tree_host_impl_->UpdateAnimationState(true);
217 void SingleThreadProxy::DoCommit() {
218 TRACE_EVENT0("cc", "SingleThreadProxy::DoCommit");
219 DCHECK(Proxy::IsMainThread());
221 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509 is
222 // fixed.
223 tracked_objects::ScopedTracker tracking_profile1(
224 FROM_HERE_WITH_EXPLICIT_FUNCTION("461509 SingleThreadProxy::DoCommit1"));
225 layer_tree_host_->WillCommit();
226 devtools_instrumentation::ScopedCommitTrace commit_task(
227 layer_tree_host_->id());
229 // Commit immediately.
231 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
232 // is fixed.
233 tracked_objects::ScopedTracker tracking_profile2(
234 FROM_HERE_WITH_EXPLICIT_FUNCTION(
235 "461509 SingleThreadProxy::DoCommit2"));
236 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
237 DebugScopedSetImplThread impl(this);
239 // This CapturePostTasks should be destroyed before CommitComplete() is
240 // called since that goes out to the embedder, and we want the embedder
241 // to receive its callbacks before that.
242 commit_blocking_task_runner_.reset(new BlockingTaskRunner::CapturePostTasks(
243 blocking_main_thread_task_runner()));
245 layer_tree_host_impl_->BeginCommit();
247 if (PrioritizedResourceManager* contents_texture_manager =
248 layer_tree_host_->contents_texture_manager()) {
249 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
250 // is fixed.
251 tracked_objects::ScopedTracker tracking_profile3(
252 FROM_HERE_WITH_EXPLICIT_FUNCTION(
253 "461509 SingleThreadProxy::DoCommit3"));
254 contents_texture_manager->PushTexturePrioritiesToBackings();
256 layer_tree_host_->BeginCommitOnImplThread(layer_tree_host_impl_.get());
258 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
259 // is fixed.
260 tracked_objects::ScopedTracker tracking_profile4(
261 FROM_HERE_WITH_EXPLICIT_FUNCTION(
262 "461509 SingleThreadProxy::DoCommit4"));
263 scoped_ptr<ResourceUpdateController> update_controller =
264 ResourceUpdateController::Create(
265 NULL,
266 MainThreadTaskRunner(),
267 queue_for_commit_.Pass(),
268 layer_tree_host_impl_->resource_provider());
270 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
271 // is fixed.
272 tracked_objects::ScopedTracker tracking_profile5(
273 FROM_HERE_WITH_EXPLICIT_FUNCTION(
274 "461509 SingleThreadProxy::DoCommit5"));
275 update_controller->Finalize();
277 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
278 // is fixed.
279 tracked_objects::ScopedTracker tracking_profile6(
280 FROM_HERE_WITH_EXPLICIT_FUNCTION(
281 "461509 SingleThreadProxy::DoCommit6"));
282 if (layer_tree_host_impl_->EvictedUIResourcesExist())
283 layer_tree_host_->RecreateUIResources();
285 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
286 // is fixed.
287 tracked_objects::ScopedTracker tracking_profile7(
288 FROM_HERE_WITH_EXPLICIT_FUNCTION(
289 "461509 SingleThreadProxy::DoCommit7"));
290 layer_tree_host_->FinishCommitOnImplThread(layer_tree_host_impl_.get());
292 #if DCHECK_IS_ON()
293 // In the single-threaded case, the scale and scroll deltas should never be
294 // touched on the impl layer tree.
295 scoped_ptr<ScrollAndScaleSet> scroll_info =
296 layer_tree_host_impl_->ProcessScrollDeltas();
297 DCHECK(!scroll_info->scrolls.size());
298 DCHECK_EQ(1.f, scroll_info->page_scale_delta);
299 #endif
301 if (layer_tree_host_->settings().impl_side_painting) {
302 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
303 // is fixed.
304 tracked_objects::ScopedTracker tracking_profile8(
305 FROM_HERE_WITH_EXPLICIT_FUNCTION(
306 "461509 SingleThreadProxy::DoCommit8"));
307 // Commit goes directly to the active tree, but we need to synchronously
308 // "activate" the tree still during commit to satisfy any potential
309 // SetNextCommitWaitsForActivation calls. Unfortunately, the tree
310 // might not be ready to draw, so DidActivateSyncTree must set
311 // the flag to force the tree to not draw until textures are ready.
312 NotifyReadyToActivate();
313 } else {
314 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
315 // is fixed.
316 tracked_objects::ScopedTracker tracking_profile9(
317 FROM_HERE_WITH_EXPLICIT_FUNCTION(
318 "461509 SingleThreadProxy::DoCommit9"));
319 CommitComplete();
324 void SingleThreadProxy::CommitComplete() {
325 DCHECK(!layer_tree_host_impl_->pending_tree())
326 << "Activation is expected to have synchronously occurred by now.";
327 DCHECK(commit_blocking_task_runner_);
329 // Notify commit complete on the impl side after activate to satisfy any
330 // SetNextCommitWaitsForActivation calls.
331 layer_tree_host_impl_->CommitComplete();
333 DebugScopedSetMainThread main(this);
334 commit_blocking_task_runner_.reset();
335 layer_tree_host_->CommitComplete();
336 layer_tree_host_->DidBeginMainFrame();
337 timing_history_.DidCommit();
339 next_frame_is_newly_committed_frame_ = true;
342 void SingleThreadProxy::SetNeedsCommit() {
343 DCHECK(Proxy::IsMainThread());
344 client_->ScheduleComposite();
345 if (commit_requested_)
346 return;
347 commit_requested_ = true;
348 DebugScopedSetImplThread impl(this);
349 if (scheduler_on_impl_thread_)
350 scheduler_on_impl_thread_->SetNeedsCommit();
353 void SingleThreadProxy::SetNeedsRedraw(const gfx::Rect& damage_rect) {
354 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsRedraw");
355 DCHECK(Proxy::IsMainThread());
356 DebugScopedSetImplThread impl(this);
357 client_->ScheduleComposite();
358 SetNeedsRedrawRectOnImplThread(damage_rect);
361 void SingleThreadProxy::SetNextCommitWaitsForActivation() {
362 // Activation always forced in commit, so nothing to do.
363 DCHECK(Proxy::IsMainThread());
366 void SingleThreadProxy::SetDeferCommits(bool defer_commits) {
367 DCHECK(Proxy::IsMainThread());
368 // Deferring commits only makes sense if there's a scheduler.
369 if (!scheduler_on_impl_thread_)
370 return;
371 if (defer_commits_ == defer_commits)
372 return;
374 if (defer_commits)
375 TRACE_EVENT_ASYNC_BEGIN0("cc", "SingleThreadProxy::SetDeferCommits", this);
376 else
377 TRACE_EVENT_ASYNC_END0("cc", "SingleThreadProxy::SetDeferCommits", this);
379 defer_commits_ = defer_commits;
380 scheduler_on_impl_thread_->SetDeferCommits(defer_commits);
383 bool SingleThreadProxy::CommitRequested() const {
384 DCHECK(Proxy::IsMainThread());
385 return commit_requested_;
388 bool SingleThreadProxy::BeginMainFrameRequested() const {
389 DCHECK(Proxy::IsMainThread());
390 // If there is no scheduler, then there can be no pending begin frame,
391 // as all frames are all manually initiated by the embedder of cc.
392 if (!scheduler_on_impl_thread_)
393 return false;
394 return commit_requested_;
397 size_t SingleThreadProxy::MaxPartialTextureUpdates() const {
398 return std::numeric_limits<size_t>::max();
401 void SingleThreadProxy::Stop() {
402 TRACE_EVENT0("cc", "SingleThreadProxy::stop");
403 DCHECK(Proxy::IsMainThread());
405 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
406 DebugScopedSetImplThread impl(this);
408 BlockingTaskRunner::CapturePostTasks blocked(
409 blocking_main_thread_task_runner());
410 layer_tree_host_->DeleteContentsTexturesOnImplThread(
411 layer_tree_host_impl_->resource_provider());
412 scheduler_on_impl_thread_ = nullptr;
413 layer_tree_host_impl_ = nullptr;
415 layer_tree_host_ = NULL;
418 void SingleThreadProxy::OnCanDrawStateChanged(bool can_draw) {
419 TRACE_EVENT1(
420 "cc", "SingleThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw);
421 DCHECK(Proxy::IsImplThread());
422 if (scheduler_on_impl_thread_)
423 scheduler_on_impl_thread_->SetCanDraw(can_draw);
426 void SingleThreadProxy::NotifyReadyToActivate() {
427 TRACE_EVENT0("cc", "SingleThreadProxy::NotifyReadyToActivate");
428 DebugScopedSetImplThread impl(this);
429 if (scheduler_on_impl_thread_)
430 scheduler_on_impl_thread_->NotifyReadyToActivate();
433 void SingleThreadProxy::NotifyReadyToDraw() {
434 TRACE_EVENT0("cc", "SingleThreadProxy::NotifyReadyToDraw");
435 DebugScopedSetImplThread impl(this);
436 if (scheduler_on_impl_thread_)
437 scheduler_on_impl_thread_->NotifyReadyToDraw();
440 void SingleThreadProxy::SetNeedsRedrawOnImplThread() {
441 client_->ScheduleComposite();
442 if (scheduler_on_impl_thread_)
443 scheduler_on_impl_thread_->SetNeedsRedraw();
446 void SingleThreadProxy::SetNeedsAnimateOnImplThread() {
447 client_->ScheduleComposite();
448 if (scheduler_on_impl_thread_)
449 scheduler_on_impl_thread_->SetNeedsAnimate();
452 void SingleThreadProxy::SetNeedsPrepareTilesOnImplThread() {
453 TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsPrepareTilesOnImplThread");
454 if (scheduler_on_impl_thread_)
455 scheduler_on_impl_thread_->SetNeedsPrepareTiles();
458 void SingleThreadProxy::SetNeedsRedrawRectOnImplThread(
459 const gfx::Rect& damage_rect) {
460 layer_tree_host_impl_->SetViewportDamage(damage_rect);
461 SetNeedsRedrawOnImplThread();
464 void SingleThreadProxy::SetNeedsCommitOnImplThread() {
465 client_->ScheduleComposite();
466 if (scheduler_on_impl_thread_)
467 scheduler_on_impl_thread_->SetNeedsCommit();
470 void SingleThreadProxy::SetVideoNeedsBeginFrames(bool needs_begin_frames) {
471 TRACE_EVENT1("cc", "SingleThreadProxy::SetVideoNeedsBeginFrames",
472 "needs_begin_frames", needs_begin_frames);
473 // In tests the layer tree is destroyed after the scheduler is.
474 if (scheduler_on_impl_thread_)
475 scheduler_on_impl_thread_->SetVideoNeedsBeginFrames(needs_begin_frames);
478 void SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread(
479 scoped_ptr<AnimationEventsVector> events) {
480 TRACE_EVENT0(
481 "cc", "SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread");
482 DCHECK(Proxy::IsImplThread());
483 DebugScopedSetMainThread main(this);
484 layer_tree_host_->SetAnimationEvents(events.Pass());
487 bool SingleThreadProxy::ReduceContentsTextureMemoryOnImplThread(
488 size_t limit_bytes,
489 int priority_cutoff) {
490 DCHECK(IsImplThread());
491 PrioritizedResourceManager* contents_texture_manager =
492 layer_tree_host_->contents_texture_manager();
494 ResourceProvider* resource_provider =
495 layer_tree_host_impl_->resource_provider();
497 if (!contents_texture_manager || !resource_provider)
498 return false;
500 return contents_texture_manager->ReduceMemoryOnImplThread(
501 limit_bytes, priority_cutoff, resource_provider);
504 bool SingleThreadProxy::IsInsideDraw() { return inside_draw_; }
506 void SingleThreadProxy::DidActivateSyncTree() {
507 // Non-impl-side painting finishes commit in DoCommit. Impl-side painting
508 // defers until here to simulate SetNextCommitWaitsForActivation.
509 if (layer_tree_host_impl_->settings().impl_side_painting) {
510 // This is required because NotifyReadyToActivate gets called immediately
511 // after commit since single thread commits directly to the active tree.
512 if (scheduler_on_impl_thread_)
513 scheduler_on_impl_thread_->SetWaitForReadyToDraw();
515 // Synchronously call to CommitComplete. Resetting
516 // |commit_blocking_task_runner| would make sure all tasks posted during
517 // commit/activation before CommitComplete.
518 CommitComplete();
521 timing_history_.DidActivateSyncTree();
524 void SingleThreadProxy::DidPrepareTiles() {
525 DCHECK(layer_tree_host_impl_->settings().impl_side_painting);
526 DCHECK(Proxy::IsImplThread());
527 if (scheduler_on_impl_thread_)
528 scheduler_on_impl_thread_->DidPrepareTiles();
531 void SingleThreadProxy::DidCompletePageScaleAnimationOnImplThread() {
532 layer_tree_host_->DidCompletePageScaleAnimation();
535 void SingleThreadProxy::UpdateRendererCapabilitiesOnImplThread() {
536 DCHECK(IsImplThread());
537 renderer_capabilities_for_main_thread_ =
538 layer_tree_host_impl_->GetRendererCapabilities().MainThreadCapabilities();
541 void SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() {
542 TRACE_EVENT0("cc", "SingleThreadProxy::DidLoseOutputSurfaceOnImplThread");
544 DebugScopedSetMainThread main(this);
545 // This must happen before we notify the scheduler as it may try to recreate
546 // the output surface if already in BEGIN_IMPL_FRAME_STATE_IDLE.
547 layer_tree_host_->DidLoseOutputSurface();
549 client_->DidAbortSwapBuffers();
550 if (scheduler_on_impl_thread_)
551 scheduler_on_impl_thread_->DidLoseOutputSurface();
554 void SingleThreadProxy::CommitVSyncParameters(base::TimeTicks timebase,
555 base::TimeDelta interval) {
556 if (scheduler_on_impl_thread_)
557 scheduler_on_impl_thread_->CommitVSyncParameters(timebase, interval);
560 void SingleThreadProxy::SetEstimatedParentDrawTime(base::TimeDelta draw_time) {
561 if (scheduler_on_impl_thread_)
562 scheduler_on_impl_thread_->SetEstimatedParentDrawTime(draw_time);
565 void SingleThreadProxy::SetMaxSwapsPendingOnImplThread(int max) {
566 if (scheduler_on_impl_thread_)
567 scheduler_on_impl_thread_->SetMaxSwapsPending(max);
570 void SingleThreadProxy::DidSwapBuffersOnImplThread() {
571 TRACE_EVENT0("cc", "SingleThreadProxy::DidSwapBuffersOnImplThread");
572 if (scheduler_on_impl_thread_)
573 scheduler_on_impl_thread_->DidSwapBuffers();
574 client_->DidPostSwapBuffers();
577 void SingleThreadProxy::DidSwapBuffersCompleteOnImplThread() {
578 TRACE_EVENT0("cc,benchmark",
579 "SingleThreadProxy::DidSwapBuffersCompleteOnImplThread");
580 if (scheduler_on_impl_thread_)
581 scheduler_on_impl_thread_->DidSwapBuffersComplete();
582 layer_tree_host_->DidCompleteSwapBuffers();
585 void SingleThreadProxy::OnDrawForOutputSurface() {
586 NOTREACHED() << "Implemented by ThreadProxy for synchronous compositor.";
589 void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) {
590 TRACE_EVENT0("cc,benchmark", "SingleThreadProxy::CompositeImmediately");
591 DCHECK(Proxy::IsMainThread());
592 #if DCHECK_IS_ON()
593 DCHECK(!inside_impl_frame_);
594 #endif
595 base::AutoReset<bool> inside_composite(&inside_synchronous_composite_, true);
597 if (layer_tree_host_->output_surface_lost()) {
598 RequestNewOutputSurface();
599 // RequestNewOutputSurface could have synchronously created an output
600 // surface, so check again before returning.
601 if (layer_tree_host_->output_surface_lost())
602 return;
605 BeginFrameArgs begin_frame_args(BeginFrameArgs::Create(
606 BEGINFRAME_FROM_HERE, frame_begin_time, base::TimeTicks(),
607 BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL));
609 // Start the impl frame.
611 DebugScopedSetImplThread impl(this);
612 WillBeginImplFrame(begin_frame_args);
615 // Run the "main thread" and get it to commit.
617 #if DCHECK_IS_ON()
618 DCHECK(inside_impl_frame_);
619 #endif
620 DoBeginMainFrame(begin_frame_args);
621 DoCommit();
623 DCHECK_EQ(0u, layer_tree_host_->num_queued_swap_promises())
624 << "Commit should always succeed and transfer promises.";
627 // Finish the impl frame.
629 DebugScopedSetImplThread impl(this);
630 if (layer_tree_host_impl_->settings().impl_side_painting) {
631 layer_tree_host_impl_->ActivateSyncTree();
632 DCHECK(!layer_tree_host_impl_->active_tree()
633 ->needs_update_draw_properties());
634 layer_tree_host_impl_->PrepareTiles();
635 layer_tree_host_impl_->SynchronouslyInitializeAllTiles();
638 DoAnimate();
640 LayerTreeHostImpl::FrameData frame;
641 DoComposite(&frame);
643 // DoComposite could abort, but because this is a synchronous composite
644 // another draw will never be scheduled, so break remaining promises.
645 layer_tree_host_impl_->active_tree()->BreakSwapPromises(
646 SwapPromise::SWAP_FAILS);
648 DidFinishImplFrame();
652 void SingleThreadProxy::ForceSerializeOnSwapBuffers() {
654 DebugScopedSetImplThread impl(this);
655 if (layer_tree_host_impl_->renderer()) {
656 DCHECK(!layer_tree_host_->output_surface_lost());
657 layer_tree_host_impl_->renderer()->DoNoOp();
662 bool SingleThreadProxy::SupportsImplScrolling() const {
663 return false;
666 bool SingleThreadProxy::ShouldComposite() const {
667 DCHECK(Proxy::IsImplThread());
668 return layer_tree_host_impl_->visible() &&
669 layer_tree_host_impl_->CanDraw();
672 void SingleThreadProxy::ScheduleRequestNewOutputSurface() {
673 if (output_surface_creation_callback_.IsCancelled() &&
674 !output_surface_creation_requested_) {
675 output_surface_creation_callback_.Reset(
676 base::Bind(&SingleThreadProxy::RequestNewOutputSurface,
677 weak_factory_.GetWeakPtr()));
678 MainThreadTaskRunner()->PostTask(
679 FROM_HERE, output_surface_creation_callback_.callback());
683 DrawResult SingleThreadProxy::DoComposite(LayerTreeHostImpl::FrameData* frame) {
684 TRACE_EVENT0("cc", "SingleThreadProxy::DoComposite");
685 DCHECK(!layer_tree_host_->output_surface_lost());
687 DrawResult draw_result;
688 bool draw_frame;
690 DebugScopedSetImplThread impl(this);
691 base::AutoReset<bool> mark_inside(&inside_draw_, true);
693 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
694 // is fixed.
695 tracked_objects::ScopedTracker tracking_profile1(
696 FROM_HERE_WITH_EXPLICIT_FUNCTION(
697 "461509 SingleThreadProxy::DoComposite1"));
699 // We guard PrepareToDraw() with CanDraw() because it always returns a valid
700 // frame, so can only be used when such a frame is possible. Since
701 // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
702 // CanDraw() as well.
703 if (!ShouldComposite()) {
704 return DRAW_ABORTED_CANT_DRAW;
707 timing_history_.DidStartDrawing();
709 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
710 // is fixed.
711 tracked_objects::ScopedTracker tracking_profile2(
712 FROM_HERE_WITH_EXPLICIT_FUNCTION(
713 "461509 SingleThreadProxy::DoComposite2"));
714 draw_result = layer_tree_host_impl_->PrepareToDraw(frame);
715 draw_frame = draw_result == DRAW_SUCCESS;
716 if (draw_frame) {
717 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
718 // is fixed.
719 tracked_objects::ScopedTracker tracking_profile3(
720 FROM_HERE_WITH_EXPLICIT_FUNCTION(
721 "461509 SingleThreadProxy::DoComposite3"));
722 layer_tree_host_impl_->DrawLayers(frame);
724 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
725 // is fixed.
726 tracked_objects::ScopedTracker tracking_profile4(
727 FROM_HERE_WITH_EXPLICIT_FUNCTION(
728 "461509 SingleThreadProxy::DoComposite4"));
729 layer_tree_host_impl_->DidDrawAllLayers(*frame);
731 bool start_ready_animations = draw_frame;
732 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
733 // is fixed.
734 tracked_objects::ScopedTracker tracking_profile5(
735 FROM_HERE_WITH_EXPLICIT_FUNCTION(
736 "461509 SingleThreadProxy::DoComposite5"));
737 layer_tree_host_impl_->UpdateAnimationState(start_ready_animations);
739 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
740 // is fixed.
741 tracked_objects::ScopedTracker tracking_profile7(
742 FROM_HERE_WITH_EXPLICIT_FUNCTION(
743 "461509 SingleThreadProxy::DoComposite7"));
744 timing_history_.DidFinishDrawing();
747 if (draw_frame) {
748 DebugScopedSetImplThread impl(this);
750 // This CapturePostTasks should be destroyed before
751 // DidCommitAndDrawFrame() is called since that goes out to the
752 // embedder,
753 // and we want the embedder to receive its callbacks before that.
754 // NOTE: This maintains consistent ordering with the ThreadProxy since
755 // the DidCommitAndDrawFrame() must be post-tasked from the impl thread
756 // there as the main thread is not blocked, so any posted tasks inside
757 // the swap buffers will execute first.
758 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
760 BlockingTaskRunner::CapturePostTasks blocked(
761 blocking_main_thread_task_runner());
762 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
763 // is fixed.
764 tracked_objects::ScopedTracker tracking_profile8(
765 FROM_HERE_WITH_EXPLICIT_FUNCTION(
766 "461509 SingleThreadProxy::DoComposite8"));
767 layer_tree_host_impl_->SwapBuffers(*frame);
769 // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509 is
770 // fixed.
771 tracked_objects::ScopedTracker tracking_profile9(
772 FROM_HERE_WITH_EXPLICIT_FUNCTION(
773 "461509 SingleThreadProxy::DoComposite9"));
774 DidCommitAndDrawFrame();
776 return draw_result;
779 void SingleThreadProxy::DidCommitAndDrawFrame() {
780 if (next_frame_is_newly_committed_frame_) {
781 DebugScopedSetMainThread main(this);
782 next_frame_is_newly_committed_frame_ = false;
783 layer_tree_host_->DidCommitAndDrawFrame();
787 bool SingleThreadProxy::MainFrameWillHappenForTesting() {
788 if (layer_tree_host_->output_surface_lost())
789 return false;
790 if (!scheduler_on_impl_thread_)
791 return false;
792 return scheduler_on_impl_thread_->MainFrameForTestingWillHappen();
795 void SingleThreadProxy::SetChildrenNeedBeginFrames(
796 bool children_need_begin_frames) {
797 scheduler_on_impl_thread_->SetChildrenNeedBeginFrames(
798 children_need_begin_frames);
801 void SingleThreadProxy::SetAuthoritativeVSyncInterval(
802 const base::TimeDelta& interval) {
803 scheduler_on_impl_thread_->SetAuthoritativeVSyncInterval(interval);
806 void SingleThreadProxy::WillBeginImplFrame(const BeginFrameArgs& args) {
807 #if DCHECK_IS_ON()
808 DCHECK(!inside_impl_frame_)
809 << "WillBeginImplFrame called while already inside an impl frame!";
810 inside_impl_frame_ = true;
811 #endif
812 layer_tree_host_impl_->WillBeginImplFrame(args);
815 void SingleThreadProxy::ScheduledActionSendBeginMainFrame() {
816 TRACE_EVENT0("cc", "SingleThreadProxy::ScheduledActionSendBeginMainFrame");
817 // Although this proxy is single-threaded, it's problematic to synchronously
818 // have BeginMainFrame happen after ScheduledActionSendBeginMainFrame. This
819 // could cause a commit to occur in between a series of SetNeedsCommit calls
820 // (i.e. property modifications) causing some to fall on one frame and some to
821 // fall on the next. Doing it asynchronously instead matches the semantics of
822 // ThreadProxy::SetNeedsCommit where SetNeedsCommit will not cause a
823 // synchronous commit.
824 #if DCHECK_IS_ON()
825 DCHECK(inside_impl_frame_)
826 << "BeginMainFrame should only be sent inside a BeginImplFrame";
827 #endif
828 const BeginFrameArgs& begin_frame_args =
829 layer_tree_host_impl_->CurrentBeginFrameArgs();
831 MainThreadTaskRunner()->PostTask(
832 FROM_HERE, base::Bind(&SingleThreadProxy::BeginMainFrame,
833 weak_factory_.GetWeakPtr(), begin_frame_args));
836 void SingleThreadProxy::SendBeginMainFrameNotExpectedSoon() {
837 layer_tree_host_->BeginMainFrameNotExpectedSoon();
840 void SingleThreadProxy::BeginMainFrame(const BeginFrameArgs& begin_frame_args) {
841 commit_requested_ = false;
842 animate_requested_ = false;
844 if (defer_commits_) {
845 TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit",
846 TRACE_EVENT_SCOPE_THREAD);
847 BeginMainFrameAbortedOnImplThread(
848 CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT);
849 return;
852 // This checker assumes NotifyReadyToCommit in this stack causes a synchronous
853 // commit.
854 ScopedAbortRemainingSwapPromises swap_promise_checker(layer_tree_host_);
856 if (!layer_tree_host_->visible()) {
857 TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD);
858 BeginMainFrameAbortedOnImplThread(
859 CommitEarlyOutReason::ABORTED_NOT_VISIBLE);
860 return;
863 if (layer_tree_host_->output_surface_lost()) {
864 TRACE_EVENT_INSTANT0(
865 "cc", "EarlyOut_OutputSurfaceLost", TRACE_EVENT_SCOPE_THREAD);
866 BeginMainFrameAbortedOnImplThread(
867 CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST);
868 return;
871 // Prevent new commits from being requested inside DoBeginMainFrame.
872 // Note: We do not want to prevent SetNeedsAnimate from requesting
873 // a commit here.
874 commit_requested_ = true;
876 DoBeginMainFrame(begin_frame_args);
879 void SingleThreadProxy::DoBeginMainFrame(
880 const BeginFrameArgs& begin_frame_args) {
881 layer_tree_host_->WillBeginMainFrame();
882 layer_tree_host_->BeginMainFrame(begin_frame_args);
883 layer_tree_host_->AnimateLayers(begin_frame_args.frame_time);
884 layer_tree_host_->Layout();
886 if (PrioritizedResourceManager* contents_texture_manager =
887 layer_tree_host_->contents_texture_manager()) {
888 contents_texture_manager->UnlinkAndClearEvictedBackings();
889 contents_texture_manager->SetMaxMemoryLimitBytes(
890 layer_tree_host_impl_->memory_allocation_limit_bytes());
891 contents_texture_manager->SetExternalPriorityCutoff(
892 layer_tree_host_impl_->memory_allocation_priority_cutoff());
895 DCHECK(!queue_for_commit_);
896 queue_for_commit_ = make_scoped_ptr(new ResourceUpdateQueue);
898 // New commits requested inside UpdateLayers should be respected.
899 commit_requested_ = false;
901 layer_tree_host_->UpdateLayers(queue_for_commit_.get());
903 timing_history_.DidBeginMainFrame();
905 // TODO(enne): SingleThreadProxy does not support cancelling commits yet,
906 // search for CommitEarlyOutReason::FINISHED_NO_UPDATES inside
907 // thread_proxy.cc
908 if (scheduler_on_impl_thread_) {
909 scheduler_on_impl_thread_->NotifyBeginMainFrameStarted();
910 scheduler_on_impl_thread_->NotifyReadyToCommit();
914 void SingleThreadProxy::BeginMainFrameAbortedOnImplThread(
915 CommitEarlyOutReason reason) {
916 DebugScopedSetImplThread impl(this);
917 DCHECK(scheduler_on_impl_thread_->CommitPending());
918 DCHECK(!layer_tree_host_impl_->pending_tree());
920 layer_tree_host_impl_->BeginMainFrameAborted(reason);
921 scheduler_on_impl_thread_->BeginMainFrameAborted(reason);
924 DrawResult SingleThreadProxy::ScheduledActionDrawAndSwapIfPossible() {
925 DebugScopedSetImplThread impl(this);
926 LayerTreeHostImpl::FrameData frame;
927 return DoComposite(&frame);
930 DrawResult SingleThreadProxy::ScheduledActionDrawAndSwapForced() {
931 NOTREACHED();
932 return INVALID_RESULT;
935 void SingleThreadProxy::ScheduledActionCommit() {
936 DebugScopedSetMainThread main(this);
937 DoCommit();
940 void SingleThreadProxy::ScheduledActionAnimate() {
941 TRACE_EVENT0("cc", "ScheduledActionAnimate");
942 DebugScopedSetImplThread impl(this);
943 DoAnimate();
946 void SingleThreadProxy::ScheduledActionActivateSyncTree() {
947 DebugScopedSetImplThread impl(this);
948 layer_tree_host_impl_->ActivateSyncTree();
951 void SingleThreadProxy::ScheduledActionBeginOutputSurfaceCreation() {
952 DebugScopedSetMainThread main(this);
953 DCHECK(scheduler_on_impl_thread_);
954 // If possible, create the output surface in a post task. Synchronously
955 // creating the output surface makes tests more awkward since this differs
956 // from the ThreadProxy behavior. However, sometimes there is no
957 // task runner.
958 if (Proxy::MainThreadTaskRunner()) {
959 ScheduleRequestNewOutputSurface();
960 } else {
961 RequestNewOutputSurface();
965 void SingleThreadProxy::ScheduledActionPrepareTiles() {
966 TRACE_EVENT0("cc", "SingleThreadProxy::ScheduledActionPrepareTiles");
967 DCHECK(layer_tree_host_impl_->settings().impl_side_painting);
968 DebugScopedSetImplThread impl(this);
969 layer_tree_host_impl_->PrepareTiles();
972 void SingleThreadProxy::ScheduledActionInvalidateOutputSurface() {
973 NOTREACHED();
976 void SingleThreadProxy::DidAnticipatedDrawTimeChange(base::TimeTicks time) {
979 base::TimeDelta SingleThreadProxy::DrawDurationEstimate() {
980 return timing_history_.DrawDurationEstimate();
983 base::TimeDelta SingleThreadProxy::BeginMainFrameToCommitDurationEstimate() {
984 return timing_history_.BeginMainFrameToCommitDurationEstimate();
987 base::TimeDelta SingleThreadProxy::CommitToActivateDurationEstimate() {
988 return timing_history_.CommitToActivateDurationEstimate();
991 void SingleThreadProxy::DidFinishImplFrame() {
992 layer_tree_host_impl_->DidFinishImplFrame();
993 #if DCHECK_IS_ON()
994 DCHECK(inside_impl_frame_)
995 << "DidBeginImplFrameDeadline called while not inside an impl frame!";
996 inside_impl_frame_ = false;
997 #endif
1000 void SingleThreadProxy::SendBeginFramesToChildren(const BeginFrameArgs& args) {
1001 layer_tree_host_->SendBeginFramesToChildren(args);
1004 } // namespace cc