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/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"
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::debug::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 OnNeedsBeginFramesChange(needs_begin_frames
);
84 needs_begin_frames_
= 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(base::debug::TracedValue
* dict
) const {
120 // As the observer might try to trace the source, prevent an infinte loop
122 if (inside_as_value_into_
) {
123 dict
->SetString("observer", "<loop detected>");
128 base::AutoReset
<bool> prevent_loops(
129 const_cast<bool*>(&inside_as_value_into_
), true);
130 dict
->BeginDictionary("observer");
131 observer_
->AsValueInto(dict
);
132 dict
->EndDictionary();
134 dict
->SetString("observer", "NULL");
136 dict
->SetBoolean("needs_begin_frames", NeedsBeginFrames());
139 // BackToBackBeginFrameSourceMixIn --------------------------------------------
140 scoped_ptr
<BackToBackBeginFrameSource
> BackToBackBeginFrameSource::Create(
141 base::SingleThreadTaskRunner
* task_runner
) {
142 return make_scoped_ptr(new BackToBackBeginFrameSource(task_runner
));
145 BackToBackBeginFrameSource::BackToBackBeginFrameSource(
146 base::SingleThreadTaskRunner
* task_runner
)
147 : BeginFrameSourceMixIn(),
149 task_runner_(task_runner
),
150 send_begin_frame_posted_(false) {
152 DCHECK_EQ(needs_begin_frames_
, false);
153 DCHECK_EQ(send_begin_frame_posted_
, false);
156 BackToBackBeginFrameSource::~BackToBackBeginFrameSource() {
159 base::TimeTicks
BackToBackBeginFrameSource::Now() {
160 return gfx::FrameTime::Now();
163 void BackToBackBeginFrameSource::OnNeedsBeginFramesChange(
164 bool needs_begin_frames
) {
165 if (!needs_begin_frames
)
168 if (send_begin_frame_posted_
)
171 send_begin_frame_posted_
= true;
172 task_runner_
->PostTask(FROM_HERE
,
173 base::Bind(&BackToBackBeginFrameSource::BeginFrame
,
174 weak_factory_
.GetWeakPtr()));
177 void BackToBackBeginFrameSource::BeginFrame() {
178 send_begin_frame_posted_
= false;
180 if (!needs_begin_frames_
)
183 base::TimeTicks now
= Now();
184 BeginFrameArgs args
=
185 BeginFrameArgs::Create(now
,
186 now
+ BeginFrameArgs::DefaultInterval(),
187 BeginFrameArgs::DefaultInterval());
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::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
,
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::CreateTyped(
247 frame_time
, deadline
, 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()) {
263 CreateBeginFrameArgs(missed_tick_time
, BeginFrameArgs::MISSED
));
267 bool SyntheticBeginFrameSource::NeedsBeginFrames() const {
268 return time_source_
->Active();
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
),
294 BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer(
295 base::TimeDelta minimum_interval
)
296 : BeginFrameSourceMixIn(),
297 minimum_interval_(minimum_interval
),
298 active_source_(NULL
),
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(),
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",
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.
329 SetActiveSource(new_source
);
332 void BeginFrameSourceMultiplexer::RemoveSource(
333 BeginFrameSource
* existing_source
) {
334 DEBUG_FRAMES("BeginFrameSourceMultiplexer::RemoveSource",
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",
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",
392 DEBUG_FRAMES("BeginFrameSourceMultiplexer::OnBeginFrame",
397 CallOnBeginFrame(args
);
400 const BeginFrameArgs
BeginFrameSourceMultiplexer::LastUsedBeginFrameArgs()
403 return observer_
->LastUsedBeginFrameArgs();
405 return BeginFrameArgs();
408 // BeginFrameSource support
409 bool BeginFrameSourceMultiplexer::NeedsBeginFrames() const {
410 if (active_source_
) {
411 return active_source_
->NeedsBeginFrames();
417 void BeginFrameSourceMultiplexer::SetNeedsBeginFrames(bool needs_begin_frames
) {
418 DEBUG_FRAMES("BeginFrameSourceMultiplexer::SetNeedsBeginFrames",
421 "needs_begin_frames",
423 if (active_source_
) {
424 active_source_
->SetNeedsBeginFrames(needs_begin_frames
);
426 DCHECK(!needs_begin_frames
);
430 void BeginFrameSourceMultiplexer::DidFinishFrame(size_t remaining_frames
) {
431 DEBUG_FRAMES("BeginFrameSourceMultiplexer::DidFinishFrame",
436 if (active_source_
) {
437 active_source_
->DidFinishFrame(remaining_frames
);
442 void BeginFrameSourceMultiplexer::AsValueInto(
443 base::debug::TracedValue
* dict
) const {
444 dict
->SetString("type", "BeginFrameSourceMultiplexer");
446 dict
->SetInteger("minimum_interval_us", minimum_interval_
.InMicroseconds());
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();
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();
465 dict
->BeginDictionary();
466 (*it
)->AsValueInto(dict
);
467 dict
->EndDictionary();
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());
482 // If the last begin frame is invalid, then any new begin frame is valid.
483 if (!observer_
->LastUsedBeginFrameArgs().IsValid())
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_
);