Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(21)

Side by Side Diff: cc/scheduler/begin_frame_source.cc

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

Powered by Google App Engine
This is Rietveld 408576698