| Index: cc/scheduler/scheduler_state_machine.cc
|
| diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
|
| index 5881f2a72340802d180d182fdd7faa4b5a014332..33e33c4544e74076b8d0a963b74d619e4e51c317 100644
|
| --- a/cc/scheduler/scheduler_state_machine.cc
|
| +++ b/cc/scheduler/scheduler_state_machine.cc
|
| @@ -18,7 +18,8 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
|
| output_surface_state_(OUTPUT_SURFACE_LOST),
|
| begin_impl_frame_state_(BEGIN_IMPL_FRAME_STATE_IDLE),
|
| commit_state_(COMMIT_STATE_IDLE),
|
| - forced_redraw_state_(FORCED_REDRAW_STATE_IDLE),
|
| + prepare_tiles_approach_(PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY),
|
| + prepare_tiles_reason_(PREPARE_TILES_NOT_NEEDED),
|
| commit_count_(0),
|
| current_frame_number_(0),
|
| last_frame_number_animate_performed_(-1),
|
| @@ -31,18 +32,20 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
|
| send_begin_main_frame_funnel_(false),
|
| invalidate_output_surface_funnel_(false),
|
| prepare_tiles_funnel_(0),
|
| - consecutive_checkerboard_animations_(0),
|
| max_pending_swaps_(1),
|
| pending_swaps_(0),
|
| needs_redraw_(false),
|
| + last_draw_result_(DRAW_SUCCESS),
|
| + retry_begin_impl_frame_(false),
|
| + retry_begin_impl_frame_deadline_(false),
|
| needs_animate_(false),
|
| - needs_prepare_tiles_(false),
|
| needs_commit_(false),
|
| visible_(false),
|
| can_start_(false),
|
| can_draw_(false),
|
| has_pending_tree_(false),
|
| pending_tree_is_ready_for_activation_(false),
|
| + requires_high_res_to_draw_(false),
|
| active_tree_needs_first_draw_(false),
|
| did_create_and_initialize_first_output_surface_(false),
|
| impl_latency_takes_priority_(false),
|
| @@ -103,6 +106,8 @@ const char* SchedulerStateMachine::BeginImplFrameDeadlineModeToString(
|
| return "BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR";
|
| case BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE:
|
| return "BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE";
|
| + case BEGIN_IMPL_FRAME_DEADLINE_MODE_TRY_TO_AVOID_CHECKERBOARD:
|
| + return "BEGIN_IMPL_FRAME_DEADLINE_MODE_TRY_TO_AVOID_CHECKERBOARD";
|
| case BEGIN_IMPL_FRAME_DEADLINE_MODE_BLOCKED_ON_READY_TO_DRAW:
|
| return "BEGIN_IMPL_FRAME_DEADLINE_MODE_BLOCKED_ON_READY_TO_DRAW";
|
| }
|
| @@ -129,17 +134,31 @@ const char* SchedulerStateMachine::CommitStateToString(CommitState state) {
|
| return "???";
|
| }
|
|
|
| -const char* SchedulerStateMachine::ForcedRedrawOnTimeoutStateToString(
|
| - ForcedRedrawOnTimeoutState state) {
|
| - switch (state) {
|
| - case FORCED_REDRAW_STATE_IDLE:
|
| - return "FORCED_REDRAW_STATE_IDLE";
|
| - case FORCED_REDRAW_STATE_WAITING_FOR_COMMIT:
|
| - return "FORCED_REDRAW_STATE_WAITING_FOR_COMMIT";
|
| - case FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION:
|
| - return "FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION";
|
| - case FORCED_REDRAW_STATE_WAITING_FOR_DRAW:
|
| - return "FORCED_REDRAW_STATE_WAITING_FOR_DRAW";
|
| +const char* SchedulerStateMachine::PrepareTilesApproachToString(
|
| + PrepareTilesApproach approach) {
|
| + switch (approach) {
|
| + case PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY:
|
| + return "PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY";
|
| + case PREPARE_TILES_APPROACH_ACCURATE_ACTIVE_WORK:
|
| + return "PREPARE_TILES_APPROACH_ACCURATE_ACTIVE_WORK";
|
| + }
|
| + NOTREACHED();
|
| + return "???";
|
| +}
|
| +
|
| +const char* SchedulerStateMachine::PrepareTilesReasonToString(
|
| + PrepareTilesReason reason) {
|
| + switch (reason) {
|
| + case PREPARE_TILES_NOT_NEEDED:
|
| + return "PREPARE_TILES_NOT_NEEDED";
|
| + case PREPARE_TILES_REQUESTED:
|
| + return "PREPARE_TILES_REQUESTED";
|
| + case PREPARE_TILES_NEEDED_FOR_COMMIT:
|
| + return "PREPARE_TILES_NEEDED_FOR_COMMIT";
|
| + case PREPARE_TILES_NEEDED_FOR_ABORTED_DRAW:
|
| + return "PREPARE_TILES_NEEDED_FOR_ABORTED_DRAW";
|
| + case PREPARE_TILES_NEEDED_TO_EVICT_TILES:
|
| + return "PREPARE_TILES_NEEDED_TO_EVICT_TILES";
|
| }
|
| NOTREACHED();
|
| return "???";
|
| @@ -189,10 +208,12 @@ void SchedulerStateMachine::AsValueInto(
|
| state->SetString("begin_impl_frame_state",
|
| BeginImplFrameStateToString(begin_impl_frame_state_));
|
| state->SetString("commit_state", CommitStateToString(commit_state_));
|
| - state->SetString("output_surface_state_",
|
| + state->SetString("prepare_tiles_approach",
|
| + PrepareTilesApproachToString(prepare_tiles_approach_));
|
| + state->SetString("prepare_tiles_reason",
|
| + PrepareTilesReasonToString(prepare_tiles_reason_));
|
| + state->SetString("output_surface_state",
|
| OutputSurfaceStateToString(output_surface_state_));
|
| - state->SetString("forced_redraw_state",
|
| - ForcedRedrawOnTimeoutStateToString(forced_redraw_state_));
|
| state->EndDictionary();
|
|
|
| state->BeginDictionary("minor_state");
|
| @@ -213,13 +234,10 @@ void SchedulerStateMachine::AsValueInto(
|
| state->SetInteger("funnel: prepare_tiles_funnel", prepare_tiles_funnel_);
|
| state->SetBoolean("funnel: invalidate_output_surface_funnel",
|
| invalidate_output_surface_funnel_);
|
| - state->SetInteger("consecutive_checkerboard_animations",
|
| - consecutive_checkerboard_animations_);
|
| state->SetInteger("max_pending_swaps_", max_pending_swaps_);
|
| state->SetInteger("pending_swaps_", pending_swaps_);
|
| state->SetBoolean("needs_redraw", needs_redraw_);
|
| state->SetBoolean("needs_animate_", needs_animate_);
|
| - state->SetBoolean("needs_prepare_tiles", needs_prepare_tiles_);
|
| state->SetBoolean("needs_commit", needs_commit_);
|
| state->SetBoolean("visible", visible_);
|
| state->SetBoolean("can_start", can_start_);
|
| @@ -344,10 +362,6 @@ bool SchedulerStateMachine::ShouldDraw() const {
|
| if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
|
| return false;
|
|
|
| - // Only handle forced redraws due to timeouts on the regular deadline.
|
| - if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
|
| - return true;
|
| -
|
| return needs_redraw_;
|
| }
|
|
|
| @@ -445,14 +459,6 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
|
| BeginFrameNeeded())
|
| return false;
|
|
|
| - // We need a new commit for the forced redraw. This honors the
|
| - // single commit per interval because the result will be swapped to screen.
|
| - // TODO(brianderson): Remove this or move it below the
|
| - // SendingBeginMainFrameMightCauseDeadlock check since we want to avoid
|
| - // ever returning true from this method if we might cause deadlock.
|
| - if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT)
|
| - return true;
|
| -
|
| // We shouldn't normally accept commits if there isn't an OutputSurface.
|
| if (!HasInitializedOutputSurface())
|
| return false;
|
| @@ -500,18 +506,36 @@ bool SchedulerStateMachine::ShouldCommit() const {
|
| }
|
|
|
| bool SchedulerStateMachine::ShouldPrepareTiles() const {
|
| - // PrepareTiles only really needs to be called immediately after commit
|
| - // and then periodically after that. Use a funnel to make sure we average
|
| - // one PrepareTiles per BeginImplFrame in the long run.
|
| - if (prepare_tiles_funnel_ > 0)
|
| - return false;
|
| + // Handle the clear cut cases.
|
| + switch (prepare_tiles_reason_) {
|
| + case PREPARE_TILES_NOT_NEEDED:
|
| + return false;
|
| + case PREPARE_TILES_NEEDED_FOR_COMMIT:
|
| + case PREPARE_TILES_NEEDED_FOR_ABORTED_DRAW:
|
| + case PREPARE_TILES_NEEDED_TO_EVICT_TILES:
|
| + return true;
|
| + case PREPARE_TILES_REQUESTED:
|
| + break;
|
| + }
|
|
|
| - // Limiting to once per-frame is not enough, since we only want to
|
| - // prepare tiles _after_ draws.
|
| - if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
|
| - return false;
|
| + switch (prepare_tiles_approach_) {
|
| + case PREPARE_TILES_APPROACH_ACCURATE_ACTIVE_WORK:
|
| + return begin_impl_frame_state_ ==
|
| + BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING;
|
| + case PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY:
|
| + break;
|
| + }
|
| +
|
| + DCHECK_EQ(PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY, prepare_tiles_approach_);
|
| + DCHECK_EQ(PREPARE_TILES_REQUESTED, prepare_tiles_reason_);
|
|
|
| - return needs_prepare_tiles_;
|
| + // Only PrepareTiles after a draw if we haven't already PreparedTiles this
|
| + // frame. This takes PrepareTiles out of the critical path, but wil make the
|
| + // NotifyReadyToDraw and NotifyReadyToActivate signals liars.
|
| + bool did_not_prepare_tiles_at_end_of_frame =
|
| + prepare_tiles_funnel_ == 0 &&
|
| + begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE;
|
| + return did_not_prepare_tiles_at_end_of_frame;
|
| }
|
|
|
| bool SchedulerStateMachine::ShouldInvalidateOutputSurface() const {
|
| @@ -527,10 +551,11 @@ bool SchedulerStateMachine::ShouldInvalidateOutputSurface() const {
|
| if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING)
|
| return false;
|
|
|
| + // TODO(brianderson): Figure out what to do with this.
|
| // TODO(sunnyps): needs_prepare_tiles_ is needed here because PrepareTiles is
|
| // called only inside the deadline / draw phase. We could remove this if we
|
| // allowed PrepareTiles to happen in OnBeginImplFrame.
|
| - return needs_redraw_ || needs_prepare_tiles_;
|
| + return needs_redraw_ || PrepareTilesPending();
|
| }
|
|
|
| SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
|
| @@ -543,10 +568,12 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
|
| if (ShouldDraw()) {
|
| if (PendingDrawsShouldBeAborted())
|
| return ACTION_DRAW_AND_SWAP_ABORT;
|
| - else if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
|
| - return ACTION_DRAW_AND_SWAP_FORCED;
|
| - else
|
| + else if (requires_high_res_to_draw_ ||
|
| + prepare_tiles_approach_ ==
|
| + PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY)
|
| return ACTION_DRAW_AND_SWAP_IF_POSSIBLE;
|
| + else
|
| + return ACTION_DRAW_AND_SWAP_FORCED;
|
| }
|
| if (ShouldPrepareTiles())
|
| return ACTION_PREPARE_TILES;
|
| @@ -559,57 +586,91 @@ SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
|
| return ACTION_NONE;
|
| }
|
|
|
| -void SchedulerStateMachine::UpdateState(Action action) {
|
| +void SchedulerStateMachine::WillAction(Action action) {
|
| switch (action) {
|
| case ACTION_NONE:
|
| return;
|
|
|
| + case ACTION_COMMIT:
|
| + WillCommit();
|
| + return;
|
| +
|
| case ACTION_ACTIVATE_SYNC_TREE:
|
| - UpdateStateOnActivation();
|
| + WillActivateSyncTree();
|
| return;
|
|
|
| case ACTION_ANIMATE:
|
| - UpdateStateOnAnimate();
|
| + WillAnimate();
|
| return;
|
|
|
| case ACTION_SEND_BEGIN_MAIN_FRAME:
|
| - UpdateStateOnSendBeginMainFrame();
|
| + WillSendBeginMainFrame();
|
| + return;
|
| +
|
| + case ACTION_DRAW_AND_SWAP_FORCED:
|
| + case ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
|
| + case ACTION_DRAW_AND_SWAP_ABORT:
|
| + return;
|
| +
|
| + case ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
|
| + WillBeginOutputSurfaceCreation();
|
| + return;
|
| +
|
| + case ACTION_PREPARE_TILES:
|
| + return;
|
| +
|
| + case ACTION_INVALIDATE_OUTPUT_SURFACE:
|
| + WillInvalidateOutputSurface();
|
| + return;
|
| + }
|
| +}
|
| +
|
| +void SchedulerStateMachine::DidAction(Action action) {
|
| + switch (action) {
|
| + case ACTION_NONE:
|
| return;
|
|
|
| case ACTION_COMMIT: {
|
| bool commit_has_no_updates = false;
|
| - UpdateStateOnCommit(commit_has_no_updates);
|
| + DidCommit(commit_has_no_updates);
|
| return;
|
| }
|
|
|
| + case ACTION_ACTIVATE_SYNC_TREE:
|
| + return;
|
| +
|
| + case ACTION_ANIMATE:
|
| + return;
|
| +
|
| + case ACTION_SEND_BEGIN_MAIN_FRAME:
|
| + return;
|
| +
|
| case ACTION_DRAW_AND_SWAP_FORCED:
|
| case ACTION_DRAW_AND_SWAP_IF_POSSIBLE: {
|
| bool did_request_swap = true;
|
| - UpdateStateOnDraw(did_request_swap);
|
| + DidDraw(did_request_swap);
|
| return;
|
| }
|
|
|
| case ACTION_DRAW_AND_SWAP_ABORT: {
|
| bool did_request_swap = false;
|
| - UpdateStateOnDraw(did_request_swap);
|
| + DidDraw(did_request_swap);
|
| return;
|
| }
|
|
|
| case ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
|
| - UpdateStateOnBeginOutputSurfaceCreation();
|
| return;
|
|
|
| case ACTION_PREPARE_TILES:
|
| - UpdateStateOnPrepareTiles();
|
| + DidPrepareTiles();
|
| return;
|
|
|
| case ACTION_INVALIDATE_OUTPUT_SURFACE:
|
| - UpdateStateOnInvalidateOutputSurface();
|
| return;
|
| }
|
| }
|
|
|
| -void SchedulerStateMachine::UpdateStateOnAnimate() {
|
| +void SchedulerStateMachine::WillAnimate() {
|
| DCHECK(!animate_funnel_);
|
| last_frame_number_animate_performed_ = current_frame_number_;
|
| animate_funnel_ = true;
|
| @@ -618,7 +679,7 @@ void SchedulerStateMachine::UpdateStateOnAnimate() {
|
| SetNeedsRedraw();
|
| }
|
|
|
| -void SchedulerStateMachine::UpdateStateOnSendBeginMainFrame() {
|
| +void SchedulerStateMachine::WillSendBeginMainFrame() {
|
| DCHECK(!has_pending_tree_ || settings_.main_frame_before_activation_enabled);
|
| DCHECK(visible_);
|
| DCHECK(!send_begin_main_frame_funnel_);
|
| @@ -628,7 +689,13 @@ void SchedulerStateMachine::UpdateStateOnSendBeginMainFrame() {
|
| last_frame_number_begin_main_frame_sent_ = current_frame_number_;
|
| }
|
|
|
| -void SchedulerStateMachine::UpdateStateOnCommit(bool commit_has_no_updates) {
|
| +void SchedulerStateMachine::WillCommit() {
|
| + // The commit may set this synchronously if the new pending tree is
|
| + // ready for activation immediately.
|
| + pending_tree_is_ready_for_activation_ = false;
|
| +}
|
| +
|
| +void SchedulerStateMachine::DidCommit(bool commit_has_no_updates) {
|
| commit_count_++;
|
|
|
| // Animate after commit even if we've already animated.
|
| @@ -649,13 +716,6 @@ void SchedulerStateMachine::UpdateStateOnCommit(bool commit_has_no_updates) {
|
| // mostly as if we are not impl-side-painting since there is no pending tree.
|
| has_pending_tree_ = settings_.impl_side_painting && !commit_has_no_updates;
|
|
|
| - // Update state related to forced draws.
|
| - if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT) {
|
| - forced_redraw_state_ = has_pending_tree_
|
| - ? FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION
|
| - : FORCED_REDRAW_STATE_WAITING_FOR_DRAW;
|
| - }
|
| -
|
| // Update the output surface state.
|
| DCHECK_NE(output_surface_state_, OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION);
|
| if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT) {
|
| @@ -667,24 +727,19 @@ void SchedulerStateMachine::UpdateStateOnCommit(bool commit_has_no_updates) {
|
| }
|
| }
|
|
|
| - // Update state if we have a new active tree to draw, or if the active tree
|
| - // was unchanged but we need to do a forced draw.
|
| - if (!has_pending_tree_ &&
|
| - (!commit_has_no_updates ||
|
| - forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)) {
|
| + // Update state if we have a new active tree to draw.
|
| + if (!has_pending_tree_) {
|
| needs_redraw_ = true;
|
| active_tree_needs_first_draw_ = true;
|
| }
|
|
|
| // This post-commit work is common to both completed and aborted commits.
|
| - pending_tree_is_ready_for_activation_ = false;
|
| -
|
| if (continuous_painting_)
|
| needs_commit_ = true;
|
| last_commit_had_no_updates_ = commit_has_no_updates;
|
| }
|
|
|
| -void SchedulerStateMachine::UpdateStateOnActivation() {
|
| +void SchedulerStateMachine::WillActivateSyncTree() {
|
| if (commit_state_ == COMMIT_STATE_WAITING_FOR_ACTIVATION) {
|
| commit_state_ = settings_.main_thread_should_always_be_low_latency
|
| ? COMMIT_STATE_WAITING_FOR_DRAW
|
| @@ -694,19 +749,13 @@ void SchedulerStateMachine::UpdateStateOnActivation() {
|
| if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION)
|
| output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
|
|
|
| - if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION)
|
| - forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_DRAW;
|
| -
|
| has_pending_tree_ = false;
|
| pending_tree_is_ready_for_activation_ = false;
|
| active_tree_needs_first_draw_ = true;
|
| needs_redraw_ = true;
|
| }
|
|
|
| -void SchedulerStateMachine::UpdateStateOnDraw(bool did_request_swap) {
|
| - if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
|
| - forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE;
|
| -
|
| +void SchedulerStateMachine::DidDraw(bool did_request_swap) {
|
| if (commit_state_ == COMMIT_STATE_WAITING_FOR_DRAW)
|
| commit_state_ = COMMIT_STATE_IDLE;
|
|
|
| @@ -719,13 +768,68 @@ void SchedulerStateMachine::UpdateStateOnDraw(bool did_request_swap) {
|
| did_request_swap_in_last_frame_ = true;
|
| last_frame_number_swap_requested_ = current_frame_number_;
|
| }
|
| +
|
| + switch (last_draw_result_) {
|
| + case INVALID_RESULT:
|
| + NOTREACHED() << "Uninitialized DrawResult.";
|
| + break;
|
| +
|
| + case DRAW_ABORTED_CANT_DRAW:
|
| + case DRAW_ABORTED_CONTEXT_LOST:
|
| + NOTREACHED() << "Invalid return value from DrawAndSwapIfPossible:"
|
| + << last_draw_result_;
|
| + break;
|
| +
|
| + case DRAW_SUCCESS:
|
| + break;
|
| +
|
| + case DRAW_ABORTED_MISSING_RASTER_OUTPUT_HIGH_RES:
|
| + case DRAW_ABORTED_MISSING_RASTER_OUTPUT_ANY_RES:
|
| + prepare_tiles_reason_ = PREPARE_TILES_NEEDED_FOR_ABORTED_DRAW;
|
| + if (prepare_tiles_approach_ ==
|
| + PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY) {
|
| + prepare_tiles_approach_ = PREPARE_TILES_APPROACH_ACCURATE_ACTIVE_WORK;
|
| + }
|
| + retry_begin_impl_frame_deadline_ = true;
|
| + needs_redraw_ = true;
|
| + break;
|
| +
|
| + case DRAW_ABORTED_MISSING_RASTER_SOURCE:
|
| + prepare_tiles_reason_ = PREPARE_TILES_NEEDED_FOR_ABORTED_DRAW;
|
| + if (prepare_tiles_approach_ ==
|
| + PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY) {
|
| + prepare_tiles_approach_ = PREPARE_TILES_APPROACH_ACCURATE_ACTIVE_WORK;
|
| + }
|
| +
|
| + if (CommitPending() || has_pending_tree_) {
|
| + // The new active tree in flight might have an updated raster source,
|
| + // so wait and see.
|
| + retry_begin_impl_frame_deadline_ = true;
|
| + } else {
|
| + // We need a new active tree to get an updated raster source.
|
| + needs_commit_ = true;
|
| + retry_begin_impl_frame_ = true;
|
| + }
|
| +
|
| + // This is one of the few cases where we actively avoid drawing a commit.
|
| + // Skipping draw of the commit can be better than a flash of checkerboard.
|
| + active_tree_needs_first_draw_ = false;
|
| + break;
|
| + }
|
| }
|
|
|
| -void SchedulerStateMachine::UpdateStateOnPrepareTiles() {
|
| - needs_prepare_tiles_ = false;
|
| +void SchedulerStateMachine::DidPrepareTiles() {
|
| + prepare_tiles_reason_ = PREPARE_TILES_NOT_NEEDED;
|
| +
|
| + active_tree_ready_to_draw_ = false;
|
| +
|
| + if (prepare_tiles_approach_ == PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY)
|
| + prepare_tiles_funnel_++;
|
| + else
|
| + prepare_tiles_funnel_ = 0;
|
| }
|
|
|
| -void SchedulerStateMachine::UpdateStateOnBeginOutputSurfaceCreation() {
|
| +void SchedulerStateMachine::WillBeginOutputSurfaceCreation() {
|
| DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_LOST);
|
| output_surface_state_ = OUTPUT_SURFACE_CREATING;
|
|
|
| @@ -737,7 +841,7 @@ void SchedulerStateMachine::UpdateStateOnBeginOutputSurfaceCreation() {
|
| DCHECK(!active_tree_needs_first_draw_);
|
| }
|
|
|
| -void SchedulerStateMachine::UpdateStateOnInvalidateOutputSurface() {
|
| +void SchedulerStateMachine::WillInvalidateOutputSurface() {
|
| DCHECK(!invalidate_output_surface_funnel_);
|
| invalidate_output_surface_funnel_ = true;
|
| last_frame_number_invalidate_output_surface_performed_ =
|
| @@ -787,6 +891,13 @@ void SchedulerStateMachine::SetVideoNeedsBeginFrames(
|
| video_needs_begin_frames_ = video_needs_begin_frames;
|
| }
|
|
|
| +void SchedulerStateMachine::NotifyBeginFrameSourceActive(bool active) {
|
| + // Upon becoming inactive, switch back to prioritizing latency.
|
| + if (!active &&
|
| + prepare_tiles_approach_ == PREPARE_TILES_APPROACH_ACCURATE_ACTIVE_WORK)
|
| + prepare_tiles_approach_ = PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY;
|
| +}
|
| +
|
| void SchedulerStateMachine::SetDeferCommits(bool defer_commits) {
|
| defer_commits_ = defer_commits;
|
| }
|
| @@ -794,11 +905,6 @@ void SchedulerStateMachine::SetDeferCommits(bool defer_commits) {
|
| // These are the cases where we require a BeginFrame message to make progress
|
| // on requested actions.
|
| bool SchedulerStateMachine::BeginFrameRequiredForAction() const {
|
| - // The forced draw respects our normal draw scheduling, so we need to
|
| - // request a BeginImplFrame for it.
|
| - if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
|
| - return true;
|
| -
|
| return needs_animate_ || needs_redraw_ || (needs_commit_ && !defer_commits_);
|
| }
|
|
|
| @@ -828,7 +934,7 @@ bool SchedulerStateMachine::ProactiveBeginFrameWanted() const {
|
|
|
| // Changing priorities may allow us to activate (given the new priorities),
|
| // which may result in a new frame.
|
| - if (needs_prepare_tiles_)
|
| + if (PrepareTilesPending())
|
| return true;
|
|
|
| // If we just sent a swap request, it's likely that we are going to produce
|
| @@ -851,6 +957,9 @@ void SchedulerStateMachine::OnBeginImplFrame() {
|
| begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING;
|
| current_frame_number_++;
|
|
|
| + retry_begin_impl_frame_ = false;
|
| + retry_begin_impl_frame_deadline_ = false;
|
| +
|
| last_commit_had_no_updates_ = false;
|
| did_request_swap_in_last_frame_ = false;
|
|
|
| @@ -863,6 +972,15 @@ void SchedulerStateMachine::OnBeginImplFrame() {
|
| if (prepare_tiles_funnel_ > 0)
|
| prepare_tiles_funnel_--;
|
|
|
| + // PREPARE_TILES_APPROACH_ACCURATE_ACTIVE_WORK doesn't work well in
|
| + // main thread low-latency mode. Transition back to
|
| + // PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY if we just recovered
|
| + // main-thread latency.
|
| + if (skip_begin_main_frame_to_reduce_latency_ &&
|
| + prepare_tiles_approach_ == PREPARE_TILES_APPROACH_ACCURATE_ACTIVE_WORK) {
|
| + prepare_tiles_approach_ = PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY;
|
| + }
|
| +
|
| skip_begin_main_frame_to_reduce_latency_ =
|
| skip_next_begin_main_frame_to_reduce_latency_;
|
| skip_next_begin_main_frame_to_reduce_latency_ = false;
|
| @@ -896,17 +1014,23 @@ SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode() const {
|
| return BEGIN_IMPL_FRAME_DEADLINE_MODE_BLOCKED_ON_READY_TO_DRAW;
|
| } else if (ShouldTriggerBeginImplFrameDeadlineImmediately()) {
|
| return BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE;
|
| - } 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.
|
| - // If we are swap throttled we should wait until we are unblocked.
|
| - return BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR;
|
| - } else {
|
| - // The impl thread doesn't have anything it wants to draw and we are just
|
| - // waiting for a new active tree or we are swap throttled. In short we are
|
| - // blocked.
|
| - return BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE;
|
| }
|
| +
|
| + if (prepare_tiles_approach_ == PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY) {
|
| + 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.
|
| + // If we are swap throttled we should wait until we are unblocked.
|
| + return BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR;
|
| + } else {
|
| + // The impl thread doesn't have anything it wants to draw and we are just
|
| + // waiting for a new active tree or we are swap throttled. In short we are
|
| + // blocked.
|
| + return BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE;
|
| + }
|
| + }
|
| +
|
| + return BEGIN_IMPL_FRAME_DEADLINE_MODE_TRY_TO_AVOID_CHECKERBOARD;
|
| }
|
|
|
| bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately()
|
| @@ -923,6 +1047,11 @@ bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately()
|
| if (pending_swaps_ >= max_pending_swaps_)
|
| return false;
|
|
|
| + // PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY is the only approach
|
| + // where we want to trigger the deadline before NotifyReadyToDraw.
|
| + if (prepare_tiles_approach_ != PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY)
|
| + return active_tree_ready_to_draw_;
|
| +
|
| if (active_tree_needs_first_draw_)
|
| return true;
|
|
|
| @@ -985,7 +1114,11 @@ bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const {
|
| return active_tree_needs_first_draw_;
|
| }
|
|
|
| -void SchedulerStateMachine::SetVisible(bool visible) { visible_ = visible; }
|
| +void SchedulerStateMachine::SetVisible(bool visible) {
|
| + visible_ = visible;
|
| + if (!visible)
|
| + prepare_tiles_reason_ = PREPARE_TILES_NEEDED_TO_EVICT_TILES;
|
| +}
|
|
|
| void SchedulerStateMachine::SetCanDraw(bool can_draw) { can_draw_ = can_draw; }
|
|
|
| @@ -1000,10 +1133,22 @@ void SchedulerStateMachine::SetWaitForReadyToDraw() {
|
| wait_for_active_tree_ready_to_draw_ = true;
|
| }
|
|
|
| -void SchedulerStateMachine::SetNeedsPrepareTiles() {
|
| - if (!needs_prepare_tiles_) {
|
| - TRACE_EVENT0("cc", "SchedulerStateMachine::SetNeedsPrepareTiles");
|
| - needs_prepare_tiles_ = true;
|
| +void SchedulerStateMachine::SetNeedsPrepareTiles(bool for_commit) {
|
| + TRACE_EVENT0("cc", "SchedulerStateMachine::SetNeedsPrepareTiles");
|
| + switch (prepare_tiles_approach_) {
|
| + case PREPARE_TILES_APPROACH_PRIORITIZE_LATENCY:
|
| + if (for_commit)
|
| + prepare_tiles_reason_ = PREPARE_TILES_NEEDED_FOR_COMMIT;
|
| + else if (prepare_tiles_reason_ == PREPARE_TILES_NOT_NEEDED)
|
| + prepare_tiles_reason_ = PREPARE_TILES_REQUESTED;
|
| + break;
|
| +
|
| + case PREPARE_TILES_APPROACH_ACCURATE_ACTIVE_WORK:
|
| + // We don't uncondititionally PrepareTiles immediately after a commit with
|
| + // this approach.
|
| + if (prepare_tiles_reason_ == PREPARE_TILES_NOT_NEEDED)
|
| + prepare_tiles_reason_ = PREPARE_TILES_REQUESTED;
|
| + break;
|
| }
|
| }
|
|
|
| @@ -1029,47 +1174,8 @@ void SchedulerStateMachine::SetImplLatencyTakesPriority(
|
| impl_latency_takes_priority_ = impl_latency_takes_priority;
|
| }
|
|
|
| -void SchedulerStateMachine::DidDrawIfPossibleCompleted(DrawResult result) {
|
| - switch (result) {
|
| - case INVALID_RESULT:
|
| - NOTREACHED() << "Uninitialized DrawResult.";
|
| - break;
|
| - case DRAW_ABORTED_CANT_DRAW:
|
| - case DRAW_ABORTED_CONTEXT_LOST:
|
| - NOTREACHED() << "Invalid return value from DrawAndSwapIfPossible:"
|
| - << result;
|
| - break;
|
| - case DRAW_SUCCESS:
|
| - consecutive_checkerboard_animations_ = 0;
|
| - forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE;
|
| - break;
|
| - case DRAW_ABORTED_CHECKERBOARD_ANIMATIONS:
|
| - needs_redraw_ = true;
|
| -
|
| - // If we're already in the middle of a redraw, we don't need to
|
| - // restart it.
|
| - if (forced_redraw_state_ != FORCED_REDRAW_STATE_IDLE)
|
| - return;
|
| -
|
| - needs_commit_ = true;
|
| - consecutive_checkerboard_animations_++;
|
| - if (settings_.timeout_and_draw_when_animation_checkerboards &&
|
| - consecutive_checkerboard_animations_ >=
|
| - settings_.maximum_number_of_failed_draws_before_draw_is_forced_) {
|
| - consecutive_checkerboard_animations_ = 0;
|
| - // We need to force a draw, but it doesn't make sense to do this until
|
| - // we've committed and have new textures.
|
| - forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_COMMIT;
|
| - }
|
| - break;
|
| - case DRAW_ABORTED_MISSING_HIGH_RES_CONTENT:
|
| - // It's not clear whether this missing content is because of missing
|
| - // pictures (which requires a commit) or because of memory pressure
|
| - // removing textures (which might not). To be safe, request a commit
|
| - // anyway.
|
| - needs_commit_ = true;
|
| - break;
|
| - }
|
| +void SchedulerStateMachine::SetDrawResult(DrawResult result) {
|
| + last_draw_result_ = result;
|
| }
|
|
|
| void SchedulerStateMachine::SetNeedsCommit() {
|
| @@ -1098,17 +1204,11 @@ void SchedulerStateMachine::BeginMainFrameAborted(CommitEarlyOutReason reason) {
|
| return;
|
| case CommitEarlyOutReason::FINISHED_NO_UPDATES:
|
| bool commit_has_no_updates = true;
|
| - UpdateStateOnCommit(commit_has_no_updates);
|
| + DidCommit(commit_has_no_updates);
|
| return;
|
| }
|
| }
|
|
|
| -void SchedulerStateMachine::DidPrepareTiles() {
|
| - needs_prepare_tiles_ = false;
|
| - // "Fill" the PrepareTiles funnel.
|
| - prepare_tiles_funnel_++;
|
| -}
|
| -
|
| void SchedulerStateMachine::DidLoseOutputSurface() {
|
| if (output_surface_state_ == OUTPUT_SURFACE_LOST ||
|
| output_surface_state_ == OUTPUT_SURFACE_CREATING)
|
| @@ -1119,12 +1219,18 @@ void SchedulerStateMachine::DidLoseOutputSurface() {
|
| }
|
|
|
| void SchedulerStateMachine::NotifyReadyToActivate() {
|
| - if (has_pending_tree_)
|
| - pending_tree_is_ready_for_activation_ = true;
|
| + pending_tree_is_ready_for_activation_ = true;
|
| }
|
|
|
| void SchedulerStateMachine::NotifyReadyToDraw() {
|
| wait_for_active_tree_ready_to_draw_ = false;
|
| + active_tree_ready_to_draw_ = true;
|
| +}
|
| +
|
| +void SchedulerStateMachine::SetRequiresHighResToDraw(bool required) {
|
| + if (requires_high_res_to_draw_ == required)
|
| + return;
|
| + requires_high_res_to_draw_ = required;
|
| }
|
|
|
| void SchedulerStateMachine::DidCreateAndInitializeOutputSurface() {
|
|
|