| 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 |