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

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: rebase? Created 7 years, 3 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 e93d0c84a2c80f7b2e50bef61a2b98b0ab88c08e..20d2ce37d7ee9ab0323d82738bade1a3ac5e04c2 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -14,21 +14,24 @@ 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),
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_update_visible_tiles_was_called_(-1),
consecutive_failed_draws_(0),
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),
@@ -56,6 +59,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:
@@ -156,6 +175,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",
enne (OOO) 2013/09/10 03:35:44 begin_frame_state
brianderson 2013/09/10 21:16:56 Done.
+ BeginFrameStateToString(begin_frame_state_));
major_state->SetString("commit_state", CommitStateToString(commit_state_));
major_state->SetString("texture_state_",
TextureStateToString(texture_state_));
@@ -197,16 +218,23 @@ 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_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_swap_performed_",
- last_frame_number_swap_performed_);
+ "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_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->SetBoolean("needs_redraw", needs_redraw_);
minor_state->SetBoolean("swap_used_incomplete_tile",
@@ -214,7 +242,6 @@ scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const {
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_);
@@ -231,18 +258,27 @@ scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const {
return state.PassAs<base::Value>();
}
-bool SchedulerStateMachine::HasDrawnAndSwappedThisFrame() const {
- return current_frame_number_ == last_frame_number_swap_performed_;
+bool SchedulerStateMachine::HasSwappedThisFrame() const {
+ 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 {
@@ -305,6 +341,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_WAITING_FOR_REPLACEMENT_COMMIT ||
@@ -325,12 +364,12 @@ bool SchedulerStateMachine::ShouldDraw() const {
if (PendingDrawsShouldBeAborted())
return active_tree_needs_first_draw_;
- // After this line, we only want to draw once per frame.
- if (HasDrawnAndSwappedThisFrame())
+ // After this line, we only want to swap once per frame.
+ if (HasSwappedThisFrame())
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.
@@ -355,6 +394,8 @@ bool SchedulerStateMachine::ShouldActivatePendingTree() const {
// There is nothing to activate.
if (!has_pending_tree_)
return false;
+ if (HasActivatedPendingTreeThisDrawAttempt())
+ return false;
// We should not activate a second tree before drawing the first one.
// Even if we need to force activation of the pending tree, we should abort
@@ -373,7 +414,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.
@@ -414,14 +455,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;
enne (OOO) 2013/09/10 03:35:44 Can you rephrase this comment to refer to this "re
brianderson 2013/09/10 21:16:56 I will change the comment to refer to the "return
+
// 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)
@@ -431,10 +486,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;
}
@@ -481,8 +532,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:
@@ -496,8 +547,8 @@ void SchedulerStateMachine::UpdateState(Action action) {
needs_commit_ = false;
if (readback_state_ == READBACK_STATE_NEEDS_BEGIN_FRAME)
readback_state_ = READBACK_STATE_WAITING_FOR_COMMIT;
- 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: {
@@ -541,6 +592,7 @@ void SchedulerStateMachine::UpdateState(Action action) {
void SchedulerStateMachine::UpdateStateOnCommit(bool commit_was_aborted) {
commit_count_++;
+ draw_attempt_count_++;
enne (OOO) 2013/09/10 03:35:44 What's the difference between "draw attempt" and "
brianderson 2013/09/10 21:16:56 Note: It is possible for a readback and a swap to
// 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.
@@ -610,8 +662,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.
@@ -622,6 +676,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;
@@ -640,6 +696,7 @@ void SchedulerStateMachine::UpdateStateOnActivation() {
pending_tree_is_ready_for_activation_ = false;
active_tree_needs_first_draw_ = true;
needs_redraw_ = true;
+ last_draw_attempt_count_tree_activation_attempted_ = draw_attempt_count_;
}
void SchedulerStateMachine::UpdateStateOnDraw(bool did_swap) {
@@ -672,10 +729,25 @@ void SchedulerStateMachine::UpdateStateOnDraw(bool did_swap) {
needs_redraw_ = false;
draw_if_possible_failed_ = false;
active_tree_needs_first_draw_ = false;
+ 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;
enne (OOO) 2013/09/10 03:35:44 Just so I understand this correctly, this is the n
brianderson 2013/09/10 21:16:56 Yes, this is the only way. We only transition out
+ break;
+ case BEGIN_FRAME_STATE_IDLE:
+ case BEGIN_FRAME_STATE_DEADLINE_PENDING:
+ break;
}
}
@@ -685,6 +757,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 {
@@ -719,15 +796,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 compositor 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 compositor because we
+ // 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;
@@ -745,18 +829,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;
+}
+
+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_needs_first_draw_;
+}
+
+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);
enne (OOO) 2013/09/10 03:35:44 What guarantees that this is true? It seems like y
brianderson 2013/09/10 21:16:56 In Scheduler::BeginFrame, we will always transitio
+ 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() {
@@ -835,8 +934,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