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/logging.h" | 10 #include "base/logging.h" |
11 #include "cc/debug/devtools_instrumentation.h" | 11 #include "cc/debug/devtools_instrumentation.h" |
12 #include "cc/debug/traced_value.h" | 12 #include "cc/debug/traced_value.h" |
13 #include "cc/scheduler/delay_based_time_source.h" | 13 #include "cc/scheduler/delay_based_time_source.h" |
| 14 #include "cc/scheduler/frame_source.h" |
14 #include "ui/gfx/frame_time.h" | 15 #include "ui/gfx/frame_time.h" |
15 | 16 |
16 namespace cc { | 17 namespace cc { |
17 | 18 |
18 class SyntheticBeginFrameSource : public TimeSourceClient { | |
19 public: | |
20 SyntheticBeginFrameSource(Scheduler* scheduler, | |
21 base::SingleThreadTaskRunner* task_runner) | |
22 : scheduler_(scheduler) { | |
23 if (gfx::FrameTime::TimestampsAreHighRes()) { | |
24 time_source_ = DelayBasedTimeSourceHighRes::Create( | |
25 scheduler_->VSyncInterval(), task_runner); | |
26 } else { | |
27 time_source_ = DelayBasedTimeSource::Create(scheduler_->VSyncInterval(), | |
28 task_runner); | |
29 } | |
30 time_source_->SetClient(this); | |
31 } | |
32 | |
33 virtual ~SyntheticBeginFrameSource() {} | |
34 | |
35 // Updates the phase and frequency of the timer. | |
36 void CommitVSyncParameters(base::TimeTicks timebase, | |
37 base::TimeDelta interval) { | |
38 time_source_->SetTimebaseAndInterval(timebase, interval); | |
39 } | |
40 | |
41 // Activates future BeginFrames and, if activating, pushes the most | |
42 // recently missed BeginFrame to the back of a retroactive queue. | |
43 void SetNeedsBeginFrame(bool needs_begin_frame, | |
44 std::deque<BeginFrameArgs>* begin_retro_frame_args) { | |
45 base::TimeTicks missed_tick_time = | |
46 time_source_->SetActive(needs_begin_frame); | |
47 if (!missed_tick_time.is_null()) { | |
48 begin_retro_frame_args->push_back( | |
49 CreateSyntheticBeginFrameArgs(missed_tick_time)); | |
50 } | |
51 } | |
52 | |
53 // TimeSourceClient implementation of OnTimerTick triggers a BeginFrame. | |
54 virtual void OnTimerTick() OVERRIDE { | |
55 BeginFrameArgs begin_frame_args( | |
56 CreateSyntheticBeginFrameArgs(time_source_->LastTickTime())); | |
57 scheduler_->BeginFrame(begin_frame_args); | |
58 } | |
59 | |
60 private: | |
61 BeginFrameArgs CreateSyntheticBeginFrameArgs(base::TimeTicks frame_time) { | |
62 base::TimeTicks deadline = | |
63 time_source_->NextTickTime() - scheduler_->EstimatedParentDrawTime(); | |
64 return BeginFrameArgs::Create( | |
65 frame_time, deadline, scheduler_->VSyncInterval()); | |
66 } | |
67 | |
68 Scheduler* scheduler_; | |
69 scoped_refptr<TimeSource> time_source_; | |
70 }; | |
71 | |
72 Scheduler::Scheduler( | 19 Scheduler::Scheduler( |
73 SchedulerClient* client, | 20 SchedulerClient* client, |
74 const SchedulerSettings& scheduler_settings, | 21 const SchedulerSettings& scheduler_settings, |
75 int layer_tree_host_id, | 22 int layer_tree_host_id, |
76 const scoped_refptr<base::SingleThreadTaskRunner>& impl_task_runner) | 23 const scoped_refptr<base::SingleThreadTaskRunner>& impl_task_runner) |
77 : settings_(scheduler_settings), | 24 : settings_(scheduler_settings), |
78 client_(client), | 25 client_(client), |
79 layer_tree_host_id_(layer_tree_host_id), | 26 layer_tree_host_id_(layer_tree_host_id), |
80 impl_task_runner_(impl_task_runner), | 27 impl_task_runner_(impl_task_runner), |
81 vsync_interval_(BeginFrameArgs::DefaultInterval()), | |
82 last_set_needs_begin_frame_(false), | 28 last_set_needs_begin_frame_(false), |
83 begin_unthrottled_frame_posted_(false), | 29 begin_unthrottled_frame_posted_(false), |
84 begin_retro_frame_posted_(false), | 30 begin_retro_frame_posted_(false), |
85 state_machine_(scheduler_settings), | 31 state_machine_(scheduler_settings), |
86 inside_process_scheduled_actions_(false), | 32 inside_process_scheduled_actions_(false), |
87 inside_action_(SchedulerStateMachine::ACTION_NONE), | 33 inside_action_(SchedulerStateMachine::ACTION_NONE), |
88 weak_factory_(this) { | 34 weak_factory_(this) { |
89 DCHECK(client_); | 35 DCHECK(client_); |
90 DCHECK(!state_machine_.BeginFrameNeeded()); | 36 DCHECK(!state_machine_.BeginFrameNeeded()); |
91 if (settings_.main_frame_before_activation_enabled) { | 37 if (settings_.main_frame_before_activation_enabled) { |
(...skipping 10 matching lines...) Expand all Loading... |
102 &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr()); | 48 &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr()); |
103 advance_commit_state_closure_ = base::Bind( | 49 advance_commit_state_closure_ = base::Bind( |
104 &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr()); | 50 &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr()); |
105 | 51 |
106 if (!settings_.begin_frame_scheduling_enabled) { | 52 if (!settings_.begin_frame_scheduling_enabled) { |
107 SetupSyntheticBeginFrames(); | 53 SetupSyntheticBeginFrames(); |
108 } | 54 } |
109 } | 55 } |
110 | 56 |
111 Scheduler::~Scheduler() { | 57 Scheduler::~Scheduler() { |
112 if (synthetic_begin_frame_source_) { | 58 frame_source_->SetNeedsBeginFrame(false); |
113 synthetic_begin_frame_source_->SetNeedsBeginFrame(false, | |
114 &begin_retro_frame_args_); | |
115 } | |
116 } | |
117 | |
118 void Scheduler::SetupSyntheticBeginFrames() { | |
119 DCHECK(!synthetic_begin_frame_source_); | |
120 synthetic_begin_frame_source_.reset( | |
121 new SyntheticBeginFrameSource(this, impl_task_runner_.get())); | |
122 } | 59 } |
123 | 60 |
124 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, | 61 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, |
125 base::TimeDelta interval) { | 62 base::TimeDelta interval) { |
126 // TODO(brianderson): We should not be receiving 0 intervals. | 63 // TODO(brianderson): We should not be receiving 0 intervals. |
127 if (interval == base::TimeDelta()) | 64 if (interval == base::TimeDelta()) |
128 interval = BeginFrameArgs::DefaultInterval(); | 65 interval = BeginFrameArgs::DefaultInterval(); |
129 vsync_interval_ = interval; | |
130 if (!settings_.begin_frame_scheduling_enabled) | 66 if (!settings_.begin_frame_scheduling_enabled) |
131 synthetic_begin_frame_source_->CommitVSyncParameters(timebase, interval); | 67 frame_source_->UpdateFrameSource(timebase, interval); |
132 } | 68 } |
133 | 69 |
134 void Scheduler::SetEstimatedParentDrawTime(base::TimeDelta draw_time) { | 70 void Scheduler::SetEstimatedParentDrawTime(base::TimeDelta draw_time) { |
135 estimated_parent_draw_time_ = draw_time; | 71 estimated_parent_draw_time_ = draw_time; |
136 } | 72 } |
137 | 73 |
138 void Scheduler::SetCanStart() { | 74 void Scheduler::SetCanStart() { |
139 state_machine_.SetCanStart(); | 75 state_machine_.SetCanStart(); |
140 ProcessScheduledActions(); | 76 ProcessScheduledActions(); |
141 } | 77 } |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
261 int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval); | 197 int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval); |
262 return timebase + (begin_impl_frame_args_.interval * intervals); | 198 return timebase + (begin_impl_frame_args_.interval * intervals); |
263 } | 199 } |
264 | 200 |
265 base::TimeTicks Scheduler::LastBeginImplFrameTime() { | 201 base::TimeTicks Scheduler::LastBeginImplFrameTime() { |
266 return begin_impl_frame_args_.frame_time; | 202 return begin_impl_frame_args_.frame_time; |
267 } | 203 } |
268 | 204 |
269 void Scheduler::SetupNextBeginFrameIfNeeded() { | 205 void Scheduler::SetupNextBeginFrameIfNeeded() { |
270 bool needs_begin_frame = state_machine_.BeginFrameNeeded(); | 206 bool needs_begin_frame = state_machine_.BeginFrameNeeded(); |
271 | 207 frame_source_->SetNeedsBeginFrame(needs_begin_frame); |
272 if (settings_.throttle_frame_production) { | |
273 SetupNextBeginFrameWhenVSyncThrottlingEnabled(needs_begin_frame); | |
274 } else { | |
275 SetupNextBeginFrameWhenVSyncThrottlingDisabled(needs_begin_frame); | |
276 } | |
277 SetupPollingMechanisms(needs_begin_frame); | 208 SetupPollingMechanisms(needs_begin_frame); |
278 } | 209 } |
279 | 210 |
280 // When we are throttling frame production, we request BeginFrames | |
281 // from the OutputSurface. | |
282 void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingEnabled( | |
283 bool needs_begin_frame) { | |
284 bool at_end_of_deadline = | |
285 state_machine_.begin_impl_frame_state() == | |
286 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE; | |
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 && !last_set_needs_begin_frame_) || | |
291 // Only stop requesting BeginFrames after a deadline. | |
292 (!needs_begin_frame && last_set_needs_begin_frame_ && at_end_of_deadline); | |
293 | |
294 if (should_call_set_needs_begin_frame) { | |
295 if (settings_.begin_frame_scheduling_enabled) { | |
296 client_->SetNeedsBeginFrame(needs_begin_frame); | |
297 } else { | |
298 synthetic_begin_frame_source_->SetNeedsBeginFrame( | |
299 needs_begin_frame, &begin_retro_frame_args_); | |
300 } | |
301 last_set_needs_begin_frame_ = needs_begin_frame; | |
302 } | |
303 | |
304 PostBeginRetroFrameIfNeeded(); | |
305 } | |
306 | |
307 // When we aren't throttling frame production, we initiate a BeginFrame | |
308 // as soon as one is needed. | |
309 void Scheduler::SetupNextBeginFrameWhenVSyncThrottlingDisabled( | |
310 bool needs_begin_frame) { | |
311 last_set_needs_begin_frame_ = needs_begin_frame; | |
312 | |
313 if (!needs_begin_frame || begin_unthrottled_frame_posted_) | |
314 return; | |
315 | |
316 if (state_machine_.begin_impl_frame_state() != | |
317 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE && | |
318 state_machine_.begin_impl_frame_state() != | |
319 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) { | |
320 return; | |
321 } | |
322 | |
323 begin_unthrottled_frame_posted_ = true; | |
324 impl_task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_); | |
325 } | |
326 | |
327 // BeginUnthrottledFrame is used when we aren't throttling frame production. | |
328 // This will usually be because VSync is disabled. | |
329 void Scheduler::BeginUnthrottledFrame() { | |
330 DCHECK(!settings_.throttle_frame_production); | |
331 DCHECK(begin_retro_frame_args_.empty()); | |
332 | |
333 base::TimeTicks now = gfx::FrameTime::Now(); | |
334 base::TimeTicks deadline = now + vsync_interval_; | |
335 | |
336 BeginFrameArgs begin_frame_args = | |
337 BeginFrameArgs::Create(now, deadline, vsync_interval_); | |
338 BeginImplFrame(begin_frame_args); | |
339 | |
340 begin_unthrottled_frame_posted_ = false; | |
341 } | |
342 | |
343 // We may need to poll when we can't rely on BeginFrame to advance certain | 211 // We may need to poll when we can't rely on BeginFrame to advance certain |
344 // state or to avoid deadlock. | 212 // state or to avoid deadlock. |
345 void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) { | 213 void Scheduler::SetupPollingMechanisms(bool needs_begin_frame) { |
346 bool needs_advance_commit_state_timer = false; | 214 bool needs_advance_commit_state_timer = false; |
347 // Setup PollForAnticipatedDrawTriggers if we need to monitor state but | 215 // Setup PollForAnticipatedDrawTriggers if we need to monitor state but |
348 // aren't expecting any more BeginFrames. This should only be needed by | 216 // aren't expecting any more BeginFrames. This should only be needed by |
349 // the synchronous compositor when BeginFrameNeeded is false. | 217 // the synchronous compositor when BeginFrameNeeded is false. |
350 if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) { | 218 if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) { |
351 DCHECK(!state_machine_.SupportsProactiveBeginFrame()); | 219 DCHECK(!state_machine_.SupportsProactiveBeginFrame()); |
352 DCHECK(!needs_begin_frame); | 220 DCHECK(!needs_begin_frame); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
388 advance_commit_state_task_.Cancel(); | 256 advance_commit_state_task_.Cancel(); |
389 } | 257 } |
390 } | 258 } |
391 | 259 |
392 // BeginFrame is the mechanism that tells us that now is a good time to start | 260 // BeginFrame is the mechanism that tells us that now is a good time to start |
393 // making a frame. Usually this means that user input for the frame is complete. | 261 // making a frame. Usually this means that user input for the frame is complete. |
394 // If the scheduler is busy, we queue the BeginFrame to be handled later as | 262 // If the scheduler is busy, we queue the BeginFrame to be handled later as |
395 // a BeginRetroFrame. | 263 // a BeginRetroFrame. |
396 void Scheduler::BeginFrame(const BeginFrameArgs& args) { | 264 void Scheduler::BeginFrame(const BeginFrameArgs& args) { |
397 TRACE_EVENT1("cc", "Scheduler::BeginFrame", "frame_time", args.frame_time); | 265 TRACE_EVENT1("cc", "Scheduler::BeginFrame", "frame_time", args.frame_time); |
| 266 |
| 267 clock_source->BeginFrame(this, args); |
| 268 } |
| 269 |
| 270 void Scheduler::BeginFrameOnScheduler(const BeginFrameArgs& args) { |
| 271 TRACE_EVENT1( |
| 272 "cc", "Scheduler::BeginFrameOnScheduler", "frame_time", args.frame_time); |
| 273 |
398 DCHECK(settings_.throttle_frame_production); | 274 DCHECK(settings_.throttle_frame_production); |
399 | 275 |
400 bool should_defer_begin_frame; | 276 bool should_defer_begin_frame; |
401 if (settings_.using_synchronous_renderer_compositor) { | 277 if (settings_.using_synchronous_renderer_compositor) { |
402 should_defer_begin_frame = false; | 278 should_defer_begin_frame = false; |
403 } else { | 279 } else { |
404 should_defer_begin_frame = | 280 should_defer_begin_frame = |
405 !begin_retro_frame_args_.empty() || begin_retro_frame_posted_ || | 281 !begin_retro_frame_args_.empty() || begin_retro_frame_posted_ || |
406 !last_set_needs_begin_frame_ || | 282 !last_set_needs_begin_frame_ || |
407 (state_machine_.begin_impl_frame_state() != | 283 (state_machine_.begin_impl_frame_state() != |
(...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
683 } | 559 } |
684 } | 560 } |
685 | 561 |
686 bool Scheduler::WillDrawIfNeeded() const { | 562 bool Scheduler::WillDrawIfNeeded() const { |
687 return !state_machine_.PendingDrawsShouldBeAborted(); | 563 return !state_machine_.PendingDrawsShouldBeAborted(); |
688 } | 564 } |
689 | 565 |
690 scoped_ptr<base::Value> Scheduler::StateAsValue() const { | 566 scoped_ptr<base::Value> Scheduler::StateAsValue() const { |
691 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue); | 567 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue); |
692 state->Set("state_machine", state_machine_.AsValue().release()); | 568 state->Set("state_machine", state_machine_.AsValue().release()); |
| 569 state->Set("frame_source", frame_source_.AsValue().release()); |
693 | 570 |
694 scoped_ptr<base::DictionaryValue> scheduler_state(new base::DictionaryValue); | 571 scoped_ptr<base::DictionaryValue> scheduler_state(new base::DictionaryValue); |
695 scheduler_state->SetDouble( | 572 scheduler_state->SetDouble( |
696 "time_until_anticipated_draw_time_ms", | 573 "time_until_anticipated_draw_time_ms", |
697 (AnticipatedDrawTime() - base::TimeTicks::Now()).InMillisecondsF()); | 574 (AnticipatedDrawTime() - base::TimeTicks::Now()).InMillisecondsF()); |
698 scheduler_state->SetDouble("vsync_interval_ms", | |
699 vsync_interval_.InMillisecondsF()); | |
700 scheduler_state->SetDouble("estimated_parent_draw_time_ms", | 575 scheduler_state->SetDouble("estimated_parent_draw_time_ms", |
701 estimated_parent_draw_time_.InMillisecondsF()); | 576 estimated_parent_draw_time_.InMillisecondsF()); |
702 scheduler_state->SetBoolean("last_set_needs_begin_frame_", | 577 scheduler_state->SetBoolean("last_set_needs_begin_frame_", |
703 last_set_needs_begin_frame_); | 578 last_set_needs_begin_frame_); |
704 scheduler_state->SetBoolean("begin_unthrottled_frame_posted_", | 579 scheduler_state->SetBoolean("begin_unthrottled_frame_posted_", |
705 begin_unthrottled_frame_posted_); | 580 begin_unthrottled_frame_posted_); |
706 scheduler_state->SetBoolean("begin_retro_frame_posted_", | 581 scheduler_state->SetBoolean("begin_retro_frame_posted_", |
707 begin_retro_frame_posted_); | 582 begin_retro_frame_posted_); |
708 scheduler_state->SetInteger("begin_retro_frame_args_", | 583 scheduler_state->SetInteger("begin_retro_frame_args_", |
709 begin_retro_frame_args_.size()); | 584 begin_retro_frame_args_.size()); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
748 } | 623 } |
749 | 624 |
750 bool Scheduler::IsBeginMainFrameSentOrStarted() const { | 625 bool Scheduler::IsBeginMainFrameSentOrStarted() const { |
751 return (state_machine_.commit_state() == | 626 return (state_machine_.commit_state() == |
752 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || | 627 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || |
753 state_machine_.commit_state() == | 628 state_machine_.commit_state() == |
754 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); | 629 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); |
755 } | 630 } |
756 | 631 |
757 } // namespace cc | 632 } // namespace cc |
OLD | NEW |