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/delay_based_time_source.h" | 5 #include "cc/scheduler/delay_based_time_source.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cmath> | 8 #include <cmath> |
9 | 9 |
10 #include "base/debug/trace_event.h" | 10 #include "base/debug/trace_event.h" |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
44 has_tick_target_(false), | 44 has_tick_target_(false), |
45 current_parameters_(interval, base::TimeTicks()), | 45 current_parameters_(interval, base::TimeTicks()), |
46 next_parameters_(interval, base::TimeTicks()), | 46 next_parameters_(interval, base::TimeTicks()), |
47 state_(STATE_INACTIVE), | 47 state_(STATE_INACTIVE), |
48 thread_(thread), | 48 thread_(thread), |
49 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {} | 49 weak_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {} |
50 | 50 |
51 DelayBasedTimeSource::~DelayBasedTimeSource() {} | 51 DelayBasedTimeSource::~DelayBasedTimeSource() {} |
52 | 52 |
53 void DelayBasedTimeSource::SetActive(bool active) { | 53 void DelayBasedTimeSource::SetActive(bool active) { |
54 TRACE_EVENT1("cc", "DelayBasedTimeSource::setActive", "active", active); | 54 TRACE_EVENT1("cc", "DelayBasedTimeSource::SetActive", "active", active); |
55 if (!active) { | 55 if (!active) { |
56 state_ = STATE_INACTIVE; | 56 state_ = STATE_INACTIVE; |
57 weak_factory_.InvalidateWeakPtrs(); | 57 weak_factory_.InvalidateWeakPtrs(); |
58 return; | 58 return; |
59 } | 59 } |
60 | 60 |
61 if (state_ == STATE_STARTING || state_ == STATE_ACTIVE) | 61 if (state_ == STATE_STARTING || state_ == STATE_ACTIVE) |
62 return; | 62 return; |
63 | 63 |
64 if (!has_tick_target_) { | 64 if (!has_tick_target_) { |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
145 return; | 145 return; |
146 } | 146 } |
147 } | 147 } |
148 | 148 |
149 base::TimeTicks DelayBasedTimeSource::Now() const { | 149 base::TimeTicks DelayBasedTimeSource::Now() const { |
150 return base::TimeTicks::Now(); | 150 return base::TimeTicks::Now(); |
151 } | 151 } |
152 | 152 |
153 // This code tries to achieve an average tick rate as close to interval_ as | 153 // This code tries to achieve an average tick rate as close to interval_ as |
154 // possible. To do this, it has to deal with a few basic issues: | 154 // possible. To do this, it has to deal with a few basic issues: |
155 // 1. postDelayedTask can delay only at a millisecond granularity. So, 16.666 | 155 // 1. PostDelayedTask can delay only at a millisecond granularity. So, 16.666 |
156 // has to posted as 16 or 17. | 156 // has to posted as 16 or 17. |
157 // 2. A delayed task may come back a bit late (a few ms), or really late | 157 // 2. A delayed task may come back a bit late (a few ms), or really late |
158 // (frames later) | 158 // (frames later) |
159 // | 159 // |
160 // The basic idea with this scheduler here is to keep track of where we *want* | 160 // The basic idea with this scheduler here is to keep track of where we *want* |
161 // to run in tick_target_. We update this with the exact interval. | 161 // to run in tick_target_. We update this with the exact interval. |
162 // | 162 // |
163 // Then, when we post our task, we take the floor of (tick_target_ and Now()). | 163 // Then, when we post our task, we take the floor of (tick_target_ and Now()). |
164 // If we started at now=0, and 60FPs (all times in milliseconds): | 164 // If we started at now=0, and 60FPs (all times in milliseconds): |
165 // now=0 target=16.667 postDelayedTask(16) | 165 // now=0 target=16.667 PostDelayedTask(16) |
166 // | 166 // |
167 // When our callback runs, we figure out how far off we were from that goal. | 167 // When our callback runs, we figure out how far off we were from that goal. |
168 // Because of the flooring operation, and assuming our timer runs exactly when | 168 // Because of the flooring operation, and assuming our timer runs exactly when |
169 // it should, this yields: | 169 // it should, this yields: |
170 // now=16 target=16.667 | 170 // now=16 target=16.667 |
171 // | 171 // |
172 // Since we can't post a 0.667 ms task to get to now=16, we just treat this as a | 172 // Since we can't post a 0.667 ms task to get to now=16, we just treat this as a |
173 // tick. Then, we update target to be 33.333. We now post another task based on | 173 // tick. Then, we update target to be 33.333. We now post another task based on |
174 // the difference between our target and now: | 174 // the difference between our target and now: |
175 // now=16 tick_target=16.667 newTarget=33.333 --> | 175 // now=16 tick_target=16.667 new_target=33.333 --> |
176 // postDelayedTask(floor(33.333 - 16)) --> postDelayedTask(17) | 176 // PostDelayedTask(floor(33.333 - 16)) --> PostDelayedTask(17) |
177 // | 177 // |
178 // Over time, with no late tasks, this leads to us posting tasks like this: | 178 // Over time, with no late tasks, this leads to us posting tasks like this: |
179 // now=0 tick_target=0 newTarget=16.667 --> | 179 // now=0 tick_target=0 new_target=16.667 --> |
180 // tick(), postDelayedTask(16) | 180 // tick(), PostDelayedTask(16) |
181 // now=16 tick_target=16.667 newTarget=33.333 --> | 181 // now=16 tick_target=16.667 new_target=33.333 --> |
182 // tick(), postDelayedTask(17) | 182 // tick(), PostDelayedTask(17) |
183 // now=33 tick_target=33.333 newTarget=50.000 --> | 183 // now=33 tick_target=33.333 new_target=50.000 --> |
184 // tick(), postDelayedTask(17) | 184 // tick(), PostDelayedTask(17) |
185 // now=50 tick_target=50.000 newTarget=66.667 --> | 185 // now=50 tick_target=50.000 new_target=66.667 --> |
186 // tick(), postDelayedTask(16) | 186 // tick(), PostDelayedTask(16) |
187 // | 187 // |
188 // We treat delays in tasks differently depending on the amount of delay we | 188 // We treat delays in tasks differently depending on the amount of delay we |
189 // encounter. Suppose we posted a task with a target=16.667: | 189 // encounter. Suppose we posted a task with a target=16.667: |
190 // Case 1: late but not unrecoverably-so | 190 // Case 1: late but not unrecoverably-so |
191 // now=18 tick_target=16.667 | 191 // now=18 tick_target=16.667 |
192 // | 192 // |
193 // Case 2: so late we obviously missed the tick | 193 // Case 2: so late we obviously missed the tick |
194 // now=25.0 tick_target=16.667 | 194 // now=25.0 tick_target=16.667 |
195 // | 195 // |
196 // We treat the first case as a tick anyway, and assume the delay was unusual. | 196 // We treat the first case as a tick anyway, and assume the delay was unusual. |
197 // Thus, we compute the newTarget based on the old timebase: | 197 // Thus, we compute the new_target based on the old timebase: |
198 // now=18 tick_target=16.667 newTarget=33.333 --> | 198 // now=18 tick_target=16.667 new_target=33.333 --> |
199 // tick(), postDelayedTask(floor(33.333-18)) --> postDelayedTask(15) | 199 // tick(), PostDelayedTask(floor(33.333-18)) --> PostDelayedTask(15) |
200 // This brings us back to 18+15 = 33, which was where we would have been if the | 200 // This brings us back to 18+15 = 33, which was where we would have been if the |
201 // task hadn't been late. | 201 // task hadn't been late. |
202 // | 202 // |
203 // For the really late delay, we we move to the next logical tick. The timebase | 203 // For the really late delay, we we move to the next logical tick. The timebase |
204 // is not reset. | 204 // is not reset. |
205 // now=37 tick_target=16.667 newTarget=50.000 --> | 205 // now=37 tick_target=16.667 new_target=50.000 --> |
206 // tick(), postDelayedTask(floor(50.000-37)) --> postDelayedTask(13) | 206 // tick(), PostDelayedTask(floor(50.000-37)) --> PostDelayedTask(13) |
207 base::TimeTicks DelayBasedTimeSource::NextTickTarget(base::TimeTicks now) { | 207 base::TimeTicks DelayBasedTimeSource::NextTickTarget(base::TimeTicks now) { |
208 base::TimeDelta new_interval = next_parameters_.interval; | 208 base::TimeDelta new_interval = next_parameters_.interval; |
209 int intervals_elapsed = | 209 int intervals_elapsed = |
210 static_cast<int>(floor((now - next_parameters_.tick_target).InSecondsF() / | 210 static_cast<int>(floor((now - next_parameters_.tick_target).InSecondsF() / |
211 new_interval.InSecondsF())); | 211 new_interval.InSecondsF())); |
212 base::TimeTicks last_effective_tick = | 212 base::TimeTicks last_effective_tick = |
213 next_parameters_.tick_target + new_interval * intervals_elapsed; | 213 next_parameters_.tick_target + new_interval * intervals_elapsed; |
214 base::TimeTicks new_tick_target = last_effective_tick + new_interval; | 214 base::TimeTicks new_tick_target = last_effective_tick + new_interval; |
215 DCHECK(new_tick_target > now); | 215 DCHECK(new_tick_target > now); |
216 | 216 |
(...skipping 17 matching lines...) Expand all Loading... |
234 (1.0 + kDoubleTickThreshold)); | 234 (1.0 + kDoubleTickThreshold)); |
235 thread_->PostDelayedTask(base::Bind(&DelayBasedTimeSource::OnTimerFired, | 235 thread_->PostDelayedTask(base::Bind(&DelayBasedTimeSource::OnTimerFired, |
236 weak_factory_.GetWeakPtr()), | 236 weak_factory_.GetWeakPtr()), |
237 delay); | 237 delay); |
238 | 238 |
239 next_parameters_.tick_target = new_tick_target; | 239 next_parameters_.tick_target = new_tick_target; |
240 current_parameters_ = next_parameters_; | 240 current_parameters_ = next_parameters_; |
241 } | 241 } |
242 | 242 |
243 } // namespace cc | 243 } // namespace cc |
OLD | NEW |