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

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: Major rewrite based on Brian's comments. 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/debug/trace_event.h"
8 #include "base/debug/trace_event_argument.h"
9 #include "base/logging.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "cc/scheduler/delay_based_time_source.h"
12 #include "cc/scheduler/scheduler.h"
13 #include "ui/gfx/frame_time.h"
14
15 namespace cc {
16
17 VSyncObserverImpl::VSyncObserverImpl(base::TimeTicks initial_vsync_timebase,
18 base::TimeDelta initial_vsync_interval)
19 : vsync_timebase_(initial_vsync_timebase),
20 vsync_interval_(initial_vsync_interval) {
21 }
22 VSyncObserverImpl::~VSyncObserverImpl() {
23 }
24
25 void VSyncObserverImpl::OnUpdateVSyncParameters(
26 base::TimeTicks new_vsync_timebase,
27 base::TimeDelta new_vsync_interval) {
28 if (vsync_timebase_ != new_vsync_timebase ||
29 vsync_interval_ != new_vsync_interval) {
30 OnTimeBaseAndIntervalChange(new_vsync_timebase, new_vsync_interval);
31 }
32 vsync_timebase_ = new_vsync_timebase;
33 vsync_interval_ = new_vsync_interval;
34 }
35
36 base::TimeTicks VSyncObserverImpl::VSyncTimebase() const {
37 return vsync_timebase_;
38 }
39
40 base::TimeDelta VSyncObserverImpl::VSyncInterval() const {
41 return vsync_interval_;
42 }
43
44 // Tracing
45 void VSyncObserverImpl::AsValueInto(base::debug::TracedValue* dict) const {
46 dict->SetInteger("vsync_timebase_us", vsync_timebase_.ToInternalValue());
47 dict->SetInteger("vsync_interval_us", vsync_interval_.InMicroseconds());
48 }
49
50 /*************************************************************************/
51
52 void BeginFrameSource::AddObserver(BeginFrameObserver* obs) {
53 DCHECK(!observer_);
54 observer_ = obs;
55 }
56
57 void BeginFrameSource::RemoveObserver(BeginFrameObserver* obs) {
58 DCHECK_EQ(observer_, obs);
59 observer_ = NULL;
60 }
61
62 void BeginFrameSource::SendBeginFrame(const BeginFrameArgs& args) {
63 if (observer_) {
64 observer_->OnBeginFrame(args);
65 }
66 }
67
68 // Tracing support
69 void BeginFrameSource::AsValueInto(base::debug::TracedValue* dict) const {
70 if (observer_) {
71 dict->BeginDictionary("observer");
72 observer_->AsValueInto(dict);
73 dict->EndDictionary();
74 } else {
75 dict->SetString("observer", "NULL");
76 }
77 }
78
79 /*************************************************************************/
80 scoped_ptr<ThrottledBeginFrameSource> ThrottledBeginFrameSource::Create(
81 base::TimeDelta minimum_interval) {
82 return make_scoped_ptr(new ThrottledBeginFrameSource(minimum_interval));
83 }
84
85 ThrottledBeginFrameSource::ThrottledBeginFrameSource(
86 base::TimeDelta minimum_interval)
87 : minimum_interval_(minimum_interval), source_(NULL) {
88 DCHECK_GE(minimum_interval_.ToInternalValue(), 0);
89 }
90
91 ThrottledBeginFrameSource::~ThrottledBeginFrameSource() {
92 if (source_) {
93 RemoveSource(source_);
94 }
95 }
96
97 void ThrottledBeginFrameSource::SetMinimumInterval(
98 base::TimeDelta new_minimum_interval) {
99 DCHECK_GE(new_minimum_interval.ToInternalValue(), 0);
100 minimum_interval_ = new_minimum_interval;
101 }
102
103 // base::TimeDelta ThrottledBeginFrameSource::SetMinimumInterval() const {
104 // return minimum_interval_;
105 //}
106
107 void ThrottledBeginFrameSource::AddSource(BeginFrameSource* new_source) {
108 DCHECK(new_source);
109 DCHECK(!source_);
110 source_ = new_source;
111 source_->AddObserver(this);
112 }
113
114 void ThrottledBeginFrameSource::RemoveSource(BeginFrameSource* new_source) {
115 DCHECK(new_source);
116 DCHECK_EQ(source_, new_source);
117
118 source_->SetNeedsBeginFrames(false);
119 source_->RemoveObserver(this);
120 source_ = NULL;
121 }
122
123 // BeginFrameObserver
124 void ThrottledBeginFrameSource::OnBeginFrame(const BeginFrameArgs& args) {
125 if (!observer_)
126 return;
127
128 if (observer_->LastBeginFrameArgs().IsValid() &&
129 observer_->LastBeginFrameArgs().frame_time + minimum_interval_ >
130 args.frame_time)
131 return;
132 SendBeginFrame(args);
133 }
134
135 const BeginFrameArgs& ThrottledBeginFrameSource::LastBeginFrameArgs() const {
136 return observer_->LastBeginFrameArgs();
137 }
138
139 // BeginFrameSource
140 bool ThrottledBeginFrameSource::NeedsBeginFrames() {
141 if (source_) {
142 return source_->NeedsBeginFrames();
143 } else {
144 return false;
145 }
146 }
147
148 void ThrottledBeginFrameSource::SetNeedsBeginFrames(bool needs_begin_frames) {
149 if (source_) {
150 source_->SetNeedsBeginFrames(needs_begin_frames);
151 } else {
152 DCHECK(!needs_begin_frames);
153 }
154 }
155
156 void ThrottledBeginFrameSource::FinishedFrame(size_t remaining_frames) {
157 source_->FinishedFrame(remaining_frames);
158 }
159
160 // Tracing
161 void ThrottledBeginFrameSource::AsValueInto(
162 base::debug::TracedValue* dict) const {
163 dict->SetString("type", "ThrottledBeginFrameSource");
164 BeginFrameSource::AsValueInto(dict);
165
166 dict->SetInteger("minimum_interval_us", minimum_interval_.InMicroseconds());
167
168 if (observer_) {
169 dict->BeginDictionary("last_begin_frame_args");
170 observer_->LastBeginFrameArgs().AsValueInto(dict);
171 dict->EndDictionary();
172 }
173
174 dict->BeginDictionary("source");
175 source_->AsValueInto(dict);
176 dict->EndDictionary();
177 }
178
179 /*************************************************************************/
180 scoped_ptr<BackToBackBeginFrameSource> BackToBackBeginFrameSource::Create(
181 base::SingleThreadTaskRunner* task_runner) {
182 return make_scoped_ptr(new BackToBackBeginFrameSource(task_runner));
183 }
184
185 BackToBackBeginFrameSource::BackToBackBeginFrameSource(
186 base::SingleThreadTaskRunner* task_runner)
187 : weak_factory_(this),
188 task_runner_(task_runner),
189 needs_begin_frames_(false),
190 send_begin_frame_posted_(false) {
191 DCHECK(task_runner);
192 }
193
194 BackToBackBeginFrameSource::~BackToBackBeginFrameSource() {
195 }
196
197 base::TimeTicks BackToBackBeginFrameSource::Now() {
198 return gfx::FrameTime::Now();
199 }
200
201 void BackToBackBeginFrameSource::ScheduleSendBeginFrameArgs() {
202 if (!needs_begin_frames_)
203 return;
204
205 if (send_begin_frame_posted_)
206 return;
207
208 send_begin_frame_posted_ = true;
209 task_runner_->PostTask(
210 FROM_HERE,
211 base::Bind(&BackToBackBeginFrameSource::SendBeginFrameArgs,
212 weak_factory_.GetWeakPtr()));
213 }
214
215 void BackToBackBeginFrameSource::SendBeginFrameArgs() {
216 send_begin_frame_posted_ = false;
217
218 // TODO(mithro): Fix the tests so this can be enabled. The tests currently
219 // depend on one begin frame firing after generate_frames_ is set false.
220 // if (!generate_frames_) {
221 // return;
222 // }
223
224 base::TimeTicks now = Now();
225 // Set deadline somewhere a long time in the future.
226 BeginFrameArgs args =
227 BeginFrameArgs::Create(now,
228 now + base::TimeDelta::FromSeconds(1000),
229 base::TimeDelta::FromInternalValue(-1));
230 SendBeginFrame(args);
brianderson 2014/09/13 01:38:12 We probably shouldn't send BeginFrames from Browse
231 }
232
233 // BeginFrameSource ------------------------------------------------------
234 bool BackToBackBeginFrameSource::NeedsBeginFrames() {
235 return needs_begin_frames_;
236 }
237
238 void BackToBackBeginFrameSource::SetNeedsBeginFrames(bool needs_begin_frames) {
239 needs_begin_frames_ = needs_begin_frames;
240 ScheduleSendBeginFrameArgs();
241 }
242
243 void BackToBackBeginFrameSource::FinishedFrame(size_t remaining_frames) {
244 if (remaining_frames == 0) {
245 ScheduleSendBeginFrameArgs();
246 }
247 }
248
249 // Tracing
250 void BackToBackBeginFrameSource::AsValueInto(
251 base::debug::TracedValue* dict) const {
252 dict->SetString("type", "BackToBackBeginFrameSource");
253 BeginFrameSource::AsValueInto(dict);
254 dict->SetBoolean("send_begin_frame_posted_", send_begin_frame_posted_);
255 dict->SetBoolean("needs_begin_frames", needs_begin_frames_);
256 }
257
258 /*************************************************************************/
259
260 scoped_ptr<SyntheticBeginFrameSource> SyntheticBeginFrameSource::Create(
261 base::SingleThreadTaskRunner* task_runner,
262 base::TimeDelta initial_vsync_interval) {
263 scoped_refptr<DelayBasedTimeSource> time_source;
264 if (gfx::FrameTime::TimestampsAreHighRes()) {
265 time_source = DelayBasedTimeSourceHighRes::Create(initial_vsync_interval,
266 task_runner);
267 } else {
268 time_source =
269 DelayBasedTimeSource::Create(initial_vsync_interval, task_runner);
270 }
271
272 base::TimeTicks initial_vsync_timebase = gfx::FrameTime::Now();
273 return make_scoped_ptr(new SyntheticBeginFrameSource(
274 time_source, initial_vsync_timebase, initial_vsync_interval));
275 }
276
277 SyntheticBeginFrameSource::SyntheticBeginFrameSource(
278 scoped_refptr<DelayBasedTimeSource> time_source,
279 base::TimeTicks initial_vsync_timebase,
280 base::TimeDelta initial_vsync_interval)
281 : BeginFrameSource(),
282 VSyncObserverImpl(initial_vsync_timebase, initial_vsync_interval),
283 time_source_(time_source) {
284 time_source_->SetActive(false);
285 time_source_->SetClient(this);
286 }
287
288 SyntheticBeginFrameSource::~SyntheticBeginFrameSource() {
289 time_source_->SetActive(false);
290 }
291
292 void SyntheticBeginFrameSource::OnTimeBaseAndIntervalChange(
293 const base::TimeTicks new_vsync_timebase,
294 const base::TimeDelta new_vsync_interval) {
295 time_source_->SetTimebaseAndInterval(new_vsync_timebase, new_vsync_interval);
296 }
297
298 void SyntheticBeginFrameSource::SendBeginFrameFromTick(
299 base::TimeTicks frame_time) {
300 base::TimeTicks deadline = time_source_->NextTickTime();
301 SendBeginFrame(BeginFrameArgs::Create(frame_time, deadline, VSyncInterval()));
302 }
303
304 // TimeSourceClient
305 void SyntheticBeginFrameSource::OnTimerTick() {
306 SendBeginFrameFromTick(time_source_->LastTickTime());
307 }
308
309 // BeginFrameSource
310 void SyntheticBeginFrameSource::SetNeedsBeginFrames(bool needs_begin_frames) {
311 base::TimeTicks missed_tick_time =
312 time_source_->SetActive(needs_begin_frames);
313 if (!missed_tick_time.is_null()) {
314 SendBeginFrameFromTick(missed_tick_time);
315 }
316 }
317
318 bool SyntheticBeginFrameSource::NeedsBeginFrames() {
319 return time_source_->Active();
320 }
321
322 // Tracing
323 void SyntheticBeginFrameSource::AsValueInto(
324 base::debug::TracedValue* dict) const {
325 dict->SetString("type", "SyntheticBeginFrameSource");
326 BeginFrameSource::AsValueInto(dict);
327
328 dict->BeginDictionary("last_frame_args");
329 time_source_->AsValueInto(dict);
330 dict->EndDictionary();
331 }
332
333 /*************************************************************************/
334
335 scoped_ptr<BeginFrameSourceMultiplexer> BeginFrameSourceMultiplexer::Create() {
336 return make_scoped_ptr(new BeginFrameSourceMultiplexer());
337 }
338
339 BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer()
340 : ThrottledBeginFrameSource(base::TimeDelta()), source_list_() {
341 }
342
343 BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer(
344 base::TimeDelta minimum_interval)
345 : ThrottledBeginFrameSource(minimum_interval), source_list_() {
346 }
347
348 BeginFrameSourceMultiplexer::~BeginFrameSourceMultiplexer() {
349 }
350
351 void BeginFrameSourceMultiplexer::SetActiveSource(
352 BeginFrameSource* new_source) {
353 DCHECK(HasSource(new_source));
354 bool needs_begin_frames = NeedsBeginFrames();
355
356 if (source_) {
357 if (needs_begin_frames)
358 source_->SetNeedsBeginFrames(false);
359
360 // Technically we shouldn't need to remove observation, but this prevents
361 // the
362 // case where SetNeedsBeginFrames message gets to the source after a message
363 // has already been sent.
364 ThrottledBeginFrameSource::RemoveSource(source_);
365 }
366 DCHECK(!source_);
367 ThrottledBeginFrameSource::AddSource(new_source);
368
369 if (needs_begin_frames) {
370 source_->SetNeedsBeginFrames(true);
371 }
372 }
373
374 const BeginFrameSource* BeginFrameSourceMultiplexer::ActiveSource() {
375 return source_;
376 }
377
378 bool BeginFrameSourceMultiplexer::HasSource(BeginFrameSource* source) {
379 return (source_list_.find(source) != source_list_.end());
380 }
381
382 // ThrottledBeginFrameSource
383 void BeginFrameSourceMultiplexer::AddSource(BeginFrameSource* new_source) {
384 DCHECK(new_source);
385 DCHECK(!HasSource(new_source));
386
387 source_list_.insert(new_source);
388
389 // If there is no active source, set the new one as the active one.
390 if (!source_)
391 SetActiveSource(new_source);
392 }
393
394 void BeginFrameSourceMultiplexer::RemoveSource(
395 BeginFrameSource* existing_source) {
396 DCHECK(existing_source);
397 DCHECK(HasSource(existing_source));
398 DCHECK_NE(existing_source, source_);
399 source_list_.erase(existing_source);
400 }
401
402 // Tracing
403 void BeginFrameSourceMultiplexer::AsValueInto(
404 base::debug::TracedValue* dict) const {
405 dict->SetString("type", "BeginFrameSourceMultiplexer");
406 ThrottledBeginFrameSource::AsValueInto(dict);
407
408 dict->BeginDictionary("active_source");
409 source_->AsValueInto(dict);
410 dict->EndDictionary();
411
412 for (std::set<BeginFrameSource*>::const_iterator it = source_list_.begin();
413 it != source_list_.end();
414 ++it) {
415 dict->BeginDictionary(
416 base::SizeTToString(std::distance(source_list_.begin(), it)).c_str());
417 (*it)->AsValueInto(dict);
418 dict->EndDictionary();
419 }
420 }
421
422 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698