OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/begin_frame_source.h" | 5 #include "cc/scheduler/begin_frame_source.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include "base/auto_reset.h" | 9 #include "base/auto_reset.h" |
10 #include "base/location.h" | 10 #include "base/location.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/memory/ptr_util.h" |
12 #include "base/strings/string_number_conversions.h" | 13 #include "base/strings/string_number_conversions.h" |
13 #include "base/strings/stringprintf.h" | 14 #include "base/strings/stringprintf.h" |
14 #include "base/trace_event/trace_event.h" | 15 #include "base/trace_event/trace_event.h" |
15 #include "base/trace_event/trace_event_argument.h" | 16 #include "base/trace_event/trace_event_argument.h" |
16 #include "cc/scheduler/delay_based_time_source.h" | 17 #include "cc/scheduler/delay_based_time_source.h" |
17 #include "cc/scheduler/scheduler.h" | 18 #include "cc/scheduler/scheduler.h" |
18 | 19 |
19 namespace cc { | 20 namespace cc { |
20 | 21 |
21 namespace { | 22 namespace { |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
90 return; | 91 return; |
91 paused_ = paused; | 92 paused_ = paused; |
92 std::set<BeginFrameObserver*> observers(observers_); | 93 std::set<BeginFrameObserver*> observers(observers_); |
93 for (BeginFrameObserver* obs : observers) | 94 for (BeginFrameObserver* obs : observers) |
94 obs->OnBeginFrameSourcePausedChanged(paused_); | 95 obs->OnBeginFrameSourcePausedChanged(paused_); |
95 } | 96 } |
96 | 97 |
97 // BackToBackBeginFrameSource -------------------------------------------- | 98 // BackToBackBeginFrameSource -------------------------------------------- |
98 BackToBackBeginFrameSource::BackToBackBeginFrameSource( | 99 BackToBackBeginFrameSource::BackToBackBeginFrameSource( |
99 base::SingleThreadTaskRunner* task_runner) | 100 base::SingleThreadTaskRunner* task_runner) |
100 : BeginFrameSourceBase(), task_runner_(task_runner), weak_factory_(this) { | 101 : SyntheticBeginFrameSource( |
101 DCHECK(task_runner); | 102 base::MakeUnique<DelayBasedTimeSource>(task_runner)) { |
| 103 SetUnthrottled(true); |
102 } | 104 } |
103 | 105 |
104 BackToBackBeginFrameSource::~BackToBackBeginFrameSource() { | 106 BackToBackBeginFrameSource::~BackToBackBeginFrameSource() = default; |
105 } | |
106 | |
107 base::TimeTicks BackToBackBeginFrameSource::Now() { | |
108 return base::TimeTicks::Now(); | |
109 } | |
110 | |
111 // BeginFrameSourceBase support | |
112 void BackToBackBeginFrameSource::AddObserver(BeginFrameObserver* obs) { | |
113 BeginFrameSourceBase::AddObserver(obs); | |
114 pending_begin_frame_observers_.insert(obs); | |
115 PostPendingBeginFramesTask(); | |
116 } | |
117 | |
118 void BackToBackBeginFrameSource::RemoveObserver(BeginFrameObserver* obs) { | |
119 BeginFrameSourceBase::RemoveObserver(obs); | |
120 pending_begin_frame_observers_.erase(obs); | |
121 if (pending_begin_frame_observers_.empty()) | |
122 begin_frame_task_.Cancel(); | |
123 } | |
124 | |
125 void BackToBackBeginFrameSource::DidFinishFrame(BeginFrameObserver* obs, | |
126 size_t remaining_frames) { | |
127 BeginFrameSourceBase::DidFinishFrame(obs, remaining_frames); | |
128 if (remaining_frames == 0 && observers_.find(obs) != observers_.end()) { | |
129 pending_begin_frame_observers_.insert(obs); | |
130 PostPendingBeginFramesTask(); | |
131 } | |
132 } | |
133 | |
134 void BackToBackBeginFrameSource::PostPendingBeginFramesTask() { | |
135 DCHECK(needs_begin_frames()); | |
136 DCHECK(!pending_begin_frame_observers_.empty()); | |
137 if (begin_frame_task_.IsCancelled()) { | |
138 begin_frame_task_.Reset( | |
139 base::Bind(&BackToBackBeginFrameSource::SendPendingBeginFrames, | |
140 weak_factory_.GetWeakPtr())); | |
141 task_runner_->PostTask(FROM_HERE, begin_frame_task_.callback()); | |
142 } | |
143 } | |
144 | |
145 void BackToBackBeginFrameSource::SendPendingBeginFrames() { | |
146 DCHECK(needs_begin_frames()); | |
147 DCHECK(!begin_frame_task_.IsCancelled()); | |
148 begin_frame_task_.Cancel(); | |
149 | |
150 base::TimeTicks now = Now(); | |
151 BeginFrameArgs args = BeginFrameArgs::Create( | |
152 BEGINFRAME_FROM_HERE, now, now + BeginFrameArgs::DefaultInterval(), | |
153 BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL); | |
154 | |
155 std::set<BeginFrameObserver*> pending_observers; | |
156 pending_observers.swap(pending_begin_frame_observers_); | |
157 for (BeginFrameObserver* obs : pending_observers) | |
158 obs->OnBeginFrame(args); | |
159 } | |
160 | 107 |
161 // SyntheticBeginFrameSource --------------------------------------------- | 108 // SyntheticBeginFrameSource --------------------------------------------- |
162 SyntheticBeginFrameSource::SyntheticBeginFrameSource( | 109 SyntheticBeginFrameSource::SyntheticBeginFrameSource( |
163 base::SingleThreadTaskRunner* task_runner, | 110 std::unique_ptr<DelayBasedTimeSource> time_source) |
164 base::TimeDelta initial_vsync_interval) | 111 : time_source_(std::move(time_source)), |
165 : time_source_( | 112 last_interval_(time_source_->Interval()) { |
166 DelayBasedTimeSource::Create(initial_vsync_interval, task_runner)) { | |
167 time_source_->SetClient(this); | 113 time_source_->SetClient(this); |
168 } | 114 } |
169 | 115 |
170 SyntheticBeginFrameSource::SyntheticBeginFrameSource( | 116 SyntheticBeginFrameSource::~SyntheticBeginFrameSource() = default; |
171 std::unique_ptr<DelayBasedTimeSource> time_source) | |
172 : time_source_(std::move(time_source)) { | |
173 time_source_->SetClient(this); | |
174 } | |
175 | |
176 SyntheticBeginFrameSource::~SyntheticBeginFrameSource() {} | |
177 | 117 |
178 void SyntheticBeginFrameSource::OnUpdateVSyncParameters( | 118 void SyntheticBeginFrameSource::OnUpdateVSyncParameters( |
179 base::TimeTicks timebase, | 119 base::TimeTicks timebase, |
180 base::TimeDelta interval) { | 120 base::TimeDelta interval) { |
181 if (!authoritative_interval_.is_zero()) | 121 if (!authoritative_interval_.is_zero()) { |
182 interval = authoritative_interval_; | 122 interval = authoritative_interval_; |
| 123 } else if (interval.is_zero()) { |
| 124 // TODO(brianderson): We should not be receiving 0 intervals. |
| 125 interval = BeginFrameArgs::DefaultInterval(); |
| 126 } |
183 | 127 |
184 last_timebase_ = timebase; | 128 last_timebase_ = timebase; |
185 time_source_->SetTimebaseAndInterval(timebase, interval); | 129 last_interval_ = interval; |
| 130 if (!unthrottled_) |
| 131 time_source_->SetTimebaseAndInterval(timebase, interval); |
186 } | 132 } |
187 | 133 |
188 void SyntheticBeginFrameSource::SetAuthoritativeVSyncInterval( | 134 void SyntheticBeginFrameSource::SetAuthoritativeVSyncInterval( |
189 base::TimeDelta interval) { | 135 base::TimeDelta interval) { |
190 authoritative_interval_ = interval; | 136 authoritative_interval_ = interval; |
191 OnUpdateVSyncParameters(last_timebase_, interval); | 137 OnUpdateVSyncParameters(last_timebase_, interval); |
192 } | 138 } |
193 | 139 |
| 140 void SyntheticBeginFrameSource::SetUnthrottled(bool unthrottled) { |
| 141 if (unthrottled) |
| 142 time_source_->SetTimebaseAndInterval(base::TimeTicks(), base::TimeDelta()); |
| 143 else |
| 144 time_source_->SetTimebaseAndInterval(last_timebase_, last_interval_); |
| 145 unthrottled_ = unthrottled; |
| 146 } |
| 147 |
194 BeginFrameArgs SyntheticBeginFrameSource::CreateBeginFrameArgs( | 148 BeginFrameArgs SyntheticBeginFrameSource::CreateBeginFrameArgs( |
195 base::TimeTicks frame_time, | 149 base::TimeTicks frame_time, |
196 BeginFrameArgs::BeginFrameArgsType type) { | 150 BeginFrameArgs::BeginFrameArgsType type) { |
| 151 if (unthrottled_) { |
| 152 // When unthrottled, the NextTickTime is not meaningful, so just use the |
| 153 // current interval as the deadline. |
| 154 return BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, |
| 155 frame_time + last_interval_, last_interval_, |
| 156 type); |
| 157 } |
197 return BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, | 158 return BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, |
198 time_source_->NextTickTime(), | 159 time_source_->NextTickTime(), last_interval_, |
199 time_source_->Interval(), type); | 160 type); |
200 } | 161 } |
201 | 162 |
202 // BeginFrameSource support | 163 // BeginFrameSource support |
203 void SyntheticBeginFrameSource::AddObserver(BeginFrameObserver* obs) { | 164 void SyntheticBeginFrameSource::AddObserver(BeginFrameObserver* obs) { |
204 BeginFrameSourceBase::AddObserver(obs); | 165 BeginFrameSourceBase::AddObserver(obs); |
| 166 |
| 167 if (unthrottled_) { |
| 168 // When unthrottled, ensure the time source is ticking for the first frame |
| 169 // this observer sees (since it only ticks when an observer is ready), and |
| 170 // don't post a MISSED frame since unthrottled just goes as fast as it can. |
| 171 time_source_->SetActive(true); |
| 172 frame_finished_observers_.insert(obs); |
| 173 return; |
| 174 } |
| 175 |
205 BeginFrameArgs args = CreateBeginFrameArgs( | 176 BeginFrameArgs args = CreateBeginFrameArgs( |
206 time_source_->NextTickTime() - time_source_->Interval(), | 177 time_source_->NextTickTime() - last_interval_, BeginFrameArgs::MISSED); |
207 BeginFrameArgs::MISSED); | |
208 BeginFrameArgs last_args = obs->LastUsedBeginFrameArgs(); | 178 BeginFrameArgs last_args = obs->LastUsedBeginFrameArgs(); |
209 if (!last_args.IsValid() || | 179 if (!last_args.IsValid() || |
210 (args.frame_time > | 180 (args.frame_time > |
211 last_args.frame_time + args.interval / kDoubleTickDivisor)) { | 181 last_args.frame_time + args.interval / kDoubleTickDivisor)) { |
212 obs->OnBeginFrame(args); | 182 obs->OnBeginFrame(args); |
213 } | 183 } |
214 } | 184 } |
215 | 185 |
| 186 void SyntheticBeginFrameSource::RemoveObserver(BeginFrameObserver* obs) { |
| 187 BeginFrameSourceBase::RemoveObserver(obs); |
| 188 frame_finished_observers_.erase(obs); |
| 189 } |
| 190 |
216 void SyntheticBeginFrameSource::OnNeedsBeginFramesChanged( | 191 void SyntheticBeginFrameSource::OnNeedsBeginFramesChanged( |
217 bool needs_begin_frames) { | 192 bool needs_begin_frames) { |
218 time_source_->SetActive(needs_begin_frames); | 193 time_source_->SetActive(needs_begin_frames); |
219 } | 194 } |
220 | 195 |
221 // DelayBasedTimeSourceClient support | 196 void SyntheticBeginFrameSource::DidFinishFrame(BeginFrameObserver* obs, |
222 void SyntheticBeginFrameSource::OnTimerTick() { | 197 size_t remaining_frames) { |
223 BeginFrameArgs args = CreateBeginFrameArgs(time_source_->LastTickTime(), | 198 if (remaining_frames == 0 && observers_.find(obs) != observers_.end()) { |
224 BeginFrameArgs::NORMAL); | 199 frame_finished_observers_.insert(obs); |
225 std::set<BeginFrameObserver*> observers(observers_); | 200 time_source_->SetActive(true); |
226 for (auto& it : observers) { | |
227 BeginFrameArgs last_args = it->LastUsedBeginFrameArgs(); | |
228 if (!last_args.IsValid() || | |
229 (args.frame_time > | |
230 last_args.frame_time + args.interval / kDoubleTickDivisor)) { | |
231 it->OnBeginFrame(args); | |
232 } | |
233 } | 201 } |
234 } | 202 } |
235 | 203 |
| 204 // DelayBasedTimeSourceClient support |
| 205 void SyntheticBeginFrameSource::OnTimerTick() { |
| 206 // This must be captured before calling SetActive(false) on the time_source_. |
| 207 base::TimeTicks now = time_source_->LastTickTime(); |
| 208 |
| 209 if (unthrottled_) { |
| 210 // When unthrottled, we only want to tick when an observer finishes a frame, |
| 211 // so stop and wait for that. |
| 212 time_source_->SetActive(false); |
| 213 } |
| 214 |
| 215 BeginFrameArgs args = CreateBeginFrameArgs(now, BeginFrameArgs::NORMAL); |
| 216 std::set<BeginFrameObserver*> observers(observers_); |
| 217 for (auto& obs : observers) { |
| 218 bool on_begin_frame = false; |
| 219 if (unthrottled_) { |
| 220 // When unthrottled, we only want to generate a new begin frame for each |
| 221 // observer when its previous one finished. |
| 222 on_begin_frame = frame_finished_observers_.count(obs) > 0; |
| 223 } else { |
| 224 // When ticking at a throttled rate we want to generate a new begin frame |
| 225 // regularly, but not too often. |
| 226 BeginFrameArgs last_args = obs->LastUsedBeginFrameArgs(); |
| 227 on_begin_frame = |
| 228 !last_args.IsValid() || |
| 229 (args.frame_time > |
| 230 last_args.frame_time + args.interval / kDoubleTickDivisor); |
| 231 } |
| 232 frame_finished_observers_.erase(obs); |
| 233 if (on_begin_frame) |
| 234 obs->OnBeginFrame(args); |
| 235 } |
| 236 } |
| 237 |
236 } // namespace cc | 238 } // namespace cc |
OLD | NEW |