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 | 8 |
9 #include "base/auto_reset.h" | 9 #include "base/auto_reset.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
122 | 122 |
123 base::TimeTicks Scheduler::Now() const { | 123 base::TimeTicks Scheduler::Now() const { |
124 base::TimeTicks now = gfx::FrameTime::Now(); | 124 base::TimeTicks now = gfx::FrameTime::Now(); |
125 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.now"), | 125 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.now"), |
126 "Scheduler::Now", | 126 "Scheduler::Now", |
127 "now", | 127 "now", |
128 now); | 128 now); |
129 return now; | 129 return now; |
130 } | 130 } |
131 | 131 |
132 void Scheduler::SetAuthoritativeVSyncInterval(const base::TimeDelta& interval) { | |
133 authoritative_vsync_interval_ = interval; | |
134 if (vsync_observer_) | |
135 vsync_observer_->OnUpdateVSyncParameters(last_vsync_timebase_, interval); | |
136 } | |
137 | |
132 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, | 138 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase, |
133 base::TimeDelta interval) { | 139 base::TimeDelta interval) { |
140 TRACE_EVENT2("cc", "Scheduler::CommitVSyncParameters", "timebase", | |
141 (timebase - base::TimeTicks()).InSecondsF(), "interval", | |
142 interval.InSecondsF()); | |
143 | |
134 if (authoritative_vsync_interval_ != base::TimeDelta()) { | 144 if (authoritative_vsync_interval_ != base::TimeDelta()) { |
135 interval = authoritative_vsync_interval_; | 145 interval = authoritative_vsync_interval_; |
136 } else if (interval == base::TimeDelta()) { | 146 } else if (interval == base::TimeDelta()) { |
137 // TODO(brianderson): We should not be receiving 0 intervals. | 147 // TODO(brianderson): We should not be receiving 0 intervals. |
138 interval = BeginFrameArgs::DefaultInterval(); | 148 interval = BeginFrameArgs::DefaultInterval(); |
139 } | 149 } |
140 | 150 |
141 last_vsync_timebase_ = timebase; | 151 last_vsync_timebase_ = timebase; |
142 | 152 |
143 if (vsync_observer_) | 153 if (vsync_observer_) |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
380 BeginImplFrameWithDeadline(adjusted_args); | 390 BeginImplFrameWithDeadline(adjusted_args); |
381 } | 391 } |
382 return true; | 392 return true; |
383 } | 393 } |
384 | 394 |
385 void Scheduler::SetChildrenNeedBeginFrames(bool children_need_begin_frames) { | 395 void Scheduler::SetChildrenNeedBeginFrames(bool children_need_begin_frames) { |
386 state_machine_.SetChildrenNeedBeginFrames(children_need_begin_frames); | 396 state_machine_.SetChildrenNeedBeginFrames(children_need_begin_frames); |
387 ProcessScheduledActions(); | 397 ProcessScheduledActions(); |
388 } | 398 } |
389 | 399 |
390 void Scheduler::SetAuthoritativeVSyncInterval(const base::TimeDelta& interval) { | |
391 authoritative_vsync_interval_ = interval; | |
392 if (vsync_observer_) | |
393 vsync_observer_->OnUpdateVSyncParameters(last_vsync_timebase_, interval); | |
394 } | |
395 | |
396 void Scheduler::SetVideoNeedsBeginFrames(bool video_needs_begin_frames) { | 400 void Scheduler::SetVideoNeedsBeginFrames(bool video_needs_begin_frames) { |
397 state_machine_.SetVideoNeedsBeginFrames(video_needs_begin_frames); | 401 state_machine_.SetVideoNeedsBeginFrames(video_needs_begin_frames); |
398 ProcessScheduledActions(); | 402 ProcessScheduledActions(); |
399 } | 403 } |
400 | 404 |
401 void Scheduler::OnDrawForOutputSurface() { | 405 void Scheduler::OnDrawForOutputSurface() { |
402 DCHECK(settings_.using_synchronous_renderer_compositor); | 406 DCHECK(settings_.using_synchronous_renderer_compositor); |
403 DCHECK_EQ(state_machine_.begin_impl_frame_state(), | 407 DCHECK_EQ(state_machine_.begin_impl_frame_state(), |
404 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); | 408 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); |
405 DCHECK(!BeginImplFrameDeadlinePending()); | 409 DCHECK(!BeginImplFrameDeadlinePending()); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
491 args.AsValue(), "main_thread_is_high_latency", | 495 args.AsValue(), "main_thread_is_high_latency", |
492 main_thread_is_in_high_latency_mode); | 496 main_thread_is_in_high_latency_mode); |
493 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), | 497 TRACE_COUNTER1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), |
494 "MainThreadLatency", main_thread_is_in_high_latency_mode); | 498 "MainThreadLatency", main_thread_is_in_high_latency_mode); |
495 | 499 |
496 advance_commit_state_task_.Cancel(); | 500 advance_commit_state_task_.Cancel(); |
497 | 501 |
498 begin_impl_frame_args_ = args; | 502 begin_impl_frame_args_ = args; |
499 begin_impl_frame_args_.deadline -= client_->DrawDurationEstimate(); | 503 begin_impl_frame_args_.deadline -= client_->DrawDurationEstimate(); |
500 | 504 |
501 if (!state_machine_.impl_latency_takes_priority() && | 505 BeginImplFrame(); |
502 main_thread_is_in_high_latency_mode && | 506 // Decide if we want skip any actions before we ProcessScheduledActions |
503 CanCommitAndActivateBeforeDeadline()) { | 507 // so that they take effect immediately rather than with a 1 frame delay. |
508 // Prioritize skipping the main thread's latency first so we can keep the | |
509 // main and impl threads synchronized. Then skip an impl frame if it makes | |
510 // sense. This avoids skipping both at the same time to avoid strange | |
511 // interactions/oscillations since ShouldRecoverImplLatency() depends on | |
512 // whether the main thread is in a high latency mode or not. | |
513 if (ShouldRecoverMainLatency()) { | |
514 TRACE_EVENT_INSTANT1("cc", "SkipBeginMainFrameToReduceLatency", | |
515 TRACE_EVENT_SCOPE_THREAD, "state", AsValue()); | |
504 state_machine_.SetSkipNextBeginMainFrameToReduceLatency(); | 516 state_machine_.SetSkipNextBeginMainFrameToReduceLatency(); |
517 } else if (ShouldRecoverImplLatency()) { | |
518 TRACE_EVENT_INSTANT1("cc", "SkipNextSwapToReduceLatency", | |
519 TRACE_EVENT_SCOPE_THREAD, "state", AsValue()); | |
520 state_machine_.SetSkipNextSwapToReduceLatency(); | |
sunnyps
2015/05/21 23:42:23
Can we call FinishImplFrame here instead of going
brianderson
2015/05/22 01:12:53
That's a good idea. I'll give it a try!
| |
505 } | 521 } |
506 | 522 ProcessScheduledActions(); |
sunnyps
2015/05/21 23:42:23
Any particular reason for splitting ProcessSchedul
brianderson
2015/05/22 01:12:53
SchedulerStateMachine::OnBeginImplFrame resets the
| |
507 BeginImplFrame(); | |
508 | 523 |
509 // The deadline will be scheduled in ProcessScheduledActions. | 524 // The deadline will be scheduled in ProcessScheduledActions. |
510 state_machine_.OnBeginImplFrameDeadlinePending(); | 525 state_machine_.OnBeginImplFrameDeadlinePending(); |
511 ProcessScheduledActions(); | 526 ProcessScheduledActions(); |
512 } | 527 } |
513 | 528 |
514 void Scheduler::BeginImplFrameSynchronous(const BeginFrameArgs& args) { | 529 void Scheduler::BeginImplFrameSynchronous(const BeginFrameArgs& args) { |
515 TRACE_EVENT1("cc,benchmark", "Scheduler::BeginImplFrame", "args", | 530 TRACE_EVENT1("cc,benchmark", "Scheduler::BeginImplFrame", "args", |
516 args.AsValue()); | 531 args.AsValue()); |
517 begin_impl_frame_args_ = args; | 532 begin_impl_frame_args_ = args; |
518 BeginImplFrame(); | 533 BeginImplFrame(); |
534 ProcessScheduledActions(); | |
535 | |
519 FinishImplFrame(); | 536 FinishImplFrame(); |
520 } | 537 } |
521 | 538 |
522 void Scheduler::FinishImplFrame() { | 539 void Scheduler::FinishImplFrame() { |
523 state_machine_.OnBeginImplFrameIdle(); | 540 state_machine_.OnBeginImplFrameIdle(); |
524 ProcessScheduledActions(); | 541 ProcessScheduledActions(); |
525 | 542 |
526 client_->DidFinishImplFrame(); | 543 client_->DidFinishImplFrame(); |
527 frame_source_->DidFinishFrame(begin_retro_frame_args_.size()); | 544 frame_source_->DidFinishFrame(begin_retro_frame_args_.size()); |
528 } | 545 } |
529 | 546 |
530 // BeginImplFrame starts a compositor frame that will wait up until a deadline | 547 // BeginImplFrame starts a compositor frame that will wait up until a deadline |
531 // for a BeginMainFrame+activation to complete before it times out and draws | 548 // for a BeginMainFrame+activation to complete before it times out and draws |
532 // any asynchronous animation and scroll/pinch updates. | 549 // any asynchronous animation and scroll/pinch updates. |
533 void Scheduler::BeginImplFrame() { | 550 void Scheduler::BeginImplFrame() { |
534 DCHECK_EQ(state_machine_.begin_impl_frame_state(), | 551 DCHECK_EQ(state_machine_.begin_impl_frame_state(), |
535 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); | 552 SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE); |
536 DCHECK(!BeginImplFrameDeadlinePending()); | 553 DCHECK(!BeginImplFrameDeadlinePending()); |
537 DCHECK(state_machine_.HasInitializedOutputSurface()); | 554 DCHECK(state_machine_.HasInitializedOutputSurface()); |
538 DCHECK(advance_commit_state_task_.IsCancelled()); | 555 DCHECK(advance_commit_state_task_.IsCancelled()); |
539 | 556 |
540 state_machine_.OnBeginImplFrame(); | 557 state_machine_.OnBeginImplFrame(); |
541 devtools_instrumentation::DidBeginFrame(layer_tree_host_id_); | 558 devtools_instrumentation::DidBeginFrame(layer_tree_host_id_); |
542 client_->WillBeginImplFrame(begin_impl_frame_args_); | 559 client_->WillBeginImplFrame(begin_impl_frame_args_); |
543 | |
544 ProcessScheduledActions(); | |
545 } | 560 } |
546 | 561 |
547 void Scheduler::ScheduleBeginImplFrameDeadline() { | 562 void Scheduler::ScheduleBeginImplFrameDeadline() { |
548 // The synchronous compositor does not post a deadline task. | 563 // The synchronous compositor does not post a deadline task. |
549 DCHECK(!settings_.using_synchronous_renderer_compositor); | 564 DCHECK(!settings_.using_synchronous_renderer_compositor); |
550 | 565 |
551 begin_impl_frame_deadline_task_.Cancel(); | 566 begin_impl_frame_deadline_task_.Cancel(); |
552 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_); | 567 begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_); |
553 | 568 |
554 begin_impl_frame_deadline_mode_ = | 569 begin_impl_frame_deadline_mode_ = |
555 state_machine_.CurrentBeginImplFrameDeadlineMode(); | 570 state_machine_.CurrentBeginImplFrameDeadlineMode(); |
556 | |
557 base::TimeTicks deadline; | 571 base::TimeTicks deadline; |
558 switch (begin_impl_frame_deadline_mode_) { | 572 switch (begin_impl_frame_deadline_mode_) { |
559 case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE: | 573 case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE: |
560 // No deadline. | 574 // No deadline. |
561 return; | 575 return; |
562 case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE: | 576 case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE: |
563 // We are ready to draw a new active tree immediately. | 577 // We are ready to draw a new active tree immediately. |
564 // We don't use Now() here because it's somewhat expensive to call. | 578 // We don't use Now() here because it's somewhat expensive to call. |
565 deadline = base::TimeTicks(); | 579 deadline = base::TimeTicks(); |
566 break; | 580 break; |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
764 state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size()); | 778 state->SetInteger("begin_retro_frame_args_", begin_retro_frame_args_.size()); |
765 state->SetBoolean("begin_retro_frame_task_", | 779 state->SetBoolean("begin_retro_frame_task_", |
766 !begin_retro_frame_task_.IsCancelled()); | 780 !begin_retro_frame_task_.IsCancelled()); |
767 state->SetBoolean("begin_impl_frame_deadline_task_", | 781 state->SetBoolean("begin_impl_frame_deadline_task_", |
768 !begin_impl_frame_deadline_task_.IsCancelled()); | 782 !begin_impl_frame_deadline_task_.IsCancelled()); |
769 state->SetBoolean("advance_commit_state_task_", | 783 state->SetBoolean("advance_commit_state_task_", |
770 !advance_commit_state_task_.IsCancelled()); | 784 !advance_commit_state_task_.IsCancelled()); |
771 state->BeginDictionary("begin_impl_frame_args"); | 785 state->BeginDictionary("begin_impl_frame_args"); |
772 begin_impl_frame_args_.AsValueInto(state); | 786 begin_impl_frame_args_.AsValueInto(state); |
773 state->EndDictionary(); | 787 state->EndDictionary(); |
788 state->SetString("begin_impl_frame_deadline_mode_", | |
789 SchedulerStateMachine::BeginImplFrameDeadlineModeToString( | |
790 begin_impl_frame_deadline_mode_)); | |
774 | 791 |
775 base::TimeTicks now = Now(); | 792 base::TimeTicks now = Now(); |
776 base::TimeTicks frame_time = begin_impl_frame_args_.frame_time; | 793 base::TimeTicks frame_time = begin_impl_frame_args_.frame_time; |
777 base::TimeTicks deadline = begin_impl_frame_args_.deadline; | 794 base::TimeTicks deadline = begin_impl_frame_args_.deadline; |
778 base::TimeDelta interval = begin_impl_frame_args_.interval; | 795 base::TimeDelta interval = begin_impl_frame_args_.interval; |
779 state->BeginDictionary("major_timestamps_in_ms"); | 796 state->BeginDictionary("major_timestamps_in_ms"); |
780 state->SetDouble("0_interval", interval.InMillisecondsF()); | 797 state->SetDouble("0_interval", interval.InMillisecondsF()); |
781 state->SetDouble("1_now_to_deadline", (deadline - now).InMillisecondsF()); | 798 state->SetDouble("1_now_to_deadline", (deadline - now).InMillisecondsF()); |
782 state->SetDouble("2_frame_time_to_now", (now - frame_time).InMillisecondsF()); | 799 state->SetDouble("2_frame_time_to_now", (now - frame_time).InMillisecondsF()); |
783 state->SetDouble("3_frame_time_to_deadline", | 800 state->SetDouble("3_frame_time_to_deadline", |
(...skipping 12 matching lines...) Expand all Loading... | |
796 client_->DrawDurationEstimate().InMillisecondsF()); | 813 client_->DrawDurationEstimate().InMillisecondsF()); |
797 state->SetDouble( | 814 state->SetDouble( |
798 "begin_main_frame_to_commit_duration_estimate_ms", | 815 "begin_main_frame_to_commit_duration_estimate_ms", |
799 client_->BeginMainFrameToCommitDurationEstimate().InMillisecondsF()); | 816 client_->BeginMainFrameToCommitDurationEstimate().InMillisecondsF()); |
800 state->SetDouble( | 817 state->SetDouble( |
801 "commit_to_activate_duration_estimate_ms", | 818 "commit_to_activate_duration_estimate_ms", |
802 client_->CommitToActivateDurationEstimate().InMillisecondsF()); | 819 client_->CommitToActivateDurationEstimate().InMillisecondsF()); |
803 state->EndDictionary(); | 820 state->EndDictionary(); |
804 } | 821 } |
805 | 822 |
823 bool Scheduler::ShouldRecoverMainLatency() const { | |
824 TRACE_EVENT0("cc", "ShouldRecoverMainLatency"); | |
825 if (!state_machine_.MainThreadIsInHighLatencyMode()) | |
826 return false; | |
827 | |
828 if (state_machine_.impl_latency_takes_priority()) | |
829 return false; | |
830 | |
831 return CanCommitAndActivateBeforeDeadline(); | |
832 } | |
833 | |
834 bool Scheduler::ShouldRecoverImplLatency() const { | |
835 TRACE_EVENT1("cc", "ShouldRecoverImplLatency", | |
836 "swaps_are_likely_high_latency", | |
837 state_machine_.swaps_are_likely_high_latency()); | |
838 if (!state_machine_.swaps_are_likely_high_latency()) | |
sunnyps
2015/05/21 23:42:22
When is swaps_are_likely_high_latency != pending_s
brianderson
2015/05/22 01:12:53
When the swap ack for a BeginImplFrame(1) comes ba
| |
839 return false; | |
840 | |
841 bool frame_time_is_before_deadline = | |
sunnyps
2015/05/21 23:42:23
Maybe we shouldn't adjust the deadline in begin_im
brianderson
2015/05/22 01:12:53
Are you saying the logic would be easier to follow
| |
842 begin_impl_frame_args_.frame_time < begin_impl_frame_args_.deadline; | |
843 | |
844 auto next_begin_impl_frame_deadline_mode = | |
sunnyps
2015/05/21 23:42:23
nit: Let's not use auto here.
brianderson
2015/05/22 01:12:53
Done.
| |
845 state_machine_.CurrentBeginImplFrameDeadlineMode(); | |
846 switch (next_begin_impl_frame_deadline_mode) { | |
847 case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_NONE: | |
848 return false; | |
849 case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_IMMEDIATE: | |
850 return frame_time_is_before_deadline; | |
851 case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_REGULAR: | |
852 return frame_time_is_before_deadline; | |
853 case SchedulerStateMachine::BEGIN_IMPL_FRAME_DEADLINE_MODE_LATE: | |
854 return CanCommitAndActivateBeforeDeadline(); | |
855 case SchedulerStateMachine:: | |
856 BEGIN_IMPL_FRAME_DEADLINE_MODE_BLOCKED_ON_READY_TO_DRAW: | |
857 return false; | |
858 } | |
859 NOTREACHED(); | |
860 return false; | |
861 } | |
862 | |
806 bool Scheduler::CanCommitAndActivateBeforeDeadline() const { | 863 bool Scheduler::CanCommitAndActivateBeforeDeadline() const { |
807 // Check if the main thread computation and commit can be finished before the | 864 // Check if the main thread computation and commit can be finished before the |
808 // impl thread's deadline. | 865 // impl thread's deadline. |
809 base::TimeTicks estimated_draw_time = | 866 base::TimeTicks estimated_draw_time = |
810 begin_impl_frame_args_.frame_time + | 867 begin_impl_frame_args_.frame_time + |
811 client_->BeginMainFrameToCommitDurationEstimate() + | 868 client_->BeginMainFrameToCommitDurationEstimate() + |
812 client_->CommitToActivateDurationEstimate(); | 869 client_->CommitToActivateDurationEstimate(); |
813 | 870 |
814 TRACE_EVENT2( | |
815 TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"), | |
816 "CanCommitAndActivateBeforeDeadline", | |
817 "time_left_after_drawing_ms", | |
818 (begin_impl_frame_args_.deadline - estimated_draw_time).InMillisecondsF(), | |
819 "state", | |
820 AsValue()); | |
821 | |
822 return estimated_draw_time < begin_impl_frame_args_.deadline; | 871 return estimated_draw_time < begin_impl_frame_args_.deadline; |
823 } | 872 } |
824 | 873 |
825 bool Scheduler::IsBeginMainFrameSentOrStarted() const { | 874 bool Scheduler::IsBeginMainFrameSentOrStarted() const { |
826 return (state_machine_.commit_state() == | 875 return (state_machine_.commit_state() == |
827 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || | 876 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT || |
828 state_machine_.commit_state() == | 877 state_machine_.commit_state() == |
829 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); | 878 SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED); |
830 } | 879 } |
831 | 880 |
832 } // namespace cc | 881 } // namespace cc |
OLD | NEW |