Index: cc/scheduler/scheduler_state_machine.cc |
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc |
index 1d77e09b3008c45af4978fa5199085aa8ee3a9e1..24a59d0122a99591c1cc2aae1363285ca5e696c3 100644 |
--- a/cc/scheduler/scheduler_state_machine.cc |
+++ b/cc/scheduler/scheduler_state_machine.cc |
@@ -19,7 +19,6 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) |
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), |
consecutive_failed_draws_(0), |
maximum_number_of_failed_draws_before_draw_is_forced_(3), |
@@ -36,6 +35,8 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) |
can_start_(false), |
can_draw_(false), |
has_pending_tree_(false), |
+ pending_tree_is_ready_for_activation_(false), |
+ active_tree_has_been_drawn_(false), |
draw_if_possible_failed_(false), |
texture_state_(LAYER_TEXTURE_STATE_UNLOCKED), |
did_create_and_initialize_first_output_surface_(false) {} |
@@ -98,8 +99,8 @@ const char* SchedulerStateMachine::ActionToString(Action action) { |
return "ACTION_COMMIT"; |
case ACTION_UPDATE_VISIBLE_TILES: |
return "ACTION_UPDATE_VISIBLE_TILES"; |
- case ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED: |
- return "ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED"; |
+ case ACTION_ACTIVATE_PENDING_TREE: |
+ return "ACTION_ACTIVATE_PENDING_TREE"; |
case ACTION_DRAW_IF_POSSIBLE: |
return "ACTION_DRAW_IF_POSSIBLE"; |
case ACTION_DRAW_FORCED: |
@@ -162,8 +163,6 @@ scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const { |
last_frame_number_where_begin_frame_sent_to_main_thread_); |
minor_state->SetInteger("last_frame_number_where_draw_was_called", |
last_frame_number_where_draw_was_called_); |
- minor_state->SetInteger("last_frame_number_where_tree_activation_attempted", |
- last_frame_number_where_tree_activation_attempted_); |
minor_state->SetInteger( |
"last_frame_number_where_update_visible_tiles_was_called", |
last_frame_number_where_update_visible_tiles_was_called_); |
@@ -189,6 +188,10 @@ scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const { |
minor_state->SetBoolean("can_start", can_start_); |
minor_state->SetBoolean("can_draw", can_draw_); |
minor_state->SetBoolean("has_pending_tree", has_pending_tree_); |
+ minor_state->SetBoolean("pending_tree_is_ready_for_activation_", |
+ pending_tree_is_ready_for_activation_); |
+ minor_state->SetBoolean("active_tree_has_been_drawn_", |
+ active_tree_has_been_drawn_); |
minor_state->SetBoolean("draw_if_possible_failed", draw_if_possible_failed_); |
minor_state->SetBoolean("did_create_and_initialize_first_output_surface", |
did_create_and_initialize_first_output_surface_); |
@@ -201,11 +204,6 @@ bool SchedulerStateMachine::HasDrawnThisFrame() const { |
return current_frame_number_ == last_frame_number_where_draw_was_called_; |
} |
-bool SchedulerStateMachine::HasAttemptedTreeActivationThisFrame() const { |
- return current_frame_number_ == |
- last_frame_number_where_tree_activation_attempted_; |
-} |
- |
bool SchedulerStateMachine::HasUpdatedVisibleTilesThisFrame() const { |
return current_frame_number_ == |
last_frame_number_where_update_visible_tiles_was_called_; |
@@ -244,12 +242,11 @@ void SchedulerStateMachine::HandleCommitInternal(bool commit_was_aborted) { |
} |
} |
- // if we don't have to wait for activation, update needs_redraw now. |
- if (!commit_results_in_pending_tree) { |
- if (!commit_was_aborted) |
- needs_redraw_ = true; |
- if (expect_immediate_begin_frame_for_main_thread_) |
+ // Update state if we have a new active tree to draw. |
+ if (!commit_results_in_pending_tree && |
+ (!commit_was_aborted || expect_immediate_begin_frame_for_main_thread_)) { |
needs_redraw_ = true; |
+ active_tree_has_been_drawn_ = false; |
} |
// This post-commit work is common to both completed and aborted commits. |
@@ -272,14 +269,32 @@ void SchedulerStateMachine::HandleCommitInternal(bool commit_was_aborted) { |
bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const { |
// These are all the cases where, if we do not abort draws to make |
// forward progress, we might deadlock with the main thread. |
+ // This should be a superset of PendingActivationsShouldBeForced(). |
+ if (PendingActivationsShouldBeForced()) |
+ return true; |
+ |
+ // Additional states where we should abort draws. |
+ // Note: We don't force activation in these cases because doing so would |
+ // result in checkerboarding on resize, becoming visible, etc. |
if (!can_draw_) |
return true; |
if (!visible_) |
return true; |
- if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE) |
+ if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION) |
return true; |
+ return false; |
+} |
+ |
+bool SchedulerStateMachine::PendingActivationsShouldBeForced() const { |
+ // These are all the cases where, if we do not force activations to make |
+ // forward progress, we might deadlock with the main thread. |
+ // This should be a subset PendingDrawsShouldBeAborted(). |
if (texture_state_ == LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD) |
return true; |
+ if (output_surface_state_ == OUTPUT_SURFACE_LOST || |
+ output_surface_state_ == OUTPUT_SURFACE_CREATING || |
+ output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT) |
+ return true; |
return false; |
} |
@@ -289,13 +304,8 @@ bool SchedulerStateMachine::ShouldDraw() const { |
return true; |
// If we are going to abort draws, we should do so ASAP. |
- if (PendingDrawsShouldBeAborted()) { |
- // TODO(brianderson): Remove the !has_pending_tree_ condition once |
- // the Scheduler controls activation. It's dangerous for us to rely on |
- // an eventual activation if we've lost the output surface. |
- return commit_state_ == COMMIT_STATE_WAITING_FOR_FIRST_DRAW && |
- !has_pending_tree_; |
- } |
+ if (PendingDrawsShouldBeAborted()) |
+ return commit_state_ == COMMIT_STATE_WAITING_FOR_FIRST_DRAW; |
// After this line, we only want to draw once per frame. |
if (HasDrawnThisFrame()) |
@@ -308,9 +318,25 @@ bool SchedulerStateMachine::ShouldDraw() const { |
return needs_redraw_; |
} |
-bool SchedulerStateMachine::ShouldAttemptTreeActivation() const { |
- return has_pending_tree_ && inside_begin_frame_ && |
- !HasAttemptedTreeActivationThisFrame(); |
+bool SchedulerStateMachine::ShouldActivatePendingTree() const { |
+ // There is nothing to activate. |
+ if (!has_pending_tree_) |
+ return false; |
+ |
+ // We don't want to activate a second tree before drawing the first one. |
+ // Note: It is possible that there is no active tree to draw when |
+ // output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION, |
+ // so we don't block activation on draw in that case. |
+ if (!active_tree_has_been_drawn_ && |
+ output_surface_state_ != OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION) |
+ return false; |
+ |
+ // If we want to force activation, do so ASAP. |
+ if (PendingActivationsShouldBeForced()) |
+ return true; |
+ |
+ // At this point, only activate if we are ready to activate. |
+ return pending_tree_is_ready_for_activation_; |
} |
bool SchedulerStateMachine::ShouldUpdateVisibleTiles() const { |
@@ -319,7 +345,7 @@ bool SchedulerStateMachine::ShouldUpdateVisibleTiles() const { |
if (HasUpdatedVisibleTilesThisFrame()) |
return false; |
- return ShouldAttemptTreeActivation() || ShouldDraw() || |
+ return ShouldActivatePendingTree() || ShouldDraw() || |
swap_used_incomplete_tile_; |
} |
@@ -388,8 +414,8 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { |
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; |
@@ -401,8 +427,8 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { |
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; |
@@ -415,8 +441,8 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { |
case COMMIT_STATE_WAITING_FOR_FIRST_DRAW: { |
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()) { |
if (needs_forced_redraw_) |
return ACTION_DRAW_FORCED; |
@@ -431,8 +457,8 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { |
case COMMIT_STATE_WAITING_FOR_FIRST_FORCED_DRAW: |
if (ShouldUpdateVisibleTiles()) |
return ACTION_UPDATE_VISIBLE_TILES; |
- if (ShouldAttemptTreeActivation()) |
- return ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED; |
+ if (ShouldActivatePendingTree()) |
+ return ACTION_ACTIVATE_PENDING_TREE; |
if (needs_forced_redraw_) |
return ACTION_DRAW_FORCED; |
return ACTION_NONE; |
@@ -451,9 +477,7 @@ void SchedulerStateMachine::UpdateState(Action action) { |
current_frame_number_; |
return; |
- case ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED: |
- last_frame_number_where_tree_activation_attempted_ = |
- current_frame_number_; |
+ case ACTION_ACTIVATE_PENDING_TREE: |
return; |
case ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD: |
@@ -519,6 +543,7 @@ void SchedulerStateMachine::UpdateStateOnDraw(bool did_swap) { |
needs_redraw_ = false; |
needs_forced_redraw_ = false; |
draw_if_possible_failed_ = false; |
+ active_tree_has_been_drawn_ = true; |
if (did_swap) |
swap_used_incomplete_tile_ = false; |
@@ -531,10 +556,6 @@ void SchedulerStateMachine::SetMainThreadNeedsLayerTextures() { |
} |
bool SchedulerStateMachine::BeginFrameNeededToDrawByImplThread() const { |
- // TODO(brianderson): Remove this hack once the Scheduler controls activation. |
- if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION) |
- return true; |
- |
// If we can't draw, don't tick until we are notified that we can draw again. |
if (!can_draw_) |
return false; |
@@ -550,7 +571,7 @@ bool SchedulerStateMachine::BeginFrameNeededToDrawByImplThread() const { |
bool SchedulerStateMachine::ProactiveBeginFrameWantedByImplThread() const { |
// Do not be proactive when invisible. |
- if (!visible_ || output_surface_state_ != OUTPUT_SURFACE_ACTIVE) |
+ if (!visible_ || !HasInitializedOutputSurface()) |
return false; |
// We should proactively request a BeginFrame if a commit or a tree activation |
@@ -636,13 +657,23 @@ void SchedulerStateMachine::DidLoseOutputSurface() { |
needs_redraw_ = false; |
} |
+void SchedulerStateMachine::NotifyReadyToActivate() { |
+ if (has_pending_tree_) |
+ pending_tree_is_ready_for_activation_ = true; |
+} |
+ |
void SchedulerStateMachine::SetHasPendingTree(bool has_pending_tree) { |
if (has_pending_tree_ && !has_pending_tree) { |
// There is a new active tree. |
if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION) |
output_surface_state_ = OUTPUT_SURFACE_ACTIVE; |
+ pending_tree_is_ready_for_activation_ = false; |
+ active_tree_has_been_drawn_ = false; |
needs_redraw_ = true; |
+ } 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; |
} |