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..124cd0a8f4afdd453ff30f530cea99cd8972e44f 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,94 @@ 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())) { |
sunnyps
2017/02/14 21:40:18
What does impl-side invalidation mean if commit_to
Khushal
2017/02/15 00:56:33
It would mean we invalidate the tiles on the activ
enne (OOO)
2017/02/15 01:09:28
Yeah, that was my thought as well. It seems like
sunnyps
2017/02/20 23:19:22
I'm still confused about how active tree tiles wil
Khushal
2017/02/21 09:43:44
The impl-side invalidation works exactly like a co
|
+ 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) |
+ return false; |
+ |
+ // At this point, create a pending tree to run impl-side invalidations. |
+ return true; |
+} |
+ |
+void SchedulerStateMachine::WillRunImplSideInvalidation() { |
+ DCHECK(needs_impl_side_invalidation_); |
+ WillRunImplSideInvalidationInternal(); |
+} |
+ |
+void SchedulerStateMachine::WillRunImplSideInvalidationInternal() { |
+ needs_impl_side_invalidation_ = false; |
+ has_pending_tree_ = true; |
+ impl_side_invalidations_take_priority_ = false; |
+ impl_side_invalidation_funnel_ = true; |
+ |
+ // We fill the BeginMainFrame funnel when running impl-side invalidations |
+ // since we know that another pending tree in this BeginFrame will end up |
+ // getting blocked on drawing of the impl-side pending tree further down the |
+ // pipeline. |
+ send_begin_main_frame_funnel_ = true; |
sunnyps
2017/02/14 21:40:18
I'm kinda worried about this. It means there will
Khushal
2017/02/15 00:56:33
If there is rAF alongside a pending invalidation,
Khushal
2017/02/15 03:23:52
Okay. After offline discussion, removed this. We w
|
+} |
+ |
+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_); |
@@ -589,6 +690,15 @@ 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. |
+ WillRunImplSideInvalidationInternal(); |
+ } 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; |
sunnyps
2017/02/14 21:40:18
nit: you can use last_commit_had_no_updates_ inste
Khushal
2017/02/15 00:56:33
That flag gets reset on every BeginImplFrame, but
|
} |
// Update state related to forced draws. |
@@ -689,6 +799,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 +881,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 +942,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) |