diff options
author | brianderson <brianderson@chromium.org> | 2015-11-24 19:48:19 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-11-25 03:49:08 +0000 |
commit | f677d495ab096cd08a821d965bb29149c6b9d76d (patch) | |
tree | a6cedb97c27da9cad8a1909aa081287af4669955 /cc/scheduler | |
parent | 9db7df5bc282f4e3d9fb06a0f9ea73e0fbf2d3af (diff) | |
download | chromium_src-f677d495ab096cd08a821d965bb29149c6b9d76d.zip chromium_src-f677d495ab096cd08a821d965bb29149c6b9d76d.tar.gz chromium_src-f677d495ab096cd08a821d965bb29149c6b9d76d.tar.bz2 |
cc: Add SchedulerStateMachine::DidDraw and use for forced draws
Refactors the code a bit to unify the regular and forced draw
paths. Adds and switches over to using a
SchedulerStateMachine::DidAction helper method.
A few unit tests are fixed or removed to be more realistic
and to reflect actual needs_redraw_ behavior after a draw
that fails with DRAW_ABORTED_CHECKERBOARD_ANIMATIONS.
BUG=486072
CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel
Review URL: https://codereview.chromium.org/1265023005
Cr-Commit-Position: refs/heads/master@{#361555}
Diffstat (limited to 'cc/scheduler')
-rw-r--r-- | cc/scheduler/draw_result.h | 1 | ||||
-rw-r--r-- | cc/scheduler/scheduler.cc | 19 | ||||
-rw-r--r-- | cc/scheduler/scheduler_state_machine.cc | 154 | ||||
-rw-r--r-- | cc/scheduler/scheduler_state_machine.h | 29 | ||||
-rw-r--r-- | cc/scheduler/scheduler_state_machine_unittest.cc | 285 |
5 files changed, 272 insertions, 216 deletions
diff --git a/cc/scheduler/draw_result.h b/cc/scheduler/draw_result.h index 0809a41..99b325c 100644 --- a/cc/scheduler/draw_result.h +++ b/cc/scheduler/draw_result.h @@ -14,6 +14,7 @@ enum DrawResult { DRAW_ABORTED_MISSING_HIGH_RES_CONTENT, DRAW_ABORTED_CONTEXT_LOST, DRAW_ABORTED_CANT_DRAW, + DRAW_ABORTED_DRAINING_PIPELINE, }; } // namespace cc diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc index 70884d1..085ed59 100644 --- a/cc/scheduler/scheduler.cc +++ b/cc/scheduler/scheduler.cc @@ -646,16 +646,19 @@ void Scheduler::OnBeginImplFrameDeadline() { } void Scheduler::DrawAndSwapIfPossible() { + state_machine_.WillDraw(); compositor_timing_history_->WillDraw(); DrawResult result = client_->ScheduledActionDrawAndSwapIfPossible(); - state_machine_.DidDrawIfPossibleCompleted(result); compositor_timing_history_->DidDraw(); + state_machine_.DidDraw(result); } void Scheduler::DrawAndSwapForced() { + state_machine_.WillDraw(); compositor_timing_history_->WillDraw(); - client_->ScheduledActionDrawAndSwapForced(); + DrawResult result = client_->ScheduledActionDrawAndSwapForced(); compositor_timing_history_->DidDraw(); + state_machine_.DidDraw(result); } void Scheduler::SetDeferCommits(bool defer_commits) { @@ -720,22 +723,16 @@ void Scheduler::ProcessScheduledActions() { tracked_objects::ScopedTracker tracking_profile6( FROM_HERE_WITH_EXPLICIT_FUNCTION( "461509 Scheduler::ProcessScheduledActions6")); - bool did_request_swap = true; - state_machine_.WillDraw(did_request_swap); DrawAndSwapIfPossible(); break; } - case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED: { - bool did_request_swap = true; - state_machine_.WillDraw(did_request_swap); + case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED: DrawAndSwapForced(); break; - } case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT: { // No action is actually performed, but this allows the state machine to - // advance out of its waiting to draw state without actually drawing. - bool did_request_swap = false; - state_machine_.WillDraw(did_request_swap); + // drain the pipeline without actually drawing. + state_machine_.AbortDrawAndSwap(); break; } case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION: diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc index 3330bd6..eedc6c3 100644 --- a/cc/scheduler/scheduler_state_machine.cc +++ b/cc/scheduler/scheduler_state_machine.cc @@ -28,11 +28,11 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) current_frame_number_(0), last_frame_number_animate_performed_(-1), last_frame_number_swap_performed_(-1), - last_frame_number_swap_requested_(-1), + last_frame_number_draw_performed_(-1), last_frame_number_begin_main_frame_sent_(-1), last_frame_number_invalidate_output_surface_performed_(-1), animate_funnel_(false), - request_swap_funnel_(false), + draw_funnel_(false), send_begin_main_frame_funnel_(true), invalidate_output_surface_funnel_(false), prepare_tiles_funnel_(0), @@ -62,8 +62,8 @@ SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings) video_needs_begin_frames_(false), last_commit_had_no_updates_(false), wait_for_ready_to_draw_(false), - did_request_swap_in_last_frame_(false), - did_perform_swap_in_last_draw_(false) {} + did_draw_in_last_frame_(false), + did_swap_in_last_frame_(false) {} const char* SchedulerStateMachine::OutputSurfaceStateToString( OutputSurfaceState state) { @@ -222,12 +222,12 @@ void SchedulerStateMachine::AsValueInto( last_frame_number_animate_performed_); state->SetInteger("last_frame_number_swap_performed", last_frame_number_swap_performed_); - state->SetInteger("last_frame_number_swap_requested", - last_frame_number_swap_requested_); + state->SetInteger("last_frame_number_draw_performed", + last_frame_number_draw_performed_); state->SetInteger("last_frame_number_begin_main_frame_sent", last_frame_number_begin_main_frame_sent_); state->SetBoolean("funnel: animate_funnel", animate_funnel_); - state->SetBoolean("funnel: request_swap_funnel", request_swap_funnel_); + state->SetBoolean("funnel: draw_funnel", draw_funnel_); state->SetBoolean("funnel: send_begin_main_frame_funnel", send_begin_main_frame_funnel_); state->SetInteger("funnel: prepare_tiles_funnel", prepare_tiles_funnel_); @@ -267,10 +267,8 @@ void SchedulerStateMachine::AsValueInto( state->SetBoolean("video_needs_begin_frames", video_needs_begin_frames_); state->SetBoolean("defer_commits", defer_commits_); state->SetBoolean("last_commit_had_no_updates", last_commit_had_no_updates_); - state->SetBoolean("did_request_swap_in_last_frame", - did_request_swap_in_last_frame_); - state->SetBoolean("did_perform_swap_in_last_draw", - did_perform_swap_in_last_draw_); + state->SetBoolean("did_draw_in_last_frame", did_draw_in_last_frame_); + state->SetBoolean("did_swap_in_last_frame", did_swap_in_last_frame_); state->EndDictionary(); } @@ -350,7 +348,7 @@ bool SchedulerStateMachine::ShouldDraw() const { // 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_) + if (draw_funnel_) return false; // Don't draw if we are waiting on the first commit after a surface. @@ -492,7 +490,7 @@ bool SchedulerStateMachine::ShouldSendBeginMainFrame() const { // make it conditional on ImplLatencyTakesPriority. bool just_swapped_in_deadline = begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE && - did_perform_swap_in_last_draw_; + did_swap_in_last_frame_; if (SwapThrottled() && !just_swapped_in_deadline) return false; } @@ -668,24 +666,78 @@ void SchedulerStateMachine::WillActivate() { needs_redraw_ = true; } -void SchedulerStateMachine::WillDraw(bool did_request_swap) { +void SchedulerStateMachine::WillDrawInternal() { + // We need to reset needs_redraw_ before we draw since the + // draw itself might request another draw. + needs_redraw_ = false; + + draw_funnel_ = true; + active_tree_needs_first_draw_ = false; + did_draw_in_last_frame_ = true; + last_frame_number_draw_performed_ = current_frame_number_; + if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW) forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE; if (begin_main_frame_state_ == BEGIN_MAIN_FRAME_STATE_WAITING_FOR_DRAW) begin_main_frame_state_ = BEGIN_MAIN_FRAME_STATE_IDLE; +} - needs_redraw_ = false; - active_tree_needs_first_draw_ = false; +void SchedulerStateMachine::DidDrawInternal(DrawResult draw_result) { + switch (draw_result) { + case INVALID_RESULT: + case DRAW_ABORTED_CANT_DRAW: + case DRAW_ABORTED_CONTEXT_LOST: + NOTREACHED() << "Invalid return DrawResult:" << draw_result; + break; + case DRAW_ABORTED_DRAINING_PIPELINE: + case DRAW_SUCCESS: + consecutive_checkerboard_animations_ = 0; + forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE; + break; + case DRAW_ABORTED_CHECKERBOARD_ANIMATIONS: + DCHECK(!did_swap_in_last_frame_); + needs_begin_main_frame_ = true; + needs_redraw_ = true; + consecutive_checkerboard_animations_++; - if (did_request_swap) { - DCHECK(!request_swap_funnel_); - request_swap_funnel_ = true; - did_request_swap_in_last_frame_ = true; - last_frame_number_swap_requested_ = current_frame_number_; + if (consecutive_checkerboard_animations_ >= + settings_.maximum_number_of_failed_draws_before_draw_is_forced && + forced_redraw_state_ == FORCED_REDRAW_STATE_IDLE && + settings_.timeout_and_draw_when_animation_checkerboards) { + // 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: + DCHECK(!did_swap_in_last_frame_); + // 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_begin_main_frame_ = true; + break; } } +void SchedulerStateMachine::WillDraw() { + DCHECK(!draw_funnel_); + WillDrawInternal(); +} + +void SchedulerStateMachine::DidDraw(DrawResult draw_result) { + DidDrawInternal(draw_result); +} + +void SchedulerStateMachine::AbortDrawAndSwap() { + // Pretend like the draw was successful. + // Note: We may abort at any time and cannot DCHECK that + // we haven't drawn in or swapped in the last frame here. + WillDrawInternal(); + DidDrawInternal(DRAW_ABORTED_DRAINING_PIPELINE); +} + void SchedulerStateMachine::WillPrepareTiles() { needs_prepare_tiles_ = false; } @@ -799,12 +851,12 @@ bool SchedulerStateMachine::ProactiveBeginFrameWanted() const { if (needs_prepare_tiles_) return true; - // If we just sent a swap request, it's likely that we are going to produce + // If we just tried to DrawAndSwap, it's likely that we are going to produce // another frame soon. This helps avoid negative glitches in our // SetNeedsBeginFrame requests, which may propagate to the BeginImplFrame // provider and get sampled at an inopportune time, delaying the next // BeginImplFrame. - if (did_request_swap_in_last_frame_) + if (did_draw_in_last_frame_) return true; // If the last commit was aborted because of early out (no updates), we should @@ -820,7 +872,8 @@ void SchedulerStateMachine::OnBeginImplFrame() { current_frame_number_++; last_commit_had_no_updates_ = false; - did_request_swap_in_last_frame_ = false; + did_draw_in_last_frame_ = false; + did_swap_in_last_frame_ = false; needs_one_begin_impl_frame_ = false; // Clear funnels for any actions we perform during the frame. @@ -840,10 +893,8 @@ void SchedulerStateMachine::OnBeginImplFrameDeadlinePending() { void SchedulerStateMachine::OnBeginImplFrameDeadline() { begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE; - did_perform_swap_in_last_draw_ = false; - // Clear funnels for any actions we perform during the deadline. - request_swap_funnel_ = false; + draw_funnel_ = false; // Allow one PrepareTiles per draw for synchronous compositor. if (settings_.using_synchronous_renderer_compositor) { @@ -979,12 +1030,12 @@ void SchedulerStateMachine::SetNeedsPrepareTiles() { } void SchedulerStateMachine::DidSwapBuffers() { TRACE_EVENT_ASYNC_BEGIN0("cc", "Scheduler:pending_swaps", this); + DCHECK_LT(pending_swaps_, kMaxPendingSwaps); + pending_swaps_++; swaps_with_current_output_surface_++; - DCHECK_LE(pending_swaps_, kMaxPendingSwaps); - - did_perform_swap_in_last_draw_ = true; + did_swap_in_last_frame_ = true; last_frame_number_swap_performed_ = current_frame_number_; } @@ -1020,49 +1071,6 @@ bool SchedulerStateMachine::ImplLatencyTakesPriority() const { return false; } -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_begin_main_frame_ = 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_begin_main_frame_ = true; - break; - } -} - void SchedulerStateMachine::SetNeedsBeginMainFrame() { needs_begin_main_frame_ = true; } diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h index 36a60a7..93f6766 100644 --- a/cc/scheduler/scheduler_state_machine.h +++ b/cc/scheduler/scheduler_state_machine.h @@ -98,13 +98,18 @@ class CC_EXPORT SchedulerStateMachine { static const char* ForcedRedrawOnTimeoutStateToString( ForcedRedrawOnTimeoutState state); + BeginMainFrameState begin_main_frame_state() const { + return begin_main_frame_state_; + } + bool CommitPending() const { return begin_main_frame_state_ == BEGIN_MAIN_FRAME_STATE_SENT || begin_main_frame_state_ == BEGIN_MAIN_FRAME_STATE_STARTED || begin_main_frame_state_ == BEGIN_MAIN_FRAME_STATE_READY_TO_COMMIT; } - BeginMainFrameState begin_main_frame_state() const { - return begin_main_frame_state_; + + bool NewActiveTreeLikely() const { + return needs_begin_main_frame_ || CommitPending() || has_pending_tree_; } bool RedrawPending() const { return needs_redraw_; } @@ -133,11 +138,15 @@ class CC_EXPORT SchedulerStateMachine { void WillSendBeginMainFrame(); void WillCommit(bool commit_had_no_updates); void WillActivate(); - void WillDraw(bool did_request_swap); + void WillDraw(); void WillBeginOutputSurfaceCreation(); void WillPrepareTiles(); void WillInvalidateOutputSurface(); + void DidDraw(DrawResult draw_result); + + void AbortDrawAndSwap(); + // Indicates whether the impl thread needs a BeginImplFrame callback in order // to make progress. bool BeginFrameNeeded() const; @@ -207,9 +216,6 @@ class CC_EXPORT SchedulerStateMachine { // SetCriticalBeginMainFrameToActivateIsFast. bool ImplLatencyTakesPriority() const; - // Indicates whether ACTION_DRAW_AND_SWAP_IF_POSSIBLE drew to the screen. - void DidDrawIfPossibleCompleted(DrawResult result); - // Indicates that a new begin main frame flow needs to be performed, either // to pull updates from the main thread to the impl, or to push deltas from // the impl thread to main. @@ -298,6 +304,9 @@ class CC_EXPORT SchedulerStateMachine { bool ShouldPrepareTiles() const; bool ShouldInvalidateOutputSurface() const; + void WillDrawInternal(); + void DidDrawInternal(DrawResult draw_result); + const SchedulerSettings settings_; OutputSurfaceState output_surface_state_; @@ -310,14 +319,14 @@ class CC_EXPORT SchedulerStateMachine { int current_frame_number_; int last_frame_number_animate_performed_; int last_frame_number_swap_performed_; - int last_frame_number_swap_requested_; + int last_frame_number_draw_performed_; int last_frame_number_begin_main_frame_sent_; int last_frame_number_invalidate_output_surface_performed_; // These are used to ensure that an action only happens once per frame, // deadline, etc. bool animate_funnel_; - bool request_swap_funnel_; + bool draw_funnel_; bool send_begin_main_frame_funnel_; bool invalidate_output_surface_funnel_; // prepare_tiles_funnel_ is "filled" each time PrepareTiles is called @@ -352,8 +361,8 @@ class CC_EXPORT SchedulerStateMachine { bool video_needs_begin_frames_; bool last_commit_had_no_updates_; bool wait_for_ready_to_draw_; - bool did_request_swap_in_last_frame_; - bool did_perform_swap_in_last_draw_; + bool did_draw_in_last_frame_; + bool did_swap_in_last_frame_; private: DISALLOW_COPY_AND_ASSIGN(SchedulerStateMachine); diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc index 90c126a..e6adbc6 100644 --- a/cc/scheduler/scheduler_state_machine_unittest.cc +++ b/cc/scheduler/scheduler_state_machine_unittest.cc @@ -40,7 +40,7 @@ EXPECT_IMPL_FRAME_STATE( \ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE); \ } \ - WillPerformAction(&state, action); \ + PerformAction(&state, action); \ if (action == SchedulerStateMachine::ACTION_NONE) { \ if (state.begin_impl_frame_state() == \ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING) \ @@ -62,57 +62,6 @@ namespace cc { namespace { -void WillPerformAction(SchedulerStateMachine* sm, - SchedulerStateMachine::Action action) { - switch (action) { - case SchedulerStateMachine::ACTION_NONE: - return; - - case SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE: - sm->WillActivate(); - return; - - case SchedulerStateMachine::ACTION_ANIMATE: - sm->WillAnimate(); - return; - - case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME: - sm->WillSendBeginMainFrame(); - return; - - case SchedulerStateMachine::ACTION_COMMIT: { - bool commit_has_no_updates = false; - sm->WillCommit(commit_has_no_updates); - return; - } - - case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED: - case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE: { - bool did_request_swap = true; - sm->WillDraw(did_request_swap); - return; - } - - case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT: { - bool did_request_swap = false; - sm->WillDraw(did_request_swap); - return; - } - - case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION: - sm->WillBeginOutputSurfaceCreation(); - return; - - case SchedulerStateMachine::ACTION_PREPARE_TILES: - sm->WillPrepareTiles(); - return; - - case SchedulerStateMachine::ACTION_INVALIDATE_OUTPUT_SURFACE: - sm->WillInvalidateOutputSurface(); - return; - } -} - const SchedulerStateMachine::BeginImplFrameState all_begin_impl_frame_states[] = {SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE, SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING, @@ -131,7 +80,8 @@ const SchedulerStateMachine::BeginMainFrameState begin_main_frame_states[] = { class StateMachine : public SchedulerStateMachine { public: explicit StateMachine(const SchedulerSettings& scheduler_settings) - : SchedulerStateMachine(scheduler_settings) {} + : SchedulerStateMachine(scheduler_settings), + draw_result_for_test_(DRAW_SUCCESS) {} void CreateAndInitializeOutputSurfaceWithActivatedCommit() { DidCreateAndInitializeOutputSurface(); @@ -173,6 +123,11 @@ class StateMachine : public SchedulerStateMachine { void SetNeedsRedraw(bool needs_redraw) { needs_redraw_ = needs_redraw; } + void SetDrawResultForTest(DrawResult draw_result) { + draw_result_for_test_ = draw_result; + } + DrawResult draw_result_for_test() { return draw_result_for_test_; } + void SetNeedsForcedRedrawForTimeout(bool b) { forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_COMMIT; active_tree_needs_first_draw_ = true; @@ -199,8 +154,60 @@ class StateMachine : public SchedulerStateMachine { using SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately; using SchedulerStateMachine::ProactiveBeginFrameWanted; using SchedulerStateMachine::WillCommit; + + protected: + DrawResult draw_result_for_test_; }; +void PerformAction(StateMachine* sm, SchedulerStateMachine::Action action) { + switch (action) { + case SchedulerStateMachine::ACTION_NONE: + return; + + case SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE: + sm->WillActivate(); + return; + + case SchedulerStateMachine::ACTION_ANIMATE: + sm->WillAnimate(); + return; + + case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME: + sm->WillSendBeginMainFrame(); + return; + + case SchedulerStateMachine::ACTION_COMMIT: { + bool commit_has_no_updates = false; + sm->WillCommit(commit_has_no_updates); + return; + } + + case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED: + case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE: { + sm->WillDraw(); + sm->DidDraw(sm->draw_result_for_test()); + return; + } + + case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT: { + sm->AbortDrawAndSwap(); + return; + } + + case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION: + sm->WillBeginOutputSurfaceCreation(); + return; + + case SchedulerStateMachine::ACTION_PREPARE_TILES: + sm->WillPrepareTiles(); + return; + + case SchedulerStateMachine::ACTION_INVALIDATE_OUTPUT_SURFACE: + sm->WillInvalidateOutputSurface(); + return; + } +} + TEST(SchedulerStateMachineTest, BeginFrameNeeded) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); @@ -406,39 +413,52 @@ TEST(SchedulerStateMachineTest, MainFrameBeforeActivationEnabled) { } TEST(SchedulerStateMachineTest, - TestFailedDrawForAnimationCheckerboardSetsNeedsCommitAndDoesNotDrawAgain) { + FailedDrawForAnimationCheckerboardSetsNeedsCommitAndRetriesDraw) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); SET_UP_STATE(state) state.SetNeedsRedraw(true); EXPECT_TRUE(state.RedrawPending()); EXPECT_TRUE(state.BeginFrameNeeded()); + + // Start a frame. state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginImplFrameDeadline(); + state.OnBeginImplFrameDeadlinePending(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + EXPECT_FALSE(state.CommitPending()); - // We're drawing now. + // Failing a draw triggers request for a new BeginMainFrame. + state.OnBeginImplFrameDeadline(); + state.SetDrawResultForTest(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); - state.DidSwapBuffers(); - state.DidSwapBuffersComplete(); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + state.OnBeginImplFrameIdle(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - EXPECT_FALSE(state.RedrawPending()); - EXPECT_FALSE(state.CommitPending()); - - // Failing the draw makes us require a commit. - state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS); + // It's okay to attempt more draws just in case additional raster + // finishes and the requested commit wasn't actually necessary. + EXPECT_TRUE(state.CommitPending()); + EXPECT_TRUE(state.RedrawPending()); state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + state.OnBeginImplFrameDeadlinePending(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + state.OnBeginImplFrameDeadline(); + state.SetDrawResultForTest(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS); EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); - EXPECT_TRUE(state.RedrawPending()); - EXPECT_TRUE(state.CommitPending()); + SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + state.OnBeginImplFrameIdle(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); } -TEST(SchedulerStateMachineTest, TestFailedDrawForMissingHighResNeedsCommit) { +TEST(SchedulerStateMachineTest, FailedDrawForMissingHighResNeedsCommit) { SchedulerSettings default_scheduler_settings; StateMachine state(default_scheduler_settings); SET_UP_STATE(state) @@ -446,61 +466,62 @@ TEST(SchedulerStateMachineTest, TestFailedDrawForMissingHighResNeedsCommit) { EXPECT_TRUE(state.RedrawPending()); EXPECT_TRUE(state.BeginFrameNeeded()); + // Start a frame. state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - state.OnBeginImplFrameDeadline(); - EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); - state.DidSwapBuffers(); - state.DidSwapBuffersComplete(); + state.OnBeginImplFrameDeadlinePending(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - EXPECT_FALSE(state.RedrawPending()); EXPECT_FALSE(state.CommitPending()); - // Missing high res content requires a commit (but not a redraw) - state.DidDrawIfPossibleCompleted(DRAW_ABORTED_MISSING_HIGH_RES_CONTENT); - state.OnBeginImplFrame(); + // Failing a draw triggers because of high res tiles missing + // request for a new BeginMainFrame. + state.OnBeginImplFrameDeadline(); + state.SetDrawResultForTest(DRAW_ABORTED_MISSING_HIGH_RES_CONTENT); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); - EXPECT_FALSE(state.RedrawPending()); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + state.OnBeginImplFrameIdle(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + + // It doesn't request a draw until we get a new commit though. EXPECT_TRUE(state.CommitPending()); -} + EXPECT_FALSE(state.RedrawPending()); + state.OnBeginImplFrame(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + state.OnBeginImplFrameDeadlinePending(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + state.OnBeginImplFrameDeadline(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + state.OnBeginImplFrameIdle(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); -TEST(SchedulerStateMachineTest, - TestsetNeedsRedrawDuringFailedDrawDoesNotRemoveNeedsRedraw) { - SchedulerSettings default_scheduler_settings; - StateMachine state(default_scheduler_settings); - SET_UP_STATE(state) - state.SetNeedsRedraw(true); + // Finish the commit and activation. + state.NotifyBeginMainFrameStarted(); + state.NotifyReadyToCommit(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + state.NotifyReadyToActivate(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_TRUE(state.RedrawPending()); - EXPECT_TRUE(state.BeginFrameNeeded()); + + // Verify we draw with the new frame. state.OnBeginImplFrame(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + state.OnBeginImplFrameDeadlinePending(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); - - // We're drawing now. + state.SetDrawResultForTest(DRAW_SUCCESS); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); state.DidSwapBuffers(); - state.DidSwapBuffersComplete(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - EXPECT_FALSE(state.RedrawPending()); - EXPECT_FALSE(state.CommitPending()); - - // While still in the same BeginMainFrame callback on the main thread, - // set needs redraw again. This should not redraw. - state.SetNeedsRedraw(true); + state.OnBeginImplFrameIdle(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); - - // Failing the draw for animation checkerboards makes us require a commit. - state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS); - state.OnBeginImplFrame(); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); - EXPECT_ACTION_UPDATE_STATE( - SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); - EXPECT_TRUE(state.RedrawPending()); } TEST(SchedulerStateMachineTest, @@ -519,19 +540,16 @@ TEST(SchedulerStateMachineTest, EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_TRUE(state.CommitPending()); - // Then initiate a draw. + // Then initiate a draw that fails. state.SetNeedsRedraw(true); state.OnBeginImplFrameDeadline(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); + state.SetDrawResultForTest(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); - - // Fail the draw. - state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); EXPECT_TRUE(state.BeginFrameNeeded()); EXPECT_TRUE(state.RedrawPending()); - // But the commit is ongoing. EXPECT_TRUE(state.CommitPending()); // Finish the commit. Note, we should not yet be forcing a draw, but should @@ -555,15 +573,18 @@ TEST(SchedulerStateMachineTest, SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); + state.SetDrawResultForTest(DRAW_SUCCESS); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED); state.DidSwapBuffers(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.DidSwapBuffersComplete(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); } TEST(SchedulerStateMachineTest, TestFailedDrawsDoNotRestartForcedDraw) { SchedulerSettings scheduler_settings; - int draw_limit = 1; + int draw_limit = 2; scheduler_settings.maximum_number_of_failed_draws_before_draw_is_forced = draw_limit; StateMachine state(scheduler_settings); @@ -585,11 +606,23 @@ TEST(SchedulerStateMachineTest, TestFailedDrawsDoNotRestartForcedDraw) { EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); - // Fail the draw enough times to force a redraw, - // then once more for good measure. - for (int i = 0; i < draw_limit + 1; ++i) - state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS); - EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + // Fail the draw enough times to force a redraw. + for (int i = 0; i < draw_limit; ++i) { + state.SetNeedsRedraw(true); + state.OnBeginImplFrame(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + state.OnBeginImplFrameDeadlinePending(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + state.OnBeginImplFrameDeadline(); + state.SetDrawResultForTest(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + state.OnBeginImplFrameIdle(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + } + EXPECT_TRUE(state.BeginFrameNeeded()); EXPECT_TRUE(state.RedrawPending()); // But the commit is ongoing. @@ -610,8 +643,21 @@ TEST(SchedulerStateMachineTest, TestFailedDrawsDoNotRestartForcedDraw) { // After failing additional draws, we should still be in a forced // redraw, but not back in WAITING_FOR_COMMIT. - for (int i = 0; i < draw_limit + 1; ++i) - state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS); + for (int i = 0; i < draw_limit; ++i) { + state.SetNeedsRedraw(true); + state.OnBeginImplFrame(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + state.OnBeginImplFrameDeadlinePending(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + state.OnBeginImplFrameDeadline(); + state.SetDrawResultForTest(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS); + EXPECT_ACTION_UPDATE_STATE( + SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + state.OnBeginImplFrameIdle(); + EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); + } EXPECT_TRUE(state.RedrawPending()); EXPECT_TRUE(state.ForcedRedrawState() == SchedulerStateMachine::FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION); @@ -630,11 +676,11 @@ TEST(SchedulerStateMachineTest, TestFailedDrawIsRetriedInNextBeginImplFrame) { EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); state.OnBeginImplFrameDeadline(); EXPECT_TRUE(state.RedrawPending()); + state.SetDrawResultForTest(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); // Failing the draw for animation checkerboards makes us require a commit. - state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -649,6 +695,7 @@ TEST(SchedulerStateMachineTest, TestFailedDrawIsRetriedInNextBeginImplFrame) { // We should try to draw again at the end of the next BeginImplFrame on // the impl thread. state.OnBeginImplFrameDeadline(); + state.SetDrawResultForTest(DRAW_SUCCESS); EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); state.DidSwapBuffers(); @@ -672,7 +719,6 @@ TEST(SchedulerStateMachineTest, TestDoestDrawTwiceInSameFrame) { EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); state.DidSwapBuffers(); - state.DidDrawIfPossibleCompleted(DRAW_SUCCESS); state.DidSwapBuffersComplete(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -692,7 +738,6 @@ TEST(SchedulerStateMachineTest, TestDoestDrawTwiceInSameFrame) { EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); state.DidSwapBuffers(); - state.DidDrawIfPossibleCompleted(DRAW_SUCCESS); state.DidSwapBuffersComplete(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); @@ -931,7 +976,6 @@ TEST(SchedulerStateMachineTest, TestSetNeedsBeginMainFrameIsNotLost) { EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); state.DidSwapBuffers(); - state.DidDrawIfPossibleCompleted(DRAW_SUCCESS); state.DidSwapBuffersComplete(); EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE); } @@ -976,7 +1020,6 @@ TEST(SchedulerStateMachineTest, TestFullCycle) { EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); state.DidSwapBuffers(); - state.DidDrawIfPossibleCompleted(DRAW_SUCCESS); state.DidSwapBuffersComplete(); // Should be synchronized, no draw needed, no action needed. @@ -1115,7 +1158,6 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitToActive) { EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); state.DidSwapBuffers(); - state.DidDrawIfPossibleCompleted(DRAW_SUCCESS); state.DidSwapBuffersComplete(); // Now will be able to start main frame. @@ -1167,7 +1209,6 @@ TEST(SchedulerStateMachineTest, TestFullCycleWithCommitRequestInbetween) { EXPECT_ACTION_UPDATE_STATE( SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE); state.DidSwapBuffers(); - state.DidDrawIfPossibleCompleted(DRAW_SUCCESS); state.DidSwapBuffersComplete(); // Should be synchronized, no draw needed, no action needed. |