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

Powered by Google App Engine
This is Rietveld 408576698