| 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/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/single_thread_task_runner.h" | 11 #include "base/single_thread_task_runner.h" |
| 12 #include "cc/debug/devtools_instrumentation.h" | 12 #include "cc/debug/devtools_instrumentation.h" |
| 13 #include "cc/debug/traced_value.h" | 13 #include "cc/debug/traced_value.h" |
| 14 #include "cc/scheduler/delay_based_time_source.h" | 14 #include "cc/scheduler/delay_based_time_source.h" |
| 15 #include "ui/gfx/frame_time.h" | |
| 16 | 15 |
| 17 namespace cc { | 16 namespace cc { |
| 18 | 17 |
| 19 Scheduler::SyntheticBeginFrameSource::SyntheticBeginFrameSource( | 18 Scheduler::SyntheticBeginFrameSource::SyntheticBeginFrameSource( |
| 20 Scheduler* scheduler, | 19 Scheduler* scheduler, |
| 21 base::SingleThreadTaskRunner* task_runner) | 20 scoped_refptr<DelayBasedTimeSource>& time_source) |
| 22 : scheduler_(scheduler) { | 21 : scheduler_(scheduler), time_source_(time_source) { |
| 23 if (gfx::FrameTime::TimestampsAreHighRes()) { | |
| 24 time_source_ = DelayBasedTimeSourceHighRes::Create( | |
| 25 scheduler_->VSyncInterval(), task_runner); | |
| 26 } else { | |
| 27 time_source_ = DelayBasedTimeSource::Create(scheduler_->VSyncInterval(), | |
| 28 task_runner); | |
| 29 } | |
| 30 time_source_->SetClient(this); | 22 time_source_->SetClient(this); |
| 31 } | 23 } |
| 32 | 24 |
| 33 Scheduler::SyntheticBeginFrameSource::~SyntheticBeginFrameSource() { | 25 Scheduler::SyntheticBeginFrameSource::~SyntheticBeginFrameSource() { |
| 34 } | 26 } |
| 35 | 27 |
| 36 void Scheduler::SyntheticBeginFrameSource::CommitVSyncParameters( | 28 void Scheduler::SyntheticBeginFrameSource::CommitVSyncParameters( |
| 37 base::TimeTicks timebase, | 29 base::TimeTicks timebase, |
| 38 base::TimeDelta interval) { | 30 base::TimeDelta interval) { |
| 39 time_source_->SetTimebaseAndInterval(timebase, interval); | 31 time_source_->SetTimebaseAndInterval(timebase, interval); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 117 } | 109 } |
| 118 | 110 |
| 119 Scheduler::~Scheduler() { | 111 Scheduler::~Scheduler() { |
| 120 if (synthetic_begin_frame_source_) { | 112 if (synthetic_begin_frame_source_) { |
| 121 synthetic_begin_frame_source_->SetNeedsBeginFrame(false, | 113 synthetic_begin_frame_source_->SetNeedsBeginFrame(false, |
| 122 &begin_retro_frame_args_); | 114 &begin_retro_frame_args_); |
| 123 } | 115 } |
| 124 } | 116 } |
| 125 | 117 |
| 126 void Scheduler::SetupSyntheticBeginFrames() { | 118 void Scheduler::SetupSyntheticBeginFrames() { |
| 119 scoped_refptr<DelayBasedTimeSource> time_source; |
| 120 if (gfx::FrameTime::TimestampsAreHighRes()) { |
| 121 time_source = DelayBasedTimeSourceHighRes::Create(VSyncInterval(), |
| 122 impl_task_runner_.get()); |
| 123 } else { |
| 124 time_source = |
| 125 DelayBasedTimeSource::Create(VSyncInterval(), impl_task_runner_.get()); |
| 126 } |
| 127 DCHECK(!synthetic_begin_frame_source_); | 127 DCHECK(!synthetic_begin_frame_source_); |
| 128 synthetic_begin_frame_source_.reset( | 128 synthetic_begin_frame_source_.reset( |
| 129 new SyntheticBeginFrameSource(this, impl_task_runner_.get())); | 129 new SyntheticBeginFrameSource(this, time_source)); |
| 130 } |
| 131 |
| 132 base::TimeTicks Scheduler::Now() const { |
| 133 return gfx::FrameTime::Now(); |
| 130 } | 134 } |
| 131 | 135 |
| 132 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, | 136 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, |
| 133 base::TimeDelta interval) { | 137 base::TimeDelta interval) { |
| 134 // TODO(brianderson): We should not be receiving 0 intervals. | 138 // TODO(brianderson): We should not be receiving 0 intervals. |
| 135 if (interval == base::TimeDelta()) | 139 if (interval == base::TimeDelta()) |
| 136 interval = BeginFrameArgs::DefaultInterval(); | 140 interval = BeginFrameArgs::DefaultInterval(); |
| 137 vsync_interval_ = interval; | 141 vsync_interval_ = interval; |
| 138 if (!settings_.begin_frame_scheduling_enabled) | 142 if (!settings_.begin_frame_scheduling_enabled) |
| 139 synthetic_begin_frame_source_->CommitVSyncParameters(timebase, interval); | 143 synthetic_begin_frame_source_->CommitVSyncParameters(timebase, interval); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 253 void Scheduler::NotifyBeginMainFrameStarted() { | 257 void Scheduler::NotifyBeginMainFrameStarted() { |
| 254 TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted"); | 258 TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted"); |
| 255 state_machine_.NotifyBeginMainFrameStarted(); | 259 state_machine_.NotifyBeginMainFrameStarted(); |
| 256 } | 260 } |
| 257 | 261 |
| 258 base::TimeTicks Scheduler::AnticipatedDrawTime() const { | 262 base::TimeTicks Scheduler::AnticipatedDrawTime() const { |
| 259 if (!last_set_needs_begin_frame_ || | 263 if (!last_set_needs_begin_frame_ || |
| 260 begin_impl_frame_args_.interval <= base::TimeDelta()) | 264 begin_impl_frame_args_.interval <= base::TimeDelta()) |
| 261 return base::TimeTicks(); | 265 return base::TimeTicks(); |
| 262 | 266 |
| 263 base::TimeTicks now = gfx::FrameTime::Now(); | 267 base::TimeTicks now = Now(); |
| 264 base::TimeTicks timebase = std::max(begin_impl_frame_args_.frame_time, | 268 base::TimeTicks timebase = std::max(begin_impl_frame_args_.frame_time, |
| 265 begin_impl_frame_args_.deadline); | 269 begin_impl_frame_args_.deadline); |
| 266 int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval); | 270 int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval); |
| 267 return timebase + (begin_impl_frame_args_.interval * intervals); | 271 return timebase + (begin_impl_frame_args_.interval * intervals); |
| 268 } | 272 } |
| 269 | 273 |
| 270 base::TimeTicks Scheduler::LastBeginImplFrameTime() { | 274 base::TimeTicks Scheduler::LastBeginImplFrameTime() { |
| 271 return begin_impl_frame_args_.frame_time; | 275 return begin_impl_frame_args_.frame_time; |
| 272 } | 276 } |
| 273 | 277 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 328 begin_unthrottled_frame_posted_ = true; | 332 begin_unthrottled_frame_posted_ = true; |
| 329 impl_task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_); | 333 impl_task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_); |
| 330 } | 334 } |
| 331 | 335 |
| 332 // BeginUnthrottledFrame is used when we aren't throttling frame production. | 336 // BeginUnthrottledFrame is used when we aren't throttling frame production. |
| 333 // This will usually be because VSync is disabled. | 337 // This will usually be because VSync is disabled. |
| 334 void Scheduler::BeginUnthrottledFrame() { | 338 void Scheduler::BeginUnthrottledFrame() { |
| 335 DCHECK(!settings_.throttle_frame_production); | 339 DCHECK(!settings_.throttle_frame_production); |
| 336 DCHECK(begin_retro_frame_args_.empty()); | 340 DCHECK(begin_retro_frame_args_.empty()); |
| 337 | 341 |
| 338 base::TimeTicks now = gfx::FrameTime::Now(); | 342 base::TimeTicks now = Now(); |
| 339 base::TimeTicks deadline = now + vsync_interval_; | 343 base::TimeTicks deadline = now + vsync_interval_; |
| 340 | 344 |
| 341 BeginFrameArgs begin_frame_args = | 345 BeginFrameArgs begin_frame_args = |
| 342 BeginFrameArgs::Create(now, deadline, vsync_interval_); | 346 BeginFrameArgs::Create(now, deadline, vsync_interval_); |
| 343 BeginImplFrame(begin_frame_args); | 347 BeginImplFrame(begin_frame_args); |
| 344 | 348 |
| 345 begin_unthrottled_frame_posted_ = false; | 349 begin_unthrottled_frame_posted_ = false; |
| 346 } | 350 } |
| 347 | 351 |
| 348 // We may need to poll when we can't rely on BeginFrame to advance certain | 352 // 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... |
| 439 if (begin_retro_frame_args_.empty()) | 443 if (begin_retro_frame_args_.empty()) |
| 440 return; | 444 return; |
| 441 | 445 |
| 442 // Discard expired BeginRetroFrames | 446 // Discard expired BeginRetroFrames |
| 443 // Today, we should always end up with at most one un-expired BeginRetroFrame | 447 // Today, we should always end up with at most one un-expired BeginRetroFrame |
| 444 // because deadlines will not be greater than the next frame time. We don't | 448 // because deadlines will not be greater than the next frame time. We don't |
| 445 // DCHECK though because some systems don't always have monotonic timestamps. | 449 // DCHECK though because some systems don't always have monotonic timestamps. |
| 446 // TODO(brianderson): In the future, long deadlines could result in us not | 450 // TODO(brianderson): In the future, long deadlines could result in us not |
| 447 // draining the queue if we don't catch up. If we consistently can't catch | 451 // draining the queue if we don't catch up. If we consistently can't catch |
| 448 // up, our fallback should be to lower our frame rate. | 452 // up, our fallback should be to lower our frame rate. |
| 449 base::TimeTicks now = gfx::FrameTime::Now(); | 453 base::TimeTicks now = Now(); |
| 450 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); | 454 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); |
| 451 while (!begin_retro_frame_args_.empty() && | 455 while (!begin_retro_frame_args_.empty() && |
| 452 now > AdjustedBeginImplFrameDeadline(begin_retro_frame_args_.front(), | 456 now > AdjustedBeginImplFrameDeadline(begin_retro_frame_args_.front(), |
| 453 draw_duration_estimate)) { | 457 draw_duration_estimate)) { |
| 454 TRACE_EVENT1("cc", | 458 TRACE_EVENT1("cc", |
| 455 "Scheduler::BeginRetroFrame discarding", | 459 "Scheduler::BeginRetroFrame discarding", |
| 456 "frame_time", | 460 "frame_time", |
| 457 begin_retro_frame_args_.front().frame_time); | 461 begin_retro_frame_args_.front().frame_time); |
| 458 begin_retro_frame_args_.pop_front(); | 462 begin_retro_frame_args_.pop_front(); |
| 459 } | 463 } |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 555 // within this call. | 559 // within this call. |
| 556 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks | 560 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks |
| 557 // so the sychronous renderer compositor can take advantage of splitting | 561 // so the sychronous renderer compositor can take advantage of splitting |
| 558 // up the BeginImplFrame and deadline as well. | 562 // up the BeginImplFrame and deadline as well. |
| 559 OnBeginImplFrameDeadline(); | 563 OnBeginImplFrameDeadline(); |
| 560 return; | 564 return; |
| 561 } | 565 } |
| 562 begin_impl_frame_deadline_task_.Cancel(); | 566 begin_impl_frame_deadline_task_.Cancel(); |
| 563 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_); | 567 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_); |
| 564 | 568 |
| 565 base::TimeDelta delta = deadline - gfx::FrameTime::Now(); | 569 base::TimeDelta delta = deadline - Now(); |
| 566 if (delta <= base::TimeDelta()) | 570 if (delta <= base::TimeDelta()) |
| 567 delta = base::TimeDelta(); | 571 delta = base::TimeDelta(); |
| 568 impl_task_runner_->PostDelayedTask( | 572 impl_task_runner_->PostDelayedTask( |
| 569 FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta); | 573 FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta); |
| 570 } | 574 } |
| 571 | 575 |
| 572 void Scheduler::OnBeginImplFrameDeadline() { | 576 void Scheduler::OnBeginImplFrameDeadline() { |
| 573 TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline"); | 577 TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline"); |
| 574 begin_impl_frame_deadline_task_.Cancel(); | 578 begin_impl_frame_deadline_task_.Cancel(); |
| 575 | 579 |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 681 } | 685 } |
| 682 | 686 |
| 683 scoped_ptr<base::Value> Scheduler::AsValue() const { | 687 scoped_ptr<base::Value> Scheduler::AsValue() const { |
| 684 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue); | 688 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue); |
| 685 state->Set("state_machine", state_machine_.AsValue().release()); | 689 state->Set("state_machine", state_machine_.AsValue().release()); |
| 686 if (synthetic_begin_frame_source_) | 690 if (synthetic_begin_frame_source_) |
| 687 state->Set("synthetic_begin_frame_source_", | 691 state->Set("synthetic_begin_frame_source_", |
| 688 synthetic_begin_frame_source_->AsValue().release()); | 692 synthetic_begin_frame_source_->AsValue().release()); |
| 689 | 693 |
| 690 scoped_ptr<base::DictionaryValue> scheduler_state(new base::DictionaryValue); | 694 scoped_ptr<base::DictionaryValue> scheduler_state(new base::DictionaryValue); |
| 691 scheduler_state->SetDouble( | 695 scheduler_state->SetDouble("time_until_anticipated_draw_time_ms", |
| 692 "time_until_anticipated_draw_time_ms", | 696 (AnticipatedDrawTime() - Now()).InMillisecondsF()); |
| 693 (AnticipatedDrawTime() - base::TimeTicks::Now()).InMillisecondsF()); | |
| 694 scheduler_state->SetDouble("vsync_interval_ms", | 697 scheduler_state->SetDouble("vsync_interval_ms", |
| 695 vsync_interval_.InMillisecondsF()); | 698 vsync_interval_.InMillisecondsF()); |
| 696 scheduler_state->SetDouble("estimated_parent_draw_time_ms", | 699 scheduler_state->SetDouble("estimated_parent_draw_time_ms", |
| 697 estimated_parent_draw_time_.InMillisecondsF()); | 700 estimated_parent_draw_time_.InMillisecondsF()); |
| 698 scheduler_state->SetBoolean("last_set_needs_begin_frame_", | 701 scheduler_state->SetBoolean("last_set_needs_begin_frame_", |
| 699 last_set_needs_begin_frame_); | 702 last_set_needs_begin_frame_); |
| 700 scheduler_state->SetBoolean("begin_unthrottled_frame_posted_", | 703 scheduler_state->SetBoolean("begin_unthrottled_frame_posted_", |
| 701 begin_unthrottled_frame_posted_); | 704 begin_unthrottled_frame_posted_); |
| 702 scheduler_state->SetBoolean("begin_retro_frame_posted_", | 705 scheduler_state->SetBoolean("begin_retro_frame_posted_", |
| 703 begin_retro_frame_posted_); | 706 begin_retro_frame_posted_); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 747 } | 750 } |
| 748 | 751 |
| 749 bool Scheduler::IsBeginMainFrameSentOrStarted() const { | 752 bool Scheduler::IsBeginMainFrameSentOrStarted() const { |
| 750 return (state_machine_.commit_state() == | 753 return (state_machine_.commit_state() == |
| 751 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || | 754 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || |
| 752 state_machine_.commit_state() == | 755 state_machine_.commit_state() == |
| 753 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); | 756 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); |
| 754 } | 757 } |
| 755 | 758 |
| 756 } // namespace cc | 759 } // namespace cc |
| OLD | NEW |