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