| OLD | NEW |
| 1 // Copyright 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "cc/scheduler/scheduler.h" | 5 #include "cc/scheduler/scheduler.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include "base/auto_reset.h" | 8 #include "base/auto_reset.h" |
| 9 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
| 10 #include "base/debug/trace_event_argument.h" | 10 #include "base/debug/trace_event_argument.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/single_thread_task_runner.h" | 12 #include "base/single_thread_task_runner.h" |
| 13 #include "cc/debug/devtools_instrumentation.h" | 13 #include "cc/debug/devtools_instrumentation.h" |
| 14 #include "cc/debug/traced_value.h" | 14 #include "cc/debug/traced_value.h" |
| 15 #include "cc/scheduler/delay_based_time_source.h" | 15 #include "cc/scheduler/delay_based_time_source.h" |
| 16 #include "ui/gfx/frame_time.h" | 16 #include "ui/gfx/frame_time.h" |
| 17 | 17 |
| 18 namespace cc { | 18 namespace cc { |
| 19 | 19 |
| 20 Scheduler::SyntheticBeginFrameSource::SyntheticBeginFrameSource( | 20 Scheduler::SyntheticBeginFrameSource::SyntheticBeginFrameSource( |
| 21 Scheduler* scheduler, | 21 Scheduler* scheduler, |
| 22 base::SingleThreadTaskRunner* task_runner) | 22 scoped_refptr<DelayBasedTimeSource> time_source) |
| 23 : scheduler_(scheduler) { | 23 : scheduler_(scheduler), time_source_(time_source) { |
| 24 if (gfx::FrameTime::TimestampsAreHighRes()) { | |
| 25 time_source_ = DelayBasedTimeSourceHighRes::Create( | |
| 26 scheduler_->VSyncInterval(), task_runner); | |
| 27 } else { | |
| 28 time_source_ = DelayBasedTimeSource::Create(scheduler_->VSyncInterval(), | |
| 29 task_runner); | |
| 30 } | |
| 31 time_source_->SetClient(this); | 24 time_source_->SetClient(this); |
| 32 } | 25 } |
| 33 | 26 |
| 34 Scheduler::SyntheticBeginFrameSource::~SyntheticBeginFrameSource() { | 27 Scheduler::SyntheticBeginFrameSource::~SyntheticBeginFrameSource() { |
| 35 } | 28 } |
| 36 | 29 |
| 37 void Scheduler::SyntheticBeginFrameSource::CommitVSyncParameters( | 30 void Scheduler::SyntheticBeginFrameSource::CommitVSyncParameters( |
| 38 base::TimeTicks timebase, | 31 base::TimeTicks timebase, |
| 39 base::TimeDelta interval) { | 32 base::TimeDelta interval) { |
| 40 time_source_->SetTimebaseAndInterval(timebase, interval); | 33 time_source_->SetTimebaseAndInterval(timebase, interval); |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 119 } | 112 } |
| 120 | 113 |
| 121 Scheduler::~Scheduler() { | 114 Scheduler::~Scheduler() { |
| 122 if (synthetic_begin_frame_source_) { | 115 if (synthetic_begin_frame_source_) { |
| 123 synthetic_begin_frame_source_->SetNeedsBeginFrame(false, | 116 synthetic_begin_frame_source_->SetNeedsBeginFrame(false, |
| 124 &begin_retro_frame_args_); | 117 &begin_retro_frame_args_); |
| 125 } | 118 } |
| 126 } | 119 } |
| 127 | 120 |
| 128 void Scheduler::SetupSyntheticBeginFrames() { | 121 void Scheduler::SetupSyntheticBeginFrames() { |
| 122 scoped_refptr<DelayBasedTimeSource> time_source; |
| 123 if (gfx::FrameTime::TimestampsAreHighRes()) { |
| 124 time_source = DelayBasedTimeSourceHighRes::Create(VSyncInterval(), |
| 125 impl_task_runner_.get()); |
| 126 } else { |
| 127 time_source = |
| 128 DelayBasedTimeSource::Create(VSyncInterval(), impl_task_runner_.get()); |
| 129 } |
| 129 DCHECK(!synthetic_begin_frame_source_); | 130 DCHECK(!synthetic_begin_frame_source_); |
| 130 synthetic_begin_frame_source_.reset( | 131 synthetic_begin_frame_source_.reset( |
| 131 new SyntheticBeginFrameSource(this, impl_task_runner_.get())); | 132 new SyntheticBeginFrameSource(this, time_source)); |
| 133 } |
| 134 |
| 135 base::TimeTicks Scheduler::Now() const { |
| 136 return gfx::FrameTime::Now(); |
| 132 } | 137 } |
| 133 | 138 |
| 134 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, | 139 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, |
| 135 base::TimeDelta interval) { | 140 base::TimeDelta interval) { |
| 136 // TODO(brianderson): We should not be receiving 0 intervals. | 141 // TODO(brianderson): We should not be receiving 0 intervals. |
| 137 if (interval == base::TimeDelta()) | 142 if (interval == base::TimeDelta()) |
| 138 interval = BeginFrameArgs::DefaultInterval(); | 143 interval = BeginFrameArgs::DefaultInterval(); |
| 139 vsync_interval_ = interval; | 144 vsync_interval_ = interval; |
| 140 if (!settings_.begin_frame_scheduling_enabled) | 145 if (!settings_.begin_frame_scheduling_enabled) |
| 141 synthetic_begin_frame_source_->CommitVSyncParameters(timebase, interval); | 146 synthetic_begin_frame_source_->CommitVSyncParameters(timebase, interval); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 255 void Scheduler::NotifyBeginMainFrameStarted() { | 260 void Scheduler::NotifyBeginMainFrameStarted() { |
| 256 TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted"); | 261 TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted"); |
| 257 state_machine_.NotifyBeginMainFrameStarted(); | 262 state_machine_.NotifyBeginMainFrameStarted(); |
| 258 } | 263 } |
| 259 | 264 |
| 260 base::TimeTicks Scheduler::AnticipatedDrawTime() const { | 265 base::TimeTicks Scheduler::AnticipatedDrawTime() const { |
| 261 if (!last_set_needs_begin_frame_ || | 266 if (!last_set_needs_begin_frame_ || |
| 262 begin_impl_frame_args_.interval <= base::TimeDelta()) | 267 begin_impl_frame_args_.interval <= base::TimeDelta()) |
| 263 return base::TimeTicks(); | 268 return base::TimeTicks(); |
| 264 | 269 |
| 265 base::TimeTicks now = gfx::FrameTime::Now(); | 270 base::TimeTicks now = Now(); |
| 266 base::TimeTicks timebase = std::max(begin_impl_frame_args_.frame_time, | 271 base::TimeTicks timebase = std::max(begin_impl_frame_args_.frame_time, |
| 267 begin_impl_frame_args_.deadline); | 272 begin_impl_frame_args_.deadline); |
| 268 int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval); | 273 int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval); |
| 269 return timebase + (begin_impl_frame_args_.interval * intervals); | 274 return timebase + (begin_impl_frame_args_.interval * intervals); |
| 270 } | 275 } |
| 271 | 276 |
| 272 base::TimeTicks Scheduler::LastBeginImplFrameTime() { | 277 base::TimeTicks Scheduler::LastBeginImplFrameTime() { |
| 273 return begin_impl_frame_args_.frame_time; | 278 return begin_impl_frame_args_.frame_time; |
| 274 } | 279 } |
| 275 | 280 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 330 begin_unthrottled_frame_posted_ = true; | 335 begin_unthrottled_frame_posted_ = true; |
| 331 impl_task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_); | 336 impl_task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_); |
| 332 } | 337 } |
| 333 | 338 |
| 334 // BeginUnthrottledFrame is used when we aren't throttling frame production. | 339 // BeginUnthrottledFrame is used when we aren't throttling frame production. |
| 335 // This will usually be because VSync is disabled. | 340 // This will usually be because VSync is disabled. |
| 336 void Scheduler::BeginUnthrottledFrame() { | 341 void Scheduler::BeginUnthrottledFrame() { |
| 337 DCHECK(!settings_.throttle_frame_production); | 342 DCHECK(!settings_.throttle_frame_production); |
| 338 DCHECK(begin_retro_frame_args_.empty()); | 343 DCHECK(begin_retro_frame_args_.empty()); |
| 339 | 344 |
| 340 base::TimeTicks now = gfx::FrameTime::Now(); | 345 base::TimeTicks now = Now(); |
| 341 base::TimeTicks deadline = now + vsync_interval_; | 346 base::TimeTicks deadline = now + vsync_interval_; |
| 342 | 347 |
| 343 BeginFrameArgs begin_frame_args = | 348 BeginFrameArgs begin_frame_args = |
| 344 BeginFrameArgs::Create(now, deadline, vsync_interval_); | 349 BeginFrameArgs::Create(now, deadline, vsync_interval_); |
| 345 BeginImplFrame(begin_frame_args); | 350 BeginImplFrame(begin_frame_args); |
| 346 | 351 |
| 347 begin_unthrottled_frame_posted_ = false; | 352 begin_unthrottled_frame_posted_ = false; |
| 348 } | 353 } |
| 349 | 354 |
| 350 // We may need to poll when we can't rely on BeginFrame to advance certain | 355 // We may need to poll when we can't rely on BeginFrame to advance certain |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 441 if (begin_retro_frame_args_.empty()) | 446 if (begin_retro_frame_args_.empty()) |
| 442 return; | 447 return; |
| 443 | 448 |
| 444 // Discard expired BeginRetroFrames | 449 // Discard expired BeginRetroFrames |
| 445 // Today, we should always end up with at most one un-expired BeginRetroFrame | 450 // Today, we should always end up with at most one un-expired BeginRetroFrame |
| 446 // because deadlines will not be greater than the next frame time. We don't | 451 // because deadlines will not be greater than the next frame time. We don't |
| 447 // DCHECK though because some systems don't always have monotonic timestamps. | 452 // DCHECK though because some systems don't always have monotonic timestamps. |
| 448 // TODO(brianderson): In the future, long deadlines could result in us not | 453 // TODO(brianderson): In the future, long deadlines could result in us not |
| 449 // draining the queue if we don't catch up. If we consistently can't catch | 454 // draining the queue if we don't catch up. If we consistently can't catch |
| 450 // up, our fallback should be to lower our frame rate. | 455 // up, our fallback should be to lower our frame rate. |
| 451 base::TimeTicks now = gfx::FrameTime::Now(); | 456 base::TimeTicks now = Now(); |
| 452 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); | 457 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); |
| 453 while (!begin_retro_frame_args_.empty() && | 458 while (!begin_retro_frame_args_.empty() && |
| 454 now > AdjustedBeginImplFrameDeadline(begin_retro_frame_args_.front(), | 459 now > AdjustedBeginImplFrameDeadline(begin_retro_frame_args_.front(), |
| 455 draw_duration_estimate)) { | 460 draw_duration_estimate)) { |
| 456 TRACE_EVENT1("cc", | 461 TRACE_EVENT1("cc", |
| 457 "Scheduler::BeginRetroFrame discarding", | 462 "Scheduler::BeginRetroFrame discarding", |
| 458 "frame_time", | 463 "frame_time", |
| 459 begin_retro_frame_args_.front().frame_time); | 464 begin_retro_frame_args_.front().frame_time); |
| 460 begin_retro_frame_args_.pop_front(); | 465 begin_retro_frame_args_.pop_front(); |
| 461 } | 466 } |
| 462 | 467 |
| 463 if (begin_retro_frame_args_.empty()) { | 468 if (begin_retro_frame_args_.empty()) { |
| 464 DCHECK(settings_.throttle_frame_production); | 469 DCHECK(settings_.throttle_frame_production); |
| 465 TRACE_EVENT_INSTANT0("cc", | 470 TRACE_EVENT_INSTANT0("cc", |
| 466 "Scheduler::BeginRetroFrames all expired", | 471 "Scheduler::BeginRetroFrames all expired", |
| 467 TRACE_EVENT_SCOPE_THREAD); | 472 TRACE_EVENT_SCOPE_THREAD); |
| 468 } else { | 473 } else { |
| 469 BeginImplFrame(begin_retro_frame_args_.front()); | 474 BeginImplFrame(begin_retro_frame_args_.front()); |
| 470 begin_retro_frame_args_.pop_front(); | 475 begin_retro_frame_args_.pop_front(); |
| 471 } | 476 } |
| 472 } | 477 } |
| 473 | 478 |
| 474 // There could be a race between the posted BeginRetroFrame and a new | 479 // There could be a race between the posted BeginRetroFrame and a new |
| 475 // BeginFrame arriving via the normal mechanism. Scheduler::BeginFrame | 480 // BeginFrame arriving via the normal mechanism. Scheduler::BeginFrame |
| 476 // will check if there is a pending BeginRetroFrame to ensure we handle | 481 // will check if there is a pending BeginRetroFrame to ensure we handle |
| 477 // BeginFrames in FIFO order. | 482 // BeginFrames in FIFO order. |
| 478 void Scheduler::PostBeginRetroFrameIfNeeded() { | 483 void Scheduler::PostBeginRetroFrameIfNeeded() { |
| 484 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), |
| 485 "Scheduler::PostBeginRetroFrameIfNeeded", |
| 486 "state", |
| 487 AsValue()); |
| 479 if (!last_set_needs_begin_frame_) | 488 if (!last_set_needs_begin_frame_) |
| 480 return; | 489 return; |
| 481 | 490 |
| 482 if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_) | 491 if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_) |
| 483 return; | 492 return; |
| 484 | 493 |
| 485 // begin_retro_frame_args_ should always be empty for the | 494 // begin_retro_frame_args_ should always be empty for the |
| 486 // synchronous compositor. | 495 // synchronous compositor. |
| 487 DCHECK(!settings_.using_synchronous_renderer_compositor); | 496 DCHECK(!settings_.using_synchronous_renderer_compositor); |
| 488 | 497 |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 545 // expected BeginImplFrame start. This allows us to draw immediately when | 554 // expected BeginImplFrame start. This allows us to draw immediately when |
| 546 // there is a new active tree, instead of waiting for the next | 555 // there is a new active tree, instead of waiting for the next |
| 547 // BeginImplFrame. | 556 // BeginImplFrame. |
| 548 // TODO(brianderson): Handle long deadlines (that are past the next frame's | 557 // TODO(brianderson): Handle long deadlines (that are past the next frame's |
| 549 // frame time) properly instead of using this hack. | 558 // frame time) properly instead of using this hack. |
| 550 return args.frame_time + args.interval; | 559 return args.frame_time + args.interval; |
| 551 } | 560 } |
| 552 } | 561 } |
| 553 | 562 |
| 554 void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) { | 563 void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) { |
| 564 TRACE_EVENT1( |
| 565 "cc", "Scheduler::ScheduleBeginImplFrameDeadline", "deadline", deadline); |
| 555 if (settings_.using_synchronous_renderer_compositor) { | 566 if (settings_.using_synchronous_renderer_compositor) { |
| 556 // The synchronous renderer compositor has to make its GL calls | 567 // The synchronous renderer compositor has to make its GL calls |
| 557 // within this call. | 568 // within this call. |
| 558 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks | 569 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks |
| 559 // so the sychronous renderer compositor can take advantage of splitting | 570 // so the sychronous renderer compositor can take advantage of splitting |
| 560 // up the BeginImplFrame and deadline as well. | 571 // up the BeginImplFrame and deadline as well. |
| 561 OnBeginImplFrameDeadline(); | 572 OnBeginImplFrameDeadline(); |
| 562 return; | 573 return; |
| 563 } | 574 } |
| 564 begin_impl_frame_deadline_task_.Cancel(); | 575 begin_impl_frame_deadline_task_.Cancel(); |
| 565 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_); | 576 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_); |
| 566 | 577 |
| 567 base::TimeDelta delta = deadline - gfx::FrameTime::Now(); | 578 base::TimeDelta delta = deadline - Now(); |
| 568 if (delta <= base::TimeDelta()) | 579 if (delta <= base::TimeDelta()) |
| 569 delta = base::TimeDelta(); | 580 delta = base::TimeDelta(); |
| 570 impl_task_runner_->PostDelayedTask( | 581 impl_task_runner_->PostDelayedTask( |
| 571 FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta); | 582 FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta); |
| 572 } | 583 } |
| 573 | 584 |
| 574 void Scheduler::OnBeginImplFrameDeadline() { | 585 void Scheduler::OnBeginImplFrameDeadline() { |
| 575 TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline"); | 586 TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline"); |
| 576 begin_impl_frame_deadline_task_.Cancel(); | 587 begin_impl_frame_deadline_task_.Cancel(); |
| 577 | 588 |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 689 state->BeginDictionary("state_machine"); | 700 state->BeginDictionary("state_machine"); |
| 690 state_machine_.AsValueInto(state); | 701 state_machine_.AsValueInto(state); |
| 691 state->EndDictionary(); | 702 state->EndDictionary(); |
| 692 if (synthetic_begin_frame_source_) { | 703 if (synthetic_begin_frame_source_) { |
| 693 state->BeginDictionary("synthetic_begin_frame_source_"); | 704 state->BeginDictionary("synthetic_begin_frame_source_"); |
| 694 synthetic_begin_frame_source_->AsValueInto(state); | 705 synthetic_begin_frame_source_->AsValueInto(state); |
| 695 state->EndDictionary(); | 706 state->EndDictionary(); |
| 696 } | 707 } |
| 697 | 708 |
| 698 state->BeginDictionary("scheduler_state"); | 709 state->BeginDictionary("scheduler_state"); |
| 699 state->SetDouble( | 710 state->SetDouble("time_until_anticipated_draw_time_ms", |
| 700 "time_until_anticipated_draw_time_ms", | 711 (AnticipatedDrawTime() - Now()).InMillisecondsF()); |
| 701 (AnticipatedDrawTime() - base::TimeTicks::Now()).InMillisecondsF()); | |
| 702 state->SetDouble("vsync_interval_ms", vsync_interval_.InMillisecondsF()); | 712 state->SetDouble("vsync_interval_ms", vsync_interval_.InMillisecondsF()); |
| 703 state->SetDouble("estimated_parent_draw_time_ms", | 713 state->SetDouble("estimated_parent_draw_time_ms", |
| 704 estimated_parent_draw_time_.InMillisecondsF()); | 714 estimated_parent_draw_time_.InMillisecondsF()); |
| 705 state->SetBoolean("last_set_needs_begin_frame_", last_set_needs_begin_frame_); | 715 state->SetBoolean("last_set_needs_begin_frame_", last_set_needs_begin_frame_); |
| 706 state->SetBoolean("begin_unthrottled_frame_posted_", | 716 state->SetBoolean("begin_unthrottled_frame_posted_", |
| 707 begin_unthrottled_frame_posted_); | 717 begin_unthrottled_frame_posted_); |
| 708 state->SetBoolean("begin_retro_frame_posted_", begin_retro_frame_posted_); | 718 state->SetBoolean("begin_retro_frame_posted_", begin_retro_frame_posted_); |
| 709 state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size()); | 719 state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size()); |
| 710 state->SetBoolean("begin_impl_frame_deadline_task_", | 720 state->SetBoolean("begin_impl_frame_deadline_task_", |
| 711 !begin_impl_frame_deadline_task_.IsCancelled()); | 721 !begin_impl_frame_deadline_task_.IsCancelled()); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 752 } | 762 } |
| 753 | 763 |
| 754 bool Scheduler::IsBeginMainFrameSentOrStarted() const { | 764 bool Scheduler::IsBeginMainFrameSentOrStarted() const { |
| 755 return (state_machine_.commit_state() == | 765 return (state_machine_.commit_state() == |
| 756 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || | 766 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || |
| 757 state_machine_.commit_state() == | 767 state_machine_.commit_state() == |
| 758 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); | 768 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); |
| 759 } | 769 } |
| 760 | 770 |
| 761 } // namespace cc | 771 } // namespace cc |
| OLD | NEW |