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" |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
70 base::TimeTicks frame_time) { | 70 base::TimeTicks frame_time) { |
71 base::TimeTicks deadline = time_source_->NextTickTime(); | 71 base::TimeTicks deadline = time_source_->NextTickTime(); |
72 return BeginFrameArgs::Create( | 72 return BeginFrameArgs::Create( |
73 frame_time, deadline, scheduler_->VSyncInterval()); | 73 frame_time, deadline, scheduler_->VSyncInterval()); |
74 } | 74 } |
75 | 75 |
76 Scheduler::Scheduler( | 76 Scheduler::Scheduler( |
77 SchedulerClient* client, | 77 SchedulerClient* client, |
78 const SchedulerSettings& scheduler_settings, | 78 const SchedulerSettings& scheduler_settings, |
79 int layer_tree_host_id, | 79 int layer_tree_host_id, |
80 const scoped_refptr<base::SingleThreadTaskRunner>& impl_task_runner) | 80 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) |
81 : settings_(scheduler_settings), | 81 : settings_(scheduler_settings), |
82 client_(client), | 82 client_(client), |
83 layer_tree_host_id_(layer_tree_host_id), | 83 layer_tree_host_id_(layer_tree_host_id), |
84 impl_task_runner_(impl_task_runner), | 84 task_runner_(task_runner), |
85 vsync_interval_(BeginFrameArgs::DefaultInterval()), | 85 vsync_interval_(BeginFrameArgs::DefaultInterval()), |
86 last_set_needs_begin_frame_(false), | 86 last_set_needs_begin_frame_(false), |
87 begin_unthrottled_frame_posted_(false), | 87 begin_unthrottled_frame_posted_(false), |
88 begin_retro_frame_posted_(false), | 88 begin_retro_frame_posted_(false), |
89 state_machine_(scheduler_settings), | 89 state_machine_(scheduler_settings), |
90 inside_process_scheduled_actions_(false), | 90 inside_process_scheduled_actions_(false), |
91 inside_action_(SchedulerStateMachine::ACTION_NONE), | 91 inside_action_(SchedulerStateMachine::ACTION_NONE), |
92 weak_factory_(this) { | 92 weak_factory_(this) { |
93 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), | 93 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), |
94 "Scheduler::Scheduler", | 94 "Scheduler::Scheduler", |
(...skipping 24 matching lines...) Expand all Loading... |
119 Scheduler::~Scheduler() { | 119 Scheduler::~Scheduler() { |
120 if (synthetic_begin_frame_source_) { | 120 if (synthetic_begin_frame_source_) { |
121 synthetic_begin_frame_source_->SetNeedsBeginFrame(false, | 121 synthetic_begin_frame_source_->SetNeedsBeginFrame(false, |
122 &begin_retro_frame_args_); | 122 &begin_retro_frame_args_); |
123 } | 123 } |
124 } | 124 } |
125 | 125 |
126 void Scheduler::SetupSyntheticBeginFrames() { | 126 void Scheduler::SetupSyntheticBeginFrames() { |
127 DCHECK(!synthetic_begin_frame_source_); | 127 DCHECK(!synthetic_begin_frame_source_); |
128 synthetic_begin_frame_source_.reset( | 128 synthetic_begin_frame_source_.reset( |
129 new SyntheticBeginFrameSource(this, impl_task_runner_.get())); | 129 new SyntheticBeginFrameSource(this, task_runner_.get())); |
130 } | 130 } |
131 | 131 |
132 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, | 132 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, |
133 base::TimeDelta interval) { | 133 base::TimeDelta interval) { |
134 // TODO(brianderson): We should not be receiving 0 intervals. | 134 // TODO(brianderson): We should not be receiving 0 intervals. |
135 if (interval == base::TimeDelta()) | 135 if (interval == base::TimeDelta()) |
136 interval = BeginFrameArgs::DefaultInterval(); | 136 interval = BeginFrameArgs::DefaultInterval(); |
137 vsync_interval_ = interval; | 137 vsync_interval_ = interval; |
138 if (!settings_.begin_frame_scheduling_enabled) | 138 if (!settings_.begin_frame_scheduling_enabled) |
139 synthetic_begin_frame_source_->CommitVSyncParameters(timebase, interval); | 139 synthetic_begin_frame_source_->CommitVSyncParameters(timebase, interval); |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
265 begin_impl_frame_args_.deadline); | 265 begin_impl_frame_args_.deadline); |
266 int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval); | 266 int64 intervals = 1 + ((now - timebase) / begin_impl_frame_args_.interval); |
267 return timebase + (begin_impl_frame_args_.interval * intervals); | 267 return timebase + (begin_impl_frame_args_.interval * intervals); |
268 } | 268 } |
269 | 269 |
270 base::TimeTicks Scheduler::LastBeginImplFrameTime() { | 270 base::TimeTicks Scheduler::LastBeginImplFrameTime() { |
271 return begin_impl_frame_args_.frame_time; | 271 return begin_impl_frame_args_.frame_time; |
272 } | 272 } |
273 | 273 |
274 void Scheduler::SetupNextBeginFrameIfNeeded() { | 274 void Scheduler::SetupNextBeginFrameIfNeeded() { |
| 275 if (!task_runner_) |
| 276 return; |
| 277 |
275 bool needs_begin_frame = state_machine_.BeginFrameNeeded(); | 278 bool needs_begin_frame = state_machine_.BeginFrameNeeded(); |
276 | 279 |
277 if (settings_.throttle_frame_production) { | 280 if (settings_.throttle_frame_production) { |
278 SetupNextBeginFrameWhenVSyncThrottlingEnabled(needs_begin_frame); | 281 SetupNextBeginFrameWhenVSyncThrottlingEnabled(needs_begin_frame); |
279 } else { | 282 } else { |
280 SetupNextBeginFrameWhenVSyncThrottlingDisabled(needs_begin_frame); | 283 SetupNextBeginFrameWhenVSyncThrottlingDisabled(needs_begin_frame); |
281 } | 284 } |
282 SetupPollingMechanisms(needs_begin_frame); | 285 SetupPollingMechanisms(needs_begin_frame); |
283 } | 286 } |
284 | 287 |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
319 return; | 322 return; |
320 | 323 |
321 if (state_machine_.begin_impl_frame_state() != | 324 if (state_machine_.begin_impl_frame_state() != |
322 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE && | 325 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE && |
323 state_machine_.begin_impl_frame_state() != | 326 state_machine_.begin_impl_frame_state() != |
324 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) { | 327 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) { |
325 return; | 328 return; |
326 } | 329 } |
327 | 330 |
328 begin_unthrottled_frame_posted_ = true; | 331 begin_unthrottled_frame_posted_ = true; |
329 impl_task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_); | 332 task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_); |
330 } | 333 } |
331 | 334 |
332 // BeginUnthrottledFrame is used when we aren't throttling frame production. | 335 // BeginUnthrottledFrame is used when we aren't throttling frame production. |
333 // This will usually be because VSync is disabled. | 336 // This will usually be because VSync is disabled. |
334 void Scheduler::BeginUnthrottledFrame() { | 337 void Scheduler::BeginUnthrottledFrame() { |
335 DCHECK(!settings_.throttle_frame_production); | 338 DCHECK(!settings_.throttle_frame_production); |
336 DCHECK(begin_retro_frame_args_.empty()); | 339 DCHECK(begin_retro_frame_args_.empty()); |
337 | 340 |
338 base::TimeTicks now = gfx::FrameTime::Now(); | 341 base::TimeTicks now = gfx::FrameTime::Now(); |
339 base::TimeTicks deadline = now + vsync_interval_; | 342 base::TimeTicks deadline = now + vsync_interval_; |
(...skipping 13 matching lines...) Expand all Loading... |
353 // aren't expecting any more BeginFrames. This should only be needed by | 356 // aren't expecting any more BeginFrames. This should only be needed by |
354 // the synchronous compositor when BeginFrameNeeded is false. | 357 // the synchronous compositor when BeginFrameNeeded is false. |
355 if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) { | 358 if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) { |
356 DCHECK(!state_machine_.SupportsProactiveBeginFrame()); | 359 DCHECK(!state_machine_.SupportsProactiveBeginFrame()); |
357 DCHECK(!needs_begin_frame); | 360 DCHECK(!needs_begin_frame); |
358 if (poll_for_draw_triggers_task_.IsCancelled()) { | 361 if (poll_for_draw_triggers_task_.IsCancelled()) { |
359 poll_for_draw_triggers_task_.Reset(poll_for_draw_triggers_closure_); | 362 poll_for_draw_triggers_task_.Reset(poll_for_draw_triggers_closure_); |
360 base::TimeDelta delay = begin_impl_frame_args_.IsValid() | 363 base::TimeDelta delay = begin_impl_frame_args_.IsValid() |
361 ? begin_impl_frame_args_.interval | 364 ? begin_impl_frame_args_.interval |
362 : BeginFrameArgs::DefaultInterval(); | 365 : BeginFrameArgs::DefaultInterval(); |
363 impl_task_runner_->PostDelayedTask( | 366 task_runner_->PostDelayedTask( |
364 FROM_HERE, poll_for_draw_triggers_task_.callback(), delay); | 367 FROM_HERE, poll_for_draw_triggers_task_.callback(), delay); |
365 } | 368 } |
366 } else { | 369 } else { |
367 poll_for_draw_triggers_task_.Cancel(); | 370 poll_for_draw_triggers_task_.Cancel(); |
368 | 371 |
369 // At this point we'd prefer to advance through the commit flow by | 372 // At this point we'd prefer to advance through the commit flow by |
370 // drawing a frame, however it's possible that the frame rate controller | 373 // drawing a frame, however it's possible that the frame rate controller |
371 // will not give us a BeginFrame until the commit completes. See | 374 // will not give us a BeginFrame until the commit completes. See |
372 // crbug.com/317430 for an example of a swap ack being held on commit. Thus | 375 // crbug.com/317430 for an example of a swap ack being held on commit. Thus |
373 // we set a repeating timer to poll on ProcessScheduledActions until we | 376 // we set a repeating timer to poll on ProcessScheduledActions until we |
374 // successfully reach BeginFrame. Synchronous compositor does not use | 377 // successfully reach BeginFrame. Synchronous compositor does not use |
375 // frame rate controller or have the circular wait in the bug. | 378 // frame rate controller or have the circular wait in the bug. |
376 if (IsBeginMainFrameSentOrStarted() && | 379 if (IsBeginMainFrameSentOrStarted() && |
377 !settings_.using_synchronous_renderer_compositor) { | 380 !settings_.using_synchronous_renderer_compositor) { |
378 needs_advance_commit_state_timer = true; | 381 needs_advance_commit_state_timer = true; |
379 } | 382 } |
380 } | 383 } |
381 | 384 |
382 if (needs_advance_commit_state_timer) { | 385 if (needs_advance_commit_state_timer) { |
383 if (advance_commit_state_task_.IsCancelled() && | 386 if (advance_commit_state_task_.IsCancelled() && |
384 begin_impl_frame_args_.IsValid()) { | 387 begin_impl_frame_args_.IsValid()) { |
385 // Since we'd rather get a BeginImplFrame by the normal mechanism, we | 388 // Since we'd rather get a BeginImplFrame by the normal mechanism, we |
386 // set the interval to twice the interval from the previous frame. | 389 // set the interval to twice the interval from the previous frame. |
387 advance_commit_state_task_.Reset(advance_commit_state_closure_); | 390 advance_commit_state_task_.Reset(advance_commit_state_closure_); |
388 impl_task_runner_->PostDelayedTask(FROM_HERE, | 391 task_runner_->PostDelayedTask(FROM_HERE, |
389 advance_commit_state_task_.callback(), | 392 advance_commit_state_task_.callback(), |
390 begin_impl_frame_args_.interval * 2); | 393 begin_impl_frame_args_.interval * 2); |
391 } | 394 } |
392 } else { | 395 } else { |
393 advance_commit_state_task_.Cancel(); | 396 advance_commit_state_task_.Cancel(); |
394 } | 397 } |
395 } | 398 } |
396 | 399 |
397 // BeginFrame is the mechanism that tells us that now is a good time to start | 400 // BeginFrame is the mechanism that tells us that now is a good time to start |
398 // making a frame. Usually this means that user input for the frame is complete. | 401 // making a frame. Usually this means that user input for the frame is complete. |
399 // If the scheduler is busy, we queue the BeginFrame to be handled later as | 402 // If the scheduler is busy, we queue the BeginFrame to be handled later as |
400 // a BeginRetroFrame. | 403 // a BeginRetroFrame. |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
482 | 485 |
483 // begin_retro_frame_args_ should always be empty for the | 486 // begin_retro_frame_args_ should always be empty for the |
484 // synchronous compositor. | 487 // synchronous compositor. |
485 DCHECK(!settings_.using_synchronous_renderer_compositor); | 488 DCHECK(!settings_.using_synchronous_renderer_compositor); |
486 | 489 |
487 if (state_machine_.begin_impl_frame_state() != | 490 if (state_machine_.begin_impl_frame_state() != |
488 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE) | 491 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE) |
489 return; | 492 return; |
490 | 493 |
491 begin_retro_frame_posted_ = true; | 494 begin_retro_frame_posted_ = true; |
492 impl_task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_); | 495 task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_); |
493 } | 496 } |
494 | 497 |
495 // BeginImplFrame starts a compositor frame that will wait up until a deadline | 498 // BeginImplFrame starts a compositor frame that will wait up until a deadline |
496 // for a BeginMainFrame+activation to complete before it times out and draws | 499 // for a BeginMainFrame+activation to complete before it times out and draws |
497 // any asynchronous animation and scroll/pinch updates. | 500 // any asynchronous animation and scroll/pinch updates. |
498 void Scheduler::BeginImplFrame(const BeginFrameArgs& args) { | 501 void Scheduler::BeginImplFrame(const BeginFrameArgs& args) { |
499 TRACE_EVENT1("cc", "Scheduler::BeginImplFrame", "args", ToTrace(args)); | 502 TRACE_EVENT1("cc", "Scheduler::BeginImplFrame", "args", ToTrace(args)); |
500 DCHECK(state_machine_.begin_impl_frame_state() == | 503 DCHECK_EQ(state_machine_.begin_impl_frame_state(), |
501 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); | 504 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); |
502 DCHECK(state_machine_.HasInitializedOutputSurface()); | 505 DCHECK(state_machine_.HasInitializedOutputSurface()); |
503 | 506 |
504 advance_commit_state_task_.Cancel(); | 507 advance_commit_state_task_.Cancel(); |
505 | 508 |
506 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); | 509 base::TimeDelta draw_duration_estimate = client_->DrawDurationEstimate(); |
507 begin_impl_frame_args_ = args; | 510 begin_impl_frame_args_ = args; |
508 begin_impl_frame_args_.deadline -= draw_duration_estimate; | 511 begin_impl_frame_args_.deadline -= draw_duration_estimate; |
509 | 512 |
510 if (!state_machine_.smoothness_takes_priority() && | 513 if (!state_machine_.smoothness_takes_priority() && |
511 state_machine_.MainThreadIsInHighLatencyMode() && | 514 state_machine_.MainThreadIsInHighLatencyMode() && |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
558 // up the BeginImplFrame and deadline as well. | 561 // up the BeginImplFrame and deadline as well. |
559 OnBeginImplFrameDeadline(); | 562 OnBeginImplFrameDeadline(); |
560 return; | 563 return; |
561 } | 564 } |
562 begin_impl_frame_deadline_task_.Cancel(); | 565 begin_impl_frame_deadline_task_.Cancel(); |
563 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_); | 566 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_); |
564 | 567 |
565 base::TimeDelta delta = deadline - gfx::FrameTime::Now(); | 568 base::TimeDelta delta = deadline - gfx::FrameTime::Now(); |
566 if (delta <= base::TimeDelta()) | 569 if (delta <= base::TimeDelta()) |
567 delta = base::TimeDelta(); | 570 delta = base::TimeDelta(); |
568 impl_task_runner_->PostDelayedTask( | 571 task_runner_->PostDelayedTask( |
569 FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta); | 572 FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta); |
570 } | 573 } |
571 | 574 |
572 void Scheduler::OnBeginImplFrameDeadline() { | 575 void Scheduler::OnBeginImplFrameDeadline() { |
573 TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline"); | 576 TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline"); |
574 begin_impl_frame_deadline_task_.Cancel(); | 577 begin_impl_frame_deadline_task_.Cancel(); |
575 | 578 |
576 // We split the deadline actions up into two phases so the state machine | 579 // We split the deadline actions up into two phases so the state machine |
577 // has a chance to trigger actions that should occur durring and after | 580 // has a chance to trigger actions that should occur durring and after |
578 // the deadline separately. For example: | 581 // the deadline separately. For example: |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
747 } | 750 } |
748 | 751 |
749 bool Scheduler::IsBeginMainFrameSentOrStarted() const { | 752 bool Scheduler::IsBeginMainFrameSentOrStarted() const { |
750 return (state_machine_.commit_state() == | 753 return (state_machine_.commit_state() == |
751 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || | 754 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || |
752 state_machine_.commit_state() == | 755 state_machine_.commit_state() == |
753 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); | 756 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); |
754 } | 757 } |
755 | 758 |
756 } // namespace cc | 759 } // namespace cc |
OLD | NEW |