OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "cc/scheduler/frame_source.h" |
| 6 |
| 7 #include "base/debug/trace_event.h" |
| 8 #include "base/logging.h" |
| 9 #include "cc/scheduler/delay_based_time_source.h" |
| 10 #include "cc/scheduler/scheduler.h" |
| 11 #include "ui/gfx/frame_time.h" |
| 12 |
| 13 #define FRAMESOURCE_TYPESTRING(x) \ |
| 14 std::string x::TypeString() const { return #x; } |
| 15 |
| 16 namespace cc { |
| 17 |
| 18 BaseBeginFrameSource::BaseBeginFrameSource(BeginFrameSink* sink) |
| 19 : frame_sink_(sink), |
| 20 generate_frames_(false), |
| 21 timebase_(), |
| 22 interval_(BeginFrameArgs::DefaultInterval()) { |
| 23 } |
| 24 |
| 25 // BeginFrameSource ------------------------------------------------------ |
| 26 void BaseBeginFrameSource::SetBeginFrameSink(BeginFrameSink* sink) { |
| 27 DCHECK(sink); |
| 28 frame_sink_ = sink; |
| 29 } |
| 30 BeginFrameSink* BaseBeginFrameSource::GetBeginFrameSink() const { |
| 31 DCHECK(frame_sink_); |
| 32 return frame_sink_; |
| 33 } |
| 34 |
| 35 void BaseBeginFrameSource::SetGenerateFrames(bool generate_frames) { |
| 36 if (generate_frames_ != generate_frames) { |
| 37 OnGenerateChange(generate_frames); |
| 38 generate_frames_ = generate_frames; |
| 39 } |
| 40 } |
| 41 |
| 42 bool BaseBeginFrameSource::IsGeneratingFrames() const { |
| 43 return generate_frames_; |
| 44 } |
| 45 |
| 46 void BaseBeginFrameSource::PendingFrames(size_t count) { |
| 47 OnPendingFrames(count); |
| 48 } |
| 49 |
| 50 void BaseBeginFrameSource::SetTimeBaseAndInterval( |
| 51 const base::TimeTicks timebase, |
| 52 const base::TimeDelta interval) { |
| 53 base::TimeDelta newinterval = interval; |
| 54 if (newinterval == base::TimeDelta()) |
| 55 newinterval = BeginFrameArgs::DefaultInterval(); |
| 56 |
| 57 OnTimeBaseAndIntervalChange(timebase, newinterval); |
| 58 |
| 59 timebase_ = timebase; |
| 60 interval_ = newinterval; |
| 61 } |
| 62 |
| 63 base::TimeTicks BaseBeginFrameSource::TimeBase() const { |
| 64 return timebase_; |
| 65 } |
| 66 |
| 67 base::TimeDelta BaseBeginFrameSource::Interval() const { |
| 68 return interval_; |
| 69 } |
| 70 |
| 71 scoped_ptr<base::Value> BaseBeginFrameSource::BeginFrameSourceAsValue() const { |
| 72 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue); |
| 73 state->SetString("type", TypeString()); |
| 74 state->SetInteger("frame_source", reinterpret_cast<size_t>(this)); |
| 75 state->SetBoolean("generate_frames", generate_frames_); |
| 76 state->SetDouble("timebase_us", timebase_.ToInternalValue()); |
| 77 state->SetDouble("interval_us", interval_.InMicroseconds()); |
| 78 |
| 79 ExtraAsValue(state.get()); |
| 80 |
| 81 return state.PassAs<base::Value>(); |
| 82 } |
| 83 |
| 84 /************************************************************************* |
| 85 * |
| 86 */ |
| 87 ProxyBeginFrameSource::ProxyBeginFrameSource(BeginFrameSink* sink, |
| 88 BeginFrameSource* source) |
| 89 : BaseBeginFrameSource(sink), source_(source) { |
| 90 DCHECK(source_); |
| 91 source_->SetBeginFrameSink(this); |
| 92 } |
| 93 |
| 94 // BeginFrameSink -------------------------------------------------------- |
| 95 void ProxyBeginFrameSource::BeginFrame(const BeginFrameArgs& args) { |
| 96 frame_sink_->BeginFrame(args); |
| 97 } |
| 98 |
| 99 // BaseBeginFrameSource --------------------------------------------------- |
| 100 |
| 101 FRAMESOURCE_TYPESTRING(ProxyBeginFrameSource); |
| 102 |
| 103 void ProxyBeginFrameSource::ExtraAsValue(base::DictionaryValue* state) const { |
| 104 state->Set("source", source_->BeginFrameSourceAsValue().release()); |
| 105 } |
| 106 |
| 107 void ProxyBeginFrameSource::OnGenerateChange(bool generate_frames) { |
| 108 DCHECK(source_); |
| 109 source_->SetGenerateFrames(generate_frames); |
| 110 } |
| 111 |
| 112 void ProxyBeginFrameSource::OnPendingFrames(size_t count) { |
| 113 DCHECK(source_); |
| 114 source_->PendingFrames(count); |
| 115 } |
| 116 |
| 117 void ProxyBeginFrameSource::OnTimeBaseAndIntervalChange( |
| 118 const base::TimeTicks timebase, |
| 119 const base::TimeDelta interval) { |
| 120 DCHECK(source_); |
| 121 source_->SetTimeBaseAndInterval(timebase, interval); |
| 122 } |
| 123 |
| 124 /************************************************************************* |
| 125 * |
| 126 */ |
| 127 ThrottledBeginFrameSource::ThrottledBeginFrameSource(BeginFrameSink* sink, |
| 128 BeginFrameSource* source, |
| 129 base::TimeDelta interval) |
| 130 : ProxyBeginFrameSource(sink, source), last_frame_args_() { |
| 131 interval_ = interval; |
| 132 } |
| 133 |
| 134 // BeginFrameSink -------------------------------------------------------- |
| 135 void ThrottledBeginFrameSource::BeginFrame(const BeginFrameArgs& args) { |
| 136 if (last_frame_args_.IsValid() && |
| 137 last_frame_args_.frame_time + interval_ > args.frame_time) |
| 138 return; |
| 139 last_frame_args_ = args; |
| 140 frame_sink_->BeginFrame(args); |
| 141 } |
| 142 |
| 143 // BeginFrameSource ------------------------------------------------------ |
| 144 |
| 145 FRAMESOURCE_TYPESTRING(ThrottledBeginFrameSource) |
| 146 |
| 147 void ThrottledBeginFrameSource::ExtraAsValue( |
| 148 base::DictionaryValue* state) const { |
| 149 state->Set("source", source_->BeginFrameSourceAsValue().release()); |
| 150 state->Set("last_frame_args", last_frame_args_.AsValue().release()); |
| 151 } |
| 152 |
| 153 /*************************************************************************/ |
| 154 BackToBackBeginFrameSource::BackToBackBeginFrameSource( |
| 155 BeginFrameSink* sink, |
| 156 base::SingleThreadTaskRunner* task_runner) |
| 157 : BaseBeginFrameSource(sink), |
| 158 task_runner_(task_runner), |
| 159 send_begin_frame_posted_(false) { |
| 160 DCHECK(task_runner); |
| 161 } |
| 162 |
| 163 void BackToBackBeginFrameSource::ScheduleSendBeginFrameArgs() { |
| 164 if (!generate_frames_) |
| 165 return; |
| 166 |
| 167 if (send_begin_frame_posted_) |
| 168 return; |
| 169 |
| 170 send_begin_frame_posted_ = true; |
| 171 task_runner_->PostTask( |
| 172 FROM_HERE, |
| 173 base::Bind(&BackToBackBeginFrameSource::SendBeginFrameArgs, |
| 174 base::Unretained(this))); |
| 175 } |
| 176 |
| 177 void BackToBackBeginFrameSource::SendBeginFrameArgs() { |
| 178 send_begin_frame_posted_ = false; |
| 179 |
| 180 // TODO(mithro): Fix the tests so this can be enabled. The tests currently |
| 181 // depend on one begin frame firing after generate_frames_ is set false. |
| 182 // if (!generate_frames_) { |
| 183 // return; |
| 184 // } |
| 185 |
| 186 base::TimeTicks now = gfx::FrameTime::Now(); |
| 187 // TODO(mithro): Is a deadline of now+interval_ sane? |
| 188 BeginFrameArgs args = BeginFrameArgs::Create(now, now + interval_, interval_); |
| 189 frame_sink_->BeginFrame(args); |
| 190 } |
| 191 |
| 192 // BeginFrameSource ------------------------------------------------------ |
| 193 |
| 194 FRAMESOURCE_TYPESTRING(BackToBackBeginFrameSource); |
| 195 |
| 196 void BackToBackBeginFrameSource::ExtraAsValue( |
| 197 base::DictionaryValue* state) const { |
| 198 state->SetBoolean("send_begin_frame_posted_", send_begin_frame_posted_); |
| 199 } |
| 200 |
| 201 void BackToBackBeginFrameSource::OnGenerateChange(bool generate_frames) { |
| 202 ScheduleSendBeginFrameArgs(); |
| 203 } |
| 204 |
| 205 void BackToBackBeginFrameSource::OnPendingFrames(size_t count) { |
| 206 if (count == 0) { |
| 207 ScheduleSendBeginFrameArgs(); |
| 208 } |
| 209 } |
| 210 |
| 211 /*************************************************************************/ |
| 212 SyntheticBeginFrameSource::SyntheticBeginFrameSource( |
| 213 BeginFrameSink* sink, |
| 214 base::SingleThreadTaskRunner* task_runner, |
| 215 base::TimeDelta interval) |
| 216 : BaseBeginFrameSource(sink), task_runner_(task_runner) { |
| 217 DCHECK(task_runner); |
| 218 interval_ = interval; |
| 219 if (gfx::FrameTime::TimestampsAreHighRes()) { |
| 220 time_source_ = DelayBasedTimeSourceHighRes::Create(interval_, task_runner); |
| 221 } else { |
| 222 time_source_ = DelayBasedTimeSource::Create(interval_, task_runner); |
| 223 } |
| 224 time_source_->SetActive(false); |
| 225 time_source_->SetClient(this); |
| 226 } |
| 227 |
| 228 SyntheticBeginFrameSource::~SyntheticBeginFrameSource() { |
| 229 time_source_->SetActive(false); |
| 230 } |
| 231 |
| 232 BeginFrameArgs SyntheticBeginFrameSource::CreateBeginFrameArgs( |
| 233 base::TimeTicks frame_time) { |
| 234 base::TimeTicks deadline = time_source_->NextTickTime(); |
| 235 return BeginFrameArgs::Create(frame_time, deadline, interval_); |
| 236 } |
| 237 |
| 238 // TimeSourceClient ------------------------------------------------------ |
| 239 |
| 240 void SyntheticBeginFrameSource::OnTimerTick() { |
| 241 frame_sink_->BeginFrame(CreateBeginFrameArgs(time_source_->LastTickTime())); |
| 242 } |
| 243 |
| 244 // BeginFrameSource ------------------------------------------------------ |
| 245 |
| 246 FRAMESOURCE_TYPESTRING(SyntheticBeginFrameSource); |
| 247 |
| 248 void SyntheticBeginFrameSource::ExtraAsValue( |
| 249 base::DictionaryValue* state) const { |
| 250 state->Set("time_source", time_source_->AsValue().release()); |
| 251 } |
| 252 |
| 253 void SyntheticBeginFrameSource::OnGenerateChange(bool generate_frames) { |
| 254 base::TimeTicks missed_tick_time = time_source_->SetActive(generate_frames); |
| 255 if (!missed_tick_time.is_null()) { |
| 256 frame_sink_->BeginFrame(CreateBeginFrameArgs(missed_tick_time)); |
| 257 } |
| 258 } |
| 259 |
| 260 void SyntheticBeginFrameSource::OnTimeBaseAndIntervalChange( |
| 261 const base::TimeTicks timebase, |
| 262 const base::TimeDelta interval) { |
| 263 time_source_->SetTimebaseAndInterval(timebase, interval); |
| 264 } |
| 265 |
| 266 /************************************************************************* |
| 267 * A virtual frame source which lets you switch between two other frame sources |
| 268 * (making sure the BeginFrameArgs stays monotonic). |
| 269 */ |
| 270 DualBeginFrameSource::DualBeginFrameSource( |
| 271 BeginFrameSink* sink, |
| 272 scoped_ptr<BeginFrameSource> source_primary, |
| 273 scoped_ptr<BeginFrameSource> source_secondary) |
| 274 : BaseBeginFrameSource(sink), |
| 275 last_frame_args_(), |
| 276 source_foreground_(source_primary.Pass()), |
| 277 source_background_(source_secondary.Pass()) { |
| 278 source_foreground_->SetBeginFrameSink(this); |
| 279 source_background_->SetBeginFrameSink(this); |
| 280 SwitchSource(SourceForeground()); |
| 281 } |
| 282 |
| 283 DualBeginFrameSource::~DualBeginFrameSource() { |
| 284 } |
| 285 |
| 286 void DualBeginFrameSource::SwitchSource(const BeginFrameSource* new_source) { |
| 287 DCHECK(new_source == SourceForeground() || new_source == SourceBackground()); |
| 288 |
| 289 if (generate_frames_) |
| 290 active_source_->SetGenerateFrames(false); |
| 291 |
| 292 active_source_ = const_cast<BeginFrameSource*>(new_source); |
| 293 |
| 294 if (generate_frames_) |
| 295 active_source_->SetGenerateFrames(true); |
| 296 } |
| 297 |
| 298 const BeginFrameSource* DualBeginFrameSource::SourceForeground() const { |
| 299 return source_foreground_.get(); |
| 300 } |
| 301 |
| 302 const BeginFrameSource* DualBeginFrameSource::SourceBackground() const { |
| 303 return source_background_.get(); |
| 304 } |
| 305 |
| 306 // BeginFrameSink ------------------------------------------------------ |
| 307 |
| 308 void DualBeginFrameSource::BeginFrame(const BeginFrameArgs& args) { |
| 309 // When switching clock sources you can get a BeginFrameArgs with a |
| 310 // frame_time before the last value. |
| 311 BeginFrameArgs new_args = args; |
| 312 if (last_frame_args_.frame_time > new_args.frame_time) |
| 313 return; |
| 314 |
| 315 last_frame_args_ = new_args; |
| 316 frame_sink_->BeginFrame(new_args); |
| 317 } |
| 318 |
| 319 // BeginFrameSource ---------------------------------------------------- |
| 320 |
| 321 FRAMESOURCE_TYPESTRING(DualBeginFrameSource) |
| 322 |
| 323 void DualBeginFrameSource::ExtraAsValue(base::DictionaryValue* state) const { |
| 324 state->Set("last_frame_args", last_frame_args_.AsValue().release()); |
| 325 if (active_source_ == SourceForeground()) |
| 326 state->SetString("active", "primary"); |
| 327 if (active_source_ == SourceBackground()) |
| 328 state->SetString("active", "secondary"); |
| 329 state->Set("primary", |
| 330 source_foreground_->BeginFrameSourceAsValue().release()); |
| 331 state->Set("secondary", |
| 332 source_background_->BeginFrameSourceAsValue().release()); |
| 333 } |
| 334 |
| 335 void DualBeginFrameSource::OnPendingFrames(size_t count) { |
| 336 active_source_->PendingFrames(count); |
| 337 } |
| 338 |
| 339 void DualBeginFrameSource::OnGenerateChange(bool generate_frames) { |
| 340 DCHECK(active_source_); |
| 341 active_source_->SetGenerateFrames(generate_frames); |
| 342 } |
| 343 |
| 344 void DualBeginFrameSource::OnTimeBaseAndIntervalChange( |
| 345 const base::TimeTicks timebase, |
| 346 const base::TimeDelta interval) { |
| 347 DCHECK_EQ(active_source_, source_foreground_); // TODO(mithro): Is this okay? |
| 348 source_foreground_->SetTimeBaseAndInterval(timebase, interval); |
| 349 } |
| 350 |
| 351 } // namespace cc |
OLD | NEW |