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/thread_proxy.h"
9 #include "base/auto_reset.h"
10 #include "base/bind.h"
11 #include "base/debug/trace_event.h"
12 #include "base/metrics/histogram.h"
13 #include "cc/debug/benchmark_instrumentation.h"
14 #include "cc/input/input_handler.h"
15 #include "cc/output/context_provider.h"
16 #include "cc/output/output_surface.h"
17 #include "cc/quads/draw_quad.h"
18 #include "cc/resources/prioritized_resource_manager.h"
19 #include "cc/scheduler/delay_based_time_source.h"
20 #include "cc/scheduler/frame_rate_controller.h"
21 #include "cc/scheduler/scheduler.h"
22 #include "cc/trees/blocking_task_runner.h"
23 #include "cc/trees/layer_tree_host.h"
24 #include "cc/trees/layer_tree_impl.h"
25 #include "ui/gfx/frame_time.h"
27 // Measured in seconds.
28 const double kSmoothnessTakesPriorityExpirationDelay = 0.25;
30 const size_t kDurationHistorySize = 60;
31 const double kCommitAndActivationDurationEstimationPercentile = 50.0;
32 const double kDrawDurationEstimationPercentile = 100.0;
33 const int kDrawDurationEstimatePaddingInMicroseconds = 0;
37 struct ThreadProxy::ReadbackRequest {
38 CompletionEvent completion;
44 struct ThreadProxy::CommitPendingRequest {
45 CompletionEvent completion;
49 struct ThreadProxy::SchedulerStateRequest {
50 CompletionEvent completion;
51 scoped_ptr<base::Value> state;
54 scoped_ptr<Proxy> ThreadProxy::Create(
55 LayerTreeHost* layer_tree_host,
56 scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
57 return make_scoped_ptr(
58 new ThreadProxy(layer_tree_host, impl_task_runner)).PassAs<Proxy>();
61 ThreadProxy::ThreadProxy(
62 LayerTreeHost* layer_tree_host,
63 scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner)
64 : Proxy(impl_task_runner),
65 animate_requested_(false),
66 commit_requested_(false),
67 commit_request_sent_to_impl_thread_(false),
68 created_offscreen_context_provider_(false),
69 layer_tree_host_(layer_tree_host),
71 textures_acquired_(true),
72 in_composite_and_readback_(false),
73 manage_tiles_pending_(false),
74 commit_waits_for_activation_(false),
75 inside_commit_(false),
76 begin_main_frame_sent_completion_event_on_impl_thread_(NULL),
77 readback_request_on_impl_thread_(NULL),
78 commit_completion_event_on_impl_thread_(NULL),
79 completion_event_for_commit_held_on_tree_activation_(NULL),
80 texture_acquisition_completion_event_on_impl_thread_(NULL),
81 next_frame_is_newly_committed_frame_on_impl_thread_(false),
82 throttle_frame_production_(
83 layer_tree_host->settings().throttle_frame_production),
84 begin_impl_frame_scheduling_enabled_(
85 layer_tree_host->settings().begin_impl_frame_scheduling_enabled),
86 using_synchronous_renderer_compositor_(
87 layer_tree_host->settings().using_synchronous_renderer_compositor),
89 can_cancel_commit_(true),
90 defer_commits_(false),
91 input_throttled_until_commit_(false),
92 renew_tree_priority_on_impl_thread_pending_(false),
93 draw_duration_history_(kDurationHistorySize),
94 begin_main_frame_to_commit_duration_history_(kDurationHistorySize),
95 commit_to_activate_duration_history_(kDurationHistorySize),
96 weak_factory_on_impl_thread_(this),
98 TRACE_EVENT0("cc", "ThreadProxy::ThreadProxy");
99 DCHECK(IsMainThread());
100 DCHECK(layer_tree_host_);
103 ThreadProxy::~ThreadProxy() {
104 TRACE_EVENT0("cc", "ThreadProxy::~ThreadProxy");
105 DCHECK(IsMainThread());
109 bool ThreadProxy::CompositeAndReadback(void* pixels, gfx::Rect rect) {
110 TRACE_EVENT0("cc", "ThreadProxy::CompositeAndReadback");
111 DCHECK(IsMainThread());
112 DCHECK(layer_tree_host_);
114 if (defer_commits_) {
115 TRACE_EVENT0("cc", "CompositeAndReadback_DeferCommit");
119 if (!layer_tree_host_->InitializeOutputSurfaceIfNeeded()) {
120 TRACE_EVENT0("cc", "CompositeAndReadback_EarlyOut_LR_Uninitialized");
124 // Perform a synchronous commit with an associated readback.
125 ReadbackRequest request;
127 request.pixels = pixels;
129 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
130 CompletionEvent begin_main_frame_sent_completion;
131 Proxy::ImplThreadTaskRunner()
132 ->PostTask(FROM_HERE,
133 base::Bind(&ThreadProxy::ForceCommitForReadbackOnImplThread,
134 impl_thread_weak_ptr_,
135 &begin_main_frame_sent_completion,
137 begin_main_frame_sent_completion.Wait();
140 in_composite_and_readback_ = true;
141 // This is the forced commit.
142 // Note: The Impl thread also queues a separate BeginMainFrame on the
143 // main thread, which will be called after this CompositeAndReadback
144 // completes, to replace the forced commit.
145 BeginMainFrame(scoped_ptr<BeginMainFrameAndCommitState>());
146 in_composite_and_readback_ = false;
148 // Composite and readback requires a second commit to undo any changes
150 can_cancel_commit_ = false;
152 request.completion.Wait();
153 return request.success;
156 void ThreadProxy::ForceCommitForReadbackOnImplThread(
157 CompletionEvent* begin_main_frame_sent_completion,
158 ReadbackRequest* request) {
159 TRACE_EVENT0("cc", "ThreadProxy::ForceCommitForReadbackOnImplThread");
160 DCHECK(IsImplThread());
161 DCHECK(!begin_main_frame_sent_completion_event_on_impl_thread_);
162 DCHECK(!readback_request_on_impl_thread_);
164 if (!layer_tree_host_impl_) {
165 begin_main_frame_sent_completion->Signal();
166 request->success = false;
167 request->completion.Signal();
171 readback_request_on_impl_thread_ = request;
173 scheduler_on_impl_thread_->SetNeedsForcedCommitForReadback();
174 if (scheduler_on_impl_thread_->CommitPending()) {
175 begin_main_frame_sent_completion->Signal();
179 begin_main_frame_sent_completion_event_on_impl_thread_ =
180 begin_main_frame_sent_completion;
183 void ThreadProxy::FinishAllRendering() {
184 DCHECK(Proxy::IsMainThread());
185 DCHECK(!defer_commits_);
187 // Make sure all GL drawing is finished on the impl thread.
188 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
189 CompletionEvent completion;
190 Proxy::ImplThreadTaskRunner()->PostTask(
192 base::Bind(&ThreadProxy::FinishAllRenderingOnImplThread,
193 impl_thread_weak_ptr_,
198 bool ThreadProxy::IsStarted() const {
199 DCHECK(Proxy::IsMainThread());
203 void ThreadProxy::SetLayerTreeHostClientReady() {
204 TRACE_EVENT0("cc", "ThreadProxy::SetLayerTreeHostClientReady");
205 Proxy::ImplThreadTaskRunner()->PostTask(
207 base::Bind(&ThreadProxy::SetLayerTreeHostClientReadyOnImplThread,
208 impl_thread_weak_ptr_));
211 void ThreadProxy::SetLayerTreeHostClientReadyOnImplThread() {
212 TRACE_EVENT0("cc", "ThreadProxy::SetLayerTreeHostClientReadyOnImplThread");
213 scheduler_on_impl_thread_->SetCanStart();
216 void ThreadProxy::SetVisible(bool visible) {
217 TRACE_EVENT0("cc", "ThreadProxy::SetVisible");
218 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
220 CompletionEvent completion;
221 Proxy::ImplThreadTaskRunner()->PostTask(
223 base::Bind(&ThreadProxy::SetVisibleOnImplThread,
224 impl_thread_weak_ptr_,
230 void ThreadProxy::SetVisibleOnImplThread(CompletionEvent* completion,
232 TRACE_EVENT0("cc", "ThreadProxy::SetVisibleOnImplThread");
233 layer_tree_host_impl_->SetVisible(visible);
234 scheduler_on_impl_thread_->SetVisible(visible);
235 UpdateBackgroundAnimateTicking();
236 completion->Signal();
239 void ThreadProxy::UpdateBackgroundAnimateTicking() {
240 layer_tree_host_impl_->UpdateBackgroundAnimateTicking(
241 !scheduler_on_impl_thread_->WillDrawIfNeeded() &&
242 layer_tree_host_impl_->active_tree()->root_layer());
245 void ThreadProxy::DoCreateAndInitializeOutputSurface() {
246 TRACE_EVENT0("cc", "ThreadProxy::DoCreateAndInitializeOutputSurface");
247 DCHECK(IsMainThread());
249 scoped_ptr<OutputSurface> output_surface = first_output_surface_.Pass();
251 output_surface = layer_tree_host_->CreateOutputSurface();
253 RendererCapabilities capabilities;
254 bool success = !!output_surface;
256 OnOutputSurfaceInitializeAttempted(false, capabilities);
260 scoped_refptr<ContextProvider> offscreen_context_provider;
261 if (created_offscreen_context_provider_) {
262 offscreen_context_provider =
263 layer_tree_host_->client()->OffscreenContextProvider();
264 success = !!offscreen_context_provider.get();
266 OnOutputSurfaceInitializeAttempted(false, capabilities);
273 // Make a blocking call to InitializeOutputSurfaceOnImplThread. The results
274 // of that call are pushed into the success and capabilities local
276 CompletionEvent completion;
277 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
279 Proxy::ImplThreadTaskRunner()->PostTask(
281 base::Bind(&ThreadProxy::InitializeOutputSurfaceOnImplThread,
282 impl_thread_weak_ptr_,
284 base::Passed(&output_surface),
285 offscreen_context_provider,
291 OnOutputSurfaceInitializeAttempted(success, capabilities);
294 void ThreadProxy::OnOutputSurfaceInitializeAttempted(
296 const RendererCapabilities& capabilities) {
297 DCHECK(IsMainThread());
298 DCHECK(layer_tree_host_);
301 renderer_capabilities_main_thread_copy_ = capabilities;
304 LayerTreeHost::CreateResult result =
305 layer_tree_host_->OnCreateAndInitializeOutputSurfaceAttempted(success);
306 if (result == LayerTreeHost::CreateFailedButTryAgain) {
307 if (!output_surface_creation_callback_.callback().is_null()) {
308 Proxy::MainThreadTaskRunner()->PostTask(
309 FROM_HERE, output_surface_creation_callback_.callback());
312 output_surface_creation_callback_.Cancel();
316 void ThreadProxy::SendCommitRequestToImplThreadIfNeeded() {
317 DCHECK(IsMainThread());
318 if (commit_request_sent_to_impl_thread_)
320 commit_request_sent_to_impl_thread_ = true;
321 Proxy::ImplThreadTaskRunner()->PostTask(
323 base::Bind(&ThreadProxy::SetNeedsCommitOnImplThread,
324 impl_thread_weak_ptr_));
327 const RendererCapabilities& ThreadProxy::GetRendererCapabilities() const {
328 DCHECK(IsMainThread());
329 DCHECK(!layer_tree_host_->output_surface_lost());
330 return renderer_capabilities_main_thread_copy_;
333 void ThreadProxy::SetNeedsAnimate() {
334 DCHECK(IsMainThread());
335 if (animate_requested_)
338 TRACE_EVENT0("cc", "ThreadProxy::SetNeedsAnimate");
339 animate_requested_ = true;
340 can_cancel_commit_ = false;
341 SendCommitRequestToImplThreadIfNeeded();
344 void ThreadProxy::SetNeedsUpdateLayers() {
345 DCHECK(IsMainThread());
347 if (commit_request_sent_to_impl_thread_)
349 TRACE_EVENT0("cc", "ThreadProxy::SetNeedsUpdateLayers");
351 SendCommitRequestToImplThreadIfNeeded();
354 void ThreadProxy::SetNeedsCommit() {
355 DCHECK(IsMainThread());
356 // Unconditionally set here to handle SetNeedsCommit calls during a commit.
357 can_cancel_commit_ = false;
359 if (commit_requested_)
361 TRACE_EVENT0("cc", "ThreadProxy::SetNeedsCommit");
362 commit_requested_ = true;
364 SendCommitRequestToImplThreadIfNeeded();
367 void ThreadProxy::DidLoseOutputSurfaceOnImplThread() {
368 DCHECK(IsImplThread());
369 TRACE_EVENT0("cc", "ThreadProxy::DidLoseOutputSurfaceOnImplThread");
370 CheckOutputSurfaceStatusOnImplThread();
373 void ThreadProxy::CheckOutputSurfaceStatusOnImplThread() {
374 DCHECK(IsImplThread());
375 TRACE_EVENT0("cc", "ThreadProxy::CheckOutputSurfaceStatusOnImplThread");
376 if (!layer_tree_host_impl_->IsContextLost())
378 if (cc::ContextProvider* offscreen_contexts =
379 layer_tree_host_impl_->offscreen_context_provider())
380 offscreen_contexts->VerifyContexts();
381 scheduler_on_impl_thread_->DidLoseOutputSurface();
384 void ThreadProxy::OnSwapBuffersCompleteOnImplThread() {
385 DCHECK(IsImplThread());
386 TRACE_EVENT0("cc", "ThreadProxy::OnSwapBuffersCompleteOnImplThread");
387 Proxy::MainThreadTaskRunner()->PostTask(
389 base::Bind(&ThreadProxy::DidCompleteSwapBuffers, main_thread_weak_ptr_));
392 void ThreadProxy::SetNeedsBeginImplFrame(bool enable) {
393 DCHECK(IsImplThread());
394 TRACE_EVENT1("cc", "ThreadProxy::SetNeedsBeginImplFrame",
396 layer_tree_host_impl_->SetNeedsBeginImplFrame(enable);
397 UpdateBackgroundAnimateTicking();
400 void ThreadProxy::BeginImplFrame(const BeginFrameArgs& args) {
401 DCHECK(IsImplThread());
402 TRACE_EVENT0("cc", "ThreadProxy::BeginImplFrame");
404 // Sample the frame time now. This time will be used for updating animations
406 layer_tree_host_impl_->CurrentFrameTimeTicks();
408 scheduler_on_impl_thread_->BeginImplFrame(args);
411 void ThreadProxy::OnCanDrawStateChanged(bool can_draw) {
412 DCHECK(IsImplThread());
414 "cc", "ThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw);
415 scheduler_on_impl_thread_->SetCanDraw(can_draw);
416 UpdateBackgroundAnimateTicking();
419 void ThreadProxy::NotifyReadyToActivate() {
420 TRACE_EVENT0("cc", "ThreadProxy::NotifyReadyToActivate");
421 scheduler_on_impl_thread_->NotifyReadyToActivate();
424 void ThreadProxy::SetNeedsCommitOnImplThread() {
425 DCHECK(IsImplThread());
426 TRACE_EVENT0("cc", "ThreadProxy::SetNeedsCommitOnImplThread");
427 scheduler_on_impl_thread_->SetNeedsCommit();
430 void ThreadProxy::PostAnimationEventsToMainThreadOnImplThread(
431 scoped_ptr<AnimationEventsVector> events,
432 base::Time wall_clock_time) {
433 DCHECK(IsImplThread());
435 "ThreadProxy::PostAnimationEventsToMainThreadOnImplThread");
436 Proxy::MainThreadTaskRunner()->PostTask(
438 base::Bind(&ThreadProxy::SetAnimationEvents,
439 main_thread_weak_ptr_,
440 base::Passed(&events),
444 bool ThreadProxy::ReduceContentsTextureMemoryOnImplThread(size_t limit_bytes,
445 int priority_cutoff) {
446 DCHECK(IsImplThread());
448 if (!layer_tree_host_->contents_texture_manager())
450 if (!layer_tree_host_impl_->resource_provider())
453 bool reduce_result = layer_tree_host_->contents_texture_manager()->
454 ReduceMemoryOnImplThread(limit_bytes,
456 layer_tree_host_impl_->resource_provider());
460 // The texture upload queue may reference textures that were just purged,
461 // clear them from the queue.
462 if (current_resource_update_controller_on_impl_thread_) {
463 current_resource_update_controller_on_impl_thread_->
464 DiscardUploadsToEvictedResources();
469 void ThreadProxy::SendManagedMemoryStats() {
470 DCHECK(IsImplThread());
471 if (!layer_tree_host_impl_)
473 if (!layer_tree_host_->contents_texture_manager())
476 // If we are using impl-side painting, then SendManagedMemoryStats is called
477 // directly after the tile manager's manage function, and doesn't need to
478 // interact with main thread's layer tree.
479 if (layer_tree_host_->settings().impl_side_painting)
482 layer_tree_host_impl_->SendManagedMemoryStats(
483 layer_tree_host_->contents_texture_manager()->MemoryVisibleBytes(),
484 layer_tree_host_->contents_texture_manager()->
485 MemoryVisibleAndNearbyBytes(),
486 layer_tree_host_->contents_texture_manager()->MemoryUseBytes());
489 bool ThreadProxy::IsInsideDraw() { return inside_draw_; }
491 void ThreadProxy::SetNeedsRedraw(gfx::Rect damage_rect) {
492 DCHECK(IsMainThread());
493 TRACE_EVENT0("cc", "ThreadProxy::SetNeedsRedraw");
494 Proxy::ImplThreadTaskRunner()->PostTask(
496 base::Bind(&ThreadProxy::SetNeedsRedrawRectOnImplThread,
497 impl_thread_weak_ptr_,
501 void ThreadProxy::SetNextCommitWaitsForActivation() {
502 DCHECK(IsMainThread());
503 DCHECK(!inside_commit_);
504 commit_waits_for_activation_ = true;
507 void ThreadProxy::SetDeferCommits(bool defer_commits) {
508 DCHECK(IsMainThread());
509 DCHECK_NE(defer_commits_, defer_commits);
510 defer_commits_ = defer_commits;
513 TRACE_EVENT_ASYNC_BEGIN0("cc", "ThreadProxy::SetDeferCommits", this);
515 TRACE_EVENT_ASYNC_END0("cc", "ThreadProxy::SetDeferCommits", this);
517 if (!defer_commits_ && pending_deferred_commit_)
518 Proxy::MainThreadTaskRunner()->PostTask(
520 base::Bind(&ThreadProxy::BeginMainFrame,
521 main_thread_weak_ptr_,
522 base::Passed(&pending_deferred_commit_)));
525 bool ThreadProxy::CommitRequested() const {
526 DCHECK(IsMainThread());
527 return commit_requested_;
530 bool ThreadProxy::BeginMainFrameRequested() const {
531 DCHECK(IsMainThread());
532 return commit_request_sent_to_impl_thread_;
535 void ThreadProxy::SetNeedsRedrawOnImplThread() {
536 DCHECK(IsImplThread());
537 TRACE_EVENT0("cc", "ThreadProxy::SetNeedsRedrawOnImplThread");
538 scheduler_on_impl_thread_->SetNeedsRedraw();
541 void ThreadProxy::SetNeedsManageTilesOnImplThread() {
542 DCHECK(IsImplThread());
543 scheduler_on_impl_thread_->SetNeedsManageTiles();
546 void ThreadProxy::SetNeedsRedrawRectOnImplThread(gfx::Rect damage_rect) {
547 DCHECK(IsImplThread());
548 layer_tree_host_impl_->SetViewportDamage(damage_rect);
549 SetNeedsRedrawOnImplThread();
552 void ThreadProxy::SetSwapUsedIncompleteTileOnImplThread(
553 bool used_incomplete_tile) {
554 DCHECK(IsImplThread());
555 if (used_incomplete_tile) {
556 TRACE_EVENT_INSTANT0(
558 "ThreadProxy::SetSwapUsedIncompleteTileOnImplThread",
559 TRACE_EVENT_SCOPE_THREAD);
561 scheduler_on_impl_thread_->SetSwapUsedIncompleteTile(
562 used_incomplete_tile);
565 void ThreadProxy::DidInitializeVisibleTileOnImplThread() {
566 DCHECK(IsImplThread());
567 TRACE_EVENT0("cc", "ThreadProxy::DidInitializeVisibleTileOnImplThread");
568 scheduler_on_impl_thread_->SetNeedsRedraw();
571 void ThreadProxy::MainThreadHasStoppedFlinging() {
572 DCHECK(IsMainThread());
573 Proxy::ImplThreadTaskRunner()->PostTask(
575 base::Bind(&ThreadProxy::MainThreadHasStoppedFlingingOnImplThread,
576 impl_thread_weak_ptr_));
579 void ThreadProxy::MainThreadHasStoppedFlingingOnImplThread() {
580 DCHECK(IsImplThread());
581 layer_tree_host_impl_->MainThreadHasStoppedFlinging();
584 void ThreadProxy::NotifyInputThrottledUntilCommit() {
585 DCHECK(IsMainThread());
586 Proxy::ImplThreadTaskRunner()->PostTask(
588 base::Bind(&ThreadProxy::SetInputThrottledUntilCommitOnImplThread,
589 impl_thread_weak_ptr_,
593 void ThreadProxy::SetInputThrottledUntilCommitOnImplThread(
595 DCHECK(IsImplThread());
596 if (is_throttled == input_throttled_until_commit_)
598 input_throttled_until_commit_ = is_throttled;
602 void ThreadProxy::Start(scoped_ptr<OutputSurface> first_output_surface) {
603 DCHECK(IsMainThread());
604 DCHECK(Proxy::HasImplThread());
605 DCHECK(first_output_surface);
607 // Create LayerTreeHostImpl.
608 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
609 CompletionEvent completion;
610 Proxy::ImplThreadTaskRunner()->PostTask(
612 base::Bind(&ThreadProxy::InitializeImplOnImplThread,
613 base::Unretained(this),
617 main_thread_weak_ptr_ = weak_factory_.GetWeakPtr();
618 first_output_surface_ = first_output_surface.Pass();
623 void ThreadProxy::Stop() {
624 TRACE_EVENT0("cc", "ThreadProxy::Stop");
625 DCHECK(IsMainThread());
628 // Synchronously finishes pending GL operations and deletes the impl.
629 // The two steps are done as separate post tasks, so that tasks posted
630 // by the GL implementation due to the Finish can be executed by the
631 // renderer before shutting it down.
633 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
635 CompletionEvent completion;
636 Proxy::ImplThreadTaskRunner()->PostTask(
638 base::Bind(&ThreadProxy::FinishGLOnImplThread,
639 impl_thread_weak_ptr_,
644 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
646 CompletionEvent completion;
647 Proxy::ImplThreadTaskRunner()->PostTask(
649 base::Bind(&ThreadProxy::LayerTreeHostClosedOnImplThread,
650 impl_thread_weak_ptr_,
655 weak_factory_.InvalidateWeakPtrs();
657 DCHECK(!layer_tree_host_impl_.get()); // verify that the impl deleted.
658 layer_tree_host_ = NULL;
662 void ThreadProxy::ForceSerializeOnSwapBuffers() {
663 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
664 CompletionEvent completion;
665 Proxy::ImplThreadTaskRunner()->PostTask(
667 base::Bind(&ThreadProxy::ForceSerializeOnSwapBuffersOnImplThread,
668 impl_thread_weak_ptr_,
673 void ThreadProxy::ForceSerializeOnSwapBuffersOnImplThread(
674 CompletionEvent* completion) {
675 if (layer_tree_host_impl_->renderer())
676 layer_tree_host_impl_->renderer()->DoNoOp();
677 completion->Signal();
680 void ThreadProxy::FinishAllRenderingOnImplThread(CompletionEvent* completion) {
681 TRACE_EVENT0("cc", "ThreadProxy::FinishAllRenderingOnImplThread");
682 DCHECK(IsImplThread());
683 layer_tree_host_impl_->FinishAllRendering();
684 completion->Signal();
687 void ThreadProxy::ScheduledActionSendBeginMainFrame() {
688 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionSendBeginMainFrame");
689 scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state(
690 new BeginMainFrameAndCommitState);
691 begin_main_frame_state->monotonic_frame_begin_time =
692 layer_tree_host_impl_->CurrentPhysicalTimeTicks();
693 begin_main_frame_state->scroll_info =
694 layer_tree_host_impl_->ProcessScrollDeltas();
696 if (!layer_tree_host_impl_->settings().impl_side_painting) {
697 DCHECK_GT(layer_tree_host_impl_->memory_allocation_limit_bytes(), 0u);
699 begin_main_frame_state->memory_allocation_limit_bytes =
700 layer_tree_host_impl_->memory_allocation_limit_bytes();
701 begin_main_frame_state->memory_allocation_priority_cutoff =
702 layer_tree_host_impl_->memory_allocation_priority_cutoff();
703 begin_main_frame_state->evicted_ui_resources =
704 layer_tree_host_impl_->EvictedUIResourcesExist();
705 Proxy::MainThreadTaskRunner()->PostTask(
707 base::Bind(&ThreadProxy::BeginMainFrame,
708 main_thread_weak_ptr_,
709 base::Passed(&begin_main_frame_state)));
711 if (begin_main_frame_sent_completion_event_on_impl_thread_) {
712 begin_main_frame_sent_completion_event_on_impl_thread_->Signal();
713 begin_main_frame_sent_completion_event_on_impl_thread_ = NULL;
715 begin_main_frame_sent_time_ = base::TimeTicks::HighResNow();
718 void ThreadProxy::BeginMainFrame(
719 scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) {
720 TRACE_EVENT0("cc", "ThreadProxy::BeginMainFrame");
721 DCHECK(IsMainThread());
723 if (!layer_tree_host_)
726 if (defer_commits_) {
727 pending_deferred_commit_ = begin_main_frame_state.Pass();
728 layer_tree_host_->DidDeferCommit();
729 TRACE_EVENT0("cc", "EarlyOut_DeferCommits");
733 // Do not notify the impl thread of commit requests that occur during
734 // the apply/animate/layout part of the BeginMainFrameAndCommit process since
735 // those commit requests will get painted immediately. Once we have done
736 // the paint, commit_requested_ will be set to false to allow new commit
737 // requests to be scheduled.
738 commit_requested_ = true;
739 commit_request_sent_to_impl_thread_ = true;
741 // On the other hand, the AnimationRequested flag needs to be cleared
742 // here so that any animation requests generated by the apply or animate
743 // callbacks will trigger another frame.
744 animate_requested_ = false;
746 if (!in_composite_and_readback_ && !layer_tree_host_->visible()) {
747 commit_requested_ = false;
748 commit_request_sent_to_impl_thread_ = false;
750 TRACE_EVENT0("cc", "EarlyOut_NotVisible");
751 bool did_handle = false;
752 Proxy::ImplThreadTaskRunner()->PostTask(
754 base::Bind(&ThreadProxy::BeginMainFrameAbortedOnImplThread,
755 impl_thread_weak_ptr_,
760 if (begin_main_frame_state)
761 layer_tree_host_->ApplyScrollAndScale(*begin_main_frame_state->scroll_info);
763 layer_tree_host_->WillBeginMainFrame();
765 if (begin_main_frame_state) {
766 layer_tree_host_->UpdateClientAnimations(
767 begin_main_frame_state->monotonic_frame_begin_time);
768 layer_tree_host_->AnimateLayers(
769 begin_main_frame_state->monotonic_frame_begin_time);
772 // Unlink any backings that the impl thread has evicted, so that we know to
773 // re-paint them in UpdateLayers.
774 if (layer_tree_host_->contents_texture_manager()) {
775 layer_tree_host_->contents_texture_manager()->
776 UnlinkAndClearEvictedBackings();
778 if (begin_main_frame_state) {
779 layer_tree_host_->contents_texture_manager()->SetMaxMemoryLimitBytes(
780 begin_main_frame_state->memory_allocation_limit_bytes);
781 layer_tree_host_->contents_texture_manager()->SetExternalPriorityCutoff(
782 begin_main_frame_state->memory_allocation_priority_cutoff);
786 // Recreate all UI resources if there were evicted UI resources when the impl
787 // thread initiated the commit.
788 bool evicted_ui_resources = begin_main_frame_state
789 ? begin_main_frame_state->evicted_ui_resources
791 if (evicted_ui_resources)
792 layer_tree_host_->RecreateUIResources();
794 layer_tree_host_->Layout();
796 // Clear the commit flag after updating animations and layout here --- objects
797 // that only layout when painted will trigger another SetNeedsCommit inside
799 commit_requested_ = false;
800 commit_request_sent_to_impl_thread_ = false;
801 bool can_cancel_this_commit =
802 can_cancel_commit_ &&
803 !in_composite_and_readback_ &&
804 !evicted_ui_resources;
805 can_cancel_commit_ = true;
807 scoped_ptr<ResourceUpdateQueue> queue =
808 make_scoped_ptr(new ResourceUpdateQueue);
810 bool updated = layer_tree_host_->UpdateLayers(queue.get());
812 // Once single buffered layers are committed, they cannot be modified until
813 // they are drawn by the impl thread.
814 textures_acquired_ = false;
816 layer_tree_host_->WillCommit();
818 if (!updated && can_cancel_this_commit) {
819 TRACE_EVENT0("cc", "EarlyOut_NoUpdates");
820 bool did_handle = true;
821 Proxy::ImplThreadTaskRunner()->PostTask(
823 base::Bind(&ThreadProxy::BeginMainFrameAbortedOnImplThread,
824 impl_thread_weak_ptr_,
827 // Although the commit is internally aborted, this is because it has been
828 // detected to be a no-op. From the perspective of an embedder, this commit
829 // went through, and input should no longer be throttled, etc.
830 layer_tree_host_->CommitComplete();
831 layer_tree_host_->DidBeginMainFrame();
835 // Before calling animate, we set animate_requested_ to false. If it is true
836 // now, it means SetNeedAnimate was called again, but during a state when
837 // commit_request_sent_to_impl_thread_ = true. We need to force that call to
838 // happen again now so that the commit request is sent to the impl thread.
839 if (animate_requested_) {
840 // Forces SetNeedsAnimate to consider posting a commit task.
841 animate_requested_ = false;
845 scoped_refptr<cc::ContextProvider> offscreen_context_provider;
846 if (renderer_capabilities_main_thread_copy_.using_offscreen_context3d &&
847 layer_tree_host_->needs_offscreen_context()) {
848 offscreen_context_provider =
849 layer_tree_host_->client()->OffscreenContextProvider();
850 if (offscreen_context_provider.get())
851 created_offscreen_context_provider_ = true;
854 // Notify the impl thread that the main thread is ready to commit. This will
855 // begin the commit process, which is blocking from the main thread's
856 // point of view, but asynchronously performed on the impl thread,
857 // coordinated by the Scheduler.
859 TRACE_EVENT0("cc", "ThreadProxy::BeginMainFrame::commit");
861 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
863 // This CapturePostTasks should be destroyed before CommitComplete() is
864 // called since that goes out to the embedder, and we want the embedder
865 // to receive its callbacks before that.
866 BlockingTaskRunner::CapturePostTasks blocked;
868 CompletionEvent completion;
869 Proxy::ImplThreadTaskRunner()->PostTask(
871 base::Bind(&ThreadProxy::StartCommitOnImplThread,
872 impl_thread_weak_ptr_,
875 offscreen_context_provider));
878 RenderingStatsInstrumentation* stats_instrumentation =
879 layer_tree_host_->rendering_stats_instrumentation();
880 BenchmarkInstrumentation::IssueMainThreadRenderingStatsEvent(
881 stats_instrumentation->main_thread_rendering_stats());
882 stats_instrumentation->AccumulateAndClearMainThreadStats();
885 layer_tree_host_->CommitComplete();
886 layer_tree_host_->DidBeginMainFrame();
889 void ThreadProxy::StartCommitOnImplThread(
890 CompletionEvent* completion,
891 ResourceUpdateQueue* raw_queue,
892 scoped_refptr<cc::ContextProvider> offscreen_context_provider) {
893 scoped_ptr<ResourceUpdateQueue> queue(raw_queue);
895 TRACE_EVENT0("cc", "ThreadProxy::StartCommitOnImplThread");
896 DCHECK(!commit_completion_event_on_impl_thread_);
897 DCHECK(IsImplThread() && IsMainThreadBlocked());
898 DCHECK(scheduler_on_impl_thread_);
899 DCHECK(scheduler_on_impl_thread_->CommitPending());
901 if (!layer_tree_host_impl_) {
902 TRACE_EVENT0("cc", "EarlyOut_NoLayerTree");
903 completion->Signal();
907 if (offscreen_context_provider.get())
908 offscreen_context_provider->BindToCurrentThread();
909 layer_tree_host_impl_->SetOffscreenContextProvider(
910 offscreen_context_provider);
912 if (layer_tree_host_->contents_texture_manager()) {
913 if (layer_tree_host_->contents_texture_manager()->
914 LinkedEvictedBackingsExist()) {
915 // Clear any uploads we were making to textures linked to evicted
917 queue->ClearUploadsToEvictedResources();
918 // Some textures in the layer tree are invalid. Kick off another commit
919 // to fill them again.
920 SetNeedsCommitOnImplThread();
923 layer_tree_host_->contents_texture_manager()->
924 PushTexturePrioritiesToBackings();
927 commit_completion_event_on_impl_thread_ = completion;
928 current_resource_update_controller_on_impl_thread_ =
929 ResourceUpdateController::Create(
931 Proxy::ImplThreadTaskRunner(),
933 layer_tree_host_impl_->resource_provider());
934 current_resource_update_controller_on_impl_thread_->PerformMoreUpdates(
935 scheduler_on_impl_thread_->AnticipatedDrawTime());
938 void ThreadProxy::BeginMainFrameAbortedOnImplThread(bool did_handle) {
939 TRACE_EVENT0("cc", "ThreadProxy::BeginMainFrameAbortedOnImplThread");
940 DCHECK(IsImplThread());
941 DCHECK(scheduler_on_impl_thread_);
942 DCHECK(scheduler_on_impl_thread_->CommitPending());
943 DCHECK(!layer_tree_host_impl_->pending_tree());
945 // If the begin frame data was handled, then scroll and scale set was applied
946 // by the main thread, so the active tree needs to be updated as if these sent
947 // values were applied and committed.
949 layer_tree_host_impl_->active_tree()
950 ->ApplySentScrollAndScaleDeltasFromAbortedCommit();
951 layer_tree_host_impl_->active_tree()->ResetContentsTexturesPurged();
952 SetInputThrottledUntilCommitOnImplThread(false);
954 scheduler_on_impl_thread_->BeginMainFrameAborted(did_handle);
957 void ThreadProxy::ScheduledActionCommit() {
958 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionCommit");
959 DCHECK(IsImplThread());
960 DCHECK(commit_completion_event_on_impl_thread_);
961 DCHECK(current_resource_update_controller_on_impl_thread_);
963 // Complete all remaining texture updates.
964 current_resource_update_controller_on_impl_thread_->Finalize();
965 current_resource_update_controller_on_impl_thread_.reset();
967 inside_commit_ = true;
968 layer_tree_host_impl_->BeginCommit();
969 layer_tree_host_->BeginCommitOnImplThread(layer_tree_host_impl_.get());
970 layer_tree_host_->FinishCommitOnImplThread(layer_tree_host_impl_.get());
971 layer_tree_host_impl_->CommitComplete();
972 inside_commit_ = false;
974 SetInputThrottledUntilCommitOnImplThread(false);
976 UpdateBackgroundAnimateTicking();
978 next_frame_is_newly_committed_frame_on_impl_thread_ = true;
980 if (layer_tree_host_->settings().impl_side_painting &&
981 commit_waits_for_activation_) {
982 // For some layer types in impl-side painting, the commit is held until
983 // the pending tree is activated. It's also possible that the
984 // pending tree has already activated if there was no work to be done.
985 TRACE_EVENT_INSTANT0("cc", "HoldCommit", TRACE_EVENT_SCOPE_THREAD);
986 completion_event_for_commit_held_on_tree_activation_ =
987 commit_completion_event_on_impl_thread_;
988 commit_completion_event_on_impl_thread_ = NULL;
990 commit_completion_event_on_impl_thread_->Signal();
991 commit_completion_event_on_impl_thread_ = NULL;
994 commit_waits_for_activation_ = false;
996 commit_complete_time_ = base::TimeTicks::HighResNow();
997 begin_main_frame_to_commit_duration_history_.InsertSample(
998 commit_complete_time_ - begin_main_frame_sent_time_);
1000 // SetVisible kicks off the next scheduler action, so this must be last.
1001 scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible());
1004 void ThreadProxy::ScheduledActionUpdateVisibleTiles() {
1005 DCHECK(IsImplThread());
1006 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionUpdateVisibleTiles");
1007 layer_tree_host_impl_->UpdateVisibleTiles();
1010 void ThreadProxy::ScheduledActionActivatePendingTree() {
1011 DCHECK(IsImplThread());
1012 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionActivatePendingTree");
1013 layer_tree_host_impl_->ActivatePendingTree();
1016 void ThreadProxy::ScheduledActionBeginOutputSurfaceCreation() {
1017 DCHECK(IsImplThread());
1018 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionBeginOutputSurfaceCreation");
1019 Proxy::MainThreadTaskRunner()->PostTask(
1021 base::Bind(&ThreadProxy::CreateAndInitializeOutputSurface,
1022 main_thread_weak_ptr_));
1025 DrawSwapReadbackResult ThreadProxy::DrawSwapReadbackInternal(
1027 bool swap_requested,
1028 bool readback_requested) {
1029 DrawSwapReadbackResult result;
1030 result.did_draw = false;
1031 result.did_swap = false;
1032 result.did_readback = false;
1033 DCHECK(IsImplThread());
1034 DCHECK(layer_tree_host_impl_.get());
1035 if (!layer_tree_host_impl_)
1038 DCHECK(layer_tree_host_impl_->renderer());
1039 if (!layer_tree_host_impl_->renderer())
1042 base::TimeTicks start_time = base::TimeTicks::HighResNow();
1043 base::TimeDelta draw_duration_estimate = DrawDurationEstimate();
1044 base::AutoReset<bool> mark_inside(&inside_draw_, true);
1046 // Advance our animations.
1047 base::TimeTicks monotonic_time =
1048 layer_tree_host_impl_->CurrentFrameTimeTicks();
1049 base::Time wall_clock_time = layer_tree_host_impl_->CurrentFrameTime();
1051 // TODO(enne): This should probably happen post-animate.
1052 if (layer_tree_host_impl_->pending_tree())
1053 layer_tree_host_impl_->pending_tree()->UpdateDrawProperties();
1054 layer_tree_host_impl_->Animate(monotonic_time, wall_clock_time);
1056 // This method is called on a forced draw, regardless of whether we are able
1057 // to produce a frame, as the calling site on main thread is blocked until its
1058 // request completes, and we signal completion here. If CanDraw() is false, we
1059 // will indicate success=false to the caller, but we must still signal
1060 // completion to avoid deadlock.
1062 // We guard PrepareToDraw() with CanDraw() because it always returns a valid
1063 // frame, so can only be used when such a frame is possible. Since
1064 // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
1065 // CanDraw() as well.
1067 bool drawing_for_readback =
1068 readback_requested && !!readback_request_on_impl_thread_;
1069 bool can_do_readback = layer_tree_host_impl_->renderer()->CanReadPixels();
1071 LayerTreeHostImpl::FrameData frame;
1072 bool draw_frame = false;
1074 if (layer_tree_host_impl_->CanDraw() &&
1075 (!drawing_for_readback || can_do_readback)) {
1076 // If it is for a readback, make sure we draw the portion being read back.
1077 gfx::Rect readback_rect;
1078 if (drawing_for_readback)
1079 readback_rect = readback_request_on_impl_thread_->rect;
1081 if (layer_tree_host_impl_->PrepareToDraw(&frame, readback_rect) ||
1087 layer_tree_host_impl_->DrawLayers(
1089 scheduler_on_impl_thread_->LastBeginImplFrameTime());
1090 result.did_draw = true;
1092 layer_tree_host_impl_->DidDrawAllLayers(frame);
1094 bool start_ready_animations = draw_frame;
1095 layer_tree_host_impl_->UpdateAnimationState(start_ready_animations);
1097 // Check for a pending CompositeAndReadback.
1098 if (drawing_for_readback) {
1099 DCHECK(!swap_requested);
1100 result.did_readback = false;
1101 if (draw_frame && !layer_tree_host_impl_->IsContextLost()) {
1102 layer_tree_host_impl_->Readback(readback_request_on_impl_thread_->pixels,
1103 readback_request_on_impl_thread_->rect);
1104 result.did_readback = true;
1106 readback_request_on_impl_thread_->success = result.did_readback;
1107 readback_request_on_impl_thread_->completion.Signal();
1108 readback_request_on_impl_thread_ = NULL;
1109 } else if (draw_frame) {
1110 DCHECK(swap_requested);
1111 result.did_swap = layer_tree_host_impl_->SwapBuffers(frame);
1113 // We don't know if we have incomplete tiles if we didn't actually swap.
1114 if (result.did_swap) {
1115 DCHECK(!frame.has_no_damage);
1116 SetSwapUsedIncompleteTileOnImplThread(frame.contains_incomplete_tile);
1120 // Tell the main thread that the the newly-commited frame was drawn.
1121 if (next_frame_is_newly_committed_frame_on_impl_thread_) {
1122 next_frame_is_newly_committed_frame_on_impl_thread_ = false;
1123 Proxy::MainThreadTaskRunner()->PostTask(
1125 base::Bind(&ThreadProxy::DidCommitAndDrawFrame, main_thread_weak_ptr_));
1129 CheckOutputSurfaceStatusOnImplThread();
1131 base::TimeDelta draw_duration = base::TimeTicks::HighResNow() - start_time;
1132 draw_duration_history_.InsertSample(draw_duration);
1133 base::TimeDelta draw_duration_overestimate;
1134 base::TimeDelta draw_duration_underestimate;
1135 if (draw_duration > draw_duration_estimate)
1136 draw_duration_underestimate = draw_duration - draw_duration_estimate;
1138 draw_duration_overestimate = draw_duration_estimate - draw_duration;
1139 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.DrawDuration",
1141 base::TimeDelta::FromMilliseconds(1),
1142 base::TimeDelta::FromMilliseconds(100),
1144 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.DrawDurationUnderestimate",
1145 draw_duration_underestimate,
1146 base::TimeDelta::FromMilliseconds(1),
1147 base::TimeDelta::FromMilliseconds(100),
1149 UMA_HISTOGRAM_CUSTOM_TIMES("Renderer.DrawDurationOverestimate",
1150 draw_duration_overestimate,
1151 base::TimeDelta::FromMilliseconds(1),
1152 base::TimeDelta::FromMilliseconds(100),
1159 void ThreadProxy::AcquireLayerTextures() {
1160 // Called when the main thread needs to modify a layer texture that is used
1161 // directly by the compositor.
1162 // This method will block until the next compositor draw if there is a
1163 // previously committed frame that is still undrawn. This is necessary to
1164 // ensure that the main thread does not monopolize access to the textures.
1165 DCHECK(IsMainThread());
1167 if (textures_acquired_)
1170 TRACE_EVENT0("cc", "ThreadProxy::AcquireLayerTextures");
1171 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
1172 CompletionEvent completion;
1173 Proxy::ImplThreadTaskRunner()->PostTask(
1175 base::Bind(&ThreadProxy::AcquireLayerTexturesForMainThreadOnImplThread,
1176 impl_thread_weak_ptr_,
1178 // Block until it is safe to write to layer textures from the main thread.
1181 textures_acquired_ = true;
1182 can_cancel_commit_ = false;
1185 void ThreadProxy::AcquireLayerTexturesForMainThreadOnImplThread(
1186 CompletionEvent* completion) {
1187 DCHECK(IsImplThread());
1188 DCHECK(!texture_acquisition_completion_event_on_impl_thread_);
1190 texture_acquisition_completion_event_on_impl_thread_ = completion;
1191 scheduler_on_impl_thread_->SetMainThreadNeedsLayerTextures();
1194 void ThreadProxy::ScheduledActionAcquireLayerTexturesForMainThread() {
1195 DCHECK(texture_acquisition_completion_event_on_impl_thread_);
1196 texture_acquisition_completion_event_on_impl_thread_->Signal();
1197 texture_acquisition_completion_event_on_impl_thread_ = NULL;
1200 void ThreadProxy::ScheduledActionManageTiles() {
1201 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionManageTiles");
1202 DCHECK(layer_tree_host_impl_->settings().impl_side_painting);
1203 layer_tree_host_impl_->ManageTiles();
1206 DrawSwapReadbackResult ThreadProxy::ScheduledActionDrawAndSwapIfPossible() {
1207 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndSwap");
1208 bool forced_draw = false;
1209 bool swap_requested = true;
1210 bool readback_requested = false;
1211 return DrawSwapReadbackInternal(
1212 forced_draw, swap_requested, readback_requested);
1215 DrawSwapReadbackResult ThreadProxy::ScheduledActionDrawAndSwapForced() {
1216 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndSwapForced");
1217 bool forced_draw = true;
1218 bool swap_requested = true;
1219 bool readback_requested = false;
1220 return DrawSwapReadbackInternal(
1221 forced_draw, swap_requested, readback_requested);
1224 DrawSwapReadbackResult ThreadProxy::ScheduledActionDrawAndReadback() {
1225 TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionDrawAndReadback");
1226 bool forced_draw = true;
1227 bool swap_requested = false;
1228 bool readback_requested = true;
1229 return DrawSwapReadbackInternal(
1230 forced_draw, swap_requested, readback_requested);
1233 void ThreadProxy::DidAnticipatedDrawTimeChange(base::TimeTicks time) {
1234 if (current_resource_update_controller_on_impl_thread_)
1235 current_resource_update_controller_on_impl_thread_->PerformMoreUpdates(
1239 base::TimeDelta ThreadProxy::DrawDurationEstimate() {
1240 base::TimeDelta historical_estimate =
1241 draw_duration_history_.Percentile(kDrawDurationEstimationPercentile);
1242 base::TimeDelta padding = base::TimeDelta::FromMicroseconds(
1243 kDrawDurationEstimatePaddingInMicroseconds);
1244 return historical_estimate + padding;
1247 base::TimeDelta ThreadProxy::BeginMainFrameToCommitDurationEstimate() {
1248 return begin_main_frame_to_commit_duration_history_.Percentile(
1249 kCommitAndActivationDurationEstimationPercentile);
1252 base::TimeDelta ThreadProxy::CommitToActivateDurationEstimate() {
1253 return commit_to_activate_duration_history_.Percentile(
1254 kCommitAndActivationDurationEstimationPercentile);
1257 void ThreadProxy::PostBeginImplFrameDeadline(const base::Closure& closure,
1258 base::TimeTicks deadline) {
1259 base::TimeDelta delta = deadline - gfx::FrameTime::Now();
1260 if (delta <= base::TimeDelta())
1261 delta = base::TimeDelta();
1262 Proxy::ImplThreadTaskRunner()->PostDelayedTask(FROM_HERE, closure, delta);
1265 void ThreadProxy::DidBeginImplFrameDeadline() {
1266 layer_tree_host_impl_->ResetCurrentFrameTimeForNextFrame();
1269 void ThreadProxy::ReadyToFinalizeTextureUpdates() {
1270 DCHECK(IsImplThread());
1271 scheduler_on_impl_thread_->FinishCommit();
1274 void ThreadProxy::DidCommitAndDrawFrame() {
1275 DCHECK(IsMainThread());
1276 if (!layer_tree_host_)
1278 layer_tree_host_->DidCommitAndDrawFrame();
1281 void ThreadProxy::DidCompleteSwapBuffers() {
1282 DCHECK(IsMainThread());
1283 if (!layer_tree_host_)
1285 layer_tree_host_->DidCompleteSwapBuffers();
1288 void ThreadProxy::SetAnimationEvents(scoped_ptr<AnimationEventsVector> events,
1289 base::Time wall_clock_time) {
1290 TRACE_EVENT0("cc", "ThreadProxy::SetAnimationEvents");
1291 DCHECK(IsMainThread());
1292 if (!layer_tree_host_)
1294 layer_tree_host_->SetAnimationEvents(events.Pass(), wall_clock_time);
1297 void ThreadProxy::CreateAndInitializeOutputSurface() {
1298 TRACE_EVENT0("cc", "ThreadProxy::CreateAndInitializeOutputSurface");
1299 DCHECK(IsMainThread());
1301 // Check that output surface has not been recreated by CompositeAndReadback
1302 // after this task is posted but before it is run.
1303 bool has_initialized_output_surface_on_impl_thread = true;
1305 CompletionEvent completion;
1306 Proxy::ImplThreadTaskRunner()->PostTask(
1308 base::Bind(&ThreadProxy::HasInitializedOutputSurfaceOnImplThread,
1309 impl_thread_weak_ptr_,
1311 &has_initialized_output_surface_on_impl_thread));
1314 if (has_initialized_output_surface_on_impl_thread)
1317 layer_tree_host_->DidLoseOutputSurface();
1318 output_surface_creation_callback_.Reset(base::Bind(
1319 &ThreadProxy::DoCreateAndInitializeOutputSurface,
1320 base::Unretained(this)));
1321 output_surface_creation_callback_.callback().Run();
1324 void ThreadProxy::HasInitializedOutputSurfaceOnImplThread(
1325 CompletionEvent* completion,
1326 bool* has_initialized_output_surface) {
1327 DCHECK(IsImplThread());
1328 *has_initialized_output_surface =
1329 scheduler_on_impl_thread_->HasInitializedOutputSurface();
1330 completion->Signal();
1333 void ThreadProxy::InitializeImplOnImplThread(CompletionEvent* completion) {
1334 TRACE_EVENT0("cc", "ThreadProxy::InitializeImplOnImplThread");
1335 DCHECK(IsImplThread());
1336 layer_tree_host_impl_ = layer_tree_host_->CreateLayerTreeHostImpl(this);
1337 const LayerTreeSettings& settings = layer_tree_host_->settings();
1338 SchedulerSettings scheduler_settings;
1339 scheduler_settings.deadline_scheduling_enabled =
1340 settings.deadline_scheduling_enabled;
1341 scheduler_settings.impl_side_painting = settings.impl_side_painting;
1342 scheduler_settings.timeout_and_draw_when_animation_checkerboards =
1343 settings.timeout_and_draw_when_animation_checkerboards;
1344 scheduler_settings.maximum_number_of_failed_draws_before_draw_is_forced_ =
1345 settings.maximum_number_of_failed_draws_before_draw_is_forced_;
1346 scheduler_settings.using_synchronous_renderer_compositor =
1347 settings.using_synchronous_renderer_compositor;
1348 scheduler_settings.throttle_frame_production =
1349 settings.throttle_frame_production;
1350 scheduler_on_impl_thread_ = Scheduler::Create(this, scheduler_settings);
1351 scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible());
1353 impl_thread_weak_ptr_ = weak_factory_on_impl_thread_.GetWeakPtr();
1354 completion->Signal();
1357 void ThreadProxy::InitializeOutputSurfaceOnImplThread(
1358 CompletionEvent* completion,
1359 scoped_ptr<OutputSurface> output_surface,
1360 scoped_refptr<ContextProvider> offscreen_context_provider,
1362 RendererCapabilities* capabilities) {
1363 TRACE_EVENT0("cc", "ThreadProxy::InitializeOutputSurfaceOnImplThread");
1364 DCHECK(IsImplThread());
1365 DCHECK(IsMainThreadBlocked());
1367 DCHECK(capabilities);
1369 layer_tree_host_->DeleteContentsTexturesOnImplThread(
1370 layer_tree_host_impl_->resource_provider());
1372 *success = layer_tree_host_impl_->InitializeRenderer(output_surface.Pass());
1375 *capabilities = layer_tree_host_impl_->GetRendererCapabilities();
1376 scheduler_on_impl_thread_->DidCreateAndInitializeOutputSurface();
1377 } else if (offscreen_context_provider.get()) {
1378 if (offscreen_context_provider->BindToCurrentThread())
1379 offscreen_context_provider->VerifyContexts();
1380 offscreen_context_provider = NULL;
1383 layer_tree_host_impl_->SetOffscreenContextProvider(
1384 offscreen_context_provider);
1386 completion->Signal();
1389 void ThreadProxy::FinishGLOnImplThread(CompletionEvent* completion) {
1390 TRACE_EVENT0("cc", "ThreadProxy::FinishGLOnImplThread");
1391 DCHECK(IsImplThread());
1392 if (layer_tree_host_impl_->resource_provider())
1393 layer_tree_host_impl_->resource_provider()->Finish();
1394 completion->Signal();
1397 void ThreadProxy::LayerTreeHostClosedOnImplThread(CompletionEvent* completion) {
1398 TRACE_EVENT0("cc", "ThreadProxy::LayerTreeHostClosedOnImplThread");
1399 DCHECK(IsImplThread());
1400 layer_tree_host_->DeleteContentsTexturesOnImplThread(
1401 layer_tree_host_impl_->resource_provider());
1402 current_resource_update_controller_on_impl_thread_.reset();
1403 layer_tree_host_impl_->SetNeedsBeginImplFrame(false);
1404 scheduler_on_impl_thread_.reset();
1405 layer_tree_host_impl_.reset();
1406 weak_factory_on_impl_thread_.InvalidateWeakPtrs();
1407 completion->Signal();
1410 size_t ThreadProxy::MaxPartialTextureUpdates() const {
1411 return ResourceUpdateController::MaxPartialTextureUpdates();
1414 ThreadProxy::BeginMainFrameAndCommitState::BeginMainFrameAndCommitState()
1415 : memory_allocation_limit_bytes(0),
1416 memory_allocation_priority_cutoff(0),
1417 evicted_ui_resources(false) {}
1419 ThreadProxy::BeginMainFrameAndCommitState::~BeginMainFrameAndCommitState() {}
1421 scoped_ptr<base::Value> ThreadProxy::AsValue() const {
1422 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
1424 CompletionEvent completion;
1426 DebugScopedSetMainThreadBlocked main_thread_blocked(
1427 const_cast<ThreadProxy*>(this));
1428 Proxy::ImplThreadTaskRunner()->PostTask(
1430 base::Bind(&ThreadProxy::AsValueOnImplThread,
1431 impl_thread_weak_ptr_,
1436 return state.PassAs<base::Value>();
1439 void ThreadProxy::AsValueOnImplThread(CompletionEvent* completion,
1440 base::DictionaryValue* state) const {
1441 state->Set("layer_tree_host_impl",
1442 layer_tree_host_impl_->AsValue().release());
1443 completion->Signal();
1446 bool ThreadProxy::CommitPendingForTesting() {
1447 DCHECK(IsMainThread());
1448 CommitPendingRequest commit_pending_request;
1450 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
1451 Proxy::ImplThreadTaskRunner()->PostTask(
1453 base::Bind(&ThreadProxy::CommitPendingOnImplThreadForTesting,
1454 impl_thread_weak_ptr_,
1455 &commit_pending_request));
1456 commit_pending_request.completion.Wait();
1458 return commit_pending_request.commit_pending;
1461 void ThreadProxy::CommitPendingOnImplThreadForTesting(
1462 CommitPendingRequest* request) {
1463 DCHECK(IsImplThread());
1464 if (layer_tree_host_impl_->output_surface())
1465 request->commit_pending = scheduler_on_impl_thread_->CommitPending();
1467 request->commit_pending = false;
1468 request->completion.Signal();
1471 scoped_ptr<base::Value> ThreadProxy::SchedulerStateAsValueForTesting() {
1473 return scheduler_on_impl_thread_->StateAsValue().Pass();
1475 SchedulerStateRequest scheduler_state_request;
1477 DebugScopedSetMainThreadBlocked main_thread_blocked(this);
1478 Proxy::ImplThreadTaskRunner()->PostTask(
1480 base::Bind(&ThreadProxy::SchedulerStateAsValueOnImplThreadForTesting,
1481 impl_thread_weak_ptr_,
1482 &scheduler_state_request));
1483 scheduler_state_request.completion.Wait();
1485 return scheduler_state_request.state.Pass();
1488 void ThreadProxy::SchedulerStateAsValueOnImplThreadForTesting(
1489 SchedulerStateRequest* request) {
1490 DCHECK(IsImplThread());
1491 request->state = scheduler_on_impl_thread_->StateAsValue();
1492 request->completion.Signal();
1495 void ThreadProxy::RenewTreePriority() {
1496 DCHECK(IsImplThread());
1497 bool smoothness_takes_priority =
1498 layer_tree_host_impl_->pinch_gesture_active() ||
1499 layer_tree_host_impl_->IsCurrentlyScrolling() ||
1500 layer_tree_host_impl_->page_scale_animation_active();
1502 base::TimeTicks now = layer_tree_host_impl_->CurrentPhysicalTimeTicks();
1504 // Update expiration time if smoothness currently takes priority.
1505 if (smoothness_takes_priority) {
1506 smoothness_takes_priority_expiration_time_ =
1507 now + base::TimeDelta::FromMilliseconds(
1508 kSmoothnessTakesPriorityExpirationDelay * 1000);
1511 // We use the same priority for both trees by default.
1512 TreePriority priority = SAME_PRIORITY_FOR_BOTH_TREES;
1514 // Smoothness takes priority if expiration time is in the future.
1515 if (smoothness_takes_priority_expiration_time_ > now)
1516 priority = SMOOTHNESS_TAKES_PRIORITY;
1518 // New content always takes priority when the active tree has
1519 // evicted resources or there is an invalid viewport size.
1520 if (layer_tree_host_impl_->active_tree()->ContentsTexturesPurged() ||
1521 layer_tree_host_impl_->active_tree()->ViewportSizeInvalid() ||
1522 layer_tree_host_impl_->EvictedUIResourcesExist() ||
1523 input_throttled_until_commit_)
1524 priority = NEW_CONTENT_TAKES_PRIORITY;
1526 layer_tree_host_impl_->SetTreePriority(priority);
1527 scheduler_on_impl_thread_->SetSmoothnessTakesPriority(
1528 priority == SMOOTHNESS_TAKES_PRIORITY);
1530 // Notify the the client of this compositor via the output surface.
1531 // TODO(epenner): Route this to compositor-thread instead of output-surface
1532 // after GTFO refactor of compositor-thread (http://crbug/170828).
1533 if (layer_tree_host_impl_->output_surface()) {
1534 layer_tree_host_impl_->output_surface()->
1535 UpdateSmoothnessTakesPriority(priority == SMOOTHNESS_TAKES_PRIORITY);
1538 base::TimeDelta delay = smoothness_takes_priority_expiration_time_ - now;
1540 // Need to make sure a delayed task is posted when we have smoothness
1541 // takes priority expiration time in the future.
1542 if (delay <= base::TimeDelta())
1544 if (renew_tree_priority_on_impl_thread_pending_)
1547 Proxy::ImplThreadTaskRunner()->PostDelayedTask(
1549 base::Bind(&ThreadProxy::RenewTreePriorityOnImplThread,
1550 weak_factory_on_impl_thread_.GetWeakPtr()),
1553 renew_tree_priority_on_impl_thread_pending_ = true;
1556 void ThreadProxy::RenewTreePriorityOnImplThread() {
1557 DCHECK(renew_tree_priority_on_impl_thread_pending_);
1558 renew_tree_priority_on_impl_thread_pending_ = false;
1560 RenewTreePriority();
1563 void ThreadProxy::RequestScrollbarAnimationOnImplThread(base::TimeDelta delay) {
1564 Proxy::ImplThreadTaskRunner()->PostDelayedTask(
1566 base::Bind(&ThreadProxy::StartScrollbarAnimationOnImplThread,
1567 impl_thread_weak_ptr_),
1571 void ThreadProxy::StartScrollbarAnimationOnImplThread() {
1572 layer_tree_host_impl_->StartScrollbarAnimation();
1575 void ThreadProxy::DidActivatePendingTree() {
1576 DCHECK(IsImplThread());
1577 TRACE_EVENT0("cc", "ThreadProxy::DidActivatePendingTreeOnImplThread");
1579 if (completion_event_for_commit_held_on_tree_activation_ &&
1580 !layer_tree_host_impl_->pending_tree()) {
1581 TRACE_EVENT_INSTANT0("cc", "ReleaseCommitbyActivation",
1582 TRACE_EVENT_SCOPE_THREAD);
1583 DCHECK(layer_tree_host_impl_->settings().impl_side_painting);
1584 completion_event_for_commit_held_on_tree_activation_->Signal();
1585 completion_event_for_commit_held_on_tree_activation_ = NULL;
1588 UpdateBackgroundAnimateTicking();
1590 commit_to_activate_duration_history_.InsertSample(
1591 base::TimeTicks::HighResNow() - commit_complete_time_);