| Index: cc/scheduler/scheduler_state_machine.cc
|
| diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
|
| index ed9c15f43f9d13af92e585dbf9ed58c608e99ecc..dbc026ca9f2e6be8403ec95fc7509ed13adcd6d6 100644
|
| --- a/cc/scheduler/scheduler_state_machine.cc
|
| +++ b/cc/scheduler/scheduler_state_machine.cc
|
| @@ -12,54 +12,64 @@ namespace cc {
|
|
|
| SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
|
| : settings_(settings),
|
| + output_surface_state_(OUTPUT_SURFACE_LOST),
|
| + begin_frame_state_(BEGIN_FRAME_STATE_IDLE),
|
| commit_state_(COMMIT_STATE_IDLE),
|
| + texture_state_(LAYER_TEXTURE_STATE_UNLOCKED),
|
| + readback_state_(READBACK_STATE_IDLE),
|
| + forced_redraw_state_(FORCED_REDRAW_STATE_IDLE),
|
| commit_count_(0),
|
| - current_frame_number_(0),
|
| - last_frame_number_where_begin_frame_sent_to_main_thread_(-1),
|
| - last_frame_number_where_draw_was_called_(-1),
|
| - last_frame_number_where_tree_activation_attempted_(-1),
|
| - last_frame_number_where_update_visible_tiles_was_called_(-1),
|
| + begin_frame_count_(0),
|
| + draw_attempt_count_(0),
|
| + last_begin_frame_count_swap_performed_(-1),
|
| + last_draw_attempt_count_draw_was_called_(-1),
|
| + last_begin_frame_count_begin_frame_sent_to_main_thread_(-1),
|
| + last_draw_attempt_count_tree_activation_attempted_(-1),
|
| + last_draw_attempt_count_update_visible_tiles_was_called_(-1),
|
| consecutive_failed_draws_(0),
|
| maximum_number_of_failed_draws_before_draw_is_forced_(3),
|
| needs_redraw_(false),
|
| swap_used_incomplete_tile_(false),
|
| - needs_forced_redraw_(false),
|
| - needs_forced_redraw_after_next_commit_(false),
|
| - needs_redraw_after_next_commit_(false),
|
| needs_commit_(false),
|
| - needs_forced_commit_(false),
|
| - expect_immediate_begin_frame_for_main_thread_(false),
|
| main_thread_needs_layer_textures_(false),
|
| - inside_begin_frame_(false),
|
| + active_tree_has_been_drawn_(false),
|
| + active_tree_is_null_(true),
|
| visible_(false),
|
| can_start_(false),
|
| can_draw_(false),
|
| has_pending_tree_(false),
|
| + pending_tree_is_ready_for_activation_(false),
|
| draw_if_possible_failed_(false),
|
| - texture_state_(LAYER_TEXTURE_STATE_UNLOCKED),
|
| - output_surface_state_(OUTPUT_SURFACE_LOST),
|
| did_create_and_initialize_first_output_surface_(false) {}
|
|
|
| std::string SchedulerStateMachine::ToString() {
|
| std::string str;
|
| - base::StringAppendF(&str,
|
| - "settings_.impl_side_painting = %d; ",
|
| + base::StringAppendF(&str, "settings_.impl_side_painting = %d; ",
|
| settings_.impl_side_painting);
|
| + base::StringAppendF(&str, "output_surface_state_ = %d; ",
|
| + output_surface_state_);
|
| + base::StringAppendF(&str, "begin_frame_state_ = %d; ", begin_frame_state_);
|
| base::StringAppendF(&str, "commit_state_ = %d; ", commit_state_);
|
| + base::StringAppendF(&str, "texture_state_ = %d; ", texture_state_);
|
| + base::StringAppendF(&str, "readback_state_ = %d; ", readback_state_);
|
| + base::StringAppendF(&str, "forced_redraw_state_ = %d; ",
|
| + forced_redraw_state_);
|
| base::StringAppendF(&str, "commit_count_ = %d; ", commit_count_);
|
| - base::StringAppendF(
|
| - &str, "current_frame_number_ = %d; ", current_frame_number_);
|
| + base::StringAppendF(&str, "begin_frame_count_ = %d; ", begin_frame_count_);
|
| + base::StringAppendF(&str, "draw_attempt_count_ = %d; ", draw_attempt_count_);
|
| + base::StringAppendF(&str, "last_begin_frame_count_swap_performed_ = %d; ",
|
| + last_begin_frame_count_swap_performed_);
|
| + base::StringAppendF(&str, "last_draw_attempt_count_draw_was_called_ = %d; ",
|
| + last_draw_attempt_count_draw_was_called_);
|
| base::StringAppendF(&str,
|
| - "last_frame_number_where_draw_was_called_ = %d; ",
|
| - last_frame_number_where_draw_was_called_);
|
| - base::StringAppendF(
|
| - &str,
|
| - "last_frame_number_where_tree_activation_attempted_ = %d; ",
|
| - last_frame_number_where_tree_activation_attempted_);
|
| - base::StringAppendF(
|
| - &str,
|
| - "last_frame_number_where_update_visible_tiles_was_called_ = %d; ",
|
| - last_frame_number_where_update_visible_tiles_was_called_);
|
| + "last_begin_frame_count_begin_frame_sent_to_main_thread_ = %d; ",
|
| + last_begin_frame_count_begin_frame_sent_to_main_thread_);
|
| + base::StringAppendF(&str,
|
| + "last_draw_attempt_count_tree_activation_attempted_ = %d; ",
|
| + last_draw_attempt_count_tree_activation_attempted_);
|
| + base::StringAppendF(&str,
|
| + "last_draw_attempt_count_update_visible_tiles_was_called_ = %d; ",
|
| + last_draw_attempt_count_update_visible_tiles_was_called_);
|
| base::StringAppendF(
|
| &str, "consecutive_failed_draws_ = %d; ", consecutive_failed_draws_);
|
| base::StringAppendF(
|
| @@ -69,22 +79,10 @@ std::string SchedulerStateMachine::ToString() {
|
| base::StringAppendF(&str, "needs_redraw_ = %d; ", needs_redraw_);
|
| base::StringAppendF(
|
| &str, "swap_used_incomplete_tile_ = %d; ", swap_used_incomplete_tile_);
|
| - base::StringAppendF(
|
| - &str, "needs_forced_redraw_ = %d; ", needs_forced_redraw_);
|
| - base::StringAppendF(&str,
|
| - "needs_forced_redraw_after_next_commit_ = %d; ",
|
| - needs_forced_redraw_after_next_commit_);
|
| base::StringAppendF(&str, "needs_commit_ = %d; ", needs_commit_);
|
| - base::StringAppendF(
|
| - &str, "needs_forced_commit_ = %d; ", needs_forced_commit_);
|
| - base::StringAppendF(&str,
|
| - "expect_immediate_begin_frame_for_main_thread_ = %d; ",
|
| - expect_immediate_begin_frame_for_main_thread_);
|
| base::StringAppendF(&str,
|
| "main_thread_needs_layer_textures_ = %d; ",
|
| main_thread_needs_layer_textures_);
|
| - base::StringAppendF(&str, "inside_begin_frame_ = %d; ",
|
| - inside_begin_frame_);
|
| base::StringAppendF(&str, "last_frame_time_ = %" PRId64 "; ",
|
| (last_begin_frame_args_.frame_time - base::TimeTicks())
|
| .InMilliseconds());
|
| @@ -98,36 +96,89 @@ std::string SchedulerStateMachine::ToString() {
|
| base::StringAppendF(
|
| &str, "draw_if_possible_failed_ = %d; ", draw_if_possible_failed_);
|
| base::StringAppendF(&str, "has_pending_tree_ = %d; ", has_pending_tree_);
|
| - base::StringAppendF(&str, "texture_state_ = %d; ", texture_state_);
|
| - base::StringAppendF(
|
| - &str, "output_surface_state_ = %d; ", output_surface_state_);
|
| + base::StringAppendF(&str,
|
| + "pending_tree_is_ready_for_activation_ = %d; ",
|
| + pending_tree_is_ready_for_activation_);
|
| + base::StringAppendF(&str, "active_tree_has_been_drawn_ = %d; ",
|
| + active_tree_has_been_drawn_);
|
| + base::StringAppendF(&str, "active_tree_is_null_ = %d; ",
|
| + active_tree_is_null_);
|
| return str;
|
| }
|
|
|
| bool SchedulerStateMachine::HasDrawnThisFrame() const {
|
| - return current_frame_number_ == last_frame_number_where_draw_was_called_;
|
| + return begin_frame_count_ == last_begin_frame_count_swap_performed_;
|
| }
|
|
|
| -bool SchedulerStateMachine::HasAttemptedTreeActivationThisFrame() const {
|
| - return current_frame_number_ ==
|
| - last_frame_number_where_tree_activation_attempted_;
|
| +bool SchedulerStateMachine::HasDrawnThisDrawAttempt() const {
|
| + return draw_attempt_count_ == last_draw_attempt_count_draw_was_called_;
|
| }
|
|
|
| -bool SchedulerStateMachine::HasUpdatedVisibleTilesThisFrame() const {
|
| - return current_frame_number_ ==
|
| - last_frame_number_where_update_visible_tiles_was_called_;
|
| +bool SchedulerStateMachine::HasSentBeginFrameToMainThreadThisFrame() const {
|
| + return begin_frame_count_ ==
|
| + last_begin_frame_count_begin_frame_sent_to_main_thread_;
|
| }
|
|
|
| -void SchedulerStateMachine::SetPostCommitFlags() {
|
| - // This post-commit work is common to both completed and aborted commits.
|
| - if (needs_forced_redraw_after_next_commit_) {
|
| - needs_forced_redraw_after_next_commit_ = false;
|
| - needs_forced_redraw_ = true;
|
| - }
|
| - if (needs_redraw_after_next_commit_) {
|
| - needs_redraw_after_next_commit_ = false;
|
| - needs_redraw_ = true;
|
| +bool SchedulerStateMachine::HasUpdatedVisibleTilesThisDrawAttempt() const {
|
| + return draw_attempt_count_ ==
|
| + last_draw_attempt_count_update_visible_tiles_was_called_;
|
| +}
|
| +
|
| +bool SchedulerStateMachine::HasActivatedPendingTreeThisDrawAttempt() const {
|
| + return draw_attempt_count_ ==
|
| + last_draw_attempt_count_tree_activation_attempted_;
|
| +}
|
| +
|
| +void SchedulerStateMachine::HandleCommitInternal(bool commit_was_aborted) {
|
| + commit_count_++;
|
| + draw_attempt_count_++;
|
| +
|
| + // If we are impl-side-painting but the commit was aborted, then we behave
|
| + // as if we are not impl-side-painting since there is no pending tree.
|
| + if (settings_.impl_side_painting && !commit_was_aborted) {
|
| + commit_state_ = COMMIT_STATE_WAITING_FOR_ACTIVATION;
|
| +
|
| + if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT)
|
| + output_surface_state_ = OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION;
|
| +
|
| + if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT)
|
| + forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION;
|
| + else if (readback_state_ == READBACK_STATE_FORCED_COMMIT_PENDING)
|
| + readback_state_ = READBACK_STATE_WAITING_FOR_ACTIVATION;
|
| + else if (readback_state_ == READBACK_STATE_REPLACEMENT_COMMIT_PENDING)
|
| + readback_state_ = READBACK_STATE_REPLACEMENT_COMMIT_ACTIVATING;
|
| +
|
| + } else {
|
| + if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT) {
|
| + output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
|
| + needs_redraw_ = true;
|
| + }
|
| +
|
| + if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT)
|
| + forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_DRAW;
|
| + else if (readback_state_ == READBACK_STATE_FORCED_COMMIT_PENDING)
|
| + readback_state_ = READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK;
|
| + else if (readback_state_ == READBACK_STATE_REPLACEMENT_COMMIT_PENDING)
|
| + readback_state_ = READBACK_STATE_IDLE;
|
| +
|
| + if (draw_if_possible_failed_) {
|
| + last_begin_frame_count_swap_performed_ = -1;
|
| + last_draw_attempt_count_draw_was_called_ = -1;
|
| + }
|
| +
|
| + if (commit_was_aborted) {
|
| + if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW ||
|
| + readback_state_ == READBACK_STATE_FORCED_COMMIT_PENDING)
|
| + commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_DRAW;
|
| + else
|
| + commit_state_ = COMMIT_STATE_IDLE;
|
| + } else {
|
| + commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_DRAW;
|
| + active_tree_has_been_drawn_ = false;
|
| + needs_redraw_ = true;
|
| + }
|
| }
|
| +
|
| texture_state_ = LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD;
|
| }
|
|
|
| @@ -150,12 +201,43 @@ bool SchedulerStateMachine::ScheduledToDraw() const {
|
| }
|
|
|
| bool SchedulerStateMachine::ShouldDraw() const {
|
| - if (needs_forced_redraw_)
|
| + if (HasDrawnThisDrawAttempt())
|
| + return false;
|
| +
|
| + // After a readback, make sure not to draw again until we've replaced the
|
| + // readback commit with a real one.
|
| + if (readback_state_ == READBACK_STATE_REPLACEMENT_COMMIT_PENDING ||
|
| + readback_state_ == READBACK_STATE_REPLACEMENT_COMMIT_ACTIVATING)
|
| + return false;
|
| +
|
| + // Draw outside of the BeginFrame deadline for readbacks.
|
| + if (readback_state_ == READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK) {
|
| + DCHECK_EQ(commit_state_, COMMIT_STATE_WAITING_FOR_FIRST_DRAW);
|
| return true;
|
| + }
|
|
|
| - if (!ScheduledToDraw())
|
| + // If we've lost the output surface or draw is suspended, we want to be able
|
| + // to abort a draw and make forward progress to unblock the main thread.
|
| + if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE ||
|
| + DrawSuspendedUntilCommit()) {
|
| + return !active_tree_has_been_drawn_ &&
|
| + (commit_state_ == COMMIT_STATE_WAITING_FOR_FIRST_DRAW ||
|
| + commit_state_ == COMMIT_STATE_WAITING_FOR_ACTIVATION ||
|
| + (output_surface_state_ != OUTPUT_SURFACE_ACTIVE &&
|
| + !active_tree_is_null_));
|
| + }
|
| +
|
| + // Except for the cases above, do not draw outside of the BeginFrame deadline.
|
| + if (begin_frame_state_ != BEGIN_FRAME_STATE_INSIDE_DEADLINE)
|
| return false;
|
| - if (!inside_begin_frame_)
|
| +
|
| + // Only handle forced redraws due to timeouts on the regular deadline.
|
| + if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW) {
|
| + DCHECK_EQ(commit_state_, COMMIT_STATE_WAITING_FOR_FIRST_DRAW);
|
| + return true;
|
| + }
|
| +
|
| + if (!ScheduledToDraw())
|
| return false;
|
| if (HasDrawnThisFrame())
|
| return false;
|
| @@ -164,18 +246,43 @@ bool SchedulerStateMachine::ShouldDraw() const {
|
| return true;
|
| }
|
|
|
| -bool SchedulerStateMachine::ShouldAttemptTreeActivation() const {
|
| - return has_pending_tree_ && inside_begin_frame_ &&
|
| - !HasAttemptedTreeActivationThisFrame();
|
| +bool SchedulerStateMachine::ShouldActivatePendingTree() const {
|
| + // Some quick early outs.
|
| + if (!has_pending_tree_)
|
| + return false;
|
| + if (HasActivatedPendingTreeThisDrawAttempt())
|
| + return false;
|
| +
|
| + // If this is our first activation, we don't want to activate early.
|
| + if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION)
|
| + return pending_tree_is_ready_for_activation_;
|
| +
|
| + // In these cases, we want to activate even if the pending tree isn't ready
|
| + // because we aren't going to draw the pending tree or need to make
|
| + // forward progress to unblock the main thread.
|
| + if (!visible_ ||
|
| + output_surface_state_ == OUTPUT_SURFACE_LOST ||
|
| + output_surface_state_ == OUTPUT_SURFACE_CREATING ||
|
| + output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT)
|
| + return true;
|
| +
|
| + // After this line, we only want to activate if we are ready to activate.
|
| + if (!pending_tree_is_ready_for_activation_)
|
| + return false;
|
| +
|
| + // We do not want to activate a second tree before drawing the first one.
|
| + // Note: If we cannot draw, activation will eventually be unblocked by
|
| + // ACTION_DRAW_AND_SWAP_ABORT which will set active_tree_has_been_drawn_.
|
| + return active_tree_has_been_drawn_ || active_tree_is_null_;
|
| }
|
|
|
| bool SchedulerStateMachine::ShouldUpdateVisibleTiles() const {
|
| if (!settings_.impl_side_painting)
|
| return false;
|
| - if (HasUpdatedVisibleTilesThisFrame())
|
| + if (HasUpdatedVisibleTilesThisDrawAttempt())
|
| return false;
|
|
|
| - return ShouldAttemptTreeActivation() || ShouldDraw() ||
|
| + return ShouldActivatePendingTree() || ShouldDraw() ||
|
| swap_used_incomplete_tile_;
|
| }
|
|
|
| @@ -194,89 +301,136 @@ bool SchedulerStateMachine::ShouldAcquireLayerTexturesForMainThread() const {
|
| return false;
|
| }
|
|
|
| +bool SchedulerStateMachine::ShouldSendBeginFrameToMainThread() const {
|
| + if (HasSentBeginFrameToMainThreadThisFrame())
|
| + return false;
|
| +
|
| + // Only send BeginFrame to the main thread when idle.
|
| + if (commit_state_ != COMMIT_STATE_IDLE)
|
| + return false;
|
| +
|
| + // We can't accept a commit if we have a pending tree.
|
| + if (has_pending_tree_)
|
| + return false;
|
| +
|
| + // We want to handle readback commits ASAP.
|
| + if (readback_state_ == READBACK_STATE_FORCED_COMMIT_REQUESTED)
|
| + return !CommitPending();
|
| +
|
| + // We want to start the first commit after we get a new output surface
|
| + // immediately.
|
| + if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT
|
| + && needs_commit_)
|
| + return true;
|
| +
|
| + // We usually want to slave the main thread's BeginFrame to the impl thread's
|
| + // BeginFrame. However, if we aren't expecting a BeginFrame on the impl
|
| + // thread, we should send a BeginFrame to the main thread anyway to make
|
| + // progress.
|
| + // TODO(brianderson): Also allow sending BeginFrame to main thread while idle
|
| + // when the main thread isn't consuming user input.
|
| + if (begin_frame_state_ == BEGIN_FRAME_STATE_IDLE &&
|
| + BeginFrameNeededByImplThread())
|
| + return false;
|
| +
|
| + // Do not send begin frame to main thread in the deadline until we have drawn.
|
| + // We have a train to catch!
|
| + if (begin_frame_state_ == BEGIN_FRAME_STATE_INSIDE_DEADLINE &&
|
| + !HasDrawnThisFrame())
|
| + return false;
|
| +
|
| + // If not impl-side-painting, do not send a BeginFrame to the main thread if
|
| + // we haven't drawn the active tree. Otherwise, the commit overwrite the
|
| + // active tree before we have a chance to draw it.
|
| + if (!settings_.impl_side_painting &&
|
| + !active_tree_has_been_drawn_ &&
|
| + !active_tree_is_null_)
|
| + return false;
|
| +
|
| + bool can_commit = needs_commit_ &&
|
| + (visible_ ||
|
| + forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT);
|
| + return can_commit &&
|
| + (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT ||
|
| + HasInitializedOutputSurface());
|
| +}
|
| +
|
| SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
|
| if (ShouldAcquireLayerTexturesForMainThread())
|
| return ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD;
|
|
|
| switch (commit_state_) {
|
| - case COMMIT_STATE_IDLE: {
|
| - if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE &&
|
| - needs_forced_redraw_)
|
| - return ACTION_DRAW_FORCED;
|
| - if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE &&
|
| - needs_forced_commit_)
|
| - // TODO(enne): Should probably drop the active tree on force commit.
|
| - return has_pending_tree_ ? ACTION_NONE
|
| - : ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD;
|
| + case COMMIT_STATE_IDLE:
|
| + if (ShouldSendBeginFrameToMainThread())
|
| + return ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD;
|
| if (output_surface_state_ == OUTPUT_SURFACE_LOST && can_start_)
|
| return ACTION_BEGIN_OUTPUT_SURFACE_CREATION;
|
| if (output_surface_state_ == OUTPUT_SURFACE_CREATING)
|
| return ACTION_NONE;
|
| if (ShouldUpdateVisibleTiles())
|
| return ACTION_UPDATE_VISIBLE_TILES;
|
| - if (ShouldAttemptTreeActivation())
|
| - return ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED;
|
| + if (ShouldActivatePendingTree())
|
| + return ACTION_ACTIVATE_PENDING_TREE;
|
| if (ShouldDraw()) {
|
| - return needs_forced_redraw_ ? ACTION_DRAW_FORCED
|
| - : ACTION_DRAW_IF_POSSIBLE;
|
| + if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE ||
|
| + DrawSuspendedUntilCommit())
|
| + return ACTION_DRAW_AND_SWAP_ABORT;
|
| + else
|
| + return ACTION_DRAW_AND_SWAP_IF_POSSIBLE;
|
| }
|
| - bool can_commit_this_frame =
|
| - visible_ &&
|
| - current_frame_number_ >
|
| - last_frame_number_where_begin_frame_sent_to_main_thread_;
|
| - if (needs_commit_ && ((can_commit_this_frame &&
|
| - output_surface_state_ == OUTPUT_SURFACE_ACTIVE) ||
|
| - needs_forced_commit_))
|
| - // TODO(enne): Should probably drop the active tree on force commit.
|
| - return has_pending_tree_ ? ACTION_NONE
|
| - : ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD;
|
| return ACTION_NONE;
|
| - }
|
| +
|
| case COMMIT_STATE_FRAME_IN_PROGRESS:
|
| if (ShouldUpdateVisibleTiles())
|
| return ACTION_UPDATE_VISIBLE_TILES;
|
| - if (ShouldAttemptTreeActivation())
|
| - return ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED;
|
| + if (ShouldActivatePendingTree())
|
| + return ACTION_ACTIVATE_PENDING_TREE;
|
| if (ShouldDraw()) {
|
| - return needs_forced_redraw_ ? ACTION_DRAW_FORCED
|
| - : ACTION_DRAW_IF_POSSIBLE;
|
| + if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE ||
|
| + DrawSuspendedUntilCommit())
|
| + return ACTION_DRAW_AND_SWAP_ABORT;
|
| + else
|
| + return ACTION_DRAW_AND_SWAP_IF_POSSIBLE;
|
| }
|
| return ACTION_NONE;
|
|
|
| case COMMIT_STATE_READY_TO_COMMIT:
|
| return ACTION_COMMIT;
|
|
|
| - case COMMIT_STATE_WAITING_FOR_FIRST_DRAW: {
|
| + case COMMIT_STATE_WAITING_FOR_ACTIVATION: {
|
| if (ShouldUpdateVisibleTiles())
|
| return ACTION_UPDATE_VISIBLE_TILES;
|
| - if (ShouldAttemptTreeActivation())
|
| - return ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED;
|
| - if (ShouldDraw() || output_surface_state_ == OUTPUT_SURFACE_LOST) {
|
| - return needs_forced_redraw_ ? ACTION_DRAW_FORCED
|
| - : ACTION_DRAW_IF_POSSIBLE;
|
| + if (ShouldActivatePendingTree())
|
| + return ACTION_ACTIVATE_PENDING_TREE;
|
| + if (ShouldDraw()) {
|
| + if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE ||
|
| + DrawSuspendedUntilCommit())
|
| + return ACTION_DRAW_AND_SWAP_ABORT;
|
| + else
|
| + return ACTION_DRAW_AND_SWAP_IF_POSSIBLE;
|
| }
|
| - // COMMIT_STATE_WAITING_FOR_FIRST_DRAW wants to enforce a draw. If
|
| - // can_draw_ is false or textures are not available, proceed to the next
|
| - // step (similar as in COMMIT_STATE_IDLE).
|
| - bool can_commit =
|
| - needs_forced_commit_ ||
|
| - (visible_ &&
|
| - current_frame_number_ >
|
| - last_frame_number_where_begin_frame_sent_to_main_thread_);
|
| - if (needs_commit_ && can_commit && DrawSuspendedUntilCommit())
|
| - return has_pending_tree_ ? ACTION_NONE
|
| - : ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD;
|
| return ACTION_NONE;
|
| }
|
|
|
| - case COMMIT_STATE_WAITING_FOR_FIRST_FORCED_DRAW:
|
| + case COMMIT_STATE_WAITING_FOR_FIRST_DRAW: {
|
| if (ShouldUpdateVisibleTiles())
|
| return ACTION_UPDATE_VISIBLE_TILES;
|
| - if (ShouldAttemptTreeActivation())
|
| - return ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED;
|
| - if (needs_forced_redraw_)
|
| - return ACTION_DRAW_FORCED;
|
| + if (ShouldActivatePendingTree())
|
| + return ACTION_ACTIVATE_PENDING_TREE;
|
| + if (ShouldDraw()) {
|
| + if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
|
| + return ACTION_DRAW_AND_SWAP_FORCED;
|
| + else if (readback_state_ ==
|
| + READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK)
|
| + return ACTION_DRAW_AND_READBACK;
|
| + else if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE ||
|
| + DrawSuspendedUntilCommit())
|
| + return ACTION_DRAW_AND_SWAP_ABORT;
|
| + else
|
| + return ACTION_DRAW_AND_SWAP_IF_POSSIBLE;
|
| + }
|
| return ACTION_NONE;
|
| + }
|
| }
|
| NOTREACHED();
|
| return ACTION_NONE;
|
| @@ -288,60 +442,41 @@ void SchedulerStateMachine::UpdateState(Action action) {
|
| return;
|
|
|
| case ACTION_UPDATE_VISIBLE_TILES:
|
| - last_frame_number_where_update_visible_tiles_was_called_ =
|
| - current_frame_number_;
|
| + last_draw_attempt_count_update_visible_tiles_was_called_ =
|
| + draw_attempt_count_;
|
| return;
|
|
|
| - case ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED:
|
| - last_frame_number_where_tree_activation_attempted_ =
|
| - current_frame_number_;
|
| + case ACTION_ACTIVATE_PENDING_TREE:
|
| + last_draw_attempt_count_tree_activation_attempted_ =
|
| + draw_attempt_count_;
|
| return;
|
|
|
| case ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD:
|
| DCHECK(!has_pending_tree_);
|
| - if (!needs_forced_commit_) {
|
| - DCHECK(visible_);
|
| - DCHECK_GT(current_frame_number_,
|
| - last_frame_number_where_begin_frame_sent_to_main_thread_);
|
| - }
|
| + DCHECK(visible_ ||
|
| + readback_state_ == READBACK_STATE_FORCED_COMMIT_REQUESTED ||
|
| + forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT ||
|
| + output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT);
|
| commit_state_ = COMMIT_STATE_FRAME_IN_PROGRESS;
|
| needs_commit_ = false;
|
| - needs_forced_commit_ = false;
|
| - last_frame_number_where_begin_frame_sent_to_main_thread_ =
|
| - current_frame_number_;
|
| + if (readback_state_ == READBACK_STATE_FORCED_COMMIT_REQUESTED)
|
| + readback_state_ = READBACK_STATE_FORCED_COMMIT_PENDING;
|
| + last_begin_frame_count_begin_frame_sent_to_main_thread_ =
|
| + begin_frame_count_;
|
| return;
|
|
|
| case ACTION_COMMIT:
|
| - commit_count_++;
|
| - if (expect_immediate_begin_frame_for_main_thread_)
|
| - commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_FORCED_DRAW;
|
| - else
|
| - commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_DRAW;
|
| - // When impl-side painting, we draw on activation instead of on commit.
|
| - if (!settings_.impl_side_painting)
|
| - needs_redraw_ = true;
|
| - if (draw_if_possible_failed_)
|
| - last_frame_number_where_draw_was_called_ = -1;
|
| - SetPostCommitFlags();
|
| + HandleCommitInternal(false);
|
| return;
|
|
|
| - case ACTION_DRAW_FORCED:
|
| - case ACTION_DRAW_IF_POSSIBLE:
|
| - needs_redraw_ = false;
|
| - needs_forced_redraw_ = false;
|
| - draw_if_possible_failed_ = false;
|
| - swap_used_incomplete_tile_ = false;
|
| - if (inside_begin_frame_)
|
| - last_frame_number_where_draw_was_called_ = current_frame_number_;
|
| - if (commit_state_ == COMMIT_STATE_WAITING_FOR_FIRST_FORCED_DRAW) {
|
| - DCHECK(expect_immediate_begin_frame_for_main_thread_);
|
| - commit_state_ = COMMIT_STATE_FRAME_IN_PROGRESS;
|
| - expect_immediate_begin_frame_for_main_thread_ = false;
|
| - } else if (commit_state_ == COMMIT_STATE_WAITING_FOR_FIRST_DRAW) {
|
| - commit_state_ = COMMIT_STATE_IDLE;
|
| - }
|
| - if (texture_state_ == LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD)
|
| - texture_state_ = LAYER_TEXTURE_STATE_UNLOCKED;
|
| + case ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
|
| + case ACTION_DRAW_AND_SWAP_FORCED:
|
| + UpdateStateOnDraw(true);
|
| + return;
|
| +
|
| + case ACTION_DRAW_AND_READBACK:
|
| + case ACTION_DRAW_AND_SWAP_ABORT:
|
| + UpdateStateOnDraw(false);
|
| return;
|
|
|
| case ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
|
| @@ -357,49 +492,115 @@ void SchedulerStateMachine::UpdateState(Action action) {
|
| }
|
| }
|
|
|
| +void SchedulerStateMachine::UpdateStateOnDraw(bool did_swap) {
|
| + if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW) {
|
| + commit_state_ = COMMIT_STATE_IDLE;
|
| + forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE;
|
| + } else if (readback_state_ ==
|
| + READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK) {
|
| + DCHECK(!has_pending_tree_);
|
| + commit_state_ = COMMIT_STATE_FRAME_IN_PROGRESS;
|
| + readback_state_ = READBACK_STATE_REPLACEMENT_COMMIT_PENDING;
|
| + } else if (commit_state_ == COMMIT_STATE_WAITING_FOR_FIRST_DRAW) {
|
| + commit_state_ = COMMIT_STATE_IDLE;
|
| + }
|
| +
|
| + if (texture_state_ == LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD)
|
| + texture_state_ = LAYER_TEXTURE_STATE_UNLOCKED;
|
| +
|
| + needs_redraw_ = false;
|
| + active_tree_has_been_drawn_ = true;
|
| + draw_if_possible_failed_ = false;
|
| + last_draw_attempt_count_draw_was_called_ = draw_attempt_count_;
|
| +
|
| + if (did_swap) {
|
| + swap_used_incomplete_tile_ = false;
|
| + last_begin_frame_count_swap_performed_ = begin_frame_count_;
|
| + }
|
| +}
|
| +
|
| +void SchedulerStateMachine::AdvanceBeginFrameStateWhenNoActionsRemain() {
|
| + switch (begin_frame_state_) {
|
| + case BEGIN_FRAME_STATE_INSIDE_BEGIN_FRAME:
|
| + begin_frame_state_ = BEGIN_FRAME_STATE_DEADLINE_PENDING;
|
| + break;
|
| + case BEGIN_FRAME_STATE_INSIDE_DEADLINE:
|
| + begin_frame_state_ = BEGIN_FRAME_STATE_IDLE;
|
| + break;
|
| + case BEGIN_FRAME_STATE_IDLE:
|
| + case BEGIN_FRAME_STATE_DEADLINE_PENDING:
|
| + break;
|
| + }
|
| +}
|
| +
|
| void SchedulerStateMachine::SetMainThreadNeedsLayerTextures() {
|
| DCHECK(!main_thread_needs_layer_textures_);
|
| DCHECK_NE(texture_state_, LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD);
|
| main_thread_needs_layer_textures_ = true;
|
| }
|
|
|
| +bool SchedulerStateMachine::BeginFrameNeededByImplThread() const {
|
| + return BeginFrameNeededToDrawByImplThread() ||
|
| + BeginFrameProactivelyNeededByImplThread();
|
| +}
|
| +
|
| bool SchedulerStateMachine::BeginFrameNeededToDrawByImplThread() const {
|
| // If we can't draw, don't tick until we are notified that we can draw again.
|
| if (!can_draw_)
|
| return false;
|
|
|
| - if (needs_forced_redraw_)
|
| + if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
|
| return true;
|
|
|
| if (visible_ && swap_used_incomplete_tile_)
|
| return true;
|
|
|
| - return needs_redraw_ && visible_ &&
|
| - output_surface_state_ == OUTPUT_SURFACE_ACTIVE;
|
| + return needs_redraw_ && visible_ && HasInitializedOutputSurface();
|
| }
|
|
|
| -bool SchedulerStateMachine::ProactiveBeginFrameWantedByImplThread() const {
|
| - // Do not be proactive when invisible.
|
| - if (!visible_ || output_surface_state_ != OUTPUT_SURFACE_ACTIVE)
|
| +bool SchedulerStateMachine::BeginFrameProactivelyNeededByImplThread() const {
|
| + if (settings_.using_synchronous_renderer_compositor)
|
| + return false;
|
| +
|
| + if (!settings_.throttle_frame_production)
|
| + return false;
|
| +
|
| + if (!visible_ || !HasInitializedOutputSurface())
|
| return false;
|
|
|
| // We should proactively request a BeginFrame if a commit or a tree activation
|
| // is pending.
|
| - return (needs_commit_ || needs_forced_commit_ ||
|
| - commit_state_ != COMMIT_STATE_IDLE || has_pending_tree_);
|
| + return (needs_commit_ ||
|
| + commit_state_ != COMMIT_STATE_IDLE ||
|
| + has_pending_tree_);
|
| }
|
|
|
| -void SchedulerStateMachine::DidEnterBeginFrame(const BeginFrameArgs& args) {
|
| - current_frame_number_++;
|
| - inside_begin_frame_ = true;
|
| +void SchedulerStateMachine::OnBeginFrame(const BeginFrameArgs& args) {
|
| + begin_frame_count_++;
|
| + draw_attempt_count_++;
|
| last_begin_frame_args_ = args;
|
| + begin_frame_state_ = BEGIN_FRAME_STATE_INSIDE_BEGIN_FRAME;
|
| +}
|
| +
|
| +bool SchedulerStateMachine::ShouldTriggerBeginFrameDeadlineEarly() const {
|
| + // TODO(brianderson): This should take into account multiple commit sources.
|
| + return begin_frame_state_ == BEGIN_FRAME_STATE_DEADLINE_PENDING &&
|
| + !active_tree_has_been_drawn_;
|
| +}
|
| +
|
| +bool SchedulerStateMachine::InsideBeginFrame() const {
|
| + return begin_frame_state_ != BEGIN_FRAME_STATE_IDLE;
|
| }
|
|
|
| -void SchedulerStateMachine::DidLeaveBeginFrame() {
|
| - inside_begin_frame_ = false;
|
| +void SchedulerStateMachine::OnBeginFrameDeadline() {
|
| + DCHECK_EQ(begin_frame_state_, BEGIN_FRAME_STATE_DEADLINE_PENDING);
|
| + draw_attempt_count_++;
|
| + begin_frame_state_ = BEGIN_FRAME_STATE_INSIDE_DEADLINE;
|
| }
|
|
|
| -void SchedulerStateMachine::SetVisible(bool visible) { visible_ = visible; }
|
| +void SchedulerStateMachine::SetVisible(bool visible) {
|
| + visible_ = visible;
|
| +}
|
|
|
| void SchedulerStateMachine::SetNeedsRedraw() { needs_redraw_ = true; }
|
|
|
| @@ -407,10 +608,6 @@ void SchedulerStateMachine::DidSwapUseIncompleteTile() {
|
| swap_used_incomplete_tile_ = true;
|
| }
|
|
|
| -void SchedulerStateMachine::SetNeedsForcedRedraw() {
|
| - needs_forced_redraw_ = true;
|
| -}
|
| -
|
| void SchedulerStateMachine::DidDrawIfPossibleCompleted(bool success) {
|
| draw_if_possible_failed_ = !success;
|
| if (draw_if_possible_failed_) {
|
| @@ -423,7 +620,7 @@ void SchedulerStateMachine::DidDrawIfPossibleCompleted(bool success) {
|
| consecutive_failed_draws_ = 0;
|
| // We need to force a draw, but it doesn't make sense to do this until
|
| // we've committed and have new textures.
|
| - needs_forced_redraw_after_next_commit_ = true;
|
| + forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_COMMIT;
|
| }
|
| } else {
|
| consecutive_failed_draws_ = 0;
|
| @@ -432,26 +629,28 @@ void SchedulerStateMachine::DidDrawIfPossibleCompleted(bool success) {
|
|
|
| void SchedulerStateMachine::SetNeedsCommit() { needs_commit_ = true; }
|
|
|
| -void SchedulerStateMachine::SetNeedsForcedCommit() {
|
| - needs_forced_commit_ = true;
|
| - expect_immediate_begin_frame_for_main_thread_ = true;
|
| +void SchedulerStateMachine::SetNeedsForcedCommitForReadback() {
|
| + DCHECK(readback_state_ == READBACK_STATE_IDLE ||
|
| + readback_state_ == READBACK_STATE_REPLACEMENT_COMMIT_PENDING);
|
| + if (commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS)
|
| + readback_state_ = READBACK_STATE_FORCED_COMMIT_PENDING;
|
| + else
|
| + readback_state_ = READBACK_STATE_FORCED_COMMIT_REQUESTED;
|
| }
|
|
|
| void SchedulerStateMachine::FinishCommit() {
|
| DCHECK(commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS ||
|
| - (expect_immediate_begin_frame_for_main_thread_ &&
|
| - commit_state_ != COMMIT_STATE_IDLE))
|
| + readback_state_ == READBACK_STATE_FORCED_COMMIT_PENDING)
|
| << ToString();
|
| commit_state_ = COMMIT_STATE_READY_TO_COMMIT;
|
| }
|
|
|
| void SchedulerStateMachine::BeginFrameAbortedByMainThread(bool did_handle) {
|
| DCHECK_EQ(commit_state_, COMMIT_STATE_FRAME_IN_PROGRESS);
|
| - if (expect_immediate_begin_frame_for_main_thread_) {
|
| - expect_immediate_begin_frame_for_main_thread_ = false;
|
| + if (readback_state_ == READBACK_STATE_FORCED_COMMIT_REQUESTED) {
|
| + readback_state_ = READBACK_STATE_IDLE;
|
| } else if (did_handle) {
|
| - commit_state_ = COMMIT_STATE_IDLE;
|
| - SetPostCommitFlags();
|
| + HandleCommitInternal(true);
|
| } else {
|
| commit_state_ = COMMIT_STATE_IDLE;
|
| SetNeedsCommit();
|
| @@ -463,33 +662,67 @@ void SchedulerStateMachine::DidLoseOutputSurface() {
|
| output_surface_state_ == OUTPUT_SURFACE_CREATING)
|
| return;
|
| output_surface_state_ = OUTPUT_SURFACE_LOST;
|
| + needs_redraw_ = false;
|
| }
|
|
|
| -void SchedulerStateMachine::SetHasPendingTree(bool has_pending_tree) {
|
| +void SchedulerStateMachine::NotifyReadyToActivate() {
|
| + if (has_pending_tree_)
|
| + pending_tree_is_ready_for_activation_ = true;
|
| +}
|
| +
|
| +void SchedulerStateMachine::SetHasTrees(bool has_pending_tree,
|
| + bool active_tree_is_null) {
|
| + active_tree_is_null_ = active_tree_is_null;
|
| + if (has_pending_tree_ && !has_pending_tree) {
|
| + // There is a new active tree.
|
| + draw_attempt_count_++;
|
| + pending_tree_is_ready_for_activation_ = false;
|
| + active_tree_has_been_drawn_ = false;
|
| + needs_redraw_ = true;
|
| +
|
| + if (draw_if_possible_failed_) {
|
| + last_begin_frame_count_swap_performed_ = -1;
|
| + last_draw_attempt_count_draw_was_called_ = -1;
|
| + }
|
| +
|
| + if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION)
|
| + output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
|
| +
|
| + DCHECK_EQ(COMMIT_STATE_WAITING_FOR_ACTIVATION, commit_state_);
|
| + if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION) {
|
| + commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_DRAW;
|
| + forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_DRAW;
|
| + } else if (readback_state_ == READBACK_STATE_WAITING_FOR_ACTIVATION) {
|
| + commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_DRAW;
|
| + readback_state_ = READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK;
|
| + } else {
|
| + commit_state_ = COMMIT_STATE_IDLE;
|
| + if (readback_state_ == READBACK_STATE_REPLACEMENT_COMMIT_ACTIVATING)
|
| + readback_state_ = READBACK_STATE_IDLE;
|
| + }
|
| + } else if (!has_pending_tree_ && has_pending_tree) {
|
| + // There is a new pending tree.
|
| + pending_tree_is_ready_for_activation_ = false;
|
| + }
|
| +
|
| has_pending_tree_ = has_pending_tree;
|
| }
|
|
|
| -void SchedulerStateMachine::SetCanDraw(bool can) { can_draw_ = can; }
|
| +void SchedulerStateMachine::SetCanDraw(bool can_draw) {
|
| + can_draw_ = can_draw;
|
| +}
|
|
|
| void SchedulerStateMachine::DidCreateAndInitializeOutputSurface() {
|
| DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_CREATING);
|
| - output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
|
| -
|
| - if (did_create_and_initialize_first_output_surface_) {
|
| - // TODO(boliu): See if we can remove this when impl-side painting is always
|
| - // on. Does anything on the main thread need to update after recreate?
|
| + output_surface_state_ = OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT;
|
| + if (did_create_and_initialize_first_output_surface_)
|
| needs_commit_ = true;
|
| - // If anything has requested a redraw, we don't want to actually draw
|
| - // when the output surface is restored until things have a chance to
|
| - // sort themselves out with a commit.
|
| - needs_redraw_ = false;
|
| - }
|
| - needs_redraw_after_next_commit_ = true;
|
| did_create_and_initialize_first_output_surface_ = true;
|
| }
|
|
|
| bool SchedulerStateMachine::HasInitializedOutputSurface() const {
|
| - return output_surface_state_ == OUTPUT_SURFACE_ACTIVE;
|
| + return output_surface_state_ != OUTPUT_SURFACE_LOST &&
|
| + output_surface_state_ != OUTPUT_SURFACE_CREATING;
|
| }
|
|
|
| void SchedulerStateMachine::SetMaximumNumberOfFailedDrawsBeforeDrawIsForced(
|
|
|