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 task_runner_.get()); |
| 126 } else { |
| 127 time_source = |
| 128 DelayBasedTimeSource::Create(VSyncInterval(), 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, 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 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
333 begin_unthrottled_frame_posted_ = true; | 338 begin_unthrottled_frame_posted_ = true; |
334 task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_); | 339 task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_); |
335 } | 340 } |
336 | 341 |
337 // BeginUnthrottledFrame is used when we aren't throttling frame production. | 342 // BeginUnthrottledFrame is used when we aren't throttling frame production. |
338 // This will usually be because VSync is disabled. | 343 // This will usually be because VSync is disabled. |
339 void Scheduler::BeginUnthrottledFrame() { | 344 void Scheduler::BeginUnthrottledFrame() { |
340 DCHECK(!settings_.throttle_frame_production); | 345 DCHECK(!settings_.throttle_frame_production); |
341 DCHECK(begin_retro_frame_args_.empty()); | 346 DCHECK(begin_retro_frame_args_.empty()); |
342 | 347 |
343 base::TimeTicks now = gfx::FrameTime::Now(); | 348 base::TimeTicks now = Now(); |
344 base::TimeTicks deadline = now + vsync_interval_; | 349 base::TimeTicks deadline = now + vsync_interval_; |
345 | 350 |
346 BeginFrameArgs begin_frame_args = | 351 BeginFrameArgs begin_frame_args = |
347 BeginFrameArgs::Create(now, deadline, vsync_interval_); | 352 BeginFrameArgs::Create(now, deadline, vsync_interval_); |
348 BeginImplFrame(begin_frame_args); | 353 BeginImplFrame(begin_frame_args); |
349 | 354 |
350 begin_unthrottled_frame_posted_ = false; | 355 begin_unthrottled_frame_posted_ = false; |
351 } | 356 } |
352 | 357 |
353 // We may need to poll when we can't rely on BeginFrame to advance certain | 358 // 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... |
444 if (begin_retro_frame_args_.empty()) | 449 if (begin_retro_frame_args_.empty()) |
445 return; | 450 return; |
446 | 451 |
447 // Discard expired BeginRetroFrames | 452 // Discard expired BeginRetroFrames |
448 // Today, we should always end up with at most one un-expired BeginRetroFrame | 453 // Today, we should always end up with at most one un-expired BeginRetroFrame |
449 // because deadlines will not be greater than the next frame time. We don't | 454 // because deadlines will not be greater than the next frame time. We don't |
450 // DCHECK though because some systems don't always have monotonic timestamps. | 455 // DCHECK though because some systems don't always have monotonic timestamps. |
451 // TODO(brianderson): In the future, long deadlines could result in us not | 456 // TODO(brianderson): In the future, long deadlines could result in us not |
452 // draining the queue if we don't catch up. If we consistently can't catch | 457 // draining the queue if we don't catch up. If we consistently can't catch |
453 // up, our fallback should be to lower our frame rate. | 458 // up, our fallback should be to lower our frame rate. |
454 base::TimeTicks now = gfx::FrameTime::Now(); | 459 base::TimeTicks now = Now(); |
455 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); | 460 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); |
456 while (!begin_retro_frame_args_.empty() && | 461 while (!begin_retro_frame_args_.empty() && |
457 now > AdjustedBeginImplFrameDeadline(begin_retro_frame_args_.front(), | 462 now > AdjustedBeginImplFrameDeadline(begin_retro_frame_args_.front(), |
458 draw_duration_estimate)) { | 463 draw_duration_estimate)) { |
459 TRACE_EVENT1("cc", | 464 TRACE_EVENT1("cc", |
460 "Scheduler::BeginRetroFrame discarding", | 465 "Scheduler::BeginRetroFrame discarding", |
461 "frame_time", | 466 "frame_time", |
462 begin_retro_frame_args_.front().frame_time); | 467 begin_retro_frame_args_.front().frame_time); |
463 begin_retro_frame_args_.pop_front(); | 468 begin_retro_frame_args_.pop_front(); |
464 } | 469 } |
465 | 470 |
466 if (begin_retro_frame_args_.empty()) { | 471 if (begin_retro_frame_args_.empty()) { |
467 DCHECK(settings_.throttle_frame_production); | 472 DCHECK(settings_.throttle_frame_production); |
468 TRACE_EVENT_INSTANT0("cc", | 473 TRACE_EVENT_INSTANT0("cc", |
469 "Scheduler::BeginRetroFrames all expired", | 474 "Scheduler::BeginRetroFrames all expired", |
470 TRACE_EVENT_SCOPE_THREAD); | 475 TRACE_EVENT_SCOPE_THREAD); |
471 } else { | 476 } else { |
472 BeginImplFrame(begin_retro_frame_args_.front()); | 477 BeginImplFrame(begin_retro_frame_args_.front()); |
473 begin_retro_frame_args_.pop_front(); | 478 begin_retro_frame_args_.pop_front(); |
474 } | 479 } |
475 } | 480 } |
476 | 481 |
477 // There could be a race between the posted BeginRetroFrame and a new | 482 // There could be a race between the posted BeginRetroFrame and a new |
478 // BeginFrame arriving via the normal mechanism. Scheduler::BeginFrame | 483 // BeginFrame arriving via the normal mechanism. Scheduler::BeginFrame |
479 // will check if there is a pending BeginRetroFrame to ensure we handle | 484 // will check if there is a pending BeginRetroFrame to ensure we handle |
480 // BeginFrames in FIFO order. | 485 // BeginFrames in FIFO order. |
481 void Scheduler::PostBeginRetroFrameIfNeeded() { | 486 void Scheduler::PostBeginRetroFrameIfNeeded() { |
| 487 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), |
| 488 "Scheduler::PostBeginRetroFrameIfNeeded", |
| 489 "state", |
| 490 AsValue()); |
482 if (!last_set_needs_begin_frame_) | 491 if (!last_set_needs_begin_frame_) |
483 return; | 492 return; |
484 | 493 |
485 if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_) | 494 if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_) |
486 return; | 495 return; |
487 | 496 |
488 // begin_retro_frame_args_ should always be empty for the | 497 // begin_retro_frame_args_ should always be empty for the |
489 // synchronous compositor. | 498 // synchronous compositor. |
490 DCHECK(!settings_.using_synchronous_renderer_compositor); | 499 DCHECK(!settings_.using_synchronous_renderer_compositor); |
491 | 500 |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
548 // expected BeginImplFrame start. This allows us to draw immediately when | 557 // expected BeginImplFrame start. This allows us to draw immediately when |
549 // there is a new active tree, instead of waiting for the next | 558 // there is a new active tree, instead of waiting for the next |
550 // BeginImplFrame. | 559 // BeginImplFrame. |
551 // TODO(brianderson): Handle long deadlines (that are past the next frame's | 560 // TODO(brianderson): Handle long deadlines (that are past the next frame's |
552 // frame time) properly instead of using this hack. | 561 // frame time) properly instead of using this hack. |
553 return args.frame_time + args.interval; | 562 return args.frame_time + args.interval; |
554 } | 563 } |
555 } | 564 } |
556 | 565 |
557 void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) { | 566 void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) { |
| 567 TRACE_EVENT1( |
| 568 "cc", "Scheduler::ScheduleBeginImplFrameDeadline", "deadline", deadline); |
558 if (settings_.using_synchronous_renderer_compositor) { | 569 if (settings_.using_synchronous_renderer_compositor) { |
559 // The synchronous renderer compositor has to make its GL calls | 570 // The synchronous renderer compositor has to make its GL calls |
560 // within this call. | 571 // within this call. |
561 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks | 572 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks |
562 // so the sychronous renderer compositor can take advantage of splitting | 573 // so the sychronous renderer compositor can take advantage of splitting |
563 // up the BeginImplFrame and deadline as well. | 574 // up the BeginImplFrame and deadline as well. |
564 OnBeginImplFrameDeadline(); | 575 OnBeginImplFrameDeadline(); |
565 return; | 576 return; |
566 } | 577 } |
567 begin_impl_frame_deadline_task_.Cancel(); | 578 begin_impl_frame_deadline_task_.Cancel(); |
568 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_); | 579 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_); |
569 | 580 |
570 base::TimeDelta delta = deadline - gfx::FrameTime::Now(); | 581 base::TimeDelta delta = deadline - Now(); |
571 if (delta <= base::TimeDelta()) | 582 if (delta <= base::TimeDelta()) |
572 delta = base::TimeDelta(); | 583 delta = base::TimeDelta(); |
573 task_runner_->PostDelayedTask( | 584 task_runner_->PostDelayedTask( |
574 FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta); | 585 FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta); |
575 } | 586 } |
576 | 587 |
577 void Scheduler::OnBeginImplFrameDeadline() { | 588 void Scheduler::OnBeginImplFrameDeadline() { |
578 TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline"); | 589 TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline"); |
579 begin_impl_frame_deadline_task_.Cancel(); | 590 begin_impl_frame_deadline_task_.Cancel(); |
580 | 591 |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
690 state->BeginDictionary("state_machine"); | 701 state->BeginDictionary("state_machine"); |
691 state_machine_.AsValueInto(state.get()); | 702 state_machine_.AsValueInto(state.get()); |
692 state->EndDictionary(); | 703 state->EndDictionary(); |
693 if (synthetic_begin_frame_source_) { | 704 if (synthetic_begin_frame_source_) { |
694 state->BeginDictionary("synthetic_begin_frame_source_"); | 705 state->BeginDictionary("synthetic_begin_frame_source_"); |
695 synthetic_begin_frame_source_->AsValueInto(state.get()); | 706 synthetic_begin_frame_source_->AsValueInto(state.get()); |
696 state->EndDictionary(); | 707 state->EndDictionary(); |
697 } | 708 } |
698 | 709 |
699 state->BeginDictionary("scheduler_state"); | 710 state->BeginDictionary("scheduler_state"); |
700 state->SetDouble( | 711 state->SetDouble("time_until_anticipated_draw_time_ms", |
701 "time_until_anticipated_draw_time_ms", | 712 (AnticipatedDrawTime() - Now()).InMillisecondsF()); |
702 (AnticipatedDrawTime() - base::TimeTicks::Now()).InMillisecondsF()); | |
703 state->SetDouble("vsync_interval_ms", vsync_interval_.InMillisecondsF()); | 713 state->SetDouble("vsync_interval_ms", vsync_interval_.InMillisecondsF()); |
704 state->SetDouble("estimated_parent_draw_time_ms", | 714 state->SetDouble("estimated_parent_draw_time_ms", |
705 estimated_parent_draw_time_.InMillisecondsF()); | 715 estimated_parent_draw_time_.InMillisecondsF()); |
706 state->SetBoolean("last_set_needs_begin_frame_", last_set_needs_begin_frame_); | 716 state->SetBoolean("last_set_needs_begin_frame_", last_set_needs_begin_frame_); |
707 state->SetBoolean("begin_unthrottled_frame_posted_", | 717 state->SetBoolean("begin_unthrottled_frame_posted_", |
708 begin_unthrottled_frame_posted_); | 718 begin_unthrottled_frame_posted_); |
709 state->SetBoolean("begin_retro_frame_posted_", begin_retro_frame_posted_); | 719 state->SetBoolean("begin_retro_frame_posted_", begin_retro_frame_posted_); |
710 state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size()); | 720 state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size()); |
711 state->SetBoolean("begin_impl_frame_deadline_task_", | 721 state->SetBoolean("begin_impl_frame_deadline_task_", |
712 !begin_impl_frame_deadline_task_.IsCancelled()); | 722 !begin_impl_frame_deadline_task_.IsCancelled()); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
753 } | 763 } |
754 | 764 |
755 bool Scheduler::IsBeginMainFrameSentOrStarted() const { | 765 bool Scheduler::IsBeginMainFrameSentOrStarted() const { |
756 return (state_machine_.commit_state() == | 766 return (state_machine_.commit_state() == |
757 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || | 767 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || |
758 state_machine_.commit_state() == | 768 state_machine_.commit_state() == |
759 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); | 769 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); |
760 } | 770 } |
761 | 771 |
762 } // namespace cc | 772 } // namespace cc |
OLD | NEW |