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