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"
18 #define DEBUG_FRAMES(...)
20 #define DEBUG_FRAMES(name, arg1_name, arg1_val, arg2_name, arg2_val) \
21 TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"), \
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",
42 last_begin_frame_args_
.AsValue(),
45 DCHECK(args
.IsValid());
46 DCHECK(args
.frame_time
>= last_begin_frame_args_
.frame_time
);
47 bool used
= OnBeginFrameMixInDelegate(args
);
49 last_begin_frame_args_
= args
;
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()
66 needs_begin_frames_(false),
67 inside_as_value_into_(false) {
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",
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",
98 void BeginFrameSourceMixIn::RemoveObserver(BeginFrameObserver
* obs
) {
99 DEBUG_FRAMES("BeginFrameSourceMixIn::RemoveObserver",
102 "to remove observer",
104 DCHECK_EQ(observer_
, obs
);
108 void BeginFrameSourceMixIn::CallOnBeginFrame(const BeginFrameArgs
& args
) {
109 DEBUG_FRAMES("BeginFrameSourceMixIn::CallOnBeginFrame",
115 return observer_
->OnBeginFrame(args
);
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
124 if (inside_as_value_into_
) {
125 dict
->SetString("observer", "<loop detected>");
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();
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) {
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
)
170 if (send_begin_frame_posted_
)
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_
)
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());
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
,
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()) {
264 CreateBeginFrameArgs(missed_tick_time
, BeginFrameArgs::MISSED
));
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
),
291 BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer(
292 base::TimeDelta minimum_interval
)
293 : BeginFrameSourceMixIn(),
294 minimum_interval_(minimum_interval
),
295 active_source_(NULL
),
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(),
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
);
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.
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",
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",
383 DEBUG_FRAMES("BeginFrameSourceMultiplexer::OnBeginFrame",
388 CallOnBeginFrame(args
);
391 const BeginFrameArgs
BeginFrameSourceMultiplexer::LastUsedBeginFrameArgs()
394 return observer_
->LastUsedBeginFrameArgs();
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",
405 if (active_source_
) {
406 active_source_
->SetNeedsBeginFrames(needs_begin_frames
);
408 DCHECK(!needs_begin_frames
);
412 void BeginFrameSourceMultiplexer::DidFinishFrame(size_t remaining_frames
) {
413 DEBUG_FRAMES("BeginFrameSourceMultiplexer::DidFinishFrame",
418 if (active_source_
) {
419 active_source_
->DidFinishFrame(remaining_frames
);
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());
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();
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();
447 dict
->BeginDictionary();
448 (*it
)->AsValueInto(dict
);
449 dict
->EndDictionary();
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());
464 // If the last begin frame is invalid, then any new begin frame is valid.
465 if (!observer_
->LastUsedBeginFrameArgs().IsValid())
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_
);