OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2011 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/scheduler.h" | |
6 | |
7 #include "base/debug/trace_event.h" | |
8 #include "base/logging.h" | |
9 #include "cc/scheduler/delay_based_time_source.h" | |
10 #include "ui/gfx/frame_time.h" | |
11 | |
12 namespace cc { | |
13 | |
14 class FrameSink { | |
15 public: | |
16 virtual void BeginFrame(BeginFrameArgs* args) = 0; | |
17 }; | |
18 | |
19 class FrameSource { | |
20 public: | |
21 FrameSource(FrameSink* sink) : sink_(sink) {} | |
22 virtual ~FrameSource() {} | |
23 | |
24 virtual void SetSink(FrameSink* sink) { sink_ = sink; } | |
25 | |
26 virtual void SendBeginFrame(BeginFrameArgs* args) { | |
27 DCHECK(sink_); | |
28 DCHECK(args); | |
29 sink_->BeginFrame(args); | |
30 } | |
31 | |
32 virtual void SetNeedsBeginFrame(bool needs_begin_frame) = 0; | |
33 | |
34 virtual void UpdateFrameSource(base::TimeTicks timebase, | |
35 base::TimeDelta interval) { | |
36 if (!interval.is_null()) | |
37 interval_ = interval; | |
38 } | |
39 | |
40 virtual scoped_ptr<base::Value> AsValue() const { | |
41 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue); | |
42 state->SetString("type", GetType()); | |
43 state->SetInteger("frame_source", this); | |
44 state->SetInteger("interval_us", interval_.InMicroseconds()); | |
45 return state.PassAs<base::Value>(); | |
46 } | |
47 | |
48 protected: | |
49 virtual std::string GetType() const = 0; | |
50 | |
51 base::TimeDelta interval_; | |
52 FrameSink* sink_; | |
53 }; | |
54 | |
55 /** | |
56 * A frame source which proxies BeginFrame from an external OutputSurface such | |
57 * as on Android. | |
58 */ | |
59 class ExternalFrameSource : public FrameSource { | |
60 public: | |
61 ExternalFrameSource(FrameSink* sink, SchedulerClient* client) | |
62 : client_(client), FrameSource(sink) { | |
63 DCHECK(client_); | |
64 } | |
65 virtual ~ExternalFrameSource() {} | |
66 | |
67 virtual void BeginFrame(BeginFrameArgs* args) { sink_->BeginFrame(args); } | |
68 | |
69 virtual void SetNeedsBeginFrame(bool needs_begin_frame) OVERRIDE { | |
70 DCHECK(client_); | |
71 client_->SetNeedsBeginFrame(needs_begin_frame); | |
72 } | |
73 | |
74 virtual scoped_ptr<base::Value> AsValue() const OVERRIDE { | |
75 scoped_ptr<base::DictionaryValue> state = FrameSource::AsValue(); | |
76 state->SetInteger("client", client_); | |
77 return state.PassAs<base::Value>(); | |
78 } | |
79 | |
80 protected: | |
81 virtual std::string GetType() const OVERRIDE { return "ExternalFrameSource"; } | |
82 | |
83 private: | |
84 SchedulerClient* client_; | |
85 }; | |
86 | |
87 /** | |
88 * A frame source which throttles down another begin frame source. | |
89 */ | |
90 class ThrottledFrameSource : public FrameSource, FrameSink { | |
brianderson
2014/05/05 16:50:05
In what cases would this class be used? Is this to
mithro-old
2014/05/05 17:10:53
Yes, examples I can think of are;
* Throttle an E
brianderson
2014/05/05 17:37:49
Cool. What would the interface look like to change
| |
91 public: | |
92 ThrottledFrameSource(FrameSink* sink, | |
93 const scoped_refptr<FrameSource>& source, | |
94 base::TimeDelta interval) | |
95 : source_(source), | |
96 interval_(interval), | |
97 last_frame_args_(), | |
98 FrameSource(sink) { | |
99 source_->SetSink(this); | |
100 } | |
101 virtual ~ThrottledFrameSource() {} | |
102 | |
103 virtual void BeginFrame(BeginFrameArgs* args) OVERRIDE { | |
104 if (last_frame_args_.frame_time + interval_ > args.frame_time) | |
105 return; | |
106 source_->SendBeginFrame(sink, args); | |
107 } | |
108 | |
109 virtual void SetNeedsBeginFrame(bool needs_begin_frame) OVERRIDE { | |
110 source_->SetNeedsBeginFrame(needs_begin_frame); | |
111 } | |
112 | |
113 virtual scoped_ptr<base::Value> AsValue() const OVERRIDE { | |
114 scoped_ptr<base::DictionaryValue> state = FrameSource::AsValue(); | |
115 state->SetValue("source", source_->AsValue().release()); | |
116 return state.PassAs<base::Value>(); | |
117 } | |
118 | |
119 protected: | |
120 virtual std::string GetType() const OVERRIDE { | |
121 return "ThrottledFrameSource"; | |
122 } | |
123 | |
124 private: | |
125 BeginFrameArgs last_frame_args_; | |
126 scoped_refptr<base::FrameSource> source_; | |
127 }; | |
128 | |
129 /** | |
130 * Frame source which needs a task runner object. | |
131 */ | |
132 class TaskRunnerFrameSource : public FrameSource { | |
133 public: | |
134 TaskRunnerFrameSource(FrameSink* sink, | |
135 base::SingleThreadTaskRunner* task_runner) | |
136 : task_runner_(task_runner), FrameSource(sink) { | |
137 DCHECK(task_runner); | |
138 } | |
139 virtual ~TaskRunnerFrameSource() {} | |
140 | |
141 protected: | |
142 base::SingleThreadTaskRunner task_runner_; | |
143 }; | |
144 | |
145 /** | |
146 * A frame source which sends a BeginFrame as soon as SetNeedsBeginFrame is | |
147 * requested. | |
148 */ | |
149 class BackToBackFrameSource : public TaskRunnerFrameSource { | |
brianderson
2014/05/05 16:50:05
Would this be used as the "vsync disabled" BeginFr
mithro-old
2014/05/05 17:10:53
Is there any reason we want to keep it level trigg
brianderson
2014/05/05 17:37:49
It is level triggered at the interface between the
| |
150 public: | |
151 virtual void SetNeedsBeginFrame(bool needs_begin_frame) OVERRIDE { | |
152 if (needs_begin_frame) { | |
153 task_runner_->PostDelayedTask( | |
154 FROM_HERE, | |
155 base::Bind(&BackToBackFrameSource::PostBeginFrame, | |
156 weak_factory_.GetWeakPtr())); | |
157 } | |
158 } | |
159 | |
160 void PostBeginFrame() { | |
161 base::TimeTicks now = gfx::FrameTime::Now(); | |
162 BeginFrameArgs begin_frame_args = | |
163 BeginFrameArgs::Create(now, base::TimeTicks(), base::TimeDelta()); | |
164 FrameSource::SendBeginFrame(args); | |
165 } | |
166 | |
167 protected: | |
168 virtual std::string GetType() const OVERRIDE { | |
169 return "BackToBackFrameSource"; | |
170 } | |
171 }; | |
172 | |
173 /** | |
174 * A frame source which is locked an external vsync source and generates | |
175 * BeginFrameArgs for it. | |
176 */ | |
177 class SyntheticFrameSource : public TaskRunnerFrameSource, | |
178 public TimeSourceClient { | |
179 public: | |
180 SyntheticFrameSource(FrameSink* sink, | |
181 base::SingleThreadTaskRunner* task_runner) | |
182 : TaskRunnerFrameSource(sink, task_runner) { | |
183 if (gfx::FrameTime::TimestampsAreHighRes()) { | |
184 time_source_ = DelayBasedTimeSourceHighRes::Create(sink_->VSyncInterval(), | |
185 task_runner); | |
186 } else { | |
187 time_source_ = | |
188 DelayBasedTimeSource::Create(sink_->VSyncInterval(), task_runner); | |
189 } | |
190 time_source_->SetClient(this); | |
191 } | |
192 virtual ~SyntheticFrameSource() {} | |
193 | |
194 // Activates future BeginFrames and, if activating, pushes the most | |
195 // recently missed BeginFrame to the back of a retroactive queue. | |
196 void SetNeedsBeginFrame(bool needs_begin_frame) OVERRIDE { | |
197 base::TimeTicks missed_tick_time = | |
198 time_source_->SetActive(needs_begin_frame); | |
199 if (!missed_tick_time.is_null()) { | |
200 BaseFrameSource::SendBeginFrame( | |
201 CreateSyntheticBeginFrameArgs(missed_tick_time)); | |
202 } | |
203 } | |
204 | |
205 // Updates the phase and frequency of the timer. | |
206 virtual void UpdateFrameSource(base::TimeTicks timebase, | |
207 base::TimeDelta interval) OVERRIDE { | |
208 TaskRunnerFrameSource::UpdateFrameSource(timebase, interval); | |
209 time_source_->SetTimebaseAndInterval(timebase, interval); | |
210 } | |
211 | |
212 virtual scoped_ptr<base::Value> AsValue() const OVERRIDE { | |
213 scoped_ptr<base::DictionaryValue> state = FrameSource::AsValue(); | |
214 state->SetValue("source", source_->AsValue().release()); | |
215 return state.PassAs<base::Value>(); | |
216 } | |
217 | |
218 // TimeSourceClient implementation of OnTimerTick triggers a BeginFrame. | |
219 virtual void OnTimerTick() OVERRIDE { | |
220 BeginFrameArgs begin_frame_args( | |
221 CreateSyntheticBeginFrameArgs(time_source_->LastTickTime())); | |
222 SendBeginFrame(begin_frame_args); | |
223 } | |
224 | |
225 protected: | |
226 virtual std::string GetType() const OVERRIDE { | |
227 return "SyntheticFrameSource"; | |
228 } | |
229 | |
230 private: | |
231 FrameSink* sink_; | |
232 scoped_refptr<TimeSource> time_source_; | |
233 | |
234 BeginFrameArgs CreateSyntheticBeginFrameArgs(base::TimeTicks frame_time) { | |
235 base::TimeTicks deadline = | |
236 time_source_->NextTickTime() - sink_->EstimatedParentDrawTime(); | |
237 return BeginFrameArgs::Create(frame_time, deadline, interval_); | |
238 } | |
239 }; | |
240 | |
241 /** | |
242 * A virtual frame source which lets you switch between two other frame sources | |
243 * (making sure the BeginFrameArgs stays monotonic). | |
244 */ | |
245 class DualFrameSource : public FrameSource, public FrameSink { | |
brianderson
2014/05/05 16:50:05
Is this going to be used to switch between backgro
mithro-old
2014/05/05 17:10:53
Yeah. The thought here was to allow switching betw
| |
246 public: | |
247 DualFrameSource(FrameSink* sink, | |
248 const scoped_refptr<FrameSource>& source_primary, | |
249 const scoped_refptr<FrameSource>& source_secondary) | |
250 : source_primary_(source_primary), | |
251 source_secondary_(source_secondary), | |
252 needs_begin_frame_(false), | |
253 last_frame_args_() { | |
254 source_primary_->SetSink(this); | |
255 source_secondary_->SetSink(this); | |
256 SwitchSource(SourcePrimary()); | |
257 } | |
258 | |
259 virtual void BeginFrame(BeginFrameArgs* args) OVERRIDE { | |
260 // When switching clock sources you can get a BeginFrameArgs with a | |
261 // frame_time before the last value. | |
262 if (last_frame_args_.frame_time > args.frame_time) | |
263 args.frame_time = last_frame_args_.frame_time; | |
264 | |
265 FrameSource::SendBeginFrame(args); | |
266 last_frame_args_ = args; | |
267 } | |
268 | |
269 virtual void SetNeedsBeginFrame(bool needs_begin_frame) OVERRIDE { | |
270 DCHECK(active_source_); | |
271 needs_begin_frame_ = needs_begin_frame; | |
272 active_source_->SetNeedsBeginFrame(needs_begin_frame); | |
273 } | |
274 | |
275 virtual scoped_ptr<base::Value> AsValue() const OVERRIDE { | |
276 scoped_ptr<base::DictionaryValue> state = FrameSource::AsValue(); | |
277 if (active_source_ == SourcePrimary()) | |
278 state->SetString("active", "primary"); | |
279 if (active_source_ == SourceSecondary()) | |
280 state->SetString("active", "secondary"); | |
281 state->SetValue("primary", source_primary_->AsValue().release()); | |
282 state->SetValue("secondary", source_secondary_->AsValue().release()); | |
283 state->SetValue("last_frame_args", last_frame_args_->AsValue().release()); | |
284 return state.PassAs<base::Value>(); | |
285 } | |
286 | |
287 // --------------------------------------------------------------------- | |
288 | |
289 void SwitchSource(base::FrameSource* new_source) { | |
290 DCHECK(new_source == SourcePrimary() || new_source == SourceSecondary()); | |
291 | |
292 if (needs_begin_frame_) | |
293 active_source_.SetNeedsBeginFrame(false); | |
294 | |
295 active_source_ = new_source; | |
296 | |
297 if (needs_begin_frame_) | |
298 active_source_.SetNeedsBeginFrame(true); | |
299 } | |
300 | |
301 base::FrameSource* SourcePrimary() { return source_primary_.get(); } | |
302 | |
303 base::FrameSource* SourceSecondary() { return source_secondary_.get(); } | |
304 | |
305 protected: | |
306 virtual std::string GetType() const OVERRIDE { | |
307 return std::string("DualFrameSource"); | |
308 } | |
309 | |
310 private: | |
311 bool needs_begin_frame_; | |
312 BeginFrameArgs last_frame_args_; | |
313 base::FrameSource* active_source_; | |
314 scoped_refptr<base::FrameSource> source_primary_; | |
315 scoped_refptr<base::FrameSource> source_secondary_; | |
316 }; | |
317 | |
318 } // namespace cc | |
OLD | NEW |