Use multiline attribute to check for IA2_STATE_MULTILINE.
[chromium-blink-merge.git] / cc / scheduler / begin_frame_source.cc
blob78fd3171601ac7f60b7163c18a3b1828625e161e
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.
5 #include "cc/scheduler/begin_frame_source.h"
7 #include "base/auto_reset.h"
8 #include "base/location.h"
9 #include "base/logging.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/trace_event/trace_event.h"
12 #include "base/trace_event/trace_event_argument.h"
13 #include "cc/scheduler/delay_based_time_source.h"
14 #include "cc/scheduler/scheduler.h"
15 #include "ui/gfx/frame_time.h"
17 #ifdef NDEBUG
18 #define DEBUG_FRAMES(...)
19 #else
20 #define DEBUG_FRAMES(name, arg1_name, arg1_val, arg2_name, arg2_val) \
21 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"), \
22 name, \
23 arg1_name, \
24 arg1_val, \
25 arg2_name, \
26 arg2_val);
27 #endif
29 namespace cc {
31 // BeginFrameObserverMixIn -----------------------------------------------
32 BeginFrameObserverMixIn::BeginFrameObserverMixIn()
33 : last_begin_frame_args_(), dropped_begin_frame_args_(0) {
36 const BeginFrameArgs BeginFrameObserverMixIn::LastUsedBeginFrameArgs() const {
37 return last_begin_frame_args_;
39 void BeginFrameObserverMixIn::OnBeginFrame(const BeginFrameArgs& args) {
40 DEBUG_FRAMES("BeginFrameObserverMixIn::OnBeginFrame",
41 "last args",
42 last_begin_frame_args_.AsValue(),
43 "new args",
44 args.AsValue());
45 DCHECK(args.IsValid());
46 DCHECK(args.frame_time >= last_begin_frame_args_.frame_time);
47 bool used = OnBeginFrameMixInDelegate(args);
48 if (used) {
49 last_begin_frame_args_ = args;
50 } else {
51 ++dropped_begin_frame_args_;
55 void BeginFrameObserverMixIn::AsValueInto(
56 base::trace_event::TracedValue* dict) const {
57 dict->BeginDictionary("last_begin_frame_args_");
58 last_begin_frame_args_.AsValueInto(dict);
59 dict->EndDictionary();
60 dict->SetInteger("dropped_begin_frame_args_", dropped_begin_frame_args_);
63 // BeginFrameSourceMixIn ------------------------------------------------------
64 BeginFrameSourceMixIn::BeginFrameSourceMixIn()
65 : observer_(NULL),
66 needs_begin_frames_(false),
67 inside_as_value_into_(false) {
68 DCHECK(!observer_);
69 DCHECK_EQ(inside_as_value_into_, false);
72 bool BeginFrameSourceMixIn::NeedsBeginFrames() const {
73 return needs_begin_frames_;
76 void BeginFrameSourceMixIn::SetNeedsBeginFrames(bool needs_begin_frames) {
77 DEBUG_FRAMES("BeginFrameSourceMixIn::SetNeedsBeginFrames",
78 "current state",
79 needs_begin_frames_,
80 "new state",
81 needs_begin_frames);
82 if (needs_begin_frames_ != needs_begin_frames) {
83 needs_begin_frames_ = needs_begin_frames;
84 OnNeedsBeginFramesChange(needs_begin_frames);
88 void BeginFrameSourceMixIn::AddObserver(BeginFrameObserver* obs) {
89 DEBUG_FRAMES("BeginFrameSourceMixIn::AddObserver",
90 "current observer",
91 observer_,
92 "to add observer",
93 obs);
94 DCHECK(!observer_);
95 observer_ = obs;
98 void BeginFrameSourceMixIn::RemoveObserver(BeginFrameObserver* obs) {
99 DEBUG_FRAMES("BeginFrameSourceMixIn::RemoveObserver",
100 "current observer",
101 observer_,
102 "to remove observer",
103 obs);
104 DCHECK_EQ(observer_, obs);
105 observer_ = NULL;
108 void BeginFrameSourceMixIn::CallOnBeginFrame(const BeginFrameArgs& args) {
109 DEBUG_FRAMES("BeginFrameSourceMixIn::CallOnBeginFrame",
110 "current observer",
111 observer_,
112 "args",
113 args.AsValue());
114 if (observer_) {
115 return observer_->OnBeginFrame(args);
119 // Tracing support
120 void BeginFrameSourceMixIn::AsValueInto(
121 base::trace_event::TracedValue* dict) const {
122 // As the observer might try to trace the source, prevent an infinte loop
123 // from occuring.
124 if (inside_as_value_into_) {
125 dict->SetString("observer", "<loop detected>");
126 return;
129 if (observer_) {
130 base::AutoReset<bool> prevent_loops(
131 const_cast<bool*>(&inside_as_value_into_), true);
132 dict->BeginDictionary("observer");
133 observer_->AsValueInto(dict);
134 dict->EndDictionary();
135 } else {
136 dict->SetString("observer", "NULL");
138 dict->SetBoolean("needs_begin_frames", NeedsBeginFrames());
141 // BackToBackBeginFrameSourceMixIn --------------------------------------------
142 scoped_ptr<BackToBackBeginFrameSource> BackToBackBeginFrameSource::Create(
143 base::SingleThreadTaskRunner* task_runner) {
144 return make_scoped_ptr(new BackToBackBeginFrameSource(task_runner));
147 BackToBackBeginFrameSource::BackToBackBeginFrameSource(
148 base::SingleThreadTaskRunner* task_runner)
149 : BeginFrameSourceMixIn(),
150 task_runner_(task_runner),
151 send_begin_frame_posted_(false),
152 weak_factory_(this) {
153 DCHECK(task_runner);
154 DCHECK_EQ(needs_begin_frames_, false);
155 DCHECK_EQ(send_begin_frame_posted_, false);
158 BackToBackBeginFrameSource::~BackToBackBeginFrameSource() {
161 base::TimeTicks BackToBackBeginFrameSource::Now() {
162 return gfx::FrameTime::Now();
165 void BackToBackBeginFrameSource::OnNeedsBeginFramesChange(
166 bool needs_begin_frames) {
167 if (!needs_begin_frames)
168 return;
170 if (send_begin_frame_posted_)
171 return;
173 send_begin_frame_posted_ = true;
174 task_runner_->PostTask(FROM_HERE,
175 base::Bind(&BackToBackBeginFrameSource::BeginFrame,
176 weak_factory_.GetWeakPtr()));
179 void BackToBackBeginFrameSource::BeginFrame() {
180 send_begin_frame_posted_ = false;
182 if (!needs_begin_frames_)
183 return;
185 base::TimeTicks now = Now();
186 BeginFrameArgs args = BeginFrameArgs::Create(
187 BEGINFRAME_FROM_HERE, now, now + BeginFrameArgs::DefaultInterval(),
188 BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL);
189 CallOnBeginFrame(args);
192 // BeginFrameSource support
194 void BackToBackBeginFrameSource::DidFinishFrame(size_t remaining_frames) {
195 if (remaining_frames == 0) {
196 OnNeedsBeginFramesChange(NeedsBeginFrames());
200 // Tracing support
201 void BackToBackBeginFrameSource::AsValueInto(
202 base::trace_event::TracedValue* dict) const {
203 dict->SetString("type", "BackToBackBeginFrameSource");
204 BeginFrameSourceMixIn::AsValueInto(dict);
205 dict->SetBoolean("send_begin_frame_posted_", send_begin_frame_posted_);
208 // SyntheticBeginFrameSource ---------------------------------------------
209 scoped_ptr<SyntheticBeginFrameSource> SyntheticBeginFrameSource::Create(
210 base::SingleThreadTaskRunner* task_runner,
211 base::TimeTicks initial_vsync_timebase,
212 base::TimeDelta initial_vsync_interval) {
213 scoped_refptr<DelayBasedTimeSource> time_source;
214 if (gfx::FrameTime::TimestampsAreHighRes()) {
215 time_source = DelayBasedTimeSourceHighRes::Create(initial_vsync_interval,
216 task_runner);
217 } else {
218 time_source =
219 DelayBasedTimeSource::Create(initial_vsync_interval, task_runner);
222 return make_scoped_ptr(new SyntheticBeginFrameSource(time_source));
225 SyntheticBeginFrameSource::SyntheticBeginFrameSource(
226 scoped_refptr<DelayBasedTimeSource> time_source)
227 : BeginFrameSourceMixIn(), time_source_(time_source) {
228 time_source_->SetActive(false);
229 time_source_->SetClient(this);
232 SyntheticBeginFrameSource::~SyntheticBeginFrameSource() {
233 if (NeedsBeginFrames())
234 time_source_->SetActive(false);
237 void SyntheticBeginFrameSource::OnUpdateVSyncParameters(
238 base::TimeTicks new_vsync_timebase,
239 base::TimeDelta new_vsync_interval) {
240 time_source_->SetTimebaseAndInterval(new_vsync_timebase, new_vsync_interval);
243 BeginFrameArgs SyntheticBeginFrameSource::CreateBeginFrameArgs(
244 base::TimeTicks frame_time,
245 BeginFrameArgs::BeginFrameArgsType type) {
246 base::TimeTicks deadline = time_source_->NextTickTime();
247 return BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, deadline,
248 time_source_->Interval(), type);
251 // TimeSourceClient support
252 void SyntheticBeginFrameSource::OnTimerTick() {
253 CallOnBeginFrame(CreateBeginFrameArgs(time_source_->LastTickTime(),
254 BeginFrameArgs::NORMAL));
257 // BeginFrameSourceMixIn support
258 void SyntheticBeginFrameSource::OnNeedsBeginFramesChange(
259 bool needs_begin_frames) {
260 base::TimeTicks missed_tick_time =
261 time_source_->SetActive(needs_begin_frames);
262 if (!missed_tick_time.is_null()) {
263 CallOnBeginFrame(
264 CreateBeginFrameArgs(missed_tick_time, BeginFrameArgs::MISSED));
268 // Tracing support
269 void SyntheticBeginFrameSource::AsValueInto(
270 base::trace_event::TracedValue* dict) const {
271 dict->SetString("type", "SyntheticBeginFrameSource");
272 BeginFrameSourceMixIn::AsValueInto(dict);
274 dict->BeginDictionary("time_source");
275 time_source_->AsValueInto(dict);
276 dict->EndDictionary();
279 // BeginFrameSourceMultiplexer -------------------------------------------
280 scoped_ptr<BeginFrameSourceMultiplexer> BeginFrameSourceMultiplexer::Create() {
281 return make_scoped_ptr(new BeginFrameSourceMultiplexer());
284 BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer()
285 : BeginFrameSourceMixIn(),
286 minimum_interval_(base::TimeDelta()),
287 active_source_(NULL),
288 source_list_() {
291 BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer(
292 base::TimeDelta minimum_interval)
293 : BeginFrameSourceMixIn(),
294 minimum_interval_(minimum_interval),
295 active_source_(NULL),
296 source_list_() {
299 BeginFrameSourceMultiplexer::~BeginFrameSourceMultiplexer() {
302 void BeginFrameSourceMultiplexer::SetMinimumInterval(
303 base::TimeDelta new_minimum_interval) {
304 DEBUG_FRAMES("BeginFrameSourceMultiplexer::SetMinimumInterval",
305 "current minimum (us)",
306 minimum_interval_.InMicroseconds(),
307 "new minimum (us)",
308 new_minimum_interval.InMicroseconds());
309 DCHECK_GE(new_minimum_interval.ToInternalValue(), 0);
310 minimum_interval_ = new_minimum_interval;
313 void BeginFrameSourceMultiplexer::AddSource(BeginFrameSource* new_source) {
314 DEBUG_FRAMES("BeginFrameSourceMultiplexer::AddSource", "current active",
315 active_source_, "source to be added", new_source);
316 DCHECK(new_source);
317 DCHECK(!HasSource(new_source));
319 source_list_.insert(new_source);
321 // If there is no active source, set the new one as the active one.
322 if (!active_source_)
323 SetActiveSource(new_source);
326 void BeginFrameSourceMultiplexer::RemoveSource(
327 BeginFrameSource* existing_source) {
328 DEBUG_FRAMES("BeginFrameSourceMultiplexer::RemoveSource", "current active",
329 active_source_, "source to be removed", existing_source);
330 DCHECK(existing_source);
331 DCHECK(HasSource(existing_source));
332 DCHECK_NE(existing_source, active_source_);
333 source_list_.erase(existing_source);
336 void BeginFrameSourceMultiplexer::SetActiveSource(
337 BeginFrameSource* new_source) {
338 DEBUG_FRAMES("BeginFrameSourceMultiplexer::SetActiveSource",
339 "current active",
340 active_source_,
341 "to become active",
342 new_source);
344 DCHECK(HasSource(new_source) || new_source == NULL);
346 bool needs_begin_frames = NeedsBeginFrames();
347 if (active_source_) {
348 if (needs_begin_frames)
349 SetNeedsBeginFrames(false);
351 // Technically we shouldn't need to remove observation, but this prevents
352 // the case where SetNeedsBeginFrames message gets to the source after a
353 // message has already been sent.
354 active_source_->RemoveObserver(this);
355 active_source_ = NULL;
357 DCHECK(!active_source_);
358 active_source_ = new_source;
360 if (active_source_) {
361 active_source_->AddObserver(this);
363 if (needs_begin_frames) {
364 SetNeedsBeginFrames(true);
369 const BeginFrameSource* BeginFrameSourceMultiplexer::ActiveSource() {
370 return active_source_;
373 // BeginFrameObserver support
374 void BeginFrameSourceMultiplexer::OnBeginFrame(const BeginFrameArgs& args) {
375 if (!IsIncreasing(args)) {
376 DEBUG_FRAMES("BeginFrameSourceMultiplexer::OnBeginFrame",
377 "action",
378 "discarding",
379 "new args",
380 args.AsValue());
381 return;
383 DEBUG_FRAMES("BeginFrameSourceMultiplexer::OnBeginFrame",
384 "action",
385 "using",
386 "new args",
387 args.AsValue());
388 CallOnBeginFrame(args);
391 const BeginFrameArgs BeginFrameSourceMultiplexer::LastUsedBeginFrameArgs()
392 const {
393 if (observer_)
394 return observer_->LastUsedBeginFrameArgs();
395 else
396 return BeginFrameArgs();
399 // BeginFrameSource support
400 void BeginFrameSourceMultiplexer::OnNeedsBeginFramesChange(
401 bool needs_begin_frames) {
402 DEBUG_FRAMES("BeginFrameSourceMultiplexer::OnNeedsBeginFramesChange",
403 "active_source", active_source_, "needs_begin_frames",
404 needs_begin_frames);
405 if (active_source_) {
406 active_source_->SetNeedsBeginFrames(needs_begin_frames);
407 } else {
408 DCHECK(!needs_begin_frames);
412 void BeginFrameSourceMultiplexer::DidFinishFrame(size_t remaining_frames) {
413 DEBUG_FRAMES("BeginFrameSourceMultiplexer::DidFinishFrame",
414 "active_source",
415 active_source_,
416 "remaining_frames",
417 remaining_frames);
418 if (active_source_) {
419 active_source_->DidFinishFrame(remaining_frames);
423 // Tracing support
424 void BeginFrameSourceMultiplexer::AsValueInto(
425 base::trace_event::TracedValue* dict) const {
426 dict->SetString("type", "BeginFrameSourceMultiplexer");
428 dict->SetInteger("minimum_interval_us", minimum_interval_.InMicroseconds());
429 if (observer_) {
430 dict->BeginDictionary("last_begin_frame_args");
431 observer_->LastUsedBeginFrameArgs().AsValueInto(dict);
432 dict->EndDictionary();
435 if (active_source_) {
436 dict->BeginDictionary("active_source");
437 active_source_->AsValueInto(dict);
438 dict->EndDictionary();
439 } else {
440 dict->SetString("active_source", "NULL");
443 dict->BeginArray("sources");
444 for (std::set<BeginFrameSource*>::const_iterator it = source_list_.begin();
445 it != source_list_.end();
446 ++it) {
447 dict->BeginDictionary();
448 (*it)->AsValueInto(dict);
449 dict->EndDictionary();
451 dict->EndArray();
454 // protected methods
455 bool BeginFrameSourceMultiplexer::HasSource(BeginFrameSource* source) {
456 return (source_list_.find(source) != source_list_.end());
459 bool BeginFrameSourceMultiplexer::IsIncreasing(const BeginFrameArgs& args) {
460 DCHECK(args.IsValid());
461 if (!observer_)
462 return false;
464 // If the last begin frame is invalid, then any new begin frame is valid.
465 if (!observer_->LastUsedBeginFrameArgs().IsValid())
466 return true;
468 // Only allow new args have a *strictly bigger* frame_time value and statisfy
469 // minimum interval requirement.
470 return (args.frame_time >=
471 observer_->LastUsedBeginFrameArgs().frame_time + minimum_interval_);
474 } // namespace cc