Chromium Code Reviews

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: Rebasing onto master. Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | | 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/logging.h"
9 #include "cc/scheduler/delay_based_time_source.h"
simonhong 2014/06/12 13:47:39 All above includes are duplicated with frame_sourc
10 #include "cc/scheduler/scheduler.h"
simonhong 2014/06/12 13:47:39 Scheduler class is not referenced in this file. Ca
11 #include "ui/gfx/frame_time.h"
simonhong 2014/06/12 13:47:38 ditto.
12
13 #define FRAMESOURCE_TYPESTRING(x) \
14 std::string x::TypeString() const { return #x; }
15
16 namespace cc {
17
18 BaseBeginFrameSource::BaseBeginFrameSource(BeginFrameSink* sink)
19 : frame_sink_(sink),
20 generate_frames_(false),
21 timebase_(),
simonhong 2014/06/12 13:47:39 can be removed.
22 interval_(BeginFrameArgs::DefaultInterval()) {
23 }
24
25 // BeginFrameSource ------------------------------------------------------
26 void BaseBeginFrameSource::SetBeginFrameSink(BeginFrameSink* sink) {
27 DCHECK(sink);
28 frame_sink_ = sink;
29 }
30 BeginFrameSink* BaseBeginFrameSource::GetBeginFrameSink() const {
31 DCHECK(frame_sink_);
32 return frame_sink_;
33 }
34
35 void BaseBeginFrameSource::SetGenerateFrames(bool generate_frames) {
36 if (generate_frames_ != generate_frames) {
37 OnGenerateChange(generate_frames);
38 generate_frames_ = generate_frames;
39 }
40 }
41
42 bool BaseBeginFrameSource::IsGeneratingFrames() const {
43 return generate_frames_;
44 }
45
46 void BaseBeginFrameSource::PendingFrames(size_t count) {
47 OnPendingFrames(count);
48 }
49
50 void BaseBeginFrameSource::SetTimeBaseAndInterval(
51 const base::TimeTicks timebase,
52 const base::TimeDelta interval) {
53 base::TimeDelta newinterval = interval;
54 if (newinterval == base::TimeDelta())
55 newinterval = BeginFrameArgs::DefaultInterval();
56
57 OnTimeBaseAndIntervalChange(timebase, newinterval);
58
59 timebase_ = timebase;
60 interval_ = newinterval;
61 }
62
63 base::TimeTicks BaseBeginFrameSource::TimeBase() const {
64 return timebase_;
65 }
66
67 base::TimeDelta BaseBeginFrameSource::Interval() const {
68 return interval_;
69 }
70
71 scoped_ptr<base::Value> BaseBeginFrameSource::BeginFrameSourceAsValue() const {
72 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue);
73 state->SetString("type", TypeString());
74 state->SetInteger("frame_source", reinterpret_cast<size_t>(this));
75 state->SetBoolean("generate_frames", generate_frames_);
76 state->SetDouble("timebase_us", timebase_.ToInternalValue());
77 state->SetDouble("interval_us", interval_.InMicroseconds());
78
79 ExtraAsValue(state.get());
80
81 return state.PassAs<base::Value>();
82 }
83
84 /*************************************************************************
85 *
86 */
87 ProxyBeginFrameSource::ProxyBeginFrameSource(BeginFrameSink* sink,
88 BeginFrameSource* source)
89 : BaseBeginFrameSource(sink), source_(source) {
90 DCHECK(source_);
91 source_->SetBeginFrameSink(this);
92 }
93
94 // BeginFrameSink --------------------------------------------------------
95 void ProxyBeginFrameSource::BeginFrame(const BeginFrameArgs& args) {
96 frame_sink_->BeginFrame(args);
97 }
98
99 // BaseBeginFrameSource ---------------------------------------------------
100
101 FRAMESOURCE_TYPESTRING(ProxyBeginFrameSource);
102
103 void ProxyBeginFrameSource::ExtraAsValue(base::DictionaryValue* state) const {
104 state->Set("source", source_->BeginFrameSourceAsValue().release());
105 }
106
107 void ProxyBeginFrameSource::OnGenerateChange(bool generate_frames) {
108 DCHECK(source_);
simonhong 2014/06/12 13:47:39 DCHECK can be removed because we don't erase or ch
109 source_->SetGenerateFrames(generate_frames);
110 }
111
112 void ProxyBeginFrameSource::OnPendingFrames(size_t count) {
113 DCHECK(source_);
simonhong 2014/06/12 13:47:39 ditto.
114 source_->PendingFrames(count);
115 }
116
117 void ProxyBeginFrameSource::OnTimeBaseAndIntervalChange(
118 const base::TimeTicks timebase,
119 const base::TimeDelta interval) {
120 DCHECK(source_);
simonhong 2014/06/12 13:47:39 ditto.
121 source_->SetTimeBaseAndInterval(timebase, interval);
122 }
123
124 /*************************************************************************
125 *
126 */
127 ThrottledBeginFrameSource::ThrottledBeginFrameSource(BeginFrameSink* sink,
128 BeginFrameSource* source,
129 base::TimeDelta interval)
130 : ProxyBeginFrameSource(sink, source), last_frame_args_() {
131 interval_ = interval;
132 }
133
134 // BeginFrameSink --------------------------------------------------------
135 void ThrottledBeginFrameSource::BeginFrame(const BeginFrameArgs& args) {
136 if (last_frame_args_.IsValid() &&
137 last_frame_args_.frame_time + interval_ > args.frame_time)
138 return;
139 last_frame_args_ = args;
140 frame_sink_->BeginFrame(args);
141 }
142
143 // BeginFrameSource ------------------------------------------------------
144
145 FRAMESOURCE_TYPESTRING(ThrottledBeginFrameSource)
146
147 void ThrottledBeginFrameSource::ExtraAsValue(
148 base::DictionaryValue* state) const {
149 state->Set("source", source_->BeginFrameSourceAsValue().release());
150 state->Set("last_frame_args", last_frame_args_.AsValue().release());
151 }
152
153 /*************************************************************************/
154 BackToBackBeginFrameSource::BackToBackBeginFrameSource(
155 BeginFrameSink* sink,
156 base::SingleThreadTaskRunner* task_runner)
157 : BaseBeginFrameSource(sink),
158 weak_factory_(this),
159 task_runner_(task_runner),
160 send_begin_frame_posted_(false) {
161 DCHECK(task_runner);
162 }
163
164 BackToBackBeginFrameSource::~BackToBackBeginFrameSource() {
165 }
166
167 void BackToBackBeginFrameSource::ScheduleSendBeginFrameArgs() {
168 if (!generate_frames_)
169 return;
170
171 if (send_begin_frame_posted_)
172 return;
173
174 send_begin_frame_posted_ = true;
175 task_runner_->PostTask(
176 FROM_HERE,
177 base::Bind(&BackToBackBeginFrameSource::SendBeginFrameArgs,
178 weak_factory_.GetWeakPtr()));
179 }
180
181 void BackToBackBeginFrameSource::SendBeginFrameArgs() {
182 send_begin_frame_posted_ = false;
183
184 // TODO(mithro): Fix the tests so this can be enabled. The tests currently
185 // depend on one begin frame firing after generate_frames_ is set false.
186 // if (!generate_frames_) {
187 // return;
188 // }
189
190 base::TimeTicks now = gfx::FrameTime::Now();
191 // TODO(mithro): Is a deadline of now+interval_ sane?
192 BeginFrameArgs args = BeginFrameArgs::Create(now, now + interval_, interval_);
193 frame_sink_->BeginFrame(args);
194 }
195
196 // BeginFrameSource ------------------------------------------------------
197
198 FRAMESOURCE_TYPESTRING(BackToBackBeginFrameSource);
199
200 void BackToBackBeginFrameSource::ExtraAsValue(
201 base::DictionaryValue* state) const {
202 state->SetBoolean("send_begin_frame_posted_", send_begin_frame_posted_);
203 }
204
205 void BackToBackBeginFrameSource::OnGenerateChange(bool generate_frames) {
206 ScheduleSendBeginFrameArgs();
207 }
208
209 void BackToBackBeginFrameSource::OnPendingFrames(size_t count) {
210 if (count == 0) {
211 ScheduleSendBeginFrameArgs();
212 }
213 }
214
215 /*************************************************************************/
216 SyntheticBeginFrameSource::SyntheticBeginFrameSource(
217 BeginFrameSink* sink,
218 base::SingleThreadTaskRunner* task_runner,
219 base::TimeDelta interval)
220 : BaseBeginFrameSource(sink), task_runner_(task_runner) {
221 DCHECK(task_runner);
222 interval_ = interval;
223 if (gfx::FrameTime::TimestampsAreHighRes()) {
224 time_source_ = DelayBasedTimeSourceHighRes::Create(interval_, task_runner);
225 } else {
226 time_source_ = DelayBasedTimeSource::Create(interval_, task_runner);
227 }
228 time_source_->SetActive(false);
simonhong 2014/06/12 13:47:39 time_source_ is set to inactive when it is initial
229 time_source_->SetClient(this);
230 }
231
232 SyntheticBeginFrameSource::~SyntheticBeginFrameSource() {
233 time_source_->SetActive(false);
234 }
235
236 BeginFrameArgs SyntheticBeginFrameSource::CreateBeginFrameArgs(
237 base::TimeTicks frame_time) {
238 base::TimeTicks deadline = time_source_->NextTickTime();
239 return BeginFrameArgs::Create(frame_time, deadline, interval_);
240 }
241
242 // TimeSourceClient ------------------------------------------------------
243
244 void SyntheticBeginFrameSource::OnTimerTick() {
245 frame_sink_->BeginFrame(CreateBeginFrameArgs(time_source_->LastTickTime()));
246 }
247
248 // BeginFrameSource ------------------------------------------------------
249
250 FRAMESOURCE_TYPESTRING(SyntheticBeginFrameSource);
251
252 void SyntheticBeginFrameSource::ExtraAsValue(
253 base::DictionaryValue* state) const {
254 state->Set("time_source", time_source_->AsValue().release());
255 }
256
257 void SyntheticBeginFrameSource::OnGenerateChange(bool generate_frames) {
258 base::TimeTicks missed_tick_time = time_source_->SetActive(generate_frames);
259 if (!missed_tick_time.is_null()) {
simonhong 2014/06/12 13:47:38 Generally, curly braces are not required for singl
260 frame_sink_->BeginFrame(CreateBeginFrameArgs(missed_tick_time));
261 }
262 }
263
264 void SyntheticBeginFrameSource::OnTimeBaseAndIntervalChange(
265 const base::TimeTicks timebase,
266 const base::TimeDelta interval) {
267 time_source_->SetTimebaseAndInterval(timebase, interval);
268 }
269
270 /*************************************************************************
271 * A virtual frame source which lets you switch between two other frame sources
272 * (making sure the BeginFrameArgs stays monotonic).
273 */
274 DualBeginFrameSource::DualBeginFrameSource(
275 BeginFrameSink* sink,
276 scoped_ptr<BeginFrameSource> source_primary,
277 scoped_ptr<BeginFrameSource> source_secondary)
278 : BaseBeginFrameSource(sink),
279 last_frame_args_(),
280 source_foreground_(source_primary.Pass()),
281 source_background_(source_secondary.Pass()) {
282 source_foreground_->SetBeginFrameSink(this);
283 source_background_->SetBeginFrameSink(this);
284 SwitchSource(SourceForeground());
285 }
286
287 DualBeginFrameSource::~DualBeginFrameSource() {
288 }
289
290 void DualBeginFrameSource::SwitchSource(const BeginFrameSource* new_source) {
291 DCHECK(new_source == SourceForeground() || new_source == SourceBackground());
292
293 if (generate_frames_)
294 active_source_->SetGenerateFrames(false);
295
296 active_source_ = const_cast<BeginFrameSource*>(new_source);
297
298 if (generate_frames_)
299 active_source_->SetGenerateFrames(true);
300 }
301
302 const BeginFrameSource* DualBeginFrameSource::SourceForeground() const {
303 return source_foreground_.get();
304 }
305
306 const BeginFrameSource* DualBeginFrameSource::SourceBackground() const {
307 return source_background_.get();
308 }
309
310 // BeginFrameSink ------------------------------------------------------
311
312 void DualBeginFrameSource::BeginFrame(const BeginFrameArgs& args) {
313 // When switching clock sources you can get a BeginFrameArgs with a
314 // frame_time before the last value.
315 BeginFrameArgs new_args = args;
316 if (last_frame_args_.frame_time > new_args.frame_time)
317 return;
318
319 last_frame_args_ = new_args;
320 frame_sink_->BeginFrame(new_args);
321 }
322
323 // BeginFrameSource ----------------------------------------------------
324
325 FRAMESOURCE_TYPESTRING(DualBeginFrameSource)
326
327 void DualBeginFrameSource::ExtraAsValue(base::DictionaryValue* state) const {
328 state->Set("last_frame_args", last_frame_args_.AsValue().release());
329 if (active_source_ == SourceForeground())
330 state->SetString("active", "primary");
331 if (active_source_ == SourceBackground())
332 state->SetString("active", "secondary");
333 state->Set("primary",
334 source_foreground_->BeginFrameSourceAsValue().release());
335 state->Set("secondary",
336 source_background_->BeginFrameSourceAsValue().release());
337 }
338
339 void DualBeginFrameSource::OnPendingFrames(size_t count) {
340 active_source_->PendingFrames(count);
341 }
342
343 void DualBeginFrameSource::OnGenerateChange(bool generate_frames) {
344 DCHECK(active_source_);
345 active_source_->SetGenerateFrames(generate_frames);
346 }
347
348 void DualBeginFrameSource::OnTimeBaseAndIntervalChange(
349 const base::TimeTicks timebase,
350 const base::TimeDelta interval) {
351 DCHECK_EQ(active_source_, source_foreground_); // TODO(mithro): Is this okay?
352 source_foreground_->SetTimeBaseAndInterval(timebase, interval);
353 }
354
355 } // namespace cc
OLDNEW

Powered by Google App Engine