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