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

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: Rebase onto master. 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::SendBeginFrame(const BeginFrameArgs& args) {
brianderson 2014/09/18 00:27:25 "Send" implies that we're sending a message. Shoul
mithro-old 2014/09/18 13:33:37 It can't actually be named OnBeginFrame otherwise
brianderson 2014/09/18 21:54:18 CallOnBeginFrame sgtm.
mithro-old 2014/09/19 02:45:38 Acknowledged.
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() {
brianderson 2014/09/18 00:27:25 ScheduleBeginFrame?
mithro-old 2014/09/18 13:33:37 Done.
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() {
brianderson 2014/09/18 00:27:25 SendBeginFrame -> BeginFrame?
mithro-old 2014/09/18 13:33:37 Done.
127 send_begin_frame_posted_ = false;
128
129 // TODO(mithro): Fix the tests so this can be enabled. The tests currently
130 // depend on one begin frame firing after generate_frames_ is set false.
131 // if (!generate_frames_) {
brianderson 2014/09/18 00:27:25 Should this be !needs_begin_frames_? Why do the t
mithro-old 2014/09/18 13:33:37 Fixed.
132 // return;
133 // }
134
135 base::TimeTicks now = Now();
136 // Set deadline somewhere a long time in the future.
brianderson 2014/09/18 00:27:25 Comment doesn't match code anymore here.
mithro-old 2014/09/18 13:33:37 Removed.
137 BeginFrameArgs args =
138 BeginFrameArgs::Create(now,
139 now + BeginFrameArgs::DefaultInterval(),
140 BeginFrameArgs::DefaultInterval());
141 SendBeginFrame(args);
142 }
143
144 // BeginFrameSource ------------------------------------------------------
145 bool BackToBackBeginFrameSource::NeedsBeginFrames() const {
146 return needs_begin_frames_;
147 }
148
149 void BackToBackBeginFrameSource::SetNeedsBeginFrames(bool needs_begin_frames) {
150 needs_begin_frames_ = needs_begin_frames;
151 ScheduleSendBeginFrameArgs();
152 }
153
154 void BackToBackBeginFrameSource::DidFinishFrame(size_t remaining_frames) {
155 if (remaining_frames == 0) {
156 ScheduleSendBeginFrameArgs();
157 }
158 }
159
160 // Tracing
161 void BackToBackBeginFrameSource::AsValueInto(
162 base::debug::TracedValue* dict) const {
163 dict->SetString("type", "BackToBackBeginFrameSource");
164 BeginFrameSource::AsValueInto(dict);
165 dict->SetBoolean("send_begin_frame_posted_", send_begin_frame_posted_);
166 dict->SetBoolean("needs_begin_frames", needs_begin_frames_);
167 }
168
169 /*************************************************************************/
170
171 scoped_ptr<SyntheticBeginFrameSource> SyntheticBeginFrameSource::Create(
172 base::SingleThreadTaskRunner* task_runner,
173 base::TimeTicks initial_vsync_timebase,
174 base::TimeDelta initial_vsync_interval) {
175 scoped_refptr<DelayBasedTimeSource> time_source;
176 if (gfx::FrameTime::TimestampsAreHighRes()) {
177 time_source = DelayBasedTimeSourceHighRes::Create(initial_vsync_interval,
178 task_runner);
179 } else {
180 time_source =
181 DelayBasedTimeSource::Create(initial_vsync_interval, task_runner);
182 }
183
184 return make_scoped_ptr(new SyntheticBeginFrameSource(
185 time_source, initial_vsync_timebase, initial_vsync_interval));
186 }
187
188 SyntheticBeginFrameSource::SyntheticBeginFrameSource(
189 scoped_refptr<DelayBasedTimeSource> time_source,
190 base::TimeTicks initial_vsync_timebase,
191 base::TimeDelta initial_vsync_interval)
192 : BeginFrameSource(),
193 VSyncParameterObserver(initial_vsync_timebase, initial_vsync_interval),
194 time_source_(time_source) {
195 time_source_->SetActive(false);
196 time_source_->SetClient(this);
197 }
198
199 SyntheticBeginFrameSource::~SyntheticBeginFrameSource() {
200 if (NeedsBeginFrames())
201 time_source_->SetActive(false);
202 }
203
204 void SyntheticBeginFrameSource::OnTimeBaseAndIntervalChange(
205 const base::TimeTicks new_vsync_timebase,
206 const base::TimeDelta new_vsync_interval) {
207 time_source_->SetTimebaseAndInterval(new_vsync_timebase, new_vsync_interval);
208 }
209
210 void SyntheticBeginFrameSource::SendBeginFrameFromTick(
brianderson 2014/09/18 00:27:25 Please roll this into OnTimerTick.
brianderson 2014/09/18 00:31:25 Nevermind about this one, I see how it's reused wh
mithro-old 2014/09/18 13:33:37 Acknowledged.
mithro-old 2014/09/18 13:33:37 Acknowledged.
211 base::TimeTicks frame_time) {
212 base::TimeTicks deadline = time_source_->NextTickTime();
213 SendBeginFrame(BeginFrameArgs::Create(frame_time, deadline, VSyncInterval()));
214 }
215
216 // TimeSourceClient
217 void SyntheticBeginFrameSource::OnTimerTick() {
218 SendBeginFrameFromTick(time_source_->LastTickTime());
219 }
220
221 // BeginFrameSource
222 void SyntheticBeginFrameSource::SetNeedsBeginFrames(bool needs_begin_frames) {
223 if (needs_begin_frames == NeedsBeginFrames())
224 return;
225
226 base::TimeTicks missed_tick_time =
227 time_source_->SetActive(needs_begin_frames);
228 if (!missed_tick_time.is_null()) {
229 SendBeginFrameFromTick(missed_tick_time);
230 }
231 }
232
233 bool SyntheticBeginFrameSource::NeedsBeginFrames() const {
234 return time_source_->Active();
235 }
236
237 // Tracing
238 void SyntheticBeginFrameSource::AsValueInto(
239 base::debug::TracedValue* dict) const {
240 dict->SetString("type", "SyntheticBeginFrameSource");
241 BeginFrameSource::AsValueInto(dict);
242
243 dict->BeginDictionary("last_frame_args");
244 time_source_->AsValueInto(dict);
245 dict->EndDictionary();
246 }
247
248 /*************************************************************************/
249
250 scoped_ptr<BeginFrameSourceMultiplexer> BeginFrameSourceMultiplexer::Create() {
251 return make_scoped_ptr(new BeginFrameSourceMultiplexer());
252 }
253
254 BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer()
255 : minimum_interval_(base::TimeDelta()),
256 active_source_(NULL),
257 source_list_() {
258 }
259
260 BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer(
261 base::TimeDelta minimum_interval)
262 : minimum_interval_(minimum_interval),
263 active_source_(NULL),
264 source_list_() {
265 }
266
267 BeginFrameSourceMultiplexer::~BeginFrameSourceMultiplexer() {
268 }
269
270 void BeginFrameSourceMultiplexer::SetActiveSource(
271 BeginFrameSource* new_source) {
272 DCHECK(HasSource(new_source) || new_source == NULL);
273
274 bool needs_begin_frames = NeedsBeginFrames();
275 if (active_source_) {
276 if (needs_begin_frames)
277 SetNeedsBeginFrames(false);
278
279 // Technically we shouldn't need to remove observation, but this prevents
280 // the case where SetNeedsBeginFrames message gets to the source after a
281 // message has already been sent.
282 active_source_->RemoveObserver(this);
283 active_source_ = NULL;
284 }
285 DCHECK(!active_source_);
286 active_source_ = new_source;
287
288 if (active_source_) {
289 active_source_->AddObserver(this);
290
291 if (needs_begin_frames) {
292 SetNeedsBeginFrames(true);
293 }
294 }
295 }
296
297 const BeginFrameSource* BeginFrameSourceMultiplexer::ActiveSource() {
298 return active_source_;
299 }
300
301 bool BeginFrameSourceMultiplexer::HasSource(BeginFrameSource* source) {
302 return (source_list_.find(source) != source_list_.end());
303 }
304
305 // ThrottledBeginFrameSource
306 void BeginFrameSourceMultiplexer::AddSource(BeginFrameSource* new_source) {
307 DCHECK(new_source);
308 DCHECK(!HasSource(new_source));
309
310 source_list_.insert(new_source);
311
312 // If there is no active source, set the new one as the active one.
313 if (!active_source_)
314 SetActiveSource(new_source);
315 }
316
317 void BeginFrameSourceMultiplexer::RemoveSource(
318 BeginFrameSource* existing_source) {
319 DCHECK(existing_source);
320 DCHECK(HasSource(existing_source));
321 DCHECK_NE(existing_source, active_source_);
322 source_list_.erase(existing_source);
323 }
324
325 void BeginFrameSourceMultiplexer::SetMinimumInterval(
326 base::TimeDelta new_minimum_interval) {
327 DCHECK_GE(new_minimum_interval.ToInternalValue(), 0);
328 minimum_interval_ = new_minimum_interval;
329 }
330
331 // BeginFrameObserver
332 void BeginFrameSourceMultiplexer::OnBeginFrame(const BeginFrameArgs& args) {
333 if (!observer_)
334 return;
335
336 if (observer_->LastBeginFrameArgs().IsValid() &&
337 observer_->LastBeginFrameArgs().frame_time + minimum_interval_ >
338 args.frame_time)
339 return;
340 SendBeginFrame(args);
341 }
342
343 const BeginFrameArgs& BeginFrameSourceMultiplexer::LastBeginFrameArgs() const {
344 return observer_->LastBeginFrameArgs();
345 }
346
347 // BeginFrameSource
348 bool BeginFrameSourceMultiplexer::NeedsBeginFrames() const {
349 if (active_source_) {
350 return active_source_->NeedsBeginFrames();
351 } else {
352 return false;
353 }
354 }
355
356 void BeginFrameSourceMultiplexer::SetNeedsBeginFrames(bool needs_begin_frames) {
357 if (active_source_) {
358 active_source_->SetNeedsBeginFrames(needs_begin_frames);
359 } else {
360 DCHECK(!needs_begin_frames);
361 }
362 }
363
364 void BeginFrameSourceMultiplexer::DidFinishFrame(size_t remaining_frames) {
365 active_source_->DidFinishFrame(remaining_frames);
366 }
367
368 // Tracing
369 void BeginFrameSourceMultiplexer::AsValueInto(
370 base::debug::TracedValue* dict) const {
371 dict->SetString("type", "BeginFrameSourceMultiplexer");
372
373 dict->SetInteger("minimum_interval_us", minimum_interval_.InMicroseconds());
374 if (observer_) {
375 dict->BeginDictionary("last_begin_frame_args");
376 observer_->LastBeginFrameArgs().AsValueInto(dict);
377 dict->EndDictionary();
378 }
379
380 if (active_source_) {
381 dict->BeginDictionary("active_source");
382 active_source_->AsValueInto(dict);
383 dict->EndDictionary();
384 } else {
385 dict->SetString("active_source", "NULL");
386 }
387
388 for (std::set<BeginFrameSource*>::const_iterator it = source_list_.begin();
389 it != source_list_.end();
390 ++it) {
391 dict->BeginDictionary(
392 base::SizeTToString(std::distance(source_list_.begin(), it)).c_str());
393 (*it)->AsValueInto(dict);
394 dict->EndDictionary();
395 }
396 }
397
398 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698