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

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 now uses frame sources, working on scheduler_unittests. 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
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_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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698