Upstream version 11.40.271.0
[platform/framework/web/crosswalk.git] / src / cc / scheduler / begin_frame_source.cc
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.
4
5 #include "cc/scheduler/begin_frame_source.h"
6
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"
15
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
27
28 namespace cc {
29
30 // BeginFrameObserverMixIn -----------------------------------------------
31 BeginFrameObserverMixIn::BeginFrameObserverMixIn()
32     : last_begin_frame_args_(), dropped_begin_frame_args_(0) {
33 }
34
35 const BeginFrameArgs BeginFrameObserverMixIn::LastUsedBeginFrameArgs() const {
36   return last_begin_frame_args_;
37 }
38 void BeginFrameObserverMixIn::OnBeginFrame(const BeginFrameArgs& args) {
39   DEBUG_FRAMES("BeginFrameObserverMixIn::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 = OnBeginFrameMixInDelegate(args);
47   if (used) {
48     last_begin_frame_args_ = args;
49   } else {
50     ++dropped_begin_frame_args_;
51   }
52 }
53
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_);
60 }
61
62 // BeginFrameSourceMixIn ------------------------------------------------------
63 BeginFrameSourceMixIn::BeginFrameSourceMixIn()
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);
69 }
70
71 bool BeginFrameSourceMixIn::NeedsBeginFrames() const {
72   return needs_begin_frames_;
73 }
74
75 void BeginFrameSourceMixIn::SetNeedsBeginFrames(bool needs_begin_frames) {
76   DEBUG_FRAMES("BeginFrameSourceMixIn::SetNeedsBeginFrames",
77                "current state",
78                needs_begin_frames_,
79                "new state",
80                needs_begin_frames);
81   if (needs_begin_frames_ != needs_begin_frames) {
82     OnNeedsBeginFramesChange(needs_begin_frames);
83   }
84   needs_begin_frames_ = needs_begin_frames;
85 }
86
87 void BeginFrameSourceMixIn::AddObserver(BeginFrameObserver* obs) {
88   DEBUG_FRAMES("BeginFrameSourceMixIn::AddObserver",
89                "current observer",
90                observer_,
91                "to add observer",
92                obs);
93   DCHECK(!observer_);
94   observer_ = obs;
95 }
96
97 void BeginFrameSourceMixIn::RemoveObserver(BeginFrameObserver* obs) {
98   DEBUG_FRAMES("BeginFrameSourceMixIn::RemoveObserver",
99                "current observer",
100                observer_,
101                "to remove observer",
102                obs);
103   DCHECK_EQ(observer_, obs);
104   observer_ = NULL;
105 }
106
107 void BeginFrameSourceMixIn::CallOnBeginFrame(const BeginFrameArgs& args) {
108   DEBUG_FRAMES("BeginFrameSourceMixIn::CallOnBeginFrame",
109                "current observer",
110                observer_,
111                "args",
112                args.AsValue());
113   if (observer_) {
114     return observer_->OnBeginFrame(args);
115   }
116 }
117
118 // Tracing support
119 void BeginFrameSourceMixIn::AsValueInto(base::debug::TracedValue* dict) const {
120   // As the observer might try to trace the source, prevent an infinte loop
121   // from occuring.
122   if (inside_as_value_into_) {
123     dict->SetString("observer", "<loop detected>");
124     return;
125   }
126
127   if (observer_) {
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();
133   } else {
134     dict->SetString("observer", "NULL");
135   }
136   dict->SetBoolean("needs_begin_frames", NeedsBeginFrames());
137 }
138
139 // BackToBackBeginFrameSourceMixIn --------------------------------------------
140 scoped_ptr<BackToBackBeginFrameSource> BackToBackBeginFrameSource::Create(
141     base::SingleThreadTaskRunner* task_runner) {
142   return make_scoped_ptr(new BackToBackBeginFrameSource(task_runner));
143 }
144
145 BackToBackBeginFrameSource::BackToBackBeginFrameSource(
146     base::SingleThreadTaskRunner* task_runner)
147     : BeginFrameSourceMixIn(),
148       weak_factory_(this),
149       task_runner_(task_runner),
150       send_begin_frame_posted_(false) {
151   DCHECK(task_runner);
152   DCHECK_EQ(needs_begin_frames_, false);
153   DCHECK_EQ(send_begin_frame_posted_, false);
154 }
155
156 BackToBackBeginFrameSource::~BackToBackBeginFrameSource() {
157 }
158
159 base::TimeTicks BackToBackBeginFrameSource::Now() {
160   return gfx::FrameTime::Now();
161 }
162
163 void BackToBackBeginFrameSource::OnNeedsBeginFramesChange(
164     bool needs_begin_frames) {
165   if (!needs_begin_frames)
166     return;
167
168   if (send_begin_frame_posted_)
169     return;
170
171   send_begin_frame_posted_ = true;
172   task_runner_->PostTask(FROM_HERE,
173                          base::Bind(&BackToBackBeginFrameSource::BeginFrame,
174                                     weak_factory_.GetWeakPtr()));
175 }
176
177 void BackToBackBeginFrameSource::BeginFrame() {
178   send_begin_frame_posted_ = false;
179
180   if (!needs_begin_frames_)
181     return;
182
183   base::TimeTicks now = Now();
184   BeginFrameArgs args =
185       BeginFrameArgs::Create(now,
186                              now + BeginFrameArgs::DefaultInterval(),
187                              BeginFrameArgs::DefaultInterval());
188   CallOnBeginFrame(args);
189 }
190
191 // BeginFrameSource support
192
193 void BackToBackBeginFrameSource::DidFinishFrame(size_t remaining_frames) {
194   if (remaining_frames == 0) {
195     OnNeedsBeginFramesChange(NeedsBeginFrames());
196   }
197 }
198
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_);
205 }
206
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);
219   }
220
221   return make_scoped_ptr(new SyntheticBeginFrameSource(time_source));
222 }
223
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);
229 }
230
231 SyntheticBeginFrameSource::~SyntheticBeginFrameSource() {
232   if (NeedsBeginFrames())
233     time_source_->SetActive(false);
234 }
235
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);
240 }
241
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);
248 }
249
250 // TimeSourceClient support
251 void SyntheticBeginFrameSource::OnTimerTick() {
252   CallOnBeginFrame(CreateBeginFrameArgs(time_source_->LastTickTime(),
253                                         BeginFrameArgs::NORMAL));
254 }
255
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));
264   }
265 }
266
267 bool SyntheticBeginFrameSource::NeedsBeginFrames() const {
268   return time_source_->Active();
269 }
270
271 // Tracing support
272 void SyntheticBeginFrameSource::AsValueInto(
273     base::debug::TracedValue* dict) const {
274   dict->SetString("type", "SyntheticBeginFrameSource");
275   BeginFrameSourceMixIn::AsValueInto(dict);
276
277   dict->BeginDictionary("time_source");
278   time_source_->AsValueInto(dict);
279   dict->EndDictionary();
280 }
281
282 // BeginFrameSourceMultiplexer -------------------------------------------
283 scoped_ptr<BeginFrameSourceMultiplexer> BeginFrameSourceMultiplexer::Create() {
284   return make_scoped_ptr(new BeginFrameSourceMultiplexer());
285 }
286
287 BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer()
288     : BeginFrameSourceMixIn(),
289       minimum_interval_(base::TimeDelta()),
290       active_source_(NULL),
291       source_list_() {
292 }
293
294 BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer(
295     base::TimeDelta minimum_interval)
296     : BeginFrameSourceMixIn(),
297       minimum_interval_(minimum_interval),
298       active_source_(NULL),
299       source_list_() {
300 }
301
302 BeginFrameSourceMultiplexer::~BeginFrameSourceMultiplexer() {
303 }
304
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;
314 }
315
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));
324
325   source_list_.insert(new_source);
326
327   // If there is no active source, set the new one as the active one.
328   if (!active_source_)
329     SetActiveSource(new_source);
330 }
331
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);
343 }
344
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);
352
353   DCHECK(HasSource(new_source) || new_source == NULL);
354
355   bool needs_begin_frames = NeedsBeginFrames();
356   if (active_source_) {
357     if (needs_begin_frames)
358       SetNeedsBeginFrames(false);
359
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;
365   }
366   DCHECK(!active_source_);
367   active_source_ = new_source;
368
369   if (active_source_) {
370     active_source_->AddObserver(this);
371
372     if (needs_begin_frames) {
373       SetNeedsBeginFrames(true);
374     }
375   }
376 }
377
378 const BeginFrameSource* BeginFrameSourceMultiplexer::ActiveSource() {
379   return active_source_;
380 }
381
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;
391   }
392   DEBUG_FRAMES("BeginFrameSourceMultiplexer::OnBeginFrame",
393                "action",
394                "using",
395                "new args",
396                args.AsValue());
397   CallOnBeginFrame(args);
398 }
399
400 const BeginFrameArgs BeginFrameSourceMultiplexer::LastUsedBeginFrameArgs()
401     const {
402   if (observer_)
403     return observer_->LastUsedBeginFrameArgs();
404   else
405     return BeginFrameArgs();
406 }
407
408 // BeginFrameSource support
409 bool BeginFrameSourceMultiplexer::NeedsBeginFrames() const {
410   if (active_source_) {
411     return active_source_->NeedsBeginFrames();
412   } else {
413     return false;
414   }
415 }
416
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);
427   }
428 }
429
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);
438   }
439 }
440
441 // Tracing support
442 void BeginFrameSourceMultiplexer::AsValueInto(
443     base::debug::TracedValue* dict) const {
444   dict->SetString("type", "BeginFrameSourceMultiplexer");
445
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();
451   }
452
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");
459   }
460
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();
468   }
469   dict->EndArray();
470 }
471
472 // protected methods
473 bool BeginFrameSourceMultiplexer::HasSource(BeginFrameSource* source) {
474   return (source_list_.find(source) != source_list_.end());
475 }
476
477 bool BeginFrameSourceMultiplexer::IsIncreasing(const BeginFrameArgs& args) {
478   DCHECK(args.IsValid());
479   if (!observer_)
480     return false;
481
482   // If the last begin frame is invalid, then any new begin frame is valid.
483   if (!observer_->LastUsedBeginFrameArgs().IsValid())
484     return true;
485
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_);
490 }
491
492 }  // namespace cc