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

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

Powered by Google App Engine
This is Rietveld 408576698