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_state_machine.h"
      6 
      7 #include "base/debug/trace_event.h"
      8 #include "base/debug/trace_event_argument.h"
      9 #include "base/format_macros.h"
     10 #include "base/logging.h"
     11 #include "base/strings/stringprintf.h"
     12 #include "base/values.h"
     13 #include "ui/gfx/frame_time.h"
     14 
     15 namespace cc {
     16 
     17 SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
     18     : settings_(settings),
     19       output_surface_state_(OUTPUT_SURFACE_LOST),
     20       begin_impl_frame_state_(BEGIN_IMPL_FRAME_STATE_IDLE),
     21       commit_state_(COMMIT_STATE_IDLE),
     22       forced_redraw_state_(FORCED_REDRAW_STATE_IDLE),
     23       commit_count_(0),
     24       current_frame_number_(0),
     25       last_frame_number_animate_performed_(-1),
     26       last_frame_number_swap_performed_(-1),
     27       last_frame_number_swap_requested_(-1),
     28       last_frame_number_begin_main_frame_sent_(-1),
     29       last_frame_number_update_visible_tiles_was_called_(-1),
     30       manage_tiles_funnel_(0),
     31       consecutive_checkerboard_animations_(0),
     32       max_pending_swaps_(1),
     33       pending_swaps_(0),
     34       needs_redraw_(false),
     35       needs_animate_(false),
     36       needs_manage_tiles_(false),
     37       swap_used_incomplete_tile_(false),
     38       needs_commit_(false),
     39       inside_poll_for_anticipated_draw_triggers_(false),
     40       visible_(false),
     41       can_start_(false),
     42       can_draw_(false),
     43       has_pending_tree_(false),
     44       pending_tree_is_ready_for_activation_(false),
     45       active_tree_needs_first_draw_(false),
     46       did_create_and_initialize_first_output_surface_(false),
     47       impl_latency_takes_priority_(false),
     48       skip_next_begin_main_frame_to_reduce_latency_(false),
     49       skip_begin_main_frame_to_reduce_latency_(false),
     50       continuous_painting_(false) {
     51 }
     52 
     53 const char* SchedulerStateMachine::OutputSurfaceStateToString(
     54     OutputSurfaceState state) {
     55   switch (state) {
     56     case OUTPUT_SURFACE_ACTIVE:
     57       return "OUTPUT_SURFACE_ACTIVE";
     58     case OUTPUT_SURFACE_LOST:
     59       return "OUTPUT_SURFACE_LOST";
     60     case OUTPUT_SURFACE_CREATING:
     61       return "OUTPUT_SURFACE_CREATING";
     62     case OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT:
     63       return "OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT";
     64     case OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION:
     65       return "OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION";
     66   }
     67   NOTREACHED();
     68   return "???";
     69 }
     70 
     71 const char* SchedulerStateMachine::BeginImplFrameStateToString(
     72     BeginImplFrameState state) {
     73   switch (state) {
     74     case BEGIN_IMPL_FRAME_STATE_IDLE:
     75       return "BEGIN_IMPL_FRAME_STATE_IDLE";
     76     case BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING:
     77       return "BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING";
     78     case BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME:
     79       return "BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME";
     80     case BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE:
     81       return "BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE";
     82   }
     83   NOTREACHED();
     84   return "???";
     85 }
     86 
     87 const char* SchedulerStateMachine::CommitStateToString(CommitState state) {
     88   switch (state) {
     89     case COMMIT_STATE_IDLE:
     90       return "COMMIT_STATE_IDLE";
     91     case COMMIT_STATE_BEGIN_MAIN_FRAME_SENT:
     92       return "COMMIT_STATE_BEGIN_MAIN_FRAME_SENT";
     93     case COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED:
     94       return "COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED";
     95     case COMMIT_STATE_READY_TO_COMMIT:
     96       return "COMMIT_STATE_READY_TO_COMMIT";
     97     case COMMIT_STATE_WAITING_FOR_ACTIVATION:
     98       return "COMMIT_STATE_WAITING_FOR_ACTIVATION";
     99     case COMMIT_STATE_WAITING_FOR_FIRST_DRAW:
    100       return "COMMIT_STATE_WAITING_FOR_FIRST_DRAW";
    101   }
    102   NOTREACHED();
    103   return "???";
    104 }
    105 
    106 const char* SchedulerStateMachine::ForcedRedrawOnTimeoutStateToString(
    107     ForcedRedrawOnTimeoutState state) {
    108   switch (state) {
    109     case FORCED_REDRAW_STATE_IDLE:
    110       return "FORCED_REDRAW_STATE_IDLE";
    111     case FORCED_REDRAW_STATE_WAITING_FOR_COMMIT:
    112       return "FORCED_REDRAW_STATE_WAITING_FOR_COMMIT";
    113     case FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION:
    114       return "FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION";
    115     case FORCED_REDRAW_STATE_WAITING_FOR_DRAW:
    116       return "FORCED_REDRAW_STATE_WAITING_FOR_DRAW";
    117   }
    118   NOTREACHED();
    119   return "???";
    120 }
    121 
    122 const char* SchedulerStateMachine::ActionToString(Action action) {
    123   switch (action) {
    124     case ACTION_NONE:
    125       return "ACTION_NONE";
    126     case ACTION_ANIMATE:
    127       return "ACTION_ANIMATE";
    128     case ACTION_SEND_BEGIN_MAIN_FRAME:
    129       return "ACTION_SEND_BEGIN_MAIN_FRAME";
    130     case ACTION_COMMIT:
    131       return "ACTION_COMMIT";
    132     case ACTION_UPDATE_VISIBLE_TILES:
    133       return "ACTION_UPDATE_VISIBLE_TILES";
    134     case ACTION_ACTIVATE_SYNC_TREE:
    135       return "ACTION_ACTIVATE_SYNC_TREE";
    136     case ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
    137       return "ACTION_DRAW_AND_SWAP_IF_POSSIBLE";
    138     case ACTION_DRAW_AND_SWAP_FORCED:
    139       return "ACTION_DRAW_AND_SWAP_FORCED";
    140     case ACTION_DRAW_AND_SWAP_ABORT:
    141       return "ACTION_DRAW_AND_SWAP_ABORT";
    142     case ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
    143       return "ACTION_BEGIN_OUTPUT_SURFACE_CREATION";
    144     case ACTION_MANAGE_TILES:
    145       return "ACTION_MANAGE_TILES";
    146   }
    147   NOTREACHED();
    148   return "???";
    149 }
    150 
    151 scoped_refptr<base::debug::ConvertableToTraceFormat>
    152 SchedulerStateMachine::AsValue() const {
    153   scoped_refptr<base::debug::TracedValue> state =
    154       new base::debug::TracedValue();
    155   AsValueInto(state.get(), gfx::FrameTime::Now());
    156   return state;
    157 }
    158 
    159 void SchedulerStateMachine::AsValueInto(base::debug::TracedValue* state,
    160                                         base::TimeTicks now) const {
    161   state->BeginDictionary("major_state");
    162   state->SetString("next_action", ActionToString(NextAction()));
    163   state->SetString("begin_impl_frame_state",
    164                    BeginImplFrameStateToString(begin_impl_frame_state_));
    165   state->SetString("commit_state", CommitStateToString(commit_state_));
    166   state->SetString("output_surface_state_",
    167                    OutputSurfaceStateToString(output_surface_state_));
    168   state->SetString("forced_redraw_state",
    169                    ForcedRedrawOnTimeoutStateToString(forced_redraw_state_));
    170   state->EndDictionary();
    171 
    172   state->BeginDictionary("major_timestamps_in_ms");
    173   state->SetDouble("0_interval",
    174                    begin_impl_frame_args_.interval.InMicroseconds() / 1000.0L);
    175   state->SetDouble(
    176       "1_now_to_deadline",
    177       (begin_impl_frame_args_.deadline - now).InMicroseconds() / 1000.0L);
    178   state->SetDouble(
    179       "2_frame_time_to_now",
    180       (now - begin_impl_frame_args_.frame_time).InMicroseconds() / 1000.0L);
    181   state->SetDouble("3_frame_time_to_deadline",
    182                    (begin_impl_frame_args_.deadline -
    183                     begin_impl_frame_args_.frame_time).InMicroseconds() /
    184                        1000.0L);
    185   state->SetDouble("4_now",
    186                    (now - base::TimeTicks()).InMicroseconds() / 1000.0L);
    187   state->SetDouble(
    188       "5_frame_time",
    189       (begin_impl_frame_args_.frame_time - base::TimeTicks()).InMicroseconds() /
    190           1000.0L);
    191   state->SetDouble(
    192       "6_deadline",
    193       (begin_impl_frame_args_.deadline - base::TimeTicks()).InMicroseconds() /
    194           1000.0L);
    195   state->EndDictionary();
    196 
    197   state->BeginDictionary("minor_state");
    198   state->SetInteger("commit_count", commit_count_);
    199   state->SetInteger("current_frame_number", current_frame_number_);
    200 
    201   state->SetInteger("last_frame_number_animate_performed",
    202                     last_frame_number_animate_performed_);
    203   state->SetInteger("last_frame_number_swap_performed",
    204                     last_frame_number_swap_performed_);
    205   state->SetInteger("last_frame_number_swap_requested",
    206                     last_frame_number_swap_requested_);
    207   state->SetInteger("last_frame_number_begin_main_frame_sent",
    208                     last_frame_number_begin_main_frame_sent_);
    209   state->SetInteger("last_frame_number_update_visible_tiles_was_called",
    210                     last_frame_number_update_visible_tiles_was_called_);
    211 
    212   state->SetInteger("manage_tiles_funnel", manage_tiles_funnel_);
    213   state->SetInteger("consecutive_checkerboard_animations",
    214                     consecutive_checkerboard_animations_);
    215   state->SetInteger("max_pending_swaps_", max_pending_swaps_);
    216   state->SetInteger("pending_swaps_", pending_swaps_);
    217   state->SetBoolean("needs_redraw", needs_redraw_);
    218   state->SetBoolean("needs_animate_", needs_animate_);
    219   state->SetBoolean("needs_manage_tiles", needs_manage_tiles_);
    220   state->SetBoolean("swap_used_incomplete_tile", swap_used_incomplete_tile_);
    221   state->SetBoolean("needs_commit", needs_commit_);
    222   state->SetBoolean("visible", visible_);
    223   state->SetBoolean("can_start", can_start_);
    224   state->SetBoolean("can_draw", can_draw_);
    225   state->SetBoolean("has_pending_tree", has_pending_tree_);
    226   state->SetBoolean("pending_tree_is_ready_for_activation",
    227                     pending_tree_is_ready_for_activation_);
    228   state->SetBoolean("active_tree_needs_first_draw",
    229                     active_tree_needs_first_draw_);
    230   state->SetBoolean("did_create_and_initialize_first_output_surface",
    231                     did_create_and_initialize_first_output_surface_);
    232   state->SetBoolean("impl_latency_takes_priority",
    233                     impl_latency_takes_priority_);
    234   state->SetBoolean("main_thread_is_in_high_latency_mode",
    235                     MainThreadIsInHighLatencyMode());
    236   state->SetBoolean("skip_begin_main_frame_to_reduce_latency",
    237                     skip_begin_main_frame_to_reduce_latency_);
    238   state->SetBoolean("skip_next_begin_main_frame_to_reduce_latency",
    239                     skip_next_begin_main_frame_to_reduce_latency_);
    240   state->SetBoolean("continuous_painting", continuous_painting_);
    241   state->EndDictionary();
    242 }
    243 
    244 void SchedulerStateMachine::AdvanceCurrentFrameNumber() {
    245   current_frame_number_++;
    246 
    247   // "Drain" the ManageTiles funnel.
    248   if (manage_tiles_funnel_ > 0)
    249     manage_tiles_funnel_--;
    250 
    251   skip_begin_main_frame_to_reduce_latency_ =
    252       skip_next_begin_main_frame_to_reduce_latency_;
    253   skip_next_begin_main_frame_to_reduce_latency_ = false;
    254 }
    255 
    256 bool SchedulerStateMachine::HasSentBeginMainFrameThisFrame() const {
    257   return current_frame_number_ ==
    258          last_frame_number_begin_main_frame_sent_;
    259 }
    260 
    261 bool SchedulerStateMachine::HasUpdatedVisibleTilesThisFrame() const {
    262   return current_frame_number_ ==
    263          last_frame_number_update_visible_tiles_was_called_;
    264 }
    265 
    266 bool SchedulerStateMachine::HasSwappedThisFrame() const {
    267   return current_frame_number_ == last_frame_number_swap_performed_;
    268 }
    269 
    270 bool SchedulerStateMachine::HasRequestedSwapThisFrame() const {
    271   return current_frame_number_ == last_frame_number_swap_requested_;
    272 }
    273 
    274 bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const {
    275   // These are all the cases where we normally cannot or do not want to draw
    276   // but, if needs_redraw_ is true and we do not draw to make forward progress,
    277   // we might deadlock with the main thread.
    278   // This should be a superset of PendingActivationsShouldBeForced() since
    279   // activation of the pending tree is blocked by drawing of the active tree and
    280   // the main thread might be blocked on activation of the most recent commit.
    281   if (PendingActivationsShouldBeForced())
    282     return true;
    283 
    284   // Additional states where we should abort draws.
    285   if (!can_draw_)
    286     return true;
    287   return false;
    288 }
    289 
    290 bool SchedulerStateMachine::PendingActivationsShouldBeForced() const {
    291   // There is no output surface to trigger our activations.
    292   // If we do not force activations to make forward progress, we might deadlock
    293   // with the main thread.
    294   if (output_surface_state_ == OUTPUT_SURFACE_LOST)
    295     return true;
    296 
    297   // If we're not visible, we should force activation.
    298   // Since we set RequiresHighResToDraw when becoming visible, we ensure that we
    299   // don't checkerboard until all visible resources are done. Furthermore, if we
    300   // do keep the pending tree around, when becoming visible we might activate
    301   // prematurely causing RequiresHighResToDraw flag to be reset. In all cases,
    302   // we can simply activate on becoming invisible since we don't need to draw
    303   // the active tree when we're in this state.
    304   if (!visible_)
    305     return true;
    306 
    307   return false;
    308 }
    309 
    310 bool SchedulerStateMachine::ShouldBeginOutputSurfaceCreation() const {
    311   // Don't try to initialize too early.
    312   if (!can_start_)
    313     return false;
    314 
    315   // We only want to start output surface initialization after the
    316   // previous commit is complete.
    317   if (commit_state_ != COMMIT_STATE_IDLE)
    318     return false;
    319 
    320   // Make sure the BeginImplFrame from any previous OutputSurfaces
    321   // are complete before creating the new OutputSurface.
    322   if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_IDLE)
    323     return false;
    324 
    325   // We want to clear the pipline of any pending draws and activations
    326   // before starting output surface initialization. This allows us to avoid
    327   // weird corner cases where we abort draws or force activation while we
    328   // are initializing the output surface.
    329   if (active_tree_needs_first_draw_ || has_pending_tree_)
    330     return false;
    331 
    332   // We need to create the output surface if we don't have one and we haven't
    333   // started creating one yet.
    334   return output_surface_state_ == OUTPUT_SURFACE_LOST;
    335 }
    336 
    337 bool SchedulerStateMachine::ShouldDraw() const {
    338   // If we need to abort draws, we should do so ASAP since the draw could
    339   // be blocking other important actions (like output surface initialization),
    340   // from occuring. If we are waiting for the first draw, then perfom the
    341   // aborted draw to keep things moving. If we are not waiting for the first
    342   // draw however, we don't want to abort for no reason.
    343   if (PendingDrawsShouldBeAborted())
    344     return active_tree_needs_first_draw_;
    345 
    346   // After this line, we only want to send a swap request once per frame.
    347   if (HasRequestedSwapThisFrame())
    348     return false;
    349 
    350   // Do not queue too many swaps.
    351   if (pending_swaps_ >= max_pending_swaps_)
    352     return false;
    353 
    354   // Except for the cases above, do not draw outside of the BeginImplFrame
    355   // deadline.
    356   if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
    357     return false;
    358 
    359   // Only handle forced redraws due to timeouts on the regular deadline.
    360   if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
    361     return true;
    362 
    363   return needs_redraw_;
    364 }
    365 
    366 bool SchedulerStateMachine::ShouldActivatePendingTree() const {
    367   // There is nothing to activate.
    368   if (!has_pending_tree_)
    369     return false;
    370 
    371   // We should not activate a second tree before drawing the first one.
    372   // Even if we need to force activation of the pending tree, we should abort
    373   // drawing the active tree first.
    374   if (active_tree_needs_first_draw_)
    375     return false;
    376 
    377   // If we want to force activation, do so ASAP.
    378   if (PendingActivationsShouldBeForced())
    379     return true;
    380 
    381   // At this point, only activate if we are ready to activate.
    382   return pending_tree_is_ready_for_activation_;
    383 }
    384 
    385 bool SchedulerStateMachine::ShouldUpdateVisibleTiles() const {
    386   if (!settings_.impl_side_painting)
    387     return false;
    388   if (HasUpdatedVisibleTilesThisFrame())
    389     return false;
    390 
    391   // We don't want to update visible tiles right after drawing.
    392   if (HasRequestedSwapThisFrame())
    393     return false;
    394 
    395   // There's no reason to check for tiles if we don't have an output surface.
    396   if (!HasInitializedOutputSurface())
    397     return false;
    398 
    399   // We should not check for visible tiles until we've entered the deadline so
    400   // we check as late as possible and give the tiles more time to initialize.
    401   if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
    402     return false;
    403 
    404   // If the last swap drew with checkerboard or missing tiles, we should
    405   // poll for any new visible tiles so we can be notified to draw again
    406   // when there are.
    407   if (swap_used_incomplete_tile_)
    408     return true;
    409 
    410   return false;
    411 }
    412 
    413 bool SchedulerStateMachine::ShouldAnimate() const {
    414   if (!can_draw_)
    415     return false;
    416 
    417   if (last_frame_number_animate_performed_ == current_frame_number_)
    418     return false;
    419 
    420   if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING &&
    421       begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
    422     return false;
    423 
    424   return needs_redraw_ || needs_animate_;
    425 }
    426 
    427 bool SchedulerStateMachine::CouldSendBeginMainFrame() const {
    428   if (!needs_commit_)
    429     return false;
    430 
    431   // We can not perform commits if we are not visible.
    432   if (!visible_)
    433     return false;
    434 
    435   return true;
    436 }
    437 
    438 bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
    439   if (!CouldSendBeginMainFrame())
    440     return false;
    441 
    442   // Only send BeginMainFrame when there isn't another commit pending already.
    443   if (commit_state_ != COMMIT_STATE_IDLE)
    444     return false;
    445 
    446   // Don't send BeginMainFrame early if we are prioritizing the active tree
    447   // because of impl_latency_takes_priority_.
    448   if (impl_latency_takes_priority_ &&
    449       (has_pending_tree_ || active_tree_needs_first_draw_)) {
    450     return false;
    451   }
    452 
    453   // We want to start the first commit after we get a new output surface ASAP.
    454   if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT)
    455     return true;
    456 
    457   // We should not send BeginMainFrame while we are in
    458   // BEGIN_IMPL_FRAME_STATE_IDLE since we might have new
    459   // user input arriving soon.
    460   // TODO(brianderson): Allow sending BeginMainFrame while idle when the main
    461   // thread isn't consuming user input.
    462   if (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_IDLE &&
    463       BeginFrameNeeded())
    464     return false;
    465 
    466   // We need a new commit for the forced redraw. This honors the
    467   // single commit per interval because the result will be swapped to screen.
    468   if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT)
    469     return true;
    470 
    471   // After this point, we only start a commit once per frame.
    472   if (HasSentBeginMainFrameThisFrame())
    473     return false;
    474 
    475   // We shouldn't normally accept commits if there isn't an OutputSurface.
    476   if (!HasInitializedOutputSurface())
    477     return false;
    478 
    479   // SwapAck throttle the BeginMainFrames unless we just swapped.
    480   // TODO(brianderson): Remove this restriction to improve throughput.
    481   bool just_swapped_in_deadline =
    482       begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE &&
    483       HasSwappedThisFrame();
    484   if (pending_swaps_ >= max_pending_swaps_ && !just_swapped_in_deadline)
    485     return false;
    486 
    487   if (skip_begin_main_frame_to_reduce_latency_)
    488     return false;
    489 
    490   return true;
    491 }
    492 
    493 bool SchedulerStateMachine::ShouldCommit() const {
    494   if (commit_state_ != COMMIT_STATE_READY_TO_COMMIT)
    495     return false;
    496 
    497   // We must not finish the commit until the pending tree is free.
    498   if (has_pending_tree_) {
    499     DCHECK(settings_.main_frame_before_activation_enabled);
    500     return false;
    501   }
    502 
    503   // Prioritize drawing the previous commit before finishing the next commit.
    504   if (active_tree_needs_first_draw_)
    505     return false;
    506 
    507   return true;
    508 }
    509 
    510 bool SchedulerStateMachine::ShouldManageTiles() const {
    511   // ManageTiles only really needs to be called immediately after commit
    512   // and then periodically after that. Use a funnel to make sure we average
    513   // one ManageTiles per BeginImplFrame in the long run.
    514   if (manage_tiles_funnel_ > 0)
    515     return false;
    516 
    517   // Limiting to once per-frame is not enough, since we only want to
    518   // manage tiles _after_ draws. Polling for draw triggers and
    519   // begin-frame are mutually exclusive, so we limit to these two cases.
    520   if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE &&
    521       !inside_poll_for_anticipated_draw_triggers_)
    522     return false;
    523   return needs_manage_tiles_;
    524 }
    525 
    526 SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
    527   if (ShouldUpdateVisibleTiles())
    528     return ACTION_UPDATE_VISIBLE_TILES;
    529   if (ShouldActivatePendingTree())
    530     return ACTION_ACTIVATE_SYNC_TREE;
    531   if (ShouldCommit())
    532     return ACTION_COMMIT;
    533   if (ShouldAnimate())
    534     return ACTION_ANIMATE;
    535   if (ShouldDraw()) {
    536     if (PendingDrawsShouldBeAborted())
    537       return ACTION_DRAW_AND_SWAP_ABORT;
    538     else if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
    539       return ACTION_DRAW_AND_SWAP_FORCED;
    540     else
    541       return ACTION_DRAW_AND_SWAP_IF_POSSIBLE;
    542   }
    543   if (ShouldManageTiles())
    544     return ACTION_MANAGE_TILES;
    545   if (ShouldSendBeginMainFrame())
    546     return ACTION_SEND_BEGIN_MAIN_FRAME;
    547   if (ShouldBeginOutputSurfaceCreation())
    548     return ACTION_BEGIN_OUTPUT_SURFACE_CREATION;
    549   return ACTION_NONE;
    550 }
    551 
    552 void SchedulerStateMachine::UpdateState(Action action) {
    553   switch (action) {
    554     case ACTION_NONE:
    555       return;
    556 
    557     case ACTION_UPDATE_VISIBLE_TILES:
    558       last_frame_number_update_visible_tiles_was_called_ =
    559           current_frame_number_;
    560       return;
    561 
    562     case ACTION_ACTIVATE_SYNC_TREE:
    563       UpdateStateOnActivation();
    564       return;
    565 
    566     case ACTION_ANIMATE:
    567       last_frame_number_animate_performed_ = current_frame_number_;
    568       needs_animate_ = false;
    569       // TODO(skyostil): Instead of assuming this, require the client to tell
    570       // us.
    571       SetNeedsRedraw();
    572       return;
    573 
    574     case ACTION_SEND_BEGIN_MAIN_FRAME:
    575       DCHECK(!has_pending_tree_ ||
    576              settings_.main_frame_before_activation_enabled);
    577       DCHECK(!active_tree_needs_first_draw_ ||
    578              settings_.main_frame_before_draw_enabled);
    579       DCHECK(visible_);
    580       commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_SENT;
    581       needs_commit_ = false;
    582       last_frame_number_begin_main_frame_sent_ =
    583           current_frame_number_;
    584       return;
    585 
    586     case ACTION_COMMIT: {
    587       bool commit_was_aborted = false;
    588       UpdateStateOnCommit(commit_was_aborted);
    589       return;
    590     }
    591 
    592     case ACTION_DRAW_AND_SWAP_FORCED:
    593     case ACTION_DRAW_AND_SWAP_IF_POSSIBLE: {
    594       bool did_request_swap = true;
    595       UpdateStateOnDraw(did_request_swap);
    596       return;
    597     }
    598 
    599     case ACTION_DRAW_AND_SWAP_ABORT: {
    600       bool did_request_swap = false;
    601       UpdateStateOnDraw(did_request_swap);
    602       return;
    603     }
    604 
    605     case ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
    606       DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_LOST);
    607       output_surface_state_ = OUTPUT_SURFACE_CREATING;
    608 
    609       // The following DCHECKs make sure we are in the proper quiescent state.
    610       // The pipeline should be flushed entirely before we start output
    611       // surface creation to avoid complicated corner cases.
    612       DCHECK_EQ(commit_state_, COMMIT_STATE_IDLE);
    613       DCHECK(!has_pending_tree_);
    614       DCHECK(!active_tree_needs_first_draw_);
    615       return;
    616 
    617     case ACTION_MANAGE_TILES:
    618       UpdateStateOnManageTiles();
    619       return;
    620   }
    621 }
    622 
    623 void SchedulerStateMachine::UpdateStateOnCommit(bool commit_was_aborted) {
    624   commit_count_++;
    625 
    626   if (commit_was_aborted || settings_.main_frame_before_activation_enabled) {
    627     commit_state_ = COMMIT_STATE_IDLE;
    628   } else if (settings_.main_frame_before_draw_enabled) {
    629     commit_state_ = settings_.impl_side_painting
    630                         ? COMMIT_STATE_WAITING_FOR_ACTIVATION
    631                         : COMMIT_STATE_IDLE;
    632   } else {
    633     commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_DRAW;
    634   }
    635 
    636   // If we are impl-side-painting but the commit was aborted, then we behave
    637   // mostly as if we are not impl-side-painting since there is no pending tree.
    638   has_pending_tree_ = settings_.impl_side_painting && !commit_was_aborted;
    639 
    640   // Update state related to forced draws.
    641   if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT) {
    642     forced_redraw_state_ = has_pending_tree_
    643                                ? FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION
    644                                : FORCED_REDRAW_STATE_WAITING_FOR_DRAW;
    645   }
    646 
    647   // Update the output surface state.
    648   DCHECK_NE(output_surface_state_, OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION);
    649   if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT) {
    650     if (has_pending_tree_) {
    651       output_surface_state_ = OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION;
    652     } else {
    653       output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
    654       needs_redraw_ = true;
    655     }
    656   }
    657 
    658   // Update state if we have a new active tree to draw, or if the active tree
    659   // was unchanged but we need to do a forced draw.
    660   if (!has_pending_tree_ &&
    661       (!commit_was_aborted ||
    662        forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)) {
    663     needs_redraw_ = true;
    664     active_tree_needs_first_draw_ = true;
    665   }
    666 
    667   // This post-commit work is common to both completed and aborted commits.
    668   pending_tree_is_ready_for_activation_ = false;
    669 
    670   if (continuous_painting_)
    671     needs_commit_ = true;
    672 }
    673 
    674 void SchedulerStateMachine::UpdateStateOnActivation() {
    675   if (commit_state_ == COMMIT_STATE_WAITING_FOR_ACTIVATION)
    676     commit_state_ = COMMIT_STATE_IDLE;
    677 
    678   if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION)
    679     output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
    680 
    681   if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION)
    682     forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_DRAW;
    683 
    684   has_pending_tree_ = false;
    685   pending_tree_is_ready_for_activation_ = false;
    686   active_tree_needs_first_draw_ = true;
    687   needs_redraw_ = true;
    688 }
    689 
    690 void SchedulerStateMachine::UpdateStateOnDraw(bool did_request_swap) {
    691   if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
    692     forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE;
    693 
    694   if (!has_pending_tree_ &&
    695       commit_state_ == COMMIT_STATE_WAITING_FOR_FIRST_DRAW) {
    696     commit_state_ = COMMIT_STATE_IDLE;
    697   }
    698 
    699   needs_redraw_ = false;
    700   active_tree_needs_first_draw_ = false;
    701 
    702   if (did_request_swap)
    703     last_frame_number_swap_requested_ = current_frame_number_;
    704 }
    705 
    706 void SchedulerStateMachine::UpdateStateOnManageTiles() {
    707   needs_manage_tiles_ = false;
    708 }
    709 
    710 void SchedulerStateMachine::SetSkipNextBeginMainFrameToReduceLatency() {
    711   skip_next_begin_main_frame_to_reduce_latency_ = true;
    712 }
    713 
    714 bool SchedulerStateMachine::BeginFrameNeeded() const {
    715   // Proactive BeginFrames are bad for the synchronous compositor because we
    716   // have to draw when we get the BeginFrame and could end up drawing many
    717   // duplicate frames if our new frame isn't ready in time.
    718   // To poll for state with the synchronous compositor without having to draw,
    719   // we rely on ShouldPollForAnticipatedDrawTriggers instead.
    720   if (!SupportsProactiveBeginFrame())
    721     return BeginFrameNeededToAnimateOrDraw();
    722 
    723   return BeginFrameNeededToAnimateOrDraw() || ProactiveBeginFrameWanted();
    724 }
    725 
    726 bool SchedulerStateMachine::ShouldPollForAnticipatedDrawTriggers() const {
    727   // ShouldPollForAnticipatedDrawTriggers is what we use in place of
    728   // ProactiveBeginFrameWanted when we are using the synchronous
    729   // compositor.
    730   if (!SupportsProactiveBeginFrame()) {
    731     return !BeginFrameNeededToAnimateOrDraw() && ProactiveBeginFrameWanted();
    732   }
    733 
    734   // Non synchronous compositors should rely on
    735   // ProactiveBeginFrameWanted to poll for state instead.
    736   return false;
    737 }
    738 
    739 // Note: If SupportsProactiveBeginFrame is false, the scheduler should poll
    740 // for changes in it's draw state so it can request a BeginFrame when it's
    741 // actually ready.
    742 bool SchedulerStateMachine::SupportsProactiveBeginFrame() const {
    743   // It is undesirable to proactively request BeginFrames if we are
    744   // using a synchronous compositor because we *must* draw for every
    745   // BeginFrame, which could cause duplicate draws.
    746   return !settings_.using_synchronous_renderer_compositor;
    747 }
    748 
    749 // These are the cases where we definitely (or almost definitely) have a
    750 // new frame to animate and/or draw and can draw.
    751 bool SchedulerStateMachine::BeginFrameNeededToAnimateOrDraw() const {
    752   // The output surface is the provider of BeginImplFrames, so we are not going
    753   // to get them even if we ask for them.
    754   if (!HasInitializedOutputSurface())
    755     return false;
    756 
    757   // If we can't draw, don't tick until we are notified that we can draw again.
    758   if (!can_draw_)
    759     return false;
    760 
    761   // The forced draw respects our normal draw scheduling, so we need to
    762   // request a BeginImplFrame for it.
    763   if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
    764     return true;
    765 
    766   // There's no need to produce frames if we are not visible.
    767   if (!visible_)
    768     return false;
    769 
    770   // We need to draw a more complete frame than we did the last BeginImplFrame,
    771   // so request another BeginImplFrame in anticipation that we will have
    772   // additional visible tiles.
    773   if (swap_used_incomplete_tile_)
    774     return true;
    775 
    776   if (needs_animate_)
    777     return true;
    778 
    779   return needs_redraw_;
    780 }
    781 
    782 // These are cases where we are very likely to draw soon, but might not
    783 // actually have a new frame to draw when we receive the next BeginImplFrame.
    784 // Proactively requesting the BeginImplFrame helps hide the round trip latency
    785 // of the SetNeedsBeginFrame request that has to go to the Browser.
    786 bool SchedulerStateMachine::ProactiveBeginFrameWanted() const {
    787   // The output surface is the provider of BeginImplFrames,
    788   // so we are not going to get them even if we ask for them.
    789   if (!HasInitializedOutputSurface())
    790     return false;
    791 
    792   // Do not be proactive when invisible.
    793   if (!visible_)
    794     return false;
    795 
    796   // We should proactively request a BeginImplFrame if a commit is pending
    797   // because we will want to draw if the commit completes quickly.
    798   if (needs_commit_ || commit_state_ != COMMIT_STATE_IDLE)
    799     return true;
    800 
    801   // If the pending tree activates quickly, we'll want a BeginImplFrame soon
    802   // to draw the new active tree.
    803   if (has_pending_tree_)
    804     return true;
    805 
    806   // Changing priorities may allow us to activate (given the new priorities),
    807   // which may result in a new frame.
    808   if (needs_manage_tiles_)
    809     return true;
    810 
    811   // If we just sent a swap request, it's likely that we are going to produce
    812   // another frame soon. This helps avoid negative glitches in our
    813   // SetNeedsBeginFrame requests, which may propagate to the BeginImplFrame
    814   // provider and get sampled at an inopportune time, delaying the next
    815   // BeginImplFrame.
    816   if (HasRequestedSwapThisFrame())
    817     return true;
    818 
    819   return false;
    820 }
    821 
    822 void SchedulerStateMachine::OnBeginImplFrame(const BeginFrameArgs& args) {
    823   AdvanceCurrentFrameNumber();
    824   begin_impl_frame_args_ = args;
    825   DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_IDLE)
    826       << AsValue()->ToString();
    827   begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING;
    828 }
    829 
    830 void SchedulerStateMachine::OnBeginImplFrameDeadlinePending() {
    831   DCHECK_EQ(begin_impl_frame_state_,
    832             BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING)
    833       << AsValue()->ToString();
    834   begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME;
    835 }
    836 
    837 void SchedulerStateMachine::OnBeginImplFrameDeadline() {
    838   DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
    839       << AsValue()->ToString();
    840   begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE;
    841 }
    842 
    843 void SchedulerStateMachine::OnBeginImplFrameIdle() {
    844   DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
    845       << AsValue()->ToString();
    846   begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_IDLE;
    847 }
    848 
    849 bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineEarly() const {
    850   // TODO(brianderson): This should take into account multiple commit sources.
    851 
    852   if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
    853     return false;
    854 
    855   // If we've lost the output surface, end the current BeginImplFrame ASAP
    856   // so we can start creating the next output surface.
    857   if (output_surface_state_ == OUTPUT_SURFACE_LOST)
    858     return true;
    859 
    860   // SwapAck throttle the deadline since we wont draw and swap anyway.
    861   if (pending_swaps_ >= max_pending_swaps_)
    862     return false;
    863 
    864   if (active_tree_needs_first_draw_)
    865     return true;
    866 
    867   if (!needs_redraw_)
    868     return false;
    869 
    870   // This is used to prioritize impl-thread draws when the main thread isn't
    871   // producing anything, e.g., after an aborted commit. We also check that we
    872   // don't have a pending tree -- otherwise we should give it a chance to
    873   // activate.
    874   // TODO(skyostil): Revisit this when we have more accurate deadline estimates.
    875   if (commit_state_ == COMMIT_STATE_IDLE && !has_pending_tree_)
    876     return true;
    877 
    878   // Prioritize impl-thread draws in impl_latency_takes_priority_ mode.
    879   if (impl_latency_takes_priority_)
    880     return true;
    881 
    882   return false;
    883 }
    884 
    885 bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const {
    886   // If a commit is pending before the previous commit has been drawn, we
    887   // are definitely in a high latency mode.
    888   if (CommitPending() && (active_tree_needs_first_draw_ || has_pending_tree_))
    889     return true;
    890 
    891   // If we just sent a BeginMainFrame and haven't hit the deadline yet, the main
    892   // thread is in a low latency mode.
    893   if (HasSentBeginMainFrameThisFrame() &&
    894       (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING ||
    895        begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME))
    896     return false;
    897 
    898   // If there's a commit in progress it must either be from the previous frame
    899   // or it started after the impl thread's deadline. In either case the main
    900   // thread is in high latency mode.
    901   if (CommitPending())
    902     return true;
    903 
    904   // Similarly, if there's a pending tree the main thread is in high latency
    905   // mode, because either
    906   //   it's from the previous frame
    907   // or
    908   //   we're currently drawing the active tree and the pending tree will thus
    909   //   only be drawn in the next frame.
    910   if (has_pending_tree_)
    911     return true;
    912 
    913   if (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) {
    914     // Even if there's a new active tree to draw at the deadline or we've just
    915     // swapped it, it may have been triggered by a previous BeginImplFrame, in
    916     // which case the main thread is in a high latency mode.
    917     return (active_tree_needs_first_draw_ || HasSwappedThisFrame()) &&
    918            !HasSentBeginMainFrameThisFrame();
    919   }
    920 
    921   // If the active tree needs its first draw in any other state, we know the
    922   // main thread is in a high latency mode.
    923   return active_tree_needs_first_draw_;
    924 }
    925 
    926 void SchedulerStateMachine::DidEnterPollForAnticipatedDrawTriggers() {
    927   AdvanceCurrentFrameNumber();
    928   inside_poll_for_anticipated_draw_triggers_ = true;
    929 }
    930 
    931 void SchedulerStateMachine::DidLeavePollForAnticipatedDrawTriggers() {
    932   inside_poll_for_anticipated_draw_triggers_ = false;
    933 }
    934 
    935 void SchedulerStateMachine::SetVisible(bool visible) { visible_ = visible; }
    936 
    937 void SchedulerStateMachine::SetCanDraw(bool can_draw) { can_draw_ = can_draw; }
    938 
    939 void SchedulerStateMachine::SetNeedsRedraw() { needs_redraw_ = true; }
    940 
    941 void SchedulerStateMachine::SetNeedsAnimate() {
    942   needs_animate_ = true;
    943 }
    944 
    945 void SchedulerStateMachine::SetNeedsManageTiles() {
    946   if (!needs_manage_tiles_) {
    947     TRACE_EVENT0("cc",
    948                  "SchedulerStateMachine::SetNeedsManageTiles");
    949     needs_manage_tiles_ = true;
    950   }
    951 }
    952 
    953 void SchedulerStateMachine::SetMaxSwapsPending(int max) {
    954   max_pending_swaps_ = max;
    955 }
    956 
    957 void SchedulerStateMachine::DidSwapBuffers() {
    958   pending_swaps_++;
    959   DCHECK_LE(pending_swaps_, max_pending_swaps_);
    960 
    961   last_frame_number_swap_performed_ = current_frame_number_;
    962 }
    963 
    964 void SchedulerStateMachine::SetSwapUsedIncompleteTile(
    965     bool used_incomplete_tile) {
    966   swap_used_incomplete_tile_ = used_incomplete_tile;
    967 }
    968 
    969 void SchedulerStateMachine::DidSwapBuffersComplete() {
    970   DCHECK_GT(pending_swaps_, 0);
    971   pending_swaps_--;
    972 }
    973 
    974 void SchedulerStateMachine::SetImplLatencyTakesPriority(
    975     bool impl_latency_takes_priority) {
    976   impl_latency_takes_priority_ = impl_latency_takes_priority;
    977 }
    978 
    979 void SchedulerStateMachine::DidDrawIfPossibleCompleted(DrawResult result) {
    980   switch (result) {
    981     case INVALID_RESULT:
    982       NOTREACHED() << "Uninitialized DrawResult.";
    983       break;
    984     case DRAW_ABORTED_CANT_DRAW:
    985     case DRAW_ABORTED_CONTEXT_LOST:
    986       NOTREACHED() << "Invalid return value from DrawAndSwapIfPossible:"
    987                    << result;
    988       break;
    989     case DRAW_SUCCESS:
    990       consecutive_checkerboard_animations_ = 0;
    991       forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE;
    992       break;
    993     case DRAW_ABORTED_CHECKERBOARD_ANIMATIONS:
    994       needs_redraw_ = true;
    995 
    996       // If we're already in the middle of a redraw, we don't need to
    997       // restart it.
    998       if (forced_redraw_state_ != FORCED_REDRAW_STATE_IDLE)
    999         return;
   1000 
   1001       needs_commit_ = true;
   1002       consecutive_checkerboard_animations_++;
   1003       if (settings_.timeout_and_draw_when_animation_checkerboards &&
   1004           consecutive_checkerboard_animations_ >=
   1005               settings_.maximum_number_of_failed_draws_before_draw_is_forced_) {
   1006         consecutive_checkerboard_animations_ = 0;
   1007         // We need to force a draw, but it doesn't make sense to do this until
   1008         // we've committed and have new textures.
   1009         forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_COMMIT;
   1010       }
   1011       break;
   1012     case DRAW_ABORTED_MISSING_HIGH_RES_CONTENT:
   1013       // It's not clear whether this missing content is because of missing
   1014       // pictures (which requires a commit) or because of memory pressure
   1015       // removing textures (which might not).  To be safe, request a commit
   1016       // anyway.
   1017       needs_commit_ = true;
   1018       break;
   1019   }
   1020 }
   1021 
   1022 void SchedulerStateMachine::SetNeedsCommit() {
   1023   needs_commit_ = true;
   1024 }
   1025 
   1026 void SchedulerStateMachine::NotifyReadyToCommit() {
   1027   DCHECK(commit_state_ == COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED)
   1028       << AsValue()->ToString();
   1029   commit_state_ = COMMIT_STATE_READY_TO_COMMIT;
   1030 }
   1031 
   1032 void SchedulerStateMachine::BeginMainFrameAborted(bool did_handle) {
   1033   DCHECK_EQ(commit_state_, COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
   1034   if (did_handle) {
   1035     bool commit_was_aborted = true;
   1036     UpdateStateOnCommit(commit_was_aborted);
   1037   } else {
   1038     commit_state_ = COMMIT_STATE_IDLE;
   1039     SetNeedsCommit();
   1040   }
   1041 }
   1042 
   1043 void SchedulerStateMachine::DidManageTiles() {
   1044   needs_manage_tiles_ = false;
   1045   // "Fill" the ManageTiles funnel.
   1046   manage_tiles_funnel_++;
   1047 }
   1048 
   1049 void SchedulerStateMachine::DidLoseOutputSurface() {
   1050   if (output_surface_state_ == OUTPUT_SURFACE_LOST ||
   1051       output_surface_state_ == OUTPUT_SURFACE_CREATING)
   1052     return;
   1053   output_surface_state_ = OUTPUT_SURFACE_LOST;
   1054   needs_redraw_ = false;
   1055 }
   1056 
   1057 void SchedulerStateMachine::NotifyReadyToActivate() {
   1058   if (has_pending_tree_)
   1059     pending_tree_is_ready_for_activation_ = true;
   1060 }
   1061 
   1062 void SchedulerStateMachine::DidCreateAndInitializeOutputSurface() {
   1063   DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_CREATING);
   1064   output_surface_state_ = OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT;
   1065 
   1066   if (did_create_and_initialize_first_output_surface_) {
   1067     // TODO(boliu): See if we can remove this when impl-side painting is always
   1068     // on. Does anything on the main thread need to update after recreate?
   1069     needs_commit_ = true;
   1070   }
   1071   did_create_and_initialize_first_output_surface_ = true;
   1072   pending_swaps_ = 0;
   1073 }
   1074 
   1075 void SchedulerStateMachine::NotifyBeginMainFrameStarted() {
   1076   DCHECK_EQ(commit_state_, COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
   1077   commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED;
   1078 }
   1079 
   1080 bool SchedulerStateMachine::HasInitializedOutputSurface() const {
   1081   switch (output_surface_state_) {
   1082     case OUTPUT_SURFACE_LOST:
   1083     case OUTPUT_SURFACE_CREATING:
   1084       return false;
   1085 
   1086     case OUTPUT_SURFACE_ACTIVE:
   1087     case OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT:
   1088     case OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION:
   1089       return true;
   1090   }
   1091   NOTREACHED();
   1092   return false;
   1093 }
   1094 
   1095 std::string SchedulerStateMachine::GetStatesForDebugging() const {
   1096   return base::StringPrintf("%c %d %d %d %c %c %c %d %d",
   1097       needs_commit_ ? 'T' : 'F',
   1098       static_cast<int>(output_surface_state_),
   1099       static_cast<int>(begin_impl_frame_state_),
   1100       static_cast<int>(commit_state_),
   1101       has_pending_tree_ ? 'T' : 'F',
   1102       pending_tree_is_ready_for_activation_ ? 'T' : 'F',
   1103       active_tree_needs_first_draw_ ? 'T' : 'F',
   1104       max_pending_swaps_,
   1105       pending_swaps_);
   1106 }
   1107 
   1108 }  // namespace cc
   1109