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..3e85448ee2a7f2140c731e560328576b71c67713 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), |
| + run_impl_side_invalidation_after_main_frame_aborted_(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_RUN_IMPL_SIDE_INVALIDATION: |
| + return "ACTION_RUN_IMPL_SIDE_INVALIDATION"; |
| } |
| NOTREACHED(); |
| return "???"; |
| @@ -558,6 +563,8 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { |
| return ACTION_PREPARE_TILES; |
| if (ShouldSendBeginMainFrame()) |
| return ACTION_SEND_BEGIN_MAIN_FRAME; |
| + if (ShouldRunImplSideInvalidation()) |
| + return ACTION_RUN_IMPL_SIDE_INVALIDATION; |
| if (ShouldInvalidateCompositorFrameSink()) |
| return ACTION_INVALIDATE_COMPOSITOR_FRAME_SINK; |
| if (ShouldBeginCompositorFrameSinkCreation()) |
| @@ -565,6 +572,79 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { |
| return ACTION_NONE; |
| } |
| +bool SchedulerStateMachine::ShouldRunImplSideInvalidation() 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 keep waiting on the main thread if the commits are being aborted. |
| + if (run_impl_side_invalidation_after_main_frame_aborted_) |
| + 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? |
| + 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) |
| + return false; |
| + |
| + // At this point, create a pending tree to run impl-side invalidations. |
| + return true; |
| +} |
| + |
| +void SchedulerStateMachine::WillRunImplSideInvalidation() { |
| + DCHECK(needs_impl_side_invalidation_); |
| + |
| + needs_impl_side_invalidation_ = false; |
| + has_pending_tree_ = true; |
| + run_impl_side_invalidation_after_main_frame_aborted_ = 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; |
| + |
| + return true; |
| +} |
| + |
| void SchedulerStateMachine::WillSendBeginMainFrame() { |
| DCHECK(!has_pending_tree_ || settings_.main_frame_before_activation_enabled); |
| DCHECK(visible_); |
| @@ -589,6 +669,13 @@ void SchedulerStateMachine::WillCommit(bool commit_has_no_updates) { |
| has_pending_tree_ = true; |
| pending_tree_is_ready_for_activation_ = false; |
| wait_for_ready_to_draw_ = settings_.commit_to_active_tree; |
| + |
| + // If there was a commit, the impl-side invalidations will be merged with |
| + // it. |
| + if (needs_impl_side_invalidation_) |
| + WillRunImplSideInvalidation(); |
|
brianderson
2017/02/03 00:54:53
I know it'll seem like extra boiler plate, but thi
Khushal
2017/02/03 01:45:11
Done.
|
| + } else if (needs_impl_side_invalidation_) { |
| + run_impl_side_invalidation_after_main_frame_aborted_ = true; |
| } |
| // Update state related to forced draws. |
| @@ -689,6 +776,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 +858,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 +919,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) |