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 |