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

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: Fixing for review comments. 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 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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698