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" | |
10 #include "cc/scheduler/scheduler.h" | |
11 #include "ui/gfx/frame_time.h" | |
12 | |
13 #define FRAMESOURCE_GETTYPE(x) \ | |
14 std::string x::FrameSourceType() const { return #x; } | |
15 | |
16 namespace cc { | |
17 | |
18 BaseFrameSource::BaseFrameSource(FrameSink* sink) : frame_sink_(sink) { | |
19 } | |
20 | |
21 void BaseFrameSource::SetSink(FrameSink* sink) { | |
22 frame_sink_ = sink; | |
23 } | |
24 | |
25 void BaseFrameSource::SendBeginFrame(const BeginFrameArgs& args) { | |
26 DCHECK(frame_sink_); | |
27 frame_sink_->BeginFrame(args); | |
28 } | |
29 | |
30 void BaseFrameSource::SetTimeBaseAndInterval(base::TimeTicks timebase, | |
31 base::TimeDelta interval) { | |
32 if (interval != base::TimeDelta()) | |
33 interval_ = interval; | |
34 } | |
35 | |
36 scoped_ptr<base::Value> BaseFrameSource::FrameSourceAsValue() const { | |
37 return BaseFrameSourceAsValue().PassAs<base::Value>(); | |
38 } | |
39 | |
40 scoped_ptr<base::DictionaryValue> BaseFrameSource::BaseFrameSourceAsValue() | |
41 const { | |
42 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue); | |
43 state->SetString("type", FrameSourceType()); | |
44 state->SetInteger("frame_source", reinterpret_cast<size_t>(this)); | |
45 state->SetInteger("interval_us", interval_.InMicroseconds()); | |
46 return state.PassAs<base::DictionaryValue>(); | |
47 } | |
48 | |
49 /** | |
50 * | |
51 */ | |
52 FRAMESOURCE_GETTYPE(ProxyFrameSource); | |
53 | |
54 ProxyFrameSource::ProxyFrameSource(FrameSink* sink, FrameSource* source) | |
55 : BaseFrameSource(sink), source_(source) { | |
56 DCHECK(source_); | |
57 source->SetSink(this); | |
58 } | |
59 | |
60 void ProxyFrameSource::BeginFrame(const BeginFrameArgs& args) { | |
61 TRACE_EVENT0("frame_time", "ProxyFrameSource::BeginFrame"); | |
62 SendBeginFrame(args); | |
63 } | |
64 | |
65 void ProxyFrameSource::SetNeedsBeginFrame(bool needs_begin_frame) { | |
66 DCHECK(source_); | |
67 source_->SetNeedsBeginFrame(needs_begin_frame); | |
68 } | |
69 | |
70 scoped_ptr<base::Value> ProxyFrameSource::FrameSourceAsValue() const { | |
71 scoped_ptr<base::DictionaryValue> state = | |
72 BaseFrameSource::BaseFrameSourceAsValue(); | |
73 state->Set("source", source_->FrameSourceAsValue().release()); | |
74 return state.PassAs<base::Value>(); | |
75 } | |
76 | |
77 void ProxyFrameSource::SetTimeBaseAndInterval(base::TimeTicks timebase, | |
78 base::TimeDelta interval) { | |
79 source_->SetTimeBaseAndInterval(timebase, interval); | |
80 } | |
81 | |
82 /** | |
83 * | |
84 */ | |
85 FRAMESOURCE_GETTYPE(ThrottledFrameSource) | |
86 | |
87 ThrottledFrameSource::ThrottledFrameSource(FrameSink* sink, | |
88 scoped_ptr<FrameSource> source, | |
89 base::TimeDelta interval) | |
90 : BaseFrameSource(sink), last_frame_args_(), source_(source.Pass()) { | |
91 interval_ = interval; | |
92 DCHECK(source_); | |
93 source_->SetSink(this); | |
94 } | |
95 | |
96 ThrottledFrameSource::~ThrottledFrameSource() { | |
97 } | |
98 | |
99 void ThrottledFrameSource::BeginFrame(const BeginFrameArgs& args) { | |
100 if (last_frame_args_.IsValid() && | |
101 last_frame_args_.frame_time + interval_ > args.frame_time) | |
102 return; | |
103 last_frame_args_ = args; | |
104 SendBeginFrame(args); | |
105 } | |
106 | |
107 void ThrottledFrameSource::SetNeedsBeginFrame(bool needs_begin_frame) { | |
108 source_->SetNeedsBeginFrame(needs_begin_frame); | |
109 } | |
110 | |
111 void ThrottledFrameSource::SetTimeBaseAndInterval(base::TimeTicks timebase, | |
112 base::TimeDelta interval) { | |
113 source_->SetTimeBaseAndInterval(timebase, interval); | |
114 } | |
115 | |
116 scoped_ptr<base::Value> ThrottledFrameSource::FrameSourceAsValue() const { | |
117 scoped_ptr<base::DictionaryValue> state = | |
118 BaseFrameSource::BaseFrameSourceAsValue(); | |
119 state->Set("source", source_->FrameSourceAsValue().release()); | |
120 state->Set("last_frame_args", last_frame_args_.AsValue().release()); | |
121 return state.PassAs<base::Value>(); | |
122 } | |
123 | |
124 /** | |
125 * | |
126 */ | |
127 TaskRunnerFrameSource::TaskRunnerFrameSource( | |
128 FrameSink* sink, | |
129 base::SingleThreadTaskRunner* task_runner) | |
130 : BaseFrameSource(sink), task_runner_(task_runner) { | |
131 DCHECK(task_runner); | |
132 } | |
133 | |
134 /** | |
135 * A frame source which sends a BeginFrame as soon as SetNeedsBeginFrame is | |
136 * requested. | |
137 */ | |
138 FRAMESOURCE_GETTYPE(BackToBackFrameSource) | |
139 | |
140 BackToBackFrameSource::BackToBackFrameSource( | |
141 FrameSink* sink, | |
142 base::SingleThreadTaskRunner* task_runner) | |
143 : TaskRunnerFrameSource(sink, task_runner) { | |
144 } | |
145 | |
146 void BackToBackFrameSource::SetNeedsBeginFrame(bool needs_begin_frame) { | |
147 if (needs_begin_frame) { | |
brianderson
2014/05/07 17:20:16
Which solution are you leaning towards for solving
mithro-old
2014/05/07 22:02:32
Yeah, I'm leaning towards the ReadyForNextBeginFra
brianderson
2014/05/08 21:08:15
I've changed my mind here. Let's just keep the sin
mithro-old
2014/05/09 02:45:58
Are you saying that SetNeedsBeginFrame should be e
| |
148 /* task_runner_->PostDelayedTask( | |
149 FROM_HERE, | |
150 base::Bind(&BackToBackFrameSource::PostBeginFrame, | |
151 this)); */ | |
152 } | |
153 } | |
154 | |
155 void BackToBackFrameSource::PostBeginFrame() { | |
156 base::TimeTicks now = gfx::FrameTime::Now(); | |
157 BeginFrameArgs args = | |
158 BeginFrameArgs::Create(now, base::TimeTicks(), base::TimeDelta()); | |
159 SendBeginFrame(args); | |
160 } | |
161 | |
162 /** | |
163 * | |
164 */ | |
165 | |
166 SyntheticFrameSource::~SyntheticFrameSource() { | |
167 } | |
168 | |
169 FRAMESOURCE_GETTYPE(SyntheticFrameSource); | |
170 SyntheticFrameSource::SyntheticFrameSource( | |
171 FrameSink* sink, | |
172 base::SingleThreadTaskRunner* task_runner, | |
173 base::TimeDelta interval) | |
174 : TaskRunnerFrameSource(sink, task_runner) { | |
175 interval_ = interval; | |
176 if (gfx::FrameTime::TimestampsAreHighRes()) { | |
177 time_source_ = DelayBasedTimeSourceHighRes::Create(interval_, task_runner); | |
178 } else { | |
179 time_source_ = DelayBasedTimeSource::Create(interval_, task_runner); | |
180 } | |
181 time_source_->SetClient(this); | |
182 } | |
183 | |
184 // Activates future BeginFrames and, if activating, pushes the most | |
185 // recently missed BeginFrame to the back of a retroactive queue. | |
186 void SyntheticFrameSource::SetNeedsBeginFrame(bool needs_begin_frame) { | |
187 base::TimeTicks missed_tick_time = time_source_->SetActive(needs_begin_frame); | |
188 if (!missed_tick_time.is_null()) { | |
189 BeginFrameArgs args(CreateSyntheticBeginFrameArgs(missed_tick_time)); | |
190 SendBeginFrame(args); | |
191 } | |
192 } | |
193 | |
194 // Updates the phase and frequency of the timer. | |
195 void SyntheticFrameSource::SetTimeBaseAndInterval(base::TimeTicks timebase, | |
196 base::TimeDelta interval) { | |
197 TaskRunnerFrameSource::SetTimeBaseAndInterval(timebase, interval); | |
198 time_source_->SetTimebaseAndInterval(timebase, interval); | |
199 } | |
200 | |
201 scoped_ptr<base::Value> SyntheticFrameSource::FrameSourceAsValue() const { | |
202 scoped_ptr<base::DictionaryValue> state = | |
203 BaseFrameSource::BaseFrameSourceAsValue(); | |
204 // state->Set("source", source_->FrameSourceAsValue().Pass()); | |
205 return state.PassAs<base::Value>(); | |
206 } | |
207 | |
208 // TimeSourceClient implementation of OnTimerTick triggers a BeginFrame. | |
209 void SyntheticFrameSource::OnTimerTick() { | |
210 BeginFrameArgs args( | |
211 CreateSyntheticBeginFrameArgs(time_source_->LastTickTime())); | |
212 SendBeginFrame(args); | |
213 } | |
214 | |
215 BeginFrameArgs SyntheticFrameSource::CreateSyntheticBeginFrameArgs( | |
216 base::TimeTicks frame_time) { | |
217 base::TimeTicks deadline = | |
218 time_source_->NextTickTime(); // scheduler_->EstimatedParentDrawTime(); | |
219 return BeginFrameArgs::Create( | |
220 frame_time, deadline, interval_); // scheduler_->VSyncInterval()); | |
221 } | |
222 | |
223 /** | |
224 * A virtual frame source which lets you switch between two other frame sources | |
225 * (making sure the BeginFrameArgs stays monotonic). | |
226 */ | |
227 FRAMESOURCE_GETTYPE(DualFrameSource) | |
228 | |
229 DualFrameSource::DualFrameSource(FrameSink* sink, | |
230 scoped_ptr<FrameSource> source_primary, | |
231 scoped_ptr<FrameSource> source_secondary) | |
232 : BaseFrameSource(sink), | |
233 needs_begin_frame_(false), | |
234 last_frame_args_(), | |
235 source_primary_(source_primary.Pass()), | |
236 source_secondary_(source_secondary.Pass()) { | |
237 source_primary_->SetSink(this); | |
238 source_secondary_->SetSink(this); | |
239 SwitchSource(SourcePrimary()); | |
240 } | |
241 | |
242 DualFrameSource::~DualFrameSource() { | |
243 } | |
244 | |
245 void DualFrameSource::BeginFrame(const BeginFrameArgs& args) { | |
246 // When switching clock sources you can get a BeginFrameArgs with a | |
247 // frame_time before the last value. | |
248 BeginFrameArgs new_args = args; | |
249 if (last_frame_args_.frame_time > new_args.frame_time) | |
250 return; | |
251 | |
252 last_frame_args_ = new_args; | |
253 BaseFrameSource::SendBeginFrame(new_args); | |
254 } | |
255 | |
256 void DualFrameSource::SetNeedsBeginFrame(bool needs_begin_frame) { | |
257 DCHECK(active_source_); | |
258 needs_begin_frame_ = needs_begin_frame; | |
259 active_source_->SetNeedsBeginFrame(needs_begin_frame); | |
260 } | |
261 | |
262 scoped_ptr<base::Value> DualFrameSource::FrameSourceAsValue() const { | |
263 scoped_ptr<base::DictionaryValue> state = | |
264 BaseFrameSource::BaseFrameSourceAsValue(); | |
265 if (active_source_ == SourcePrimary()) | |
266 state->SetString("active", "primary"); | |
267 if (active_source_ == SourceSecondary()) | |
268 state->SetString("active", "secondary"); | |
269 state->Set("primary", source_primary_->FrameSourceAsValue().release()); | |
270 state->Set("secondary", source_secondary_->FrameSourceAsValue().release()); | |
271 state->Set("last_frame_args", last_frame_args_.AsValue().release()); | |
272 return state.PassAs<base::Value>(); | |
273 } | |
274 | |
275 // --------------------------------------------------------------------- | |
276 | |
277 void DualFrameSource::SwitchSource(const FrameSource* new_source) { | |
278 DCHECK(new_source == SourcePrimary() || new_source == SourceSecondary()); | |
brianderson
2014/05/07 17:20:16
Can we avoid exposing the underlying frame sources
mithro-old
2014/05/07 22:02:32
I originally started with an enum.
After adding t
brianderson
2014/05/08 00:55:58
Do we need to expose the underlying sources at all
mithro-old
2014/05/09 02:45:58
As the DualFrameSource takes ownership of the sour
| |
279 | |
280 if (needs_begin_frame_) | |
281 active_source_->SetNeedsBeginFrame(false); | |
282 | |
283 active_source_ = const_cast<FrameSource*>(new_source); | |
284 | |
285 if (needs_begin_frame_) | |
286 active_source_->SetNeedsBeginFrame(true); | |
287 } | |
288 | |
289 const FrameSource* DualFrameSource::SourcePrimary() const { | |
290 return source_primary_.get(); | |
291 } | |
292 | |
293 const FrameSource* DualFrameSource::SourceSecondary() const { | |
294 return source_secondary_.get(); | |
295 } | |
296 | |
297 } // namespace cc | |
OLD | NEW |