Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(403)

Side by Side Diff: cc/scheduler/frame_source.cc

Issue 267783004: Refactoring the way begin frame sources inside scheduler work. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Testing.. Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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/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 namespace cc {
17
18 VSyncParameterObserver::VSyncParameterObserver(
19 base::TimeTicks initial_vsync_timebase,
20 base::TimeDelta initial_vsync_interval)
21 : vsync_timebase_(initial_vsync_timebase),
22 vsync_interval_(initial_vsync_interval) {
23 }
24 VSyncParameterObserver::~VSyncParameterObserver() {
25 }
26
27 void VSyncParameterObserver::OnUpdateVSyncParameters(
28 base::TimeTicks new_vsync_timebase,
29 base::TimeDelta new_vsync_interval) {
30 if (vsync_timebase_ != new_vsync_timebase ||
31 vsync_interval_ != new_vsync_interval) {
32 OnTimeBaseAndIntervalChange(new_vsync_timebase, new_vsync_interval);
33 }
34 vsync_timebase_ = new_vsync_timebase;
35 vsync_interval_ = new_vsync_interval;
36 }
37
38 base::TimeTicks VSyncParameterObserver::VSyncTimebase() const {
39 return vsync_timebase_;
40 }
41
42 base::TimeDelta VSyncParameterObserver::VSyncInterval() const {
43 return vsync_interval_;
44 }
45
46 // Tracing
47 void VSyncParameterObserver::AsValueInto(base::debug::TracedValue* dict) const {
48 dict->SetInteger("vsync_timebase_us", vsync_timebase_.ToInternalValue());
49 dict->SetInteger("vsync_interval_us", vsync_interval_.InMicroseconds());
50 }
51
52 /*************************************************************************/
53
54 void BeginFrameSource::AddObserver(BeginFrameObserver* obs) {
55 DCHECK(!observer_);
56 observer_ = obs;
57 }
58
59 void BeginFrameSource::RemoveObserver(BeginFrameObserver* obs) {
60 DCHECK_EQ(observer_, obs);
61 observer_ = NULL;
62 }
63
64 void BeginFrameSource::CallOnBeginFrame(const BeginFrameArgs& args) {
65 if (observer_) {
66 observer_->OnBeginFrame(args);
67 }
68 }
69
70 // Tracing support
71 void BeginFrameSource::AsValueInto(base::debug::TracedValue* dict) const {
72 // As the observer might try to trace the source, prevent an infinte loop
73 // from occuring.
74 if (inside_as_value_into_) {
75 dict->SetString("observer", "<loop detected>");
76 return;
77 }
78
79 if (observer_) {
80 base::AutoReset<bool> prevent_loops(
81 const_cast<bool*>(&inside_as_value_into_), true);
82 dict->BeginDictionary("observer");
83 observer_->AsValueInto(dict);
84 dict->EndDictionary();
85 } else {
86 dict->SetString("observer", "NULL");
87 }
88 }
89
90 /*************************************************************************/
91 scoped_ptr<BackToBackBeginFrameSource> BackToBackBeginFrameSource::Create(
92 base::SingleThreadTaskRunner* task_runner) {
93 return make_scoped_ptr(new BackToBackBeginFrameSource(task_runner));
94 }
95
96 BackToBackBeginFrameSource::BackToBackBeginFrameSource(
97 base::SingleThreadTaskRunner* task_runner)
98 : weak_factory_(this),
99 task_runner_(task_runner),
100 needs_begin_frames_(false),
101 send_begin_frame_posted_(false) {
102 DCHECK(task_runner);
103 }
104
105 BackToBackBeginFrameSource::~BackToBackBeginFrameSource() {
106 }
107
108 base::TimeTicks BackToBackBeginFrameSource::Now() {
109 return gfx::FrameTime::Now();
110 }
111
112 void BackToBackBeginFrameSource::ScheduleSendBeginFrameArgs() {
113 if (!needs_begin_frames_)
114 return;
115
116 if (send_begin_frame_posted_)
117 return;
118
119 send_begin_frame_posted_ = true;
120 task_runner_->PostTask(
121 FROM_HERE,
122 base::Bind(&BackToBackBeginFrameSource::SendBeginFrameArgs,
123 weak_factory_.GetWeakPtr()));
124 }
125
126 void BackToBackBeginFrameSource::SendBeginFrameArgs() {
127 send_begin_frame_posted_ = false;
128
129 if (!needs_begin_frames_) {
130 return;
131 }
132
133 base::TimeTicks now = Now();
134 BeginFrameArgs args =
135 BeginFrameArgs::Create(now,
136 now + BeginFrameArgs::DefaultInterval(),
137 BeginFrameArgs::DefaultInterval());
138 CallOnBeginFrame(args);
139 }
140
141 // BeginFrameSource ------------------------------------------------------
142 bool BackToBackBeginFrameSource::NeedsBeginFrames() const {
143 return needs_begin_frames_;
144 }
145
146 void BackToBackBeginFrameSource::SetNeedsBeginFrames(bool needs_begin_frames) {
147 needs_begin_frames_ = needs_begin_frames;
148 ScheduleSendBeginFrameArgs();
149 }
150
151 void BackToBackBeginFrameSource::DidFinishFrame(size_t remaining_frames) {
152 if (remaining_frames == 0) {
153 ScheduleSendBeginFrameArgs();
154 }
155 }
156
157 // Tracing
158 void BackToBackBeginFrameSource::AsValueInto(
159 base::debug::TracedValue* dict) const {
160 dict->SetString("type", "BackToBackBeginFrameSource");
161 BeginFrameSource::AsValueInto(dict);
162 dict->SetBoolean("send_begin_frame_posted_", send_begin_frame_posted_);
163 dict->SetBoolean("needs_begin_frames", needs_begin_frames_);
164 }
165
166 /*************************************************************************/
167
168 scoped_ptr<SyntheticBeginFrameSource> SyntheticBeginFrameSource::Create(
169 base::SingleThreadTaskRunner* task_runner,
170 base::TimeTicks initial_vsync_timebase,
171 base::TimeDelta initial_vsync_interval) {
172 scoped_refptr<DelayBasedTimeSource> time_source;
173 if (gfx::FrameTime::TimestampsAreHighRes()) {
174 time_source = DelayBasedTimeSourceHighRes::Create(initial_vsync_interval,
175 task_runner);
176 } else {
177 time_source =
178 DelayBasedTimeSource::Create(initial_vsync_interval, task_runner);
179 }
180
181 return make_scoped_ptr(new SyntheticBeginFrameSource(
182 time_source, initial_vsync_timebase, initial_vsync_interval));
183 }
184
185 SyntheticBeginFrameSource::SyntheticBeginFrameSource(
186 scoped_refptr<DelayBasedTimeSource> time_source,
187 base::TimeTicks initial_vsync_timebase,
188 base::TimeDelta initial_vsync_interval)
189 : BeginFrameSource(),
190 VSyncParameterObserver(initial_vsync_timebase, initial_vsync_interval),
191 time_source_(time_source) {
192 time_source_->SetActive(false);
193 time_source_->SetClient(this);
194 }
195
196 SyntheticBeginFrameSource::~SyntheticBeginFrameSource() {
197 if (NeedsBeginFrames())
198 time_source_->SetActive(false);
199 }
200
201 void SyntheticBeginFrameSource::OnTimeBaseAndIntervalChange(
202 const base::TimeTicks new_vsync_timebase,
203 const base::TimeDelta new_vsync_interval) {
204 time_source_->SetTimebaseAndInterval(new_vsync_timebase, new_vsync_interval);
205 }
206
207 void SyntheticBeginFrameSource::SendBeginFrameFromTick(
208 base::TimeTicks frame_time) {
209 base::TimeTicks deadline = time_source_->NextTickTime();
210 CallOnBeginFrame(
211 BeginFrameArgs::Create(frame_time, deadline, VSyncInterval()));
212 }
213
214 // TimeSourceClient
215 void SyntheticBeginFrameSource::OnTimerTick() {
216 SendBeginFrameFromTick(time_source_->LastTickTime());
217 }
218
219 // BeginFrameSource
220 void SyntheticBeginFrameSource::SetNeedsBeginFrames(bool needs_begin_frames) {
221 if (needs_begin_frames == NeedsBeginFrames())
222 return;
223
224 base::TimeTicks missed_tick_time =
225 time_source_->SetActive(needs_begin_frames);
226 if (!missed_tick_time.is_null()) {
227 SendBeginFrameFromTick(missed_tick_time);
228 }
229 }
230
231 bool SyntheticBeginFrameSource::NeedsBeginFrames() const {
232 return time_source_->Active();
233 }
234
235 // Tracing
236 void SyntheticBeginFrameSource::AsValueInto(
237 base::debug::TracedValue* dict) const {
238 dict->SetString("type", "SyntheticBeginFrameSource");
239 BeginFrameSource::AsValueInto(dict);
240
241 dict->BeginDictionary("last_frame_args");
242 time_source_->AsValueInto(dict);
243 dict->EndDictionary();
244 }
245
246 /*************************************************************************/
247
248 scoped_ptr<BeginFrameSourceMultiplexer> BeginFrameSourceMultiplexer::Create() {
249 return make_scoped_ptr(new BeginFrameSourceMultiplexer());
250 }
251
252 BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer()
253 : minimum_interval_(base::TimeDelta()),
254 active_source_(NULL),
255 source_list_() {
256 }
257
258 BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer(
259 base::TimeDelta minimum_interval)
260 : minimum_interval_(minimum_interval),
261 active_source_(NULL),
262 source_list_() {
263 }
264
265 BeginFrameSourceMultiplexer::~BeginFrameSourceMultiplexer() {
266 }
267
268 void BeginFrameSourceMultiplexer::SetActiveSource(
269 BeginFrameSource* new_source) {
270 DCHECK(HasSource(new_source) || new_source == NULL);
271
272 bool needs_begin_frames = NeedsBeginFrames();
273 if (active_source_) {
274 if (needs_begin_frames)
275 SetNeedsBeginFrames(false);
276
277 // Technically we shouldn't need to remove observation, but this prevents
278 // the case where SetNeedsBeginFrames message gets to the source after a
279 // message has already been sent.
280 active_source_->RemoveObserver(this);
281 active_source_ = NULL;
282 }
283 DCHECK(!active_source_);
284 active_source_ = new_source;
285
286 if (active_source_) {
287 active_source_->AddObserver(this);
288
289 if (needs_begin_frames) {
290 SetNeedsBeginFrames(true);
291 }
292 }
293 }
294
295 const BeginFrameSource* BeginFrameSourceMultiplexer::ActiveSource() {
296 return active_source_;
297 }
298
299 bool BeginFrameSourceMultiplexer::HasSource(BeginFrameSource* source) {
300 return (source_list_.find(source) != source_list_.end());
301 }
302
303 // ThrottledBeginFrameSource
304 void BeginFrameSourceMultiplexer::AddSource(BeginFrameSource* new_source) {
305 DCHECK(new_source);
306 DCHECK(!HasSource(new_source));
307
308 source_list_.insert(new_source);
309
310 // If there is no active source, set the new one as the active one.
311 if (!active_source_)
312 SetActiveSource(new_source);
313 }
314
315 void BeginFrameSourceMultiplexer::RemoveSource(
316 BeginFrameSource* existing_source) {
317 DCHECK(existing_source);
318 DCHECK(HasSource(existing_source));
319 DCHECK_NE(existing_source, active_source_);
320 source_list_.erase(existing_source);
321 }
322
323 void BeginFrameSourceMultiplexer::SetMinimumInterval(
324 base::TimeDelta new_minimum_interval) {
325 DCHECK_GE(new_minimum_interval.ToInternalValue(), 0);
326 minimum_interval_ = new_minimum_interval;
327 }
328
329 // BeginFrameObserver
330 void BeginFrameSourceMultiplexer::OnBeginFrame(const BeginFrameArgs& args) {
331 if (!observer_)
332 return;
333
334 if (observer_->LastBeginFrameArgs().IsValid() &&
335 observer_->LastBeginFrameArgs().frame_time + minimum_interval_ >
336 args.frame_time)
337 return;
338 CallOnBeginFrame(args);
339 }
340
341 const BeginFrameArgs& BeginFrameSourceMultiplexer::LastBeginFrameArgs() const {
342 return observer_->LastBeginFrameArgs();
343 }
344
345 // BeginFrameSource
346 bool BeginFrameSourceMultiplexer::NeedsBeginFrames() const {
347 if (active_source_) {
348 return active_source_->NeedsBeginFrames();
349 } else {
350 return false;
351 }
352 }
353
354 void BeginFrameSourceMultiplexer::SetNeedsBeginFrames(bool needs_begin_frames) {
355 if (active_source_) {
356 active_source_->SetNeedsBeginFrames(needs_begin_frames);
357 } else {
358 DCHECK(!needs_begin_frames);
359 }
360 }
361
362 void BeginFrameSourceMultiplexer::DidFinishFrame(size_t remaining_frames) {
363 active_source_->DidFinishFrame(remaining_frames);
364 }
365
366 // Tracing
367 void BeginFrameSourceMultiplexer::AsValueInto(
368 base::debug::TracedValue* dict) const {
369 dict->SetString("type", "BeginFrameSourceMultiplexer");
370
371 dict->SetInteger("minimum_interval_us", minimum_interval_.InMicroseconds());
372 if (observer_) {
373 dict->BeginDictionary("last_begin_frame_args");
374 observer_->LastBeginFrameArgs().AsValueInto(dict);
375 dict->EndDictionary();
376 }
377
378 if (active_source_) {
379 dict->BeginDictionary("active_source");
380 active_source_->AsValueInto(dict);
381 dict->EndDictionary();
382 } else {
383 dict->SetString("active_source", "NULL");
384 }
385
386 for (std::set<BeginFrameSource*>::const_iterator it = source_list_.begin();
387 it != source_list_.end();
388 ++it) {
389 dict->BeginDictionary(
390 base::SizeTToString(std::distance(source_list_.begin(), it)).c_str());
391 (*it)->AsValueInto(dict);
392 dict->EndDictionary();
393 }
394 }
395
396 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698