Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(510)

Side by Side Diff: cc/scheduler/scheduler_state_machine.cc

Issue 1533773002: Delete CC. (Closed) Base URL: git@github.com:domokit/mojo.git@cl-2e
Patch Set: rebase Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "cc/scheduler/scheduler_state_machine.h"
6
7 #include "base/format_macros.h"
8 #include "base/logging.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/trace_event/trace_event.h"
11 #include "base/trace_event/trace_event_argument.h"
12 #include "base/values.h"
13 #include "ui/gfx/frame_time.h"
14
15 namespace cc {
16
17 SchedulerStateMachine::SchedulerStateMachine(const SchedulerSettings& settings)
18 : settings_(settings),
19 output_surface_state_(OUTPUT_SURFACE_LOST),
20 begin_impl_frame_state_(BEGIN_IMPL_FRAME_STATE_IDLE),
21 commit_state_(COMMIT_STATE_IDLE),
22 forced_redraw_state_(FORCED_REDRAW_STATE_IDLE),
23 commit_count_(0),
24 current_frame_number_(0),
25 last_frame_number_animate_performed_(-1),
26 last_frame_number_swap_performed_(-1),
27 last_frame_number_swap_requested_(-1),
28 last_frame_number_begin_main_frame_sent_(-1),
29 animate_funnel_(false),
30 perform_swap_funnel_(false),
31 request_swap_funnel_(false),
32 send_begin_main_frame_funnel_(false),
33 prepare_tiles_funnel_(0),
34 consecutive_checkerboard_animations_(0),
35 max_pending_swaps_(1),
36 pending_swaps_(0),
37 needs_redraw_(false),
38 needs_animate_(false),
39 needs_prepare_tiles_(false),
40 needs_commit_(false),
41 inside_poll_for_anticipated_draw_triggers_(false),
42 visible_(false),
43 can_start_(false),
44 can_draw_(false),
45 has_pending_tree_(false),
46 pending_tree_is_ready_for_activation_(false),
47 active_tree_needs_first_draw_(false),
48 did_create_and_initialize_first_output_surface_(false),
49 impl_latency_takes_priority_(false),
50 skip_next_begin_main_frame_to_reduce_latency_(false),
51 skip_begin_main_frame_to_reduce_latency_(false),
52 continuous_painting_(false),
53 children_need_begin_frames_(false),
54 defer_commits_(false),
55 last_commit_had_no_updates_(false) {
56 }
57
58 const char* SchedulerStateMachine::OutputSurfaceStateToString(
59 OutputSurfaceState state) {
60 switch (state) {
61 case OUTPUT_SURFACE_ACTIVE:
62 return "OUTPUT_SURFACE_ACTIVE";
63 case OUTPUT_SURFACE_LOST:
64 return "OUTPUT_SURFACE_LOST";
65 case OUTPUT_SURFACE_CREATING:
66 return "OUTPUT_SURFACE_CREATING";
67 case OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT:
68 return "OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT";
69 case OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION:
70 return "OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION";
71 }
72 NOTREACHED();
73 return "???";
74 }
75
76 const char* SchedulerStateMachine::BeginImplFrameStateToString(
77 BeginImplFrameState state) {
78 switch (state) {
79 case BEGIN_IMPL_FRAME_STATE_IDLE:
80 return "BEGIN_IMPL_FRAME_STATE_IDLE";
81 case BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING:
82 return "BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING";
83 case BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME:
84 return "BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME";
85 case BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE:
86 return "BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE";
87 }
88 NOTREACHED();
89 return "???";
90 }
91
92 const char* SchedulerStateMachine::CommitStateToString(CommitState state) {
93 switch (state) {
94 case COMMIT_STATE_IDLE:
95 return "COMMIT_STATE_IDLE";
96 case COMMIT_STATE_BEGIN_MAIN_FRAME_SENT:
97 return "COMMIT_STATE_BEGIN_MAIN_FRAME_SENT";
98 case COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED:
99 return "COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED";
100 case COMMIT_STATE_READY_TO_COMMIT:
101 return "COMMIT_STATE_READY_TO_COMMIT";
102 case COMMIT_STATE_WAITING_FOR_ACTIVATION:
103 return "COMMIT_STATE_WAITING_FOR_ACTIVATION";
104 case COMMIT_STATE_WAITING_FOR_DRAW:
105 return "COMMIT_STATE_WAITING_FOR_DRAW";
106 }
107 NOTREACHED();
108 return "???";
109 }
110
111 const char* SchedulerStateMachine::ForcedRedrawOnTimeoutStateToString(
112 ForcedRedrawOnTimeoutState state) {
113 switch (state) {
114 case FORCED_REDRAW_STATE_IDLE:
115 return "FORCED_REDRAW_STATE_IDLE";
116 case FORCED_REDRAW_STATE_WAITING_FOR_COMMIT:
117 return "FORCED_REDRAW_STATE_WAITING_FOR_COMMIT";
118 case FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION:
119 return "FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION";
120 case FORCED_REDRAW_STATE_WAITING_FOR_DRAW:
121 return "FORCED_REDRAW_STATE_WAITING_FOR_DRAW";
122 }
123 NOTREACHED();
124 return "???";
125 }
126
127 const char* SchedulerStateMachine::ActionToString(Action action) {
128 switch (action) {
129 case ACTION_NONE:
130 return "ACTION_NONE";
131 case ACTION_ANIMATE:
132 return "ACTION_ANIMATE";
133 case ACTION_SEND_BEGIN_MAIN_FRAME:
134 return "ACTION_SEND_BEGIN_MAIN_FRAME";
135 case ACTION_COMMIT:
136 return "ACTION_COMMIT";
137 case ACTION_ACTIVATE_SYNC_TREE:
138 return "ACTION_ACTIVATE_SYNC_TREE";
139 case ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
140 return "ACTION_DRAW_AND_SWAP_IF_POSSIBLE";
141 case ACTION_DRAW_AND_SWAP_FORCED:
142 return "ACTION_DRAW_AND_SWAP_FORCED";
143 case ACTION_DRAW_AND_SWAP_ABORT:
144 return "ACTION_DRAW_AND_SWAP_ABORT";
145 case ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
146 return "ACTION_BEGIN_OUTPUT_SURFACE_CREATION";
147 case ACTION_PREPARE_TILES:
148 return "ACTION_PREPARE_TILES";
149 }
150 NOTREACHED();
151 return "???";
152 }
153
154 scoped_refptr<base::trace_event::ConvertableToTraceFormat>
155 SchedulerStateMachine::AsValue() const {
156 scoped_refptr<base::trace_event::TracedValue> state =
157 new base::trace_event::TracedValue();
158 AsValueInto(state.get());
159 return state;
160 }
161
162 void SchedulerStateMachine::AsValueInto(
163 base::trace_event::TracedValue* state) const {
164 state->BeginDictionary("major_state");
165 state->SetString("next_action", ActionToString(NextAction()));
166 state->SetString("begin_impl_frame_state",
167 BeginImplFrameStateToString(begin_impl_frame_state_));
168 state->SetString("commit_state", CommitStateToString(commit_state_));
169 state->SetString("output_surface_state_",
170 OutputSurfaceStateToString(output_surface_state_));
171 state->SetString("forced_redraw_state",
172 ForcedRedrawOnTimeoutStateToString(forced_redraw_state_));
173 state->EndDictionary();
174
175 state->BeginDictionary("minor_state");
176 state->SetInteger("commit_count", commit_count_);
177 state->SetInteger("current_frame_number", current_frame_number_);
178 state->SetInteger("last_frame_number_animate_performed",
179 last_frame_number_animate_performed_);
180 state->SetInteger("last_frame_number_swap_performed",
181 last_frame_number_swap_performed_);
182 state->SetInteger("last_frame_number_swap_requested",
183 last_frame_number_swap_requested_);
184 state->SetInteger("last_frame_number_begin_main_frame_sent",
185 last_frame_number_begin_main_frame_sent_);
186 state->SetBoolean("funnel: animate_funnel", animate_funnel_);
187 state->SetBoolean("funnel: perform_swap_funnel", perform_swap_funnel_);
188 state->SetBoolean("funnel: request_swap_funnel", request_swap_funnel_);
189 state->SetBoolean("funnel: send_begin_main_frame_funnel",
190 send_begin_main_frame_funnel_);
191 state->SetInteger("funnel: prepare_tiles_funnel", prepare_tiles_funnel_);
192 state->SetInteger("consecutive_checkerboard_animations",
193 consecutive_checkerboard_animations_);
194 state->SetInteger("max_pending_swaps_", max_pending_swaps_);
195 state->SetInteger("pending_swaps_", pending_swaps_);
196 state->SetBoolean("needs_redraw", needs_redraw_);
197 state->SetBoolean("needs_animate_", needs_animate_);
198 state->SetBoolean("needs_prepare_tiles", needs_prepare_tiles_);
199 state->SetBoolean("needs_commit", needs_commit_);
200 state->SetBoolean("visible", visible_);
201 state->SetBoolean("can_start", can_start_);
202 state->SetBoolean("can_draw", can_draw_);
203 state->SetBoolean("has_pending_tree", has_pending_tree_);
204 state->SetBoolean("pending_tree_is_ready_for_activation",
205 pending_tree_is_ready_for_activation_);
206 state->SetBoolean("active_tree_needs_first_draw",
207 active_tree_needs_first_draw_);
208 state->SetBoolean("did_create_and_initialize_first_output_surface",
209 did_create_and_initialize_first_output_surface_);
210 state->SetBoolean("impl_latency_takes_priority",
211 impl_latency_takes_priority_);
212 state->SetBoolean("main_thread_is_in_high_latency_mode",
213 MainThreadIsInHighLatencyMode());
214 state->SetBoolean("skip_begin_main_frame_to_reduce_latency",
215 skip_begin_main_frame_to_reduce_latency_);
216 state->SetBoolean("skip_next_begin_main_frame_to_reduce_latency",
217 skip_next_begin_main_frame_to_reduce_latency_);
218 state->SetBoolean("continuous_painting", continuous_painting_);
219 state->SetBoolean("children_need_begin_frames", children_need_begin_frames_);
220 state->SetBoolean("defer_commits", defer_commits_);
221 state->EndDictionary();
222 }
223
224 void SchedulerStateMachine::AdvanceCurrentFrameNumber() {
225 current_frame_number_++;
226
227 animate_funnel_ = false;
228 perform_swap_funnel_ = false;
229 request_swap_funnel_ = false;
230 send_begin_main_frame_funnel_ = false;
231
232 // "Drain" the PrepareTiles funnel.
233 if (prepare_tiles_funnel_ > 0)
234 prepare_tiles_funnel_--;
235
236 skip_begin_main_frame_to_reduce_latency_ =
237 skip_next_begin_main_frame_to_reduce_latency_;
238 skip_next_begin_main_frame_to_reduce_latency_ = false;
239 }
240
241 bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const {
242 // These are all the cases where we normally cannot or do not want to draw
243 // but, if needs_redraw_ is true and we do not draw to make forward progress,
244 // we might deadlock with the main thread.
245 // This should be a superset of PendingActivationsShouldBeForced() since
246 // activation of the pending tree is blocked by drawing of the active tree and
247 // the main thread might be blocked on activation of the most recent commit.
248 if (PendingActivationsShouldBeForced())
249 return true;
250
251 // Additional states where we should abort draws.
252 if (!can_draw_)
253 return true;
254 return false;
255 }
256
257 bool SchedulerStateMachine::PendingActivationsShouldBeForced() const {
258 // There is no output surface to trigger our activations.
259 // If we do not force activations to make forward progress, we might deadlock
260 // with the main thread.
261 if (output_surface_state_ == OUTPUT_SURFACE_LOST)
262 return true;
263
264 // If we're not visible, we should force activation.
265 // Since we set RequiresHighResToDraw when becoming visible, we ensure that we
266 // don't checkerboard until all visible resources are done. Furthermore, if we
267 // do keep the pending tree around, when becoming visible we might activate
268 // prematurely causing RequiresHighResToDraw flag to be reset. In all cases,
269 // we can simply activate on becoming invisible since we don't need to draw
270 // the active tree when we're in this state.
271 if (!visible_)
272 return true;
273
274 return false;
275 }
276
277 bool SchedulerStateMachine::ShouldBeginOutputSurfaceCreation() const {
278 // Don't try to initialize too early.
279 if (!can_start_)
280 return false;
281
282 // We only want to start output surface initialization after the
283 // previous commit is complete.
284 if (commit_state_ != COMMIT_STATE_IDLE)
285 return false;
286
287 // Make sure the BeginImplFrame from any previous OutputSurfaces
288 // are complete before creating the new OutputSurface.
289 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_IDLE)
290 return false;
291
292 // We want to clear the pipline of any pending draws and activations
293 // before starting output surface initialization. This allows us to avoid
294 // weird corner cases where we abort draws or force activation while we
295 // are initializing the output surface.
296 if (active_tree_needs_first_draw_ || has_pending_tree_)
297 return false;
298
299 // We need to create the output surface if we don't have one and we haven't
300 // started creating one yet.
301 return output_surface_state_ == OUTPUT_SURFACE_LOST;
302 }
303
304 bool SchedulerStateMachine::ShouldDraw() const {
305 // If we need to abort draws, we should do so ASAP since the draw could
306 // be blocking other important actions (like output surface initialization),
307 // from occuring. If we are waiting for the first draw, then perfom the
308 // aborted draw to keep things moving. If we are not waiting for the first
309 // draw however, we don't want to abort for no reason.
310 if (PendingDrawsShouldBeAborted())
311 return active_tree_needs_first_draw_;
312
313 // Do not draw too many times in a single frame. It's okay that we don't check
314 // this before checking for aborted draws because aborted draws do not request
315 // a swap.
316 if (request_swap_funnel_)
317 return false;
318
319 // Don't draw if we are waiting on the first commit after a surface.
320 if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE)
321 return false;
322
323 // Do not queue too many swaps.
324 if (pending_swaps_ >= max_pending_swaps_)
325 return false;
326
327 // Except for the cases above, do not draw outside of the BeginImplFrame
328 // deadline.
329 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
330 return false;
331
332 // Only handle forced redraws due to timeouts on the regular deadline.
333 if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
334 return true;
335
336 return needs_redraw_;
337 }
338
339 bool SchedulerStateMachine::ShouldActivatePendingTree() const {
340 // There is nothing to activate.
341 if (!has_pending_tree_)
342 return false;
343
344 // We should not activate a second tree before drawing the first one.
345 // Even if we need to force activation of the pending tree, we should abort
346 // drawing the active tree first.
347 if (active_tree_needs_first_draw_)
348 return false;
349
350 // If we want to force activation, do so ASAP.
351 if (PendingActivationsShouldBeForced())
352 return true;
353
354 // At this point, only activate if we are ready to activate.
355 return pending_tree_is_ready_for_activation_;
356 }
357
358 bool SchedulerStateMachine::ShouldAnimate() const {
359 // Do not animate too many times in a single frame.
360 if (animate_funnel_)
361 return false;
362
363 // Don't animate if we are waiting on the first commit after a surface.
364 if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE)
365 return false;
366
367 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING &&
368 begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
369 return false;
370
371 return needs_redraw_ || needs_animate_;
372 }
373
374 bool SchedulerStateMachine::CouldSendBeginMainFrame() const {
375 // Do not send begin main frame too many times in a single frame.
376 if (send_begin_main_frame_funnel_)
377 return false;
378
379 if (!needs_commit_)
380 return false;
381
382 // We can not perform commits if we are not visible.
383 if (!visible_)
384 return false;
385
386 // Do not make a new commits when it is deferred.
387 if (defer_commits_)
388 return false;
389
390 return true;
391 }
392
393 bool SchedulerStateMachine::ShouldSendBeginMainFrame() const {
394 if (!CouldSendBeginMainFrame())
395 return false;
396
397 // Only send BeginMainFrame when there isn't another commit pending already.
398 if (commit_state_ != COMMIT_STATE_IDLE)
399 return false;
400
401 // Don't send BeginMainFrame early if we are prioritizing the active tree
402 // because of impl_latency_takes_priority_.
403 if (impl_latency_takes_priority_ &&
404 (has_pending_tree_ || active_tree_needs_first_draw_)) {
405 return false;
406 }
407
408 // We should not send BeginMainFrame while we are in
409 // BEGIN_IMPL_FRAME_STATE_IDLE since we might have new
410 // user input arriving soon.
411 // TODO(brianderson): Allow sending BeginMainFrame while idle when the main
412 // thread isn't consuming user input.
413 if (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_IDLE &&
414 BeginFrameNeeded())
415 return false;
416
417 // We need a new commit for the forced redraw. This honors the
418 // single commit per interval because the result will be swapped to screen.
419 if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT)
420 return true;
421
422 // We shouldn't normally accept commits if there isn't an OutputSurface.
423 if (!HasInitializedOutputSurface())
424 return false;
425
426 // SwapAck throttle the BeginMainFrames unless we just swapped.
427 // TODO(brianderson): Remove this restriction to improve throughput.
428 bool just_swapped_in_deadline =
429 begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE &&
430 perform_swap_funnel_;
431 if (pending_swaps_ >= max_pending_swaps_ && !just_swapped_in_deadline)
432 return false;
433
434 if (skip_begin_main_frame_to_reduce_latency_)
435 return false;
436
437 return true;
438 }
439
440 bool SchedulerStateMachine::ShouldCommit() const {
441 if (commit_state_ != COMMIT_STATE_READY_TO_COMMIT)
442 return false;
443
444 // We must not finish the commit until the pending tree is free.
445 if (has_pending_tree_) {
446 DCHECK(settings_.main_frame_before_activation_enabled);
447 return false;
448 }
449
450 // Prioritize drawing the previous commit before finishing the next commit.
451 if (active_tree_needs_first_draw_)
452 return false;
453
454 return true;
455 }
456
457 bool SchedulerStateMachine::ShouldPrepareTiles() const {
458 // PrepareTiles only really needs to be called immediately after commit
459 // and then periodically after that. Use a funnel to make sure we average
460 // one PrepareTiles per BeginImplFrame in the long run.
461 if (prepare_tiles_funnel_ > 0)
462 return false;
463
464 // Limiting to once per-frame is not enough, since we only want to
465 // prepare tiles _after_ draws. Polling for draw triggers and
466 // begin-frame are mutually exclusive, so we limit to these two cases.
467 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE &&
468 !inside_poll_for_anticipated_draw_triggers_)
469 return false;
470 return needs_prepare_tiles_;
471 }
472
473 SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
474 if (ShouldActivatePendingTree())
475 return ACTION_ACTIVATE_SYNC_TREE;
476 if (ShouldCommit())
477 return ACTION_COMMIT;
478 if (ShouldAnimate())
479 return ACTION_ANIMATE;
480 if (ShouldDraw()) {
481 if (PendingDrawsShouldBeAborted())
482 return ACTION_DRAW_AND_SWAP_ABORT;
483 else if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
484 return ACTION_DRAW_AND_SWAP_FORCED;
485 else
486 return ACTION_DRAW_AND_SWAP_IF_POSSIBLE;
487 }
488 if (ShouldPrepareTiles())
489 return ACTION_PREPARE_TILES;
490 if (ShouldSendBeginMainFrame())
491 return ACTION_SEND_BEGIN_MAIN_FRAME;
492 if (ShouldBeginOutputSurfaceCreation())
493 return ACTION_BEGIN_OUTPUT_SURFACE_CREATION;
494 return ACTION_NONE;
495 }
496
497 void SchedulerStateMachine::UpdateState(Action action) {
498 switch (action) {
499 case ACTION_NONE:
500 return;
501
502 case ACTION_ACTIVATE_SYNC_TREE:
503 UpdateStateOnActivation();
504 return;
505
506 case ACTION_ANIMATE:
507 DCHECK(!animate_funnel_);
508 last_frame_number_animate_performed_ = current_frame_number_;
509 animate_funnel_ = true;
510 needs_animate_ = false;
511 // TODO(skyostil): Instead of assuming this, require the client to tell
512 // us.
513 SetNeedsRedraw();
514 return;
515
516 case ACTION_SEND_BEGIN_MAIN_FRAME:
517 DCHECK(!has_pending_tree_ ||
518 settings_.main_frame_before_activation_enabled);
519 DCHECK(visible_);
520 DCHECK(!send_begin_main_frame_funnel_);
521 commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_SENT;
522 needs_commit_ = false;
523 send_begin_main_frame_funnel_ = true;
524 last_frame_number_begin_main_frame_sent_ =
525 current_frame_number_;
526 return;
527
528 case ACTION_COMMIT: {
529 bool commit_has_no_updates = false;
530 UpdateStateOnCommit(commit_has_no_updates);
531 return;
532 }
533
534 case ACTION_DRAW_AND_SWAP_FORCED:
535 case ACTION_DRAW_AND_SWAP_IF_POSSIBLE: {
536 bool did_request_swap = true;
537 UpdateStateOnDraw(did_request_swap);
538 return;
539 }
540
541 case ACTION_DRAW_AND_SWAP_ABORT: {
542 bool did_request_swap = false;
543 UpdateStateOnDraw(did_request_swap);
544 return;
545 }
546
547 case ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
548 DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_LOST);
549 output_surface_state_ = OUTPUT_SURFACE_CREATING;
550
551 // The following DCHECKs make sure we are in the proper quiescent state.
552 // The pipeline should be flushed entirely before we start output
553 // surface creation to avoid complicated corner cases.
554 DCHECK_EQ(commit_state_, COMMIT_STATE_IDLE);
555 DCHECK(!has_pending_tree_);
556 DCHECK(!active_tree_needs_first_draw_);
557 return;
558
559 case ACTION_PREPARE_TILES:
560 UpdateStateOnPrepareTiles();
561 return;
562 }
563 }
564
565 void SchedulerStateMachine::UpdateStateOnCommit(bool commit_has_no_updates) {
566 commit_count_++;
567
568 if (!commit_has_no_updates)
569 animate_funnel_ = false;
570
571 if (commit_has_no_updates || settings_.main_frame_before_activation_enabled) {
572 commit_state_ = COMMIT_STATE_IDLE;
573 } else if (settings_.impl_side_painting) {
574 commit_state_ = COMMIT_STATE_WAITING_FOR_ACTIVATION;
575 } else {
576 commit_state_ = settings_.main_thread_should_always_be_low_latency
577 ? COMMIT_STATE_WAITING_FOR_DRAW
578 : COMMIT_STATE_IDLE;
579 }
580
581 // If we are impl-side-painting but the commit was aborted, then we behave
582 // mostly as if we are not impl-side-painting since there is no pending tree.
583 has_pending_tree_ = settings_.impl_side_painting && !commit_has_no_updates;
584
585 // Update state related to forced draws.
586 if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT) {
587 forced_redraw_state_ = has_pending_tree_
588 ? FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION
589 : FORCED_REDRAW_STATE_WAITING_FOR_DRAW;
590 }
591
592 // Update the output surface state.
593 DCHECK_NE(output_surface_state_, OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION);
594 if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT) {
595 if (has_pending_tree_) {
596 output_surface_state_ = OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION;
597 } else {
598 output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
599 needs_redraw_ = true;
600 }
601 }
602
603 // Update state if we have a new active tree to draw, or if the active tree
604 // was unchanged but we need to do a forced draw.
605 if (!has_pending_tree_ &&
606 (!commit_has_no_updates ||
607 forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)) {
608 needs_redraw_ = true;
609 active_tree_needs_first_draw_ = true;
610 }
611
612 // This post-commit work is common to both completed and aborted commits.
613 pending_tree_is_ready_for_activation_ = false;
614
615 if (continuous_painting_)
616 needs_commit_ = true;
617 last_commit_had_no_updates_ = commit_has_no_updates;
618 }
619
620 void SchedulerStateMachine::UpdateStateOnActivation() {
621 if (commit_state_ == COMMIT_STATE_WAITING_FOR_ACTIVATION) {
622 commit_state_ = settings_.main_thread_should_always_be_low_latency
623 ? COMMIT_STATE_WAITING_FOR_DRAW
624 : COMMIT_STATE_IDLE;
625 }
626
627 if (output_surface_state_ == OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION)
628 output_surface_state_ = OUTPUT_SURFACE_ACTIVE;
629
630 if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_ACTIVATION)
631 forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_DRAW;
632
633 has_pending_tree_ = false;
634 pending_tree_is_ready_for_activation_ = false;
635 active_tree_needs_first_draw_ = true;
636 needs_redraw_ = true;
637 }
638
639 void SchedulerStateMachine::UpdateStateOnDraw(bool did_request_swap) {
640 if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
641 forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE;
642
643 if (commit_state_ == COMMIT_STATE_WAITING_FOR_DRAW)
644 commit_state_ = COMMIT_STATE_IDLE;
645
646 needs_redraw_ = false;
647 active_tree_needs_first_draw_ = false;
648
649 if (did_request_swap) {
650 DCHECK(!request_swap_funnel_);
651 request_swap_funnel_ = true;
652 last_frame_number_swap_requested_ = current_frame_number_;
653 }
654 }
655
656 void SchedulerStateMachine::UpdateStateOnPrepareTiles() {
657 needs_prepare_tiles_ = false;
658 }
659
660 void SchedulerStateMachine::SetSkipNextBeginMainFrameToReduceLatency() {
661 TRACE_EVENT_INSTANT0("cc",
662 "Scheduler: SkipNextBeginMainFrameToReduceLatency",
663 TRACE_EVENT_SCOPE_THREAD);
664 skip_next_begin_main_frame_to_reduce_latency_ = true;
665 }
666
667 bool SchedulerStateMachine::BeginFrameNeededForChildren() const {
668 if (HasInitializedOutputSurface())
669 return children_need_begin_frames_;
670
671 return false;
672 }
673
674 bool SchedulerStateMachine::BeginFrameNeeded() const {
675 // We can't handle BeginFrames when output surface isn't initialized.
676 // TODO(brianderson): Support output surface creation inside a BeginFrame.
677 if (!HasInitializedOutputSurface())
678 return false;
679
680 if (SupportsProactiveBeginFrame()) {
681 return (BeginFrameNeededToAnimateOrDraw() ||
682 BeginFrameNeededForChildren() ||
683 ProactiveBeginFrameWanted());
684 }
685
686 // Proactive BeginFrames are bad for the synchronous compositor because we
687 // have to draw when we get the BeginFrame and could end up drawing many
688 // duplicate frames if our new frame isn't ready in time.
689 // To poll for state with the synchronous compositor without having to draw,
690 // we rely on ShouldPollForAnticipatedDrawTriggers instead.
691 // Synchronous compositor doesn't have a browser.
692 DCHECK(!children_need_begin_frames_);
693 return BeginFrameNeededToAnimateOrDraw();
694 }
695
696 bool SchedulerStateMachine::ShouldPollForAnticipatedDrawTriggers() const {
697 // ShouldPollForAnticipatedDrawTriggers is what we use in place of
698 // ProactiveBeginFrameWanted when we are using the synchronous
699 // compositor.
700 if (!SupportsProactiveBeginFrame()) {
701 return !BeginFrameNeededToAnimateOrDraw() && ProactiveBeginFrameWanted();
702 }
703
704 // Non synchronous compositors should rely on
705 // ProactiveBeginFrameWanted to poll for state instead.
706 return false;
707 }
708
709 // Note: If SupportsProactiveBeginFrame is false, the scheduler should poll
710 // for changes in it's draw state so it can request a BeginFrame when it's
711 // actually ready.
712 bool SchedulerStateMachine::SupportsProactiveBeginFrame() const {
713 // It is undesirable to proactively request BeginFrames if we are
714 // using a synchronous compositor because we *must* draw for every
715 // BeginFrame, which could cause duplicate draws.
716 return !settings_.using_synchronous_renderer_compositor;
717 }
718
719 void SchedulerStateMachine::SetChildrenNeedBeginFrames(
720 bool children_need_begin_frames) {
721 children_need_begin_frames_ = children_need_begin_frames;
722 }
723
724 void SchedulerStateMachine::SetDeferCommits(bool defer_commits) {
725 defer_commits_ = defer_commits;
726 }
727
728 // These are the cases where we definitely (or almost definitely) have a
729 // new frame to animate and/or draw and can draw.
730 bool SchedulerStateMachine::BeginFrameNeededToAnimateOrDraw() const {
731 // The forced draw respects our normal draw scheduling, so we need to
732 // request a BeginImplFrame for it.
733 if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
734 return true;
735
736 return needs_animate_ || needs_redraw_;
737 }
738
739 // These are cases where we are very likely to draw soon, but might not
740 // actually have a new frame to draw when we receive the next BeginImplFrame.
741 // Proactively requesting the BeginImplFrame helps hide the round trip latency
742 // of the SetNeedsBeginFrame request that has to go to the Browser.
743 bool SchedulerStateMachine::ProactiveBeginFrameWanted() const {
744 // Do not be proactive when invisible.
745 if (!visible_)
746 return false;
747
748 // We should proactively request a BeginImplFrame if a commit is pending
749 // because we will want to draw if the commit completes quickly.
750 if (needs_commit_ || commit_state_ != COMMIT_STATE_IDLE)
751 return true;
752
753 // If the pending tree activates quickly, we'll want a BeginImplFrame soon
754 // to draw the new active tree.
755 if (has_pending_tree_)
756 return true;
757
758 // Changing priorities may allow us to activate (given the new priorities),
759 // which may result in a new frame.
760 if (needs_prepare_tiles_)
761 return true;
762
763 // If we just sent a swap request, it's likely that we are going to produce
764 // another frame soon. This helps avoid negative glitches in our
765 // SetNeedsBeginFrame requests, which may propagate to the BeginImplFrame
766 // provider and get sampled at an inopportune time, delaying the next
767 // BeginImplFrame.
768 if (request_swap_funnel_)
769 return true;
770
771 // If the last commit was aborted because of early out (no updates), we should
772 // still want a begin frame in case there is a commit coming again.
773 if (last_commit_had_no_updates_)
774 return true;
775
776 return false;
777 }
778
779 void SchedulerStateMachine::OnBeginImplFrame() {
780 AdvanceCurrentFrameNumber();
781 DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_IDLE)
782 << AsValue()->ToString();
783 begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING;
784 last_commit_had_no_updates_ = false;
785 }
786
787 void SchedulerStateMachine::OnBeginImplFrameDeadlinePending() {
788 DCHECK_EQ(begin_impl_frame_state_,
789 BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING)
790 << AsValue()->ToString();
791 begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME;
792 }
793
794 void SchedulerStateMachine::OnBeginImplFrameDeadline() {
795 DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
796 << AsValue()->ToString();
797 begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE;
798 }
799
800 void SchedulerStateMachine::OnBeginImplFrameIdle() {
801 DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
802 << AsValue()->ToString();
803 begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_IDLE;
804 }
805
806 SchedulerStateMachine::BeginImplFrameDeadlineMode
807 SchedulerStateMachine::CurrentBeginImplFrameDeadlineMode() const {
808 if (ShouldTriggerBeginImplFrameDeadlineImmediately()) {
809 return BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE;
810 } else if (needs_redraw_ && pending_swaps_ < max_pending_swaps_) {
811 // We have an animation or fast input path on the impl thread that wants
812 // to draw, so don't wait too long for a new active tree.
813 // If we are swap throttled we should wait until we are unblocked.
814 return BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR;
815 } else {
816 // The impl thread doesn't have anything it wants to draw and we are just
817 // waiting for a new active tree or we are swap throttled. In short we are
818 // blocked.
819 return BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE;
820 }
821 }
822
823 bool SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately()
824 const {
825 // TODO(brianderson): This should take into account multiple commit sources.
826
827 if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME)
828 return false;
829
830 // If we've lost the output surface, end the current BeginImplFrame ASAP
831 // so we can start creating the next output surface.
832 if (output_surface_state_ == OUTPUT_SURFACE_LOST)
833 return true;
834
835 // SwapAck throttle the deadline since we wont draw and swap anyway.
836 if (pending_swaps_ >= max_pending_swaps_)
837 return false;
838
839 if (active_tree_needs_first_draw_)
840 return true;
841
842 if (!needs_redraw_)
843 return false;
844
845 // This is used to prioritize impl-thread draws when the main thread isn't
846 // producing anything, e.g., after an aborted commit. We also check that we
847 // don't have a pending tree -- otherwise we should give it a chance to
848 // activate.
849 // TODO(skyostil): Revisit this when we have more accurate deadline estimates.
850 if (commit_state_ == COMMIT_STATE_IDLE && !has_pending_tree_)
851 return true;
852
853 // Prioritize impl-thread draws in impl_latency_takes_priority_ mode.
854 if (impl_latency_takes_priority_)
855 return true;
856
857 return false;
858 }
859
860 bool SchedulerStateMachine::MainThreadIsInHighLatencyMode() const {
861 // If a commit is pending before the previous commit has been drawn, we
862 // are definitely in a high latency mode.
863 if (CommitPending() && (active_tree_needs_first_draw_ || has_pending_tree_))
864 return true;
865
866 // If we just sent a BeginMainFrame and haven't hit the deadline yet, the main
867 // thread is in a low latency mode.
868 if (send_begin_main_frame_funnel_ &&
869 (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING ||
870 begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME))
871 return false;
872
873 // If there's a commit in progress it must either be from the previous frame
874 // or it started after the impl thread's deadline. In either case the main
875 // thread is in high latency mode.
876 if (CommitPending())
877 return true;
878
879 // Similarly, if there's a pending tree the main thread is in high latency
880 // mode, because either
881 // it's from the previous frame
882 // or
883 // we're currently drawing the active tree and the pending tree will thus
884 // only be drawn in the next frame.
885 if (has_pending_tree_)
886 return true;
887
888 if (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) {
889 // Even if there's a new active tree to draw at the deadline or we've just
890 // swapped it, it may have been triggered by a previous BeginImplFrame, in
891 // which case the main thread is in a high latency mode.
892 return (active_tree_needs_first_draw_ || perform_swap_funnel_) &&
893 !send_begin_main_frame_funnel_;
894 }
895
896 // If the active tree needs its first draw in any other state, we know the
897 // main thread is in a high latency mode.
898 return active_tree_needs_first_draw_;
899 }
900
901 void SchedulerStateMachine::DidEnterPollForAnticipatedDrawTriggers() {
902 AdvanceCurrentFrameNumber();
903 inside_poll_for_anticipated_draw_triggers_ = true;
904 }
905
906 void SchedulerStateMachine::DidLeavePollForAnticipatedDrawTriggers() {
907 inside_poll_for_anticipated_draw_triggers_ = false;
908 }
909
910 void SchedulerStateMachine::SetVisible(bool visible) { visible_ = visible; }
911
912 void SchedulerStateMachine::SetCanDraw(bool can_draw) { can_draw_ = can_draw; }
913
914 void SchedulerStateMachine::SetNeedsRedraw() { needs_redraw_ = true; }
915
916 void SchedulerStateMachine::SetNeedsAnimate() {
917 needs_animate_ = true;
918 }
919
920 void SchedulerStateMachine::SetNeedsPrepareTiles() {
921 if (!needs_prepare_tiles_) {
922 TRACE_EVENT0("cc", "SchedulerStateMachine::SetNeedsPrepareTiles");
923 needs_prepare_tiles_ = true;
924 }
925 }
926
927 void SchedulerStateMachine::SetMaxSwapsPending(int max) {
928 max_pending_swaps_ = max;
929 }
930
931 void SchedulerStateMachine::DidSwapBuffers() {
932 pending_swaps_++;
933 DCHECK_LE(pending_swaps_, max_pending_swaps_);
934 DCHECK(!perform_swap_funnel_);
935
936 perform_swap_funnel_ = true;
937 last_frame_number_swap_performed_ = current_frame_number_;
938 }
939
940 void SchedulerStateMachine::DidSwapBuffersComplete() {
941 DCHECK_GT(pending_swaps_, 0);
942 pending_swaps_--;
943 }
944
945 void SchedulerStateMachine::SetImplLatencyTakesPriority(
946 bool impl_latency_takes_priority) {
947 impl_latency_takes_priority_ = impl_latency_takes_priority;
948 }
949
950 void SchedulerStateMachine::DidDrawIfPossibleCompleted(DrawResult result) {
951 switch (result) {
952 case INVALID_RESULT:
953 NOTREACHED() << "Uninitialized DrawResult.";
954 break;
955 case DRAW_ABORTED_CANT_DRAW:
956 case DRAW_ABORTED_CONTEXT_LOST:
957 NOTREACHED() << "Invalid return value from DrawAndSwapIfPossible:"
958 << result;
959 break;
960 case DRAW_SUCCESS:
961 consecutive_checkerboard_animations_ = 0;
962 forced_redraw_state_ = FORCED_REDRAW_STATE_IDLE;
963 break;
964 case DRAW_ABORTED_CHECKERBOARD_ANIMATIONS:
965 needs_redraw_ = true;
966
967 // If we're already in the middle of a redraw, we don't need to
968 // restart it.
969 if (forced_redraw_state_ != FORCED_REDRAW_STATE_IDLE)
970 return;
971
972 needs_commit_ = true;
973 consecutive_checkerboard_animations_++;
974 if (settings_.timeout_and_draw_when_animation_checkerboards &&
975 consecutive_checkerboard_animations_ >=
976 settings_.maximum_number_of_failed_draws_before_draw_is_forced_) {
977 consecutive_checkerboard_animations_ = 0;
978 // We need to force a draw, but it doesn't make sense to do this until
979 // we've committed and have new textures.
980 forced_redraw_state_ = FORCED_REDRAW_STATE_WAITING_FOR_COMMIT;
981 }
982 break;
983 case DRAW_ABORTED_MISSING_HIGH_RES_CONTENT:
984 // It's not clear whether this missing content is because of missing
985 // pictures (which requires a commit) or because of memory pressure
986 // removing textures (which might not). To be safe, request a commit
987 // anyway.
988 needs_commit_ = true;
989 break;
990 }
991 }
992
993 void SchedulerStateMachine::SetNeedsCommit() {
994 needs_commit_ = true;
995 }
996
997 void SchedulerStateMachine::NotifyReadyToCommit() {
998 DCHECK(commit_state_ == COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED)
999 << AsValue()->ToString();
1000 commit_state_ = COMMIT_STATE_READY_TO_COMMIT;
1001 // In main thread low latency mode, commit should happen right after
1002 // BeginFrame, meaning when this function is called, next action should be
1003 // commit.
1004 if (settings_.main_thread_should_always_be_low_latency)
1005 DCHECK(ShouldCommit());
1006 }
1007
1008 void SchedulerStateMachine::BeginMainFrameAborted(CommitEarlyOutReason reason) {
1009 DCHECK_EQ(commit_state_, COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
1010 switch (reason) {
1011 case CommitEarlyOutReason::ABORTED_OUTPUT_SURFACE_LOST:
1012 case CommitEarlyOutReason::ABORTED_NOT_VISIBLE:
1013 case CommitEarlyOutReason::ABORTED_DEFERRED_COMMIT:
1014 commit_state_ = COMMIT_STATE_IDLE;
1015 SetNeedsCommit();
1016 return;
1017 case CommitEarlyOutReason::FINISHED_NO_UPDATES:
1018 bool commit_has_no_updates = true;
1019 UpdateStateOnCommit(commit_has_no_updates);
1020 return;
1021 }
1022 }
1023
1024 void SchedulerStateMachine::DidPrepareTiles() {
1025 needs_prepare_tiles_ = false;
1026 // "Fill" the PrepareTiles funnel.
1027 prepare_tiles_funnel_++;
1028 }
1029
1030 void SchedulerStateMachine::DidLoseOutputSurface() {
1031 if (output_surface_state_ == OUTPUT_SURFACE_LOST ||
1032 output_surface_state_ == OUTPUT_SURFACE_CREATING)
1033 return;
1034 output_surface_state_ = OUTPUT_SURFACE_LOST;
1035 needs_redraw_ = false;
1036 }
1037
1038 void SchedulerStateMachine::NotifyReadyToActivate() {
1039 if (has_pending_tree_)
1040 pending_tree_is_ready_for_activation_ = true;
1041 }
1042
1043 void SchedulerStateMachine::DidCreateAndInitializeOutputSurface() {
1044 DCHECK_EQ(output_surface_state_, OUTPUT_SURFACE_CREATING);
1045 output_surface_state_ = OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT;
1046
1047 if (did_create_and_initialize_first_output_surface_) {
1048 // TODO(boliu): See if we can remove this when impl-side painting is always
1049 // on. Does anything on the main thread need to update after recreate?
1050 needs_commit_ = true;
1051 }
1052 did_create_and_initialize_first_output_surface_ = true;
1053 pending_swaps_ = 0;
1054 }
1055
1056 void SchedulerStateMachine::NotifyBeginMainFrameStarted() {
1057 DCHECK_EQ(commit_state_, COMMIT_STATE_BEGIN_MAIN_FRAME_SENT);
1058 commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED;
1059 }
1060
1061 bool SchedulerStateMachine::HasInitializedOutputSurface() const {
1062 switch (output_surface_state_) {
1063 case OUTPUT_SURFACE_LOST:
1064 case OUTPUT_SURFACE_CREATING:
1065 return false;
1066
1067 case OUTPUT_SURFACE_ACTIVE:
1068 case OUTPUT_SURFACE_WAITING_FOR_FIRST_COMMIT:
1069 case OUTPUT_SURFACE_WAITING_FOR_FIRST_ACTIVATION:
1070 return true;
1071 }
1072 NOTREACHED();
1073 return false;
1074 }
1075
1076 std::string SchedulerStateMachine::GetStatesForDebugging() const {
1077 return base::StringPrintf("%c %d %d %d %c %c %c %d %d",
1078 needs_commit_ ? 'T' : 'F',
1079 static_cast<int>(output_surface_state_),
1080 static_cast<int>(begin_impl_frame_state_),
1081 static_cast<int>(commit_state_),
1082 has_pending_tree_ ? 'T' : 'F',
1083 pending_tree_is_ready_for_activation_ ? 'T' : 'F',
1084 active_tree_needs_first_draw_ ? 'T' : 'F',
1085 max_pending_swaps_,
1086 pending_swaps_);
1087 }
1088
1089 } // namespace cc
OLDNEW
« no previous file with comments | « cc/scheduler/scheduler_state_machine.h ('k') | cc/scheduler/scheduler_state_machine_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698