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) |