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_checkerboard_animations_(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_checkerboard_animations",
244 consecutive_checkerboard_animations_);
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 // Make sure the BeginImplFrame from any previous OutputSurfaces
343 // are complete before creating the new OutputSurface.
344 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_IDLE)
347 // We want to clear the pipline of any pending draws and activations
348 // before starting output surface initialization. This allows us to avoid
349 // weird corner cases where we abort draws or force activation while we
350 // are initializing the output surface and can potentially have a pending
352 if (active_tree_needs_first_draw_ || has_pending_tree_)
355 // We need to create the output surface if we don't have one and we haven't
356 // started creating one yet.
357 return output_surface_state_ == OUTPUT_SURFACE_LOST;
360 bool SchedulerStateMachine::ShouldDraw() const {
361 // After a readback, make sure not to draw again until we've replaced the
362 // readback commit with a real one.
363 if (readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT ||
364 readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION)
367 // Draw immediately for readbacks to unblock the main thread quickly.
368 if (readback_state_ == READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK) {
369 DCHECK_EQ(commit_state_, COMMIT_STATE_WAITING_FOR_FIRST_DRAW);
373 // If we need to abort draws, we should do so ASAP since the draw could
374 // be blocking other important actions (like output surface initialization),
375 // from occuring. If we are waiting for the first draw, then perfom the
376 // aborted draw to keep things moving. If we are not waiting for the first
377 // draw however, we don't want to abort for no reason.
378 if (PendingDrawsShouldBeAborted())
379 return active_tree_needs_first_draw_;
381 // After this line, we only want to swap once per frame.
382 if (HasSwappedThisFrame())
385 // Except for the cases above, do not draw outside of the BeginImplFrame
387 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
390 // Only handle forced redraws due to timeouts on the regular deadline.
391 if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW) {
392 DCHECK_EQ(commit_state_, COMMIT_STATE_WAITING_FOR_FIRST_DRAW);
396 return needs_redraw_;
399 bool SchedulerStateMachine::ShouldAcquireLayerTexturesForMainThread() const {
400 if (!main_thread_needs_layer_textures_)
402 if (texture_state_ == LAYER_TEXTURE_STATE_UNLOCKED)
404 DCHECK_EQ(texture_state_, LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD);
408 bool SchedulerStateMachine::ShouldActivatePendingTree() const {
409 // There is nothing to activate.
410 if (!has_pending_tree_)
413 // We should not activate a second tree before drawing the first one.
414 // Even if we need to force activation of the pending tree, we should abort
415 // drawing the active tree first.
416 if (active_tree_needs_first_draw_)
419 // If we want to force activation, do so ASAP.
420 if (PendingActivationsShouldBeForced())
423 // At this point, only activate if we are ready to activate.
424 return pending_tree_is_ready_for_activation_;
427 bool SchedulerStateMachine::ShouldUpdateVisibleTiles() const {
428 if (!settings_.impl_side_painting)
430 if (HasUpdatedVisibleTilesThisFrame())
433 // There's no reason to check for tiles if we don't have an output surface.
434 if (!HasInitializedOutputSurface())
437 // We should not check for visible tiles until we've entered the deadline so
438 // we check as late as possible and give the tiles more time to initialize.
439 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
442 // If the last swap drew with checkerboard or missing tiles, we should
443 // poll for any new visible tiles so we can be notified to draw again
445 if (swap_used_incomplete_tile_)
451 bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
455 // Only send BeginMainFrame when there isn't another commit pending already.
456 if (commit_state_ != COMMIT_STATE_IDLE)
459 // We can't accept a commit if we have a pending tree.
460 if (has_pending_tree_)
463 // We want to handle readback commits immediately to unblock the main thread.
464 // Note: This BeginMainFrame will correspond to the replacement commit that
465 // comes after the readback commit itself, so we only send the BeginMainFrame
466 // if a commit isn't already pending behind the readback.
467 if (readback_state_ == READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME)
468 return !CommitPending();
470 // We do not need commits if we are not visible, unless there's a
471 // request for a readback.
475 // We want to start the first commit after we get a new output surface ASAP.
476 if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT)
479 // With deadline scheduling enabled, we should not send BeginMainFrame while
480 // we are in BEGIN_IMPL_FRAME_STATE_IDLE, since we might have new user input
482 // However, if we are not expecting a BeginImplFrame to take us out of idle,
483 // we should not early out here to avoid blocking commits forever.
484 // This only works well when deadline scheduling is enabled because there is
485 // an interval over which to accept the commit and draw. Without deadline
486 // scheduling, delaying the commit could prevent us from having something
487 // to draw on the next BeginImplFrame.
488 // TODO(brianderson): Allow sending BeginMainFrame while idle when the main
489 // thread isn't consuming user input.
490 if (settings_.deadline_scheduling_enabled &&
491 begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_IDLE &&
492 BeginImplFrameNeeded())
495 // We need a new commit for the forced redraw. This honors the
496 // single commit per interval because the result will be swapped to screen.
497 if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT)
500 // After this point, we only start a commit once per frame.
501 if (HasSentBeginMainFrameThisFrame())
504 // We shouldn't normally accept commits if there isn't an OutputSurface.
505 if (!HasInitializedOutputSurface())
508 if (skip_begin_main_frame_to_reduce_latency_)
514 bool SchedulerStateMachine::ShouldCommit() const {
515 return commit_state_ == COMMIT_STATE_READY_TO_COMMIT;
518 bool SchedulerStateMachine::IsCommitStateWaiting() const {
519 return commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS;
522 bool SchedulerStateMachine::ShouldManageTiles() const {
523 // ManageTiles only really needs to be called immediately after commit
524 // and then periodically after that. Use a funnel to make sure we average
525 // one ManageTiles per BeginImplFrame in the long run.
526 if (manage_tiles_funnel_ > 0)
529 // Limiting to once per-frame is not enough, since we only want to
530 // manage tiles _after_ draws. Polling for draw triggers and
531 // begin-frame are mutually exclusive, so we limit to these two cases.
532 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE &&
533 !inside_poll_for_anticipated_draw_triggers_)
535 return needs_manage_tiles_;
538 SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
539 if (ShouldAcquireLayerTexturesForMainThread())
540 return ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD;
541 if (ShouldUpdateVisibleTiles())
542 return ACTION_UPDATE_VISIBLE_TILES;
543 if (ShouldActivatePendingTree())
544 return ACTION_ACTIVATE_PENDING_TREE;
546 return ACTION_COMMIT;
548 if (readback_state_ == READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK)
549 return ACTION_DRAW_AND_READBACK;
550 else if (PendingDrawsShouldBeAborted())
551 return ACTION_DRAW_AND_SWAP_ABORT;
552 else if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
553 return ACTION_DRAW_AND_SWAP_FORCED;
555 return ACTION_DRAW_AND_SWAP_IF_POSSIBLE;
557 if (ShouldManageTiles())
558 return ACTION_MANAGE_TILES;
559 if (ShouldSendBeginMainFrame())
560 return ACTION_SEND_BEGIN_MAIN_FRAME;
561 if (ShouldBeginOutputSurfaceCreation())
562 return ACTION_BEGIN_OUTPUT_SURFACE_CREATION;
566 void SchedulerStateMachine::CheckInvariants() {
567 // We should never try to perform a draw for readback and forced draw due to
568 // timeout simultaneously.
569 DCHECK(!(forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW &&
570 readback_state_ == READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK));
573 void SchedulerStateMachine::UpdateState(Action action) {
578 case ACTION_UPDATE_VISIBLE_TILES:
579 last_frame_number_update_visible_tiles_was_called_ =
580 current_frame_number_;
583 case ACTION_ACTIVATE_PENDING_TREE:
584 UpdateStateOnActivation();
587 case ACTION_SEND_BEGIN_MAIN_FRAME:
588 DCHECK(!has_pending_tree_);
590 readback_state_ == READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME);
591 commit_state_ = COMMIT_STATE_FRAME_IN_PROGRESS;
592 needs_commit_ = false;
593 if (readback_state_ == READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME)
594 readback_state_ = READBACK_STATE_WAITING_FOR_COMMIT;
595 last_frame_number_begin_main_frame_sent_ =
596 current_frame_number_;
599 case ACTION_COMMIT: {
600 bool commit_was_aborted = false;
601 UpdateStateOnCommit(commit_was_aborted);
605 case ACTION_DRAW_AND_SWAP_FORCED:
606 case ACTION_DRAW_AND_SWAP_IF_POSSIBLE: {
607 bool did_swap = true;
608 UpdateStateOnDraw(did_swap);
612 case ACTION_DRAW_AND_SWAP_ABORT:
613 case ACTION_DRAW_AND_READBACK: {
614 bool did_swap = false;
615 UpdateStateOnDraw(did_swap);
619 case ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
620 DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_LOST);
621 output_surface_state_ = OUTPUT_SURFACE_CREATING;
623 // The following DCHECKs make sure we are in the proper quiescent state.
624 // The pipeline should be flushed entirely before we start output
625 // surface creation to avoid complicated corner cases.
626 DCHECK_EQ(commit_state_, COMMIT_STATE_IDLE);
627 DCHECK(!has_pending_tree_);
628 DCHECK(!active_tree_needs_first_draw_);
631 case ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD:
632 texture_state_ = LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD;
633 main_thread_needs_layer_textures_ = false;
636 case ACTION_MANAGE_TILES:
637 UpdateStateOnManageTiles();
642 void SchedulerStateMachine::UpdateStateOnCommit(bool commit_was_aborted) {
645 // If we are impl-side-painting but the commit was aborted, then we behave
646 // mostly as if we are not impl-side-painting since there is no pending tree.
647 has_pending_tree_ = settings_.impl_side_painting && !commit_was_aborted;
649 // Update state related to readbacks.
650 if (readback_state_ == READBACK_STATE_WAITING_FOR_COMMIT) {
651 // Update the state if this is the readback commit.
652 readback_state_ = has_pending_tree_
653 ? READBACK_STATE_WAITING_FOR_ACTIVATION
654 : READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK;
655 } else if (readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT) {
656 // Update the state if this is the commit replacing the readback commit.
657 readback_state_ = has_pending_tree_
658 ? READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION
659 : READBACK_STATE_IDLE;
661 DCHECK(readback_state_ == READBACK_STATE_IDLE);
664 // Readbacks can interrupt output surface initialization and forced draws,
665 // so we do not want to advance those states if we are in the middle of a
666 // readback. Note: It is possible for the readback's replacement commit to
667 // be the output surface's first commit and/or the forced redraw's commit.
668 if (readback_state_ == READBACK_STATE_IDLE ||
669 readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION) {
670 // Update state related to forced draws.
671 if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT) {
672 forced_redraw_state_ = has_pending_tree_
673 ? FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION
674 : FORCED_REDRAW_STATE_WAITING_FOR_DRAW;
677 // Update the output surface state.
678 DCHECK_NE(output_surface_state_,
679 OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION);
680 if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT) {
681 if (has_pending_tree_) {
682 output_surface_state_ = OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION;
684 output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
685 needs_redraw_ = true;
690 // Update the commit state. We expect and wait for a draw if the commit
691 // was not aborted or if we are in a readback or forced draw.
692 if (!commit_was_aborted) {
693 DCHECK(commit_state_ == COMMIT_STATE_READY_TO_COMMIT);
694 commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_DRAW;
695 } else if (readback_state_ != READBACK_STATE_IDLE ||
696 forced_redraw_state_ != FORCED_REDRAW_STATE_IDLE) {
697 commit_state_ = COMMIT_STATE_WAITING_FOR_FIRST_DRAW;
699 commit_state_ = COMMIT_STATE_IDLE;
702 // Update state if we have a new active tree to draw, or if the active tree
703 // was unchanged but we need to do a readback or forced draw.
704 if (!has_pending_tree_ &&
705 (!commit_was_aborted ||
706 readback_state_ == READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK ||
707 forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)) {
708 needs_redraw_ = true;
709 active_tree_needs_first_draw_ = true;
712 // This post-commit work is common to both completed and aborted commits.
713 pending_tree_is_ready_for_activation_ = false;
715 if (draw_if_possible_failed_)
716 last_frame_number_swap_performed_ = -1;
718 // If we are planing to draw with the new commit, lock the layer textures for
719 // use on the impl thread. Otherwise, leave them unlocked.
720 if (has_pending_tree_ || needs_redraw_)
721 texture_state_ = LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD;
723 texture_state_ = LAYER_TEXTURE_STATE_UNLOCKED;
726 void SchedulerStateMachine::UpdateStateOnActivation() {
727 // Update output surface state.
728 if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION)
729 output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
731 // Update readback state
732 if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION)
733 forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_DRAW;
735 // Update forced redraw state
736 if (readback_state_ == READBACK_STATE_WAITING_FOR_ACTIVATION)
737 readback_state_ = READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK;
738 else if (readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION)
739 readback_state_ = READBACK_STATE_IDLE;
741 has_pending_tree_ = false;
742 pending_tree_is_ready_for_activation_ = false;
743 active_tree_needs_first_draw_ = true;
744 needs_redraw_ = true;
747 void SchedulerStateMachine::UpdateStateOnDraw(bool did_swap) {
748 DCHECK(readback_state_ != READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT &&
749 readback_state_ != READBACK_STATE_WAITING_FOR_REPLACEMENT_ACTIVATION)
752 if (readback_state_ == READBACK_STATE_WAITING_FOR_DRAW_AND_READBACK) {
753 // The draw correspons to a readback commit.
754 DCHECK_EQ(commit_state_, COMMIT_STATE_WAITING_FOR_FIRST_DRAW);
755 // We are blocking commits from the main thread until after this draw, so
756 // we should not have a pending tree.
757 DCHECK(!has_pending_tree_);
758 // We transition to COMMIT_STATE_FRAME_IN_PROGRESS because there is a
759 // pending BeginMainFrame behind the readback request.
760 commit_state_ = COMMIT_STATE_FRAME_IN_PROGRESS;
761 readback_state_ = READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT;
762 } else if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW) {
763 DCHECK_EQ(commit_state_, COMMIT_STATE_WAITING_FOR_FIRST_DRAW);
764 commit_state_ = COMMIT_STATE_IDLE;
765 forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE;
766 } else if (commit_state_ == COMMIT_STATE_WAITING_FOR_FIRST_DRAW &&
767 !has_pending_tree_) {
768 commit_state_ = COMMIT_STATE_IDLE;
771 if (texture_state_ == LAYER_TEXTURE_STATE_ACQUIRED_BY_IMPL_THREAD)
772 texture_state_ = LAYER_TEXTURE_STATE_UNLOCKED;
774 needs_redraw_ = false;
775 draw_if_possible_failed_ = false;
776 active_tree_needs_first_draw_ = false;
779 last_frame_number_swap_performed_ = current_frame_number_;
782 void SchedulerStateMachine::UpdateStateOnManageTiles() {
783 needs_manage_tiles_ = false;
786 void SchedulerStateMachine::SetMainThreadNeedsLayerTextures() {
787 DCHECK(!main_thread_needs_layer_textures_);
788 DCHECK_NE(texture_state_, LAYER_TEXTURE_STATE_ACQUIRED_BY_MAIN_THREAD);
789 main_thread_needs_layer_textures_ = true;
792 void SchedulerStateMachine::SetSkipBeginMainFrameToReduceLatency(bool skip) {
793 skip_begin_main_frame_to_reduce_latency_ = skip;
796 bool SchedulerStateMachine::BeginImplFrameNeeded() const {
797 // Proactive BeginImplFrames are bad for the synchronous compositor because we
798 // have to draw when we get the BeginImplFrame and could end up drawing many
799 // duplicate frames if our new frame isn't ready in time.
800 // To poll for state with the synchronous compositor without having to draw,
801 // we rely on ShouldPollForAnticipatedDrawTriggers instead.
802 if (!SupportsProactiveBeginImplFrame())
803 return BeginImplFrameNeededToDraw();
805 return BeginImplFrameNeededToDraw() ||
806 ProactiveBeginImplFrameWanted();
809 bool SchedulerStateMachine::ShouldPollForAnticipatedDrawTriggers() const {
810 // ShouldPollForAnticipatedDrawTriggers is what we use in place of
811 // ProactiveBeginImplFrameWanted when we are using the synchronous
813 if (!SupportsProactiveBeginImplFrame()) {
814 return !BeginImplFrameNeededToDraw() &&
815 ProactiveBeginImplFrameWanted();
818 // Non synchronous compositors should rely on
819 // ProactiveBeginImplFrameWanted to poll for state instead.
823 bool SchedulerStateMachine::SupportsProactiveBeginImplFrame() const {
824 // Both the synchronous compositor and disabled vsync settings
825 // make it undesirable to proactively request BeginImplFrames.
826 // If this is true, the scheduler should poll.
827 return !settings_.using_synchronous_renderer_compositor &&
828 settings_.throttle_frame_production;
831 // These are the cases where we definitely (or almost definitely) have a
832 // new frame to draw and can draw.
833 bool SchedulerStateMachine::BeginImplFrameNeededToDraw() const {
834 // The output surface is the provider of BeginImplFrames, so we are not going
835 // to get them even if we ask for them.
836 if (!HasInitializedOutputSurface())
839 // If we can't draw, don't tick until we are notified that we can draw again.
843 // The forced draw respects our normal draw scheduling, so we need to
844 // request a BeginImplFrame for it.
845 if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
848 // There's no need to produce frames if we are not visible.
852 // We need to draw a more complete frame than we did the last BeginImplFrame,
853 // so request another BeginImplFrame in anticipation that we will have
854 // additional visible tiles.
855 if (swap_used_incomplete_tile_)
858 return needs_redraw_;
861 // These are cases where we are very likely to draw soon, but might not
862 // actually have a new frame to draw when we receive the next BeginImplFrame.
863 // Proactively requesting the BeginImplFrame helps hide the round trip latency
864 // of the SetNeedsBeginImplFrame request that has to go to the Browser.
865 bool SchedulerStateMachine::ProactiveBeginImplFrameWanted() const {
866 // The output surface is the provider of BeginImplFrames,
867 // so we are not going to get them even if we ask for them.
868 if (!HasInitializedOutputSurface())
871 // Do not be proactive when invisible.
875 // We should proactively request a BeginImplFrame if a commit is pending
876 // because we will want to draw if the commit completes quickly.
877 if (needs_commit_ || commit_state_ != COMMIT_STATE_IDLE)
880 // If the pending tree activates quickly, we'll want a BeginImplFrame soon
881 // to draw the new active tree.
882 if (has_pending_tree_)
885 // Changing priorities may allow us to activate (given the new priorities),
886 // which may result in a new frame.
887 if (needs_manage_tiles_)
890 // If we just swapped, it's likely that we are going to produce another
891 // frame soon. This helps avoid negative glitches in our
892 // SetNeedsBeginImplFrame requests, which may propagate to the BeginImplFrame
893 // provider and get sampled at an inopportune time, delaying the next
895 if (last_frame_number_swap_performed_ == current_frame_number_)
901 void SchedulerStateMachine::OnBeginImplFrame(const BeginFrameArgs& args) {
902 AdvanceCurrentFrameNumber();
903 last_begin_impl_frame_args_ = args;
904 DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_IDLE) << *AsValue();
905 begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING;
908 void SchedulerStateMachine::OnBeginImplFrameDeadlinePending() {
909 DCHECK_EQ(begin_impl_frame_state_,
910 BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING)
912 begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME;
915 void SchedulerStateMachine::OnBeginImplFrameDeadline() {
916 DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
918 begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE;
921 void SchedulerStateMachine::OnBeginImplFrameIdle() {
922 DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
924 begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_IDLE;
927 bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineEarly() const {
928 // TODO(brianderson): This should take into account multiple commit sources.
930 // If we are in the middle of the readback, we won't swap, so there is
931 // no reason to trigger the deadline early.
932 if (readback_state_ != READBACK_STATE_IDLE)
935 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
938 // If we've lost the output surface, end the current BeginImplFrame ASAP
939 // so we can start creating the next output surface.
940 if (output_surface_state_ == OUTPUT_SURFACE_LOST)
943 if (active_tree_needs_first_draw_)
949 // This is used to prioritize impl-thread draws when the main thread isn't
950 // producing anything, e.g., after an aborted commit. We also check that we
951 // don't have a pending tree -- otherwise we should give it a chance to
953 // TODO(skyostil): Revisit this when we have more accurate deadline estimates.
954 if (commit_state_ == COMMIT_STATE_IDLE && !has_pending_tree_)
957 // Prioritize impl-thread draws in smoothness mode.
958 if (smoothness_takes_priority_)
964 bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const {
965 // If we just sent a BeginMainFrame and haven't hit the deadline yet, the main
966 // thread is in a low latency mode.
967 if (last_frame_number_begin_main_frame_sent_ == current_frame_number_ &&
968 (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING ||
969 begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME))
972 // If there's a commit in progress it must either be from the previous frame
973 // or it started after the impl thread's deadline. In either case the main
974 // thread is in high latency mode.
975 if (commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS ||
976 commit_state_ == COMMIT_STATE_READY_TO_COMMIT)
979 // Similarly, if there's a pending tree the main thread is in high latency
980 // mode, because either
981 // it's from the previous frame
983 // we're currently drawing the active tree and the pending tree will thus
984 // only be drawn in the next frame.
985 if (has_pending_tree_)
988 if (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) {
989 // Even if there's a new active tree to draw at the deadline or we've just
990 // drawn it, it may have been triggered by a previous BeginImplFrame, in
991 // which case the main thread is in a high latency mode.
992 return (active_tree_needs_first_draw_ ||
993 last_frame_number_swap_performed_ == current_frame_number_) &&
994 last_frame_number_begin_main_frame_sent_ != current_frame_number_;
997 // If the active tree needs its first draw in any other state, we know the
998 // main thread is in a high latency mode.
999 return active_tree_needs_first_draw_;
1002 void SchedulerStateMachine::DidEnterPollForAnticipatedDrawTriggers() {
1003 AdvanceCurrentFrameNumber();
1004 inside_poll_for_anticipated_draw_triggers_ = true;
1007 void SchedulerStateMachine::DidLeavePollForAnticipatedDrawTriggers() {
1008 inside_poll_for_anticipated_draw_triggers_ = false;
1011 void SchedulerStateMachine::SetVisible(bool visible) { visible_ = visible; }
1013 void SchedulerStateMachine::SetCanDraw(bool can_draw) { can_draw_ = can_draw; }
1015 void SchedulerStateMachine::SetNeedsRedraw() { needs_redraw_ = true; }
1017 void SchedulerStateMachine::SetNeedsManageTiles() {
1018 if (!needs_manage_tiles_) {
1020 "SchedulerStateMachine::SetNeedsManageTiles");
1021 needs_manage_tiles_ = true;
1025 void SchedulerStateMachine::SetSwapUsedIncompleteTile(
1026 bool used_incomplete_tile) {
1027 swap_used_incomplete_tile_ = used_incomplete_tile;
1030 void SchedulerStateMachine::SetSmoothnessTakesPriority(
1031 bool smoothness_takes_priority) {
1032 smoothness_takes_priority_ = smoothness_takes_priority;
1035 void SchedulerStateMachine::DidDrawIfPossibleCompleted(
1036 DrawSwapReadbackResult::DrawResult result) {
1038 case DrawSwapReadbackResult::INVALID_RESULT:
1039 NOTREACHED() << "Uninitialized DrawSwapReadbackResult.";
1041 case DrawSwapReadbackResult::DRAW_ABORTED_CANT_DRAW:
1042 case DrawSwapReadbackResult::DRAW_ABORTED_CANT_READBACK:
1043 case DrawSwapReadbackResult::DRAW_ABORTED_CONTEXT_LOST:
1044 NOTREACHED() << "Invalid return value from DrawAndSwapIfPossible:"
1047 case DrawSwapReadbackResult::DRAW_SUCCESS:
1048 consecutive_checkerboard_animations_ = 0;
1049 forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE;
1051 case DrawSwapReadbackResult::DRAW_ABORTED_CHECKERBOARD_ANIMATIONS:
1052 needs_redraw_ = true;
1054 // If we're already in the middle of a redraw, we don't need to
1056 if (forced_redraw_state_ != FORCED_REDRAW_STATE_IDLE)
1059 needs_commit_ = true;
1060 consecutive_checkerboard_animations_++;
1061 if (settings_.timeout_and_draw_when_animation_checkerboards &&
1062 consecutive_checkerboard_animations_ >=
1063 settings_.maximum_number_of_failed_draws_before_draw_is_forced_) {
1064 consecutive_checkerboard_animations_ = 0;
1065 // We need to force a draw, but it doesn't make sense to do this until
1066 // we've committed and have new textures.
1067 forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_COMMIT;
1070 case DrawSwapReadbackResult::DRAW_ABORTED_MISSING_HIGH_RES_CONTENT:
1071 // It's not clear whether this missing content is because of missing
1072 // pictures (which requires a commit) or because of memory pressure
1073 // removing textures (which might not). To be safe, request a commit
1075 needs_commit_ = true;
1080 void SchedulerStateMachine::SetNeedsCommit() { needs_commit_ = true; }
1082 void SchedulerStateMachine::SetNeedsForcedCommitForReadback() {
1083 // If this is called in READBACK_STATE_IDLE, this is a "first" readback
1085 // If this is called in READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT, this
1086 // is a back-to-back readback request that started before the replacement
1087 // commit had a chance to land.
1088 DCHECK(readback_state_ == READBACK_STATE_IDLE ||
1089 readback_state_ == READBACK_STATE_WAITING_FOR_REPLACEMENT_COMMIT);
1091 // If there is already a commit in progress when we get the readback request
1092 // (we are in COMMIT_STATE_FRAME_IN_PROGRESS), then we don't need to send a
1093 // BeginMainFrame for the replacement commit, since there's already a
1094 // BeginMainFrame behind the readback request. In that case, we can skip
1095 // READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME and go directly to
1096 // READBACK_STATE_WAITING_FOR_COMMIT
1097 if (commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS)
1098 readback_state_ = READBACK_STATE_WAITING_FOR_COMMIT;
1100 readback_state_ = READBACK_STATE_NEEDS_BEGIN_MAIN_FRAME;
1103 void SchedulerStateMachine::FinishCommit() {
1104 DCHECK(commit_state_ == COMMIT_STATE_FRAME_IN_PROGRESS) << *AsValue();
1105 commit_state_ = COMMIT_STATE_READY_TO_COMMIT;
1108 void SchedulerStateMachine::BeginMainFrameAborted(bool did_handle) {
1109 DCHECK_EQ(commit_state_, COMMIT_STATE_FRAME_IN_PROGRESS);
1111 bool commit_was_aborted = true;
1112 UpdateStateOnCommit(commit_was_aborted);
1114 DCHECK_NE(readback_state_, READBACK_STATE_WAITING_FOR_COMMIT);
1115 commit_state_ = COMMIT_STATE_IDLE;
1120 void SchedulerStateMachine::DidManageTiles() {
1121 needs_manage_tiles_ = false;
1122 // "Fill" the ManageTiles funnel.
1123 manage_tiles_funnel_++;
1126 void SchedulerStateMachine::DidLoseOutputSurface() {
1127 if (output_surface_state_ == OUTPUT_SURFACE_LOST ||
1128 output_surface_state_ == OUTPUT_SURFACE_CREATING)
1130 output_surface_state_ = OUTPUT_SURFACE_LOST;
1131 needs_redraw_ = false;
1134 void SchedulerStateMachine::NotifyReadyToActivate() {
1135 if (has_pending_tree_)
1136 pending_tree_is_ready_for_activation_ = true;
1139 void SchedulerStateMachine::DidCreateAndInitializeOutputSurface() {
1140 DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_CREATING);
1141 output_surface_state_ = OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT;
1143 if (did_create_and_initialize_first_output_surface_) {
1144 // TODO(boliu): See if we can remove this when impl-side painting is always
1145 // on. Does anything on the main thread need to update after recreate?
1146 needs_commit_ = true;
1148 did_create_and_initialize_first_output_surface_ = true;
1151 bool SchedulerStateMachine::HasInitializedOutputSurface() const {
1152 switch (output_surface_state_) {
1153 case OUTPUT_SURFACE_LOST:
1154 case OUTPUT_SURFACE_CREATING:
1157 case OUTPUT_SURFACE_ACTIVE:
1158 case OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT:
1159 case OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION: