Index: cc/scheduler/scheduler_state_machine.cc |
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc |
index 5881f2a72340802d180d182fdd7faa4b5a014332..33e33c4544e74076b8d0a963b74d619e4e51c317 100644 |
--- a/cc/scheduler/scheduler_state_machine.cc |
+++ b/cc/scheduler/scheduler_state_machine.cc |
@@ -18,7 +18,8 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) |
output_surface_state_(OUTPUT_SURFACE_LOST), |
begin_impl_frame_state_(BEGIN_IMPL_FRAME_STATE_IDLE), |
commit_state_(COMMIT_STATE_IDLE), |
- forced_redraw_state_(FORCED_REDRAW_STATE_IDLE), |
+ prepare_tiles_approach_(PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY), |
+ prepare_tiles_reason_(PREPARE_TILES_NOT_NEEDED), |
commit_count_(0), |
current_frame_number_(0), |
last_frame_number_animate_performed_(-1), |
@@ -31,18 +32,20 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) |
send_begin_main_frame_funnel_(false), |
invalidate_output_surface_funnel_(false), |
prepare_tiles_funnel_(0), |
- consecutive_checkerboard_animations_(0), |
max_pending_swaps_(1), |
pending_swaps_(0), |
needs_redraw_(false), |
+ last_draw_result_(DRAW_SUCCESS), |
+ retry_begin_impl_frame_(false), |
+ retry_begin_impl_frame_deadline_(false), |
needs_animate_(false), |
- needs_prepare_tiles_(false), |
needs_commit_(false), |
visible_(false), |
can_start_(false), |
can_draw_(false), |
has_pending_tree_(false), |
pending_tree_is_ready_for_activation_(false), |
+ requires_high_res_to_draw_(false), |
active_tree_needs_first_draw_(false), |
did_create_and_initialize_first_output_surface_(false), |
impl_latency_takes_priority_(false), |
@@ -103,6 +106,8 @@ const char* SchedulerStateMachine::BeginImplFrameDeadlineModeToString( |
return "BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR"; |
case BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE: |
return "BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE"; |
+ case BEGIN_IMPL_FRAME_DEADLINE_MODE_TRY_TO_AVOID_CHECKERBOARD: |
+ return "BEGIN_IMPL_FRAME_DEADLINE_MODE_TRY_TO_AVOID_CHECKERBOARD"; |
case BEGIN_IMPL_FRAME_DEADLINE_MODE_BLOCKED_ON_READY_TO_DRAW: |
return "BEGIN_IMPL_FRAME_DEADLINE_MODE_BLOCKED_ON_READY_TO_DRAW"; |
} |
@@ -129,17 +134,31 @@ const char* SchedulerStateMachine::CommitStateToString(CommitState state) { |
return "???"; |
} |
-const char* SchedulerStateMachine::ForcedRedrawOnTimeoutStateToString( |
- ForcedRedrawOnTimeoutState state) { |
- switch (state) { |
- case FORCED_REDRAW_STATE_IDLE: |
- return "FORCED_REDRAW_STATE_IDLE"; |
- case FORCED_REDRAW_STATE_WAITING_FOR_COMMIT: |
- return "FORCED_REDRAW_STATE_WAITING_FOR_COMMIT"; |
- case FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION: |
- return "FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION"; |
- case FORCED_REDRAW_STATE_WAITING_FOR_DRAW: |
- return "FORCED_REDRAW_STATE_WAITING_FOR_DRAW"; |
+const char* SchedulerStateMachine::PrepareTilesApproachToString( |
+ PrepareTilesApproach approach) { |
+ switch (approach) { |
+ case PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY: |
+ return "PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY"; |
+ case PREPARE_TILES_APPROACH_ACCURATE_ACTIVE_WORK: |
+ return "PREPARE_TILES_APPROACH_ACCURATE_ACTIVE_WORK"; |
+ } |
+ NOTREACHED(); |
+ return "???"; |
+} |
+ |
+const char* SchedulerStateMachine::PrepareTilesReasonToString( |
+ PrepareTilesReason reason) { |
+ switch (reason) { |
+ case PREPARE_TILES_NOT_NEEDED: |
+ return "PREPARE_TILES_NOT_NEEDED"; |
+ case PREPARE_TILES_REQUESTED: |
+ return "PREPARE_TILES_REQUESTED"; |
+ case PREPARE_TILES_NEEDED_FOR_COMMIT: |
+ return "PREPARE_TILES_NEEDED_FOR_COMMIT"; |
+ case PREPARE_TILES_NEEDED_FOR_ABORTED_DRAW: |
+ return "PREPARE_TILES_NEEDED_FOR_ABORTED_DRAW"; |
+ case PREPARE_TILES_NEEDED_TO_EVICT_TILES: |
+ return "PREPARE_TILES_NEEDED_TO_EVICT_TILES"; |
} |
NOTREACHED(); |
return "???"; |
@@ -189,10 +208,12 @@ void SchedulerStateMachine::AsValueInto( |
state->SetString("begin_impl_frame_state", |
BeginImplFrameStateToString(begin_impl_frame_state_)); |
state->SetString("commit_state", CommitStateToString(commit_state_)); |
- state->SetString("output_surface_state_", |
+ state->SetString("prepare_tiles_approach", |
+ PrepareTilesApproachToString(prepare_tiles_approach_)); |
+ state->SetString("prepare_tiles_reason", |
+ PrepareTilesReasonToString(prepare_tiles_reason_)); |
+ state->SetString("output_surface_state", |
OutputSurfaceStateToString(output_surface_state_)); |
- state->SetString("forced_redraw_state", |
- ForcedRedrawOnTimeoutStateToString(forced_redraw_state_)); |
state->EndDictionary(); |
state->BeginDictionary("minor_state"); |
@@ -213,13 +234,10 @@ void SchedulerStateMachine::AsValueInto( |
state->SetInteger("funnel: prepare_tiles_funnel", prepare_tiles_funnel_); |
state->SetBoolean("funnel: invalidate_output_surface_funnel", |
invalidate_output_surface_funnel_); |
- state->SetInteger("consecutive_checkerboard_animations", |
- consecutive_checkerboard_animations_); |
state->SetInteger("max_pending_swaps_", max_pending_swaps_); |
state->SetInteger("pending_swaps_", pending_swaps_); |
state->SetBoolean("needs_redraw", needs_redraw_); |
state->SetBoolean("needs_animate_", needs_animate_); |
- state->SetBoolean("needs_prepare_tiles", needs_prepare_tiles_); |
state->SetBoolean("needs_commit", needs_commit_); |
state->SetBoolean("visible", visible_); |
state->SetBoolean("can_start", can_start_); |
@@ -344,10 +362,6 @@ bool SchedulerStateMachine::ShouldDraw() const { |
if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) |
return false; |
- // Only handle forced redraws due to timeouts on the regular deadline. |
- if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW) |
- return true; |
- |
return needs_redraw_; |
} |
@@ -445,14 +459,6 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const { |
BeginFrameNeeded()) |
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. |
- // TODO(brianderson): Remove this or move it below the |
- // SendingBeginMainFrameMightCauseDeadlock check since we want to avoid |
- // ever returning true from this method if we might cause deadlock. |
- if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT) |
- return true; |
- |
// We shouldn't normally accept commits if there isn't an OutputSurface. |
if (!HasInitializedOutputSurface()) |
return false; |
@@ -500,18 +506,36 @@ bool SchedulerStateMachine::ShouldCommit() const { |
} |
bool SchedulerStateMachine::ShouldPrepareTiles() const { |
- // PrepareTiles only really needs to be called immediately after commit |
- // and then periodically after that. Use a funnel to make sure we average |
- // one PrepareTiles per BeginImplFrame in the long run. |
- if (prepare_tiles_funnel_ > 0) |
- return false; |
+ // Handle the clear cut cases. |
+ switch (prepare_tiles_reason_) { |
+ case PREPARE_TILES_NOT_NEEDED: |
+ return false; |
+ case PREPARE_TILES_NEEDED_FOR_COMMIT: |
+ case PREPARE_TILES_NEEDED_FOR_ABORTED_DRAW: |
+ case PREPARE_TILES_NEEDED_TO_EVICT_TILES: |
+ return true; |
+ case PREPARE_TILES_REQUESTED: |
+ break; |
+ } |
- // Limiting to once per-frame is not enough, since we only want to |
- // prepare tiles _after_ draws. |
- if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) |
- return false; |
+ switch (prepare_tiles_approach_) { |
+ case PREPARE_TILES_APPROACH_ACCURATE_ACTIVE_WORK: |
+ return begin_impl_frame_state_ == |
+ BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING; |
+ case PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY: |
+ break; |
+ } |
+ |
+ DCHECK_EQ(PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY, prepare_tiles_approach_); |
+ DCHECK_EQ(PREPARE_TILES_REQUESTED, prepare_tiles_reason_); |
- return needs_prepare_tiles_; |
+ // Only PrepareTiles after a draw if we haven't already PreparedTiles this |
+ // frame. This takes PrepareTiles out of the critical path, but wil make the |
+ // NotifyReadyToDraw and NotifyReadyToActivate signals liars. |
+ bool did_not_prepare_tiles_at_end_of_frame = |
+ prepare_tiles_funnel_ == 0 && |
+ begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE; |
+ return did_not_prepare_tiles_at_end_of_frame; |
} |
bool SchedulerStateMachine::ShouldInvalidateOutputSurface() const { |
@@ -527,10 +551,11 @@ bool SchedulerStateMachine::ShouldInvalidateOutputSurface() const { |
if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING) |
return false; |
+ // TODO(brianderson): Figure out what to do with this. |
// TODO(sunnyps): needs_prepare_tiles_ is needed here because PrepareTiles is |
// called only inside the deadline / draw phase. We could remove this if we |
// allowed PrepareTiles to happen in OnBeginImplFrame. |
- return needs_redraw_ || needs_prepare_tiles_; |
+ return needs_redraw_ || PrepareTilesPending(); |
} |
SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { |
@@ -543,10 +568,12 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { |
if (ShouldDraw()) { |
if (PendingDrawsShouldBeAborted()) |
return ACTION_DRAW_AND_SWAP_ABORT; |
- else if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW) |
- return ACTION_DRAW_AND_SWAP_FORCED; |
- else |
+ else if (requires_high_res_to_draw_ || |
+ prepare_tiles_approach_ == |
+ PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY) |
return ACTION_DRAW_AND_SWAP_IF_POSSIBLE; |
+ else |
+ return ACTION_DRAW_AND_SWAP_FORCED; |
} |
if (ShouldPrepareTiles()) |
return ACTION_PREPARE_TILES; |
@@ -559,57 +586,91 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { |
return ACTION_NONE; |
} |
-void SchedulerStateMachine::UpdateState(Action action) { |
+void SchedulerStateMachine::WillAction(Action action) { |
switch (action) { |
case ACTION_NONE: |
return; |
+ case ACTION_COMMIT: |
+ WillCommit(); |
+ return; |
+ |
case ACTION_ACTIVATE_SYNC_TREE: |
- UpdateStateOnActivation(); |
+ WillActivateSyncTree(); |
return; |
case ACTION_ANIMATE: |
- UpdateStateOnAnimate(); |
+ WillAnimate(); |
return; |
case ACTION_SEND_BEGIN_MAIN_FRAME: |
- UpdateStateOnSendBeginMainFrame(); |
+ WillSendBeginMainFrame(); |
+ return; |
+ |
+ case ACTION_DRAW_AND_SWAP_FORCED: |
+ case ACTION_DRAW_AND_SWAP_IF_POSSIBLE: |
+ case ACTION_DRAW_AND_SWAP_ABORT: |
+ return; |
+ |
+ case ACTION_BEGIN_OUTPUT_SURFACE_CREATION: |
+ WillBeginOutputSurfaceCreation(); |
+ return; |
+ |
+ case ACTION_PREPARE_TILES: |
+ return; |
+ |
+ case ACTION_INVALIDATE_OUTPUT_SURFACE: |
+ WillInvalidateOutputSurface(); |
+ return; |
+ } |
+} |
+ |
+void SchedulerStateMachine::DidAction(Action action) { |
+ switch (action) { |
+ case ACTION_NONE: |
return; |
case ACTION_COMMIT: { |
bool commit_has_no_updates = false; |
- UpdateStateOnCommit(commit_has_no_updates); |
+ DidCommit(commit_has_no_updates); |
return; |
} |
+ case ACTION_ACTIVATE_SYNC_TREE: |
+ return; |
+ |
+ case ACTION_ANIMATE: |
+ return; |
+ |
+ case ACTION_SEND_BEGIN_MAIN_FRAME: |
+ return; |
+ |
case ACTION_DRAW_AND_SWAP_FORCED: |
case ACTION_DRAW_AND_SWAP_IF_POSSIBLE: { |
bool did_request_swap = true; |
- UpdateStateOnDraw(did_request_swap); |
+ DidDraw(did_request_swap); |
return; |
} |
case ACTION_DRAW_AND_SWAP_ABORT: { |
bool did_request_swap = false; |
- UpdateStateOnDraw(did_request_swap); |
+ DidDraw(did_request_swap); |
return; |
} |
case ACTION_BEGIN_OUTPUT_SURFACE_CREATION: |
- UpdateStateOnBeginOutputSurfaceCreation(); |
return; |
case ACTION_PREPARE_TILES: |
- UpdateStateOnPrepareTiles(); |
+ DidPrepareTiles(); |
return; |
case ACTION_INVALIDATE_OUTPUT_SURFACE: |
- UpdateStateOnInvalidateOutputSurface(); |
return; |
} |
} |
-void SchedulerStateMachine::UpdateStateOnAnimate() { |
+void SchedulerStateMachine::WillAnimate() { |
DCHECK(!animate_funnel_); |
last_frame_number_animate_performed_ = current_frame_number_; |
animate_funnel_ = true; |
@@ -618,7 +679,7 @@ void SchedulerStateMachine::UpdateStateOnAnimate() { |
SetNeedsRedraw(); |
} |
-void SchedulerStateMachine::UpdateStateOnSendBeginMainFrame() { |
+void SchedulerStateMachine::WillSendBeginMainFrame() { |
DCHECK(!has_pending_tree_ || settings_.main_frame_before_activation_enabled); |
DCHECK(visible_); |
DCHECK(!send_begin_main_frame_funnel_); |
@@ -628,7 +689,13 @@ void SchedulerStateMachine::UpdateStateOnSendBeginMainFrame() { |
last_frame_number_begin_main_frame_sent_ = current_frame_number_; |
} |
-void SchedulerStateMachine::UpdateStateOnCommit(bool commit_has_no_updates) { |
+void SchedulerStateMachine::WillCommit() { |
+ // The commit may set this synchronously if the new pending tree is |
+ // ready for activation immediately. |
+ pending_tree_is_ready_for_activation_ = false; |
+} |
+ |
+void SchedulerStateMachine::DidCommit(bool commit_has_no_updates) { |
commit_count_++; |
// Animate after commit even if we've already animated. |
@@ -649,13 +716,6 @@ void SchedulerStateMachine::UpdateStateOnCommit(bool commit_has_no_updates) { |
// mostly as if we are not impl-side-painting since there is no pending tree. |
has_pending_tree_ = settings_.impl_side_painting && !commit_has_no_updates; |
- // Update state related to forced draws. |
- if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT) { |
- forced_redraw_state_ = has_pending_tree_ |
- ? FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION |
- : FORCED_REDRAW_STATE_WAITING_FOR_DRAW; |
- } |
- |
// Update the output surface state. |
DCHECK_NE(output_surface_state_, OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION); |
if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT) { |
@@ -667,24 +727,19 @@ void SchedulerStateMachine::UpdateStateOnCommit(bool commit_has_no_updates) { |
} |
} |
- // Update state if we have a new active tree to draw, or if the active tree |
- // was unchanged but we need to do a forced draw. |
- if (!has_pending_tree_ && |
- (!commit_has_no_updates || |
- forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)) { |
+ // Update state if we have a new active tree to draw. |
+ if (!has_pending_tree_) { |
needs_redraw_ = true; |
active_tree_needs_first_draw_ = true; |
} |
// This post-commit work is common to both completed and aborted commits. |
- pending_tree_is_ready_for_activation_ = false; |
- |
if (continuous_painting_) |
needs_commit_ = true; |
last_commit_had_no_updates_ = commit_has_no_updates; |
} |
-void SchedulerStateMachine::UpdateStateOnActivation() { |
+void SchedulerStateMachine::WillActivateSyncTree() { |
if (commit_state_ == COMMIT_STATE_WAITING_FOR_ACTIVATION) { |
commit_state_ = settings_.main_thread_should_always_be_low_latency |
? COMMIT_STATE_WAITING_FOR_DRAW |
@@ -694,19 +749,13 @@ void SchedulerStateMachine::UpdateStateOnActivation() { |
if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION) |
output_surface_state_ = OUTPUT_SURFACE_ACTIVE; |
- if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION) |
- forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_DRAW; |
- |
has_pending_tree_ = false; |
pending_tree_is_ready_for_activation_ = false; |
active_tree_needs_first_draw_ = true; |
needs_redraw_ = true; |
} |
-void SchedulerStateMachine::UpdateStateOnDraw(bool did_request_swap) { |
- if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW) |
- forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE; |
- |
+void SchedulerStateMachine::DidDraw(bool did_request_swap) { |
if (commit_state_ == COMMIT_STATE_WAITING_FOR_DRAW) |
commit_state_ = COMMIT_STATE_IDLE; |
@@ -719,13 +768,68 @@ void SchedulerStateMachine::UpdateStateOnDraw(bool did_request_swap) { |
did_request_swap_in_last_frame_ = true; |
last_frame_number_swap_requested_ = current_frame_number_; |
} |
+ |
+ switch (last_draw_result_) { |
+ case INVALID_RESULT: |
+ NOTREACHED() << "Uninitialized DrawResult."; |
+ break; |
+ |
+ case DRAW_ABORTED_CANT_DRAW: |
+ case DRAW_ABORTED_CONTEXT_LOST: |
+ NOTREACHED() << "Invalid return value from DrawAndSwapIfPossible:" |
+ << last_draw_result_; |
+ break; |
+ |
+ case DRAW_SUCCESS: |
+ break; |
+ |
+ case DRAW_ABORTED_MISSING_RASTER_OUTPUT_HIGH_RES: |
+ case DRAW_ABORTED_MISSING_RASTER_OUTPUT_ANY_RES: |
+ prepare_tiles_reason_ = PREPARE_TILES_NEEDED_FOR_ABORTED_DRAW; |
+ if (prepare_tiles_approach_ == |
+ PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY) { |
+ prepare_tiles_approach_ = PREPARE_TILES_APPROACH_ACCURATE_ACTIVE_WORK; |
+ } |
+ retry_begin_impl_frame_deadline_ = true; |
+ needs_redraw_ = true; |
+ break; |
+ |
+ case DRAW_ABORTED_MISSING_RASTER_SOURCE: |
+ prepare_tiles_reason_ = PREPARE_TILES_NEEDED_FOR_ABORTED_DRAW; |
+ if (prepare_tiles_approach_ == |
+ PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY) { |
+ prepare_tiles_approach_ = PREPARE_TILES_APPROACH_ACCURATE_ACTIVE_WORK; |
+ } |
+ |
+ if (CommitPending() || has_pending_tree_) { |
+ // The new active tree in flight might have an updated raster source, |
+ // so wait and see. |
+ retry_begin_impl_frame_deadline_ = true; |
+ } else { |
+ // We need a new active tree to get an updated raster source. |
+ needs_commit_ = true; |
+ retry_begin_impl_frame_ = true; |
+ } |
+ |
+ // This is one of the few cases where we actively avoid drawing a commit. |
+ // Skipping draw of the commit can be better than a flash of checkerboard. |
+ active_tree_needs_first_draw_ = false; |
+ break; |
+ } |
} |
-void SchedulerStateMachine::UpdateStateOnPrepareTiles() { |
- needs_prepare_tiles_ = false; |
+void SchedulerStateMachine::DidPrepareTiles() { |
+ prepare_tiles_reason_ = PREPARE_TILES_NOT_NEEDED; |
+ |
+ active_tree_ready_to_draw_ = false; |
+ |
+ if (prepare_tiles_approach_ == PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY) |
+ prepare_tiles_funnel_++; |
+ else |
+ prepare_tiles_funnel_ = 0; |
} |
-void SchedulerStateMachine::UpdateStateOnBeginOutputSurfaceCreation() { |
+void SchedulerStateMachine::WillBeginOutputSurfaceCreation() { |
DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_LOST); |
output_surface_state_ = OUTPUT_SURFACE_CREATING; |
@@ -737,7 +841,7 @@ void SchedulerStateMachine::UpdateStateOnBeginOutputSurfaceCreation() { |
DCHECK(!active_tree_needs_first_draw_); |
} |
-void SchedulerStateMachine::UpdateStateOnInvalidateOutputSurface() { |
+void SchedulerStateMachine::WillInvalidateOutputSurface() { |
DCHECK(!invalidate_output_surface_funnel_); |
invalidate_output_surface_funnel_ = true; |
last_frame_number_invalidate_output_surface_performed_ = |
@@ -787,6 +891,13 @@ void SchedulerStateMachine::SetVideoNeedsBeginFrames( |
video_needs_begin_frames_ = video_needs_begin_frames; |
} |
+void SchedulerStateMachine::NotifyBeginFrameSourceActive(bool active) { |
+ // Upon becoming inactive, switch back to prioritizing latency. |
+ if (!active && |
+ prepare_tiles_approach_ == PREPARE_TILES_APPROACH_ACCURATE_ACTIVE_WORK) |
+ prepare_tiles_approach_ = PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY; |
+} |
+ |
void SchedulerStateMachine::SetDeferCommits(bool defer_commits) { |
defer_commits_ = defer_commits; |
} |
@@ -794,11 +905,6 @@ void SchedulerStateMachine::SetDeferCommits(bool defer_commits) { |
// These are the cases where we require a BeginFrame message to make progress |
// on requested actions. |
bool SchedulerStateMachine::BeginFrameRequiredForAction() const { |
- // The forced draw respects our normal draw scheduling, so we need to |
- // request a BeginImplFrame for it. |
- if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW) |
- return true; |
- |
return needs_animate_ || needs_redraw_ || (needs_commit_ && !defer_commits_); |
} |
@@ -828,7 +934,7 @@ bool SchedulerStateMachine::ProactiveBeginFrameWanted() const { |
// Changing priorities may allow us to activate (given the new priorities), |
// which may result in a new frame. |
- if (needs_prepare_tiles_) |
+ if (PrepareTilesPending()) |
return true; |
// If we just sent a swap request, it's likely that we are going to produce |
@@ -851,6 +957,9 @@ void SchedulerStateMachine::OnBeginImplFrame() { |
begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING; |
current_frame_number_++; |
+ retry_begin_impl_frame_ = false; |
+ retry_begin_impl_frame_deadline_ = false; |
+ |
last_commit_had_no_updates_ = false; |
did_request_swap_in_last_frame_ = false; |
@@ -863,6 +972,15 @@ void SchedulerStateMachine::OnBeginImplFrame() { |
if (prepare_tiles_funnel_ > 0) |
prepare_tiles_funnel_--; |
+ // PREPARE_TILES_APPROACH_ACCURATE_ACTIVE_WORK doesn't work well in |
+ // main thread low-latency mode. Transition back to |
+ // PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY if we just recovered |
+ // main-thread latency. |
+ if (skip_begin_main_frame_to_reduce_latency_ && |
+ prepare_tiles_approach_ == PREPARE_TILES_APPROACH_ACCURATE_ACTIVE_WORK) { |
+ prepare_tiles_approach_ = PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY; |
+ } |
+ |
skip_begin_main_frame_to_reduce_latency_ = |
skip_next_begin_main_frame_to_reduce_latency_; |
skip_next_begin_main_frame_to_reduce_latency_ = false; |
@@ -896,17 +1014,23 @@ SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode() const { |
return BEGIN_IMPL_FRAME_DEADLINE_MODE_BLOCKED_ON_READY_TO_DRAW; |
} else if (ShouldTriggerBeginImplFrameDeadlineImmediately()) { |
return BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE; |
- } else if (needs_redraw_ && pending_swaps_ < max_pending_swaps_) { |
- // We have an animation or fast input path on the impl thread that wants |
- // to draw, so don't wait too long for a new active tree. |
- // If we are swap throttled we should wait until we are unblocked. |
- return BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR; |
- } else { |
- // The impl thread doesn't have anything it wants to draw and we are just |
- // waiting for a new active tree or we are swap throttled. In short we are |
- // blocked. |
- return BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE; |
} |
+ |
+ if (prepare_tiles_approach_ == PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY) { |
+ if (needs_redraw_ && pending_swaps_ < max_pending_swaps_) { |
+ // We have an animation or fast input path on the impl thread that wants |
+ // to draw, so don't wait too long for a new active tree. |
+ // If we are swap throttled we should wait until we are unblocked. |
+ return BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR; |
+ } else { |
+ // The impl thread doesn't have anything it wants to draw and we are just |
+ // waiting for a new active tree or we are swap throttled. In short we are |
+ // blocked. |
+ return BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE; |
+ } |
+ } |
+ |
+ return BEGIN_IMPL_FRAME_DEADLINE_MODE_TRY_TO_AVOID_CHECKERBOARD; |
} |
bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately() |
@@ -923,6 +1047,11 @@ bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately() |
if (pending_swaps_ >= max_pending_swaps_) |
return false; |
+ // PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY is the only approach |
+ // where we want to trigger the deadline before NotifyReadyToDraw. |
+ if (prepare_tiles_approach_ != PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY) |
+ return active_tree_ready_to_draw_; |
+ |
if (active_tree_needs_first_draw_) |
return true; |
@@ -985,7 +1114,11 @@ bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const { |
return active_tree_needs_first_draw_; |
} |
-void SchedulerStateMachine::SetVisible(bool visible) { visible_ = visible; } |
+void SchedulerStateMachine::SetVisible(bool visible) { |
+ visible_ = visible; |
+ if (!visible) |
+ prepare_tiles_reason_ = PREPARE_TILES_NEEDED_TO_EVICT_TILES; |
+} |
void SchedulerStateMachine::SetCanDraw(bool can_draw) { can_draw_ = can_draw; } |
@@ -1000,10 +1133,22 @@ void SchedulerStateMachine::SetWaitForReadyToDraw() { |
wait_for_active_tree_ready_to_draw_ = true; |
} |
-void SchedulerStateMachine::SetNeedsPrepareTiles() { |
- if (!needs_prepare_tiles_) { |
- TRACE_EVENT0("cc", "SchedulerStateMachine::SetNeedsPrepareTiles"); |
- needs_prepare_tiles_ = true; |
+void SchedulerStateMachine::SetNeedsPrepareTiles(bool for_commit) { |
+ TRACE_EVENT0("cc", "SchedulerStateMachine::SetNeedsPrepareTiles"); |
+ switch (prepare_tiles_approach_) { |
+ case PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY: |
+ if (for_commit) |
+ prepare_tiles_reason_ = PREPARE_TILES_NEEDED_FOR_COMMIT; |
+ else if (prepare_tiles_reason_ == PREPARE_TILES_NOT_NEEDED) |
+ prepare_tiles_reason_ = PREPARE_TILES_REQUESTED; |
+ break; |
+ |
+ case PREPARE_TILES_APPROACH_ACCURATE_ACTIVE_WORK: |
+ // We don't uncondititionally PrepareTiles immediately after a commit with |
+ // this approach. |
+ if (prepare_tiles_reason_ == PREPARE_TILES_NOT_NEEDED) |
+ prepare_tiles_reason_ = PREPARE_TILES_REQUESTED; |
+ break; |
} |
} |
@@ -1029,47 +1174,8 @@ void SchedulerStateMachine::SetImplLatencyTakesPriority( |
impl_latency_takes_priority_ = impl_latency_takes_priority; |
} |
-void SchedulerStateMachine::DidDrawIfPossibleCompleted(DrawResult result) { |
- switch (result) { |
- case INVALID_RESULT: |
- NOTREACHED() << "Uninitialized DrawResult."; |
- break; |
- case DRAW_ABORTED_CANT_DRAW: |
- case DRAW_ABORTED_CONTEXT_LOST: |
- NOTREACHED() << "Invalid return value from DrawAndSwapIfPossible:" |
- << result; |
- break; |
- case DRAW_SUCCESS: |
- consecutive_checkerboard_animations_ = 0; |
- forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE; |
- break; |
- case DRAW_ABORTED_CHECKERBOARD_ANIMATIONS: |
- needs_redraw_ = true; |
- |
- // If we're already in the middle of a redraw, we don't need to |
- // restart it. |
- if (forced_redraw_state_ != FORCED_REDRAW_STATE_IDLE) |
- return; |
- |
- needs_commit_ = true; |
- consecutive_checkerboard_animations_++; |
- if (settings_.timeout_and_draw_when_animation_checkerboards && |
- consecutive_checkerboard_animations_ >= |
- settings_.maximum_number_of_failed_draws_before_draw_is_forced_) { |
- consecutive_checkerboard_animations_ = 0; |
- // We need to force a draw, but it doesn't make sense to do this until |
- // we've committed and have new textures. |
- forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_COMMIT; |
- } |
- break; |
- case DRAW_ABORTED_MISSING_HIGH_RES_CONTENT: |
- // It's not clear whether this missing content is because of missing |
- // pictures (which requires a commit) or because of memory pressure |
- // removing textures (which might not). To be safe, request a commit |
- // anyway. |
- needs_commit_ = true; |
- break; |
- } |
+void SchedulerStateMachine::SetDrawResult(DrawResult result) { |
+ last_draw_result_ = result; |
} |
void SchedulerStateMachine::SetNeedsCommit() { |
@@ -1098,17 +1204,11 @@ void SchedulerStateMachine::BeginMainFrameAborted(CommitEarlyOutReason reason) { |
return; |
case CommitEarlyOutReason::FINISHED_NO_UPDATES: |
bool commit_has_no_updates = true; |
- UpdateStateOnCommit(commit_has_no_updates); |
+ DidCommit(commit_has_no_updates); |
return; |
} |
} |
-void SchedulerStateMachine::DidPrepareTiles() { |
- needs_prepare_tiles_ = false; |
- // "Fill" the PrepareTiles funnel. |
- prepare_tiles_funnel_++; |
-} |
- |
void SchedulerStateMachine::DidLoseOutputSurface() { |
if (output_surface_state_ == OUTPUT_SURFACE_LOST || |
output_surface_state_ == OUTPUT_SURFACE_CREATING) |
@@ -1119,12 +1219,18 @@ void SchedulerStateMachine::DidLoseOutputSurface() { |
} |
void SchedulerStateMachine::NotifyReadyToActivate() { |
- if (has_pending_tree_) |
- pending_tree_is_ready_for_activation_ = true; |
+ pending_tree_is_ready_for_activation_ = true; |
} |
void SchedulerStateMachine::NotifyReadyToDraw() { |
wait_for_active_tree_ready_to_draw_ = false; |
+ active_tree_ready_to_draw_ = true; |
+} |
+ |
+void SchedulerStateMachine::SetRequiresHighResToDraw(bool required) { |
+ if (requires_high_res_to_draw_ == required) |
+ return; |
+ requires_high_res_to_draw_ = required; |
} |
void SchedulerStateMachine::DidCreateAndInitializeOutputSurface() { |