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.
4
5#include "cc/trees/single_thread_proxy.h"
6
7#include "base/auto_reset.h"
8#include "base/debug/trace_event.h"
9#include "cc/debug/benchmark_instrumentation.h"
10#include "cc/output/context_provider.h"
11#include "cc/output/output_surface.h"
12#include "cc/quads/draw_quad.h"
13#include "cc/resources/prioritized_resource_manager.h"
14#include "cc/resources/resource_update_controller.h"
15#include "cc/trees/blocking_task_runner.h"
16#include "cc/trees/layer_tree_host.h"
17#include "cc/trees/layer_tree_host_single_thread_client.h"
18#include "cc/trees/layer_tree_impl.h"
19#include "cc/trees/scoped_abort_remaining_swap_promises.h"
20#include "ui/gfx/frame_time.h"
21
22namespace cc {
23
24scoped_ptr<Proxy> SingleThreadProxy::Create(
25    LayerTreeHost* layer_tree_host,
26    LayerTreeHostSingleThreadClient* client,
27    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner) {
28  return make_scoped_ptr(
29             new SingleThreadProxy(layer_tree_host, client, main_task_runner))
30      .PassAs<Proxy>();
31}
32
33SingleThreadProxy::SingleThreadProxy(
34    LayerTreeHost* layer_tree_host,
35    LayerTreeHostSingleThreadClient* client,
36    scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)
37    : Proxy(main_task_runner, NULL),
38      layer_tree_host_(layer_tree_host),
39      client_(client),
40      timing_history_(layer_tree_host->rendering_stats_instrumentation()),
41      next_frame_is_newly_committed_frame_(false),
42      inside_draw_(false),
43      defer_commits_(false),
44      commit_was_deferred_(false),
45      commit_requested_(false),
46      weak_factory_(this) {
47  TRACE_EVENT0("cc", "SingleThreadProxy::SingleThreadProxy");
48  DCHECK(Proxy::IsMainThread());
49  DCHECK(layer_tree_host);
50
51  // Impl-side painting not supported without threaded compositing.
52  CHECK(!layer_tree_host->settings().impl_side_painting)
53      << "Threaded compositing must be enabled to use impl-side painting.";
54}
55
56void SingleThreadProxy::Start() {
57  DebugScopedSetImplThread impl(this);
58  layer_tree_host_impl_ = layer_tree_host_->CreateLayerTreeHostImpl(this);
59}
60
61SingleThreadProxy::~SingleThreadProxy() {
62  TRACE_EVENT0("cc", "SingleThreadProxy::~SingleThreadProxy");
63  DCHECK(Proxy::IsMainThread());
64  // Make sure Stop() got called or never Started.
65  DCHECK(!layer_tree_host_impl_);
66}
67
68void SingleThreadProxy::FinishAllRendering() {
69  TRACE_EVENT0("cc", "SingleThreadProxy::FinishAllRendering");
70  DCHECK(Proxy::IsMainThread());
71  {
72    DebugScopedSetImplThread impl(this);
73    layer_tree_host_impl_->FinishAllRendering();
74  }
75}
76
77bool SingleThreadProxy::IsStarted() const {
78  DCHECK(Proxy::IsMainThread());
79  return layer_tree_host_impl_;
80}
81
82void SingleThreadProxy::SetLayerTreeHostClientReady() {
83  TRACE_EVENT0("cc", "SingleThreadProxy::SetLayerTreeHostClientReady");
84  // Scheduling is controlled by the embedder in the single thread case, so
85  // nothing to do.
86  DCHECK(Proxy::IsMainThread());
87  DebugScopedSetImplThread impl(this);
88  if (layer_tree_host_->settings().single_thread_proxy_scheduler &&
89      !scheduler_on_impl_thread_) {
90    SchedulerSettings scheduler_settings(layer_tree_host_->settings());
91    scheduler_on_impl_thread_ = Scheduler::Create(this,
92                                                  scheduler_settings,
93                                                  layer_tree_host_->id(),
94                                                  MainThreadTaskRunner());
95    scheduler_on_impl_thread_->SetCanStart();
96    scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible());
97  }
98}
99
100void SingleThreadProxy::SetVisible(bool visible) {
101  TRACE_EVENT0("cc", "SingleThreadProxy::SetVisible");
102  DebugScopedSetImplThread impl(this);
103  layer_tree_host_impl_->SetVisible(visible);
104  if (scheduler_on_impl_thread_)
105    scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible());
106  // Changing visibility could change ShouldComposite().
107  UpdateBackgroundAnimateTicking();
108}
109
110void SingleThreadProxy::RequestNewOutputSurface() {
111  DCHECK(Proxy::IsMainThread());
112  DCHECK(layer_tree_host_->output_surface_lost());
113  layer_tree_host_->RequestNewOutputSurface();
114}
115
116void SingleThreadProxy::SetOutputSurface(
117    scoped_ptr<OutputSurface> output_surface) {
118  DCHECK(Proxy::IsMainThread());
119  DCHECK(layer_tree_host_->output_surface_lost());
120  renderer_capabilities_for_main_thread_ = RendererCapabilities();
121
122  bool success = !!output_surface;
123  if (success) {
124    DebugScopedSetMainThreadBlocked main_thread_blocked(this);
125    DebugScopedSetImplThread impl(this);
126    layer_tree_host_->DeleteContentsTexturesOnImplThread(
127        layer_tree_host_impl_->resource_provider());
128    success = layer_tree_host_impl_->InitializeRenderer(output_surface.Pass());
129  }
130
131  layer_tree_host_->OnCreateAndInitializeOutputSurfaceAttempted(success);
132
133  if (success) {
134    if (scheduler_on_impl_thread_)
135      scheduler_on_impl_thread_->DidCreateAndInitializeOutputSurface();
136  } else if (Proxy::MainThreadTaskRunner()) {
137    MainThreadTaskRunner()->PostTask(
138        FROM_HERE,
139        base::Bind(&SingleThreadProxy::RequestNewOutputSurface,
140                   weak_factory_.GetWeakPtr()));
141  }
142}
143
144const RendererCapabilities& SingleThreadProxy::GetRendererCapabilities() const {
145  DCHECK(Proxy::IsMainThread());
146  DCHECK(!layer_tree_host_->output_surface_lost());
147  return renderer_capabilities_for_main_thread_;
148}
149
150void SingleThreadProxy::SetNeedsAnimate() {
151  TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsAnimate");
152  DCHECK(Proxy::IsMainThread());
153  client_->ScheduleAnimation();
154  SetNeedsCommit();
155}
156
157void SingleThreadProxy::SetNeedsUpdateLayers() {
158  TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsUpdateLayers");
159  DCHECK(Proxy::IsMainThread());
160  SetNeedsCommit();
161}
162
163void SingleThreadProxy::DoCommit(const BeginFrameArgs& begin_frame_args) {
164  TRACE_EVENT0("cc", "SingleThreadProxy::DoCommit");
165  DCHECK(Proxy::IsMainThread());
166  layer_tree_host_->WillBeginMainFrame();
167  layer_tree_host_->BeginMainFrame(begin_frame_args);
168  layer_tree_host_->AnimateLayers(begin_frame_args.frame_time);
169  layer_tree_host_->Layout();
170  commit_requested_ = false;
171
172  if (PrioritizedResourceManager* contents_texture_manager =
173          layer_tree_host_->contents_texture_manager()) {
174    contents_texture_manager->UnlinkAndClearEvictedBackings();
175    contents_texture_manager->SetMaxMemoryLimitBytes(
176        layer_tree_host_impl_->memory_allocation_limit_bytes());
177    contents_texture_manager->SetExternalPriorityCutoff(
178        layer_tree_host_impl_->memory_allocation_priority_cutoff());
179  }
180
181  scoped_ptr<ResourceUpdateQueue> queue =
182      make_scoped_ptr(new ResourceUpdateQueue);
183
184  layer_tree_host_->UpdateLayers(queue.get());
185
186  layer_tree_host_->WillCommit();
187
188  // Commit immediately.
189  {
190    DebugScopedSetMainThreadBlocked main_thread_blocked(this);
191    DebugScopedSetImplThread impl(this);
192
193    // This CapturePostTasks should be destroyed before CommitComplete() is
194    // called since that goes out to the embedder, and we want the embedder
195    // to receive its callbacks before that.
196    BlockingTaskRunner::CapturePostTasks blocked(
197        blocking_main_thread_task_runner());
198
199    layer_tree_host_impl_->BeginCommit();
200
201    if (PrioritizedResourceManager* contents_texture_manager =
202        layer_tree_host_->contents_texture_manager()) {
203      contents_texture_manager->PushTexturePrioritiesToBackings();
204    }
205    layer_tree_host_->BeginCommitOnImplThread(layer_tree_host_impl_.get());
206
207    scoped_ptr<ResourceUpdateController> update_controller =
208        ResourceUpdateController::Create(
209            NULL,
210            MainThreadTaskRunner(),
211            queue.Pass(),
212            layer_tree_host_impl_->resource_provider());
213    update_controller->Finalize();
214
215    if (layer_tree_host_impl_->EvictedUIResourcesExist())
216      layer_tree_host_->RecreateUIResources();
217
218    layer_tree_host_->FinishCommitOnImplThread(layer_tree_host_impl_.get());
219
220    layer_tree_host_impl_->CommitComplete();
221
222    UpdateBackgroundAnimateTicking();
223
224#if DCHECK_IS_ON
225    // In the single-threaded case, the scale and scroll deltas should never be
226    // touched on the impl layer tree.
227    scoped_ptr<ScrollAndScaleSet> scroll_info =
228        layer_tree_host_impl_->ProcessScrollDeltas();
229    DCHECK(!scroll_info->scrolls.size());
230    DCHECK_EQ(1.f, scroll_info->page_scale_delta);
231#endif
232
233    RenderingStatsInstrumentation* stats_instrumentation =
234        layer_tree_host_->rendering_stats_instrumentation();
235    benchmark_instrumentation::IssueMainThreadRenderingStatsEvent(
236        stats_instrumentation->main_thread_rendering_stats());
237    stats_instrumentation->AccumulateAndClearMainThreadStats();
238  }
239  layer_tree_host_->CommitComplete();
240  layer_tree_host_->DidBeginMainFrame();
241  timing_history_.DidCommit();
242
243  next_frame_is_newly_committed_frame_ = true;
244}
245
246void SingleThreadProxy::SetNeedsCommit() {
247  DCHECK(Proxy::IsMainThread());
248  DebugScopedSetImplThread impl(this);
249  client_->ScheduleComposite();
250  if (scheduler_on_impl_thread_)
251    scheduler_on_impl_thread_->SetNeedsCommit();
252  commit_requested_ = true;
253}
254
255void SingleThreadProxy::SetNeedsRedraw(const gfx::Rect& damage_rect) {
256  TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsRedraw");
257  DCHECK(Proxy::IsMainThread());
258  DebugScopedSetImplThread impl(this);
259  client_->ScheduleComposite();
260  SetNeedsRedrawRectOnImplThread(damage_rect);
261}
262
263void SingleThreadProxy::SetNextCommitWaitsForActivation() {
264  // There is no activation here other than commit. So do nothing.
265  DCHECK(Proxy::IsMainThread());
266}
267
268void SingleThreadProxy::SetDeferCommits(bool defer_commits) {
269  DCHECK(Proxy::IsMainThread());
270  // Deferring commits only makes sense if there's a scheduler.
271  if (!scheduler_on_impl_thread_)
272    return;
273  if (defer_commits_ == defer_commits)
274    return;
275
276  if (defer_commits)
277    TRACE_EVENT_ASYNC_BEGIN0("cc", "SingleThreadProxy::SetDeferCommits", this);
278  else
279    TRACE_EVENT_ASYNC_END0("cc", "SingleThreadProxy::SetDeferCommits", this);
280
281  defer_commits_ = defer_commits;
282  if (!defer_commits_ && commit_was_deferred_) {
283    commit_was_deferred_ = false;
284    BeginMainFrame();
285  }
286}
287
288bool SingleThreadProxy::CommitRequested() const {
289  DCHECK(Proxy::IsMainThread());
290  return commit_requested_;
291}
292
293bool SingleThreadProxy::BeginMainFrameRequested() const {
294  DCHECK(Proxy::IsMainThread());
295  // If there is no scheduler, then there can be no pending begin frame,
296  // as all frames are all manually initiated by the embedder of cc.
297  if (!scheduler_on_impl_thread_)
298    return false;
299  return commit_requested_;
300}
301
302size_t SingleThreadProxy::MaxPartialTextureUpdates() const {
303  return std::numeric_limits<size_t>::max();
304}
305
306void SingleThreadProxy::Stop() {
307  TRACE_EVENT0("cc", "SingleThreadProxy::stop");
308  DCHECK(Proxy::IsMainThread());
309  {
310    DebugScopedSetMainThreadBlocked main_thread_blocked(this);
311    DebugScopedSetImplThread impl(this);
312
313    BlockingTaskRunner::CapturePostTasks blocked(
314        blocking_main_thread_task_runner());
315    layer_tree_host_->DeleteContentsTexturesOnImplThread(
316        layer_tree_host_impl_->resource_provider());
317    scheduler_on_impl_thread_.reset();
318    layer_tree_host_impl_.reset();
319  }
320  layer_tree_host_ = NULL;
321}
322
323void SingleThreadProxy::OnCanDrawStateChanged(bool can_draw) {
324  TRACE_EVENT1(
325      "cc", "SingleThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw);
326  DCHECK(Proxy::IsImplThread());
327  UpdateBackgroundAnimateTicking();
328  if (scheduler_on_impl_thread_)
329    scheduler_on_impl_thread_->SetCanDraw(can_draw);
330}
331
332void SingleThreadProxy::NotifyReadyToActivate() {
333  // Impl-side painting only.
334  NOTREACHED();
335}
336
337void SingleThreadProxy::SetNeedsRedrawOnImplThread() {
338  client_->ScheduleComposite();
339  if (scheduler_on_impl_thread_)
340    scheduler_on_impl_thread_->SetNeedsRedraw();
341}
342
343void SingleThreadProxy::SetNeedsAnimateOnImplThread() {
344  SetNeedsRedrawOnImplThread();
345}
346
347void SingleThreadProxy::SetNeedsManageTilesOnImplThread() {
348  // Impl-side painting only.
349  NOTREACHED();
350}
351
352void SingleThreadProxy::SetNeedsRedrawRectOnImplThread(
353    const gfx::Rect& damage_rect) {
354  layer_tree_host_impl_->SetViewportDamage(damage_rect);
355  SetNeedsRedrawOnImplThread();
356}
357
358void SingleThreadProxy::DidInitializeVisibleTileOnImplThread() {
359  // Impl-side painting only.
360  NOTREACHED();
361}
362
363void SingleThreadProxy::SetNeedsCommitOnImplThread() {
364  client_->ScheduleComposite();
365  if (scheduler_on_impl_thread_)
366    scheduler_on_impl_thread_->SetNeedsCommit();
367}
368
369void SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread(
370    scoped_ptr<AnimationEventsVector> events) {
371  TRACE_EVENT0(
372      "cc", "SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread");
373  DCHECK(Proxy::IsImplThread());
374  DebugScopedSetMainThread main(this);
375  layer_tree_host_->SetAnimationEvents(events.Pass());
376}
377
378bool SingleThreadProxy::ReduceContentsTextureMemoryOnImplThread(
379    size_t limit_bytes,
380    int priority_cutoff) {
381  DCHECK(IsImplThread());
382  PrioritizedResourceManager* contents_texture_manager =
383      layer_tree_host_->contents_texture_manager();
384
385  ResourceProvider* resource_provider =
386      layer_tree_host_impl_->resource_provider();
387
388  if (!contents_texture_manager || !resource_provider)
389    return false;
390
391  return contents_texture_manager->ReduceMemoryOnImplThread(
392      limit_bytes, priority_cutoff, resource_provider);
393}
394
395bool SingleThreadProxy::IsInsideDraw() { return inside_draw_; }
396
397void SingleThreadProxy::UpdateRendererCapabilitiesOnImplThread() {
398  DCHECK(IsImplThread());
399  renderer_capabilities_for_main_thread_ =
400      layer_tree_host_impl_->GetRendererCapabilities().MainThreadCapabilities();
401}
402
403void SingleThreadProxy::DidManageTiles() {
404  // Impl-side painting only.
405  NOTREACHED();
406}
407
408void SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() {
409  TRACE_EVENT0("cc", "SingleThreadProxy::DidLoseOutputSurfaceOnImplThread");
410  {
411    DebugScopedSetMainThread main(this);
412    // This must happen before we notify the scheduler as it may try to recreate
413    // the output surface if already in BEGIN_IMPL_FRAME_STATE_IDLE.
414    layer_tree_host_->DidLoseOutputSurface();
415  }
416  client_->DidAbortSwapBuffers();
417  if (scheduler_on_impl_thread_)
418    scheduler_on_impl_thread_->DidLoseOutputSurface();
419}
420
421void SingleThreadProxy::DidSwapBuffersOnImplThread() {
422  TRACE_EVENT0("cc", "SingleThreadProxy::DidSwapBuffersOnImplThread");
423  if (scheduler_on_impl_thread_)
424    scheduler_on_impl_thread_->DidSwapBuffers();
425  client_->DidPostSwapBuffers();
426}
427
428void SingleThreadProxy::DidSwapBuffersCompleteOnImplThread() {
429  TRACE_EVENT0("cc", "SingleThreadProxy::DidSwapBuffersCompleteOnImplThread");
430  if (scheduler_on_impl_thread_)
431    scheduler_on_impl_thread_->DidSwapBuffersComplete();
432  layer_tree_host_->DidCompleteSwapBuffers();
433}
434
435void SingleThreadProxy::BeginFrame(const BeginFrameArgs& args) {
436  TRACE_EVENT0("cc", "SingleThreadProxy::BeginFrame");
437  if (scheduler_on_impl_thread_)
438    scheduler_on_impl_thread_->BeginFrame(args);
439}
440
441void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) {
442  TRACE_EVENT0("cc", "SingleThreadProxy::CompositeImmediately");
443  DCHECK(Proxy::IsMainThread());
444  DCHECK(!layer_tree_host_->output_surface_lost());
445
446  BeginFrameArgs begin_frame_args = BeginFrameArgs::Create(
447      frame_begin_time, base::TimeTicks(), BeginFrameArgs::DefaultInterval());
448  DoCommit(begin_frame_args);
449
450  LayerTreeHostImpl::FrameData frame;
451  DoComposite(frame_begin_time, &frame);
452}
453
454void SingleThreadProxy::AsValueInto(base::debug::TracedValue* state) const {
455  // The following line casts away const modifiers because it is just
456  // setting debug state. We still want the AsValue() function and its
457  // call chain to be const throughout.
458  DebugScopedSetImplThread impl(const_cast<SingleThreadProxy*>(this));
459
460  state->BeginDictionary("layer_tree_host_impl");
461  layer_tree_host_impl_->AsValueInto(state);
462  state->EndDictionary();
463}
464
465void SingleThreadProxy::ForceSerializeOnSwapBuffers() {
466  {
467    DebugScopedSetImplThread impl(this);
468    if (layer_tree_host_impl_->renderer()) {
469      DCHECK(!layer_tree_host_->output_surface_lost());
470      layer_tree_host_impl_->renderer()->DoNoOp();
471    }
472  }
473}
474
475bool SingleThreadProxy::SupportsImplScrolling() const {
476  return false;
477}
478
479bool SingleThreadProxy::ShouldComposite() const {
480  DCHECK(Proxy::IsImplThread());
481  return layer_tree_host_impl_->visible() &&
482         layer_tree_host_impl_->CanDraw();
483}
484
485void SingleThreadProxy::UpdateBackgroundAnimateTicking() {
486  DCHECK(Proxy::IsImplThread());
487  layer_tree_host_impl_->UpdateBackgroundAnimateTicking(
488      !ShouldComposite() && layer_tree_host_impl_->active_tree()->root_layer());
489}
490
491DrawResult SingleThreadProxy::DoComposite(base::TimeTicks frame_begin_time,
492                                          LayerTreeHostImpl::FrameData* frame) {
493  TRACE_EVENT0("cc", "SingleThreadProxy::DoComposite");
494  DCHECK(!layer_tree_host_->output_surface_lost());
495
496  {
497    DebugScopedSetImplThread impl(this);
498    base::AutoReset<bool> mark_inside(&inside_draw_, true);
499
500    // We guard PrepareToDraw() with CanDraw() because it always returns a valid
501    // frame, so can only be used when such a frame is possible. Since
502    // DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
503    // CanDraw() as well.
504    if (!ShouldComposite()) {
505      UpdateBackgroundAnimateTicking();
506      return DRAW_ABORTED_CANT_DRAW;
507    }
508
509    timing_history_.DidStartDrawing();
510
511    layer_tree_host_impl_->Animate(
512        layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time);
513    UpdateBackgroundAnimateTicking();
514
515    layer_tree_host_impl_->PrepareToDraw(frame);
516    layer_tree_host_impl_->DrawLayers(frame, frame_begin_time);
517    layer_tree_host_impl_->DidDrawAllLayers(*frame);
518
519    bool start_ready_animations = true;
520    layer_tree_host_impl_->UpdateAnimationState(start_ready_animations);
521
522    layer_tree_host_impl_->ResetCurrentBeginFrameArgsForNextFrame();
523
524    timing_history_.DidFinishDrawing();
525  }
526
527  {
528    DebugScopedSetImplThread impl(this);
529
530    // This CapturePostTasks should be destroyed before
531    // DidCommitAndDrawFrame() is called since that goes out to the
532    // embedder,
533    // and we want the embedder to receive its callbacks before that.
534    // NOTE: This maintains consistent ordering with the ThreadProxy since
535    // the DidCommitAndDrawFrame() must be post-tasked from the impl thread
536    // there as the main thread is not blocked, so any posted tasks inside
537    // the swap buffers will execute first.
538    DebugScopedSetMainThreadBlocked main_thread_blocked(this);
539
540    BlockingTaskRunner::CapturePostTasks blocked(
541        blocking_main_thread_task_runner());
542    layer_tree_host_impl_->SwapBuffers(*frame);
543  }
544  DidCommitAndDrawFrame();
545
546  return DRAW_SUCCESS;
547}
548
549void SingleThreadProxy::DidCommitAndDrawFrame() {
550  if (next_frame_is_newly_committed_frame_) {
551    DebugScopedSetMainThread main(this);
552    next_frame_is_newly_committed_frame_ = false;
553    layer_tree_host_->DidCommitAndDrawFrame();
554  }
555}
556
557bool SingleThreadProxy::MainFrameWillHappenForTesting() {
558  return false;
559}
560
561void SingleThreadProxy::SetNeedsBeginFrame(bool enable) {
562  layer_tree_host_impl_->SetNeedsBeginFrame(enable);
563}
564
565void SingleThreadProxy::WillBeginImplFrame(const BeginFrameArgs& args) {
566  layer_tree_host_impl_->WillBeginImplFrame(args);
567}
568
569void SingleThreadProxy::ScheduledActionSendBeginMainFrame() {
570  TRACE_EVENT0("cc", "SingleThreadProxy::ScheduledActionSendBeginMainFrame");
571  // Although this proxy is single-threaded, it's problematic to synchronously
572  // have BeginMainFrame happen after ScheduledActionSendBeginMainFrame.  This
573  // could cause a commit to occur in between a series of SetNeedsCommit calls
574  // (i.e. property modifications) causing some to fall on one frame and some to
575  // fall on the next.  Doing it asynchronously instead matches the semantics of
576  // ThreadProxy::SetNeedsCommit where SetNeedsCommit will not cause a
577  // synchronous commit.
578  MainThreadTaskRunner()->PostTask(
579      FROM_HERE,
580      base::Bind(&SingleThreadProxy::BeginMainFrame,
581                 weak_factory_.GetWeakPtr()));
582}
583
584void SingleThreadProxy::BeginMainFrame() {
585  if (defer_commits_) {
586    DCHECK(!commit_was_deferred_);
587    commit_was_deferred_ = true;
588    layer_tree_host_->DidDeferCommit();
589    return;
590  }
591
592  // This checker assumes NotifyReadyToCommit below causes a synchronous commit.
593  ScopedAbortRemainingSwapPromises swap_promise_checker(layer_tree_host_);
594
595  if (!layer_tree_host_->visible()) {
596    TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD);
597    BeginMainFrameAbortedOnImplThread();
598    return;
599  }
600
601  if (layer_tree_host_->output_surface_lost()) {
602    TRACE_EVENT_INSTANT0(
603        "cc", "EarlyOut_OutputSurfaceLost", TRACE_EVENT_SCOPE_THREAD);
604    BeginMainFrameAbortedOnImplThread();
605    return;
606  }
607
608  timing_history_.DidBeginMainFrame();
609
610  DCHECK(scheduler_on_impl_thread_);
611  scheduler_on_impl_thread_->NotifyBeginMainFrameStarted();
612  scheduler_on_impl_thread_->NotifyReadyToCommit();
613}
614
615void SingleThreadProxy::BeginMainFrameAbortedOnImplThread() {
616  DebugScopedSetImplThread impl(this);
617  DCHECK(scheduler_on_impl_thread_->CommitPending());
618  DCHECK(!layer_tree_host_impl_->pending_tree());
619
620  // TODO(enne): SingleThreadProxy does not support cancelling commits yet so
621  // did_handle is always false.
622  bool did_handle = false;
623  layer_tree_host_impl_->BeginMainFrameAborted(did_handle);
624  scheduler_on_impl_thread_->BeginMainFrameAborted(did_handle);
625}
626
627DrawResult SingleThreadProxy::ScheduledActionDrawAndSwapIfPossible() {
628  DebugScopedSetImplThread impl(this);
629  LayerTreeHostImpl::FrameData frame;
630  return DoComposite(layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time,
631                     &frame);
632}
633
634DrawResult SingleThreadProxy::ScheduledActionDrawAndSwapForced() {
635  NOTREACHED();
636  return INVALID_RESULT;
637}
638
639void SingleThreadProxy::ScheduledActionCommit() {
640  DebugScopedSetMainThread main(this);
641  DoCommit(layer_tree_host_impl_->CurrentBeginFrameArgs());
642}
643
644void SingleThreadProxy::ScheduledActionAnimate() {
645  TRACE_EVENT0("cc", "ScheduledActionAnimate");
646  layer_tree_host_impl_->Animate(
647      layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time);
648}
649
650void SingleThreadProxy::ScheduledActionUpdateVisibleTiles() {
651  // Impl-side painting only.
652  NOTREACHED();
653}
654
655void SingleThreadProxy::ScheduledActionActivateSyncTree() {
656}
657
658void SingleThreadProxy::ScheduledActionBeginOutputSurfaceCreation() {
659  DebugScopedSetMainThread main(this);
660  DCHECK(scheduler_on_impl_thread_);
661  // If possible, create the output surface in a post task.  Synchronously
662  // creating the output surface makes tests more awkward since this differs
663  // from the ThreadProxy behavior.  However, sometimes there is no
664  // task runner.
665  if (Proxy::MainThreadTaskRunner()) {
666    MainThreadTaskRunner()->PostTask(
667        FROM_HERE,
668        base::Bind(&SingleThreadProxy::RequestNewOutputSurface,
669                   weak_factory_.GetWeakPtr()));
670  } else {
671    RequestNewOutputSurface();
672  }
673}
674
675void SingleThreadProxy::ScheduledActionManageTiles() {
676  // Impl-side painting only.
677  NOTREACHED();
678}
679
680void SingleThreadProxy::DidAnticipatedDrawTimeChange(base::TimeTicks time) {
681}
682
683base::TimeDelta SingleThreadProxy::DrawDurationEstimate() {
684  return timing_history_.DrawDurationEstimate();
685}
686
687base::TimeDelta SingleThreadProxy::BeginMainFrameToCommitDurationEstimate() {
688  return timing_history_.BeginMainFrameToCommitDurationEstimate();
689}
690
691base::TimeDelta SingleThreadProxy::CommitToActivateDurationEstimate() {
692  return timing_history_.CommitToActivateDurationEstimate();
693}
694
695void SingleThreadProxy::DidBeginImplFrameDeadline() {
696  layer_tree_host_impl_->ResetCurrentBeginFrameArgsForNextFrame();
697}
698
699}  // namespace cc
700