ChromeVox should only intercept 'tab' key if nothing has focus.
[chromium-blink-merge.git] / cc / scheduler / begin_frame_source.cc
blob8ef3b6798bbbb7cd04d76b48ce4da3c2635bb4c4
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/debug/trace_event.h"
9 #include "base/debug/trace_event_argument.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/strings/string_number_conversions.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::debug::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(base::debug::TracedValue* dict) const {
121 // As the observer might try to trace the source, prevent an infinte loop
122 // from occuring.
123 if (inside_as_value_into_) {
124 dict->SetString("observer", "<loop detected>");
125 return;
128 if (observer_) {
129 base::AutoReset<bool> prevent_loops(
130 const_cast<bool*>(&inside_as_value_into_), true);
131 dict->BeginDictionary("observer");
132 observer_->AsValueInto(dict);
133 dict->EndDictionary();
134 } else {
135 dict->SetString("observer", "NULL");
137 dict->SetBoolean("needs_begin_frames", NeedsBeginFrames());
140 // BackToBackBeginFrameSourceMixIn --------------------------------------------
141 scoped_ptr<BackToBackBeginFrameSource> BackToBackBeginFrameSource::Create(
142 base::SingleThreadTaskRunner* task_runner) {
143 return make_scoped_ptr(new BackToBackBeginFrameSource(task_runner));
146 BackToBackBeginFrameSource::BackToBackBeginFrameSource(
147 base::SingleThreadTaskRunner* task_runner)
148 : BeginFrameSourceMixIn(),
149 task_runner_(task_runner),
150 send_begin_frame_posted_(false),
151 weak_factory_(this) {
152 DCHECK(task_runner);
153 DCHECK_EQ(needs_begin_frames_, false);
154 DCHECK_EQ(send_begin_frame_posted_, false);
157 BackToBackBeginFrameSource::~BackToBackBeginFrameSource() {
160 base::TimeTicks BackToBackBeginFrameSource::Now() {
161 return gfx::FrameTime::Now();
164 void BackToBackBeginFrameSource::OnNeedsBeginFramesChange(
165 bool needs_begin_frames) {
166 if (!needs_begin_frames)
167 return;
169 if (send_begin_frame_posted_)
170 return;
172 send_begin_frame_posted_ = true;
173 task_runner_->PostTask(FROM_HERE,
174 base::Bind(&BackToBackBeginFrameSource::BeginFrame,
175 weak_factory_.GetWeakPtr()));
178 void BackToBackBeginFrameSource::BeginFrame() {
179 send_begin_frame_posted_ = false;
181 if (!needs_begin_frames_)
182 return;
184 base::TimeTicks now = Now();
185 BeginFrameArgs args = BeginFrameArgs::Create(
186 BEGINFRAME_FROM_HERE, now, now + BeginFrameArgs::DefaultInterval(),
187 BeginFrameArgs::DefaultInterval(), BeginFrameArgs::NORMAL);
188 CallOnBeginFrame(args);
191 // BeginFrameSource support
193 void BackToBackBeginFrameSource::DidFinishFrame(size_t remaining_frames) {
194 if (remaining_frames == 0) {
195 OnNeedsBeginFramesChange(NeedsBeginFrames());
199 // Tracing support
200 void BackToBackBeginFrameSource::AsValueInto(
201 base::debug::TracedValue* dict) const {
202 dict->SetString("type", "BackToBackBeginFrameSource");
203 BeginFrameSourceMixIn::AsValueInto(dict);
204 dict->SetBoolean("send_begin_frame_posted_", send_begin_frame_posted_);
207 // SyntheticBeginFrameSource ---------------------------------------------
208 scoped_ptr<SyntheticBeginFrameSource> SyntheticBeginFrameSource::Create(
209 base::SingleThreadTaskRunner* task_runner,
210 base::TimeTicks initial_vsync_timebase,
211 base::TimeDelta initial_vsync_interval) {
212 scoped_refptr<DelayBasedTimeSource> time_source;
213 if (gfx::FrameTime::TimestampsAreHighRes()) {
214 time_source = DelayBasedTimeSourceHighRes::Create(initial_vsync_interval,
215 task_runner);
216 } else {
217 time_source =
218 DelayBasedTimeSource::Create(initial_vsync_interval, task_runner);
221 return make_scoped_ptr(new SyntheticBeginFrameSource(time_source));
224 SyntheticBeginFrameSource::SyntheticBeginFrameSource(
225 scoped_refptr<DelayBasedTimeSource> time_source)
226 : BeginFrameSourceMixIn(), time_source_(time_source) {
227 time_source_->SetActive(false);
228 time_source_->SetClient(this);
231 SyntheticBeginFrameSource::~SyntheticBeginFrameSource() {
232 if (NeedsBeginFrames())
233 time_source_->SetActive(false);
236 void SyntheticBeginFrameSource::OnUpdateVSyncParameters(
237 base::TimeTicks new_vsync_timebase,
238 base::TimeDelta new_vsync_interval) {
239 time_source_->SetTimebaseAndInterval(new_vsync_timebase, new_vsync_interval);
242 BeginFrameArgs SyntheticBeginFrameSource::CreateBeginFrameArgs(
243 base::TimeTicks frame_time,
244 BeginFrameArgs::BeginFrameArgsType type) {
245 base::TimeTicks deadline = time_source_->NextTickTime();
246 return BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, deadline,
247 time_source_->Interval(), type);
250 // TimeSourceClient support
251 void SyntheticBeginFrameSource::OnTimerTick() {
252 CallOnBeginFrame(CreateBeginFrameArgs(time_source_->LastTickTime(),
253 BeginFrameArgs::NORMAL));
256 // BeginFrameSourceMixIn support
257 void SyntheticBeginFrameSource::OnNeedsBeginFramesChange(
258 bool needs_begin_frames) {
259 base::TimeTicks missed_tick_time =
260 time_source_->SetActive(needs_begin_frames);
261 if (!missed_tick_time.is_null()) {
262 CallOnBeginFrame(
263 CreateBeginFrameArgs(missed_tick_time, BeginFrameArgs::MISSED));
267 bool SyntheticBeginFrameSource::NeedsBeginFrames() const {
268 return time_source_->Active();
271 // Tracing support
272 void SyntheticBeginFrameSource::AsValueInto(
273 base::debug::TracedValue* dict) const {
274 dict->SetString("type", "SyntheticBeginFrameSource");
275 BeginFrameSourceMixIn::AsValueInto(dict);
277 dict->BeginDictionary("time_source");
278 time_source_->AsValueInto(dict);
279 dict->EndDictionary();
282 // BeginFrameSourceMultiplexer -------------------------------------------
283 scoped_ptr<BeginFrameSourceMultiplexer> BeginFrameSourceMultiplexer::Create() {
284 return make_scoped_ptr(new BeginFrameSourceMultiplexer());
287 BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer()
288 : BeginFrameSourceMixIn(),
289 minimum_interval_(base::TimeDelta()),
290 active_source_(NULL),
291 source_list_() {
294 BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer(
295 base::TimeDelta minimum_interval)
296 : BeginFrameSourceMixIn(),
297 minimum_interval_(minimum_interval),
298 active_source_(NULL),
299 source_list_() {
302 BeginFrameSourceMultiplexer::~BeginFrameSourceMultiplexer() {
305 void BeginFrameSourceMultiplexer::SetMinimumInterval(
306 base::TimeDelta new_minimum_interval) {
307 DEBUG_FRAMES("BeginFrameSourceMultiplexer::SetMinimumInterval",
308 "current minimum (us)",
309 minimum_interval_.InMicroseconds(),
310 "new minimum (us)",
311 new_minimum_interval.InMicroseconds());
312 DCHECK_GE(new_minimum_interval.ToInternalValue(), 0);
313 minimum_interval_ = new_minimum_interval;
316 void BeginFrameSourceMultiplexer::AddSource(BeginFrameSource* new_source) {
317 DEBUG_FRAMES("BeginFrameSourceMultiplexer::AddSource",
318 "current active",
319 active_source_,
320 "source to remove",
321 new_source);
322 DCHECK(new_source);
323 DCHECK(!HasSource(new_source));
325 source_list_.insert(new_source);
327 // If there is no active source, set the new one as the active one.
328 if (!active_source_)
329 SetActiveSource(new_source);
332 void BeginFrameSourceMultiplexer::RemoveSource(
333 BeginFrameSource* existing_source) {
334 DEBUG_FRAMES("BeginFrameSourceMultiplexer::RemoveSource",
335 "current active",
336 active_source_,
337 "source to remove",
338 existing_source);
339 DCHECK(existing_source);
340 DCHECK(HasSource(existing_source));
341 DCHECK_NE(existing_source, active_source_);
342 source_list_.erase(existing_source);
345 void BeginFrameSourceMultiplexer::SetActiveSource(
346 BeginFrameSource* new_source) {
347 DEBUG_FRAMES("BeginFrameSourceMultiplexer::SetActiveSource",
348 "current active",
349 active_source_,
350 "to become active",
351 new_source);
353 DCHECK(HasSource(new_source) || new_source == NULL);
355 bool needs_begin_frames = NeedsBeginFrames();
356 if (active_source_) {
357 if (needs_begin_frames)
358 SetNeedsBeginFrames(false);
360 // Technically we shouldn't need to remove observation, but this prevents
361 // the case where SetNeedsBeginFrames message gets to the source after a
362 // message has already been sent.
363 active_source_->RemoveObserver(this);
364 active_source_ = NULL;
366 DCHECK(!active_source_);
367 active_source_ = new_source;
369 if (active_source_) {
370 active_source_->AddObserver(this);
372 if (needs_begin_frames) {
373 SetNeedsBeginFrames(true);
378 const BeginFrameSource* BeginFrameSourceMultiplexer::ActiveSource() {
379 return active_source_;
382 // BeginFrameObserver support
383 void BeginFrameSourceMultiplexer::OnBeginFrame(const BeginFrameArgs& args) {
384 if (!IsIncreasing(args)) {
385 DEBUG_FRAMES("BeginFrameSourceMultiplexer::OnBeginFrame",
386 "action",
387 "discarding",
388 "new args",
389 args.AsValue());
390 return;
392 DEBUG_FRAMES("BeginFrameSourceMultiplexer::OnBeginFrame",
393 "action",
394 "using",
395 "new args",
396 args.AsValue());
397 CallOnBeginFrame(args);
400 const BeginFrameArgs BeginFrameSourceMultiplexer::LastUsedBeginFrameArgs()
401 const {
402 if (observer_)
403 return observer_->LastUsedBeginFrameArgs();
404 else
405 return BeginFrameArgs();
408 // BeginFrameSource support
409 bool BeginFrameSourceMultiplexer::NeedsBeginFrames() const {
410 if (active_source_) {
411 return active_source_->NeedsBeginFrames();
412 } else {
413 return false;
417 void BeginFrameSourceMultiplexer::SetNeedsBeginFrames(bool needs_begin_frames) {
418 DEBUG_FRAMES("BeginFrameSourceMultiplexer::SetNeedsBeginFrames",
419 "active_source",
420 active_source_,
421 "needs_begin_frames",
422 needs_begin_frames);
423 if (active_source_) {
424 active_source_->SetNeedsBeginFrames(needs_begin_frames);
425 } else {
426 DCHECK(!needs_begin_frames);
430 void BeginFrameSourceMultiplexer::DidFinishFrame(size_t remaining_frames) {
431 DEBUG_FRAMES("BeginFrameSourceMultiplexer::DidFinishFrame",
432 "active_source",
433 active_source_,
434 "remaining_frames",
435 remaining_frames);
436 if (active_source_) {
437 active_source_->DidFinishFrame(remaining_frames);
441 // Tracing support
442 void BeginFrameSourceMultiplexer::AsValueInto(
443 base::debug::TracedValue* dict) const {
444 dict->SetString("type", "BeginFrameSourceMultiplexer");
446 dict->SetInteger("minimum_interval_us", minimum_interval_.InMicroseconds());
447 if (observer_) {
448 dict->BeginDictionary("last_begin_frame_args");
449 observer_->LastUsedBeginFrameArgs().AsValueInto(dict);
450 dict->EndDictionary();
453 if (active_source_) {
454 dict->BeginDictionary("active_source");
455 active_source_->AsValueInto(dict);
456 dict->EndDictionary();
457 } else {
458 dict->SetString("active_source", "NULL");
461 dict->BeginArray("sources");
462 for (std::set<BeginFrameSource*>::const_iterator it = source_list_.begin();
463 it != source_list_.end();
464 ++it) {
465 dict->BeginDictionary();
466 (*it)->AsValueInto(dict);
467 dict->EndDictionary();
469 dict->EndArray();
472 // protected methods
473 bool BeginFrameSourceMultiplexer::HasSource(BeginFrameSource* source) {
474 return (source_list_.find(source) != source_list_.end());
477 bool BeginFrameSourceMultiplexer::IsIncreasing(const BeginFrameArgs& args) {
478 DCHECK(args.IsValid());
479 if (!observer_)
480 return false;
482 // If the last begin frame is invalid, then any new begin frame is valid.
483 if (!observer_->LastUsedBeginFrameArgs().IsValid())
484 return true;
486 // Only allow new args have a *strictly bigger* frame_time value and statisfy
487 // minimum interval requirement.
488 return (args.frame_time >=
489 observer_->LastUsedBeginFrameArgs().frame_time + minimum_interval_);
492 } // namespace cc