| Index: cc/scheduler/scheduler_state_machine.cc
|
| diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
|
| index dc3fa3643aaa9096b92abf0955e45889149d4d71..81c54ab27ca4a58bca0c847544a3aca29f88f6de 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),
|
| @@ -48,7 +48,8 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
|
| skip_begin_main_frame_to_reduce_latency_(false),
|
| continuous_painting_(false),
|
| impl_latency_takes_priority_on_battery_(false),
|
| - children_need_begin_frames_(false) {
|
| + children_need_begin_frames_(false),
|
| + output_surface_did_request_draw_(false) {
|
| }
|
|
|
| const char* SchedulerStateMachine::OutputSurfaceStateToString(
|
| @@ -85,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:
|
| @@ -142,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 "???";
|
| @@ -270,6 +289,10 @@ 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,
|
| @@ -334,6 +357,12 @@ bool SchedulerStateMachine::ShouldBeginOutputSurfaceCreation() const {
|
| }
|
|
|
| bool SchedulerStateMachine::ShouldDraw() const {
|
| + // In the synchronous compositor mode, draws are initiated by the output
|
| + // surface only.
|
| + if (settings_.using_synchronous_renderer_compositor &&
|
| + !output_surface_did_request_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
|
| @@ -489,14 +518,30 @@ 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 excluding deadline.
|
| + if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING &&
|
| + begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
|
| + 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;
|
| @@ -516,6 +561,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;
|
| @@ -557,6 +604,9 @@ void SchedulerStateMachine::UpdateState(Action action) {
|
|
|
| case ACTION_DRAW_AND_SWAP_FORCED:
|
| case ACTION_DRAW_AND_SWAP_IF_POSSIBLE: {
|
| + // Synchronous compositor only draws when requested.
|
| + DCHECK_IMPLIES(settings_.using_synchronous_renderer_compositor,
|
| + output_surface_did_request_draw_);
|
| bool did_request_swap = true;
|
| UpdateStateOnDraw(did_request_swap);
|
| return;
|
| @@ -583,6 +633,10 @@ 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;
|
| }
|
| }
|
|
|
| @@ -668,6 +722,7 @@ void SchedulerStateMachine::UpdateStateOnDraw(bool did_request_swap) {
|
|
|
| needs_redraw_ = false;
|
| active_tree_needs_first_draw_ = false;
|
| + output_surface_did_request_draw_ = false;
|
|
|
| if (did_request_swap)
|
| last_frame_number_swap_requested_ = current_frame_number_;
|
| @@ -692,43 +747,9 @@ bool SchedulerStateMachine::BeginFrameNeededForChildren() const {
|
| }
|
|
|
| bool SchedulerStateMachine::BeginFrameNeeded() const {
|
| - 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();
|
| -}
|
| -
|
| -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;
|
| + return (BeginFrameNeededToAnimateOrDraw() ||
|
| + BeginFrameNeededForChildren() ||
|
| + ProactiveBeginFrameWanted());
|
| }
|
|
|
| void SchedulerStateMachine::SetChildrenNeedBeginFrames(
|
| @@ -822,8 +843,13 @@ void SchedulerStateMachine::OnBeginImplFrameIdle() {
|
|
|
| SchedulerStateMachine::BeginImplFrameDeadlineMode
|
| SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode() const {
|
| - if (ShouldTriggerBeginImplFrameDeadlineImmediately()) {
|
| - return BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE;
|
| + if (settings_.using_synchronous_renderer_compositor &&
|
| + output_surface_did_request_draw_) {
|
| + // If the synchronous compositor wants to draw now or if we know that the
|
| + // synchronous compositor won't draw trigger an immediate deadline.
|
| + 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.
|
| @@ -840,6 +866,14 @@ SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode() const {
|
| bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately()
|
| const {
|
| // TODO(brianderson): This should take into account multiple commit sources.
|
| +
|
| + // Set an immediate asynchronous deadline for the synchronous compositor.
|
| + // If the output surface was invalidated, then the synchronous compositor will
|
| + // cause the deadline to be rescheduled on OutputSurfaceDidRequestDraw.
|
| + // If the output surface was not invalidated (i.e. needs_redraw_ is false)
|
| + // then the deadline will pass but drawing will not happen.
|
| + if (settings_.using_synchronous_renderer_compositor)
|
| + return true;
|
|
|
| if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
|
| return false;
|
| @@ -920,21 +954,16 @@ 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; }
|
|
|
| void SchedulerStateMachine::SetNeedsRedraw() { needs_redraw_ = true; }
|
|
|
| +void SchedulerStateMachine::OutputSurfaceDidRequestDraw() {
|
| + output_surface_did_request_draw_ = true;
|
| +}
|
| +
|
| void SchedulerStateMachine::SetNeedsAnimate() {
|
| needs_animate_ = true;
|
| }
|
|
|