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