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/format_macros.h"
      8 #include "base/logging.h"
      9 #include "base/strings/stringprintf.h"
     10 
     11 namespace cc {
     12 
     13 SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
     14     : settings_(settings),
     15       commit_state_(COMMIT_STATE_IDLE),
     16       commit_count_(0),
     17       current_frame_number_(0),
     18       last_frame_number_where_begin_frame_sent_to_main_thread_(-1),
     19       last_frame_number_where_draw_was_called_(-1),
     20       last_frame_number_where_tree_activation_attempted_(-1),
     21       last_frame_number_where_update_visible_tiles_was_called_(-1),
     22       consecutive_failed_draws_(0),
     23       maximum_number_of_failed_draws_before_draw_is_forced_(3),
     24       needs_redraw_(false),
     25       swap_used_incomplete_tile_(false),
     26       needs_forced_redraw_(false),
     27       needs_forced_redraw_after_next_commit_(false),
     28       needs_redraw_after_next_commit_(false),
     29       needs_commit_(false),
     30       needs_forced_commit_(false),
     31       expect_immediate_begin_frame_for_main_thread_(false),
     32       main_thread_needs_layer_textures_(false),
     33       inside_begin_frame_(false),
     34       visible_(false),
     35       can_start_(false),
     36       can_draw_(false),
     37       has_pending_tree_(false),
     38       draw_if_possible_failed_(false),
     39       texture_state_(LAYER_TEXTURE_STATE_UNLOCKED),
     40       output_surface_state_(OUTPUT_SURFACE_LOST),
     41       did_create_and_initialize_first_output_surface_(false) {}
     42 
     43 std::string SchedulerStateMachine::ToString() {
     44   std::string str;
     45   base::StringAppendF(&str,
     46                       "settings_.impl_side_painting = %d; ",
     47                       settings_.impl_side_painting);
     48   base::StringAppendF(&str, "commit_state_ = %d; ", commit_state_);
     49   base::StringAppendF(&str, "commit_count_ = %d; ", commit_count_);
     50   base::StringAppendF(
     51       &str, "current_frame_number_ = %d; ", current_frame_number_);
     52   base::StringAppendF(&str,
     53                       "last_frame_number_where_draw_was_called_ = %d; ",
     54                       last_frame_number_where_draw_was_called_);
     55   base::StringAppendF(
     56       &str,
     57       "last_frame_number_where_tree_activation_attempted_ = %d; ",
     58       last_frame_number_where_tree_activation_attempted_);
     59   base::StringAppendF(
     60       &str,
     61       "last_frame_number_where_update_visible_tiles_was_called_ = %d; ",
     62       last_frame_number_where_update_visible_tiles_was_called_);
     63   base::StringAppendF(
     64       &str, "consecutive_failed_draws_ = %d; ", consecutive_failed_draws_);
     65   base::StringAppendF(
     66       &str,
     67       "maximum_number_of_failed_draws_before_draw_is_forced_ = %d; ",
     68       maximum_number_of_failed_draws_before_draw_is_forced_);
     69   base::StringAppendF(&str, "needs_redraw_ = %d; ", needs_redraw_);
     70   base::StringAppendF(
     71       &str, "swap_used_incomplete_tile_ = %d; ", swap_used_incomplete_tile_);
     72   base::StringAppendF(
     73       &str, "needs_forced_redraw_ = %d; ", needs_forced_redraw_);
     74   base::StringAppendF(&str,
     75                       "needs_forced_redraw_after_next_commit_ = %d; ",
     76                       needs_forced_redraw_after_next_commit_);
     77   base::StringAppendF(&str, "needs_commit_ = %d; ", needs_commit_);
     78   base::StringAppendF(
     79       &str, "needs_forced_commit_ = %d; ", needs_forced_commit_);
     80   base::StringAppendF(&str,
     81                       "expect_immediate_begin_frame_for_main_thread_ = %d; ",
     82                       expect_immediate_begin_frame_for_main_thread_);
     83   base::StringAppendF(&str,
     84                       "main_thread_needs_layer_textures_ = %d; ",
     85                       main_thread_needs_layer_textures_);
     86   base::StringAppendF(&str, "inside_begin_frame_ = %d; ",
     87       inside_begin_frame_);
     88   base::StringAppendF(&str, "last_frame_time_ = %" PRId64 "; ",
     89       (last_begin_frame_args_.frame_time - base::TimeTicks())
     90           .InMilliseconds());
     91   base::StringAppendF(&str, "last_deadline_ = %" PRId64 "; ",
     92       (last_begin_frame_args_.deadline - base::TimeTicks()).InMilliseconds());
     93   base::StringAppendF(&str, "last_interval_ = %" PRId64 "; ",
     94       last_begin_frame_args_.interval.InMilliseconds());
     95   base::StringAppendF(&str, "visible_ = %d; ", visible_);
     96   base::StringAppendF(&str, "can_start_ = %d; ", can_start_);
     97   base::StringAppendF(&str, "can_draw_ = %d; ", can_draw_);
     98   base::StringAppendF(
     99       &str, "draw_if_possible_failed_ = %d; ", draw_if_possible_failed_);
    100   base::StringAppendF(&str, "has_pending_tree_ = %d; ", has_pending_tree_);
    101   base::StringAppendF(&str, "texture_state_ = %d; ", texture_state_);
    102   base::StringAppendF(
    103       &str, "output_surface_state_ = %d; ", output_surface_state_);
    104   return str;
    105 }
    106 
    107 bool SchedulerStateMachine::HasDrawnThisFrame() const {
    108   return current_frame_number_ == last_frame_number_where_draw_was_called_;
    109 }
    110 
    111 bool SchedulerStateMachine::HasAttemptedTreeActivationThisFrame() const {
    112   return current_frame_number_ ==
    113          last_frame_number_where_tree_activation_attempted_;
    114 }
    115 
    116 bool SchedulerStateMachine::HasUpdatedVisibleTilesThisFrame() const {
    117   return current_frame_number_ ==
    118          last_frame_number_where_update_visible_tiles_was_called_;
    119 }
    120 
    121 void SchedulerStateMachine::SetPostCommitFlags() {
    122   // This post-commit work is common to both completed and aborted commits.
    123   if (needs_forced_redraw_after_next_commit_) {
    124     needs_forced_redraw_after_next_commit_ = false;
    125     needs_forced_redraw_ = true;
    126   }
    127   if (needs_redraw_after_next_commit_) {
    128     needs_redraw_after_next_commit_ = false;
    129     needs_redraw_ = true;
    130   }
    131   texture_state_ = LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD;
    132 }
    133 
    134 bool SchedulerStateMachine::DrawSuspendedUntilCommit() const {
    135   if (!can_draw_)
    136     return true;
    137   if (!visible_)
    138     return true;
    139   if (texture_state_ == LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD)
    140     return true;
    141   return false;
    142 }
    143 
    144 bool SchedulerStateMachine::ScheduledToDraw() const {
    145   if (!needs_redraw_)
    146     return false;
    147   if (DrawSuspendedUntilCommit())
    148     return false;
    149   return true;
    150 }
    151 
    152 bool SchedulerStateMachine::ShouldDraw() const {
    153   if (needs_forced_redraw_)
    154     return true;
    155 
    156   if (!ScheduledToDraw())
    157     return false;
    158   if (!inside_begin_frame_)
    159     return false;
    160   if (HasDrawnThisFrame())
    161     return false;
    162   if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE)
    163     return false;
    164   return true;
    165 }
    166 
    167 bool SchedulerStateMachine::ShouldAttemptTreeActivation() const {
    168   // === START ANDROID FORK FOR http://b/11001058
    169   return has_pending_tree_ && !HasAttemptedTreeActivationThisFrame();
    170   // === END   ANDROID FORK FOR http://b/11001058
    171 }
    172 
    173 bool SchedulerStateMachine::ShouldUpdateVisibleTiles() const {
    174   if (!settings_.impl_side_painting)
    175     return false;
    176   if (HasUpdatedVisibleTilesThisFrame())
    177     return false;
    178 
    179   return ShouldAttemptTreeActivation() || ShouldDraw() ||
    180          swap_used_incomplete_tile_;
    181 }
    182 
    183 bool SchedulerStateMachine::ShouldAcquireLayerTexturesForMainThread() const {
    184   if (!main_thread_needs_layer_textures_)
    185     return false;
    186   if (texture_state_ == LAYER_TEXTURE_STATE_UNLOCKED)
    187     return true;
    188   DCHECK_EQ(texture_state_, LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD);
    189   // Transfer the lock from impl thread to main thread immediately if the
    190   // impl thread is not even scheduled to draw. Guards against deadlocking.
    191   if (!ScheduledToDraw())
    192     return true;
    193   if (!BeginFrameNeededToDrawByImplThread())
    194     return true;
    195   return false;
    196 }
    197 
    198 SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
    199   if (ShouldAcquireLayerTexturesForMainThread())
    200     return ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD;
    201 
    202   switch (commit_state_) {
    203     case COMMIT_STATE_IDLE: {
    204       if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE &&
    205           needs_forced_redraw_)
    206         return ACTION_DRAW_FORCED;
    207       if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE &&
    208           needs_forced_commit_)
    209         // TODO(enne): Should probably drop the active tree on force commit.
    210         return has_pending_tree_ ? ACTION_NONE
    211                                  : ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD;
    212       if (output_surface_state_ == OUTPUT_SURFACE_LOST && can_start_)
    213         return ACTION_BEGIN_OUTPUT_SURFACE_CREATION;
    214       if (output_surface_state_ == OUTPUT_SURFACE_CREATING)
    215         return ACTION_NONE;
    216       if (ShouldUpdateVisibleTiles())
    217         return ACTION_UPDATE_VISIBLE_TILES;
    218       if (ShouldAttemptTreeActivation())
    219         return ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED;
    220       if (ShouldDraw()) {
    221         return needs_forced_redraw_ ? ACTION_DRAW_FORCED
    222                                     : ACTION_DRAW_IF_POSSIBLE;
    223       }
    224       bool can_commit_this_frame =
    225           visible_ &&
    226           current_frame_number_ >
    227               last_frame_number_where_begin_frame_sent_to_main_thread_;
    228       if (needs_commit_ && ((can_commit_this_frame &&
    229                              output_surface_state_ == OUTPUT_SURFACE_ACTIVE) ||
    230                             needs_forced_commit_))
    231         // TODO(enne): Should probably drop the active tree on force commit.
    232         return has_pending_tree_ ? ACTION_NONE
    233                                  : ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD;
    234       return ACTION_NONE;
    235     }
    236     case COMMIT_STATE_FRAME_IN_PROGRESS:
    237       if (ShouldUpdateVisibleTiles())
    238         return ACTION_UPDATE_VISIBLE_TILES;
    239       if (ShouldAttemptTreeActivation())
    240         return ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED;
    241       if (ShouldDraw()) {
    242         return needs_forced_redraw_ ? ACTION_DRAW_FORCED
    243                                     : ACTION_DRAW_IF_POSSIBLE;
    244       }
    245       return ACTION_NONE;
    246 
    247     case COMMIT_STATE_READY_TO_COMMIT:
    248       return ACTION_COMMIT;
    249 
    250     case COMMIT_STATE_WAITING_FOR_FIRST_DRAW: {
    251       if (ShouldUpdateVisibleTiles())
    252         return ACTION_UPDATE_VISIBLE_TILES;
    253       if (ShouldAttemptTreeActivation())
    254         return ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED;
    255       if (ShouldDraw() || output_surface_state_ == OUTPUT_SURFACE_LOST) {
    256         return needs_forced_redraw_ ? ACTION_DRAW_FORCED
    257                                     : ACTION_DRAW_IF_POSSIBLE;
    258       }
    259       // COMMIT_STATE_WAITING_FOR_FIRST_DRAW wants to enforce a draw. If
    260       // can_draw_ is false or textures are not available, proceed to the next
    261       // step (similar as in COMMIT_STATE_IDLE).
    262       bool can_commit =
    263           needs_forced_commit_ ||
    264           (visible_ &&
    265            current_frame_number_ >
    266                last_frame_number_where_begin_frame_sent_to_main_thread_);
    267       if (needs_commit_ && can_commit && DrawSuspendedUntilCommit())
    268         return has_pending_tree_ ? ACTION_NONE
    269                                  : ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD;
    270       return ACTION_NONE;
    271     }
    272 
    273     case COMMIT_STATE_WAITING_FOR_FIRST_FORCED_DRAW:
    274       if (ShouldUpdateVisibleTiles())
    275         return ACTION_UPDATE_VISIBLE_TILES;
    276       if (ShouldAttemptTreeActivation())
    277         return ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED;
    278       if (needs_forced_redraw_)
    279         return ACTION_DRAW_FORCED;
    280       return ACTION_NONE;
    281   }
    282   NOTREACHED();
    283   return ACTION_NONE;
    284 }
    285 
    286 void SchedulerStateMachine::UpdateState(Action action) {
    287   switch (action) {
    288     case ACTION_NONE:
    289       return;
    290 
    291     case ACTION_UPDATE_VISIBLE_TILES:
    292       last_frame_number_where_update_visible_tiles_was_called_ =
    293           current_frame_number_;
    294       return;
    295 
    296     case ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED:
    297       last_frame_number_where_tree_activation_attempted_ =
    298           current_frame_number_;
    299       return;
    300 
    301     case ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD:
    302       DCHECK(!has_pending_tree_);
    303       if (!needs_forced_commit_) {
    304         DCHECK(visible_);
    305         DCHECK_GT(current_frame_number_,
    306                   last_frame_number_where_begin_frame_sent_to_main_thread_);
    307       }
    308       commit_state_ = COMMIT_STATE_FRAME_IN_PROGRESS;
    309       needs_commit_ = false;
    310       needs_forced_commit_ = false;
    311       last_frame_number_where_begin_frame_sent_to_main_thread_ =
    312           current_frame_number_;
    313       return;
    314 
    315     case ACTION_COMMIT:
    316       commit_count_++;
    317       if (expect_immediate_begin_frame_for_main_thread_)
    318         commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_FORCED_DRAW;
    319       else
    320         commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_DRAW;
    321       // When impl-side painting, we draw on activation instead of on commit.
    322       if (!settings_.impl_side_painting)
    323         needs_redraw_ = true;
    324       if (draw_if_possible_failed_)
    325         last_frame_number_where_draw_was_called_ = -1;
    326       SetPostCommitFlags();
    327       return;
    328 
    329     case ACTION_DRAW_FORCED:
    330     case ACTION_DRAW_IF_POSSIBLE:
    331       needs_redraw_ = false;
    332       needs_forced_redraw_ = false;
    333       draw_if_possible_failed_ = false;
    334       swap_used_incomplete_tile_ = false;
    335       if (inside_begin_frame_)
    336         last_frame_number_where_draw_was_called_ = current_frame_number_;
    337       if (commit_state_ == COMMIT_STATE_WAITING_FOR_FIRST_FORCED_DRAW) {
    338         DCHECK(expect_immediate_begin_frame_for_main_thread_);
    339         commit_state_ = COMMIT_STATE_FRAME_IN_PROGRESS;
    340         expect_immediate_begin_frame_for_main_thread_ = false;
    341       } else if (commit_state_ == COMMIT_STATE_WAITING_FOR_FIRST_DRAW) {
    342         commit_state_ = COMMIT_STATE_IDLE;
    343       }
    344       if (texture_state_ == LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD)
    345         texture_state_ = LAYER_TEXTURE_STATE_UNLOCKED;
    346       return;
    347 
    348     case ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
    349       DCHECK_EQ(commit_state_, COMMIT_STATE_IDLE);
    350       DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_LOST);
    351       output_surface_state_ = OUTPUT_SURFACE_CREATING;
    352       return;
    353 
    354     case ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD:
    355       texture_state_ = LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD;
    356       main_thread_needs_layer_textures_ = false;
    357       return;
    358   }
    359 }
    360 
    361 void SchedulerStateMachine::SetMainThreadNeedsLayerTextures() {
    362   DCHECK(!main_thread_needs_layer_textures_);
    363   DCHECK_NE(texture_state_, LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD);
    364   main_thread_needs_layer_textures_ = true;
    365 }
    366 
    367 bool SchedulerStateMachine::BeginFrameNeededToDrawByImplThread() const {
    368   // If we can't draw, don't tick until we are notified that we can draw again.
    369   if (!can_draw_)
    370     return false;
    371 
    372   if (needs_forced_redraw_)
    373     return true;
    374 
    375   if (visible_ && swap_used_incomplete_tile_)
    376     return true;
    377 
    378   return needs_redraw_ && visible_ &&
    379          output_surface_state_ == OUTPUT_SURFACE_ACTIVE;
    380 }
    381 
    382 bool SchedulerStateMachine::ProactiveBeginFrameWantedByImplThread() const {
    383   // Do not be proactive when invisible.
    384   if (!visible_ || output_surface_state_ != OUTPUT_SURFACE_ACTIVE)
    385     return false;
    386 
    387   // We should proactively request a BeginFrame if a commit or a tree activation
    388   // is pending.
    389   return (needs_commit_ || needs_forced_commit_ ||
    390           commit_state_ != COMMIT_STATE_IDLE || has_pending_tree_);
    391 }
    392 
    393 void SchedulerStateMachine::DidEnterBeginFrame(const BeginFrameArgs& args) {
    394   current_frame_number_++;
    395   inside_begin_frame_ = true;
    396   last_begin_frame_args_ = args;
    397 }
    398 
    399 void SchedulerStateMachine::DidLeaveBeginFrame() {
    400   inside_begin_frame_ = false;
    401 }
    402 
    403 void SchedulerStateMachine::PollForAnticipatedDrawTriggers() {
    404   current_frame_number_++;
    405 }
    406 
    407 void SchedulerStateMachine::SetVisible(bool visible) { visible_ = visible; }
    408 
    409 void SchedulerStateMachine::SetNeedsRedraw() { needs_redraw_ = true; }
    410 
    411 void SchedulerStateMachine::DidSwapUseIncompleteTile() {
    412   swap_used_incomplete_tile_ = true;
    413 }
    414 
    415 void SchedulerStateMachine::SetNeedsForcedRedraw() {
    416   needs_forced_redraw_ = true;
    417 }
    418 
    419 void SchedulerStateMachine::DidDrawIfPossibleCompleted(bool success) {
    420   draw_if_possible_failed_ = !success;
    421   if (draw_if_possible_failed_) {
    422     needs_redraw_ = true;
    423     needs_commit_ = true;
    424     consecutive_failed_draws_++;
    425     if (settings_.timeout_and_draw_when_animation_checkerboards &&
    426         consecutive_failed_draws_ >=
    427         maximum_number_of_failed_draws_before_draw_is_forced_) {
    428       consecutive_failed_draws_ = 0;
    429       // We need to force a draw, but it doesn't make sense to do this until
    430       // we've committed and have new textures.
    431       needs_forced_redraw_after_next_commit_ = true;
    432     }
    433   } else {
    434     consecutive_failed_draws_ = 0;
    435   }
    436 }
    437 
    438 void SchedulerStateMachine::SetNeedsCommit() { needs_commit_ = true; }
    439 
    440 void SchedulerStateMachine::SetNeedsForcedCommit() {
    441   needs_forced_commit_ = true;
    442   expect_immediate_begin_frame_for_main_thread_ = true;
    443 }
    444 
    445 void SchedulerStateMachine::FinishCommit() {
    446   DCHECK(commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS ||
    447          (expect_immediate_begin_frame_for_main_thread_ &&
    448           commit_state_ != COMMIT_STATE_IDLE))
    449       << ToString();
    450   commit_state_ = COMMIT_STATE_READY_TO_COMMIT;
    451 }
    452 
    453 void SchedulerStateMachine::BeginFrameAbortedByMainThread(bool did_handle) {
    454   DCHECK_EQ(commit_state_, COMMIT_STATE_FRAME_IN_PROGRESS);
    455   if (expect_immediate_begin_frame_for_main_thread_) {
    456     expect_immediate_begin_frame_for_main_thread_ = false;
    457   } else if (did_handle) {
    458     commit_state_ = COMMIT_STATE_IDLE;
    459     SetPostCommitFlags();
    460   } else {
    461     commit_state_ = COMMIT_STATE_IDLE;
    462     SetNeedsCommit();
    463   }
    464 }
    465 
    466 void SchedulerStateMachine::DidLoseOutputSurface() {
    467   if (output_surface_state_ == OUTPUT_SURFACE_LOST ||
    468       output_surface_state_ == OUTPUT_SURFACE_CREATING)
    469     return;
    470   output_surface_state_ = OUTPUT_SURFACE_LOST;
    471 }
    472 
    473 void SchedulerStateMachine::SetHasPendingTree(bool has_pending_tree) {
    474   has_pending_tree_ = has_pending_tree;
    475 }
    476 
    477 void SchedulerStateMachine::SetCanDraw(bool can) { can_draw_ = can; }
    478 
    479 void SchedulerStateMachine::DidCreateAndInitializeOutputSurface() {
    480   DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_CREATING);
    481   output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
    482 
    483   if (did_create_and_initialize_first_output_surface_) {
    484     // TODO(boliu): See if we can remove this when impl-side painting is always
    485     // on. Does anything on the main thread need to update after recreate?
    486     needs_commit_ = true;
    487     // If anything has requested a redraw, we don't want to actually draw
    488     // when the output surface is restored until things have a chance to
    489     // sort themselves out with a commit.
    490     needs_redraw_ = false;
    491   }
    492   needs_redraw_after_next_commit_ = true;
    493   did_create_and_initialize_first_output_surface_ = true;
    494 }
    495 
    496 bool SchedulerStateMachine::HasInitializedOutputSurface() const {
    497   return output_surface_state_ == OUTPUT_SURFACE_ACTIVE;
    498 }
    499 
    500 void SchedulerStateMachine::SetMaximumNumberOfFailedDrawsBeforeDrawIsForced(
    501     int num_draws) {
    502   maximum_number_of_failed_draws_before_draw_is_forced_ = num_draws;
    503 }
    504 
    505 }  // namespace cc
    506