Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / cc / scheduler / scheduler.cc
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/scheduler/scheduler.h"
6
7 #include <algorithm>
8 #include "base/auto_reset.h"
9 #include "base/debug/trace_event.h"
10 #include "base/logging.h"
11 #include "cc/debug/devtools_instrumentation.h"
12 #include "cc/debug/traced_value.h"
13 #include "cc/scheduler/delay_based_time_source.h"
14 #include "ui/gfx/frame_time.h"
15
16 namespace cc {
17
18 class SyntheticBeginFrameSource : public TimeSourceClient {
19  public:
20   SyntheticBeginFrameSource(Scheduler* scheduler,
21                             base::SingleThreadTaskRunner* task_runner)
22       : scheduler_(scheduler) {
23     if (gfx::FrameTime::TimestampsAreHighRes()) {
24       time_source_ = DelayBasedTimeSourceHighRes::Create(
25           scheduler_->VSyncInterval(), task_runner);
26     } else {
27       time_source_ = DelayBasedTimeSource::Create(scheduler_->VSyncInterval(),
28                                                   task_runner);
29     }
30     time_source_->SetClient(this);
31   }
32
33   virtual ~SyntheticBeginFrameSource() {}
34
35   // Updates the phase and frequency of the timer.
36   void CommitVSyncParameters(base::TimeTicks timebase,
37                              base::TimeDelta interval) {
38     time_source_->SetTimebaseAndInterval(timebase, interval);
39   }
40
41   // Activates future BeginFrames and, if activating, pushes the most
42   // recently missed BeginFrame to the back of a retroactive queue.
43   void SetNeedsBeginFrame(bool needs_begin_frame,
44                           std::deque<BeginFrameArgs>* begin_retro_frame_args) {
45     base::TimeTicks missed_tick_time =
46         time_source_->SetActive(needs_begin_frame);
47     if (!missed_tick_time.is_null()) {
48       begin_retro_frame_args->push_back(
49           CreateSyntheticBeginFrameArgs(missed_tick_time));
50     }
51   }
52
53   // TimeSourceClient implementation of OnTimerTick triggers a BeginFrame.
54   virtual void OnTimerTick() OVERRIDE {
55     BeginFrameArgs begin_frame_args(
56         CreateSyntheticBeginFrameArgs(time_source_->LastTickTime()));
57     scheduler_->BeginFrame(begin_frame_args);
58   }
59
60  private:
61   BeginFrameArgs CreateSyntheticBeginFrameArgs(base::TimeTicks frame_time) {
62     base::TimeTicks deadline =
63         time_source_->NextTickTime() - scheduler_->EstimatedParentDrawTime();
64     return BeginFrameArgs::Create(
65         frame_time, deadline, scheduler_->VSyncInterval());
66   }
67
68   Scheduler* scheduler_;
69   scoped_refptr<TimeSource> time_source_;
70 };
71
72 Scheduler::Scheduler(
73     SchedulerClient* client,
74     const SchedulerSettings& scheduler_settings,
75     int layer_tree_host_id,
76     const scoped_refptr<base::SingleThreadTaskRunner>& impl_task_runner)
77     : settings_(scheduler_settings),
78       client_(client),
79       layer_tree_host_id_(layer_tree_host_id),
80       impl_task_runner_(impl_task_runner),
81       vsync_interval_(BeginFrameArgs::DefaultInterval()),
82       last_set_needs_begin_frame_(false),
83       begin_unthrottled_frame_posted_(false),
84       begin_retro_frame_posted_(false),
85       state_machine_(scheduler_settings),
86       inside_process_scheduled_actions_(false),
87       inside_action_(SchedulerStateMachine::ACTION_NONE),
88       weak_factory_(this) {
89   DCHECK(client_);
90   DCHECK(!state_machine_.BeginFrameNeeded());
91   if (settings_.main_frame_before_activation_enabled) {
92     DCHECK(settings_.main_frame_before_draw_enabled);
93   }
94
95   begin_retro_frame_closure_ =
96       base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr());
97   begin_unthrottled_frame_closure_ =
98       base::Bind(&Scheduler::BeginUnthrottledFrame, weak_factory_.GetWeakPtr());
99   begin_impl_frame_deadline_closure_ = base::Bind(
100       &Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr());
101   poll_for_draw_triggers_closure_ = base::Bind(
102       &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr());
103   advance_commit_state_closure_ = base::Bind(
104       &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr());
105
106   if (!settings_.begin_frame_scheduling_enabled) {
107     SetupSyntheticBeginFrames();
108   }
109 }
110
111 Scheduler::~Scheduler() {
112   if (synthetic_begin_frame_source_) {
113     synthetic_begin_frame_source_->SetNeedsBeginFrame(false,
114                                                       &begin_retro_frame_args_);
115   }
116 }
117
118 void Scheduler::SetupSyntheticBeginFrames() {
119   DCHECK(!synthetic_begin_frame_source_);
120   synthetic_begin_frame_source_.reset(
121       new SyntheticBeginFrameSource(this, impl_task_runner_.get()));
122 }
123
124 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase,
125                                       base::TimeDelta interval) {
126   // TODO(brianderson): We should not be receiving 0 intervals.
127   if (interval == base::TimeDelta())
128     interval = BeginFrameArgs::DefaultInterval();
129   vsync_interval_ = interval;
130   if (!settings_.begin_frame_scheduling_enabled)
131     synthetic_begin_frame_source_->CommitVSyncParameters(timebase, interval);
132 }
133
134 void Scheduler::SetEstimatedParentDrawTime(base::TimeDelta draw_time) {
135   estimated_parent_draw_time_ = draw_time;
136 }
137
138 void Scheduler::SetCanStart() {
139   state_machine_.SetCanStart();
140   ProcessScheduledActions();
141 }
142
143 void Scheduler::SetVisible(bool visible) {
144   state_machine_.SetVisible(visible);
145   ProcessScheduledActions();
146 }
147
148 void Scheduler::SetCanDraw(bool can_draw) {
149   state_machine_.SetCanDraw(can_draw);
150   ProcessScheduledActions();
151 }
152
153 void Scheduler::NotifyReadyToActivate() {
154   state_machine_.NotifyReadyToActivate();
155   ProcessScheduledActions();
156 }
157
158 void Scheduler::ActivatePendingTree() {
159   client_->ScheduledActionActivatePendingTree();
160 }
161
162 void Scheduler::SetNeedsCommit() {
163   state_machine_.SetNeedsCommit();
164   ProcessScheduledActions();
165 }
166
167 void Scheduler::SetNeedsForcedCommitForReadback() {
168   state_machine_.SetNeedsForcedCommitForReadback();
169   ProcessScheduledActions();
170 }
171
172 void Scheduler::SetNeedsRedraw() {
173   state_machine_.SetNeedsRedraw();
174   ProcessScheduledActions();
175 }
176
177 void Scheduler::SetNeedsAnimate() {
178   state_machine_.SetNeedsAnimate();
179   ProcessScheduledActions();
180 }
181
182 void Scheduler::SetNeedsManageTiles() {
183   DCHECK(!IsInsideAction(SchedulerStateMachine::ACTION_MANAGE_TILES));
184   state_machine_.SetNeedsManageTiles();
185   ProcessScheduledActions();
186 }
187
188 void Scheduler::SetMaxSwapsPending(int max) {
189   state_machine_.SetMaxSwapsPending(max);
190 }
191
192 void Scheduler::DidSwapBuffers() {
193   state_machine_.DidSwapBuffers();
194   // There is no need to call ProcessScheduledActions here because
195   // swapping should not trigger any new actions.
196   if (!inside_process_scheduled_actions_) {
197     DCHECK_EQ(state_machine_.NextAction(), SchedulerStateMachine::ACTION_NONE);
198   }
199 }
200
201 void Scheduler::SetSwapUsedIncompleteTile(bool used_incomplete_tile) {
202   state_machine_.SetSwapUsedIncompleteTile(used_incomplete_tile);
203   ProcessScheduledActions();
204 }
205
206 void Scheduler::DidSwapBuffersComplete() {
207   state_machine_.DidSwapBuffersComplete();
208   ProcessScheduledActions();
209 }
210
211 void Scheduler::SetSmoothnessTakesPriority(bool smoothness_takes_priority) {
212   state_machine_.SetSmoothnessTakesPriority(smoothness_takes_priority);
213   ProcessScheduledActions();
214 }
215
216 void Scheduler::NotifyReadyToCommit() {
217   TRACE_EVENT0("cc", "Scheduler::NotifyReadyToCommit");
218   state_machine_.NotifyReadyToCommit();
219   ProcessScheduledActions();
220 }
221
222 void Scheduler::BeginMainFrameAborted(bool did_handle) {
223   TRACE_EVENT0("cc", "Scheduler::BeginMainFrameAborted");
224   state_machine_.BeginMainFrameAborted(did_handle);
225   ProcessScheduledActions();
226 }
227
228 void Scheduler::DidManageTiles() {
229   state_machine_.DidManageTiles();
230 }
231
232 void Scheduler::DidLoseOutputSurface() {
233   TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface");
234   state_machine_.DidLoseOutputSurface();
235   last_set_needs_begin_frame_ = false;
236   begin_retro_frame_args_.clear();
237   ProcessScheduledActions();
238 }
239
240 void Scheduler::DidCreateAndInitializeOutputSurface() {
241   TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface");
242   DCHECK(!last_set_needs_begin_frame_);
243   DCHECK(begin_impl_frame_deadline_task_.IsCancelled());
244   state_machine_.DidCreateAndInitializeOutputSurface();
245   ProcessScheduledActions();
246 }
247
248 void Scheduler::NotifyBeginMainFrameStarted() {
249   TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted");
250   state_machine_.NotifyBeginMainFrameStarted();
251 }
252
253 base::TimeTicks Scheduler::AnticipatedDrawTime() const {
254   if (!last_set_needs_begin_frame_ ||
255       begin_impl_frame_args_.interval <= base::TimeDelta())
256     return base::TimeTicks();
257
258   base::TimeTicks now = gfx::FrameTime::Now();
259   base::TimeTicks timebase = std::max(begin_impl_frame_args_.frame_time,
260                                       begin_impl_frame_args_.deadline);
261   int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval);
262   return timebase + (begin_impl_frame_args_.interval * intervals);
263 }
264
265 base::TimeTicks Scheduler::LastBeginImplFrameTime() {
266   return begin_impl_frame_args_.frame_time;
267 }
268
269 void Scheduler::SetupNextBeginFrameIfNeeded() {
270   bool needs_begin_frame = state_machine_.BeginFrameNeeded();
271
272   if (settings_.throttle_frame_production) {
273     SetupNextBeginFrameWhenVSyncThrottlingEnabled(needs_begin_frame);
274   } else {
275     SetupNextBeginFrameWhenVSyncThrottlingDisabled(needs_begin_frame);
276   }
277   SetupPollingMechanisms(needs_begin_frame);
278 }
279
280 // When we are throttling frame production, we request BeginFrames
281 // from the OutputSurface.
282 void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingEnabled(
283     bool needs_begin_frame) {
284   bool at_end_of_deadline =
285       state_machine_.begin_impl_frame_state() ==
286           SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE;
287
288   bool should_call_set_needs_begin_frame =
289       // Always request the BeginFrame immediately if it wasn't needed before.
290       (needs_begin_frame && !last_set_needs_begin_frame_) ||
291       // Only stop requesting BeginFrames after a deadline.
292       (!needs_begin_frame && last_set_needs_begin_frame_ && at_end_of_deadline);
293
294   if (should_call_set_needs_begin_frame) {
295     if (settings_.begin_frame_scheduling_enabled) {
296       client_->SetNeedsBeginFrame(needs_begin_frame);
297     } else {
298       synthetic_begin_frame_source_->SetNeedsBeginFrame(
299           needs_begin_frame, &begin_retro_frame_args_);
300     }
301     last_set_needs_begin_frame_ = needs_begin_frame;
302   }
303
304   PostBeginRetroFrameIfNeeded();
305 }
306
307 // When we aren't throttling frame production, we initiate a BeginFrame
308 // as soon as one is needed.
309 void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingDisabled(
310     bool needs_begin_frame) {
311   last_set_needs_begin_frame_ = needs_begin_frame;
312
313   if (!needs_begin_frame || begin_unthrottled_frame_posted_)
314     return;
315
316   if (state_machine_.begin_impl_frame_state() !=
317           SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE &&
318       state_machine_.begin_impl_frame_state() !=
319           SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) {
320     return;
321   }
322
323   begin_unthrottled_frame_posted_ = true;
324   impl_task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_);
325 }
326
327 // BeginUnthrottledFrame is used when we aren't throttling frame production.
328 // This will usually be because VSync is disabled.
329 void Scheduler::BeginUnthrottledFrame() {
330   DCHECK(!settings_.throttle_frame_production);
331   DCHECK(begin_retro_frame_args_.empty());
332
333   base::TimeTicks now = gfx::FrameTime::Now();
334   base::TimeTicks deadline = now + vsync_interval_;
335
336   BeginFrameArgs begin_frame_args =
337       BeginFrameArgs::Create(now, deadline, vsync_interval_);
338   BeginImplFrame(begin_frame_args);
339
340   begin_unthrottled_frame_posted_ = false;
341 }
342
343 // We may need to poll when we can't rely on BeginFrame to advance certain
344 // state or to avoid deadlock.
345 void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) {
346   bool needs_advance_commit_state_timer = false;
347   // Setup PollForAnticipatedDrawTriggers if we need to monitor state but
348   // aren't expecting any more BeginFrames. This should only be needed by
349   // the synchronous compositor when BeginFrameNeeded is false.
350   if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) {
351     DCHECK(!state_machine_.SupportsProactiveBeginFrame());
352     DCHECK(!needs_begin_frame);
353     if (poll_for_draw_triggers_task_.IsCancelled()) {
354       poll_for_draw_triggers_task_.Reset(poll_for_draw_triggers_closure_);
355       base::TimeDelta delay = begin_impl_frame_args_.IsValid()
356                                   ? begin_impl_frame_args_.interval
357                                   : BeginFrameArgs::DefaultInterval();
358       impl_task_runner_->PostDelayedTask(
359           FROM_HERE, poll_for_draw_triggers_task_.callback(), delay);
360     }
361   } else {
362     poll_for_draw_triggers_task_.Cancel();
363
364     // At this point we'd prefer to advance through the commit flow by
365     // drawing a frame, however it's possible that the frame rate controller
366     // will not give us a BeginFrame until the commit completes.  See
367     // crbug.com/317430 for an example of a swap ack being held on commit. Thus
368     // we set a repeating timer to poll on ProcessScheduledActions until we
369     // successfully reach BeginFrame. Synchronous compositor does not use
370     // frame rate controller or have the circular wait in the bug.
371     if (IsBeginMainFrameSentOrStarted() &&
372         !settings_.using_synchronous_renderer_compositor) {
373       needs_advance_commit_state_timer = true;
374     }
375   }
376
377   if (needs_advance_commit_state_timer) {
378     if (advance_commit_state_task_.IsCancelled() &&
379         begin_impl_frame_args_.IsValid()) {
380       // Since we'd rather get a BeginImplFrame by the normal mechanism, we
381       // set the interval to twice the interval from the previous frame.
382       advance_commit_state_task_.Reset(advance_commit_state_closure_);
383       impl_task_runner_->PostDelayedTask(FROM_HERE,
384                                          advance_commit_state_task_.callback(),
385                                          begin_impl_frame_args_.interval * 2);
386     }
387   } else {
388     advance_commit_state_task_.Cancel();
389   }
390 }
391
392 // BeginFrame is the mechanism that tells us that now is a good time to start
393 // making a frame. Usually this means that user input for the frame is complete.
394 // If the scheduler is busy, we queue the BeginFrame to be handled later as
395 // a BeginRetroFrame.
396 void Scheduler::BeginFrame(const BeginFrameArgs& args) {
397   TRACE_EVENT1("cc", "Scheduler::BeginFrame", "frame_time", args.frame_time);
398   DCHECK(settings_.throttle_frame_production);
399
400   bool should_defer_begin_frame;
401   if (settings_.using_synchronous_renderer_compositor) {
402     should_defer_begin_frame = false;
403   } else {
404     should_defer_begin_frame =
405         !begin_retro_frame_args_.empty() || begin_retro_frame_posted_ ||
406         !last_set_needs_begin_frame_ ||
407         (state_machine_.begin_impl_frame_state() !=
408          SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
409   }
410
411   if (should_defer_begin_frame) {
412     begin_retro_frame_args_.push_back(args);
413     TRACE_EVENT_INSTANT0(
414         "cc", "Scheduler::BeginFrame deferred", TRACE_EVENT_SCOPE_THREAD);
415     return;
416   }
417
418   BeginImplFrame(args);
419 }
420
421 // BeginRetroFrame is called for BeginFrames that we've deferred because
422 // the scheduler was in the middle of processing a previous BeginFrame.
423 void Scheduler::BeginRetroFrame() {
424   TRACE_EVENT0("cc", "Scheduler::BeginRetroFrame");
425   DCHECK(!settings_.using_synchronous_renderer_compositor);
426   DCHECK(begin_retro_frame_posted_);
427   begin_retro_frame_posted_ = false;
428
429   // If there aren't any retroactive BeginFrames, then we've lost the
430   // OutputSurface and should abort.
431   if (begin_retro_frame_args_.empty())
432     return;
433
434   // Discard expired BeginRetroFrames
435   // Today, we should always end up with at most one un-expired BeginRetroFrame
436   // because deadlines will not be greater than the next frame time. We don't
437   // DCHECK though because some systems don't always have monotonic timestamps.
438   // TODO(brianderson): In the future, long deadlines could result in us not
439   // draining the queue if we don't catch up. If we consistently can't catch
440   // up, our fallback should be to lower our frame rate.
441   base::TimeTicks now = gfx::FrameTime::Now();
442   base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate();
443   while (!begin_retro_frame_args_.empty() &&
444          now > AdjustedBeginImplFrameDeadline(begin_retro_frame_args_.front(),
445                                               draw_duration_estimate)) {
446     TRACE_EVENT1("cc",
447                  "Scheduler::BeginRetroFrame discarding",
448                  "frame_time",
449                  begin_retro_frame_args_.front().frame_time);
450     begin_retro_frame_args_.pop_front();
451   }
452
453   if (begin_retro_frame_args_.empty()) {
454     DCHECK(settings_.throttle_frame_production);
455     TRACE_EVENT_INSTANT0("cc",
456                          "Scheduler::BeginRetroFrames all expired",
457                          TRACE_EVENT_SCOPE_THREAD);
458   } else {
459     BeginImplFrame(begin_retro_frame_args_.front());
460     begin_retro_frame_args_.pop_front();
461   }
462 }
463
464 // There could be a race between the posted BeginRetroFrame and a new
465 // BeginFrame arriving via the normal mechanism. Scheduler::BeginFrame
466 // will check if there is a pending BeginRetroFrame to ensure we handle
467 // BeginFrames in FIFO order.
468 void Scheduler::PostBeginRetroFrameIfNeeded() {
469   if (!last_set_needs_begin_frame_)
470     return;
471
472   if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_)
473     return;
474
475   // begin_retro_frame_args_ should always be empty for the
476   // synchronous compositor.
477   DCHECK(!settings_.using_synchronous_renderer_compositor);
478
479   if (state_machine_.begin_impl_frame_state() !=
480       SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE)
481     return;
482
483   begin_retro_frame_posted_ = true;
484   impl_task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_);
485 }
486
487 // BeginImplFrame starts a compositor frame that will wait up until a deadline
488 // for a BeginMainFrame+activation to complete before it times out and draws
489 // any asynchronous animation and scroll/pinch updates.
490 void Scheduler::BeginImplFrame(const BeginFrameArgs& args) {
491   TRACE_EVENT1(
492       "cc", "Scheduler::BeginImplFrame", "frame_time", args.frame_time);
493   DCHECK(state_machine_.begin_impl_frame_state() ==
494          SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
495   DCHECK(state_machine_.HasInitializedOutputSurface());
496
497   advance_commit_state_task_.Cancel();
498
499   base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate();
500   begin_impl_frame_args_ = args;
501   begin_impl_frame_args_.deadline -= draw_duration_estimate;
502
503   if (!state_machine_.smoothness_takes_priority() &&
504       state_machine_.MainThreadIsInHighLatencyMode() &&
505       CanCommitAndActivateBeforeDeadline()) {
506     state_machine_.SetSkipNextBeginMainFrameToReduceLatency();
507   }
508
509   client_->WillBeginImplFrame(begin_impl_frame_args_);
510   state_machine_.OnBeginImplFrame(begin_impl_frame_args_);
511   devtools_instrumentation::DidBeginFrame(layer_tree_host_id_);
512
513   ProcessScheduledActions();
514
515   state_machine_.OnBeginImplFrameDeadlinePending();
516   ScheduleBeginImplFrameDeadline(
517       AdjustedBeginImplFrameDeadline(args, draw_duration_estimate));
518 }
519
520 base::TimeTicks Scheduler::AdjustedBeginImplFrameDeadline(
521     const BeginFrameArgs& args,
522     base::TimeDelta draw_duration_estimate) const {
523   if (settings_.using_synchronous_renderer_compositor) {
524     // The synchronous compositor needs to draw right away.
525     return base::TimeTicks();
526   } else if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) {
527     // We are ready to draw a new active tree immediately.
528     return base::TimeTicks();
529   } else if (state_machine_.needs_redraw()) {
530     // We have an animation or fast input path on the impl thread that wants
531     // to draw, so don't wait too long for a new active tree.
532     return args.deadline - draw_duration_estimate;
533   } else {
534     // The impl thread doesn't have anything it wants to draw and we are just
535     // waiting for a new active tree, so post the deadline for the next
536     // expected BeginImplFrame start. This allows us to draw immediately when
537     // there is a new active tree, instead of waiting for the next
538     // BeginImplFrame.
539     // TODO(brianderson): Handle long deadlines (that are past the next frame's
540     // frame time) properly instead of using this hack.
541     return args.frame_time + args.interval;
542   }
543 }
544
545 void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) {
546   if (settings_.using_synchronous_renderer_compositor) {
547     // The synchronous renderer compositor has to make its GL calls
548     // within this call.
549     // TODO(brianderson): Have the OutputSurface initiate the deadline tasks
550     // so the sychronous renderer compositor can take advantage of splitting
551     // up the BeginImplFrame and deadline as well.
552     OnBeginImplFrameDeadline();
553     return;
554   }
555   begin_impl_frame_deadline_task_.Cancel();
556   begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_);
557
558   base::TimeDelta delta = deadline - gfx::FrameTime::Now();
559   if (delta <= base::TimeDelta())
560     delta = base::TimeDelta();
561   impl_task_runner_->PostDelayedTask(
562       FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta);
563 }
564
565 void Scheduler::OnBeginImplFrameDeadline() {
566   TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline");
567   begin_impl_frame_deadline_task_.Cancel();
568
569   // We split the deadline actions up into two phases so the state machine
570   // has a chance to trigger actions that should occur durring and after
571   // the deadline separately. For example:
572   // * Sending the BeginMainFrame will not occur after the deadline in
573   //     order to wait for more user-input before starting the next commit.
574   // * Creating a new OuputSurface will not occur during the deadline in
575   //     order to allow the state machine to "settle" first.
576   state_machine_.OnBeginImplFrameDeadline();
577   ProcessScheduledActions();
578   state_machine_.OnBeginImplFrameIdle();
579   ProcessScheduledActions();
580
581   client_->DidBeginImplFrameDeadline();
582 }
583
584 void Scheduler::PollForAnticipatedDrawTriggers() {
585   TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers");
586   poll_for_draw_triggers_task_.Cancel();
587   state_machine_.DidEnterPollForAnticipatedDrawTriggers();
588   ProcessScheduledActions();
589   state_machine_.DidLeavePollForAnticipatedDrawTriggers();
590 }
591
592 void Scheduler::PollToAdvanceCommitState() {
593   TRACE_EVENT0("cc", "Scheduler::PollToAdvanceCommitState");
594   advance_commit_state_task_.Cancel();
595   ProcessScheduledActions();
596 }
597
598 bool Scheduler::IsBeginMainFrameSent() const {
599   return state_machine_.commit_state() ==
600          SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT;
601 }
602
603 void Scheduler::DrawAndSwapIfPossible() {
604   DrawSwapReadbackResult result =
605       client_->ScheduledActionDrawAndSwapIfPossible();
606   state_machine_.DidDrawIfPossibleCompleted(result.draw_result);
607 }
608
609 void Scheduler::DrawAndSwapForced() {
610   client_->ScheduledActionDrawAndSwapForced();
611 }
612
613 void Scheduler::DrawAndReadback() {
614   DrawSwapReadbackResult result = client_->ScheduledActionDrawAndReadback();
615   DCHECK(!result.did_request_swap);
616 }
617
618 void Scheduler::ProcessScheduledActions() {
619   // We do not allow ProcessScheduledActions to be recursive.
620   // The top-level call will iteratively execute the next action for us anyway.
621   if (inside_process_scheduled_actions_)
622     return;
623
624   base::AutoReset<bool> mark_inside(&inside_process_scheduled_actions_, true);
625
626   SchedulerStateMachine::Action action;
627   do {
628     state_machine_.CheckInvariants();
629     action = state_machine_.NextAction();
630     TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
631                  "SchedulerStateMachine",
632                  "state",
633                  TracedValue::FromValue(StateAsValue().release()));
634     state_machine_.UpdateState(action);
635     base::AutoReset<SchedulerStateMachine::Action>
636         mark_inside_action(&inside_action_, action);
637     switch (action) {
638       case SchedulerStateMachine::ACTION_NONE:
639         break;
640       case SchedulerStateMachine::ACTION_ANIMATE:
641         client_->ScheduledActionAnimate();
642         break;
643       case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME:
644         client_->ScheduledActionSendBeginMainFrame();
645         break;
646       case SchedulerStateMachine::ACTION_COMMIT:
647         client_->ScheduledActionCommit();
648         break;
649       case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES:
650         client_->ScheduledActionUpdateVisibleTiles();
651         break;
652       case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE:
653         ActivatePendingTree();
654         break;
655       case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
656         DrawAndSwapIfPossible();
657         break;
658       case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED:
659         DrawAndSwapForced();
660         break;
661       case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT:
662         // No action is actually performed, but this allows the state machine to
663         // advance out of its waiting to draw state without actually drawing.
664         break;
665       case SchedulerStateMachine::ACTION_DRAW_AND_READBACK:
666         DrawAndReadback();
667         break;
668       case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
669         client_->ScheduledActionBeginOutputSurfaceCreation();
670         break;
671       case SchedulerStateMachine::ACTION_MANAGE_TILES:
672         client_->ScheduledActionManageTiles();
673         break;
674     }
675   } while (action != SchedulerStateMachine::ACTION_NONE);
676
677   SetupNextBeginFrameIfNeeded();
678   client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime());
679
680   if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) {
681     DCHECK(!settings_.using_synchronous_renderer_compositor);
682     ScheduleBeginImplFrameDeadline(base::TimeTicks());
683   }
684 }
685
686 bool Scheduler::WillDrawIfNeeded() const {
687   return !state_machine_.PendingDrawsShouldBeAborted();
688 }
689
690 scoped_ptr<base::Value> Scheduler::StateAsValue() const {
691   scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue);
692   state->Set("state_machine", state_machine_.AsValue().release());
693
694   scoped_ptr<base::DictionaryValue> scheduler_state(new base::DictionaryValue);
695   scheduler_state->SetDouble(
696       "time_until_anticipated_draw_time_ms",
697       (AnticipatedDrawTime() - base::TimeTicks::Now()).InMillisecondsF());
698   scheduler_state->SetDouble("vsync_interval_ms",
699                              vsync_interval_.InMillisecondsF());
700   scheduler_state->SetDouble("estimated_parent_draw_time_ms",
701                              estimated_parent_draw_time_.InMillisecondsF());
702   scheduler_state->SetBoolean("last_set_needs_begin_frame_",
703                               last_set_needs_begin_frame_);
704   scheduler_state->SetBoolean("begin_unthrottled_frame_posted_",
705                               begin_unthrottled_frame_posted_);
706   scheduler_state->SetBoolean("begin_retro_frame_posted_",
707                               begin_retro_frame_posted_);
708   scheduler_state->SetInteger("begin_retro_frame_args_",
709                               begin_retro_frame_args_.size());
710   scheduler_state->SetBoolean("begin_impl_frame_deadline_task_",
711                               !begin_impl_frame_deadline_task_.IsCancelled());
712   scheduler_state->SetBoolean("poll_for_draw_triggers_task_",
713                               !poll_for_draw_triggers_task_.IsCancelled());
714   scheduler_state->SetBoolean("advance_commit_state_task_",
715                               !advance_commit_state_task_.IsCancelled());
716   state->Set("scheduler_state", scheduler_state.release());
717
718   scoped_ptr<base::DictionaryValue> client_state(new base::DictionaryValue);
719   client_state->SetDouble("draw_duration_estimate_ms",
720                           client_->DrawDurationEstimate().InMillisecondsF());
721   client_state->SetDouble(
722       "begin_main_frame_to_commit_duration_estimate_ms",
723       client_->BeginMainFrameToCommitDurationEstimate().InMillisecondsF());
724   client_state->SetDouble(
725       "commit_to_activate_duration_estimate_ms",
726       client_->CommitToActivateDurationEstimate().InMillisecondsF());
727   state->Set("client_state", client_state.release());
728   return state.PassAs<base::Value>();
729 }
730
731 bool Scheduler::CanCommitAndActivateBeforeDeadline() const {
732   // Check if the main thread computation and commit can be finished before the
733   // impl thread's deadline.
734   base::TimeTicks estimated_draw_time =
735       begin_impl_frame_args_.frame_time +
736       client_->BeginMainFrameToCommitDurationEstimate() +
737       client_->CommitToActivateDurationEstimate();
738
739   TRACE_EVENT2(
740       TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
741       "CanCommitAndActivateBeforeDeadline",
742       "time_left_after_drawing_ms",
743       (begin_impl_frame_args_.deadline - estimated_draw_time).InMillisecondsF(),
744       "state",
745       TracedValue::FromValue(StateAsValue().release()));
746
747   return estimated_draw_time < begin_impl_frame_args_.deadline;
748 }
749
750 bool Scheduler::IsBeginMainFrameSentOrStarted() const {
751   return (state_machine_.commit_state() ==
752               SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT ||
753           state_machine_.commit_state() ==
754               SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED);
755 }
756
757 }  // namespace cc