Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(201)

Unified Diff: cc/scheduler/scheduler_state_machine.cc

Issue 16871016: cc: Use BeginFrameArgs (Closed) Base URL: http://git.chromium.org/chromium/src.git@bfargs2
Patch Set: Rebase; Avoid double activate; Fix OutputSurface init and page scroll delta; Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..6c2d879ae1b769cbbd6f914d230f5ec69c235dab 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_draw_was_called_(-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_draw_was_called_ = %d; ",
+ last_begin_frame_count_draw_was_called_);
+ 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_draw_was_called_;
}
-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_draw_was_called_ = -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,45 @@ 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
enne (OOO) 2013/08/02 19:41:25 This looks really good. This is what I was trying
+ // 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;
+
enne (OOO) 2013/08/02 19:41:25 This comment doesn't really add much, and I don't
brianderson 2013/08/02 23:04:31 Good catch! This needlessly delays activation. I p
+ // Do not activate in BEGIN_FRAME_STATE_IDLE
+ if (begin_frame_state_ == BEGIN_FRAME_STATE_IDLE)
+ return false;
+
+ // We do not want to activate a second tree before drawing the first one.
enne (OOO) 2013/08/02 19:41:25 How is that possible? Maybe I'm misreading other p
brianderson 2013/08/02 23:04:31 In this patch, the draw no longer has to occur bef
+ return active_tree_has_been_drawn_ || active_tree_is_null_;
enne (OOO) 2013/08/02 19:41:25 There are other reasons that the active tree might
brianderson 2013/08/02 23:04:31 In cases where can_draw_ is false, ACTION_DRAW_AND
enne (OOO) 2013/08/05 19:37:43 In that case, shouldn't that logic to set active_t
brianderson 2013/08/05 21:56:19 As it is currently coded, ShouldDraw() will not re
}
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 +303,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 +444,56 @@ 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_);
+ case ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
+ case ACTION_DRAW_AND_SWAP_FORCED:
+ case ACTION_DRAW_AND_READBACK:
+ case ACTION_DRAW_AND_SWAP_ABORT:
+ 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;
- expect_immediate_begin_frame_for_main_thread_ = false;
+ readback_state_ = READBACK_STATE_REPLACEMENT_COMMIT_PENDING;
} else if (commit_state_ == COMMIT_STATE_WAITING_FOR_FIRST_DRAW) {
commit_state_ = COMMIT_STATE_IDLE;
}
+ needs_redraw_ = false;
+ draw_if_possible_failed_ = false;
+ swap_used_incomplete_tile_ = false;
+ last_begin_frame_count_draw_was_called_ = begin_frame_count_;
+ last_draw_attempt_count_draw_was_called_ = draw_attempt_count_;
if (texture_state_ == LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD)
texture_state_ = LAYER_TEXTURE_STATE_UNLOCKED;
+ active_tree_has_been_drawn_ = true;
return;
case ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
@@ -357,49 +509,88 @@ void SchedulerStateMachine::UpdateState(Action action) {
}
}
+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 +598,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 +610,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 +619,27 @@ 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_EQ(readback_state_, READBACK_STATE_IDLE);
+ 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 +651,67 @@ void SchedulerStateMachine::DidLoseOutputSurface() {
output_surface_state_ == OUTPUT_SURFACE_CREATING)
return;
output_surface_state_ = OUTPUT_SURFACE_LOST;
+ needs_redraw_ = false;
+}
+
+void SchedulerStateMachine::NotifyReadyToActivate() {
+ if (has_pending_tree_)
+ pending_tree_is_ready_for_activation_ = true;
}
-void SchedulerStateMachine::SetHasPendingTree(bool has_pending_tree) {
+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_draw_was_called_ = -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(

Powered by Google App Engine
This is Rietveld 408576698