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 |