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.h" 6 7 #include <algorithm> 8 #include "base/auto_reset.h" 9 #include "base/debug/trace_event.h" 10 #include "base/debug/trace_event_argument.h" 11 #include "base/logging.h" 12 #include "base/single_thread_task_runner.h" 13 #include "cc/debug/devtools_instrumentation.h" 14 #include "cc/debug/traced_value.h" 15 #include "cc/scheduler/delay_based_time_source.h" 16 #include "ui/gfx/frame_time.h" 17 18 namespace cc { 19 20 Scheduler::SyntheticBeginFrameSource::SyntheticBeginFrameSource( 21 Scheduler* scheduler, 22 scoped_refptr<DelayBasedTimeSource> time_source) 23 : scheduler_(scheduler), time_source_(time_source) { 24 time_source_->SetClient(this); 25 } 26 27 Scheduler::SyntheticBeginFrameSource::~SyntheticBeginFrameSource() { 28 } 29 30 void Scheduler::SyntheticBeginFrameSource::CommitVSyncParameters( 31 base::TimeTicks timebase, 32 base::TimeDelta interval) { 33 time_source_->SetTimebaseAndInterval(timebase, interval); 34 } 35 36 void Scheduler::SyntheticBeginFrameSource::SetNeedsBeginFrame( 37 bool needs_begin_frame, 38 std::deque<BeginFrameArgs>* begin_retro_frame_args) { 39 DCHECK(begin_retro_frame_args); 40 base::TimeTicks missed_tick_time = 41 time_source_->SetActive(needs_begin_frame); 42 if (!missed_tick_time.is_null()) { 43 begin_retro_frame_args->push_back( 44 CreateSyntheticBeginFrameArgs(missed_tick_time)); 45 } 46 } 47 48 bool Scheduler::SyntheticBeginFrameSource::IsActive() const { 49 return time_source_->Active(); 50 } 51 52 void Scheduler::SyntheticBeginFrameSource::OnTimerTick() { 53 BeginFrameArgs begin_frame_args( 54 CreateSyntheticBeginFrameArgs(time_source_->LastTickTime())); 55 scheduler_->BeginFrame(begin_frame_args); 56 } 57 58 void Scheduler::SyntheticBeginFrameSource::AsValueInto( 59 base::debug::TracedValue* state) const { 60 time_source_->AsValueInto(state); 61 } 62 63 BeginFrameArgs 64 Scheduler::SyntheticBeginFrameSource::CreateSyntheticBeginFrameArgs( 65 base::TimeTicks frame_time) { 66 base::TimeTicks deadline = time_source_->NextTickTime(); 67 return BeginFrameArgs::Create( 68 frame_time, deadline, scheduler_->VSyncInterval()); 69 } 70 71 Scheduler::Scheduler( 72 SchedulerClient* client, 73 const SchedulerSettings& scheduler_settings, 74 int layer_tree_host_id, 75 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) 76 : settings_(scheduler_settings), 77 client_(client), 78 layer_tree_host_id_(layer_tree_host_id), 79 task_runner_(task_runner), 80 vsync_interval_(BeginFrameArgs::DefaultInterval()), 81 last_set_needs_begin_frame_(false), 82 begin_unthrottled_frame_posted_(false), 83 begin_retro_frame_posted_(false), 84 state_machine_(scheduler_settings), 85 inside_process_scheduled_actions_(false), 86 inside_action_(SchedulerStateMachine::ACTION_NONE), 87 weak_factory_(this) { 88 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), 89 "Scheduler::Scheduler", 90 "settings", 91 settings_.AsValue()); 92 DCHECK(client_); 93 DCHECK(!state_machine_.BeginFrameNeeded()); 94 if (settings_.main_frame_before_activation_enabled) { 95 DCHECK(settings_.main_frame_before_draw_enabled); 96 } 97 98 begin_retro_frame_closure_ = 99 base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr()); 100 begin_unthrottled_frame_closure_ = 101 base::Bind(&Scheduler::BeginUnthrottledFrame, weak_factory_.GetWeakPtr()); 102 begin_impl_frame_deadline_closure_ = base::Bind( 103 &Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr()); 104 poll_for_draw_triggers_closure_ = base::Bind( 105 &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr()); 106 advance_commit_state_closure_ = base::Bind( 107 &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr()); 108 109 if (!settings_.begin_frame_scheduling_enabled) { 110 SetupSyntheticBeginFrames(); 111 } 112 } 113 114 Scheduler::~Scheduler() { 115 if (synthetic_begin_frame_source_) { 116 synthetic_begin_frame_source_->SetNeedsBeginFrame(false, 117 &begin_retro_frame_args_); 118 } 119 } 120 121 void Scheduler::SetupSyntheticBeginFrames() { 122 scoped_refptr<DelayBasedTimeSource> time_source; 123 if (gfx::FrameTime::TimestampsAreHighRes()) { 124 time_source = DelayBasedTimeSourceHighRes::Create(VSyncInterval(), 125 task_runner_.get()); 126 } else { 127 time_source = 128 DelayBasedTimeSource::Create(VSyncInterval(), task_runner_.get()); 129 } 130 DCHECK(!synthetic_begin_frame_source_); 131 synthetic_begin_frame_source_.reset( 132 new SyntheticBeginFrameSource(this, time_source)); 133 } 134 135 base::TimeTicks Scheduler::Now() const { 136 return gfx::FrameTime::Now(); 137 } 138 139 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, 140 base::TimeDelta interval) { 141 // TODO(brianderson): We should not be receiving 0 intervals. 142 if (interval == base::TimeDelta()) 143 interval = BeginFrameArgs::DefaultInterval(); 144 vsync_interval_ = interval; 145 if (!settings_.begin_frame_scheduling_enabled) 146 synthetic_begin_frame_source_->CommitVSyncParameters(timebase, interval); 147 } 148 149 void Scheduler::SetEstimatedParentDrawTime(base::TimeDelta draw_time) { 150 DCHECK_GE(draw_time.ToInternalValue(), 0); 151 estimated_parent_draw_time_ = draw_time; 152 } 153 154 void Scheduler::SetCanStart() { 155 state_machine_.SetCanStart(); 156 ProcessScheduledActions(); 157 } 158 159 void Scheduler::SetVisible(bool visible) { 160 state_machine_.SetVisible(visible); 161 ProcessScheduledActions(); 162 } 163 164 void Scheduler::SetCanDraw(bool can_draw) { 165 state_machine_.SetCanDraw(can_draw); 166 ProcessScheduledActions(); 167 } 168 169 void Scheduler::NotifyReadyToActivate() { 170 state_machine_.NotifyReadyToActivate(); 171 ProcessScheduledActions(); 172 } 173 174 void Scheduler::SetNeedsCommit() { 175 state_machine_.SetNeedsCommit(); 176 ProcessScheduledActions(); 177 } 178 179 void Scheduler::SetNeedsRedraw() { 180 state_machine_.SetNeedsRedraw(); 181 ProcessScheduledActions(); 182 } 183 184 void Scheduler::SetNeedsAnimate() { 185 state_machine_.SetNeedsAnimate(); 186 ProcessScheduledActions(); 187 } 188 189 void Scheduler::SetNeedsManageTiles() { 190 DCHECK(!IsInsideAction(SchedulerStateMachine::ACTION_MANAGE_TILES)); 191 state_machine_.SetNeedsManageTiles(); 192 ProcessScheduledActions(); 193 } 194 195 void Scheduler::SetMaxSwapsPending(int max) { 196 state_machine_.SetMaxSwapsPending(max); 197 } 198 199 void Scheduler::DidSwapBuffers() { 200 state_machine_.DidSwapBuffers(); 201 202 // There is no need to call ProcessScheduledActions here because 203 // swapping should not trigger any new actions. 204 if (!inside_process_scheduled_actions_) { 205 DCHECK_EQ(state_machine_.NextAction(), SchedulerStateMachine::ACTION_NONE); 206 } 207 } 208 209 void Scheduler::SetSwapUsedIncompleteTile(bool used_incomplete_tile) { 210 state_machine_.SetSwapUsedIncompleteTile(used_incomplete_tile); 211 ProcessScheduledActions(); 212 } 213 214 void Scheduler::DidSwapBuffersComplete() { 215 state_machine_.DidSwapBuffersComplete(); 216 ProcessScheduledActions(); 217 } 218 219 void Scheduler::SetImplLatencyTakesPriority(bool impl_latency_takes_priority) { 220 state_machine_.SetImplLatencyTakesPriority(impl_latency_takes_priority); 221 ProcessScheduledActions(); 222 } 223 224 void Scheduler::NotifyReadyToCommit() { 225 TRACE_EVENT0("cc", "Scheduler::NotifyReadyToCommit"); 226 state_machine_.NotifyReadyToCommit(); 227 ProcessScheduledActions(); 228 } 229 230 void Scheduler::BeginMainFrameAborted(bool did_handle) { 231 TRACE_EVENT0("cc", "Scheduler::BeginMainFrameAborted"); 232 state_machine_.BeginMainFrameAborted(did_handle); 233 ProcessScheduledActions(); 234 } 235 236 void Scheduler::DidManageTiles() { 237 state_machine_.DidManageTiles(); 238 } 239 240 void Scheduler::DidLoseOutputSurface() { 241 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface"); 242 state_machine_.DidLoseOutputSurface(); 243 last_set_needs_begin_frame_ = false; 244 if (!settings_.begin_frame_scheduling_enabled) { 245 synthetic_begin_frame_source_->SetNeedsBeginFrame(false, 246 &begin_retro_frame_args_); 247 } 248 begin_retro_frame_args_.clear(); 249 ProcessScheduledActions(); 250 } 251 252 void Scheduler::DidCreateAndInitializeOutputSurface() { 253 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); 254 DCHECK(!last_set_needs_begin_frame_); 255 DCHECK(begin_impl_frame_deadline_task_.IsCancelled()); 256 state_machine_.DidCreateAndInitializeOutputSurface(); 257 ProcessScheduledActions(); 258 } 259 260 void Scheduler::NotifyBeginMainFrameStarted() { 261 TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted"); 262 state_machine_.NotifyBeginMainFrameStarted(); 263 } 264 265 base::TimeTicks Scheduler::AnticipatedDrawTime() const { 266 if (!last_set_needs_begin_frame_ || 267 begin_impl_frame_args_.interval <= base::TimeDelta()) 268 return base::TimeTicks(); 269 270 base::TimeTicks now = Now(); 271 base::TimeTicks timebase = std::max(begin_impl_frame_args_.frame_time, 272 begin_impl_frame_args_.deadline); 273 int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval); 274 return timebase + (begin_impl_frame_args_.interval * intervals); 275 } 276 277 base::TimeTicks Scheduler::LastBeginImplFrameTime() { 278 return begin_impl_frame_args_.frame_time; 279 } 280 281 void Scheduler::SetupNextBeginFrameIfNeeded() { 282 if (!task_runner_.get()) 283 return; 284 285 bool needs_begin_frame = state_machine_.BeginFrameNeeded(); 286 287 if (settings_.throttle_frame_production) { 288 SetupNextBeginFrameWhenVSyncThrottlingEnabled(needs_begin_frame); 289 } else { 290 SetupNextBeginFrameWhenVSyncThrottlingDisabled(needs_begin_frame); 291 } 292 SetupPollingMechanisms(needs_begin_frame); 293 } 294 295 // When we are throttling frame production, we request BeginFrames 296 // from the OutputSurface. 297 void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingEnabled( 298 bool needs_begin_frame) { 299 bool at_end_of_deadline = 300 state_machine_.begin_impl_frame_state() == 301 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE; 302 303 bool should_call_set_needs_begin_frame = 304 // Always request the BeginFrame immediately if it wasn't needed before. 305 (needs_begin_frame && !last_set_needs_begin_frame_) || 306 // Only stop requesting BeginFrames after a deadline. 307 (!needs_begin_frame && last_set_needs_begin_frame_ && at_end_of_deadline); 308 309 if (should_call_set_needs_begin_frame) { 310 if (settings_.begin_frame_scheduling_enabled) { 311 client_->SetNeedsBeginFrame(needs_begin_frame); 312 } else { 313 synthetic_begin_frame_source_->SetNeedsBeginFrame( 314 needs_begin_frame, &begin_retro_frame_args_); 315 } 316 last_set_needs_begin_frame_ = needs_begin_frame; 317 } 318 319 PostBeginRetroFrameIfNeeded(); 320 } 321 322 // When we aren't throttling frame production, we initiate a BeginFrame 323 // as soon as one is needed. 324 void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingDisabled( 325 bool needs_begin_frame) { 326 last_set_needs_begin_frame_ = needs_begin_frame; 327 328 if (!needs_begin_frame || begin_unthrottled_frame_posted_) 329 return; 330 331 if (state_machine_.begin_impl_frame_state() != 332 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE && 333 state_machine_.begin_impl_frame_state() != 334 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) { 335 return; 336 } 337 338 begin_unthrottled_frame_posted_ = true; 339 task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_); 340 } 341 342 // BeginUnthrottledFrame is used when we aren't throttling frame production. 343 // This will usually be because VSync is disabled. 344 void Scheduler::BeginUnthrottledFrame() { 345 DCHECK(!settings_.throttle_frame_production); 346 DCHECK(begin_retro_frame_args_.empty()); 347 348 base::TimeTicks now = Now(); 349 base::TimeTicks deadline = now + vsync_interval_; 350 351 BeginFrameArgs begin_frame_args = 352 BeginFrameArgs::Create(now, deadline, vsync_interval_); 353 BeginImplFrame(begin_frame_args); 354 355 begin_unthrottled_frame_posted_ = false; 356 } 357 358 // We may need to poll when we can't rely on BeginFrame to advance certain 359 // state or to avoid deadlock. 360 void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) { 361 bool needs_advance_commit_state_timer = false; 362 // Setup PollForAnticipatedDrawTriggers if we need to monitor state but 363 // aren't expecting any more BeginFrames. This should only be needed by 364 // the synchronous compositor when BeginFrameNeeded is false. 365 if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) { 366 DCHECK(!state_machine_.SupportsProactiveBeginFrame()); 367 DCHECK(!needs_begin_frame); 368 if (poll_for_draw_triggers_task_.IsCancelled()) { 369 poll_for_draw_triggers_task_.Reset(poll_for_draw_triggers_closure_); 370 base::TimeDelta delay = begin_impl_frame_args_.IsValid() 371 ? begin_impl_frame_args_.interval 372 : BeginFrameArgs::DefaultInterval(); 373 task_runner_->PostDelayedTask( 374 FROM_HERE, poll_for_draw_triggers_task_.callback(), delay); 375 } 376 } else { 377 poll_for_draw_triggers_task_.Cancel(); 378 379 // At this point we'd prefer to advance through the commit flow by 380 // drawing a frame, however it's possible that the frame rate controller 381 // will not give us a BeginFrame until the commit completes. See 382 // crbug.com/317430 for an example of a swap ack being held on commit. Thus 383 // we set a repeating timer to poll on ProcessScheduledActions until we 384 // successfully reach BeginFrame. Synchronous compositor does not use 385 // frame rate controller or have the circular wait in the bug. 386 if (IsBeginMainFrameSentOrStarted() && 387 !settings_.using_synchronous_renderer_compositor) { 388 needs_advance_commit_state_timer = true; 389 } 390 } 391 392 if (needs_advance_commit_state_timer) { 393 if (advance_commit_state_task_.IsCancelled() && 394 begin_impl_frame_args_.IsValid()) { 395 // Since we'd rather get a BeginImplFrame by the normal mechanism, we 396 // set the interval to twice the interval from the previous frame. 397 advance_commit_state_task_.Reset(advance_commit_state_closure_); 398 task_runner_->PostDelayedTask(FROM_HERE, 399 advance_commit_state_task_.callback(), 400 begin_impl_frame_args_.interval * 2); 401 } 402 } else { 403 advance_commit_state_task_.Cancel(); 404 } 405 } 406 407 // BeginFrame is the mechanism that tells us that now is a good time to start 408 // making a frame. Usually this means that user input for the frame is complete. 409 // If the scheduler is busy, we queue the BeginFrame to be handled later as 410 // a BeginRetroFrame. 411 void Scheduler::BeginFrame(const BeginFrameArgs& args) { 412 TRACE_EVENT1("cc", "Scheduler::BeginFrame", "args", args.AsValue()); 413 DCHECK(settings_.throttle_frame_production); 414 415 BeginFrameArgs adjusted_args(args); 416 adjusted_args.deadline -= EstimatedParentDrawTime(); 417 418 bool should_defer_begin_frame; 419 if (settings_.using_synchronous_renderer_compositor) { 420 should_defer_begin_frame = false; 421 } else { 422 should_defer_begin_frame = 423 !begin_retro_frame_args_.empty() || begin_retro_frame_posted_ || 424 !last_set_needs_begin_frame_ || 425 (state_machine_.begin_impl_frame_state() != 426 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); 427 } 428 429 if (should_defer_begin_frame) { 430 begin_retro_frame_args_.push_back(adjusted_args); 431 TRACE_EVENT_INSTANT0( 432 "cc", "Scheduler::BeginFrame deferred", TRACE_EVENT_SCOPE_THREAD); 433 return; 434 } 435 436 BeginImplFrame(adjusted_args); 437 } 438 439 // BeginRetroFrame is called for BeginFrames that we've deferred because 440 // the scheduler was in the middle of processing a previous BeginFrame. 441 void Scheduler::BeginRetroFrame() { 442 TRACE_EVENT0("cc", "Scheduler::BeginRetroFrame"); 443 DCHECK(!settings_.using_synchronous_renderer_compositor); 444 DCHECK(begin_retro_frame_posted_); 445 begin_retro_frame_posted_ = false; 446 447 // If there aren't any retroactive BeginFrames, then we've lost the 448 // OutputSurface and should abort. 449 if (begin_retro_frame_args_.empty()) 450 return; 451 452 // Discard expired BeginRetroFrames 453 // Today, we should always end up with at most one un-expired BeginRetroFrame 454 // because deadlines will not be greater than the next frame time. We don't 455 // DCHECK though because some systems don't always have monotonic timestamps. 456 // TODO(brianderson): In the future, long deadlines could result in us not 457 // draining the queue if we don't catch up. If we consistently can't catch 458 // up, our fallback should be to lower our frame rate. 459 base::TimeTicks now = Now(); 460 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); 461 while (!begin_retro_frame_args_.empty()) { 462 base::TimeTicks adjusted_deadline = AdjustedBeginImplFrameDeadline( 463 begin_retro_frame_args_.front(), draw_duration_estimate); 464 if (now <= adjusted_deadline) 465 break; 466 467 TRACE_EVENT_INSTANT2("cc", 468 "Scheduler::BeginRetroFrame discarding", 469 TRACE_EVENT_SCOPE_THREAD, 470 "deadline - now", 471 (adjusted_deadline - now).InMicroseconds(), 472 "BeginFrameArgs", 473 begin_retro_frame_args_.front().AsValue()); 474 begin_retro_frame_args_.pop_front(); 475 } 476 477 if (begin_retro_frame_args_.empty()) { 478 DCHECK(settings_.throttle_frame_production); 479 TRACE_EVENT_INSTANT0("cc", 480 "Scheduler::BeginRetroFrames all expired", 481 TRACE_EVENT_SCOPE_THREAD); 482 } else { 483 BeginImplFrame(begin_retro_frame_args_.front()); 484 begin_retro_frame_args_.pop_front(); 485 } 486 } 487 488 // There could be a race between the posted BeginRetroFrame and a new 489 // BeginFrame arriving via the normal mechanism. Scheduler::BeginFrame 490 // will check if there is a pending BeginRetroFrame to ensure we handle 491 // BeginFrames in FIFO order. 492 void Scheduler::PostBeginRetroFrameIfNeeded() { 493 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), 494 "Scheduler::PostBeginRetroFrameIfNeeded", 495 "state", 496 AsValue()); 497 if (!last_set_needs_begin_frame_) 498 return; 499 500 if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_) 501 return; 502 503 // begin_retro_frame_args_ should always be empty for the 504 // synchronous compositor. 505 DCHECK(!settings_.using_synchronous_renderer_compositor); 506 507 if (state_machine_.begin_impl_frame_state() != 508 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE) 509 return; 510 511 begin_retro_frame_posted_ = true; 512 task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_); 513 } 514 515 // BeginImplFrame starts a compositor frame that will wait up until a deadline 516 // for a BeginMainFrame+activation to complete before it times out and draws 517 // any asynchronous animation and scroll/pinch updates. 518 void Scheduler::BeginImplFrame(const BeginFrameArgs& args) { 519 TRACE_EVENT1("cc", "Scheduler::BeginImplFrame", "args", args.AsValue()); 520 DCHECK_EQ(state_machine_.begin_impl_frame_state(), 521 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); 522 DCHECK(state_machine_.HasInitializedOutputSurface()); 523 524 advance_commit_state_task_.Cancel(); 525 526 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); 527 begin_impl_frame_args_ = args; 528 begin_impl_frame_args_.deadline -= draw_duration_estimate; 529 530 if (!state_machine_.impl_latency_takes_priority() && 531 state_machine_.MainThreadIsInHighLatencyMode() && 532 CanCommitAndActivateBeforeDeadline()) { 533 state_machine_.SetSkipNextBeginMainFrameToReduceLatency(); 534 } 535 536 client_->WillBeginImplFrame(begin_impl_frame_args_); 537 state_machine_.OnBeginImplFrame(begin_impl_frame_args_); 538 devtools_instrumentation::DidBeginFrame(layer_tree_host_id_); 539 540 ProcessScheduledActions(); 541 542 state_machine_.OnBeginImplFrameDeadlinePending(); 543 ScheduleBeginImplFrameDeadline( 544 AdjustedBeginImplFrameDeadline(args, draw_duration_estimate)); 545 } 546 547 base::TimeTicks Scheduler::AdjustedBeginImplFrameDeadline( 548 const BeginFrameArgs& args, 549 base::TimeDelta draw_duration_estimate) const { 550 if (settings_.using_synchronous_renderer_compositor) { 551 // The synchronous compositor needs to draw right away. 552 return base::TimeTicks(); 553 } else if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) { 554 // We are ready to draw a new active tree immediately. 555 return base::TimeTicks(); 556 } else if (state_machine_.needs_redraw()) { 557 // We have an animation or fast input path on the impl thread that wants 558 // to draw, so don't wait too long for a new active tree. 559 return args.deadline - draw_duration_estimate; 560 } else { 561 // The impl thread doesn't have anything it wants to draw and we are just 562 // waiting for a new active tree, so post the deadline for the next 563 // expected BeginImplFrame start. This allows us to draw immediately when 564 // there is a new active tree, instead of waiting for the next 565 // BeginImplFrame. 566 // TODO(brianderson): Handle long deadlines (that are past the next frame's 567 // frame time) properly instead of using this hack. 568 return args.frame_time + args.interval; 569 } 570 } 571 572 void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) { 573 TRACE_EVENT1( 574 "cc", "Scheduler::ScheduleBeginImplFrameDeadline", "deadline", deadline); 575 if (settings_.using_synchronous_renderer_compositor) { 576 // The synchronous renderer compositor has to make its GL calls 577 // within this call. 578 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks 579 // so the sychronous renderer compositor can take advantage of splitting 580 // up the BeginImplFrame and deadline as well. 581 OnBeginImplFrameDeadline(); 582 return; 583 } 584 begin_impl_frame_deadline_task_.Cancel(); 585 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_); 586 587 base::TimeDelta delta = deadline - Now(); 588 if (delta <= base::TimeDelta()) 589 delta = base::TimeDelta(); 590 task_runner_->PostDelayedTask( 591 FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta); 592 } 593 594 void Scheduler::OnBeginImplFrameDeadline() { 595 TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline"); 596 begin_impl_frame_deadline_task_.Cancel(); 597 598 // We split the deadline actions up into two phases so the state machine 599 // has a chance to trigger actions that should occur durring and after 600 // the deadline separately. For example: 601 // * Sending the BeginMainFrame will not occur after the deadline in 602 // order to wait for more user-input before starting the next commit. 603 // * Creating a new OuputSurface will not occur during the deadline in 604 // order to allow the state machine to "settle" first. 605 state_machine_.OnBeginImplFrameDeadline(); 606 ProcessScheduledActions(); 607 state_machine_.OnBeginImplFrameIdle(); 608 ProcessScheduledActions(); 609 610 client_->DidBeginImplFrameDeadline(); 611 } 612 613 void Scheduler::PollForAnticipatedDrawTriggers() { 614 TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers"); 615 poll_for_draw_triggers_task_.Cancel(); 616 state_machine_.DidEnterPollForAnticipatedDrawTriggers(); 617 ProcessScheduledActions(); 618 state_machine_.DidLeavePollForAnticipatedDrawTriggers(); 619 } 620 621 void Scheduler::PollToAdvanceCommitState() { 622 TRACE_EVENT0("cc", "Scheduler::PollToAdvanceCommitState"); 623 advance_commit_state_task_.Cancel(); 624 ProcessScheduledActions(); 625 } 626 627 void Scheduler::DrawAndSwapIfPossible() { 628 DrawResult result = client_->ScheduledActionDrawAndSwapIfPossible(); 629 state_machine_.DidDrawIfPossibleCompleted(result); 630 } 631 632 void Scheduler::ProcessScheduledActions() { 633 // We do not allow ProcessScheduledActions to be recursive. 634 // The top-level call will iteratively execute the next action for us anyway. 635 if (inside_process_scheduled_actions_) 636 return; 637 638 base::AutoReset<bool> mark_inside(&inside_process_scheduled_actions_, true); 639 640 SchedulerStateMachine::Action action; 641 do { 642 action = state_machine_.NextAction(); 643 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), 644 "SchedulerStateMachine", 645 "state", 646 AsValue()); 647 VLOG(2) << "Scheduler::ProcessScheduledActions: " 648 << SchedulerStateMachine::ActionToString(action) << " " 649 << state_machine_.GetStatesForDebugging(); 650 state_machine_.UpdateState(action); 651 base::AutoReset<SchedulerStateMachine::Action> 652 mark_inside_action(&inside_action_, action); 653 switch (action) { 654 case SchedulerStateMachine::ACTION_NONE: 655 break; 656 case SchedulerStateMachine::ACTION_ANIMATE: 657 client_->ScheduledActionAnimate(); 658 break; 659 case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME: 660 client_->ScheduledActionSendBeginMainFrame(); 661 break; 662 case SchedulerStateMachine::ACTION_COMMIT: 663 client_->ScheduledActionCommit(); 664 break; 665 case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES: 666 client_->ScheduledActionUpdateVisibleTiles(); 667 break; 668 case SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE: 669 client_->ScheduledActionActivateSyncTree(); 670 break; 671 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE: 672 DrawAndSwapIfPossible(); 673 break; 674 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED: 675 client_->ScheduledActionDrawAndSwapForced(); 676 break; 677 case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT: 678 // No action is actually performed, but this allows the state machine to 679 // advance out of its waiting to draw state without actually drawing. 680 break; 681 case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION: 682 client_->ScheduledActionBeginOutputSurfaceCreation(); 683 break; 684 case SchedulerStateMachine::ACTION_MANAGE_TILES: 685 client_->ScheduledActionManageTiles(); 686 break; 687 } 688 } while (action != SchedulerStateMachine::ACTION_NONE); 689 690 SetupNextBeginFrameIfNeeded(); 691 client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime()); 692 693 if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) { 694 DCHECK(!settings_.using_synchronous_renderer_compositor); 695 ScheduleBeginImplFrameDeadline(base::TimeTicks()); 696 } 697 } 698 699 bool Scheduler::WillDrawIfNeeded() const { 700 return !state_machine_.PendingDrawsShouldBeAborted(); 701 } 702 703 scoped_refptr<base::debug::ConvertableToTraceFormat> Scheduler::AsValue() 704 const { 705 scoped_refptr<base::debug::TracedValue> state = 706 new base::debug::TracedValue(); 707 AsValueInto(state.get()); 708 return state; 709 } 710 711 void Scheduler::AsValueInto(base::debug::TracedValue* state) const { 712 state->BeginDictionary("state_machine"); 713 state_machine_.AsValueInto(state, Now()); 714 state->EndDictionary(); 715 if (synthetic_begin_frame_source_) { 716 state->BeginDictionary("synthetic_begin_frame_source_"); 717 synthetic_begin_frame_source_->AsValueInto(state); 718 state->EndDictionary(); 719 } 720 721 state->BeginDictionary("scheduler_state"); 722 state->SetDouble("time_until_anticipated_draw_time_ms", 723 (AnticipatedDrawTime() - Now()).InMillisecondsF()); 724 state->SetDouble("vsync_interval_ms", vsync_interval_.InMillisecondsF()); 725 state->SetDouble("estimated_parent_draw_time_ms", 726 estimated_parent_draw_time_.InMillisecondsF()); 727 state->SetBoolean("last_set_needs_begin_frame_", last_set_needs_begin_frame_); 728 state->SetBoolean("begin_unthrottled_frame_posted_", 729 begin_unthrottled_frame_posted_); 730 state->SetBoolean("begin_retro_frame_posted_", begin_retro_frame_posted_); 731 state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size()); 732 state->SetBoolean("begin_impl_frame_deadline_task_", 733 !begin_impl_frame_deadline_task_.IsCancelled()); 734 state->SetBoolean("poll_for_draw_triggers_task_", 735 !poll_for_draw_triggers_task_.IsCancelled()); 736 state->SetBoolean("advance_commit_state_task_", 737 !advance_commit_state_task_.IsCancelled()); 738 state->BeginDictionary("begin_impl_frame_args"); 739 begin_impl_frame_args_.AsValueInto(state); 740 state->EndDictionary(); 741 742 state->EndDictionary(); 743 744 state->BeginDictionary("client_state"); 745 state->SetDouble("draw_duration_estimate_ms", 746 client_->DrawDurationEstimate().InMillisecondsF()); 747 state->SetDouble( 748 "begin_main_frame_to_commit_duration_estimate_ms", 749 client_->BeginMainFrameToCommitDurationEstimate().InMillisecondsF()); 750 state->SetDouble( 751 "commit_to_activate_duration_estimate_ms", 752 client_->CommitToActivateDurationEstimate().InMillisecondsF()); 753 state->EndDictionary(); 754 } 755 756 bool Scheduler::CanCommitAndActivateBeforeDeadline() const { 757 // Check if the main thread computation and commit can be finished before the 758 // impl thread's deadline. 759 base::TimeTicks estimated_draw_time = 760 begin_impl_frame_args_.frame_time + 761 client_->BeginMainFrameToCommitDurationEstimate() + 762 client_->CommitToActivateDurationEstimate(); 763 764 TRACE_EVENT2( 765 TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), 766 "CanCommitAndActivateBeforeDeadline", 767 "time_left_after_drawing_ms", 768 (begin_impl_frame_args_.deadline - estimated_draw_time).InMillisecondsF(), 769 "state", 770 AsValue()); 771 772 return estimated_draw_time < begin_impl_frame_args_.deadline; 773 } 774 775 bool Scheduler::IsBeginMainFrameSentOrStarted() const { 776 return (state_machine_.commit_state() == 777 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || 778 state_machine_.commit_state() == 779 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); 780 } 781 782 } // namespace cc 783