Index: cc/scheduler/scheduler_state_machine.cc |
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc |
index 4e6509f527ddc35ac7be8b8355b85111f3cbbfa7..9ee7933f50d507653ef1e29d8fe23b664e48b40b 100644 |
--- a/cc/scheduler/scheduler_state_machine.cc |
+++ b/cc/scheduler/scheduler_state_machine.cc |
@@ -26,6 +26,7 @@ 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), |
+ last_frame_number_invalidate_output_surface_performed_(-1), |
prepare_tiles_funnel_(0), |
consecutive_checkerboard_animations_(0), |
max_pending_swaps_(1), |
@@ -34,7 +35,6 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) |
needs_animate_(false), |
needs_prepare_tiles_(false), |
needs_commit_(false), |
- inside_poll_for_anticipated_draw_triggers_(false), |
visible_(false), |
can_start_(false), |
can_draw_(false), |
@@ -86,6 +86,22 @@ const char* SchedulerStateMachine::BeginImplFrameStateToString( |
return "???"; |
} |
+const char* SchedulerStateMachine::BeginImplFrameDeadlineModeToString( |
+ BeginImplFrameDeadlineMode mode) { |
+ switch (mode) { |
+ case BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE_SYNCHRONOUS: |
+ return "BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE_SYNCHRONOUS"; |
+ case BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE_ASYNCHRONOUS: |
+ return "BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE_ASYNCHRONOUS"; |
+ case BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR: |
+ return "BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR"; |
+ case BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE: |
+ return "BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE"; |
+ } |
+ NOTREACHED(); |
+ return "???"; |
+} |
+ |
const char* SchedulerStateMachine::CommitStateToString(CommitState state) { |
switch (state) { |
case COMMIT_STATE_IDLE: |
@@ -143,6 +159,8 @@ const char* SchedulerStateMachine::ActionToString(Action action) { |
return "ACTION_BEGIN_OUTPUT_SURFACE_CREATION"; |
case ACTION_PREPARE_TILES: |
return "ACTION_PREPARE_TILES"; |
+ case ACTION_INVALIDATE_OUTPUT_SURFACE: |
+ return "ACTION_INVALIDATE_OUTPUT_SURFACE"; |
} |
NOTREACHED(); |
return "???"; |
@@ -243,7 +261,7 @@ void SchedulerStateMachine::AsValueInto(base::trace_event::TracedValue* state, |
state->EndDictionary(); |
} |
-void SchedulerStateMachine::AdvanceCurrentFrameNumber() { |
+void SchedulerStateMachine::AdvanceFrame() { |
current_frame_number_++; |
// "Drain" the PrepareTiles funnel. |
@@ -272,6 +290,11 @@ bool SchedulerStateMachine::HasRequestedSwapThisFrame() const { |
return current_frame_number_ == last_frame_number_swap_requested_; |
} |
+bool SchedulerStateMachine::HasInvalidatedOutputSurfaceThisFrame() const { |
+ return current_frame_number_ == |
+ last_frame_number_invalidate_output_surface_performed_; |
+} |
+ |
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, |
@@ -336,6 +359,11 @@ bool SchedulerStateMachine::ShouldBeginOutputSurfaceCreation() const { |
} |
bool SchedulerStateMachine::ShouldDraw() const { |
+ // In the synchronous compositor mode, draw only when asked to. |
+ if (settings_.using_synchronous_renderer_compositor && |
+ begin_impl_frame_args_.type != BeginFrameArgs::SYNCHRONOUS_DRAW) |
+ return false; |
+ |
// If we need to abort draws, we should do so ASAP since the draw could |
// be blocking other important actions (like output surface initialization), |
// from occuring. If we are waiting for the first draw, then perfom the |
@@ -499,14 +527,29 @@ bool SchedulerStateMachine::ShouldPrepareTiles() const { |
return false; |
// Limiting to once per-frame is not enough, since we only want to |
- // prepare tiles _after_ draws. Polling for draw triggers and |
- // begin-frame are mutually exclusive, so we limit to these two cases. |
- if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE && |
- !inside_poll_for_anticipated_draw_triggers_) |
+ // prepare tiles _after_ draws. |
+ if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) |
return false; |
+ |
return needs_prepare_tiles_; |
} |
+bool SchedulerStateMachine::ShouldInvalidateOutputSurface() const { |
+ // Only the synchronous compositor requires invalidations. |
+ if (!settings_.using_synchronous_renderer_compositor) |
+ return false; |
+ |
+ // Invalidations are only performed inside a BeginFrame deadline. |
+ if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) |
+ return false; |
+ |
+ // Invalidate the output surface only once per frame. |
+ if (HasInvalidatedOutputSurfaceThisFrame()) |
+ return false; |
+ |
+ return needs_redraw_; |
+} |
+ |
SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { |
if (ShouldActivatePendingTree()) |
return ACTION_ACTIVATE_SYNC_TREE; |
@@ -526,6 +569,8 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const { |
return ACTION_PREPARE_TILES; |
if (ShouldSendBeginMainFrame()) |
return ACTION_SEND_BEGIN_MAIN_FRAME; |
+ if (ShouldInvalidateOutputSurface()) |
+ return ACTION_INVALIDATE_OUTPUT_SURFACE; |
if (ShouldBeginOutputSurfaceCreation()) |
return ACTION_BEGIN_OUTPUT_SURFACE_CREATION; |
return ACTION_NONE; |
@@ -593,6 +638,11 @@ void SchedulerStateMachine::UpdateState(Action action) { |
case ACTION_PREPARE_TILES: |
UpdateStateOnPrepareTiles(); |
return; |
+ |
+ case ACTION_INVALIDATE_OUTPUT_SURFACE: |
+ last_frame_number_invalidate_output_surface_performed_ = |
+ current_frame_number_; |
+ return; |
} |
} |
@@ -706,21 +756,8 @@ bool SchedulerStateMachine::BeginFrameNeeded() const { |
// TODO(brianderson): Support output surface creation inside a BeginFrame. |
if (!HasInitializedOutputSurface()) |
return false; |
- |
- if (SupportsProactiveBeginFrame()) { |
- return (BeginFrameNeededToAnimateOrDraw() || |
- BeginFrameNeededForChildren() || |
- ProactiveBeginFrameWanted()); |
- } |
- |
- // Proactive BeginFrames are bad for the synchronous compositor because we |
- // have to draw when we get the BeginFrame and could end up drawing many |
- // duplicate frames if our new frame isn't ready in time. |
- // To poll for state with the synchronous compositor without having to draw, |
- // we rely on ShouldPollForAnticipatedDrawTriggers instead. |
- // Synchronous compositor doesn't have a browser. |
- DCHECK(!children_need_begin_frames_); |
- return BeginFrameNeededToAnimateOrDraw(); |
+ return (BeginFrameNeededToAnimateOrDraw() || BeginFrameNeededForChildren() || |
+ ProactiveBeginFrameWanted()); |
} |
bool SchedulerStateMachine::ShouldSetNeedsBeginFrames( |
@@ -746,29 +783,6 @@ bool SchedulerStateMachine::ShouldSetNeedsBeginFrames( |
return false; |
} |
-bool SchedulerStateMachine::ShouldPollForAnticipatedDrawTriggers() const { |
- // ShouldPollForAnticipatedDrawTriggers is what we use in place of |
- // ProactiveBeginFrameWanted when we are using the synchronous |
- // compositor. |
- if (!SupportsProactiveBeginFrame()) { |
- return !BeginFrameNeededToAnimateOrDraw() && ProactiveBeginFrameWanted(); |
- } |
- |
- // Non synchronous compositors should rely on |
- // ProactiveBeginFrameWanted to poll for state instead. |
- return false; |
-} |
- |
-// Note: If SupportsProactiveBeginFrame is false, the scheduler should poll |
-// for changes in it's draw state so it can request a BeginFrame when it's |
-// actually ready. |
-bool SchedulerStateMachine::SupportsProactiveBeginFrame() const { |
- // It is undesirable to proactively request BeginFrames if we are |
- // using a synchronous compositor because we *must* draw for every |
- // BeginFrame, which could cause duplicate draws. |
- return !settings_.using_synchronous_renderer_compositor; |
-} |
- |
void SchedulerStateMachine::SetChildrenNeedBeginFrames( |
bool children_need_begin_frames) { |
DCHECK(settings_.forward_begin_frames_to_children); |
@@ -826,8 +840,13 @@ bool SchedulerStateMachine::ProactiveBeginFrameWanted() const { |
} |
void SchedulerStateMachine::OnBeginImplFrame(const BeginFrameArgs& args) { |
- AdvanceCurrentFrameNumber(); |
begin_impl_frame_args_ = args; |
+ |
+ // Advance frame for synchronous compositor on SYNCHRONOUS_ANIMATE only. |
+ if (!settings_.using_synchronous_renderer_compositor || |
+ begin_impl_frame_args_.type == BeginFrameArgs::SYNCHRONOUS_ANIMATE) |
+ AdvanceFrame(); |
+ |
DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_IDLE) |
<< AsValue()->ToString(); |
begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING; |
@@ -854,8 +873,11 @@ void SchedulerStateMachine::OnBeginImplFrameIdle() { |
SchedulerStateMachine::BeginImplFrameDeadlineMode |
SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode() const { |
- if (ShouldTriggerBeginImplFrameDeadlineImmediately()) { |
- return BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE; |
+ if (settings_.using_synchronous_renderer_compositor) { |
+ // If the synchronous compositor wants to draw now. |
+ return BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE_SYNCHRONOUS; |
+ } else if (ShouldTriggerBeginImplFrameDeadlineImmediately()) { |
+ return BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE_ASYNCHRONOUS; |
} else if (needs_redraw_ && pending_swaps_ < max_pending_swaps_) { |
// We have an animation or fast input path on the impl thread that wants |
// to draw, so don't wait too long for a new active tree. |
@@ -872,7 +894,6 @@ SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode() const { |
bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately() |
const { |
// TODO(brianderson): This should take into account multiple commit sources. |
- |
if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME) |
return false; |
@@ -952,15 +973,6 @@ bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const { |
return active_tree_needs_first_draw_; |
} |
-void SchedulerStateMachine::DidEnterPollForAnticipatedDrawTriggers() { |
- AdvanceCurrentFrameNumber(); |
- inside_poll_for_anticipated_draw_triggers_ = true; |
-} |
- |
-void SchedulerStateMachine::DidLeavePollForAnticipatedDrawTriggers() { |
- inside_poll_for_anticipated_draw_triggers_ = false; |
-} |
- |
void SchedulerStateMachine::SetVisible(bool visible) { visible_ = visible; } |
void SchedulerStateMachine::SetCanDraw(bool can_draw) { can_draw_ = can_draw; } |