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