Chromium Code Reviews| Index: cc/scheduler/scheduler_state_machine.cc |
| diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc |
| index 91ae485850381b5ce41b3eb509a11d06deb5ba09..93e38bae634c804c70a25452f1c0cf1e5aa3b08b 100644 |
| --- a/cc/scheduler/scheduler_state_machine.cc |
| +++ b/cc/scheduler/scheduler_state_machine.cc |
| @@ -33,6 +33,7 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) |
| draw_funnel_(false), |
| send_begin_main_frame_funnel_(true), |
| invalidate_compositor_frame_sink_funnel_(false), |
| + impl_side_invalidation_funnel_(false), |
| prepare_tiles_funnel_(0), |
| consecutive_checkerboard_animations_(0), |
| pending_submit_frames_(0), |
| @@ -60,7 +61,9 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) |
| last_commit_had_no_updates_(false), |
| wait_for_ready_to_draw_(false), |
| did_draw_in_last_frame_(false), |
| - did_submit_in_last_frame_(false) {} |
| + did_submit_in_last_frame_(false), |
| + needs_impl_side_invalidation_(false), |
| + impl_side_invalidations_take_priority_(false) {} |
| const char* SchedulerStateMachine::CompositorFrameSinkStateToString( |
| CompositorFrameSinkState state) { |
| @@ -177,6 +180,8 @@ const char* SchedulerStateMachine::ActionToString(Action action) { |
| return "ACTION_PREPARE_TILES"; |
| case ACTION_INVALIDATE_COMPOSITOR_FRAME_SINK: |
| return "ACTION_INVALIDATE_COMPOSITOR_FRAME_SINK"; |
| + case ACTION_PERFORM_IMPL_SIDE_INVALIDATION: |
| + return "ACTION_PERFORM_IMPL_SIDE_INVALIDATION"; |
| } |
| NOTREACHED(); |
| return "???"; |
| @@ -220,6 +225,8 @@ void SchedulerStateMachine::AsValueInto( |
| state->SetInteger("funnel: prepare_tiles_funnel", prepare_tiles_funnel_); |
| state->SetBoolean("funnel: invalidate_compositor_frame_sink_funnel", |
| invalidate_compositor_frame_sink_funnel_); |
| + state->SetBoolean("funnel: impl_side_invalidation_funnel", |
| + impl_side_invalidation_funnel_); |
| state->SetInteger("consecutive_checkerboard_animations", |
| consecutive_checkerboard_animations_); |
| state->SetInteger("pending_submit_frames_", pending_submit_frames_); |
| @@ -255,6 +262,10 @@ void SchedulerStateMachine::AsValueInto( |
| state->SetBoolean("last_commit_had_no_updates", last_commit_had_no_updates_); |
| state->SetBoolean("did_draw_in_last_frame", did_draw_in_last_frame_); |
| state->SetBoolean("did_submit_in_last_frame", did_submit_in_last_frame_); |
| + state->SetBoolean("needs_impl_side_invalidation", |
| + needs_impl_side_invalidation_); |
| + state->SetBoolean("impl_side_invalidations_take_priority", |
| + impl_side_invalidations_take_priority_); |
| state->EndDictionary(); |
| } |
| @@ -558,6 +569,8 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { |
| return ACTION_PREPARE_TILES; |
| if (ShouldSendBeginMainFrame()) |
| return ACTION_SEND_BEGIN_MAIN_FRAME; |
| + if (ShouldPerformImplSideInvalidation()) |
| + return ACTION_PERFORM_IMPL_SIDE_INVALIDATION; |
| if (ShouldInvalidateCompositorFrameSink()) |
| return ACTION_INVALIDATE_COMPOSITOR_FRAME_SINK; |
| if (ShouldBeginCompositorFrameSinkCreation()) |
| @@ -565,6 +578,90 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { |
| return ACTION_NONE; |
| } |
| +bool SchedulerStateMachine::ShouldPerformImplSideInvalidation() const { |
| + if (!needs_impl_side_invalidation_) |
| + return false; |
| + |
| + if (!CouldCreatePendingTree()) |
| + return false; |
| + |
| + // If the main thread is ready to commit, the impl-side invalidations will be |
| + // merged with the incoming main frame. |
| + if (begin_main_frame_state_ == BEGIN_MAIN_FRAME_STATE_READY_TO_COMMIT) |
| + return false; |
| + |
| + // Don't invalidate too many times in the same frame. |
| + if (impl_side_invalidation_funnel_) |
| + return false; |
| + |
| + // If invalidations go to the active tree and we are waiting for the previous |
| + // frame to be drawn, submitted and acked. |
| + if (settings_.commit_to_active_tree && |
| + (active_tree_needs_first_draw_ || IsDrawThrottled())) { |
| + return false; |
| + } |
| + |
| + // Don't wait on the response to BeginMainFrame if we are prioritizing impl |
| + // side invalidations. |
| + if (impl_side_invalidations_take_priority_) |
| + return true; |
| + |
| + // If BeginMainFrame has been sent, let's wait for the main thread before |
| + // pipelining impl-side invalidations. |
| + // TODO(khushalsagar): If the main thread is high latency, may be run |
| + // impl-side invalidations instead of waiting on the main thread? |
| + // See crbug.com/691735. |
| + if (begin_main_frame_state_ == BEGIN_MAIN_FRAME_STATE_SENT || |
| + begin_main_frame_state_ == BEGIN_MAIN_FRAME_STATE_STARTED) |
| + return false; |
| + |
| + // If a main frame request is pending, always prioritize sending a |
| + // BeginMainFrame and receiving an update from the main thread before creating |
| + // a pending tree for impl-side invalidations. |
| + if (CouldSendBeginMainFrame() && |
| + begin_main_frame_state_ == |
| + BeginMainFrameState::BEGIN_MAIN_FRAME_STATE_IDLE) |
|
brianderson
2017/02/21 23:34:59
Given the preceding logic, I think the STATE_IDLE
Khushal
2017/02/22 20:24:02
This code went away in the new patch, now that we
|
| + return false; |
| + |
| + // At this point, create a pending tree to run impl-side invalidations. |
| + return true; |
| +} |
| + |
| +void SchedulerStateMachine::WillPerformImplSideInvalidation() { |
| + WillPerformImplSideInvalidationInternal(); |
| +} |
| + |
| +void SchedulerStateMachine::WillPerformImplSideInvalidationInternal() { |
| + DCHECK(needs_impl_side_invalidation_); |
| + DCHECK(!has_pending_tree_); |
| + |
| + needs_impl_side_invalidation_ = false; |
| + has_pending_tree_ = true; |
|
sunnyps
2017/02/20 23:19:22
For UI, has_pending_tree_ = true should never be t
Khushal
2017/02/21 09:43:44
Good point. The impl-side invalidation should be d
|
| + impl_side_invalidations_take_priority_ = false; |
| + impl_side_invalidation_funnel_ = true; |
| +} |
| + |
| +bool SchedulerStateMachine::CouldCreatePendingTree() const { |
| + // Can't create a new pending tree till the current one is activated. |
| + if (has_pending_tree_) |
| + return false; |
| + |
| + // Can't make frames while we're invisible. |
| + if (!visible_) |
| + return false; |
| + |
| + // If the BeginFrameSource is paused, we will not be able to make any impl |
| + // frames. |
| + if (begin_frame_source_paused_) |
| + return false; |
| + |
| + // Don't create a pending tree till a frame sink is initialized. |
| + if (!HasInitializedCompositorFrameSink()) |
| + return false; |
| + |
| + return true; |
| +} |
| + |
| void SchedulerStateMachine::WillSendBeginMainFrame() { |
| DCHECK(!has_pending_tree_ || settings_.main_frame_before_activation_enabled); |
| DCHECK(visible_); |
| @@ -585,10 +682,24 @@ void SchedulerStateMachine::WillCommit(bool commit_has_no_updates) { |
| begin_main_frame_state_ = BEGIN_MAIN_FRAME_STATE_IDLE; |
| if (!commit_has_no_updates) { |
| + // If there was a commit, the impl-side invalidations will be merged with |
| + // it. We always fill the impl-side invalidation funnel here, even if no |
| + // request was currently pending, to defer creating another pending tree and |
| + // performing PrepareTiles until the next frame, in case the invalidation |
| + // request is received after the commit. |
| + if (needs_impl_side_invalidation_) |
| + WillPerformImplSideInvalidationInternal(); |
| + impl_side_invalidation_funnel_ = true; |
| + |
| // Pending tree only exists if commit had updates. |
| has_pending_tree_ = true; |
| pending_tree_is_ready_for_activation_ = false; |
| wait_for_ready_to_draw_ = settings_.commit_to_active_tree; |
| + } else if (needs_impl_side_invalidation_) { |
| + // If the main frame is getting aborted, the impl-side updates will end up |
| + // continuously waiting on a commit. In this case, prioritize these over |
| + // the main frame. |
| + impl_side_invalidations_take_priority_ = true; |
| } |
| // Update state related to forced draws. |
| @@ -689,6 +800,10 @@ void SchedulerStateMachine::DidDraw(DrawResult draw_result) { |
| DidDrawInternal(draw_result); |
| } |
| +void SchedulerStateMachine::SetNeedsImplSideInvalidation() { |
| + needs_impl_side_invalidation_ = true; |
| +} |
| + |
| void SchedulerStateMachine::AbortDraw() { |
| // Pretend like the draw was successful. |
| // Note: We may abort at any time and cannot DCHECK that |
| @@ -767,7 +882,8 @@ bool SchedulerStateMachine::BeginFrameRequiredForAction() const { |
| return true; |
| return needs_redraw_ || needs_one_begin_impl_frame_ || |
| - (needs_begin_main_frame_ && !defer_commits_); |
| + (needs_begin_main_frame_ && !defer_commits_) || |
| + needs_impl_side_invalidation_; |
| } |
| // These are cases where we are very likely want a BeginFrame message in the |
| @@ -827,6 +943,7 @@ void SchedulerStateMachine::OnBeginImplFrame() { |
| // Clear funnels for any actions we perform during the frame. |
| send_begin_main_frame_funnel_ = false; |
| invalidate_compositor_frame_sink_funnel_ = false; |
| + impl_side_invalidation_funnel_ = false; |
| // "Drain" the PrepareTiles funnel. |
| if (prepare_tiles_funnel_ > 0) |