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"
17 #define DEBUG_FRAMES(...)
19 #define DEBUG_FRAMES(name, arg1_name, arg1_val, arg2_name, arg2_val) \
20 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"), \
30 // BeginFrameObserverMixIn -----------------------------------------------
31 BeginFrameObserverMixIn::BeginFrameObserverMixIn()
32 : last_begin_frame_args_(), dropped_begin_frame_args_(0) {
35 const BeginFrameArgs
BeginFrameObserverMixIn::LastUsedBeginFrameArgs() const {
36 return last_begin_frame_args_
;
38 void BeginFrameObserverMixIn::OnBeginFrame(const BeginFrameArgs
& args
) {
39 DEBUG_FRAMES("BeginFrameObserverMixIn::OnBeginFrame",
41 last_begin_frame_args_
.AsValue(),
44 DCHECK(args
.IsValid());
45 DCHECK(args
.frame_time
>= last_begin_frame_args_
.frame_time
);
46 bool used
= OnBeginFrameMixInDelegate(args
);
48 last_begin_frame_args_
= args
;
50 ++dropped_begin_frame_args_
;
54 void BeginFrameObserverMixIn::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 // BeginFrameSourceMixIn ------------------------------------------------------
63 BeginFrameSourceMixIn::BeginFrameSourceMixIn()
65 needs_begin_frames_(false),
66 inside_as_value_into_(false) {
68 DCHECK_EQ(inside_as_value_into_
, false);
71 bool BeginFrameSourceMixIn::NeedsBeginFrames() const {
72 return needs_begin_frames_
;
75 void BeginFrameSourceMixIn::SetNeedsBeginFrames(bool needs_begin_frames
) {
76 DEBUG_FRAMES("BeginFrameSourceMixIn::SetNeedsBeginFrames",
81 if (needs_begin_frames_
!= needs_begin_frames
) {
82 needs_begin_frames_
= needs_begin_frames
;
83 OnNeedsBeginFramesChange(needs_begin_frames
);
87 void BeginFrameSourceMixIn::AddObserver(BeginFrameObserver
* obs
) {
88 DEBUG_FRAMES("BeginFrameSourceMixIn::AddObserver",
97 void BeginFrameSourceMixIn::RemoveObserver(BeginFrameObserver
* obs
) {
98 DEBUG_FRAMES("BeginFrameSourceMixIn::RemoveObserver",
101 "to remove observer",
103 DCHECK_EQ(observer_
, obs
);
107 void BeginFrameSourceMixIn::CallOnBeginFrame(const BeginFrameArgs
& args
) {
108 DEBUG_FRAMES("BeginFrameSourceMixIn::CallOnBeginFrame",
114 return observer_
->OnBeginFrame(args
);
119 void BeginFrameSourceMixIn::AsValueInto(
120 base::trace_event::TracedValue
* dict
) const {
121 // As the observer might try to trace the source, prevent an infinte loop
123 if (inside_as_value_into_
) {
124 dict
->SetString("observer", "<loop detected>");
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();
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) {
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
)
169 if (send_begin_frame_posted_
)
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_
)
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());
200 void BackToBackBeginFrameSource::AsValueInto(
201 base::trace_event::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
;
214 DelayBasedTimeSource::Create(initial_vsync_interval
, task_runner
);
215 return make_scoped_ptr(new SyntheticBeginFrameSource(time_source
));
218 SyntheticBeginFrameSource::SyntheticBeginFrameSource(
219 scoped_refptr
<DelayBasedTimeSource
> time_source
)
220 : BeginFrameSourceMixIn(), time_source_(time_source
) {
221 time_source_
->SetActive(false);
222 time_source_
->SetClient(this);
225 SyntheticBeginFrameSource::~SyntheticBeginFrameSource() {
226 if (NeedsBeginFrames())
227 time_source_
->SetActive(false);
230 void SyntheticBeginFrameSource::OnUpdateVSyncParameters(
231 base::TimeTicks new_vsync_timebase
,
232 base::TimeDelta new_vsync_interval
) {
233 time_source_
->SetTimebaseAndInterval(new_vsync_timebase
, new_vsync_interval
);
236 BeginFrameArgs
SyntheticBeginFrameSource::CreateBeginFrameArgs(
237 base::TimeTicks frame_time
,
238 BeginFrameArgs::BeginFrameArgsType type
) {
239 base::TimeTicks deadline
= time_source_
->NextTickTime();
240 return BeginFrameArgs::Create(BEGINFRAME_FROM_HERE
, frame_time
, deadline
,
241 time_source_
->Interval(), type
);
244 // TimeSourceClient support
245 void SyntheticBeginFrameSource::OnTimerTick() {
246 CallOnBeginFrame(CreateBeginFrameArgs(time_source_
->LastTickTime(),
247 BeginFrameArgs::NORMAL
));
250 // BeginFrameSourceMixIn support
251 void SyntheticBeginFrameSource::OnNeedsBeginFramesChange(
252 bool needs_begin_frames
) {
253 base::TimeTicks missed_tick_time
=
254 time_source_
->SetActive(needs_begin_frames
);
255 if (!missed_tick_time
.is_null()) {
257 CreateBeginFrameArgs(missed_tick_time
, BeginFrameArgs::MISSED
));
262 void SyntheticBeginFrameSource::AsValueInto(
263 base::trace_event::TracedValue
* dict
) const {
264 dict
->SetString("type", "SyntheticBeginFrameSource");
265 BeginFrameSourceMixIn::AsValueInto(dict
);
267 dict
->BeginDictionary("time_source");
268 time_source_
->AsValueInto(dict
);
269 dict
->EndDictionary();
272 // BeginFrameSourceMultiplexer -------------------------------------------
273 scoped_ptr
<BeginFrameSourceMultiplexer
> BeginFrameSourceMultiplexer::Create() {
274 return make_scoped_ptr(new BeginFrameSourceMultiplexer());
277 BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer()
278 : BeginFrameSourceMixIn(),
279 minimum_interval_(base::TimeDelta()),
280 active_source_(NULL
),
284 BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer(
285 base::TimeDelta minimum_interval
)
286 : BeginFrameSourceMixIn(),
287 minimum_interval_(minimum_interval
),
288 active_source_(NULL
),
292 BeginFrameSourceMultiplexer::~BeginFrameSourceMultiplexer() {
293 if (active_source_
) {
294 active_source_
->SetNeedsBeginFrames(false);
295 active_source_
->RemoveObserver(this);
299 void BeginFrameSourceMultiplexer::SetMinimumInterval(
300 base::TimeDelta new_minimum_interval
) {
301 DEBUG_FRAMES("BeginFrameSourceMultiplexer::SetMinimumInterval",
302 "current minimum (us)",
303 minimum_interval_
.InMicroseconds(),
305 new_minimum_interval
.InMicroseconds());
306 DCHECK_GE(new_minimum_interval
.ToInternalValue(), 0);
307 minimum_interval_
= new_minimum_interval
;
310 void BeginFrameSourceMultiplexer::AddSource(BeginFrameSource
* new_source
) {
311 DEBUG_FRAMES("BeginFrameSourceMultiplexer::AddSource", "current active",
312 active_source_
, "source to be added", new_source
);
314 DCHECK(!HasSource(new_source
));
316 source_list_
.insert(new_source
);
318 // If there is no active source, set the new one as the active one.
320 SetActiveSource(new_source
);
323 void BeginFrameSourceMultiplexer::RemoveSource(
324 BeginFrameSource
* existing_source
) {
325 DEBUG_FRAMES("BeginFrameSourceMultiplexer::RemoveSource", "current active",
326 active_source_
, "source to be removed", existing_source
);
327 DCHECK(existing_source
);
328 DCHECK(HasSource(existing_source
));
329 DCHECK_NE(existing_source
, active_source_
);
330 source_list_
.erase(existing_source
);
333 void BeginFrameSourceMultiplexer::SetActiveSource(
334 BeginFrameSource
* new_source
) {
335 DEBUG_FRAMES("BeginFrameSourceMultiplexer::SetActiveSource",
341 DCHECK(HasSource(new_source
) || new_source
== NULL
);
343 bool needs_begin_frames
= NeedsBeginFrames();
344 if (active_source_
) {
345 if (needs_begin_frames
)
346 SetNeedsBeginFrames(false);
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
;
354 DCHECK(!active_source_
);
355 active_source_
= new_source
;
357 if (active_source_
) {
358 active_source_
->AddObserver(this);
360 if (needs_begin_frames
) {
361 SetNeedsBeginFrames(true);
366 const BeginFrameSource
* BeginFrameSourceMultiplexer::ActiveSource() {
367 return active_source_
;
370 // BeginFrameObserver support
371 void BeginFrameSourceMultiplexer::OnBeginFrame(const BeginFrameArgs
& args
) {
372 if (!IsIncreasing(args
)) {
373 DEBUG_FRAMES("BeginFrameSourceMultiplexer::OnBeginFrame",
380 DEBUG_FRAMES("BeginFrameSourceMultiplexer::OnBeginFrame",
385 CallOnBeginFrame(args
);
388 const BeginFrameArgs
BeginFrameSourceMultiplexer::LastUsedBeginFrameArgs()
391 return observer_
->LastUsedBeginFrameArgs();
393 return BeginFrameArgs();
396 // BeginFrameSource support
397 void BeginFrameSourceMultiplexer::OnNeedsBeginFramesChange(
398 bool needs_begin_frames
) {
399 DEBUG_FRAMES("BeginFrameSourceMultiplexer::OnNeedsBeginFramesChange",
400 "active_source", active_source_
, "needs_begin_frames",
402 if (active_source_
) {
403 active_source_
->SetNeedsBeginFrames(needs_begin_frames
);
405 DCHECK(!needs_begin_frames
);
409 void BeginFrameSourceMultiplexer::DidFinishFrame(size_t remaining_frames
) {
410 DEBUG_FRAMES("BeginFrameSourceMultiplexer::DidFinishFrame",
415 if (active_source_
) {
416 active_source_
->DidFinishFrame(remaining_frames
);
421 void BeginFrameSourceMultiplexer::AsValueInto(
422 base::trace_event::TracedValue
* dict
) const {
423 dict
->SetString("type", "BeginFrameSourceMultiplexer");
425 dict
->SetInteger("minimum_interval_us", minimum_interval_
.InMicroseconds());
427 dict
->BeginDictionary("last_begin_frame_args");
428 observer_
->LastUsedBeginFrameArgs().AsValueInto(dict
);
429 dict
->EndDictionary();
432 if (active_source_
) {
433 dict
->BeginDictionary("active_source");
434 active_source_
->AsValueInto(dict
);
435 dict
->EndDictionary();
437 dict
->SetString("active_source", "NULL");
440 dict
->BeginArray("sources");
441 for (std::set
<BeginFrameSource
*>::const_iterator it
= source_list_
.begin();
442 it
!= source_list_
.end();
444 dict
->BeginDictionary();
445 (*it
)->AsValueInto(dict
);
446 dict
->EndDictionary();
452 bool BeginFrameSourceMultiplexer::HasSource(BeginFrameSource
* source
) {
453 return (source_list_
.find(source
) != source_list_
.end());
456 bool BeginFrameSourceMultiplexer::IsIncreasing(const BeginFrameArgs
& args
) {
457 DCHECK(args
.IsValid());
461 // If the last begin frame is invalid, then any new begin frame is valid.
462 if (!observer_
->LastUsedBeginFrameArgs().IsValid())
465 // Only allow new args have a *strictly bigger* frame_time value and statisfy
466 // minimum interval requirement.
467 return (args
.frame_time
>=
468 observer_
->LastUsedBeginFrameArgs().frame_time
+ minimum_interval_
);