OLD | NEW |
---|---|
(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 | |
OLD | NEW |