Fix dcheck in message port code on Mandoline shutdown.
[chromium-blink-merge.git] / cc / scheduler / begin_frame_source.cc
blobd9cadc83e726f7ceaca6fb32298c279b18c1ccb5
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"
16 #ifdef NDEBUG
17 #define DEBUG_FRAMES(...)
18 #else
19 #define DEBUG_FRAMES(name, arg1_name, arg1_val, arg2_name, arg2_val) \
20 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"), \
21 name, \
22 arg1_name, \
23 arg1_val, \
24 arg2_name, \
25 arg2_val);
26 #endif
28 namespace cc {
30 // BeginFrameObserverBase -----------------------------------------------
31 BeginFrameObserverBase::BeginFrameObserverBase()
32 : last_begin_frame_args_(), dropped_begin_frame_args_(0) {
35 const BeginFrameArgs BeginFrameObserverBase::LastUsedBeginFrameArgs() const {
36 return last_begin_frame_args_;
38 void BeginFrameObserverBase::OnBeginFrame(const BeginFrameArgs& args) {
39 DEBUG_FRAMES("BeginFrameObserverBase::OnBeginFrame",
40 "last args",
41 last_begin_frame_args_.AsValue(),
42 "new args",
43 args.AsValue());
44 DCHECK(args.IsValid());
45 DCHECK(args.frame_time >= last_begin_frame_args_.frame_time);
46 bool used = OnBeginFrameDerivedImpl(args);
47 if (used) {
48 last_begin_frame_args_ = args;
49 } else {
50 ++dropped_begin_frame_args_;
54 void BeginFrameObserverBase::AsValueInto(
55 base::trace_event::TracedValue* dict) const {
56 dict->BeginDictionary("last_begin_frame_args_");
57 last_begin_frame_args_.AsValueInto(dict);
58 dict->EndDictionary();
59 dict->SetInteger("dropped_begin_frame_args_", dropped_begin_frame_args_);
62 // BeginFrameSourceBase ------------------------------------------------------
63 BeginFrameSourceBase::BeginFrameSourceBase()
64 : observer_(NULL),
65 needs_begin_frames_(false),
66 inside_as_value_into_(false) {
67 DCHECK(!observer_);
68 DCHECK_EQ(inside_as_value_into_, false);
71 bool BeginFrameSourceBase::NeedsBeginFrames() const {
72 return needs_begin_frames_;
75 void BeginFrameSourceBase::SetNeedsBeginFrames(bool needs_begin_frames) {
76 DEBUG_FRAMES("BeginFrameSourceBase::SetNeedsBeginFrames",
77 "current state",
78 needs_begin_frames_,
79 "new state",
80 needs_begin_frames);
81 if (needs_begin_frames_ != needs_begin_frames) {
82 needs_begin_frames_ = needs_begin_frames;
83 OnNeedsBeginFramesChange(needs_begin_frames);
87 void BeginFrameSourceBase::AddObserver(BeginFrameObserver* obs) {
88 DEBUG_FRAMES("BeginFrameSourceBase::AddObserver",
89 "current observer",
90 observer_,
91 "to add observer",
92 obs);
93 DCHECK(!observer_);
94 observer_ = obs;
97 void BeginFrameSourceBase::RemoveObserver(BeginFrameObserver* obs) {
98 DEBUG_FRAMES("BeginFrameSourceBase::RemoveObserver",
99 "current observer",
100 observer_,
101 "to remove observer",
102 obs);
103 DCHECK_EQ(observer_, obs);
104 observer_ = NULL;
107 void BeginFrameSourceBase::CallOnBeginFrame(const BeginFrameArgs& args) {
108 DEBUG_FRAMES("BeginFrameSourceBase::CallOnBeginFrame",
109 "current observer",
110 observer_,
111 "args",
112 args.AsValue());
113 if (observer_) {
114 return observer_->OnBeginFrame(args);
118 // Tracing support
119 void BeginFrameSourceBase::AsValueInto(
120 base::trace_event::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 // BackToBackBeginFrameSource --------------------------------------------
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 : BeginFrameSourceBase(),
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 base::TimeTicks::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::trace_event::TracedValue* dict) const {
202 dict->SetString("type", "BackToBackBeginFrameSource");
203 BeginFrameSourceBase::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::TimeDelta initial_vsync_interval) {
211 scoped_ptr<DelayBasedTimeSource> time_source =
212 DelayBasedTimeSource::Create(initial_vsync_interval, task_runner);
213 return make_scoped_ptr(new SyntheticBeginFrameSource(time_source.Pass()));
216 SyntheticBeginFrameSource::SyntheticBeginFrameSource(
217 scoped_ptr<DelayBasedTimeSource> time_source)
218 : BeginFrameSourceBase(), time_source_(time_source.Pass()) {
219 time_source_->SetActive(false);
220 time_source_->SetClient(this);
223 SyntheticBeginFrameSource::~SyntheticBeginFrameSource() {
224 time_source_->SetActive(false);
227 void SyntheticBeginFrameSource::OnUpdateVSyncParameters(
228 base::TimeTicks new_vsync_timebase,
229 base::TimeDelta new_vsync_interval) {
230 time_source_->SetTimebaseAndInterval(new_vsync_timebase, new_vsync_interval);
233 BeginFrameArgs SyntheticBeginFrameSource::CreateBeginFrameArgs(
234 base::TimeTicks frame_time,
235 BeginFrameArgs::BeginFrameArgsType type) {
236 base::TimeTicks deadline = time_source_->NextTickTime();
237 return BeginFrameArgs::Create(BEGINFRAME_FROM_HERE, frame_time, deadline,
238 time_source_->Interval(), type);
241 // DelayBasedTimeSourceClient support
242 void SyntheticBeginFrameSource::OnTimerTick() {
243 CallOnBeginFrame(CreateBeginFrameArgs(time_source_->LastTickTime(),
244 BeginFrameArgs::NORMAL));
247 // BeginFrameSourceBase support
248 void SyntheticBeginFrameSource::OnNeedsBeginFramesChange(
249 bool needs_begin_frames) {
250 base::TimeTicks missed_tick_time =
251 time_source_->SetActive(needs_begin_frames);
252 if (!missed_tick_time.is_null()) {
253 DCHECK(needs_begin_frames);
254 CallOnBeginFrame(
255 CreateBeginFrameArgs(missed_tick_time, BeginFrameArgs::MISSED));
259 // Tracing support
260 void SyntheticBeginFrameSource::AsValueInto(
261 base::trace_event::TracedValue* dict) const {
262 dict->SetString("type", "SyntheticBeginFrameSource");
263 BeginFrameSourceBase::AsValueInto(dict);
265 dict->BeginDictionary("time_source");
266 time_source_->AsValueInto(dict);
267 dict->EndDictionary();
270 // BeginFrameSourceMultiplexer -------------------------------------------
271 scoped_ptr<BeginFrameSourceMultiplexer> BeginFrameSourceMultiplexer::Create() {
272 return make_scoped_ptr(new BeginFrameSourceMultiplexer());
275 BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer()
276 : BeginFrameSourceBase(),
277 minimum_interval_(base::TimeDelta()),
278 active_source_(NULL),
279 source_list_() {
282 BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer(
283 base::TimeDelta minimum_interval)
284 : BeginFrameSourceBase(),
285 minimum_interval_(minimum_interval),
286 active_source_(NULL),
287 source_list_() {
290 BeginFrameSourceMultiplexer::~BeginFrameSourceMultiplexer() {
291 if (active_source_) {
292 active_source_->SetNeedsBeginFrames(false);
293 active_source_->RemoveObserver(this);
297 void BeginFrameSourceMultiplexer::SetMinimumInterval(
298 base::TimeDelta new_minimum_interval) {
299 DEBUG_FRAMES("BeginFrameSourceMultiplexer::SetMinimumInterval",
300 "current minimum (us)",
301 minimum_interval_.InMicroseconds(),
302 "new minimum (us)",
303 new_minimum_interval.InMicroseconds());
304 DCHECK_GE(new_minimum_interval.ToInternalValue(), 0);
305 minimum_interval_ = new_minimum_interval;
308 void BeginFrameSourceMultiplexer::AddSource(BeginFrameSource* new_source) {
309 DEBUG_FRAMES("BeginFrameSourceMultiplexer::AddSource", "current active",
310 active_source_, "source to be added", new_source);
311 DCHECK(new_source);
312 DCHECK(!HasSource(new_source));
314 source_list_.insert(new_source);
316 // If there is no active source, set the new one as the active one.
317 if (!active_source_)
318 SetActiveSource(new_source);
321 void BeginFrameSourceMultiplexer::RemoveSource(
322 BeginFrameSource* existing_source) {
323 DEBUG_FRAMES("BeginFrameSourceMultiplexer::RemoveSource", "current active",
324 active_source_, "source to be removed", existing_source);
325 DCHECK(existing_source);
326 DCHECK(HasSource(existing_source));
327 DCHECK_NE(existing_source, active_source_);
328 source_list_.erase(existing_source);
331 void BeginFrameSourceMultiplexer::SetActiveSource(
332 BeginFrameSource* new_source) {
333 DEBUG_FRAMES("BeginFrameSourceMultiplexer::SetActiveSource",
334 "current active",
335 active_source_,
336 "to become active",
337 new_source);
339 DCHECK(HasSource(new_source) || new_source == NULL);
341 bool needs_begin_frames = NeedsBeginFrames();
342 if (active_source_) {
343 if (needs_begin_frames)
344 SetNeedsBeginFrames(false);
346 // Technically we shouldn't need to remove observation, but this prevents
347 // the case where SetNeedsBeginFrames message gets to the source after a
348 // message has already been sent.
349 active_source_->RemoveObserver(this);
350 active_source_ = NULL;
352 DCHECK(!active_source_);
353 active_source_ = new_source;
355 if (active_source_) {
356 active_source_->AddObserver(this);
358 if (needs_begin_frames) {
359 SetNeedsBeginFrames(true);
364 const BeginFrameSource* BeginFrameSourceMultiplexer::ActiveSource() {
365 return active_source_;
368 // BeginFrameObserver support
369 void BeginFrameSourceMultiplexer::OnBeginFrame(const BeginFrameArgs& args) {
370 if (!IsIncreasing(args)) {
371 DEBUG_FRAMES("BeginFrameSourceMultiplexer::OnBeginFrame",
372 "action",
373 "discarding",
374 "new args",
375 args.AsValue());
376 return;
378 DEBUG_FRAMES("BeginFrameSourceMultiplexer::OnBeginFrame",
379 "action",
380 "using",
381 "new args",
382 args.AsValue());
383 CallOnBeginFrame(args);
386 const BeginFrameArgs BeginFrameSourceMultiplexer::LastUsedBeginFrameArgs()
387 const {
388 if (observer_)
389 return observer_->LastUsedBeginFrameArgs();
390 else
391 return BeginFrameArgs();
394 // BeginFrameSource support
395 void BeginFrameSourceMultiplexer::OnNeedsBeginFramesChange(
396 bool needs_begin_frames) {
397 DEBUG_FRAMES("BeginFrameSourceMultiplexer::OnNeedsBeginFramesChange",
398 "active_source", active_source_, "needs_begin_frames",
399 needs_begin_frames);
400 if (active_source_) {
401 active_source_->SetNeedsBeginFrames(needs_begin_frames);
402 } else {
403 DCHECK(!needs_begin_frames);
407 void BeginFrameSourceMultiplexer::DidFinishFrame(size_t remaining_frames) {
408 DEBUG_FRAMES("BeginFrameSourceMultiplexer::DidFinishFrame",
409 "active_source",
410 active_source_,
411 "remaining_frames",
412 remaining_frames);
413 if (active_source_) {
414 active_source_->DidFinishFrame(remaining_frames);
418 // Tracing support
419 void BeginFrameSourceMultiplexer::AsValueInto(
420 base::trace_event::TracedValue* dict) const {
421 dict->SetString("type", "BeginFrameSourceMultiplexer");
423 dict->SetInteger("minimum_interval_us", minimum_interval_.InMicroseconds());
424 if (observer_) {
425 dict->BeginDictionary("last_begin_frame_args");
426 observer_->LastUsedBeginFrameArgs().AsValueInto(dict);
427 dict->EndDictionary();
430 if (active_source_) {
431 dict->BeginDictionary("active_source");
432 active_source_->AsValueInto(dict);
433 dict->EndDictionary();
434 } else {
435 dict->SetString("active_source", "NULL");
438 dict->BeginArray("sources");
439 for (std::set<BeginFrameSource*>::const_iterator it = source_list_.begin();
440 it != source_list_.end();
441 ++it) {
442 dict->BeginDictionary();
443 (*it)->AsValueInto(dict);
444 dict->EndDictionary();
446 dict->EndArray();
449 // protected methods
450 bool BeginFrameSourceMultiplexer::HasSource(BeginFrameSource* source) {
451 return (source_list_.find(source) != source_list_.end());
454 bool BeginFrameSourceMultiplexer::IsIncreasing(const BeginFrameArgs& args) {
455 DCHECK(args.IsValid());
456 if (!observer_)
457 return false;
459 // If the last begin frame is invalid, then any new begin frame is valid.
460 if (!observer_->LastUsedBeginFrameArgs().IsValid())
461 return true;
463 // Only allow new args have a *strictly bigger* frame_time value and statisfy
464 // minimum interval requirement.
465 return (args.frame_time >=
466 observer_->LastUsedBeginFrameArgs().frame_time + minimum_interval_);
469 } // namespace cc