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

Unified Diff: cc/scheduler/scheduler_state_machine.cc

Issue 2753843003: Create a new action triggered when a BeginMainFrame is not expected before vsync (Closed)
Patch Set: fix up some const refs that should be POD. Fix up state machine decision comments. add some logging. Created 3 years, 8 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 e73508ce1ab1fb198c9b69ff0e65609a3e637e8e..f8a828476ad9f8f0ecb2b654776f085a8b30fb04 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -42,9 +42,11 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
last_frame_number_begin_main_frame_sent_(-1),
last_frame_number_invalidate_compositor_frame_sink_performed_(-1),
draw_funnel_(false),
- send_begin_main_frame_funnel_(true),
+ did_send_begin_main_frame_for_current_frame_(true),
invalidate_compositor_frame_sink_funnel_(false),
impl_side_invalidation_funnel_(false),
+ did_notify_begin_main_frame_not_sent_(false),
+ did_commit_during_frame_(false),
prepare_tiles_funnel_(0),
consecutive_checkerboard_animations_(0),
pending_submit_frames_(0),
@@ -194,6 +196,8 @@ const char* SchedulerStateMachine::ActionToString(Action action) {
return "ACTION_INVALIDATE_COMPOSITOR_FRAME_SINK";
case ACTION_PERFORM_IMPL_SIDE_INVALIDATION:
return "ACTION_PERFORM_IMPL_SIDE_INVALIDATION";
+ case ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT:
+ return "ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT";
}
NOTREACHED();
return "???";
@@ -244,8 +248,12 @@ void SchedulerStateMachine::AsValueInto(
"last_begin_frame_sequence_number_compositor_frame_was_fresh",
last_begin_frame_sequence_number_compositor_frame_was_fresh_);
state->SetBoolean("funnel: draw_funnel", draw_funnel_);
- state->SetBoolean("funnel: send_begin_main_frame_funnel",
- send_begin_main_frame_funnel_);
+ state->SetBoolean("funnel: did_send_begin_main_frame",
+ did_send_begin_main_frame_for_current_frame_);
+ state->SetBoolean("funnel: did_notify_begin_main_frame_not_sent",
+ did_notify_begin_main_frame_not_sent_);
+ state->SetBoolean("funnel: did_commit_during_frame",
+ did_commit_during_frame_);
state->SetInteger("funnel: prepare_tiles_funnel", prepare_tiles_funnel_);
state->SetBoolean("funnel: invalidate_compositor_frame_sink_funnel",
invalidate_compositor_frame_sink_funnel_);
@@ -428,6 +436,44 @@ bool SchedulerStateMachine::ShouldActivatePendingTree() const {
return pending_tree_is_ready_for_activation_;
}
+bool SchedulerStateMachine::ShouldNotifyBeginMainFrameNotSent() const {
brianderson 2017/04/07 22:03:16 Is it okay that we'll be sending this at the start
Dan Elphick 2017/04/10 15:53:22 We're aware this might cause some problems, but we
+ // This method returns true if most of the conditions for sending a
+ // BeginMainFrame are met, but one is not actually requested. This gives the
+ // main thread the chance to do something else.
+
+ // Don't notify if a BeginMainFrame has already been requested.
+ if (needs_begin_main_frame_ || did_send_begin_main_frame_for_current_frame_)
brianderson 2017/04/07 22:03:16 I think the did_send_begin_main_frame_for_current_
Dan Elphick 2017/04/10 15:53:22 It is actually necessary as it's the flag is initi
+ return false;
+
+ // Only notify when we're visible.
+ if (!visible_)
+ return false;
+
+ // There are no BeginImplFrames while BeginFrameSource is paused, meaning
+ // the scheduler should send SendBeginMainFrameNotExpectedSoon instead,
+ // indicating a longer period of inactivity.
+ if (begin_frame_source_paused_)
+ return false;
+
+ // Do not notify that no BeginMainFrame was sent too many times in a single
+ // frame.
+ if (did_notify_begin_main_frame_not_sent_)
+ return false;
+
+ // Do not notify if a commit happened during this frame as the main thread
+ // will already be active and does not need to be woken up to make further
+ // actions. (This occurs if the main frame was scheduled but didn't complete
+ // before the vsync deadline).
+ if (did_commit_during_frame_)
+ return false;
+
+ // If a BeginMainFrame is in progress, there's no need to activate it.
+ if (begin_main_frame_state_ != BEGIN_MAIN_FRAME_STATE_IDLE)
brianderson 2017/04/07 22:03:16 Group this with the needs_begin_main_frame_ check
Dan Elphick 2017/04/10 15:53:22 Done.
+ return false;
+
+ return true;
+}
+
bool SchedulerStateMachine::CouldSendBeginMainFrame() const {
if (!needs_begin_main_frame_)
return false;
@@ -454,7 +500,7 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
// Do not send begin main frame too many times in a single frame or before
// the first BeginFrame.
- if (send_begin_main_frame_funnel_)
+ if (did_send_begin_main_frame_for_current_frame_)
return false;
// Only send BeginMainFrame when there isn't another commit pending already.
@@ -598,6 +644,8 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
return ACTION_INVALIDATE_COMPOSITOR_FRAME_SINK;
if (ShouldBeginCompositorFrameSinkCreation())
return ACTION_BEGIN_COMPOSITOR_FRAME_SINK_CREATION;
+ if (ShouldNotifyBeginMainFrameNotSent())
+ return ACTION_NOTIFY_BEGIN_MAIN_FRAME_NOT_SENT;
return ACTION_NONE;
}
@@ -683,15 +731,22 @@ void SchedulerStateMachine::WillSendBeginMainFrame() {
DCHECK(!has_pending_tree_ || settings_.main_frame_before_activation_enabled);
DCHECK(visible_);
DCHECK(!begin_frame_source_paused_);
- DCHECK(!send_begin_main_frame_funnel_);
+ DCHECK(!did_send_begin_main_frame_for_current_frame_);
begin_main_frame_state_ = BEGIN_MAIN_FRAME_STATE_SENT;
needs_begin_main_frame_ = false;
- send_begin_main_frame_funnel_ = true;
+ did_send_begin_main_frame_for_current_frame_ = true;
last_frame_number_begin_main_frame_sent_ = current_frame_number_;
last_begin_frame_sequence_number_begin_main_frame_sent_ =
begin_frame_sequence_number_;
}
+void SchedulerStateMachine::WillNotifyBeginMainFrameNotSent() {
+ DCHECK(visible_);
+ DCHECK(!begin_frame_source_paused_);
+ DCHECK(!did_notify_begin_main_frame_not_sent_);
+ did_notify_begin_main_frame_not_sent_ = true;
+}
+
void SchedulerStateMachine::WillCommit(bool commit_has_no_updates) {
bool can_have_pending_tree =
commit_has_no_updates &&
@@ -701,6 +756,7 @@ void SchedulerStateMachine::WillCommit(bool commit_has_no_updates) {
commit_count_++;
last_commit_had_no_updates_ = commit_has_no_updates;
begin_main_frame_state_ = BEGIN_MAIN_FRAME_STATE_IDLE;
+ did_commit_during_frame_ = true;
if (commit_has_no_updates) {
// Pending tree might still exist from prior commit.
@@ -1047,7 +1103,9 @@ void SchedulerStateMachine::OnBeginImplFrame(uint32_t source_id,
needs_one_begin_impl_frame_ = false;
// Clear funnels for any actions we perform during the frame.
- send_begin_main_frame_funnel_ = false;
+ did_notify_begin_main_frame_not_sent_ = false;
+ did_send_begin_main_frame_for_current_frame_ = false;
+ did_commit_during_frame_ = false;
invalidate_compositor_frame_sink_funnel_ = false;
impl_side_invalidation_funnel_ = false;
@@ -1085,7 +1143,7 @@ void SchedulerStateMachine::OnBeginImplFrameIdle() {
// If we're entering a state where we won't get BeginFrames set all the
// funnels so that we don't perform any actions that we shouldn't.
if (!BeginFrameNeeded())
- send_begin_main_frame_funnel_ = true;
+ did_send_begin_main_frame_for_current_frame_ = true;
// Synchronous compositor finishes BeginFrames before triggering their
// deadline. Therefore, we update sequence numbers when becoming idle, before

Powered by Google App Engine
This is Rietveld 408576698