OLD | NEW |
1 // Copyright 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "cc/scheduler/scheduler.h" | 5 #include "cc/scheduler/scheduler.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include "base/auto_reset.h" | 8 #include "base/auto_reset.h" |
9 #include "base/debug/trace_event.h" | 9 #include "base/debug/trace_event.h" |
10 #include "base/debug/trace_event_argument.h" | 10 #include "base/debug/trace_event_argument.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/single_thread_task_runner.h" | 12 #include "base/single_thread_task_runner.h" |
13 #include "cc/debug/devtools_instrumentation.h" | 13 #include "cc/debug/devtools_instrumentation.h" |
14 #include "cc/debug/traced_value.h" | 14 #include "cc/debug/traced_value.h" |
15 #include "cc/scheduler/delay_based_time_source.h" | 15 #include "cc/scheduler/delay_based_time_source.h" |
16 #include "ui/gfx/frame_time.h" | 16 #include "ui/gfx/frame_time.h" |
17 | 17 |
18 namespace cc { | 18 namespace cc { |
19 | 19 |
20 Scheduler::SyntheticBeginFrameSource::SyntheticBeginFrameSource( | 20 BeginFrameSource* SchedulerFrameSourcesConstructor::ConstructPrimaryFrameSource( |
21 Scheduler* scheduler, | 21 Scheduler* scheduler) { |
22 scoped_refptr<DelayBasedTimeSource> time_source) | 22 if (!scheduler->settings_.throttle_frame_production) { |
23 : scheduler_(scheduler), time_source_(time_source) { | 23 TRACE_EVENT1("cc", |
24 time_source_->SetClient(this); | 24 "Scheduler::Scheduler()", |
25 } | 25 "PrimaryFrameSource", |
| 26 "BackToBackBeginFrameSource"); |
| 27 DCHECK(!scheduler->primary_frame_source_internal_); |
| 28 scheduler->primary_frame_source_internal_ = |
| 29 BackToBackBeginFrameSource::Create(scheduler->task_runner_.get()); |
| 30 return scheduler->primary_frame_source_internal_.get(); |
| 31 } else if (scheduler->settings_.begin_frame_scheduling_enabled) { |
| 32 TRACE_EVENT1("cc", |
| 33 "Scheduler::Scheduler()", |
| 34 "PrimaryFrameSource", |
| 35 "SchedulerClient"); |
| 36 return scheduler->client_->ExternalBeginFrameSource(); |
| 37 } else { |
| 38 TRACE_EVENT1("cc", |
| 39 "Scheduler::Scheduler()", |
| 40 "PrimaryFrameSource", |
| 41 "SyntheticBeginFrameSource"); |
| 42 scoped_ptr<SyntheticBeginFrameSource> synthetic_source = |
| 43 SyntheticBeginFrameSource::Create(scheduler->task_runner_.get(), |
| 44 scheduler->Now(), |
| 45 BeginFrameArgs::DefaultInterval()); |
26 | 46 |
27 Scheduler::SyntheticBeginFrameSource::~SyntheticBeginFrameSource() { | 47 DCHECK(!scheduler->vsync_observer_); |
28 } | 48 scheduler->vsync_observer_ = synthetic_source.get(); |
29 | 49 |
30 void Scheduler::SyntheticBeginFrameSource::CommitVSyncParameters( | 50 DCHECK(!scheduler->primary_frame_source_internal_); |
31 base::TimeTicks timebase, | 51 scheduler->primary_frame_source_internal_ = synthetic_source.Pass(); |
32 base::TimeDelta interval) { | 52 return scheduler->primary_frame_source_internal_.get(); |
33 time_source_->SetTimebaseAndInterval(timebase, interval); | |
34 } | |
35 | |
36 void Scheduler::SyntheticBeginFrameSource::SetNeedsBeginFrame( | |
37 bool needs_begin_frame, | |
38 std::deque<BeginFrameArgs>* begin_retro_frame_args) { | |
39 DCHECK(begin_retro_frame_args); | |
40 base::TimeTicks missed_tick_time = | |
41 time_source_->SetActive(needs_begin_frame); | |
42 if (!missed_tick_time.is_null()) { | |
43 begin_retro_frame_args->push_back( | |
44 CreateSyntheticBeginFrameArgs(missed_tick_time)); | |
45 } | 53 } |
46 } | 54 } |
47 | 55 |
48 bool Scheduler::SyntheticBeginFrameSource::IsActive() const { | 56 BeginFrameSource* |
49 return time_source_->Active(); | 57 SchedulerFrameSourcesConstructor::ConstructBackgroundFrameSource( |
50 } | 58 Scheduler* scheduler) { |
51 | 59 TRACE_EVENT1("cc", |
52 void Scheduler::SyntheticBeginFrameSource::OnTimerTick() { | 60 "Scheduler::Scheduler()", |
53 BeginFrameArgs begin_frame_args( | 61 "BackgroundFrameSource", |
54 CreateSyntheticBeginFrameArgs(time_source_->LastTickTime())); | 62 "SyntheticBeginFrameSource"); |
55 scheduler_->BeginFrame(begin_frame_args); | 63 DCHECK(!(scheduler->background_frame_source_internal_)); |
56 } | 64 scheduler->background_frame_source_internal_ = |
57 | 65 SyntheticBeginFrameSource::Create(scheduler->task_runner_.get(), |
58 void Scheduler::SyntheticBeginFrameSource::AsValueInto( | 66 scheduler->Now(), |
59 base::debug::TracedValue* state) const { | 67 base::TimeDelta::FromSeconds(1)); |
60 time_source_->AsValueInto(state); | 68 return scheduler->background_frame_source_internal_.get(); |
61 } | |
62 | |
63 BeginFrameArgs | |
64 Scheduler::SyntheticBeginFrameSource::CreateSyntheticBeginFrameArgs( | |
65 base::TimeTicks frame_time) { | |
66 base::TimeTicks deadline = time_source_->NextTickTime(); | |
67 return BeginFrameArgs::Create( | |
68 frame_time, deadline, scheduler_->VSyncInterval()); | |
69 } | 69 } |
70 | 70 |
71 Scheduler::Scheduler( | 71 Scheduler::Scheduler( |
72 SchedulerClient* client, | 72 SchedulerClient* client, |
73 const SchedulerSettings& scheduler_settings, | 73 const SchedulerSettings& scheduler_settings, |
74 int layer_tree_host_id, | 74 int layer_tree_host_id, |
75 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) | 75 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
76 : settings_(scheduler_settings), | 76 SchedulerFrameSourcesConstructor* frame_sources_constructor) |
| 77 : frame_source_(), |
| 78 primary_frame_source_(NULL), |
| 79 background_frame_source_(NULL), |
| 80 primary_frame_source_internal_(), |
| 81 background_frame_source_internal_(), |
| 82 vsync_observer_(NULL), |
| 83 settings_(scheduler_settings), |
77 client_(client), | 84 client_(client), |
78 layer_tree_host_id_(layer_tree_host_id), | 85 layer_tree_host_id_(layer_tree_host_id), |
79 task_runner_(task_runner), | 86 task_runner_(task_runner), |
80 vsync_interval_(BeginFrameArgs::DefaultInterval()), | |
81 last_set_needs_begin_frame_(false), | |
82 begin_unthrottled_frame_posted_(false), | |
83 begin_retro_frame_posted_(false), | 87 begin_retro_frame_posted_(false), |
84 state_machine_(scheduler_settings), | 88 state_machine_(scheduler_settings), |
85 inside_process_scheduled_actions_(false), | 89 inside_process_scheduled_actions_(false), |
86 inside_action_(SchedulerStateMachine::ACTION_NONE), | 90 inside_action_(SchedulerStateMachine::ACTION_NONE), |
87 weak_factory_(this) { | 91 weak_factory_(this) { |
88 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), | 92 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), |
89 "Scheduler::Scheduler", | 93 "Scheduler::Scheduler", |
90 "settings", | 94 "settings", |
91 settings_.AsValue()); | 95 settings_.AsValue()); |
92 DCHECK(client_); | 96 DCHECK(client_); |
93 DCHECK(!state_machine_.BeginFrameNeeded()); | 97 DCHECK(!state_machine_.BeginFrameNeeded()); |
94 | 98 |
95 begin_retro_frame_closure_ = | 99 begin_retro_frame_closure_ = |
96 base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr()); | 100 base::Bind(&Scheduler::BeginRetroFrame, weak_factory_.GetWeakPtr()); |
97 begin_unthrottled_frame_closure_ = | |
98 base::Bind(&Scheduler::BeginUnthrottledFrame, weak_factory_.GetWeakPtr()); | |
99 begin_impl_frame_deadline_closure_ = base::Bind( | 101 begin_impl_frame_deadline_closure_ = base::Bind( |
100 &Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr()); | 102 &Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr()); |
101 poll_for_draw_triggers_closure_ = base::Bind( | 103 poll_for_draw_triggers_closure_ = base::Bind( |
102 &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr()); | 104 &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr()); |
103 advance_commit_state_closure_ = base::Bind( | 105 advance_commit_state_closure_ = base::Bind( |
104 &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr()); | 106 &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr()); |
105 | 107 |
106 if (!settings_.begin_frame_scheduling_enabled) { | 108 frame_source_ = BeginFrameSourceMultiplexer::Create(); |
107 SetupSyntheticBeginFrames(); | 109 frame_source_->AddObserver(this); |
108 } | 110 |
| 111 // Primary frame source |
| 112 primary_frame_source_ = |
| 113 frame_sources_constructor->ConstructPrimaryFrameSource(this); |
| 114 frame_source_->AddSource(primary_frame_source_); |
| 115 |
| 116 // Background ticking frame source |
| 117 background_frame_source_ = |
| 118 frame_sources_constructor->ConstructBackgroundFrameSource(this); |
| 119 frame_source_->AddSource(background_frame_source_); |
109 } | 120 } |
110 | 121 |
111 Scheduler::~Scheduler() { | 122 Scheduler::~Scheduler() { |
112 if (synthetic_begin_frame_source_) { | |
113 synthetic_begin_frame_source_->SetNeedsBeginFrame(false, | |
114 &begin_retro_frame_args_); | |
115 } | |
116 } | |
117 | |
118 void Scheduler::SetupSyntheticBeginFrames() { | |
119 scoped_refptr<DelayBasedTimeSource> time_source; | |
120 if (gfx::FrameTime::TimestampsAreHighRes()) { | |
121 time_source = DelayBasedTimeSourceHighRes::Create(VSyncInterval(), | |
122 task_runner_.get()); | |
123 } else { | |
124 time_source = | |
125 DelayBasedTimeSource::Create(VSyncInterval(), task_runner_.get()); | |
126 } | |
127 DCHECK(!synthetic_begin_frame_source_); | |
128 synthetic_begin_frame_source_.reset( | |
129 new SyntheticBeginFrameSource(this, time_source)); | |
130 } | 123 } |
131 | 124 |
132 base::TimeTicks Scheduler::Now() const { | 125 base::TimeTicks Scheduler::Now() const { |
133 return gfx::FrameTime::Now(); | 126 base::TimeTicks now = gfx::FrameTime::Now(); |
| 127 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.now"), |
| 128 "Scheduler::Now", |
| 129 "now", |
| 130 now); |
| 131 return now; |
134 } | 132 } |
135 | 133 |
136 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, | 134 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, |
137 base::TimeDelta interval) { | 135 base::TimeDelta interval) { |
138 // TODO(brianderson): We should not be receiving 0 intervals. | 136 // TODO(brianderson): We should not be receiving 0 intervals. |
139 if (interval == base::TimeDelta()) | 137 if (interval == base::TimeDelta()) |
140 interval = BeginFrameArgs::DefaultInterval(); | 138 interval = BeginFrameArgs::DefaultInterval(); |
141 vsync_interval_ = interval; | 139 |
142 if (!settings_.begin_frame_scheduling_enabled) | 140 if (vsync_observer_) |
143 synthetic_begin_frame_source_->CommitVSyncParameters(timebase, interval); | 141 vsync_observer_->OnUpdateVSyncParameters(timebase, interval); |
144 } | 142 } |
145 | 143 |
146 void Scheduler::SetEstimatedParentDrawTime(base::TimeDelta draw_time) { | 144 void Scheduler::SetEstimatedParentDrawTime(base::TimeDelta draw_time) { |
147 DCHECK_GE(draw_time.ToInternalValue(), 0); | 145 DCHECK_GE(draw_time.ToInternalValue(), 0); |
148 estimated_parent_draw_time_ = draw_time; | 146 estimated_parent_draw_time_ = draw_time; |
149 } | 147 } |
150 | 148 |
151 void Scheduler::SetCanStart() { | 149 void Scheduler::SetCanStart() { |
152 state_machine_.SetCanStart(); | 150 state_machine_.SetCanStart(); |
153 ProcessScheduledActions(); | 151 ProcessScheduledActions(); |
154 } | 152 } |
155 | 153 |
156 void Scheduler::SetVisible(bool visible) { | 154 void Scheduler::SetVisible(bool visible) { |
157 state_machine_.SetVisible(visible); | 155 state_machine_.SetVisible(visible); |
| 156 if (visible) { |
| 157 frame_source_->SetActiveSource(primary_frame_source_); |
| 158 } else { |
| 159 frame_source_->SetActiveSource(background_frame_source_); |
| 160 } |
158 ProcessScheduledActions(); | 161 ProcessScheduledActions(); |
159 } | 162 } |
160 | 163 |
161 void Scheduler::SetCanDraw(bool can_draw) { | 164 void Scheduler::SetCanDraw(bool can_draw) { |
162 state_machine_.SetCanDraw(can_draw); | 165 state_machine_.SetCanDraw(can_draw); |
163 ProcessScheduledActions(); | 166 ProcessScheduledActions(); |
164 } | 167 } |
165 | 168 |
166 void Scheduler::NotifyReadyToActivate() { | 169 void Scheduler::NotifyReadyToActivate() { |
167 state_machine_.NotifyReadyToActivate(); | 170 state_machine_.NotifyReadyToActivate(); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
230 ProcessScheduledActions(); | 233 ProcessScheduledActions(); |
231 } | 234 } |
232 | 235 |
233 void Scheduler::DidManageTiles() { | 236 void Scheduler::DidManageTiles() { |
234 state_machine_.DidManageTiles(); | 237 state_machine_.DidManageTiles(); |
235 } | 238 } |
236 | 239 |
237 void Scheduler::DidLoseOutputSurface() { | 240 void Scheduler::DidLoseOutputSurface() { |
238 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface"); | 241 TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface"); |
239 state_machine_.DidLoseOutputSurface(); | 242 state_machine_.DidLoseOutputSurface(); |
240 last_set_needs_begin_frame_ = false; | 243 if (frame_source_->NeedsBeginFrames()) |
241 if (!settings_.begin_frame_scheduling_enabled) { | 244 frame_source_->SetNeedsBeginFrames(false); |
242 synthetic_begin_frame_source_->SetNeedsBeginFrame(false, | |
243 &begin_retro_frame_args_); | |
244 } | |
245 begin_retro_frame_args_.clear(); | 245 begin_retro_frame_args_.clear(); |
246 ProcessScheduledActions(); | 246 ProcessScheduledActions(); |
247 } | 247 } |
248 | 248 |
249 void Scheduler::DidCreateAndInitializeOutputSurface() { | 249 void Scheduler::DidCreateAndInitializeOutputSurface() { |
250 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); | 250 TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface"); |
251 DCHECK(!last_set_needs_begin_frame_); | 251 DCHECK(!frame_source_->NeedsBeginFrames()); |
252 DCHECK(begin_impl_frame_deadline_task_.IsCancelled()); | 252 DCHECK(begin_impl_frame_deadline_task_.IsCancelled()); |
253 state_machine_.DidCreateAndInitializeOutputSurface(); | 253 state_machine_.DidCreateAndInitializeOutputSurface(); |
254 ProcessScheduledActions(); | 254 ProcessScheduledActions(); |
255 } | 255 } |
256 | 256 |
257 void Scheduler::NotifyBeginMainFrameStarted() { | 257 void Scheduler::NotifyBeginMainFrameStarted() { |
258 TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted"); | 258 TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted"); |
259 state_machine_.NotifyBeginMainFrameStarted(); | 259 state_machine_.NotifyBeginMainFrameStarted(); |
260 } | 260 } |
261 | 261 |
262 base::TimeTicks Scheduler::AnticipatedDrawTime() const { | 262 base::TimeTicks Scheduler::AnticipatedDrawTime() const { |
263 if (!last_set_needs_begin_frame_ || | 263 if (!frame_source_->NeedsBeginFrames() || |
264 begin_impl_frame_args_.interval <= base::TimeDelta()) | 264 begin_impl_frame_args_.interval <= base::TimeDelta()) |
265 return base::TimeTicks(); | 265 return base::TimeTicks(); |
266 | 266 |
267 base::TimeTicks now = Now(); | 267 base::TimeTicks now = Now(); |
268 base::TimeTicks timebase = std::max(begin_impl_frame_args_.frame_time, | 268 base::TimeTicks timebase = std::max(begin_impl_frame_args_.frame_time, |
269 begin_impl_frame_args_.deadline); | 269 begin_impl_frame_args_.deadline); |
270 int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval); | 270 int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval); |
271 return timebase + (begin_impl_frame_args_.interval * intervals); | 271 return timebase + (begin_impl_frame_args_.interval * intervals); |
272 } | 272 } |
273 | 273 |
274 base::TimeTicks Scheduler::LastBeginImplFrameTime() { | 274 base::TimeTicks Scheduler::LastBeginImplFrameTime() { |
275 return begin_impl_frame_args_.frame_time; | 275 return begin_impl_frame_args_.frame_time; |
276 } | 276 } |
277 | 277 |
278 void Scheduler::SetupNextBeginFrameIfNeeded() { | 278 void Scheduler::SetupNextBeginFrameIfNeeded() { |
279 if (!task_runner_.get()) | 279 if (!task_runner_.get()) |
280 return; | 280 return; |
281 | 281 |
282 bool needs_begin_frame = state_machine_.BeginFrameNeeded(); | 282 bool needs_begin_frame = state_machine_.BeginFrameNeeded(); |
283 | 283 |
284 if (settings_.throttle_frame_production) { | 284 bool at_end_of_deadline = |
285 SetupNextBeginFrameWhenVSyncThrottlingEnabled(needs_begin_frame); | 285 (state_machine_.begin_impl_frame_state() == |
286 } else { | 286 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE); |
287 SetupNextBeginFrameWhenVSyncThrottlingDisabled(needs_begin_frame); | 287 |
| 288 bool should_call_set_needs_begin_frame = |
| 289 // Always request the BeginFrame immediately if it wasn't needed before. |
| 290 (needs_begin_frame && !frame_source_->NeedsBeginFrames()) || |
| 291 // Only stop requesting BeginFrames after a deadline. |
| 292 (!needs_begin_frame && frame_source_->NeedsBeginFrames() && |
| 293 at_end_of_deadline); |
| 294 |
| 295 if (should_call_set_needs_begin_frame) { |
| 296 frame_source_->SetNeedsBeginFrames(needs_begin_frame); |
288 } | 297 } |
| 298 |
| 299 if (at_end_of_deadline) { |
| 300 frame_source_->DidFinishFrame(begin_retro_frame_args_.size()); |
| 301 } |
| 302 |
| 303 PostBeginRetroFrameIfNeeded(); |
289 SetupPollingMechanisms(needs_begin_frame); | 304 SetupPollingMechanisms(needs_begin_frame); |
290 } | 305 } |
291 | 306 |
292 // When we are throttling frame production, we request BeginFrames | |
293 // from the OutputSurface. | |
294 void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingEnabled( | |
295 bool needs_begin_frame) { | |
296 bool at_end_of_deadline = | |
297 state_machine_.begin_impl_frame_state() == | |
298 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE; | |
299 | |
300 bool should_call_set_needs_begin_frame = | |
301 // Always request the BeginFrame immediately if it wasn't needed before. | |
302 (needs_begin_frame && !last_set_needs_begin_frame_) || | |
303 // Only stop requesting BeginFrames after a deadline. | |
304 (!needs_begin_frame && last_set_needs_begin_frame_ && at_end_of_deadline); | |
305 | |
306 if (should_call_set_needs_begin_frame) { | |
307 if (settings_.begin_frame_scheduling_enabled) { | |
308 client_->SetNeedsBeginFrame(needs_begin_frame); | |
309 } else { | |
310 synthetic_begin_frame_source_->SetNeedsBeginFrame( | |
311 needs_begin_frame, &begin_retro_frame_args_); | |
312 } | |
313 last_set_needs_begin_frame_ = needs_begin_frame; | |
314 } | |
315 | |
316 PostBeginRetroFrameIfNeeded(); | |
317 } | |
318 | |
319 // When we aren't throttling frame production, we initiate a BeginFrame | |
320 // as soon as one is needed. | |
321 void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingDisabled( | |
322 bool needs_begin_frame) { | |
323 last_set_needs_begin_frame_ = needs_begin_frame; | |
324 | |
325 if (!needs_begin_frame || begin_unthrottled_frame_posted_) | |
326 return; | |
327 | |
328 if (state_machine_.begin_impl_frame_state() != | |
329 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE && | |
330 state_machine_.begin_impl_frame_state() != | |
331 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) { | |
332 return; | |
333 } | |
334 | |
335 begin_unthrottled_frame_posted_ = true; | |
336 task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_); | |
337 } | |
338 | |
339 // BeginUnthrottledFrame is used when we aren't throttling frame production. | |
340 // This will usually be because VSync is disabled. | |
341 void Scheduler::BeginUnthrottledFrame() { | |
342 DCHECK(!settings_.throttle_frame_production); | |
343 DCHECK(begin_retro_frame_args_.empty()); | |
344 | |
345 base::TimeTicks now = Now(); | |
346 base::TimeTicks deadline = now + vsync_interval_; | |
347 | |
348 BeginFrameArgs begin_frame_args = | |
349 BeginFrameArgs::Create(now, deadline, vsync_interval_); | |
350 BeginImplFrame(begin_frame_args); | |
351 | |
352 begin_unthrottled_frame_posted_ = false; | |
353 } | |
354 | |
355 // We may need to poll when we can't rely on BeginFrame to advance certain | 307 // We may need to poll when we can't rely on BeginFrame to advance certain |
356 // state or to avoid deadlock. | 308 // state or to avoid deadlock. |
357 void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) { | 309 void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) { |
358 bool needs_advance_commit_state_timer = false; | 310 bool needs_advance_commit_state_timer = false; |
359 // Setup PollForAnticipatedDrawTriggers if we need to monitor state but | 311 // Setup PollForAnticipatedDrawTriggers if we need to monitor state but |
360 // aren't expecting any more BeginFrames. This should only be needed by | 312 // aren't expecting any more BeginFrames. This should only be needed by |
361 // the synchronous compositor when BeginFrameNeeded is false. | 313 // the synchronous compositor when BeginFrameNeeded is false. |
362 if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) { | 314 if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) { |
363 DCHECK(!state_machine_.SupportsProactiveBeginFrame()); | 315 DCHECK(!state_machine_.SupportsProactiveBeginFrame()); |
364 DCHECK(!needs_begin_frame); | 316 DCHECK(!needs_begin_frame); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
398 } | 350 } |
399 } else { | 351 } else { |
400 advance_commit_state_task_.Cancel(); | 352 advance_commit_state_task_.Cancel(); |
401 } | 353 } |
402 } | 354 } |
403 | 355 |
404 // BeginFrame is the mechanism that tells us that now is a good time to start | 356 // BeginFrame is the mechanism that tells us that now is a good time to start |
405 // making a frame. Usually this means that user input for the frame is complete. | 357 // making a frame. Usually this means that user input for the frame is complete. |
406 // If the scheduler is busy, we queue the BeginFrame to be handled later as | 358 // If the scheduler is busy, we queue the BeginFrame to be handled later as |
407 // a BeginRetroFrame. | 359 // a BeginRetroFrame. |
408 void Scheduler::BeginFrame(const BeginFrameArgs& args) { | 360 bool Scheduler::OnBeginFrameMixInDelegate(const BeginFrameArgs& args) { |
409 TRACE_EVENT1("cc", "Scheduler::BeginFrame", "args", args.AsValue()); | 361 TRACE_EVENT1("cc", "Scheduler::BeginFrame", "args", args.AsValue()); |
410 DCHECK(settings_.throttle_frame_production); | 362 |
| 363 // We have just called SetNeedsBeginFrame(true) and the BeginFrameSource has |
| 364 // sent us the last BeginFrame we have missed. As we might not be able to |
| 365 // actually make rendering for this call, handle it like a "retro frame". |
| 366 // TODO(brainderson): Add a test for this functionality ASAP! |
| 367 if (args.type == BeginFrameArgs::MISSED) { |
| 368 begin_retro_frame_args_.push_back(args); |
| 369 PostBeginRetroFrameIfNeeded(); |
| 370 return true; |
| 371 } |
411 | 372 |
412 BeginFrameArgs adjusted_args(args); | 373 BeginFrameArgs adjusted_args(args); |
413 adjusted_args.deadline -= EstimatedParentDrawTime(); | 374 adjusted_args.deadline -= EstimatedParentDrawTime(); |
414 | 375 |
415 bool should_defer_begin_frame; | 376 bool should_defer_begin_frame; |
416 if (settings_.using_synchronous_renderer_compositor) { | 377 if (settings_.using_synchronous_renderer_compositor) { |
417 should_defer_begin_frame = false; | 378 should_defer_begin_frame = false; |
418 } else { | 379 } else { |
419 should_defer_begin_frame = | 380 should_defer_begin_frame = |
420 !begin_retro_frame_args_.empty() || begin_retro_frame_posted_ || | 381 !begin_retro_frame_args_.empty() || begin_retro_frame_posted_ || |
421 !last_set_needs_begin_frame_ || | 382 !frame_source_->NeedsBeginFrames() || |
422 (state_machine_.begin_impl_frame_state() != | 383 (state_machine_.begin_impl_frame_state() != |
423 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); | 384 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); |
424 } | 385 } |
425 | 386 |
426 if (should_defer_begin_frame) { | 387 if (should_defer_begin_frame) { |
427 begin_retro_frame_args_.push_back(adjusted_args); | 388 begin_retro_frame_args_.push_back(adjusted_args); |
428 TRACE_EVENT_INSTANT0( | 389 TRACE_EVENT_INSTANT0( |
429 "cc", "Scheduler::BeginFrame deferred", TRACE_EVENT_SCOPE_THREAD); | 390 "cc", "Scheduler::BeginFrame deferred", TRACE_EVENT_SCOPE_THREAD); |
430 return; | 391 // Queuing the frame counts as "using it", so we need to return true. |
| 392 } else { |
| 393 BeginImplFrame(adjusted_args); |
431 } | 394 } |
432 | 395 return true; |
433 BeginImplFrame(adjusted_args); | |
434 } | 396 } |
435 | 397 |
436 // BeginRetroFrame is called for BeginFrames that we've deferred because | 398 // BeginRetroFrame is called for BeginFrames that we've deferred because |
437 // the scheduler was in the middle of processing a previous BeginFrame. | 399 // the scheduler was in the middle of processing a previous BeginFrame. |
438 void Scheduler::BeginRetroFrame() { | 400 void Scheduler::BeginRetroFrame() { |
439 TRACE_EVENT0("cc", "Scheduler::BeginRetroFrame"); | 401 TRACE_EVENT0("cc", "Scheduler::BeginRetroFrame"); |
440 DCHECK(!settings_.using_synchronous_renderer_compositor); | 402 DCHECK(!settings_.using_synchronous_renderer_compositor); |
441 DCHECK(begin_retro_frame_posted_); | 403 DCHECK(begin_retro_frame_posted_); |
442 begin_retro_frame_posted_ = false; | 404 begin_retro_frame_posted_ = false; |
443 | 405 |
(...skipping 18 matching lines...) Expand all Loading... |
462 break; | 424 break; |
463 | 425 |
464 TRACE_EVENT_INSTANT2("cc", | 426 TRACE_EVENT_INSTANT2("cc", |
465 "Scheduler::BeginRetroFrame discarding", | 427 "Scheduler::BeginRetroFrame discarding", |
466 TRACE_EVENT_SCOPE_THREAD, | 428 TRACE_EVENT_SCOPE_THREAD, |
467 "deadline - now", | 429 "deadline - now", |
468 (adjusted_deadline - now).InMicroseconds(), | 430 (adjusted_deadline - now).InMicroseconds(), |
469 "BeginFrameArgs", | 431 "BeginFrameArgs", |
470 begin_retro_frame_args_.front().AsValue()); | 432 begin_retro_frame_args_.front().AsValue()); |
471 begin_retro_frame_args_.pop_front(); | 433 begin_retro_frame_args_.pop_front(); |
| 434 frame_source_->DidFinishFrame(begin_retro_frame_args_.size()); |
472 } | 435 } |
473 | 436 |
474 if (begin_retro_frame_args_.empty()) { | 437 if (begin_retro_frame_args_.empty()) { |
475 DCHECK(settings_.throttle_frame_production); | |
476 TRACE_EVENT_INSTANT0("cc", | 438 TRACE_EVENT_INSTANT0("cc", |
477 "Scheduler::BeginRetroFrames all expired", | 439 "Scheduler::BeginRetroFrames all expired", |
478 TRACE_EVENT_SCOPE_THREAD); | 440 TRACE_EVENT_SCOPE_THREAD); |
479 } else { | 441 } else { |
480 BeginImplFrame(begin_retro_frame_args_.front()); | 442 BeginImplFrame(begin_retro_frame_args_.front()); |
481 begin_retro_frame_args_.pop_front(); | 443 begin_retro_frame_args_.pop_front(); |
482 } | 444 } |
483 } | 445 } |
484 | 446 |
485 // There could be a race between the posted BeginRetroFrame and a new | 447 // There could be a race between the posted BeginRetroFrame and a new |
486 // BeginFrame arriving via the normal mechanism. Scheduler::BeginFrame | 448 // BeginFrame arriving via the normal mechanism. Scheduler::BeginFrame |
487 // will check if there is a pending BeginRetroFrame to ensure we handle | 449 // will check if there is a pending BeginRetroFrame to ensure we handle |
488 // BeginFrames in FIFO order. | 450 // BeginFrames in FIFO order. |
489 void Scheduler::PostBeginRetroFrameIfNeeded() { | 451 void Scheduler::PostBeginRetroFrameIfNeeded() { |
490 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), | 452 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), |
491 "Scheduler::PostBeginRetroFrameIfNeeded", | 453 "Scheduler::PostBeginRetroFrameIfNeeded", |
492 "state", | 454 "state", |
493 AsValue()); | 455 AsValue()); |
494 if (!last_set_needs_begin_frame_) | 456 if (!frame_source_->NeedsBeginFrames()) |
495 return; | 457 return; |
496 | 458 |
497 if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_) | 459 if (begin_retro_frame_args_.empty() || begin_retro_frame_posted_) |
498 return; | 460 return; |
499 | 461 |
500 // begin_retro_frame_args_ should always be empty for the | 462 // begin_retro_frame_args_ should always be empty for the |
501 // synchronous compositor. | 463 // synchronous compositor. |
502 DCHECK(!settings_.using_synchronous_renderer_compositor); | 464 DCHECK(!settings_.using_synchronous_renderer_compositor); |
503 | 465 |
504 if (state_machine_.begin_impl_frame_state() != | 466 if (state_machine_.begin_impl_frame_state() != |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
712 scoped_refptr<base::debug::TracedValue> state = | 674 scoped_refptr<base::debug::TracedValue> state = |
713 new base::debug::TracedValue(); | 675 new base::debug::TracedValue(); |
714 AsValueInto(state.get()); | 676 AsValueInto(state.get()); |
715 return state; | 677 return state; |
716 } | 678 } |
717 | 679 |
718 void Scheduler::AsValueInto(base::debug::TracedValue* state) const { | 680 void Scheduler::AsValueInto(base::debug::TracedValue* state) const { |
719 state->BeginDictionary("state_machine"); | 681 state->BeginDictionary("state_machine"); |
720 state_machine_.AsValueInto(state, Now()); | 682 state_machine_.AsValueInto(state, Now()); |
721 state->EndDictionary(); | 683 state->EndDictionary(); |
722 if (synthetic_begin_frame_source_) { | 684 |
723 state->BeginDictionary("synthetic_begin_frame_source_"); | 685 state->BeginDictionary("frame_source_"); |
724 synthetic_begin_frame_source_->AsValueInto(state); | 686 frame_source_->AsValueInto(state); |
725 state->EndDictionary(); | 687 state->EndDictionary(); |
726 } | |
727 | 688 |
728 state->BeginDictionary("scheduler_state"); | 689 state->BeginDictionary("scheduler_state"); |
729 state->SetDouble("time_until_anticipated_draw_time_ms", | 690 state->SetDouble("time_until_anticipated_draw_time_ms", |
730 (AnticipatedDrawTime() - Now()).InMillisecondsF()); | 691 (AnticipatedDrawTime() - Now()).InMillisecondsF()); |
731 state->SetDouble("vsync_interval_ms", vsync_interval_.InMillisecondsF()); | |
732 state->SetDouble("estimated_parent_draw_time_ms", | 692 state->SetDouble("estimated_parent_draw_time_ms", |
733 estimated_parent_draw_time_.InMillisecondsF()); | 693 estimated_parent_draw_time_.InMillisecondsF()); |
734 state->SetBoolean("last_set_needs_begin_frame_", last_set_needs_begin_frame_); | 694 state->SetBoolean("last_set_needs_begin_frame_", |
735 state->SetBoolean("begin_unthrottled_frame_posted_", | 695 frame_source_->NeedsBeginFrames()); |
736 begin_unthrottled_frame_posted_); | |
737 state->SetBoolean("begin_retro_frame_posted_", begin_retro_frame_posted_); | 696 state->SetBoolean("begin_retro_frame_posted_", begin_retro_frame_posted_); |
738 state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size()); | 697 state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size()); |
739 state->SetBoolean("begin_impl_frame_deadline_task_", | 698 state->SetBoolean("begin_impl_frame_deadline_task_", |
740 !begin_impl_frame_deadline_task_.IsCancelled()); | 699 !begin_impl_frame_deadline_task_.IsCancelled()); |
741 state->SetBoolean("poll_for_draw_triggers_task_", | 700 state->SetBoolean("poll_for_draw_triggers_task_", |
742 !poll_for_draw_triggers_task_.IsCancelled()); | 701 !poll_for_draw_triggers_task_.IsCancelled()); |
743 state->SetBoolean("advance_commit_state_task_", | 702 state->SetBoolean("advance_commit_state_task_", |
744 !advance_commit_state_task_.IsCancelled()); | 703 !advance_commit_state_task_.IsCancelled()); |
745 state->BeginDictionary("begin_impl_frame_args"); | 704 state->BeginDictionary("begin_impl_frame_args"); |
746 begin_impl_frame_args_.AsValueInto(state); | 705 begin_impl_frame_args_.AsValueInto(state); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
780 } | 739 } |
781 | 740 |
782 bool Scheduler::IsBeginMainFrameSentOrStarted() const { | 741 bool Scheduler::IsBeginMainFrameSentOrStarted() const { |
783 return (state_machine_.commit_state() == | 742 return (state_machine_.commit_state() == |
784 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || | 743 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || |
785 state_machine_.commit_state() == | 744 state_machine_.commit_state() == |
786 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); | 745 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); |
787 } | 746 } |
788 | 747 |
789 } // namespace cc | 748 } // namespace cc |
OLD | NEW |