Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1211)

Unified Diff: cc/scheduler/scheduler_state_machine.cc

Issue 2659123004: cc: Add scheduler support for invalidating content on impl thread. (Closed)
Patch Set: moar tests Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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)

Powered by Google App Engine
This is Rietveld 408576698