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/begin_frame_source.h" | |
6 | |
7 #include "base/auto_reset.h" | |
8 #include "base/debug/trace_event.h" | |
9 #include "base/debug/trace_event_argument.h" | |
10 #include "base/logging.h" | |
11 #include "base/strings/string_number_conversions.h" | |
12 #include "cc/scheduler/delay_based_time_source.h" | |
13 #include "cc/scheduler/scheduler.h" | |
14 #include "ui/gfx/frame_time.h" | |
15 | |
16 #ifdef NDEBUG | |
17 #define DEBUG_FRAMES(...) | |
18 #else | |
19 #define DEBUG_FRAMES(...) \ | |
20 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"), \ | |
21 __VA_ARGS__); | |
22 #endif | |
23 | |
24 namespace cc { | |
25 | |
26 // BeginFrameObserverMixIn ----------------------------------------------- | |
27 BeginFrameObserverMixIn::BeginFrameObserverMixIn() | |
28 : last_begin_frame_args_(), dropped_begin_frame_args_(0) { | |
29 } | |
30 | |
31 const BeginFrameArgs BeginFrameObserverMixIn::LastUsedBeginFrameArgs() const { | |
32 return last_begin_frame_args_; | |
33 } | |
34 BeginFrameObserver::BeginFrameArgsStatus BeginFrameObserverMixIn::OnBeginFrame( | |
35 const BeginFrameArgs& args) { | |
36 DEBUG_FRAMES("BeginFrameObserverMixIn::OnBeginFrame", | |
37 "last args", | |
38 last_begin_frame_args_.AsValue(), | |
39 "new args", | |
40 args.AsValue()); | |
41 DCHECK(args.IsValid()); | |
42 // DCHECK(args.frame_time > last_begin_frame_args_.frame_time); | |
43 DCHECK(args.frame_time >= last_begin_frame_args_.frame_time); | |
44 BeginFrameObserver::BeginFrameArgsStatus status = ProcessBeginFrameArgs(args); | |
45 switch (status) { | |
46 case BeginFrameObserver::BeginFrameArgsStatus::USED: | |
47 last_begin_frame_args_ = args; | |
48 break; | |
49 case BeginFrameObserver::BeginFrameArgsStatus::DROPPED: | |
50 ++dropped_begin_frame_args_; | |
51 break; | |
52 } | |
53 return status; | |
54 } | |
55 | |
56 BeginFrameObserver::BeginFrameArgsStatus | |
57 BeginFrameObserverMixIn::OnMissedBeginFrame(const BeginFrameArgs& args) { | |
58 DEBUG_FRAMES("BeginFrameObserverMixIn::OnMissedBeginFrame", | |
59 "last args", | |
60 last_begin_frame_args_.AsValue(), | |
61 "new args", | |
62 args.AsValue()); | |
63 return OnBeginFrame(args); | |
brianderson
2014/09/24 06:03:05
Looks like this is redirecting to the wrong method
mithro-old
2014/09/24 17:14:54
Done.
| |
64 } | |
65 | |
66 void BeginFrameObserverMixIn::AsValueInto( | |
67 base::debug::TracedValue* dict) const { | |
68 dict->BeginDictionary("last_begin_frame_args_"); | |
69 last_begin_frame_args_.AsValueInto(dict); | |
70 dict->EndDictionary(); | |
71 dict->SetInteger("dropped_begin_frame_args_", dropped_begin_frame_args_); | |
72 } | |
73 | |
74 // BeginFrameSource ------------------------------------------------------ | |
75 BeginFrameSource::BeginFrameSource() | |
76 : observer_(NULL), inside_as_value_into_(false) { | |
77 DCHECK(!observer_); | |
78 DCHECK_EQ(inside_as_value_into_, false); | |
79 } | |
80 | |
81 void BeginFrameSource::AddObserver(BeginFrameObserver* obs) { | |
82 DEBUG_FRAMES("BeginFrameSource::AddObserver", | |
83 "current observer", | |
84 observer_, | |
85 "to add observer", | |
86 obs); | |
87 DCHECK(!observer_); | |
88 observer_ = obs; | |
89 } | |
90 | |
91 void BeginFrameSource::RemoveObserver(BeginFrameObserver* obs) { | |
92 DEBUG_FRAMES("BeginFrameSource::RemoveObserver", | |
93 "current observer", | |
94 observer_, | |
95 "to remove observer", | |
96 obs); | |
97 DCHECK_EQ(observer_, obs); | |
98 observer_ = NULL; | |
99 } | |
100 | |
101 BeginFrameObserver::BeginFrameArgsStatus BeginFrameSource::CallOnBeginFrame( | |
102 const BeginFrameArgs& args) { | |
103 DEBUG_FRAMES("BeginFrameSource::CallOnBeginFrame", | |
104 "current observer", | |
105 observer_, | |
106 "args", | |
107 args.AsValue()); | |
108 if (observer_) { | |
109 return observer_->OnBeginFrame(args); | |
110 } | |
111 return BeginFrameObserver::BeginFrameArgsStatus::DROPPED; | |
112 } | |
113 | |
114 BeginFrameObserver::BeginFrameArgsStatus | |
115 BeginFrameSource::CallOnMissedBeginFrame(const BeginFrameArgs& args) { | |
116 DEBUG_FRAMES("BeginFrameSource::CallOnMissedBeginFrame", | |
117 "current observer", | |
118 observer_, | |
119 "args", | |
120 args.AsValue()); | |
121 if (observer_) { | |
122 return observer_->OnMissedBeginFrame(args); | |
123 } | |
124 return BeginFrameObserver::BeginFrameArgsStatus::DROPPED; | |
125 } | |
126 | |
127 // Tracing support | |
128 void BeginFrameSource::AsValueInto(base::debug::TracedValue* dict) const { | |
129 // As the observer might try to trace the source, prevent an infinte loop | |
130 // from occuring. | |
131 if (inside_as_value_into_) { | |
132 dict->SetString("observer", "<loop detected>"); | |
133 return; | |
134 } | |
135 | |
136 if (observer_) { | |
137 base::AutoReset<bool> prevent_loops( | |
138 const_cast<bool*>(&inside_as_value_into_), true); | |
139 dict->BeginDictionary("observer"); | |
140 observer_->AsValueInto(dict); | |
141 dict->EndDictionary(); | |
142 } else { | |
143 dict->SetString("observer", "NULL"); | |
144 } | |
145 } | |
146 | |
147 // BackToBackBeginFrameSource -------------------------------------------- | |
148 scoped_ptr<BackToBackBeginFrameSource> BackToBackBeginFrameSource::Create( | |
149 base::SingleThreadTaskRunner* task_runner) { | |
150 return make_scoped_ptr(new BackToBackBeginFrameSource(task_runner)); | |
151 } | |
152 | |
153 BackToBackBeginFrameSource::BackToBackBeginFrameSource( | |
154 base::SingleThreadTaskRunner* task_runner) | |
155 : BeginFrameSource(), | |
156 weak_factory_(this), | |
157 task_runner_(task_runner), | |
158 needs_begin_frames_(false), | |
159 send_begin_frame_posted_(false) { | |
160 DCHECK(task_runner); | |
161 DCHECK_EQ(needs_begin_frames_, false); | |
162 DCHECK_EQ(send_begin_frame_posted_, false); | |
163 } | |
164 | |
165 BackToBackBeginFrameSource::~BackToBackBeginFrameSource() { | |
166 } | |
167 | |
168 base::TimeTicks BackToBackBeginFrameSource::Now() { | |
169 return gfx::FrameTime::Now(); | |
170 } | |
171 | |
172 void BackToBackBeginFrameSource::ScheduleBeginFrame() { | |
173 if (!needs_begin_frames_) | |
174 return; | |
175 | |
176 if (send_begin_frame_posted_) | |
177 return; | |
178 | |
179 send_begin_frame_posted_ = true; | |
180 task_runner_->PostTask(FROM_HERE, | |
181 base::Bind(&BackToBackBeginFrameSource::BeginFrame, | |
182 weak_factory_.GetWeakPtr())); | |
183 } | |
184 | |
185 void BackToBackBeginFrameSource::BeginFrame() { | |
186 send_begin_frame_posted_ = false; | |
187 | |
188 if (!needs_begin_frames_) | |
189 return; | |
190 | |
191 base::TimeTicks now = Now(); | |
192 BeginFrameArgs args = | |
193 BeginFrameArgs::Create(now, | |
194 now + BeginFrameArgs::DefaultInterval(), | |
195 BeginFrameArgs::DefaultInterval()); | |
196 CallOnBeginFrame(args); | |
197 } | |
198 | |
199 // BackToBackBeginFrameSource -------------------------------------------- | |
200 bool BackToBackBeginFrameSource::NeedsBeginFrames() const { | |
201 return needs_begin_frames_; | |
202 } | |
203 | |
204 void BackToBackBeginFrameSource::SetNeedsBeginFrames(bool needs_begin_frames) { | |
205 needs_begin_frames_ = needs_begin_frames; | |
206 ScheduleBeginFrame(); | |
207 } | |
208 | |
209 void BackToBackBeginFrameSource::DidFinishFrame(size_t remaining_frames) { | |
210 if (remaining_frames == 0) { | |
211 ScheduleBeginFrame(); | |
212 } | |
213 } | |
214 | |
215 // Tracing | |
216 void BackToBackBeginFrameSource::AsValueInto( | |
217 base::debug::TracedValue* dict) const { | |
218 dict->SetString("type", "BackToBackBeginFrameSource"); | |
219 BeginFrameSource::AsValueInto(dict); | |
220 dict->SetBoolean("send_begin_frame_posted_", send_begin_frame_posted_); | |
221 dict->SetBoolean("needs_begin_frames", needs_begin_frames_); | |
222 } | |
223 | |
224 // SyntheticBeginFrameSource --------------------------------------------- | |
225 scoped_ptr<SyntheticBeginFrameSource> SyntheticBeginFrameSource::Create( | |
226 base::SingleThreadTaskRunner* task_runner, | |
227 base::TimeTicks initial_vsync_timebase, | |
228 base::TimeDelta initial_vsync_interval) { | |
229 scoped_refptr<DelayBasedTimeSource> time_source; | |
230 if (gfx::FrameTime::TimestampsAreHighRes()) { | |
231 time_source = DelayBasedTimeSourceHighRes::Create(initial_vsync_interval, | |
232 task_runner); | |
233 } else { | |
234 time_source = | |
235 DelayBasedTimeSource::Create(initial_vsync_interval, task_runner); | |
236 } | |
237 | |
238 return make_scoped_ptr(new SyntheticBeginFrameSource(time_source)); | |
239 } | |
240 | |
241 SyntheticBeginFrameSource::SyntheticBeginFrameSource( | |
242 scoped_refptr<DelayBasedTimeSource> time_source) | |
243 : BeginFrameSource(), time_source_(time_source) { | |
244 time_source_->SetActive(false); | |
245 time_source_->SetClient(this); | |
246 } | |
247 | |
248 SyntheticBeginFrameSource::~SyntheticBeginFrameSource() { | |
249 if (NeedsBeginFrames()) | |
250 time_source_->SetActive(false); | |
251 } | |
252 | |
253 void SyntheticBeginFrameSource::OnUpdateVSyncParameters( | |
254 base::TimeTicks new_vsync_timebase, | |
255 base::TimeDelta new_vsync_interval) { | |
256 time_source_->SetTimebaseAndInterval(new_vsync_timebase, new_vsync_interval); | |
257 } | |
258 | |
259 void SyntheticBeginFrameSource::SendBeginFrameFromTick( | |
260 base::TimeTicks frame_time) { | |
261 base::TimeTicks deadline = time_source_->NextTickTime(); | |
262 CallOnBeginFrame( | |
263 BeginFrameArgs::Create(frame_time, deadline, time_source_->Interval())); | |
264 } | |
265 | |
266 // TimeSourceClient | |
267 void SyntheticBeginFrameSource::OnTimerTick() { | |
268 SendBeginFrameFromTick(time_source_->LastTickTime()); | |
269 } | |
270 | |
271 // BeginFrameSource | |
272 void SyntheticBeginFrameSource::SetNeedsBeginFrames(bool needs_begin_frames) { | |
273 if (needs_begin_frames == NeedsBeginFrames()) | |
274 return; | |
275 | |
276 base::TimeTicks missed_tick_time = | |
277 time_source_->SetActive(needs_begin_frames); | |
278 if (!missed_tick_time.is_null()) { | |
279 SendBeginFrameFromTick(missed_tick_time); | |
280 } | |
281 } | |
282 | |
283 bool SyntheticBeginFrameSource::NeedsBeginFrames() const { | |
284 return time_source_->Active(); | |
285 } | |
286 | |
287 // Tracing | |
288 void SyntheticBeginFrameSource::AsValueInto( | |
289 base::debug::TracedValue* dict) const { | |
290 dict->SetString("type", "SyntheticBeginFrameSource"); | |
291 BeginFrameSource::AsValueInto(dict); | |
292 | |
293 dict->BeginDictionary("last_frame_args"); | |
294 time_source_->AsValueInto(dict); | |
295 dict->EndDictionary(); | |
296 } | |
297 | |
298 // BeginFrameSourceMultiplexer ------------------------------------------- | |
299 scoped_ptr<BeginFrameSourceMultiplexer> BeginFrameSourceMultiplexer::Create() { | |
300 return make_scoped_ptr(new BeginFrameSourceMultiplexer()); | |
301 } | |
302 | |
303 BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer() | |
304 : BeginFrameSource(), | |
305 minimum_interval_(base::TimeDelta()), | |
306 active_source_(NULL), | |
307 source_list_() { | |
308 } | |
309 | |
310 BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer( | |
311 base::TimeDelta minimum_interval) | |
312 : BeginFrameSource(), | |
313 minimum_interval_(minimum_interval), | |
314 active_source_(NULL), | |
315 source_list_() { | |
316 } | |
317 | |
318 BeginFrameSourceMultiplexer::~BeginFrameSourceMultiplexer() { | |
319 } | |
320 | |
321 void BeginFrameSourceMultiplexer::SetMinimumInterval( | |
322 base::TimeDelta new_minimum_interval) { | |
323 DEBUG_FRAMES("BeginFrameSourceMultiplexer::SetMinimumInterval", | |
324 "current minimum (us)", | |
325 minimum_interval_.InMicroseconds(), | |
326 "new minimum (us)", | |
327 new_minimum_interval.InMicroseconds()); | |
328 DCHECK_GE(new_minimum_interval.ToInternalValue(), 0); | |
329 minimum_interval_ = new_minimum_interval; | |
330 } | |
331 | |
332 void BeginFrameSourceMultiplexer::AddSource(BeginFrameSource* new_source) { | |
333 DEBUG_FRAMES("BeginFrameSourceMultiplexer::AddSource", | |
334 "current active", | |
335 active_source_, | |
336 "source to remove", | |
337 new_source); | |
338 DCHECK(new_source); | |
339 DCHECK(!HasSource(new_source)); | |
340 | |
341 source_list_.insert(new_source); | |
342 | |
343 // If there is no active source, set the new one as the active one. | |
344 if (!active_source_) | |
345 SetActiveSource(new_source); | |
346 } | |
347 | |
348 void BeginFrameSourceMultiplexer::RemoveSource( | |
349 BeginFrameSource* existing_source) { | |
350 DEBUG_FRAMES("BeginFrameSourceMultiplexer::RemoveSource", | |
351 "current active", | |
352 active_source_, | |
353 "source to remove", | |
354 existing_source); | |
355 DCHECK(existing_source); | |
356 DCHECK(HasSource(existing_source)); | |
357 DCHECK_NE(existing_source, active_source_); | |
358 source_list_.erase(existing_source); | |
359 } | |
360 | |
361 void BeginFrameSourceMultiplexer::SetActiveSource( | |
362 BeginFrameSource* new_source) { | |
363 DEBUG_FRAMES("BeginFrameSourceMultiplexer::SetActiveSource", | |
364 "current active", | |
365 active_source_, | |
366 "to become active", | |
367 new_source); | |
368 | |
369 DCHECK(HasSource(new_source) || new_source == NULL); | |
370 | |
371 bool needs_begin_frames = NeedsBeginFrames(); | |
372 if (active_source_) { | |
373 if (needs_begin_frames) | |
374 SetNeedsBeginFrames(false); | |
375 | |
376 // Technically we shouldn't need to remove observation, but this prevents | |
377 // the case where SetNeedsBeginFrames message gets to the source after a | |
378 // message has already been sent. | |
379 active_source_->RemoveObserver(this); | |
380 active_source_ = NULL; | |
381 } | |
382 DCHECK(!active_source_); | |
383 active_source_ = new_source; | |
384 | |
385 if (active_source_) { | |
386 active_source_->AddObserver(this); | |
387 | |
388 if (needs_begin_frames) { | |
389 SetNeedsBeginFrames(true); | |
390 } | |
391 } | |
392 } | |
393 | |
394 const BeginFrameSource* BeginFrameSourceMultiplexer::ActiveSource() { | |
395 return active_source_; | |
396 } | |
397 | |
398 // BeginFrameObserver | |
399 BeginFrameObserver::BeginFrameArgsStatus | |
400 BeginFrameSourceMultiplexer::OnBeginFrame(const BeginFrameArgs& args) { | |
401 if (!IsIncreasing(args)) { | |
402 DEBUG_FRAMES("BeginFrameSourceMultiplexer::OnBeginFrame", | |
403 "action", | |
404 "discarding", | |
405 "new args", | |
406 args.AsValue()); | |
407 return BeginFrameObserver::BeginFrameArgsStatus::DROPPED; | |
408 } else { | |
409 DEBUG_FRAMES("BeginFrameSourceMultiplexer::OnBeginFrame", | |
410 "action", | |
411 "using", | |
412 "new args", | |
413 args.AsValue()); | |
414 } | |
415 return CallOnBeginFrame(args); | |
416 } | |
417 | |
418 BeginFrameObserver::BeginFrameArgsStatus | |
419 BeginFrameSourceMultiplexer::OnMissedBeginFrame(const BeginFrameArgs& args) { | |
420 if (!IsIncreasing(args)) { | |
421 DEBUG_FRAMES("BeginFrameSourceMultiplexer::OnMissedBeginFrame", | |
422 "action", | |
423 "discarding", | |
424 "new args", | |
425 args.AsValue()); | |
426 return BeginFrameObserver::BeginFrameArgsStatus::DROPPED; | |
427 } else { | |
428 DEBUG_FRAMES("BeginFrameSourceMultiplexer::OnMissedBeginFrame", | |
429 "action", | |
430 "using", | |
431 "new args", | |
432 args.AsValue()); | |
433 } | |
434 return CallOnMissedBeginFrame(args); | |
435 } | |
436 | |
437 const BeginFrameArgs BeginFrameSourceMultiplexer::LastUsedBeginFrameArgs() | |
438 const { | |
439 if (observer_) | |
440 return observer_->LastUsedBeginFrameArgs(); | |
441 else | |
442 return BeginFrameArgs(); | |
443 } | |
444 | |
445 // BeginFrameSource | |
446 bool BeginFrameSourceMultiplexer::NeedsBeginFrames() const { | |
447 if (active_source_) { | |
448 return active_source_->NeedsBeginFrames(); | |
449 } else { | |
450 return false; | |
451 } | |
452 } | |
453 | |
454 void BeginFrameSourceMultiplexer::SetNeedsBeginFrames(bool needs_begin_frames) { | |
455 DEBUG_FRAMES("BeginFrameSourceMultiplexer::SetNeedsBeginFrames", | |
456 "active_source", | |
457 active_source_, | |
458 "needs_begin_frames", | |
459 needs_begin_frames); | |
460 if (active_source_) { | |
461 active_source_->SetNeedsBeginFrames(needs_begin_frames); | |
462 } else { | |
463 DCHECK(!needs_begin_frames); | |
464 } | |
465 } | |
466 | |
467 void BeginFrameSourceMultiplexer::DidFinishFrame(size_t remaining_frames) { | |
468 DEBUG_FRAMES("BeginFrameSourceMultiplexer::DidFinishFrame", | |
469 "active_source", | |
470 active_source_, | |
471 "remaining_frames", | |
472 remaining_frames); | |
473 if (active_source_) { | |
474 active_source_->DidFinishFrame(remaining_frames); | |
475 } | |
476 } | |
477 | |
478 // Tracing | |
479 void BeginFrameSourceMultiplexer::AsValueInto( | |
480 base::debug::TracedValue* dict) const { | |
481 dict->SetString("type", "BeginFrameSourceMultiplexer"); | |
482 | |
483 dict->SetInteger("minimum_interval_us", minimum_interval_.InMicroseconds()); | |
484 if (observer_) { | |
485 dict->BeginDictionary("last_begin_frame_args"); | |
486 observer_->LastUsedBeginFrameArgs().AsValueInto(dict); | |
487 dict->EndDictionary(); | |
488 } | |
489 | |
490 if (active_source_) { | |
491 dict->BeginDictionary("active_source"); | |
492 active_source_->AsValueInto(dict); | |
493 dict->EndDictionary(); | |
494 } else { | |
495 dict->SetString("active_source", "NULL"); | |
496 } | |
497 | |
498 for (std::set<BeginFrameSource*>::const_iterator it = source_list_.begin(); | |
499 it != source_list_.end(); | |
500 ++it) { | |
501 dict->BeginDictionary( | |
502 base::SizeTToString(std::distance(source_list_.begin(), it)).c_str()); | |
503 (*it)->AsValueInto(dict); | |
504 dict->EndDictionary(); | |
505 } | |
506 } | |
507 | |
508 // protected methods | |
509 bool BeginFrameSourceMultiplexer::HasSource(BeginFrameSource* source) { | |
510 return (source_list_.find(source) != source_list_.end()); | |
511 } | |
512 | |
513 bool BeginFrameSourceMultiplexer::IsIncreasing(const BeginFrameArgs& args) { | |
514 DCHECK(args.IsValid()); | |
515 if (!observer_) | |
516 return false; | |
517 | |
518 // If the last begin frame is invalid, than any new begin frame is valid. | |
brianderson
2014/09/24 06:03:05
than -> then
mithro-old
2014/09/24 17:14:55
Done.
| |
519 if (!observer_->LastUsedBeginFrameArgs().IsValid()) | |
520 return true; | |
521 | |
522 // Only allow new args have a *strictly bigger* frame_time value and statisfy | |
523 // minimum interval requirement. | |
524 return ( // args.frame_time > observer_->LastUsedBeginFrameArgs().frame_time | |
brianderson
2014/09/24 06:03:05
Remove commented out code.
mithro-old
2014/09/24 17:14:55
Done.
| |
525 // && | |
526 args.frame_time >= | |
527 observer_->LastUsedBeginFrameArgs().frame_time + minimum_interval_); | |
528 } | |
529 | |
530 } // namespace cc | |
OLD | NEW |