summaryrefslogtreecommitdiffstats
path: root/cc/scheduler
diff options
context:
space:
mode:
authorbrianderson <brianderson@chromium.org>2015-11-24 19:48:19 -0800
committerCommit bot <commit-bot@chromium.org>2015-11-25 03:49:08 +0000
commitf677d495ab096cd08a821d965bb29149c6b9d76d (patch)
treea6cedb97c27da9cad8a1909aa081287af4669955 /cc/scheduler
parent9db7df5bc282f4e3d9fb06a0f9ea73e0fbf2d3af (diff)
downloadchromium_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.h1
-rw-r--r--cc/scheduler/scheduler.cc19
-rw-r--r--cc/scheduler/scheduler_state_machine.cc154
-rw-r--r--cc/scheduler/scheduler_state_machine.h29
-rw-r--r--cc/scheduler/scheduler_state_machine_unittest.cc285
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.