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 #ifndef CC_SCHEDULER_SCHEDULER_STATE_MACHINE_H_
6 #define CC_SCHEDULER_SCHEDULER_STATE_MACHINE_H_
7 
8 #include <stdint.h>
9 
10 #include <memory>
11 #include <string>
12 
13 #include "cc/cc_export.h"
14 #include "cc/scheduler/commit_earlyout_reason.h"
15 #include "cc/scheduler/draw_result.h"
16 #include "cc/scheduler/scheduler_settings.h"
17 #include "cc/tiles/tile_priority.h"
18 #include "components/viz/common/frame_sinks/begin_frame_args.h"
19 #include "third_party/perfetto/protos/perfetto/trace/track_event/chrome_compositor_scheduler_state.pbzero.h"
20 
21 namespace cc {
22 
23 enum class ScrollHandlerState {
24   SCROLL_AFFECTS_SCROLL_HANDLER,
25   SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER,
26 };
27 
28 // The SchedulerStateMachine decides how to coordinate main thread activites
29 // like painting/running javascript with rendering and input activities on the
30 // impl thread.
31 //
32 // The state machine tracks internal state but is also influenced by external
33 // state.  Internal state includes things like whether a frame has been
34 // requested, while external state includes things like the current time being
35 // near to the vblank time.
36 //
37 // The scheduler seperates "what to do next" from the updating of its internal
38 // state to make testing cleaner.
39 class CC_EXPORT SchedulerStateMachine {
40  public:
41   // settings must be valid for the lifetime of this class.
42   explicit SchedulerStateMachine(const SchedulerSettings& settings);
43   SchedulerStateMachine(const SchedulerStateMachine&) = delete;
44   ~SchedulerStateMachine();
45 
46   SchedulerStateMachine& operator=(const SchedulerStateMachine&) = delete;
47 
48   enum class LayerTreeFrameSinkState {
49     NONE,
50     ACTIVE,
51     CREATING,
52     WAITING_FOR_FIRST_COMMIT,
53     WAITING_FOR_FIRST_ACTIVATION,
54   };
55   static perfetto::protos::pbzero::ChromeCompositorStateMachine::MajorState::
56       LayerTreeFrameSinkState
57       LayerTreeFrameSinkStateToProtozeroEnum(LayerTreeFrameSinkState state);
58 
59   // Note: BeginImplFrameState does not cycle through these states in a fixed
60   // order on all platforms. It's up to the scheduler to set these correctly.
61   enum class BeginImplFrameState {
62     IDLE,
63     INSIDE_BEGIN_FRAME,
64     INSIDE_DEADLINE,
65   };
66   static perfetto::protos::pbzero::ChromeCompositorStateMachine::MajorState::
67       BeginImplFrameState
68       BeginImplFrameStateToProtozeroEnum(BeginImplFrameState state);
69 
70   // The scheduler uses a deadline to wait for main thread updates before
71   // submitting a compositor frame. BeginImplFrameDeadlineMode specifies when
72   // the deadline should run.
73   enum class BeginImplFrameDeadlineMode {
74     NONE,  // No deadline should be scheduled e.g. for synchronous compositor.
75     IMMEDIATE,  // Deadline should be scheduled to run immediately.
76     REGULAR,  // Deadline should be scheduled to run at the deadline provided by
77               // in the BeginFrameArgs.
78     LATE,  // Deadline should be scheduled run when the next frame is expected
79            // to arrive.
80     BLOCKED,  // Deadline should be blocked indefinitely until the next frame
81               // arrives.
82   };
83   // TODO(nuskos): Update Scheduler::ScheduleBeginImplFrameDeadline event to
84   // used typed macros so we can remove this ToString function.
85   static const char* BeginImplFrameDeadlineModeToString(
86       BeginImplFrameDeadlineMode mode);
87   static perfetto::protos::pbzero::ChromeCompositorSchedulerState::
88       BeginImplFrameDeadlineMode
89       BeginImplFrameDeadlineModeToProtozeroEnum(
90           BeginImplFrameDeadlineMode mode);
91 
92   enum class BeginMainFrameState {
93     IDLE,             // A new BeginMainFrame can start.
94     SENT,             // A BeginMainFrame has already been issued.
95     READY_TO_COMMIT,  // A previously issued BeginMainFrame has been processed,
96                       // and is ready to commit.
97   };
98   static perfetto::protos::pbzero::ChromeCompositorStateMachine::MajorState::
99       BeginMainFrameState
100       BeginMainFrameStateToProtozeroEnum(BeginMainFrameState state);
101 
102   // When a redraw is forced, it goes through a complete commit -> activation ->
103   // draw cycle. Until a redraw has been forced, it remains in IDLE state.
104   enum class ForcedRedrawOnTimeoutState {
105     IDLE,
106     WAITING_FOR_COMMIT,
107     WAITING_FOR_ACTIVATION,
108     WAITING_FOR_DRAW,
109   };
110   static perfetto::protos::pbzero::ChromeCompositorStateMachine::MajorState::
111       ForcedRedrawOnTimeoutState
112       ForcedRedrawOnTimeoutStateToProtozeroEnum(
113           ForcedRedrawOnTimeoutState state);
114 
begin_main_frame_state()115   BeginMainFrameState begin_main_frame_state() const {
116     return begin_main_frame_state_;
117   }
118 
CommitPending()119   bool CommitPending() const {
120     return begin_main_frame_state_ != BeginMainFrameState::IDLE;
121   }
122 
NewActiveTreeLikely()123   bool NewActiveTreeLikely() const {
124     return (needs_begin_main_frame_ && !last_commit_had_no_updates_) ||
125            CommitPending() || has_pending_tree_;
126   }
127 
RedrawPending()128   bool RedrawPending() const { return needs_redraw_; }
PrepareTilesPending()129   bool PrepareTilesPending() const { return needs_prepare_tiles_; }
130 
131   enum class Action {
132     NONE,
133     SEND_BEGIN_MAIN_FRAME,
134     COMMIT,
135     ACTIVATE_SYNC_TREE,
136     PERFORM_IMPL_SIDE_INVALIDATION,
137     DRAW_IF_POSSIBLE,
138     DRAW_FORCED,
139     DRAW_ABORT,
140     BEGIN_LAYER_TREE_FRAME_SINK_CREATION,
141     PREPARE_TILES,
142     INVALIDATE_LAYER_TREE_FRAME_SINK,
143     NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_UNTIL,
144     NOTIFY_BEGIN_MAIN_FRAME_NOT_EXPECTED_SOON,
145   };
146   static perfetto::protos::pbzero::ChromeCompositorSchedulerAction
147   ActionToProtozeroEnum(Action action);
148 
149   void AsProtozeroInto(
150       perfetto::protos::pbzero::ChromeCompositorStateMachine* state) const;
151 
152   Action NextAction() const;
153   void WillSendBeginMainFrame();
154   void WillNotifyBeginMainFrameNotExpectedUntil();
155   void WillNotifyBeginMainFrameNotExpectedSoon();
156   void WillCommit(bool commit_had_no_updates);
157   void WillActivate();
158   void WillDraw();
159   void WillBeginLayerTreeFrameSinkCreation();
160   void WillPrepareTiles();
161   void WillInvalidateLayerTreeFrameSink();
162   void WillPerformImplSideInvalidation();
163 
164   void DidDraw(DrawResult draw_result);
165 
166   void AbortDraw();
167 
168   // Indicates whether the impl thread needs a BeginImplFrame callback in order
169   // to make progress.
170   bool BeginFrameNeeded() const;
171 
172   // Indicates that the system has entered and left a BeginImplFrame callback.
173   // The scheduler will not draw more than once in a given BeginImplFrame
174   // callback nor send more than one BeginMainFrame message.
175   void OnBeginImplFrame(const viz::BeginFrameId& frame_id, bool animate_only);
176   // Indicates that the scheduler has entered the draw phase. The scheduler
177   // will not draw more than once in a single draw phase.
178   // TODO(sunnyps): Rename OnBeginImplFrameDeadline to OnDraw or similar.
179   void OnBeginImplFrameDeadline();
180   void OnBeginImplFrameIdle();
181 
current_frame_number()182   int current_frame_number() const { return current_frame_number_; }
183 
begin_impl_frame_state()184   BeginImplFrameState begin_impl_frame_state() const {
185     return begin_impl_frame_state_;
186   }
187 
188   // Returns BeginImplFrameDeadlineMode computed based on current state.
189   BeginImplFrameDeadlineMode CurrentBeginImplFrameDeadlineMode() const;
190 
191   // If the main thread didn't manage to produce a new frame in time for the
192   // impl thread to draw, it is in a high latency mode.
main_thread_missed_last_deadline()193   bool main_thread_missed_last_deadline() const {
194     return main_thread_missed_last_deadline_;
195   }
196 
197   bool IsDrawThrottled() const;
198 
199   // Indicates whether the LayerTreeHostImpl is visible.
200   void SetVisible(bool visible);
visible()201   bool visible() const { return visible_; }
202 
203   void SetBeginFrameSourcePaused(bool paused);
begin_frame_source_paused()204   bool begin_frame_source_paused() const { return begin_frame_source_paused_; }
205 
206   // Indicates that a redraw is required, either due to the impl tree changing
207   // or the screen being damaged and simply needing redisplay. Note that if the
208   // changes in the impl tree has not been activated yet, then |needs_redraw()|
209   // can return false. For checking any invalidations, check
210   // |did_invalidate_layer_tree_frame_sink()|.
211   void SetNeedsRedraw();
needs_redraw()212   bool needs_redraw() const { return needs_redraw_; }
213 
did_invalidate_layer_tree_frame_sink()214   bool did_invalidate_layer_tree_frame_sink() const {
215     return did_invalidate_layer_tree_frame_sink_;
216   }
217 
218   bool OnlyImplSideUpdatesExpected() const;
219 
220   // Indicates that prepare-tiles is required. This guarantees another
221   // PrepareTiles will occur shortly (even if no redraw is required).
222   void SetNeedsPrepareTiles();
223 
224   // If the scheduler attempted to draw, this provides feedback regarding
225   // whether or not a CompositorFrame was actually submitted. We might skip the
226   // submitting anything when there is not damage, for example.
227   void DidSubmitCompositorFrame();
228 
229   // Notification from the LayerTreeFrameSink that a submitted frame has been
230   // consumed and it is ready for the next one.
231   void DidReceiveCompositorFrameAck();
232 
pending_submit_frames()233   int pending_submit_frames() const { return pending_submit_frames_; }
234 
235   // Indicates whether to prioritize impl thread latency (i.e., animation
236   // smoothness) over new content activation.
237   void SetTreePrioritiesAndScrollState(TreePriority tree_priority,
238                                        ScrollHandlerState scroll_handler_state);
239 
240   // Indicates if the main thread will likely respond within 1 vsync.
241   void SetCriticalBeginMainFrameToActivateIsFast(bool is_fast);
242 
243   // A function of SetTreePrioritiesAndScrollState and
244   // SetCriticalBeginMainFrameToActivateIsFast.
245   bool ImplLatencyTakesPriority() const;
246 
247   // Indicates that a new begin main frame flow needs to be performed, either
248   // to pull updates from the main thread to the impl, or to push deltas from
249   // the impl thread to main.
250   void SetNeedsBeginMainFrame();
needs_begin_main_frame()251   bool needs_begin_main_frame() const { return needs_begin_main_frame_; }
252 
253   void SetMainThreadWantsBeginMainFrameNotExpectedMessages(bool new_state);
wants_begin_main_frame_not_expected_messages()254   bool wants_begin_main_frame_not_expected_messages() const {
255     return wants_begin_main_frame_not_expected_;
256   }
257 
258   // Requests a single impl frame (after the current frame if there is one
259   // active).
260   void SetNeedsOneBeginImplFrame();
261 
262   // Call this only in response to receiving an Action::SEND_BEGIN_MAIN_FRAME
263   // from NextAction.
264   // Indicates that all painting is complete.
265   void NotifyReadyToCommit();
266 
267   // Call this only in response to receiving an Action::SEND_BEGIN_MAIN_FRAME
268   // from NextAction if the client rejects the BeginMainFrame message.
269   void BeginMainFrameAborted(CommitEarlyOutReason reason);
270 
271   // Indicates production should be skipped to recover latency.
272   void SetSkipNextBeginMainFrameToReduceLatency(bool skip);
273 
274   // For Android WebView, resourceless software draws are allowed even when
275   // invisible.
276   void SetResourcelessSoftwareDraw(bool resourceless_draw);
277 
278   // Indicates whether drawing would, at this time, make sense.
279   // CanDraw can be used to suppress flashes or checkerboarding
280   // when such behavior would be undesirable.
281   void SetCanDraw(bool can);
282 
283   // For Android WebView, indicates that the draw should be skipped because the
284   // frame sink is not ready to receive frames.
285   void SetSkipDraw(bool skip);
286 
287   // Indicates that the pending tree is ready for activation. Returns whether
288   // the notification received updated the state for the current pending tree,
289   // if any.
290   bool NotifyReadyToActivate();
291 
292   // Indicates the active tree's visible tiles are ready to be drawn.
293   void NotifyReadyToDraw();
294 
295   enum class AnimationWorkletState { PROCESSING, IDLE };
296   enum class PaintWorkletState { PROCESSING, IDLE };
297   enum class TreeType { ACTIVE, PENDING };
298 
299   // Indicates if currently processing animation worklets for the active or
300   // pending tree. This is used to determine if the draw deadline should be
301   // extended or activation delayed.
302   void NotifyAnimationWorkletStateChange(AnimationWorkletState state,
303                                          TreeType tree);
304 
305   // Sets whether asynchronous paint worklets are running. Paint worklets
306   // running should block activation of the pending tree, as it isn't fully
307   // painted until they are done.
308   void NotifyPaintWorkletStateChange(PaintWorkletState state);
309 
310   void SetNeedsImplSideInvalidation(bool needs_first_draw_on_activation);
311 
has_pending_tree()312   bool has_pending_tree() const { return has_pending_tree_; }
active_tree_needs_first_draw()313   bool active_tree_needs_first_draw() const {
314     return active_tree_needs_first_draw_;
315   }
316 
317   void DidPrepareTiles();
318   void DidLoseLayerTreeFrameSink();
319   void DidCreateAndInitializeLayerTreeFrameSink();
320   bool HasInitializedLayerTreeFrameSink() const;
321 
322   // True if we need to abort draws to make forward progress.
323   bool PendingDrawsShouldBeAborted() const;
324 
325   bool CouldSendBeginMainFrame() const;
326 
327   void SetDeferBeginMainFrame(bool defer_begin_main_frame);
328 
329   void SetVideoNeedsBeginFrames(bool video_needs_begin_frames);
video_needs_begin_frames()330   bool video_needs_begin_frames() const { return video_needs_begin_frames_; }
331 
did_submit_in_last_frame()332   bool did_submit_in_last_frame() const { return did_submit_in_last_frame_; }
draw_succeeded_in_last_frame()333   bool draw_succeeded_in_last_frame() const {
334     return draw_succeeded_in_last_frame_;
335   }
336 
needs_impl_side_invalidation()337   bool needs_impl_side_invalidation() const {
338     return needs_impl_side_invalidation_;
339   }
previous_pending_tree_was_impl_side()340   bool previous_pending_tree_was_impl_side() const {
341     return previous_pending_tree_was_impl_side_;
342   }
critical_begin_main_frame_to_activate_is_fast()343   bool critical_begin_main_frame_to_activate_is_fast() const {
344     return critical_begin_main_frame_to_activate_is_fast_;
345   }
346 
set_should_defer_invalidation_for_fast_main_frame(bool defer)347   void set_should_defer_invalidation_for_fast_main_frame(bool defer) {
348     should_defer_invalidation_for_fast_main_frame_ = defer;
349   }
should_defer_invalidation_for_fast_main_frame()350   bool should_defer_invalidation_for_fast_main_frame() const {
351     return should_defer_invalidation_for_fast_main_frame_;
352   }
353 
354  protected:
355   bool BeginFrameRequiredForAction() const;
356   bool BeginFrameNeededForVideo() const;
357   bool ProactiveBeginFrameWanted() const;
358 
359   // Indicates if we should post the deadline to draw immediately. This is true
360   // when we aren't expecting a commit or activation, or we're prioritizing
361   // active tree draw (see ImplLatencyTakesPriority()).
362   bool ShouldTriggerBeginImplFrameDeadlineImmediately() const;
363 
364   // Indicates if we shouldn't schedule a deadline. Used to defer drawing until
365   // the entire pipeline is flushed and active tree is ready to draw for
366   // headless.
367   bool ShouldBlockDeadlineIndefinitely() const;
368 
369   bool ShouldPerformImplSideInvalidation() const;
370   bool CouldCreatePendingTree() const;
371   bool ShouldDeferInvalidatingForMainFrame() const;
372 
373   bool ShouldAbortCurrentFrame() const;
374 
375   bool ShouldBeginLayerTreeFrameSinkCreation() const;
376   bool ShouldDraw() const;
377   bool ShouldActivateSyncTree() const;
378   bool ShouldSendBeginMainFrame() const;
379   bool ShouldCommit() const;
380   bool ShouldPrepareTiles() const;
381   bool ShouldInvalidateLayerTreeFrameSink() const;
382   bool ShouldNotifyBeginMainFrameNotExpectedUntil() const;
383   bool ShouldNotifyBeginMainFrameNotExpectedSoon() const;
384 
385   void WillDrawInternal();
386   void WillPerformImplSideInvalidationInternal();
387   void DidDrawInternal(DrawResult draw_result);
388 
389   const SchedulerSettings settings_;
390 
391   LayerTreeFrameSinkState layer_tree_frame_sink_state_ =
392       LayerTreeFrameSinkState::NONE;
393   BeginImplFrameState begin_impl_frame_state_ = BeginImplFrameState::IDLE;
394   BeginMainFrameState begin_main_frame_state_ = BeginMainFrameState::IDLE;
395 
396   // A redraw is forced when too many checkerboarded-frames are produced during
397   // an animation.
398   ForcedRedrawOnTimeoutState forced_redraw_state_ =
399       ForcedRedrawOnTimeoutState::IDLE;
400 
401   // These are used for tracing only.
402   int commit_count_ = 0;
403   int current_frame_number_ = 0;
404   int last_frame_number_submit_performed_ = -1;
405   int last_frame_number_draw_performed_ = -1;
406   int last_frame_number_begin_main_frame_sent_ = -1;
407   int last_frame_number_invalidate_layer_tree_frame_sink_performed_ = -1;
408 
409   // Inputs from the last impl frame that are required for decisions made in
410   // this impl frame. The values from the last frame are cached before being
411   // reset in OnBeginImplFrame.
412   struct FrameEvents {
413     bool commit_had_no_updates = false;
414     bool did_commit_during_frame = false;
415   };
416   FrameEvents last_frame_events_;
417 
418   // These are used to ensure that an action only happens once per frame,
419   // deadline, etc.
420   bool did_draw_ = false;
421   bool did_send_begin_main_frame_for_current_frame_ = true;
422 
423   // Initialized to true to prevent begin main frame before begin frames have
424   // started. Reset to true when we stop asking for begin frames.
425   bool did_notify_begin_main_frame_not_expected_until_ = true;
426   bool did_notify_begin_main_frame_not_expected_soon_ = true;
427 
428   bool did_commit_during_frame_ = false;
429   bool did_invalidate_layer_tree_frame_sink_ = false;
430   bool did_perform_impl_side_invalidation_ = false;
431   bool did_prepare_tiles_ = false;
432 
433   int consecutive_checkerboard_animations_ = 0;
434   int pending_submit_frames_ = 0;
435   int submit_frames_with_current_layer_tree_frame_sink_ = 0;
436   bool needs_redraw_ = false;
437   bool needs_prepare_tiles_ = false;
438   bool needs_begin_main_frame_ = false;
439   bool needs_one_begin_impl_frame_ = false;
440   bool visible_ = false;
441   bool begin_frame_source_paused_ = false;
442   bool resourceless_draw_ = false;
443   bool can_draw_ = false;
444   bool skip_draw_ = false;
445   bool has_pending_tree_ = false;
446   bool pending_tree_is_ready_for_activation_ = false;
447   bool active_tree_needs_first_draw_ = false;
448   bool did_create_and_initialize_first_layer_tree_frame_sink_ = false;
449   TreePriority tree_priority_ = NEW_CONTENT_TAKES_PRIORITY;
450   ScrollHandlerState scroll_handler_state_ =
451       ScrollHandlerState::SCROLL_DOES_NOT_AFFECT_SCROLL_HANDLER;
452   bool critical_begin_main_frame_to_activate_is_fast_ = true;
453   bool main_thread_missed_last_deadline_ = false;
454   bool skip_next_begin_main_frame_to_reduce_latency_ = false;
455   bool defer_begin_main_frame_ = false;
456   bool video_needs_begin_frames_ = false;
457   bool last_commit_had_no_updates_ = false;
458   bool active_tree_is_ready_to_draw_ = true;
459   bool did_attempt_draw_in_last_frame_ = false;
460   bool draw_succeeded_in_last_frame_ = false;
461   bool did_submit_in_last_frame_ = false;
462   bool needs_impl_side_invalidation_ = false;
463   bool next_invalidation_needs_first_draw_on_activation_ = false;
464   bool should_defer_invalidation_for_fast_main_frame_ = true;
465   bool begin_frame_is_animate_only_ = false;
466 
467   // Number of async mutation cycles for the active tree that are in-flight or
468   // queued.  Can be 0, 1 or 2.
469   int processing_animation_worklets_for_active_tree_ = 0;
470   // Indicates if an aysnc mutation cycle is in-flight or queued for the pending
471   // tree.  Only one can be running or queued at any time.
472   bool processing_animation_worklets_for_pending_tree_ = false;
473   // Indicates if asychronous paint worklet painting is ongoing for the pending
474   // tree. During this time we should not activate the pending tree.
475   bool processing_paint_worklets_for_pending_tree_ = false;
476 
477   bool previous_pending_tree_was_impl_side_ = false;
478   bool current_pending_tree_is_impl_side_ = false;
479 
480   bool wants_begin_main_frame_not_expected_ = false;
481 
482   // If set to true, the pending tree must be drawn at least once after
483   // activation before a new tree can be activated.
484   bool pending_tree_needs_first_draw_on_activation_ = false;
485 };
486 
487 }  // namespace cc
488 
489 #endif  // CC_SCHEDULER_SCHEDULER_STATE_MACHINE_H_
490