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

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

Powered by Google App Engine
This is Rietveld 408576698