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/power_monitor/power_monitor.h" | |
12 #include "base/single_thread_task_runner.h" | 13 #include "base/single_thread_task_runner.h" |
13 #include "cc/debug/devtools_instrumentation.h" | 14 #include "cc/debug/devtools_instrumentation.h" |
14 #include "cc/debug/traced_value.h" | 15 #include "cc/debug/traced_value.h" |
15 #include "cc/scheduler/delay_based_time_source.h" | 16 #include "cc/scheduler/delay_based_time_source.h" |
16 #include "ui/gfx/frame_time.h" | 17 #include "ui/gfx/frame_time.h" |
17 | 18 |
18 namespace cc { | 19 namespace cc { |
19 | 20 |
20 Scheduler::SyntheticBeginFrameSource::SyntheticBeginFrameSource( | 21 Scheduler::SyntheticBeginFrameSource::SyntheticBeginFrameSource( |
21 Scheduler* scheduler, | 22 Scheduler* scheduler, |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
99 base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr()); | 100 base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr()); |
100 begin_unthrottled_frame_closure_ = | 101 begin_unthrottled_frame_closure_ = |
101 base::Bind(&Scheduler::BeginUnthrottledFrame, weak_factory_.GetWeakPtr()); | 102 base::Bind(&Scheduler::BeginUnthrottledFrame, weak_factory_.GetWeakPtr()); |
102 begin_impl_frame_deadline_closure_ = base::Bind( | 103 begin_impl_frame_deadline_closure_ = base::Bind( |
103 &Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr()); | 104 &Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr()); |
104 poll_for_draw_triggers_closure_ = base::Bind( | 105 poll_for_draw_triggers_closure_ = base::Bind( |
105 &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr()); | 106 &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr()); |
106 advance_commit_state_closure_ = base::Bind( | 107 advance_commit_state_closure_ = base::Bind( |
107 &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr()); | 108 &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr()); |
108 | 109 |
110 if (settings_.high_latency_mode_on_battery) { | |
111 SetupPowerMonitoring(); | |
112 } | |
113 | |
109 if (!settings_.begin_frame_scheduling_enabled) { | 114 if (!settings_.begin_frame_scheduling_enabled) { |
110 SetupSyntheticBeginFrames(); | 115 SetupSyntheticBeginFrames(); |
111 } | 116 } |
112 } | 117 } |
113 | 118 |
114 Scheduler::~Scheduler() { | 119 Scheduler::~Scheduler() { |
120 if (settings_.high_latency_mode_on_battery) { | |
121 TeardownPowerMonitoring(); | |
122 } | |
123 | |
115 if (synthetic_begin_frame_source_) { | 124 if (synthetic_begin_frame_source_) { |
116 synthetic_begin_frame_source_->SetNeedsBeginFrame(false, | 125 synthetic_begin_frame_source_->SetNeedsBeginFrame(false, |
117 &begin_retro_frame_args_); | 126 &begin_retro_frame_args_); |
118 } | 127 } |
119 } | 128 } |
120 | 129 |
121 void Scheduler::SetupSyntheticBeginFrames() { | 130 void Scheduler::SetupSyntheticBeginFrames() { |
122 scoped_refptr<DelayBasedTimeSource> time_source; | 131 scoped_refptr<DelayBasedTimeSource> time_source; |
123 if (gfx::FrameTime::TimestampsAreHighRes()) { | 132 if (gfx::FrameTime::TimestampsAreHighRes()) { |
124 time_source = DelayBasedTimeSourceHighRes::Create(VSyncInterval(), | 133 time_source = DelayBasedTimeSourceHighRes::Create(VSyncInterval(), |
125 task_runner_.get()); | 134 task_runner_.get()); |
126 } else { | 135 } else { |
127 time_source = | 136 time_source = |
128 DelayBasedTimeSource::Create(VSyncInterval(), task_runner_.get()); | 137 DelayBasedTimeSource::Create(VSyncInterval(), task_runner_.get()); |
129 } | 138 } |
130 DCHECK(!synthetic_begin_frame_source_); | 139 DCHECK(!synthetic_begin_frame_source_); |
131 synthetic_begin_frame_source_.reset( | 140 synthetic_begin_frame_source_.reset( |
132 new SyntheticBeginFrameSource(this, time_source)); | 141 new SyntheticBeginFrameSource(this, time_source)); |
133 } | 142 } |
134 | 143 |
135 base::TimeTicks Scheduler::Now() const { | 144 base::TimeTicks Scheduler::Now() const { |
136 return gfx::FrameTime::Now(); | 145 return gfx::FrameTime::Now(); |
137 } | 146 } |
138 | 147 |
148 void Scheduler::SetupPowerMonitoring() { | |
149 base::PowerMonitor* power_monitor = base::PowerMonitor::Get(); | |
150 DCHECK(power_monitor != NULL); | |
151 power_monitor->AddObserver(this); | |
152 on_battery_power_ = power_monitor->IsOnBatteryPower(); | |
153 } | |
154 | |
155 void Scheduler::TeardownPowerMonitoring() { | |
156 base::PowerMonitor* power_monitor = base::PowerMonitor::Get(); | |
157 DCHECK(power_monitor != NULL); | |
158 power_monitor->RemoveObserver(this); | |
159 } | |
160 | |
161 void Scheduler::OnPowerStateChange(bool on_battery_power) { | |
162 on_battery_power_ = on_battery_power; | |
163 } | |
164 | |
139 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, | 165 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, |
140 base::TimeDelta interval) { | 166 base::TimeDelta interval) { |
141 // TODO(brianderson): We should not be receiving 0 intervals. | 167 // TODO(brianderson): We should not be receiving 0 intervals. |
142 if (interval == base::TimeDelta()) | 168 if (interval == base::TimeDelta()) |
143 interval = BeginFrameArgs::DefaultInterval(); | 169 interval = BeginFrameArgs::DefaultInterval(); |
144 vsync_interval_ = interval; | 170 vsync_interval_ = interval; |
145 if (!settings_.begin_frame_scheduling_enabled) | 171 if (!settings_.begin_frame_scheduling_enabled) |
146 synthetic_begin_frame_source_->CommitVSyncParameters(timebase, interval); | 172 synthetic_begin_frame_source_->CommitVSyncParameters(timebase, interval); |
147 } | 173 } |
148 | 174 |
(...skipping 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
499 DCHECK(!settings_.using_synchronous_renderer_compositor); | 525 DCHECK(!settings_.using_synchronous_renderer_compositor); |
500 | 526 |
501 if (state_machine_.begin_impl_frame_state() != | 527 if (state_machine_.begin_impl_frame_state() != |
502 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE) | 528 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE) |
503 return; | 529 return; |
504 | 530 |
505 begin_retro_frame_posted_ = true; | 531 begin_retro_frame_posted_ = true; |
506 task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_); | 532 task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_); |
507 } | 533 } |
508 | 534 |
535 bool Scheduler::ShouldPostBeginImplFrameDeadline() const { | |
536 // The synchronous renderer compositor has to make its GL calls | |
537 // within the BeginFrame call stack. | |
538 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks | |
539 // so the sychronous renderer compositor can take advantage of splitting | |
540 // up the BeginImplFrame and deadline as well. | |
541 if (settings_.using_synchronous_renderer_compositor) | |
542 return false; | |
543 | |
544 if (settings_.high_latency_mode_on_battery && on_battery_power_) | |
brianderson
2014/09/12 22:05:27
Please add a comment above this if.
| |
545 return false; | |
546 | |
547 return true; | |
548 } | |
549 | |
509 // BeginImplFrame starts a compositor frame that will wait up until a deadline | 550 // BeginImplFrame starts a compositor frame that will wait up until a deadline |
510 // for a BeginMainFrame+activation to complete before it times out and draws | 551 // for a BeginMainFrame+activation to complete before it times out and draws |
511 // any asynchronous animation and scroll/pinch updates. | 552 // any asynchronous animation and scroll/pinch updates. |
512 void Scheduler::BeginImplFrame(const BeginFrameArgs& args) { | 553 void Scheduler::BeginImplFrame(const BeginFrameArgs& args) { |
513 TRACE_EVENT1("cc", "Scheduler::BeginImplFrame", "args", args.AsValue()); | 554 TRACE_EVENT1("cc", "Scheduler::BeginImplFrame", "args", args.AsValue()); |
514 DCHECK_EQ(state_machine_.begin_impl_frame_state(), | 555 DCHECK_EQ(state_machine_.begin_impl_frame_state(), |
515 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); | 556 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); |
516 DCHECK(state_machine_.HasInitializedOutputSurface()); | 557 DCHECK(state_machine_.HasInitializedOutputSurface()); |
558 DCHECK(begin_impl_frame_deadline_task_.IsCancelled()); | |
517 | 559 |
518 advance_commit_state_task_.Cancel(); | 560 advance_commit_state_task_.Cancel(); |
519 | 561 |
520 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); | 562 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); |
521 begin_impl_frame_args_ = args; | 563 begin_impl_frame_args_ = args; |
522 begin_impl_frame_args_.deadline -= draw_duration_estimate; | 564 begin_impl_frame_args_.deadline -= draw_duration_estimate; |
523 | 565 |
524 if (!state_machine_.impl_latency_takes_priority() && | 566 if (!state_machine_.impl_latency_takes_priority() && |
525 state_machine_.MainThreadIsInHighLatencyMode() && | 567 state_machine_.MainThreadIsInHighLatencyMode() && |
526 CanCommitAndActivateBeforeDeadline()) { | 568 CanCommitAndActivateBeforeDeadline()) { |
527 state_machine_.SetSkipNextBeginMainFrameToReduceLatency(); | 569 state_machine_.SetSkipNextBeginMainFrameToReduceLatency(); |
528 } | 570 } |
529 | 571 |
530 client_->WillBeginImplFrame(begin_impl_frame_args_); | 572 client_->WillBeginImplFrame(begin_impl_frame_args_); |
531 state_machine_.OnBeginImplFrame(begin_impl_frame_args_); | 573 state_machine_.OnBeginImplFrame(begin_impl_frame_args_); |
532 devtools_instrumentation::DidBeginFrame(layer_tree_host_id_); | 574 devtools_instrumentation::DidBeginFrame(layer_tree_host_id_); |
533 | 575 |
534 ProcessScheduledActions(); | 576 ProcessScheduledActions(); |
535 | 577 |
536 state_machine_.OnBeginImplFrameDeadlinePending(); | 578 state_machine_.OnBeginImplFrameDeadlinePending(); |
537 ScheduleBeginImplFrameDeadline( | 579 |
538 AdjustedBeginImplFrameDeadline(args, draw_duration_estimate)); | 580 if (ShouldPostBeginImplFrameDeadline()) { |
581 ScheduleBeginImplFrameDeadline( | |
582 AdjustedBeginImplFrameDeadline(args, draw_duration_estimate)); | |
583 } else { | |
584 OnBeginImplFrameDeadline(); | |
brianderson
2014/09/12 22:05:27
After thinking about this some more, I am a bit co
sunnyps
2014/09/15 21:52:48
An immediate task will also take 15 ms before it e
sunnyps
2014/09/16 21:30:31
I've gone through some of the MessageLoop/MessageP
| |
585 } | |
539 } | 586 } |
540 | 587 |
541 base::TimeTicks Scheduler::AdjustedBeginImplFrameDeadline( | 588 base::TimeTicks Scheduler::AdjustedBeginImplFrameDeadline( |
542 const BeginFrameArgs& args, | 589 const BeginFrameArgs& args, |
543 base::TimeDelta draw_duration_estimate) const { | 590 base::TimeDelta draw_duration_estimate) const { |
544 if (settings_.using_synchronous_renderer_compositor) { | 591 if (!ShouldPostBeginImplFrameDeadline()) { |
545 // The synchronous compositor needs to draw right away. | |
546 return base::TimeTicks(); | 592 return base::TimeTicks(); |
547 } else if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) { | 593 } else if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) { |
548 // We are ready to draw a new active tree immediately. | 594 // We are ready to draw a new active tree immediately. |
549 return base::TimeTicks(); | 595 return base::TimeTicks(); |
550 } else if (state_machine_.needs_redraw()) { | 596 } else if (state_machine_.needs_redraw()) { |
551 // We have an animation or fast input path on the impl thread that wants | 597 // We have an animation or fast input path on the impl thread that wants |
552 // to draw, so don't wait too long for a new active tree. | 598 // to draw, so don't wait too long for a new active tree. |
553 return args.deadline - draw_duration_estimate; | 599 return args.deadline - draw_duration_estimate; |
554 } else { | 600 } else { |
555 // The impl thread doesn't have anything it wants to draw and we are just | 601 // The impl thread doesn't have anything it wants to draw and we are just |
556 // waiting for a new active tree, so post the deadline for the next | 602 // waiting for a new active tree, so post the deadline for the next |
557 // expected BeginImplFrame start. This allows us to draw immediately when | 603 // expected BeginImplFrame start. This allows us to draw immediately when |
558 // there is a new active tree, instead of waiting for the next | 604 // there is a new active tree, instead of waiting for the next |
559 // BeginImplFrame. | 605 // BeginImplFrame. |
560 // TODO(brianderson): Handle long deadlines (that are past the next frame's | 606 // TODO(brianderson): Handle long deadlines (that are past the next frame's |
561 // frame time) properly instead of using this hack. | 607 // frame time) properly instead of using this hack. |
562 return args.frame_time + args.interval; | 608 return args.frame_time + args.interval; |
563 } | 609 } |
564 } | 610 } |
565 | 611 |
566 void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) { | 612 void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) { |
567 TRACE_EVENT1( | 613 TRACE_EVENT1( |
568 "cc", "Scheduler::ScheduleBeginImplFrameDeadline", "deadline", deadline); | 614 "cc", "Scheduler::ScheduleBeginImplFrameDeadline", "deadline", deadline); |
569 if (settings_.using_synchronous_renderer_compositor) { | |
570 // The synchronous renderer compositor has to make its GL calls | |
571 // within this call. | |
572 // TODO(brianderson): Have the OutputSurface initiate the deadline tasks | |
573 // so the sychronous renderer compositor can take advantage of splitting | |
574 // up the BeginImplFrame and deadline as well. | |
575 OnBeginImplFrameDeadline(); | |
576 return; | |
577 } | |
578 begin_impl_frame_deadline_task_.Cancel(); | 615 begin_impl_frame_deadline_task_.Cancel(); |
579 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_); | 616 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_); |
580 | 617 |
581 base::TimeDelta delta = deadline - Now(); | 618 base::TimeDelta delta = deadline - Now(); |
582 if (delta <= base::TimeDelta()) | 619 if (delta <= base::TimeDelta()) |
583 delta = base::TimeDelta(); | 620 delta = base::TimeDelta(); |
584 task_runner_->PostDelayedTask( | 621 task_runner_->PostDelayedTask( |
585 FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta); | 622 FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta); |
586 } | 623 } |
587 | 624 |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
763 } | 800 } |
764 | 801 |
765 bool Scheduler::IsBeginMainFrameSentOrStarted() const { | 802 bool Scheduler::IsBeginMainFrameSentOrStarted() const { |
766 return (state_machine_.commit_state() == | 803 return (state_machine_.commit_state() == |
767 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || | 804 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || |
768 state_machine_.commit_state() == | 805 state_machine_.commit_state() == |
769 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); | 806 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); |
770 } | 807 } |
771 | 808 |
772 } // namespace cc | 809 } // namespace cc |
OLD | NEW |