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..df814e253033e14c595c51b3d9b08a1d3ecfbad8 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,10 @@ 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), |
+ previous_pending_tree_was_impl_side_(false), |
+ current_pending_tree_is_impl_side_(false) {} |
const char* SchedulerStateMachine::CompositorFrameSinkStateToString( |
CompositorFrameSinkState state) { |
@@ -177,6 +181,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 +226,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 +263,8 @@ 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->EndDictionary(); |
} |
@@ -519,6 +529,11 @@ bool SchedulerStateMachine::ShouldPrepareTiles() const { |
if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) |
return false; |
+ // If an impl-side invalidation request is pending and we are inside the |
+ // deadline, then performing these invalidations will also do PrepareTiles. |
+ if (needs_impl_side_invalidation_) |
sunnyps
2017/02/23 00:33:21
Impl side invalidation will happen before prepare
Khushal
2017/02/23 01:25:43
Done.
sunnyps
2017/02/23 01:34:12
nit: Try moving this DCHECK to WillPrepareTiles. T
Khushal
2017/02/23 07:42:37
Actually on second look, I don't think this logic/
|
+ return false; |
+ |
return needs_prepare_tiles_; |
} |
@@ -554,6 +569,8 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { |
else |
return ACTION_DRAW_IF_POSSIBLE; |
} |
+ if (ShouldPerformImplSideInvalidation()) |
+ return ACTION_PERFORM_IMPL_SIDE_INVALIDATION; |
if (ShouldPrepareTiles()) |
return ACTION_PREPARE_TILES; |
if (ShouldSendBeginMainFrame()) |
@@ -565,6 +582,81 @@ 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; |
+ } |
+ |
+ // If we are inside the deadline and an impl-side invalidation request is |
+ // still pending, do it now. We restrict performing impl-side invalidations |
+ // until the deadline to give the main thread a chance to respond to a sent |
+ // BeginMainFrame. If the main thread responds with a commit, we know the |
+ // invalidations will have been merged with the main frame. |
+ // If the commit was aborted, or the main thread fails to respond within the |
+ // deadline, then we create a pending tree for impl-side invalidations now. |
+ // This also checks to make sure that the |prepare_tiles_funnel_| is not full, |
+ // since impl-side invalidations will cause a PrepareTiles. |
+ if (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE && |
+ prepare_tiles_funnel_ == 0) |
sunnyps
2017/02/23 00:33:21
nit: braces
Khushal
2017/02/23 01:25:43
Done.
|
+ return true; |
+ |
+ // Wait till the deadline to perform impl-side invalidations. |
+ return false; |
+} |
+ |
+void SchedulerStateMachine::WillPerformImplSideInvalidation() { |
+ current_pending_tree_is_impl_side_ = true; |
+ 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/23 00:33:21
For invalidating active tree (commit_to_active_tre
Khushal
2017/02/23 01:25:43
Yup, sending the activation signal will happen in
|
+ 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,6 +677,15 @@ 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; |
@@ -619,6 +720,9 @@ void SchedulerStateMachine::WillActivate() { |
pending_tree_is_ready_for_activation_ = false; |
active_tree_needs_first_draw_ = true; |
needs_redraw_ = true; |
+ |
+ previous_pending_tree_was_impl_side_ = current_pending_tree_is_impl_side_; |
+ current_pending_tree_is_impl_side_ = false; |
} |
void SchedulerStateMachine::WillDrawInternal() { |
@@ -689,6 +793,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 +875,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 +936,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) |