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 14 namespace cc { 15 16 SchedulerStateMachine::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 52 const 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 70 const 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 86 const 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 105 const 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 121 const 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 150 scoped_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 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 // 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 294 bool 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 305 bool 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 332 bool 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 361 bool 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 380 bool 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 408 bool 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 422 bool 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 481 bool 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 498 bool 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 514 SchedulerStateMachine::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 540 void 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 611 void 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 662 void 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 678 void 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 694 void SchedulerStateMachine::UpdateStateOnManageTiles() { 695 needs_manage_tiles_ = false; 696 } 697 698 void SchedulerStateMachine::SetSkipNextBeginMainFrameToReduceLatency() { 699 skip_next_begin_main_frame_to_reduce_latency_ = true; 700 } 701 702 bool 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 714 bool 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. 730 bool 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. 739 bool 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. 774 bool 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 810 void 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 817 void 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 824 void 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 830 void 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 836 bool 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 872 bool 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 913 void SchedulerStateMachine::DidEnterPollForAnticipatedDrawTriggers() { 914 AdvanceCurrentFrameNumber(); 915 inside_poll_for_anticipated_draw_triggers_ = true; 916 } 917 918 void SchedulerStateMachine::DidLeavePollForAnticipatedDrawTriggers() { 919 inside_poll_for_anticipated_draw_triggers_ = false; 920 } 921 922 void SchedulerStateMachine::SetVisible(bool visible) { visible_ = visible; } 923 924 void SchedulerStateMachine::SetCanDraw(bool can_draw) { can_draw_ = can_draw; } 925 926 void SchedulerStateMachine::SetNeedsRedraw() { needs_redraw_ = true; } 927 928 void SchedulerStateMachine::SetNeedsAnimate() { 929 needs_animate_ = true; 930 } 931 932 void SchedulerStateMachine::SetNeedsManageTiles() { 933 if (!needs_manage_tiles_) { 934 TRACE_EVENT0("cc", 935 "SchedulerStateMachine::SetNeedsManageTiles"); 936 needs_manage_tiles_ = true; 937 } 938 } 939 940 void SchedulerStateMachine::SetMaxSwapsPending(int max) { 941 max_pending_swaps_ = max; 942 } 943 944 void 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 951 void SchedulerStateMachine::SetSwapUsedIncompleteTile( 952 bool used_incomplete_tile) { 953 swap_used_incomplete_tile_ = used_incomplete_tile; 954 } 955 956 void SchedulerStateMachine::DidSwapBuffersComplete() { 957 DCHECK_GT(pending_swaps_, 0); 958 pending_swaps_--; 959 } 960 961 void SchedulerStateMachine::SetSmoothnessTakesPriority( 962 bool smoothness_takes_priority) { 963 smoothness_takes_priority_ = smoothness_takes_priority; 964 } 965 966 void 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 1009 void SchedulerStateMachine::SetNeedsCommit() { needs_commit_ = true; } 1010 1011 void SchedulerStateMachine::NotifyReadyToCommit() { 1012 DCHECK(commit_state_ == COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED) << *AsValue(); 1013 commit_state_ = COMMIT_STATE_READY_TO_COMMIT; 1014 } 1015 1016 void 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 1027 void SchedulerStateMachine::DidManageTiles() { 1028 needs_manage_tiles_ = false; 1029 // "Fill" the ManageTiles funnel. 1030 manage_tiles_funnel_++; 1031 } 1032 1033 void 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 1041 void SchedulerStateMachine::NotifyReadyToActivate() { 1042 if (has_pending_tree_) 1043 pending_tree_is_ready_for_activation_ = true; 1044 } 1045 1046 void 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 1059 void SchedulerStateMachine::NotifyBeginMainFrameStarted() { 1060 DCHECK_EQ(commit_state_, COMMIT_STATE_BEGIN_MAIN_FRAME_SENT); 1061 commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED; 1062 } 1063 1064 bool 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