1 // Copyright 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/scheduler/scheduler_state_machine.h"
7 #include "base/debug/trace_event.h"
8 #include "base/format_macros.h"
9 #include "base/logging.h"
10 #include "base/strings/stringprintf.h"
11 #include "base/values.h"
12 #include "ui/gfx/frame_time.h"
16 SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
17 : settings_(settings),
18 output_surface_state_(OUTPUT_SURFACE_LOST),
19 begin_impl_frame_state_(BEGIN_IMPL_FRAME_STATE_IDLE),
20 commit_state_(COMMIT_STATE_IDLE),
21 texture_state_(LAYER_TEXTURE_STATE_UNLOCKED),
22 forced_redraw_state_(FORCED_REDRAW_STATE_IDLE),
23 readback_state_(READBACK_STATE_IDLE),
25 current_frame_number_(0),
26 last_frame_number_swap_performed_(-1),
27 last_frame_number_begin_main_frame_sent_(-1),
28 last_frame_number_update_visible_tiles_was_called_(-1),
29 manage_tiles_funnel_(0),
30 consecutive_failed_draws_(0),
32 needs_manage_tiles_(false),
33 swap_used_incomplete_tile_(false),
35 main_thread_needs_layer_textures_(false),
36 inside_poll_for_anticipated_draw_triggers_(false),
40 has_pending_tree_(false),
41 pending_tree_is_ready_for_activation_(false),
42 active_tree_needs_first_draw_(false),
43 draw_if_possible_failed_(false),
44 did_create_and_initialize_first_output_surface_(false),
45 smoothness_takes_priority_(false),
46 skip_begin_main_frame_to_reduce_latency_(false) {}
48 const char* SchedulerStateMachine::OutputSurfaceStateToString(
49 OutputSurfaceState state) {
51 case OUTPUT_SURFACE_ACTIVE:
52 return "OUTPUT_SURFACE_ACTIVE";
53 case OUTPUT_SURFACE_LOST:
54 return "OUTPUT_SURFACE_LOST";
55 case OUTPUT_SURFACE_CREATING:
56 return "OUTPUT_SURFACE_CREATING";
57 case OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT:
58 return "OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT";
59 case OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION:
60 return "OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION";
66 const char* SchedulerStateMachine::BeginImplFrameStateToString(
67 BeginImplFrameState state) {
69 case BEGIN_IMPL_FRAME_STATE_IDLE:
70 return "BEGIN_IMPL_FRAME_STATE_IDLE";
71 case BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING:
72 return "BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING";
73 case BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME:
74 return "BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME";
75 case BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE:
76 return "BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE";
82 const char* SchedulerStateMachine::CommitStateToString(CommitState state) {
84 case COMMIT_STATE_IDLE:
85 return "COMMIT_STATE_IDLE";
86 case COMMIT_STATE_FRAME_IN_PROGRESS:
87 return "COMMIT_STATE_FRAME_IN_PROGRESS";
88 case COMMIT_STATE_READY_TO_COMMIT:
89 return "COMMIT_STATE_READY_TO_COMMIT";
90 case COMMIT_STATE_WAITING_FOR_FIRST_DRAW:
91 return "COMMIT_STATE_WAITING_FOR_FIRST_DRAW";
97 const char* SchedulerStateMachine::TextureStateToString(TextureState state) {
99 case LAYER_TEXTURE_STATE_UNLOCKED:
100 return "LAYER_TEXTURE_STATE_UNLOCKED";
101 case LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD:
102 return "LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD";
103 case LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD:
104 return "LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD";
110 const char* SchedulerStateMachine::SynchronousReadbackStateToString(
111 SynchronousReadbackState state) {
113 case READBACK_STATE_IDLE:
114 return "READBACK_STATE_IDLE";
115 case READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME:
116 return "READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME";
117 case READBACK_STATE_WAITING_FOR_COMMIT:
118 return "READBACK_STATE_WAITING_FOR_COMMIT";
119 case READBACK_STATE_WAITING_FOR_ACTIVATION:
120 return "READBACK_STATE_WAITING_FOR_ACTIVATION";
121 case READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK:
122 return "READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK";
123 case READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT:
124 return "READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT";
125 case READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION:
126 return "READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION";
132 const char* SchedulerStateMachine::ForcedRedrawOnTimeoutStateToString(
133 ForcedRedrawOnTimeoutState state) {
135 case FORCED_REDRAW_STATE_IDLE:
136 return "FORCED_REDRAW_STATE_IDLE";
137 case FORCED_REDRAW_STATE_WAITING_FOR_COMMIT:
138 return "FORCED_REDRAW_STATE_WAITING_FOR_COMMIT";
139 case FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION:
140 return "FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION";
141 case FORCED_REDRAW_STATE_WAITING_FOR_DRAW:
142 return "FORCED_REDRAW_STATE_WAITING_FOR_DRAW";
148 const char* SchedulerStateMachine::ActionToString(Action action) {
151 return "ACTION_NONE";
152 case ACTION_SEND_BEGIN_MAIN_FRAME:
153 return "ACTION_SEND_BEGIN_MAIN_FRAME";
155 return "ACTION_COMMIT";
156 case ACTION_UPDATE_VISIBLE_TILES:
157 return "ACTION_UPDATE_VISIBLE_TILES";
158 case ACTION_ACTIVATE_PENDING_TREE:
159 return "ACTION_ACTIVATE_PENDING_TREE";
160 case ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
161 return "ACTION_DRAW_AND_SWAP_IF_POSSIBLE";
162 case ACTION_DRAW_AND_SWAP_FORCED:
163 return "ACTION_DRAW_AND_SWAP_FORCED";
164 case ACTION_DRAW_AND_SWAP_ABORT:
165 return "ACTION_DRAW_AND_SWAP_ABORT";
166 case ACTION_DRAW_AND_READBACK:
167 return "ACTION_DRAW_AND_READBACK";
168 case ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
169 return "ACTION_BEGIN_OUTPUT_SURFACE_CREATION";
170 case ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD:
171 return "ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD";
172 case ACTION_MANAGE_TILES:
173 return "ACTION_MANAGE_TILES";
179 scoped_ptr<base::Value> SchedulerStateMachine::AsValue() const {
180 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue);
182 scoped_ptr<base::DictionaryValue> major_state(new base::DictionaryValue);
183 major_state->SetString("next_action", ActionToString(NextAction()));
184 major_state->SetString("begin_impl_frame_state",
185 BeginImplFrameStateToString(begin_impl_frame_state_));
186 major_state->SetString("commit_state", CommitStateToString(commit_state_));
187 major_state->SetString("texture_state_",
188 TextureStateToString(texture_state_));
189 major_state->SetString("output_surface_state_",
190 OutputSurfaceStateToString(output_surface_state_));
191 major_state->SetString(
192 "forced_redraw_state",
193 ForcedRedrawOnTimeoutStateToString(forced_redraw_state_));
194 major_state->SetString("readback_state",
195 SynchronousReadbackStateToString(readback_state_));
196 state->Set("major_state", major_state.release());
198 scoped_ptr<base::DictionaryValue> timestamps_state(new base::DictionaryValue);
199 base::TimeTicks now = gfx::FrameTime::Now();
200 timestamps_state->SetDouble(
202 last_begin_impl_frame_args_.interval.InMicroseconds() / 1000.0L);
203 timestamps_state->SetDouble(
205 (last_begin_impl_frame_args_.deadline - now).InMicroseconds() / 1000.0L);
206 timestamps_state->SetDouble(
207 "2_frame_time_to_now",
208 (now - last_begin_impl_frame_args_.frame_time).InMicroseconds() /
210 timestamps_state->SetDouble(
211 "3_frame_time_to_deadline",
212 (last_begin_impl_frame_args_.deadline -
213 last_begin_impl_frame_args_.frame_time).InMicroseconds() /
215 timestamps_state->SetDouble(
216 "4_now", (now - base::TimeTicks()).InMicroseconds() / 1000.0L);
217 timestamps_state->SetDouble(
219 (last_begin_impl_frame_args_.frame_time - base::TimeTicks())
222 timestamps_state->SetDouble(
224 (last_begin_impl_frame_args_.deadline - base::TimeTicks())
227 state->Set("major_timestamps_in_ms", timestamps_state.release());
229 scoped_ptr<base::DictionaryValue> minor_state(new base::DictionaryValue);
230 minor_state->SetInteger("commit_count", commit_count_);
231 minor_state->SetInteger("current_frame_number", current_frame_number_);
233 minor_state->SetInteger("last_frame_number_swap_performed",
234 last_frame_number_swap_performed_);
235 minor_state->SetInteger(
236 "last_frame_number_begin_main_frame_sent",
237 last_frame_number_begin_main_frame_sent_);
238 minor_state->SetInteger(
239 "last_frame_number_update_visible_tiles_was_called",
240 last_frame_number_update_visible_tiles_was_called_);
242 minor_state->SetInteger("manage_tiles_funnel", manage_tiles_funnel_);
243 minor_state->SetInteger("consecutive_failed_draws",
244 consecutive_failed_draws_);
245 minor_state->SetBoolean("needs_redraw", needs_redraw_);
246 minor_state->SetBoolean("needs_manage_tiles", needs_manage_tiles_);
247 minor_state->SetBoolean("swap_used_incomplete_tile",
248 swap_used_incomplete_tile_);
249 minor_state->SetBoolean("needs_commit", needs_commit_);
250 minor_state->SetBoolean("main_thread_needs_layer_textures",
251 main_thread_needs_layer_textures_);
252 minor_state->SetBoolean("visible", visible_);
253 minor_state->SetBoolean("can_start", can_start_);
254 minor_state->SetBoolean("can_draw", can_draw_);
255 minor_state->SetBoolean("has_pending_tree", has_pending_tree_);
256 minor_state->SetBoolean("pending_tree_is_ready_for_activation",
257 pending_tree_is_ready_for_activation_);
258 minor_state->SetBoolean("active_tree_needs_first_draw",
259 active_tree_needs_first_draw_);
260 minor_state->SetBoolean("draw_if_possible_failed", draw_if_possible_failed_);
261 minor_state->SetBoolean("did_create_and_initialize_first_output_surface",
262 did_create_and_initialize_first_output_surface_);
263 minor_state->SetBoolean("smoothness_takes_priority",
264 smoothness_takes_priority_);
265 minor_state->SetBoolean("main_thread_is_in_high_latency_mode",
266 MainThreadIsInHighLatencyMode());
267 minor_state->SetBoolean("skip_begin_main_frame_to_reduce_latency",
268 skip_begin_main_frame_to_reduce_latency_);
269 state->Set("minor_state", minor_state.release());
271 return state.PassAs<base::Value>();
274 void SchedulerStateMachine::AdvanceCurrentFrameNumber() {
275 current_frame_number_++;
277 // "Drain" the ManageTiles funnel.
278 if (manage_tiles_funnel_ > 0)
279 manage_tiles_funnel_--;
282 bool SchedulerStateMachine::HasSentBeginMainFrameThisFrame() const {
283 return current_frame_number_ ==
284 last_frame_number_begin_main_frame_sent_;
287 bool SchedulerStateMachine::HasUpdatedVisibleTilesThisFrame() const {
288 return current_frame_number_ ==
289 last_frame_number_update_visible_tiles_was_called_;
292 bool SchedulerStateMachine::HasSwappedThisFrame() const {
293 return current_frame_number_ == last_frame_number_swap_performed_;
296 bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const {
297 // These are all the cases where we normally cannot or do not want to draw
298 // but, if needs_redraw_ is true and we do not draw to make forward progress,
299 // we might deadlock with the main thread.
300 // This should be a superset of PendingActivationsShouldBeForced() since
301 // activation of the pending tree is blocked by drawing of the active tree and
302 // the main thread might be blocked on activation of the most recent commit.
303 if (PendingActivationsShouldBeForced())
306 // Additional states where we should abort draws.
307 // Note: We don't force activation in these cases because doing so would
308 // result in checkerboarding on resize, becoming visible, etc.
316 bool SchedulerStateMachine::PendingActivationsShouldBeForced() const {
317 // These are all the cases where, if we do not force activations to make
318 // forward progress, we might deadlock with the main thread.
320 // The impl thread cannot lock layer textures unless the pending
321 // tree can be activated to unblock the commit.
322 if (texture_state_ == LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD)
325 // There is no output surface to trigger our activations.
326 if (output_surface_state_ == OUTPUT_SURFACE_LOST)
332 bool SchedulerStateMachine::ShouldBeginOutputSurfaceCreation() const {
333 // Don't try to initialize too early.
337 // We only want to start output surface initialization after the
338 // previous commit is complete.
339 if (commit_state_ != COMMIT_STATE_IDLE)
342 // We want to clear the pipline of any pending draws and activations
343 // before starting output surface initialization. This allows us to avoid
344 // weird corner cases where we abort draws or force activation while we
345 // are initializing the output surface and can potentially have a pending
347 if (active_tree_needs_first_draw_ || has_pending_tree_)
350 // We need to create the output surface if we don't have one and we haven't
351 // started creating one yet.
352 return output_surface_state_ == OUTPUT_SURFACE_LOST;
355 bool SchedulerStateMachine::ShouldDraw() const {
356 // After a readback, make sure not to draw again until we've replaced the
357 // readback commit with a real one.
358 if (readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT ||
359 readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION)
362 // Draw immediately for readbacks to unblock the main thread quickly.
363 if (readback_state_ == READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK) {
364 DCHECK_EQ(commit_state_, COMMIT_STATE_WAITING_FOR_FIRST_DRAW);
368 // If we need to abort draws, we should do so ASAP since the draw could
369 // be blocking other important actions (like output surface initialization),
370 // from occuring. If we are waiting for the first draw, then perfom the
371 // aborted draw to keep things moving. If we are not waiting for the first
372 // draw however, we don't want to abort for no reason.
373 if (PendingDrawsShouldBeAborted())
374 return active_tree_needs_first_draw_;
376 // After this line, we only want to swap once per frame.
377 if (HasSwappedThisFrame())
380 // Except for the cases above, do not draw outside of the BeginImplFrame
382 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
385 // Only handle forced redraws due to timeouts on the regular deadline.
386 if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW) {
387 DCHECK_EQ(commit_state_, COMMIT_STATE_WAITING_FOR_FIRST_DRAW);
391 return needs_redraw_;
394 bool SchedulerStateMachine::ShouldAcquireLayerTexturesForMainThread() const {
395 if (!main_thread_needs_layer_textures_)
397 if (texture_state_ == LAYER_TEXTURE_STATE_UNLOCKED)
399 DCHECK_EQ(texture_state_, LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD);
403 bool SchedulerStateMachine::ShouldActivatePendingTree() const {
404 // There is nothing to activate.
405 if (!has_pending_tree_)
408 // We should not activate a second tree before drawing the first one.
409 // Even if we need to force activation of the pending tree, we should abort
410 // drawing the active tree first.
411 if (active_tree_needs_first_draw_)
414 // If we want to force activation, do so ASAP.
415 if (PendingActivationsShouldBeForced())
418 // At this point, only activate if we are ready to activate.
419 return pending_tree_is_ready_for_activation_;
422 bool SchedulerStateMachine::ShouldUpdateVisibleTiles() const {
423 if (!settings_.impl_side_painting)
425 if (HasUpdatedVisibleTilesThisFrame())
428 // There's no reason to check for tiles if we don't have an output surface.
429 if (!HasInitializedOutputSurface())
432 // We should not check for visible tiles until we've entered the deadline so
433 // we check as late as possible and give the tiles more time to initialize.
434 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
437 // If the last swap drew with checkerboard or missing tiles, we should
438 // poll for any new visible tiles so we can be notified to draw again
440 if (swap_used_incomplete_tile_)
446 bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
450 // Only send BeginMainFrame when there isn't another commit pending already.
451 if (commit_state_ != COMMIT_STATE_IDLE)
454 // We can't accept a commit if we have a pending tree.
455 if (has_pending_tree_)
458 // We want to handle readback commits immediately to unblock the main thread.
459 // Note: This BeginMainFrame will correspond to the replacement commit that
460 // comes after the readback commit itself, so we only send the BeginMainFrame
461 // if a commit isn't already pending behind the readback.
462 if (readback_state_ == READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME)
463 return !CommitPending();
465 // We do not need commits if we are not visible, unless there's a
466 // request for a readback.
470 // We want to start the first commit after we get a new output surface ASAP.
471 if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT)
474 // With deadline scheduling enabled, we should not send BeginMainFrame while
475 // we are in BEGIN_IMPL_FRAME_STATE_IDLE, since we might have new user input
477 // However, if we are not expecting a BeginImplFrame to take us out of idle,
478 // we should not early out here to avoid blocking commits forever.
479 // This only works well when deadline scheduling is enabled because there is
480 // an interval over which to accept the commit and draw. Without deadline
481 // scheduling, delaying the commit could prevent us from having something
482 // to draw on the next BeginImplFrame.
483 // TODO(brianderson): Allow sending BeginMainFrame while idle when the main
484 // thread isn't consuming user input.
485 if (settings_.deadline_scheduling_enabled &&
486 begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_IDLE &&
487 BeginImplFrameNeeded())
490 // We need a new commit for the forced redraw. This honors the
491 // single commit per interval because the result will be swapped to screen.
492 if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT)
495 // After this point, we only start a commit once per frame.
496 if (HasSentBeginMainFrameThisFrame())
499 // We shouldn't normally accept commits if there isn't an OutputSurface.
500 if (!HasInitializedOutputSurface())
503 if (skip_begin_main_frame_to_reduce_latency_)
509 bool SchedulerStateMachine::ShouldCommit() const {
510 return commit_state_ == COMMIT_STATE_READY_TO_COMMIT;
513 bool SchedulerStateMachine::IsCommitStateWaiting() const {
514 return commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS;
517 bool SchedulerStateMachine::ShouldManageTiles() const {
518 // ManageTiles only really needs to be called immediately after commit
519 // and then periodically after that. Use a funnel to make sure we average
520 // one ManageTiles per BeginImplFrame in the long run.
521 if (manage_tiles_funnel_ > 0)
524 // Limiting to once per-frame is not enough, since we only want to
525 // manage tiles _after_ draws. Polling for draw triggers and
526 // begin-frame are mutually exclusive, so we limit to these two cases.
527 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE &&
528 !inside_poll_for_anticipated_draw_triggers_)
530 return needs_manage_tiles_;
533 SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
534 if (ShouldAcquireLayerTexturesForMainThread())
535 return ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD;
536 if (ShouldUpdateVisibleTiles())
537 return ACTION_UPDATE_VISIBLE_TILES;
538 if (ShouldActivatePendingTree())
539 return ACTION_ACTIVATE_PENDING_TREE;
541 return ACTION_COMMIT;
543 if (readback_state_ == READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK)
544 return ACTION_DRAW_AND_READBACK;
545 else if (PendingDrawsShouldBeAborted())
546 return ACTION_DRAW_AND_SWAP_ABORT;
547 else if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
548 return ACTION_DRAW_AND_SWAP_FORCED;
550 return ACTION_DRAW_AND_SWAP_IF_POSSIBLE;
552 if (ShouldManageTiles())
553 return ACTION_MANAGE_TILES;
554 if (ShouldSendBeginMainFrame())
555 return ACTION_SEND_BEGIN_MAIN_FRAME;
556 if (ShouldBeginOutputSurfaceCreation())
557 return ACTION_BEGIN_OUTPUT_SURFACE_CREATION;
561 void SchedulerStateMachine::CheckInvariants() {
562 // We should never try to perform a draw for readback and forced draw due to
563 // timeout simultaneously.
564 DCHECK(!(forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW &&
565 readback_state_ == READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK));
568 void SchedulerStateMachine::UpdateState(Action action) {
573 case ACTION_UPDATE_VISIBLE_TILES:
574 last_frame_number_update_visible_tiles_was_called_ =
575 current_frame_number_;
578 case ACTION_ACTIVATE_PENDING_TREE:
579 UpdateStateOnActivation();
582 case ACTION_SEND_BEGIN_MAIN_FRAME:
583 DCHECK(!has_pending_tree_);
585 readback_state_ == READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME);
586 commit_state_ = COMMIT_STATE_FRAME_IN_PROGRESS;
587 needs_commit_ = false;
588 if (readback_state_ == READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME)
589 readback_state_ = READBACK_STATE_WAITING_FOR_COMMIT;
590 last_frame_number_begin_main_frame_sent_ =
591 current_frame_number_;
594 case ACTION_COMMIT: {
595 bool commit_was_aborted = false;
596 UpdateStateOnCommit(commit_was_aborted);
600 case ACTION_DRAW_AND_SWAP_FORCED:
601 case ACTION_DRAW_AND_SWAP_IF_POSSIBLE: {
602 bool did_swap = true;
603 UpdateStateOnDraw(did_swap);
607 case ACTION_DRAW_AND_SWAP_ABORT:
608 case ACTION_DRAW_AND_READBACK: {
609 bool did_swap = false;
610 UpdateStateOnDraw(did_swap);
614 case ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
615 DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_LOST);
616 output_surface_state_ = OUTPUT_SURFACE_CREATING;
618 // The following DCHECKs make sure we are in the proper quiescent state.
619 // The pipeline should be flushed entirely before we start output
620 // surface creation to avoid complicated corner cases.
621 DCHECK_EQ(commit_state_, COMMIT_STATE_IDLE);
622 DCHECK(!has_pending_tree_);
623 DCHECK(!active_tree_needs_first_draw_);
626 case ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD:
627 texture_state_ = LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD;
628 main_thread_needs_layer_textures_ = false;
631 case ACTION_MANAGE_TILES:
632 UpdateStateOnManageTiles();
637 void SchedulerStateMachine::UpdateStateOnCommit(bool commit_was_aborted) {
640 // If we are impl-side-painting but the commit was aborted, then we behave
641 // mostly as if we are not impl-side-painting since there is no pending tree.
642 has_pending_tree_ = settings_.impl_side_painting && !commit_was_aborted;
644 // Update state related to readbacks.
645 if (readback_state_ == READBACK_STATE_WAITING_FOR_COMMIT) {
646 // Update the state if this is the readback commit.
647 readback_state_ = has_pending_tree_
648 ? READBACK_STATE_WAITING_FOR_ACTIVATION
649 : READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK;
650 } else if (readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT) {
651 // Update the state if this is the commit replacing the readback commit.
652 readback_state_ = has_pending_tree_
653 ? READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION
654 : READBACK_STATE_IDLE;
656 DCHECK(readback_state_ == READBACK_STATE_IDLE);
659 // Readbacks can interrupt output surface initialization and forced draws,
660 // so we do not want to advance those states if we are in the middle of a
661 // readback. Note: It is possible for the readback's replacement commit to
662 // be the output surface's first commit and/or the forced redraw's commit.
663 if (readback_state_ == READBACK_STATE_IDLE ||
664 readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION) {
665 // Update state related to forced draws.
666 if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT) {
667 forced_redraw_state_ = has_pending_tree_
668 ? FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION
669 : FORCED_REDRAW_STATE_WAITING_FOR_DRAW;
672 // Update the output surface state.
673 DCHECK_NE(output_surface_state_,
674 OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION);
675 if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT) {
676 if (has_pending_tree_) {
677 output_surface_state_ = OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION;
679 output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
680 needs_redraw_ = true;
685 // Update the commit state. We expect and wait for a draw if the commit
686 // was not aborted or if we are in a readback or forced draw.
687 if (!commit_was_aborted) {
688 DCHECK(commit_state_ == COMMIT_STATE_READY_TO_COMMIT);
689 commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_DRAW;
690 } else if (readback_state_ != READBACK_STATE_IDLE ||
691 forced_redraw_state_ != FORCED_REDRAW_STATE_IDLE) {
692 commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_DRAW;
694 commit_state_ = COMMIT_STATE_IDLE;
697 // Update state if we have a new active tree to draw, or if the active tree
698 // was unchanged but we need to do a readback or forced draw.
699 if (!has_pending_tree_ &&
700 (!commit_was_aborted ||
701 readback_state_ == READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK ||
702 forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)) {
703 needs_redraw_ = true;
704 active_tree_needs_first_draw_ = true;
707 // This post-commit work is common to both completed and aborted commits.
708 pending_tree_is_ready_for_activation_ = false;
710 if (draw_if_possible_failed_)
711 last_frame_number_swap_performed_ = -1;
713 // If we are planing to draw with the new commit, lock the layer textures for
714 // use on the impl thread. Otherwise, leave them unlocked.
715 if (has_pending_tree_ || needs_redraw_)
716 texture_state_ = LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD;
718 texture_state_ = LAYER_TEXTURE_STATE_UNLOCKED;
721 void SchedulerStateMachine::UpdateStateOnActivation() {
722 // Update output surface state.
723 if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION)
724 output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
726 // Update readback state
727 if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION)
728 forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_DRAW;
730 // Update forced redraw state
731 if (readback_state_ == READBACK_STATE_WAITING_FOR_ACTIVATION)
732 readback_state_ = READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK;
733 else if (readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION)
734 readback_state_ = READBACK_STATE_IDLE;
736 has_pending_tree_ = false;
737 pending_tree_is_ready_for_activation_ = false;
738 active_tree_needs_first_draw_ = true;
739 needs_redraw_ = true;
742 void SchedulerStateMachine::UpdateStateOnDraw(bool did_swap) {
743 DCHECK(readback_state_ != READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT &&
744 readback_state_ != READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION)
747 if (readback_state_ == READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK) {
748 // The draw correspons to a readback commit.
749 DCHECK_EQ(commit_state_, COMMIT_STATE_WAITING_FOR_FIRST_DRAW);
750 // We are blocking commits from the main thread until after this draw, so
751 // we should not have a pending tree.
752 DCHECK(!has_pending_tree_);
753 // We transition to COMMIT_STATE_FRAME_IN_PROGRESS because there is a
754 // pending BeginMainFrame behind the readback request.
755 commit_state_ = COMMIT_STATE_FRAME_IN_PROGRESS;
756 readback_state_ = READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT;
757 } else if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW) {
758 DCHECK_EQ(commit_state_, COMMIT_STATE_WAITING_FOR_FIRST_DRAW);
759 commit_state_ = COMMIT_STATE_IDLE;
760 forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE;
761 } else if (commit_state_ == COMMIT_STATE_WAITING_FOR_FIRST_DRAW &&
762 !has_pending_tree_) {
763 commit_state_ = COMMIT_STATE_IDLE;
766 if (texture_state_ == LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD)
767 texture_state_ = LAYER_TEXTURE_STATE_UNLOCKED;
769 needs_redraw_ = false;
770 draw_if_possible_failed_ = false;
771 active_tree_needs_first_draw_ = false;
774 last_frame_number_swap_performed_ = current_frame_number_;
777 void SchedulerStateMachine::UpdateStateOnManageTiles() {
778 needs_manage_tiles_ = false;
781 void SchedulerStateMachine::SetMainThreadNeedsLayerTextures() {
782 DCHECK(!main_thread_needs_layer_textures_);
783 DCHECK_NE(texture_state_, LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD);
784 main_thread_needs_layer_textures_ = true;
787 void SchedulerStateMachine::SetSkipBeginMainFrameToReduceLatency(bool skip) {
788 skip_begin_main_frame_to_reduce_latency_ = skip;
791 bool SchedulerStateMachine::BeginImplFrameNeeded() const {
792 // Proactive BeginImplFrames are bad for the synchronous compositor because we
793 // have to draw when we get the BeginImplFrame and could end up drawing many
794 // duplicate frames if our new frame isn't ready in time.
795 // To poll for state with the synchronous compositor without having to draw,
796 // we rely on ShouldPollForAnticipatedDrawTriggers instead.
797 if (!SupportsProactiveBeginImplFrame())
798 return BeginImplFrameNeededToDraw();
800 return BeginImplFrameNeededToDraw() ||
801 ProactiveBeginImplFrameWanted();
804 bool SchedulerStateMachine::ShouldPollForAnticipatedDrawTriggers() const {
805 // ShouldPollForAnticipatedDrawTriggers is what we use in place of
806 // ProactiveBeginImplFrameWanted when we are using the synchronous
808 if (!SupportsProactiveBeginImplFrame()) {
809 return !BeginImplFrameNeededToDraw() &&
810 ProactiveBeginImplFrameWanted();
813 // Non synchronous compositors should rely on
814 // ProactiveBeginImplFrameWanted to poll for state instead.
818 bool SchedulerStateMachine::SupportsProactiveBeginImplFrame() const {
819 // Both the synchronous compositor and disabled vsync settings
820 // make it undesirable to proactively request BeginImplFrames.
821 // If this is true, the scheduler should poll.
822 return !settings_.using_synchronous_renderer_compositor &&
823 settings_.throttle_frame_production;
826 // These are the cases where we definitely (or almost definitely) have a
827 // new frame to draw and can draw.
828 bool SchedulerStateMachine::BeginImplFrameNeededToDraw() const {
829 // The output surface is the provider of BeginImplFrames, so we are not going
830 // to get them even if we ask for them.
831 if (!HasInitializedOutputSurface())
834 // If we can't draw, don't tick until we are notified that we can draw again.
838 // The forced draw respects our normal draw scheduling, so we need to
839 // request a BeginImplFrame for it.
840 if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
843 // There's no need to produce frames if we are not visible.
847 // We need to draw a more complete frame than we did the last BeginImplFrame,
848 // so request another BeginImplFrame in anticipation that we will have
849 // additional visible tiles.
850 if (swap_used_incomplete_tile_)
853 return needs_redraw_;
856 // These are cases where we are very likely to draw soon, but might not
857 // actually have a new frame to draw when we receive the next BeginImplFrame.
858 // Proactively requesting the BeginImplFrame helps hide the round trip latency
859 // of the SetNeedsBeginImplFrame request that has to go to the Browser.
860 bool SchedulerStateMachine::ProactiveBeginImplFrameWanted() const {
861 // The output surface is the provider of BeginImplFrames,
862 // so we are not going to get them even if we ask for them.
863 if (!HasInitializedOutputSurface())
866 // Do not be proactive when invisible.
870 // We should proactively request a BeginImplFrame if a commit is pending
871 // because we will want to draw if the commit completes quickly.
872 if (needs_commit_ || commit_state_ != COMMIT_STATE_IDLE)
875 // If the pending tree activates quickly, we'll want a BeginImplFrame soon
876 // to draw the new active tree.
877 if (has_pending_tree_)
880 // Changing priorities may allow us to activate (given the new priorities),
881 // which may result in a new frame.
882 if (needs_manage_tiles_)
885 // If we just swapped, it's likely that we are going to produce another
886 // frame soon. This helps avoid negative glitches in our
887 // SetNeedsBeginImplFrame requests, which may propagate to the BeginImplFrame
888 // provider and get sampled at an inopportune time, delaying the next
890 if (last_frame_number_swap_performed_ == current_frame_number_)
896 void SchedulerStateMachine::OnBeginImplFrame(const BeginFrameArgs& args) {
897 AdvanceCurrentFrameNumber();
898 last_begin_impl_frame_args_ = args;
899 DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_IDLE) << *AsValue();
900 begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING;
903 void SchedulerStateMachine::OnBeginImplFrameDeadlinePending() {
904 DCHECK_EQ(begin_impl_frame_state_,
905 BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING)
907 begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME;
910 void SchedulerStateMachine::OnBeginImplFrameDeadline() {
911 DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
913 begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE;
916 void SchedulerStateMachine::OnBeginImplFrameIdle() {
917 DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
919 begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_IDLE;
922 bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineEarly() const {
923 // TODO(brianderson): This should take into account multiple commit sources.
925 // If we are in the middle of the readback, we won't swap, so there is
926 // no reason to trigger the deadline early.
927 if (readback_state_ != READBACK_STATE_IDLE)
930 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
933 if (active_tree_needs_first_draw_)
939 // This is used to prioritize impl-thread draws when the main thread isn't
940 // producing anything, e.g., after an aborted commit. We also check that we
941 // don't have a pending tree -- otherwise we should give it a chance to
943 // TODO(skyostil): Revisit this when we have more accurate deadline estimates.
944 if (commit_state_ == COMMIT_STATE_IDLE && !has_pending_tree_)
947 // Prioritize impl-thread draws in smoothness mode.
948 if (smoothness_takes_priority_)
954 bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const {
955 // If we just sent a BeginMainFrame and haven't hit the deadline yet, the main
956 // thread is in a low latency mode.
957 if (last_frame_number_begin_main_frame_sent_ == current_frame_number_ &&
958 (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING ||
959 begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME))
962 // If there's a commit in progress it must either be from the previous frame
963 // or it started after the impl thread's deadline. In either case the main
964 // thread is in high latency mode.
965 if (commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS ||
966 commit_state_ == COMMIT_STATE_READY_TO_COMMIT)
969 // Similarly, if there's a pending tree the main thread is in high latency
970 // mode, because either
971 // it's from the previous frame
973 // we're currently drawing the active tree and the pending tree will thus
974 // only be drawn in the next frame.
975 if (has_pending_tree_)
978 if (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) {
979 // Even if there's a new active tree to draw at the deadline or we've just
980 // drawn it, it may have been triggered by a previous BeginImplFrame, in
981 // which case the main thread is in a high latency mode.
982 return (active_tree_needs_first_draw_ ||
983 last_frame_number_swap_performed_ == current_frame_number_) &&
984 last_frame_number_begin_main_frame_sent_ != current_frame_number_;
987 // If the active tree needs its first draw in any other state, we know the
988 // main thread is in a high latency mode.
989 return active_tree_needs_first_draw_;
992 void SchedulerStateMachine::DidEnterPollForAnticipatedDrawTriggers() {
993 AdvanceCurrentFrameNumber();
994 inside_poll_for_anticipated_draw_triggers_ = true;
997 void SchedulerStateMachine::DidLeavePollForAnticipatedDrawTriggers() {
998 inside_poll_for_anticipated_draw_triggers_ = false;
1001 void SchedulerStateMachine::SetVisible(bool visible) { visible_ = visible; }
1003 void SchedulerStateMachine::SetCanDraw(bool can_draw) { can_draw_ = can_draw; }
1005 void SchedulerStateMachine::SetNeedsRedraw() { needs_redraw_ = true; }
1007 void SchedulerStateMachine::SetNeedsManageTiles() {
1008 if (!needs_manage_tiles_) {
1010 "SchedulerStateMachine::SetNeedsManageTiles");
1011 needs_manage_tiles_ = true;
1015 void SchedulerStateMachine::SetSwapUsedIncompleteTile(
1016 bool used_incomplete_tile) {
1017 swap_used_incomplete_tile_ = used_incomplete_tile;
1020 void SchedulerStateMachine::SetSmoothnessTakesPriority(
1021 bool smoothness_takes_priority) {
1022 smoothness_takes_priority_ = smoothness_takes_priority;
1025 void SchedulerStateMachine::DidDrawIfPossibleCompleted(bool success) {
1026 draw_if_possible_failed_ = !success;
1027 if (draw_if_possible_failed_) {
1028 needs_redraw_ = true;
1030 // If we're already in the middle of a redraw, we don't need to
1032 if (forced_redraw_state_ != FORCED_REDRAW_STATE_IDLE)
1035 needs_commit_ = true;
1036 consecutive_failed_draws_++;
1037 if (settings_.timeout_and_draw_when_animation_checkerboards &&
1038 consecutive_failed_draws_ >=
1039 settings_.maximum_number_of_failed_draws_before_draw_is_forced_) {
1040 consecutive_failed_draws_ = 0;
1041 // We need to force a draw, but it doesn't make sense to do this until
1042 // we've committed and have new textures.
1043 forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_COMMIT;
1046 consecutive_failed_draws_ = 0;
1047 forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE;
1051 void SchedulerStateMachine::SetNeedsCommit() { needs_commit_ = true; }
1053 void SchedulerStateMachine::SetNeedsForcedCommitForReadback() {
1054 // If this is called in READBACK_STATE_IDLE, this is a "first" readback
1056 // If this is called in READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT, this
1057 // is a back-to-back readback request that started before the replacement
1058 // commit had a chance to land.
1059 DCHECK(readback_state_ == READBACK_STATE_IDLE ||
1060 readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT);
1062 // If there is already a commit in progress when we get the readback request
1063 // (we are in COMMIT_STATE_FRAME_IN_PROGRESS), then we don't need to send a
1064 // BeginMainFrame for the replacement commit, since there's already a
1065 // BeginMainFrame behind the readback request. In that case, we can skip
1066 // READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME and go directly to
1067 // READBACK_STATE_WAITING_FOR_COMMIT
1068 if (commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS)
1069 readback_state_ = READBACK_STATE_WAITING_FOR_COMMIT;
1071 readback_state_ = READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME;
1074 void SchedulerStateMachine::FinishCommit() {
1075 DCHECK(commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS) << *AsValue();
1076 commit_state_ = COMMIT_STATE_READY_TO_COMMIT;
1079 void SchedulerStateMachine::BeginMainFrameAborted(bool did_handle) {
1080 DCHECK_EQ(commit_state_, COMMIT_STATE_FRAME_IN_PROGRESS);
1082 bool commit_was_aborted = true;
1083 UpdateStateOnCommit(commit_was_aborted);
1085 DCHECK_NE(readback_state_, READBACK_STATE_WAITING_FOR_COMMIT);
1086 commit_state_ = COMMIT_STATE_IDLE;
1091 void SchedulerStateMachine::DidManageTiles() {
1092 needs_manage_tiles_ = false;
1093 // "Fill" the ManageTiles funnel.
1094 manage_tiles_funnel_++;
1097 void SchedulerStateMachine::DidLoseOutputSurface() {
1098 if (output_surface_state_ == OUTPUT_SURFACE_LOST ||
1099 output_surface_state_ == OUTPUT_SURFACE_CREATING)
1101 output_surface_state_ = OUTPUT_SURFACE_LOST;
1102 needs_redraw_ = false;
1103 begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_IDLE;
1106 void SchedulerStateMachine::NotifyReadyToActivate() {
1107 if (has_pending_tree_)
1108 pending_tree_is_ready_for_activation_ = true;
1111 void SchedulerStateMachine::DidCreateAndInitializeOutputSurface() {
1112 DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_CREATING);
1113 output_surface_state_ = OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT;
1115 if (did_create_and_initialize_first_output_surface_) {
1116 // TODO(boliu): See if we can remove this when impl-side painting is always
1117 // on. Does anything on the main thread need to update after recreate?
1118 needs_commit_ = true;
1120 did_create_and_initialize_first_output_surface_ = true;
1123 bool SchedulerStateMachine::HasInitializedOutputSurface() const {
1124 switch (output_surface_state_) {
1125 case OUTPUT_SURFACE_LOST:
1126 case OUTPUT_SURFACE_CREATING:
1129 case OUTPUT_SURFACE_ACTIVE:
1130 case OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT:
1131 case OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION: