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

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: Created 6 years, 7 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/output/begin_frame_args.h ('k') | cc/scheduler/scheduler.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 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
OLDNEW
« no previous file with comments | « cc/output/begin_frame_args.h ('k') | cc/scheduler/scheduler.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698