Commit 55ee3562 authored by sunnyps's avatar sunnyps Committed by Commit bot

cc: Do not use current frame number in state machine decisions.

This allows the scheduler to evolve to a state where it's able to
perform multiple actions of the same type in a given frame. One example
of this is webview where we can stop receiving BeginFrames but still
have to draw any number of times the system asks us to.

BUG=439275

Review URL: https://codereview.chromium.org/1002493006

Cr-Commit-Position: refs/heads/master@{#321625}
parent f71cc7bb
...@@ -26,6 +26,10 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) ...@@ -26,6 +26,10 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
last_frame_number_swap_performed_(-1), last_frame_number_swap_performed_(-1),
last_frame_number_swap_requested_(-1), last_frame_number_swap_requested_(-1),
last_frame_number_begin_main_frame_sent_(-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), prepare_tiles_funnel_(0),
consecutive_checkerboard_animations_(0), consecutive_checkerboard_animations_(0),
max_pending_swaps_(1), max_pending_swaps_(1),
...@@ -41,7 +45,6 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) ...@@ -41,7 +45,6 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
has_pending_tree_(false), has_pending_tree_(false),
pending_tree_is_ready_for_activation_(false), pending_tree_is_ready_for_activation_(false),
active_tree_needs_first_draw_(false), active_tree_needs_first_draw_(false),
did_commit_after_animating_(false),
did_create_and_initialize_first_output_surface_(false), did_create_and_initialize_first_output_surface_(false),
impl_latency_takes_priority_(false), impl_latency_takes_priority_(false),
skip_next_begin_main_frame_to_reduce_latency_(false), skip_next_begin_main_frame_to_reduce_latency_(false),
...@@ -171,7 +174,6 @@ void SchedulerStateMachine::AsValueInto( ...@@ -171,7 +174,6 @@ void SchedulerStateMachine::AsValueInto(
state->BeginDictionary("minor_state"); state->BeginDictionary("minor_state");
state->SetInteger("commit_count", commit_count_); state->SetInteger("commit_count", commit_count_);
state->SetInteger("current_frame_number", current_frame_number_); state->SetInteger("current_frame_number", current_frame_number_);
state->SetInteger("last_frame_number_animate_performed", state->SetInteger("last_frame_number_animate_performed",
last_frame_number_animate_performed_); last_frame_number_animate_performed_);
state->SetInteger("last_frame_number_swap_performed", state->SetInteger("last_frame_number_swap_performed",
...@@ -180,8 +182,12 @@ void SchedulerStateMachine::AsValueInto( ...@@ -180,8 +182,12 @@ void SchedulerStateMachine::AsValueInto(
last_frame_number_swap_requested_); last_frame_number_swap_requested_);
state->SetInteger("last_frame_number_begin_main_frame_sent", state->SetInteger("last_frame_number_begin_main_frame_sent",
last_frame_number_begin_main_frame_sent_); last_frame_number_begin_main_frame_sent_);
state->SetBoolean("funnel: animate_funnel", animate_funnel_);
state->SetInteger("prepare_tiles_funnel", prepare_tiles_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", state->SetInteger("consecutive_checkerboard_animations",
consecutive_checkerboard_animations_); consecutive_checkerboard_animations_);
state->SetInteger("max_pending_swaps_", max_pending_swaps_); state->SetInteger("max_pending_swaps_", max_pending_swaps_);
...@@ -198,7 +204,6 @@ void SchedulerStateMachine::AsValueInto( ...@@ -198,7 +204,6 @@ void SchedulerStateMachine::AsValueInto(
pending_tree_is_ready_for_activation_); pending_tree_is_ready_for_activation_);
state->SetBoolean("active_tree_needs_first_draw", state->SetBoolean("active_tree_needs_first_draw",
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", state->SetBoolean("did_create_and_initialize_first_output_surface",
did_create_and_initialize_first_output_surface_); did_create_and_initialize_first_output_surface_);
state->SetBoolean("impl_latency_takes_priority", state->SetBoolean("impl_latency_takes_priority",
...@@ -218,6 +223,11 @@ void SchedulerStateMachine::AsValueInto( ...@@ -218,6 +223,11 @@ void SchedulerStateMachine::AsValueInto(
void SchedulerStateMachine::AdvanceCurrentFrameNumber() { void SchedulerStateMachine::AdvanceCurrentFrameNumber() {
current_frame_number_++; current_frame_number_++;
animate_funnel_ = false;
perform_swap_funnel_ = false;
request_swap_funnel_ = false;
send_begin_main_frame_funnel_ = false;
// "Drain" the PrepareTiles funnel. // "Drain" the PrepareTiles funnel.
if (prepare_tiles_funnel_ > 0) if (prepare_tiles_funnel_ > 0)
prepare_tiles_funnel_--; prepare_tiles_funnel_--;
...@@ -227,23 +237,6 @@ void SchedulerStateMachine::AdvanceCurrentFrameNumber() { ...@@ -227,23 +237,6 @@ void SchedulerStateMachine::AdvanceCurrentFrameNumber() {
skip_next_begin_main_frame_to_reduce_latency_ = false; 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 { bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const {
// These are all the cases where we normally cannot or do not want to draw // 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, // but, if needs_redraw_ is true and we do not draw to make forward progress,
...@@ -316,17 +309,14 @@ bool SchedulerStateMachine::ShouldDraw() const { ...@@ -316,17 +309,14 @@ bool SchedulerStateMachine::ShouldDraw() const {
if (PendingDrawsShouldBeAborted()) if (PendingDrawsShouldBeAborted())
return active_tree_needs_first_draw_; return active_tree_needs_first_draw_;
// Don't draw if we are waiting on the first commit after a surface. // Do not draw too many times in a single frame. It's okay that we don't check
if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE) // this before checking for aborted draws because aborted draws do not request
return false; // a swap.
if (request_swap_funnel_)
// If a commit has occurred after the animate call, we need to call animate
// again before we should draw.
if (did_commit_after_animating_)
return false; return false;
// After this line, we only want to send a swap request once per frame. // Don't draw if we are waiting on the first commit after a surface.
if (HasRequestedSwapThisFrame()) if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE)
return false; return false;
// Do not queue too many swaps. // Do not queue too many swaps.
...@@ -365,12 +355,12 @@ bool SchedulerStateMachine::ShouldActivatePendingTree() const { ...@@ -365,12 +355,12 @@ bool SchedulerStateMachine::ShouldActivatePendingTree() const {
} }
bool SchedulerStateMachine::ShouldAnimate() const { bool SchedulerStateMachine::ShouldAnimate() const {
// Don't animate if we are waiting on the first commit after a surface. // Do not animate too many times in a single frame.
if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE) if (animate_funnel_)
return false; return false;
// If a commit occurred after our last call, we need to do animation again. // Don't animate if we are waiting on the first commit after a surface.
if (HasAnimatedThisFrame() && !did_commit_after_animating_) if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE)
return false; return false;
if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING && if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING &&
...@@ -381,6 +371,10 @@ bool SchedulerStateMachine::ShouldAnimate() const { ...@@ -381,6 +371,10 @@ bool SchedulerStateMachine::ShouldAnimate() const {
} }
bool SchedulerStateMachine::CouldSendBeginMainFrame() 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_) if (!needs_commit_)
return false; return false;
...@@ -424,10 +418,6 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const { ...@@ -424,10 +418,6 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT) if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT)
return true; 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. // We shouldn't normally accept commits if there isn't an OutputSurface.
if (!HasInitializedOutputSurface()) if (!HasInitializedOutputSurface())
return false; return false;
...@@ -436,7 +426,7 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const { ...@@ -436,7 +426,7 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
// TODO(brianderson): Remove this restriction to improve throughput. // TODO(brianderson): Remove this restriction to improve throughput.
bool just_swapped_in_deadline = bool just_swapped_in_deadline =
begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_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) if (pending_swaps_ >= max_pending_swaps_ && !just_swapped_in_deadline)
return false; return false;
...@@ -513,9 +503,10 @@ void SchedulerStateMachine::UpdateState(Action action) { ...@@ -513,9 +503,10 @@ void SchedulerStateMachine::UpdateState(Action action) {
return; return;
case ACTION_ANIMATE: case ACTION_ANIMATE:
DCHECK(!animate_funnel_);
last_frame_number_animate_performed_ = current_frame_number_; last_frame_number_animate_performed_ = current_frame_number_;
animate_funnel_ = true;
needs_animate_ = false; needs_animate_ = false;
did_commit_after_animating_ = false;
// TODO(skyostil): Instead of assuming this, require the client to tell // TODO(skyostil): Instead of assuming this, require the client to tell
// us. // us.
SetNeedsRedraw(); SetNeedsRedraw();
...@@ -525,8 +516,10 @@ void SchedulerStateMachine::UpdateState(Action action) { ...@@ -525,8 +516,10 @@ void SchedulerStateMachine::UpdateState(Action action) {
DCHECK(!has_pending_tree_ || DCHECK(!has_pending_tree_ ||
settings_.main_frame_before_activation_enabled); settings_.main_frame_before_activation_enabled);
DCHECK(visible_); DCHECK(visible_);
DCHECK(!send_begin_main_frame_funnel_);
commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_SENT; commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_SENT;
needs_commit_ = false; needs_commit_ = false;
send_begin_main_frame_funnel_ = true;
last_frame_number_begin_main_frame_sent_ = last_frame_number_begin_main_frame_sent_ =
current_frame_number_; current_frame_number_;
return; return;
...@@ -571,8 +564,8 @@ void SchedulerStateMachine::UpdateState(Action action) { ...@@ -571,8 +564,8 @@ void SchedulerStateMachine::UpdateState(Action action) {
void SchedulerStateMachine::UpdateStateOnCommit(bool commit_has_no_updates) { void SchedulerStateMachine::UpdateStateOnCommit(bool commit_has_no_updates) {
commit_count_++; commit_count_++;
if (!commit_has_no_updates && HasAnimatedThisFrame()) if (!commit_has_no_updates)
did_commit_after_animating_ = true; animate_funnel_ = false;
if (commit_has_no_updates || settings_.main_frame_before_activation_enabled) { if (commit_has_no_updates || settings_.main_frame_before_activation_enabled) {
commit_state_ = COMMIT_STATE_IDLE; commit_state_ = COMMIT_STATE_IDLE;
...@@ -651,8 +644,11 @@ void SchedulerStateMachine::UpdateStateOnDraw(bool did_request_swap) { ...@@ -651,8 +644,11 @@ void SchedulerStateMachine::UpdateStateOnDraw(bool did_request_swap) {
needs_redraw_ = false; needs_redraw_ = false;
active_tree_needs_first_draw_ = 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_; last_frame_number_swap_requested_ = current_frame_number_;
}
} }
void SchedulerStateMachine::UpdateStateOnPrepareTiles() { void SchedulerStateMachine::UpdateStateOnPrepareTiles() {
...@@ -767,7 +763,7 @@ bool SchedulerStateMachine::ProactiveBeginFrameWanted() const { ...@@ -767,7 +763,7 @@ bool SchedulerStateMachine::ProactiveBeginFrameWanted() const {
// SetNeedsBeginFrame requests, which may propagate to the BeginImplFrame // SetNeedsBeginFrame requests, which may propagate to the BeginImplFrame
// provider and get sampled at an inopportune time, delaying the next // provider and get sampled at an inopportune time, delaying the next
// BeginImplFrame. // BeginImplFrame.
if (HasRequestedSwapThisFrame()) if (request_swap_funnel_)
return true; return true;
return false; return false;
...@@ -861,7 +857,7 @@ bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const { ...@@ -861,7 +857,7 @@ bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const {
// If we just sent a BeginMainFrame and haven't hit the deadline yet, the main // If we just sent a BeginMainFrame and haven't hit the deadline yet, the main
// thread is in a low latency mode. // 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_BEGIN_FRAME_STARTING ||
begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)) begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME))
return false; return false;
...@@ -885,8 +881,8 @@ bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const { ...@@ -885,8 +881,8 @@ bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const {
// Even if there's a new active tree to draw at the deadline or we've just // 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 // swapped it, it may have been triggered by a previous BeginImplFrame, in
// which case the main thread is in a high latency mode. // which case the main thread is in a high latency mode.
return (active_tree_needs_first_draw_ || HasSwappedThisFrame()) && return (active_tree_needs_first_draw_ || perform_swap_funnel_) &&
!HasSentBeginMainFrameThisFrame(); !send_begin_main_frame_funnel_;
} }
// If the active tree needs its first draw in any other state, we know the // If the active tree needs its first draw in any other state, we know the
...@@ -927,7 +923,9 @@ void SchedulerStateMachine::SetMaxSwapsPending(int max) { ...@@ -927,7 +923,9 @@ void SchedulerStateMachine::SetMaxSwapsPending(int max) {
void SchedulerStateMachine::DidSwapBuffers() { void SchedulerStateMachine::DidSwapBuffers() {
pending_swaps_++; pending_swaps_++;
DCHECK_LE(pending_swaps_, max_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_; last_frame_number_swap_performed_ = current_frame_number_;
} }
......
...@@ -278,10 +278,6 @@ class CC_EXPORT SchedulerStateMachine { ...@@ -278,10 +278,6 @@ class CC_EXPORT SchedulerStateMachine {
bool ShouldPrepareTiles() const; bool ShouldPrepareTiles() const;
void AdvanceCurrentFrameNumber(); void AdvanceCurrentFrameNumber();
bool HasAnimatedThisFrame() const;
bool HasSentBeginMainFrameThisFrame() const;
bool HasRequestedSwapThisFrame() const;
bool HasSwappedThisFrame() const;
void UpdateStateOnCommit(bool commit_had_no_updates); void UpdateStateOnCommit(bool commit_had_no_updates);
void UpdateStateOnActivation(); void UpdateStateOnActivation();
...@@ -295,6 +291,7 @@ class CC_EXPORT SchedulerStateMachine { ...@@ -295,6 +291,7 @@ class CC_EXPORT SchedulerStateMachine {
CommitState commit_state_; CommitState commit_state_;
ForcedRedrawOnTimeoutState forced_redraw_state_; ForcedRedrawOnTimeoutState forced_redraw_state_;
// These are used for tracing only.
int commit_count_; int commit_count_;
int current_frame_number_; int current_frame_number_;
int last_frame_number_animate_performed_; int last_frame_number_animate_performed_;
...@@ -302,11 +299,18 @@ class CC_EXPORT SchedulerStateMachine { ...@@ -302,11 +299,18 @@ class CC_EXPORT SchedulerStateMachine {
int last_frame_number_swap_requested_; int last_frame_number_swap_requested_;
int last_frame_number_begin_main_frame_sent_; int last_frame_number_begin_main_frame_sent_;
// These are used to ensure that an action only happens once per frame,
// deadline, etc.
bool animate_funnel_;
bool perform_swap_funnel_;
bool request_swap_funnel_;
bool send_begin_main_frame_funnel_;
// prepare_tiles_funnel_ is "filled" each time PrepareTiles is called // prepare_tiles_funnel_ is "filled" each time PrepareTiles is called
// and "drained" on each BeginImplFrame. If the funnel gets too full, // and "drained" on each BeginImplFrame. If the funnel gets too full,
// we start throttling ACTION_PREPARE_TILES such that we average one // we start throttling ACTION_PREPARE_TILES such that we average one
// PrepareTiles per BeginImplFrame. // PrepareTiles per BeginImplFrame.
int prepare_tiles_funnel_; int prepare_tiles_funnel_;
int consecutive_checkerboard_animations_; int consecutive_checkerboard_animations_;
int max_pending_swaps_; int max_pending_swaps_;
int pending_swaps_; int pending_swaps_;
...@@ -321,7 +325,6 @@ class CC_EXPORT SchedulerStateMachine { ...@@ -321,7 +325,6 @@ class CC_EXPORT SchedulerStateMachine {
bool has_pending_tree_; bool has_pending_tree_;
bool pending_tree_is_ready_for_activation_; bool pending_tree_is_ready_for_activation_;
bool active_tree_needs_first_draw_; bool active_tree_needs_first_draw_;
bool did_commit_after_animating_;
bool did_create_and_initialize_first_output_surface_; bool did_create_and_initialize_first_output_surface_;
bool impl_latency_takes_priority_; bool impl_latency_takes_priority_;
bool skip_next_begin_main_frame_to_reduce_latency_; bool skip_next_begin_main_frame_to_reduce_latency_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment