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