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

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

Powered by Google App Engine
This is Rietveld 408576698