Index: cc/scheduler/scheduler_state_machine.cc |
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc |
index 189387cf12856f1fc348c605a976d1422aaf705c..c512987bd23f501abdaf1fceab783945f8dc1ae4 100644 |
--- a/cc/scheduler/scheduler_state_machine.cc |
+++ b/cc/scheduler/scheduler_state_machine.cc |
@@ -26,6 +26,10 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) |
last_frame_number_swap_performed_(-1), |
last_frame_number_swap_requested_(-1), |
last_frame_number_begin_main_frame_sent_(-1), |
+ animate_funnel_(false), |
+ perform_swap_funnel_(false), |
+ request_swap_funnel_(false), |
+ send_begin_main_frame_funnel_(false), |
prepare_tiles_funnel_(0), |
consecutive_checkerboard_animations_(0), |
max_pending_swaps_(1), |
@@ -41,14 +45,14 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) |
has_pending_tree_(false), |
pending_tree_is_ready_for_activation_(false), |
active_tree_needs_first_draw_(false), |
- did_commit_after_animating_(false), |
did_create_and_initialize_first_output_surface_(false), |
impl_latency_takes_priority_(false), |
skip_next_begin_main_frame_to_reduce_latency_(false), |
skip_begin_main_frame_to_reduce_latency_(false), |
continuous_painting_(false), |
children_need_begin_frames_(false), |
- defer_commits_(false) { |
+ defer_commits_(false), |
+ last_commit_had_no_updates_(false) { |
} |
const char* SchedulerStateMachine::OutputSurfaceStateToString( |
@@ -151,12 +155,12 @@ scoped_refptr<base::trace_event::ConvertableToTraceFormat> |
SchedulerStateMachine::AsValue() const { |
scoped_refptr<base::trace_event::TracedValue> state = |
new base::trace_event::TracedValue(); |
- AsValueInto(state.get(), gfx::FrameTime::Now()); |
+ AsValueInto(state.get()); |
return state; |
} |
-void SchedulerStateMachine::AsValueInto(base::trace_event::TracedValue* state, |
- base::TimeTicks now) const { |
+void SchedulerStateMachine::AsValueInto( |
+ base::trace_event::TracedValue* state) const { |
state->BeginDictionary("major_state"); |
state->SetString("next_action", ActionToString(NextAction())); |
state->SetString("begin_impl_frame_state", |
@@ -168,35 +172,9 @@ void SchedulerStateMachine::AsValueInto(base::trace_event::TracedValue* state, |
ForcedRedrawOnTimeoutStateToString(forced_redraw_state_)); |
state->EndDictionary(); |
- state->BeginDictionary("major_timestamps_in_ms"); |
- state->SetDouble("0_interval", |
- begin_impl_frame_args_.interval.InMicroseconds() / 1000.0L); |
- state->SetDouble( |
- "1_now_to_deadline", |
- (begin_impl_frame_args_.deadline - now).InMicroseconds() / 1000.0L); |
- state->SetDouble( |
- "2_frame_time_to_now", |
- (now - begin_impl_frame_args_.frame_time).InMicroseconds() / 1000.0L); |
- state->SetDouble("3_frame_time_to_deadline", |
- (begin_impl_frame_args_.deadline - |
- begin_impl_frame_args_.frame_time).InMicroseconds() / |
- 1000.0L); |
- state->SetDouble("4_now", |
- (now - base::TimeTicks()).InMicroseconds() / 1000.0L); |
- state->SetDouble( |
- "5_frame_time", |
- (begin_impl_frame_args_.frame_time - base::TimeTicks()).InMicroseconds() / |
- 1000.0L); |
- state->SetDouble( |
- "6_deadline", |
- (begin_impl_frame_args_.deadline - base::TimeTicks()).InMicroseconds() / |
- 1000.0L); |
- state->EndDictionary(); |
- |
state->BeginDictionary("minor_state"); |
state->SetInteger("commit_count", commit_count_); |
state->SetInteger("current_frame_number", current_frame_number_); |
- |
state->SetInteger("last_frame_number_animate_performed", |
last_frame_number_animate_performed_); |
state->SetInteger("last_frame_number_swap_performed", |
@@ -205,8 +183,12 @@ void SchedulerStateMachine::AsValueInto(base::trace_event::TracedValue* state, |
last_frame_number_swap_requested_); |
state->SetInteger("last_frame_number_begin_main_frame_sent", |
last_frame_number_begin_main_frame_sent_); |
- |
- state->SetInteger("prepare_tiles_funnel", prepare_tiles_funnel_); |
+ state->SetBoolean("funnel: animate_funnel", animate_funnel_); |
+ state->SetBoolean("funnel: perform_swap_funnel", perform_swap_funnel_); |
+ state->SetBoolean("funnel: request_swap_funnel", request_swap_funnel_); |
+ state->SetBoolean("funnel: send_begin_main_frame_funnel", |
+ send_begin_main_frame_funnel_); |
+ state->SetInteger("funnel: prepare_tiles_funnel", prepare_tiles_funnel_); |
state->SetInteger("consecutive_checkerboard_animations", |
consecutive_checkerboard_animations_); |
state->SetInteger("max_pending_swaps_", max_pending_swaps_); |
@@ -223,7 +205,6 @@ void SchedulerStateMachine::AsValueInto(base::trace_event::TracedValue* state, |
pending_tree_is_ready_for_activation_); |
state->SetBoolean("active_tree_needs_first_draw", |
active_tree_needs_first_draw_); |
- state->SetBoolean("did_commit_after_animating", did_commit_after_animating_); |
state->SetBoolean("did_create_and_initialize_first_output_surface", |
did_create_and_initialize_first_output_surface_); |
state->SetBoolean("impl_latency_takes_priority", |
@@ -243,6 +224,11 @@ void SchedulerStateMachine::AsValueInto(base::trace_event::TracedValue* state, |
void SchedulerStateMachine::AdvanceCurrentFrameNumber() { |
current_frame_number_++; |
+ animate_funnel_ = false; |
+ perform_swap_funnel_ = false; |
+ request_swap_funnel_ = false; |
+ send_begin_main_frame_funnel_ = false; |
+ |
// "Drain" the PrepareTiles funnel. |
if (prepare_tiles_funnel_ > 0) |
prepare_tiles_funnel_--; |
@@ -252,23 +238,6 @@ void SchedulerStateMachine::AdvanceCurrentFrameNumber() { |
skip_next_begin_main_frame_to_reduce_latency_ = false; |
} |
-bool SchedulerStateMachine::HasAnimatedThisFrame() const { |
- return last_frame_number_animate_performed_ == current_frame_number_; |
-} |
- |
-bool SchedulerStateMachine::HasSentBeginMainFrameThisFrame() const { |
- return current_frame_number_ == |
- last_frame_number_begin_main_frame_sent_; |
-} |
- |
-bool SchedulerStateMachine::HasSwappedThisFrame() const { |
- return current_frame_number_ == last_frame_number_swap_performed_; |
-} |
- |
-bool SchedulerStateMachine::HasRequestedSwapThisFrame() const { |
- return current_frame_number_ == last_frame_number_swap_requested_; |
-} |
- |
bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const { |
// These are all the cases where we normally cannot or do not want to draw |
// but, if needs_redraw_ is true and we do not draw to make forward progress, |
@@ -341,17 +310,14 @@ bool SchedulerStateMachine::ShouldDraw() const { |
if (PendingDrawsShouldBeAborted()) |
return active_tree_needs_first_draw_; |
- // Don't draw if we are waiting on the first commit after a surface. |
- if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE) |
- return false; |
- |
- // If a commit has occurred after the animate call, we need to call animate |
- // again before we should draw. |
- if (did_commit_after_animating_) |
+ // Do not draw too many times in a single frame. It's okay that we don't check |
+ // this before checking for aborted draws because aborted draws do not request |
+ // a swap. |
+ if (request_swap_funnel_) |
return false; |
- // After this line, we only want to send a swap request once per frame. |
- if (HasRequestedSwapThisFrame()) |
+ // Don't draw if we are waiting on the first commit after a surface. |
+ if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE) |
return false; |
// Do not queue too many swaps. |
@@ -390,12 +356,12 @@ bool SchedulerStateMachine::ShouldActivatePendingTree() const { |
} |
bool SchedulerStateMachine::ShouldAnimate() const { |
- // Don't animate if we are waiting on the first commit after a surface. |
- if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE) |
+ // Do not animate too many times in a single frame. |
+ if (animate_funnel_) |
return false; |
- // If a commit occurred after our last call, we need to do animation again. |
- if (HasAnimatedThisFrame() && !did_commit_after_animating_) |
+ // Don't animate if we are waiting on the first commit after a surface. |
+ if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE) |
return false; |
if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING && |
@@ -406,6 +372,10 @@ bool SchedulerStateMachine::ShouldAnimate() const { |
} |
bool SchedulerStateMachine::CouldSendBeginMainFrame() const { |
+ // Do not send begin main frame too many times in a single frame. |
+ if (send_begin_main_frame_funnel_) |
+ return false; |
+ |
if (!needs_commit_) |
return false; |
@@ -449,10 +419,6 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const { |
if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT) |
return true; |
- // After this point, we only start a commit once per frame. |
- if (HasSentBeginMainFrameThisFrame()) |
- return false; |
- |
// We shouldn't normally accept commits if there isn't an OutputSurface. |
if (!HasInitializedOutputSurface()) |
return false; |
@@ -461,7 +427,7 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const { |
// TODO(brianderson): Remove this restriction to improve throughput. |
bool just_swapped_in_deadline = |
begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE && |
- HasSwappedThisFrame(); |
+ perform_swap_funnel_; |
if (pending_swaps_ >= max_pending_swaps_ && !just_swapped_in_deadline) |
return false; |
@@ -538,9 +504,10 @@ void SchedulerStateMachine::UpdateState(Action action) { |
return; |
case ACTION_ANIMATE: |
+ DCHECK(!animate_funnel_); |
last_frame_number_animate_performed_ = current_frame_number_; |
+ animate_funnel_ = true; |
needs_animate_ = false; |
- did_commit_after_animating_ = false; |
// TODO(skyostil): Instead of assuming this, require the client to tell |
// us. |
SetNeedsRedraw(); |
@@ -550,8 +517,10 @@ void SchedulerStateMachine::UpdateState(Action action) { |
DCHECK(!has_pending_tree_ || |
settings_.main_frame_before_activation_enabled); |
DCHECK(visible_); |
+ DCHECK(!send_begin_main_frame_funnel_); |
commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_SENT; |
needs_commit_ = false; |
+ send_begin_main_frame_funnel_ = true; |
last_frame_number_begin_main_frame_sent_ = |
current_frame_number_; |
return; |
@@ -596,8 +565,8 @@ void SchedulerStateMachine::UpdateState(Action action) { |
void SchedulerStateMachine::UpdateStateOnCommit(bool commit_has_no_updates) { |
commit_count_++; |
- if (!commit_has_no_updates && HasAnimatedThisFrame()) |
- did_commit_after_animating_ = true; |
+ if (!commit_has_no_updates) |
+ animate_funnel_ = false; |
if (commit_has_no_updates || settings_.main_frame_before_activation_enabled) { |
commit_state_ = COMMIT_STATE_IDLE; |
@@ -645,6 +614,7 @@ void SchedulerStateMachine::UpdateStateOnCommit(bool commit_has_no_updates) { |
if (continuous_painting_) |
needs_commit_ = true; |
+ last_commit_had_no_updates_ = commit_has_no_updates; |
} |
void SchedulerStateMachine::UpdateStateOnActivation() { |
@@ -676,8 +646,11 @@ void SchedulerStateMachine::UpdateStateOnDraw(bool did_request_swap) { |
needs_redraw_ = false; |
active_tree_needs_first_draw_ = false; |
- if (did_request_swap) |
+ if (did_request_swap) { |
+ DCHECK(!request_swap_funnel_); |
+ request_swap_funnel_ = true; |
last_frame_number_swap_requested_ = current_frame_number_; |
+ } |
} |
void SchedulerStateMachine::UpdateStateOnPrepareTiles() { |
@@ -720,29 +693,6 @@ bool SchedulerStateMachine::BeginFrameNeeded() const { |
return BeginFrameNeededToAnimateOrDraw(); |
} |
-bool SchedulerStateMachine::ShouldSetNeedsBeginFrames( |
- bool frame_source_needs_begin_frames) const { |
- bool needs_begin_frame = BeginFrameNeeded(); |
- |
- // Never call SetNeedsBeginFrames if the frame source has the right value. |
- if (needs_begin_frame == frame_source_needs_begin_frames) |
- return false; |
- |
- // Always request the BeginFrame immediately if it's needed. |
- if (needs_begin_frame) |
- return true; |
- |
- // Stop requesting BeginFrames after a deadline. |
- if (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) |
- return true; |
- |
- // Stop requesting BeginFrames immediately when output surface is lost. |
- if (!HasInitializedOutputSurface()) |
- return true; |
- |
- return false; |
-} |
- |
bool SchedulerStateMachine::ShouldPollForAnticipatedDrawTriggers() const { |
// ShouldPollForAnticipatedDrawTriggers is what we use in place of |
// ProactiveBeginFrameWanted when we are using the synchronous |
@@ -815,18 +765,23 @@ bool SchedulerStateMachine::ProactiveBeginFrameWanted() const { |
// SetNeedsBeginFrame requests, which may propagate to the BeginImplFrame |
// provider and get sampled at an inopportune time, delaying the next |
// BeginImplFrame. |
- if (HasRequestedSwapThisFrame()) |
+ if (request_swap_funnel_) |
+ return true; |
+ |
+ // If the last commit was aborted because of early out (no updates), we should |
+ // still want a begin frame in case there is a commit coming again. |
+ if (last_commit_had_no_updates_) |
return true; |
return false; |
} |
-void SchedulerStateMachine::OnBeginImplFrame(const BeginFrameArgs& args) { |
+void SchedulerStateMachine::OnBeginImplFrame() { |
AdvanceCurrentFrameNumber(); |
- begin_impl_frame_args_ = args; |
DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_IDLE) |
<< AsValue()->ToString(); |
begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING; |
+ last_commit_had_no_updates_ = false; |
} |
void SchedulerStateMachine::OnBeginImplFrameDeadlinePending() { |
@@ -910,7 +865,7 @@ bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const { |
// If we just sent a BeginMainFrame and haven't hit the deadline yet, the main |
// thread is in a low latency mode. |
- if (HasSentBeginMainFrameThisFrame() && |
+ if (send_begin_main_frame_funnel_ && |
(begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING || |
begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)) |
return false; |
@@ -934,8 +889,8 @@ bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const { |
// Even if there's a new active tree to draw at the deadline or we've just |
// swapped it, it may have been triggered by a previous BeginImplFrame, in |
// which case the main thread is in a high latency mode. |
- return (active_tree_needs_first_draw_ || HasSwappedThisFrame()) && |
- !HasSentBeginMainFrameThisFrame(); |
+ return (active_tree_needs_first_draw_ || perform_swap_funnel_) && |
+ !send_begin_main_frame_funnel_; |
} |
// If the active tree needs its first draw in any other state, we know the |
@@ -976,7 +931,9 @@ void SchedulerStateMachine::SetMaxSwapsPending(int max) { |
void SchedulerStateMachine::DidSwapBuffers() { |
pending_swaps_++; |
DCHECK_LE(pending_swaps_, max_pending_swaps_); |
+ DCHECK(!perform_swap_funnel_); |
+ perform_swap_funnel_ = true; |
last_frame_number_swap_performed_ = current_frame_number_; |
} |