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

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: Scheduler tests now pass and the code is cleaner. Created 6 years, 6 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
« no previous file with comments | « cc/scheduler/frame_source.h ('k') | cc/scheduler/frame_source_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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"
10 #include "cc/scheduler/scheduler.h"
11 #include "ui/gfx/frame_time.h"
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_(),
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_);
109 source_->SetGenerateFrames(generate_frames);
110 }
111
112 void ProxyBeginFrameSource::OnPendingFrames(size_t count) {
113 DCHECK(source_);
114 source_->PendingFrames(count);
115 }
116
117 void ProxyBeginFrameSource::OnTimeBaseAndIntervalChange(
118 const base::TimeTicks timebase,
119 const base::TimeDelta interval) {
120 DCHECK(source_);
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 task_runner_(task_runner),
159 send_begin_frame_posted_(false) {
160 DCHECK(task_runner);
161 }
162
163 void BackToBackBeginFrameSource::ScheduleSendBeginFrameArgs() {
164 if (!generate_frames_)
165 return;
166
167 if (send_begin_frame_posted_)
168 return;
169
170 send_begin_frame_posted_ = true;
171 task_runner_->PostTask(
172 FROM_HERE,
173 base::Bind(&BackToBackBeginFrameSource::SendBeginFrameArgs,
174 base::Unretained(this)));
175 }
176
177 void BackToBackBeginFrameSource::SendBeginFrameArgs() {
178 send_begin_frame_posted_ = false;
179
180 // TODO(mithro): Fix the tests so this can be enabled. The tests currently
181 // depend on one begin frame firing after generate_frames_ is set false.
182 // if (!generate_frames_) {
183 // return;
184 // }
185
186 base::TimeTicks now = gfx::FrameTime::Now();
187 // TODO(mithro): Is a deadline of now+interval_ sane?
188 BeginFrameArgs args = BeginFrameArgs::Create(now, now + interval_, interval_);
189 frame_sink_->BeginFrame(args);
190 }
191
192 // BeginFrameSource ------------------------------------------------------
193
194 FRAMESOURCE_TYPESTRING(BackToBackBeginFrameSource);
195
196 void BackToBackBeginFrameSource::ExtraAsValue(
197 base::DictionaryValue* state) const {
198 state->SetBoolean("send_begin_frame_posted_", send_begin_frame_posted_);
199 }
200
201 void BackToBackBeginFrameSource::OnGenerateChange(bool generate_frames) {
202 ScheduleSendBeginFrameArgs();
203 }
204
205 void BackToBackBeginFrameSource::OnPendingFrames(size_t count) {
206 if (count == 0) {
207 ScheduleSendBeginFrameArgs();
208 }
209 }
210
211 /*************************************************************************/
212 SyntheticBeginFrameSource::SyntheticBeginFrameSource(
213 BeginFrameSink* sink,
214 base::SingleThreadTaskRunner* task_runner,
215 base::TimeDelta interval)
216 : BaseBeginFrameSource(sink), task_runner_(task_runner) {
217 DCHECK(task_runner);
218 interval_ = interval;
219 if (gfx::FrameTime::TimestampsAreHighRes()) {
220 time_source_ = DelayBasedTimeSourceHighRes::Create(interval_, task_runner);
221 } else {
222 time_source_ = DelayBasedTimeSource::Create(interval_, task_runner);
223 }
224 time_source_->SetActive(false);
225 time_source_->SetClient(this);
226 }
227
228 SyntheticBeginFrameSource::~SyntheticBeginFrameSource() {
229 time_source_->SetActive(false);
230 }
231
232 BeginFrameArgs SyntheticBeginFrameSource::CreateBeginFrameArgs(
233 base::TimeTicks frame_time) {
234 base::TimeTicks deadline = time_source_->NextTickTime();
235 return BeginFrameArgs::Create(frame_time, deadline, interval_);
236 }
237
238 // TimeSourceClient ------------------------------------------------------
239
240 void SyntheticBeginFrameSource::OnTimerTick() {
241 frame_sink_->BeginFrame(CreateBeginFrameArgs(time_source_->LastTickTime()));
242 }
243
244 // BeginFrameSource ------------------------------------------------------
245
246 FRAMESOURCE_TYPESTRING(SyntheticBeginFrameSource);
247
248 void SyntheticBeginFrameSource::ExtraAsValue(
249 base::DictionaryValue* state) const {
250 state->Set("time_source", time_source_->AsValue().release());
251 }
252
253 void SyntheticBeginFrameSource::OnGenerateChange(bool generate_frames) {
254 base::TimeTicks missed_tick_time = time_source_->SetActive(generate_frames);
255 if (!missed_tick_time.is_null()) {
256 frame_sink_->BeginFrame(CreateBeginFrameArgs(missed_tick_time));
257 }
258 }
259
260 void SyntheticBeginFrameSource::OnTimeBaseAndIntervalChange(
261 const base::TimeTicks timebase,
262 const base::TimeDelta interval) {
263 time_source_->SetTimebaseAndInterval(timebase, interval);
264 }
265
266 /*************************************************************************
267 * A virtual frame source which lets you switch between two other frame sources
268 * (making sure the BeginFrameArgs stays monotonic).
269 */
270 DualBeginFrameSource::DualBeginFrameSource(
271 BeginFrameSink* sink,
272 scoped_ptr<BeginFrameSource> source_primary,
273 scoped_ptr<BeginFrameSource> source_secondary)
274 : BaseBeginFrameSource(sink),
275 last_frame_args_(),
276 source_foreground_(source_primary.Pass()),
277 source_background_(source_secondary.Pass()) {
278 source_foreground_->SetBeginFrameSink(this);
279 source_background_->SetBeginFrameSink(this);
280 SwitchSource(SourceForeground());
281 }
282
283 DualBeginFrameSource::~DualBeginFrameSource() {
284 }
285
286 void DualBeginFrameSource::SwitchSource(const BeginFrameSource* new_source) {
287 DCHECK(new_source == SourceForeground() || new_source == SourceBackground());
288
289 if (generate_frames_)
290 active_source_->SetGenerateFrames(false);
291
292 active_source_ = const_cast<BeginFrameSource*>(new_source);
293
294 if (generate_frames_)
295 active_source_->SetGenerateFrames(true);
296 }
297
298 const BeginFrameSource* DualBeginFrameSource::SourceForeground() const {
299 return source_foreground_.get();
300 }
301
302 const BeginFrameSource* DualBeginFrameSource::SourceBackground() const {
303 return source_background_.get();
304 }
305
306 // BeginFrameSink ------------------------------------------------------
307
308 void DualBeginFrameSource::BeginFrame(const BeginFrameArgs& args) {
309 // When switching clock sources you can get a BeginFrameArgs with a
310 // frame_time before the last value.
311 BeginFrameArgs new_args = args;
312 if (last_frame_args_.frame_time > new_args.frame_time)
313 return;
314
315 last_frame_args_ = new_args;
316 frame_sink_->BeginFrame(new_args);
317 }
318
319 // BeginFrameSource ----------------------------------------------------
320
321 FRAMESOURCE_TYPESTRING(DualBeginFrameSource)
322
323 void DualBeginFrameSource::ExtraAsValue(base::DictionaryValue* state) const {
324 state->Set("last_frame_args", last_frame_args_.AsValue().release());
325 if (active_source_ == SourceForeground())
326 state->SetString("active", "primary");
327 if (active_source_ == SourceBackground())
328 state->SetString("active", "secondary");
329 state->Set("primary",
330 source_foreground_->BeginFrameSourceAsValue().release());
331 state->Set("secondary",
332 source_background_->BeginFrameSourceAsValue().release());
333 }
334
335 void DualBeginFrameSource::OnPendingFrames(size_t count) {
336 active_source_->PendingFrames(count);
337 }
338
339 void DualBeginFrameSource::OnGenerateChange(bool generate_frames) {
340 DCHECK(active_source_);
341 active_source_->SetGenerateFrames(generate_frames);
342 }
343
344 void DualBeginFrameSource::OnTimeBaseAndIntervalChange(
345 const base::TimeTicks timebase,
346 const base::TimeDelta interval) {
347 DCHECK_EQ(active_source_, source_foreground_); // TODO(mithro): Is this okay?
348 source_foreground_->SetTimeBaseAndInterval(timebase, interval);
349 }
350
351 } // namespace cc
OLDNEW
« no previous file with comments | « cc/scheduler/frame_source.h ('k') | cc/scheduler/frame_source_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698