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

Unified Diff: cc/scheduler/scheduler_state_machine.cc

Issue 23796002: cc: Implement deadine scheduling disabled by default (Closed) Base URL: http://git.chromium.org/chromium/src.git@schedReadback4
Patch Set: Created 7 years, 4 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 941f8de4d999d7a9e480c5727555b34bc43c4317..70a25c98cb62869d12e0169cd5bd4919058d32da 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -19,17 +19,20 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
forced_redraw_state_(FORCED_REDRAW_STATE_IDLE),
readback_state_(READBACK_STATE_IDLE),
commit_count_(0),
- current_frame_number_(0),
- last_frame_number_where_begin_frame_sent_to_main_thread_(-1),
- last_frame_number_swap_performed_(-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_completed_tile_uploads_checked_(-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_commit_(false),
main_thread_needs_layer_textures_(false),
- inside_begin_frame_(false),
visible_(false),
can_start_(false),
can_draw_(false),
@@ -57,6 +60,22 @@ const char* SchedulerStateMachine::OutputSurfaceStateToString(
return "???";
}
+const char* SchedulerStateMachine::BeginFrameStateToString(
+ BeginFrameState state) {
+ switch (state) {
+ case BEGIN_FRAME_STATE_IDLE:
+ return "BEGIN_FRAME_STATE_IDLE";
+ case BEGIN_FRAME_STATE_INSIDE_BEGIN_FRAME:
+ return "BEGIN_FRAME_STATE_INSIDE_BEGIN_FRAME";
+ case BEGIN_FRAME_STATE_DEADLINE_PENDING:
+ return "BEGIN_FRAME_STATE_DEADLINE_PENDING";
+ case BEGIN_FRAME_STATE_INSIDE_DEADLINE:
+ return "BEGIN_FRAME_STATE_INSIDE_DEADLINE";
+ }
+ NOTREACHED();
+ return "???";
+}
+
const char* SchedulerStateMachine::CommitStateToString(CommitState state) {
switch (state) {
case COMMIT_STATE_IDLE:
@@ -157,6 +176,8 @@ scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const {
scoped_ptr<base::DictionaryValue> major_state(new base::DictionaryValue);
major_state->SetString("next_action", ActionToString(NextAction()));
+ major_state->SetString("commit_state",
+ BeginFrameStateToString(begin_frame_state_));
major_state->SetString("commit_state", CommitStateToString(commit_state_));
major_state->SetString("texture_state_",
TextureStateToString(texture_state_));
@@ -198,27 +219,37 @@ scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const {
scoped_ptr<base::DictionaryValue> minor_state(new base::DictionaryValue);
minor_state->SetInteger("commit_count", commit_count_);
- minor_state->SetInteger("current_frame_number", current_frame_number_);
+ minor_state->SetInteger("begin_frame_count_", begin_frame_count_);
+ minor_state->SetInteger("draw_attempt_count_", draw_attempt_count_);
+
+ minor_state->SetInteger("last_begin_frame_count_swap_performed_",
+ last_begin_frame_count_swap_performed_);
+ minor_state->SetInteger("last_draw_attempt_count_draw_was_called_",
+ last_draw_attempt_count_draw_was_called_);
+ minor_state->SetInteger(
+ "last_begin_frame_count_begin_frame_sent_to_main_thread_",
+ last_begin_frame_count_begin_frame_sent_to_main_thread_);
+ minor_state->SetInteger("last_draw_attempt_count_tree_activation_attempted_",
+ last_draw_attempt_count_tree_activation_attempted_);
minor_state->SetInteger(
- "last_frame_number_where_begin_frame_sent_to_main_thread",
- last_frame_number_where_begin_frame_sent_to_main_thread_);
- minor_state->SetInteger("last_frame_number_where_draw_was_called",
- last_frame_number_swap_performed_);
+ "last_draw_attempt_count_completed_tile_uploads_checked_",
+ last_draw_attempt_count_completed_tile_uploads_checked_);
minor_state->SetInteger(
- "last_frame_number_where_update_visible_tiles_was_called",
- last_frame_number_where_update_visible_tiles_was_called_);
- minor_state->SetInteger("consecutive_failed_draws",
+ "last_draw_attempt_count_update_visible_tiles_was_called_",
+ last_draw_attempt_count_update_visible_tiles_was_called_);
+
+ minor_state->SetInteger("consecutive_failed_draws_",
consecutive_failed_draws_);
minor_state->SetInteger(
- "maximum_number_of_failed_draws_before_draw_is_forced",
+ "maximum_number_of_failed_draws_before_draw_is_forced_",
maximum_number_of_failed_draws_before_draw_is_forced_);
+
minor_state->SetBoolean("needs_redraw", needs_redraw_);
minor_state->SetBoolean("swap_used_incomplete_tile",
swap_used_incomplete_tile_);
minor_state->SetBoolean("needs_commit", needs_commit_);
minor_state->SetBoolean("main_thread_needs_layer_textures",
main_thread_needs_layer_textures_);
- minor_state->SetBoolean("inside_begin_frame", inside_begin_frame_);
minor_state->SetBoolean("visible", visible_);
minor_state->SetBoolean("can_start", can_start_);
minor_state->SetBoolean("can_draw", can_draw_);
@@ -236,17 +267,26 @@ scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const {
}
bool SchedulerStateMachine::HasDrawnThisFrame() const {
- return current_frame_number_ == last_frame_number_swap_performed_;
+ return begin_frame_count_ == last_begin_frame_count_swap_performed_;
}
-bool SchedulerStateMachine::HasUpdatedVisibleTilesThisFrame() const {
- return current_frame_number_ ==
- last_frame_number_where_update_visible_tiles_was_called_;
+bool SchedulerStateMachine::HasDrawnThisDrawAttempt() const {
+ return draw_attempt_count_ == last_draw_attempt_count_draw_was_called_;
}
bool SchedulerStateMachine::HasSentBeginFrameToMainThreadThisFrame() const {
- return current_frame_number_ ==
- last_frame_number_where_begin_frame_sent_to_main_thread_;
+ return begin_frame_count_ ==
+ last_begin_frame_count_begin_frame_sent_to_main_thread_;
+}
+
+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_;
}
bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const {
@@ -306,6 +346,9 @@ bool SchedulerStateMachine::ShouldBeginOutputSurfaceCreation() const {
}
bool SchedulerStateMachine::ShouldDraw() const {
+ 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 ||
@@ -330,8 +373,8 @@ bool SchedulerStateMachine::ShouldDraw() const {
if (HasDrawnThisFrame())
return false;
- // We currently only draw within the BeginFrame.
- if (!inside_begin_frame_)
+ // Except for the cases above, do not draw outside of the BeginFrame deadline.
+ if (begin_frame_state_ != BEGIN_FRAME_STATE_INSIDE_DEADLINE)
return false;
// Only handle forced redraws due to timeouts on the regular deadline.
@@ -356,6 +399,8 @@ bool SchedulerStateMachine::ShouldActivatePendingTree() const {
// There is nothing to activate.
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)
@@ -376,7 +421,7 @@ bool SchedulerStateMachine::ShouldActivatePendingTree() const {
bool SchedulerStateMachine::ShouldUpdateVisibleTiles() const {
if (!settings_.impl_side_painting)
return false;
- if (HasUpdatedVisibleTilesThisFrame())
+ if (HasUpdatedVisibleTilesThisDrawAttempt())
return false;
// There's no reason to check for tiles if we don't have an output surface.
@@ -417,14 +462,28 @@ bool SchedulerStateMachine::ShouldSendBeginFrameToMainThread() const {
return !CommitPending();
// We do not need commits if we are not visible, unless there's a
- // request for a forced commit.
+ // request for a readback.
if (!visible_)
return false;
+ // We shouldn't normally accept commits if there isn't an OutputSurface.
+ if (!HasInitializedOutputSurface())
+ return false;
+
// We want to start the first commit after we get a new output surface ASAP.
if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_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;
+
// We need a new commit for the forced redraw. This honors the
// single commit per interval because the result will be swapped to screen.
if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT)
@@ -434,10 +493,6 @@ bool SchedulerStateMachine::ShouldSendBeginFrameToMainThread() const {
if (HasSentBeginFrameToMainThreadThisFrame())
return false;
- // We shouldn't normally accept commits if there isn't an OutputSurface.
- if (!HasInitializedOutputSurface())
- return false;
-
return true;
}
@@ -484,8 +539,8 @@ 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:
@@ -502,8 +557,8 @@ void SchedulerStateMachine::UpdateState(Action action) {
needs_commit_ = false;
if (readback_state_ == READBACK_STATE_FORCED_COMMIT_REQUESTED)
readback_state_ = READBACK_STATE_FORCED_COMMIT_PENDING;
- last_frame_number_where_begin_frame_sent_to_main_thread_ =
- current_frame_number_;
+ last_begin_frame_count_begin_frame_sent_to_main_thread_ =
+ begin_frame_count_;
return;
case ACTION_COMMIT: {
@@ -543,6 +598,7 @@ void SchedulerStateMachine::UpdateState(Action action) {
void SchedulerStateMachine::UpdateStateOnCommit(bool commit_was_aborted) {
commit_count_++;
+ draw_attempt_count_++;
// If we are impl-side-painting but the commit was aborted, then we behave
// mostly as if we are not impl-side-painting since there is no pending tree.
@@ -611,8 +667,10 @@ void SchedulerStateMachine::UpdateStateOnCommit(bool commit_was_aborted) {
// This post-commit work is common to both completed and aborted commits.
pending_tree_is_ready_for_activation_ = false;
- if (draw_if_possible_failed_)
- last_frame_number_swap_performed_ = -1;
+ if (draw_if_possible_failed_) {
+ last_begin_frame_count_swap_performed_ = -1;
+ last_draw_attempt_count_draw_was_called_ = -1;
+ }
// If we are planing to draw with the new commit, lock the layer textures for
// use on the impl thread. Otherwise, leave them unlocked.
@@ -623,6 +681,8 @@ void SchedulerStateMachine::UpdateStateOnCommit(bool commit_was_aborted) {
}
void SchedulerStateMachine::UpdateStateOnActivation() {
+ draw_attempt_count_++;
+
// Update output surface state.
if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION)
output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
@@ -641,6 +701,7 @@ void SchedulerStateMachine::UpdateStateOnActivation() {
pending_tree_is_ready_for_activation_ = false;
active_tree_has_been_drawn_ = false;
needs_redraw_ = true;
+ last_draw_attempt_count_tree_activation_attempted_ = draw_attempt_count_;
}
void SchedulerStateMachine::UpdateStateOnDraw(bool did_swap) {
@@ -673,10 +734,25 @@ void SchedulerStateMachine::UpdateStateOnDraw(bool did_swap) {
needs_redraw_ = false;
draw_if_possible_failed_ = false;
active_tree_has_been_drawn_ = true;
+ last_draw_attempt_count_draw_was_called_ = draw_attempt_count_;
if (did_swap) {
swap_used_incomplete_tile_ = false;
- last_frame_number_swap_performed_ = current_frame_number_;
+ 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;
}
}
@@ -686,6 +762,11 @@ void SchedulerStateMachine::SetMainThreadNeedsLayerTextures() {
main_thread_needs_layer_textures_ = true;
}
+bool SchedulerStateMachine::BeginFrameNeededByImplThread() const {
+ return BeginFrameNeededToDrawByImplThread() ||
+ ProactiveBeginFrameWantedByImplThread();
+}
+
// These are the cases where we definitely (or almost definitely) have a
// new frame to draw and can draw.
bool SchedulerStateMachine::BeginFrameNeededToDrawByImplThread() const {
@@ -720,15 +801,22 @@ bool SchedulerStateMachine::BeginFrameNeededToDrawByImplThread() const {
// actually have a new frame to draw when we receive the next BeginFrame.
// Proactively requesting the BeginFrame helps hide the round trip latency of
// the SetNeedsBeginFrame request that has to go to the Browser.
-// However, this is bad for the synchronous compoisitor because we have to
-// draw when we get the BeginFrame and could end up drawing many duplicate
-// frames.
bool SchedulerStateMachine::ProactiveBeginFrameWantedByImplThread() const {
// The output surface is the provider of BeginFrames for the impl thread,
// so we are not going to get them even if we ask for them.
if (!HasInitializedOutputSurface())
return false;
+ // Proactive BeginFrames are bad for the synchronous compoisitor because we
Sami 2013/08/30 13:49:06 Typo: compositor
+ // have to draw when we get the BeginFrame and could end up drawing many
+ // duplicate frames if our new frame isn't ready in time.
+ if (settings_.using_synchronous_renderer_compositor)
+ return false;
+
+ // Do not be proactive if vsync is off.
+ if (!settings_.throttle_frame_production)
+ return false;
+
// Do not be proactive when invisible.
if (!visible_)
return false;
@@ -746,18 +834,33 @@ bool SchedulerStateMachine::ProactiveBeginFrameWantedByImplThread() const {
return false;
}
-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;
}
-void SchedulerStateMachine::DidLeaveBeginFrame() {
- inside_begin_frame_ = false;
+bool SchedulerStateMachine::ShouldTriggerBeginFrameDeadlineEarly() const {
+ // TODO(brianderson): This should take into account multiple commit sources.
Sami 2013/08/30 13:49:06 When could something like this happen? If there's
brianderson 2013/09/03 22:51:47 This isn't so much an issue for Android as it is f
+ 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::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::SetCanDraw(bool can_draw) { can_draw_ = can_draw; }
+
void SchedulerStateMachine::SetNeedsRedraw() { needs_redraw_ = true; }
void SchedulerStateMachine::DidSwapUseIncompleteTile() {
@@ -837,8 +940,6 @@ void SchedulerStateMachine::NotifyReadyToActivate() {
pending_tree_is_ready_for_activation_ = true;
}
-void SchedulerStateMachine::SetCanDraw(bool can) { can_draw_ = can; }
-
void SchedulerStateMachine::DidCreateAndInitializeOutputSurface() {
DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_CREATING);
output_surface_state_ = OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT;

Powered by Google App Engine
This is Rietveld 408576698