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

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: Fixing loop causing segfault. 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) {
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 // 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_) {
132 // return;
133 // }
134
135 base::TimeTicks now = Now();
136 // Set deadline somewhere a long time in the future.
137 BeginFrameArgs args =
138 BeginFrameArgs::Create(now,
139 now + base::TimeDelta::FromSeconds(1000),
brianderson 2014/09/16 23:55:04 The current logic sets the deadline to be now+inte
140 base::TimeDelta::FromInternalValue(-1));
Sami 2014/09/15 13:17:00 Can we use a valid interval (say, BeginFrameArgs::
141 SendBeginFrame(args);
142 }
143
144 // BeginFrameSource ------------------------------------------------------
145 bool BackToBackBeginFrameSource::NeedsBeginFrames() {
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::FinishedFrame(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::TimeDelta initial_vsync_interval) {
174 scoped_refptr<DelayBasedTimeSource> time_source;
175 if (gfx::FrameTime::TimestampsAreHighRes()) {
176 time_source = DelayBasedTimeSourceHighRes::Create(initial_vsync_interval,
177 task_runner);
178 } else {
179 time_source =
180 DelayBasedTimeSource::Create(initial_vsync_interval, task_runner);
181 }
182
183 base::TimeTicks initial_vsync_timebase = gfx::FrameTime::Now();
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 time_source_->SetActive(false);
201 }
202
203 void SyntheticBeginFrameSource::OnTimeBaseAndIntervalChange(
204 const base::TimeTicks new_vsync_timebase,
205 const base::TimeDelta new_vsync_interval) {
206 time_source_->SetTimebaseAndInterval(new_vsync_timebase, new_vsync_interval);
207 }
208
209 void SyntheticBeginFrameSource::SendBeginFrameFromTick(
210 base::TimeTicks frame_time) {
211 base::TimeTicks deadline = time_source_->NextTickTime();
212 SendBeginFrame(BeginFrameArgs::Create(frame_time, deadline, VSyncInterval()));
213 }
214
215 // TimeSourceClient
216 void SyntheticBeginFrameSource::OnTimerTick() {
217 SendBeginFrameFromTick(time_source_->LastTickTime());
218 }
219
220 // BeginFrameSource
221 void SyntheticBeginFrameSource::SetNeedsBeginFrames(bool needs_begin_frames) {
222 base::TimeTicks missed_tick_time =
223 time_source_->SetActive(needs_begin_frames);
224 if (!missed_tick_time.is_null()) {
225 SendBeginFrameFromTick(missed_tick_time);
226 }
227 }
228
229 bool SyntheticBeginFrameSource::NeedsBeginFrames() {
230 return time_source_->Active();
231 }
232
233 // Tracing
234 void SyntheticBeginFrameSource::AsValueInto(
235 base::debug::TracedValue* dict) const {
236 dict->SetString("type", "SyntheticBeginFrameSource");
237 BeginFrameSource::AsValueInto(dict);
238
239 dict->BeginDictionary("last_frame_args");
240 time_source_->AsValueInto(dict);
241 dict->EndDictionary();
242 }
243
244 /*************************************************************************/
245
246 scoped_ptr<BeginFrameSourceMultiplexer> BeginFrameSourceMultiplexer::Create() {
247 return make_scoped_ptr(new BeginFrameSourceMultiplexer());
248 }
249
250 BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer()
251 : minimum_interval_(base::TimeDelta()),
252 active_source_(NULL),
253 source_list_() {
254 }
255
256 BeginFrameSourceMultiplexer::BeginFrameSourceMultiplexer(
257 base::TimeDelta minimum_interval)
258 : minimum_interval_(minimum_interval),
259 active_source_(NULL),
260 source_list_() {
261 }
262
263 BeginFrameSourceMultiplexer::~BeginFrameSourceMultiplexer() {
264 SetActiveSource(NULL);
265 }
266
267 void BeginFrameSourceMultiplexer::SetActiveSource(
268 BeginFrameSource* new_source) {
269 DCHECK(HasSource(new_source) || new_source == NULL);
270
271 bool needs_begin_frames = NeedsBeginFrames();
272
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 SendBeginFrame(args);
339 }
340
341 const BeginFrameArgs& BeginFrameSourceMultiplexer::LastBeginFrameArgs() const {
342 return observer_->LastBeginFrameArgs();
343 }
344
345 // BeginFrameSource
346 bool BeginFrameSourceMultiplexer::NeedsBeginFrames() {
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::FinishedFrame(size_t remaining_frames) {
363 active_source_->FinishedFrame(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 dict->BeginDictionary("active_source");
379 active_source_->AsValueInto(dict);
380 dict->EndDictionary();
381
382 for (std::set<BeginFrameSource*>::const_iterator it = source_list_.begin();
383 it != source_list_.end();
384 ++it) {
385 dict->BeginDictionary(
386 base::SizeTToString(std::distance(source_list_.begin(), it)).c_str());
387 (*it)->AsValueInto(dict);
388 dict->EndDictionary();
389 }
390 }
391
392 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698