Chromium Code Reviews| 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 |