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 3 // found in the LICENSE file. 4 5 #include "cc/scheduler/frame_rate_controller.h" 6 7 #include "base/bind.h" 8 #include "base/debug/trace_event.h" 9 #include "base/location.h" 10 #include "base/logging.h" 11 #include "base/single_thread_task_runner.h" 12 #include "cc/scheduler/delay_based_time_source.h" 13 #include "cc/scheduler/time_source.h" 14 15 namespace cc { 16 17 class FrameRateControllerTimeSourceAdapter : public TimeSourceClient { 18 public: 19 static scoped_ptr<FrameRateControllerTimeSourceAdapter> Create( 20 FrameRateController* frame_rate_controller) { 21 return make_scoped_ptr( 22 new FrameRateControllerTimeSourceAdapter(frame_rate_controller)); 23 } 24 virtual ~FrameRateControllerTimeSourceAdapter() {} 25 26 virtual void OnTimerTick() OVERRIDE { 27 frame_rate_controller_->OnTimerTick(); 28 } 29 30 private: 31 explicit FrameRateControllerTimeSourceAdapter( 32 FrameRateController* frame_rate_controller) 33 : frame_rate_controller_(frame_rate_controller) {} 34 35 FrameRateController* frame_rate_controller_; 36 }; 37 38 FrameRateController::FrameRateController(scoped_refptr<TimeSource> timer) 39 : client_(NULL), 40 num_frames_pending_(0), 41 max_swaps_pending_(0), 42 interval_(BeginFrameArgs::DefaultInterval()), 43 time_source_(timer), 44 active_(false), 45 is_time_source_throttling_(true), 46 weak_factory_(this), 47 task_runner_(NULL) { 48 time_source_client_adapter_ = 49 FrameRateControllerTimeSourceAdapter::Create(this); 50 time_source_->SetClient(time_source_client_adapter_.get()); 51 } 52 53 FrameRateController::FrameRateController( 54 base::SingleThreadTaskRunner* task_runner) 55 : client_(NULL), 56 num_frames_pending_(0), 57 max_swaps_pending_(0), 58 interval_(BeginFrameArgs::DefaultInterval()), 59 active_(false), 60 is_time_source_throttling_(false), 61 weak_factory_(this), 62 task_runner_(task_runner) {} 63 64 FrameRateController::~FrameRateController() { 65 if (is_time_source_throttling_) 66 time_source_->SetActive(false); 67 } 68 69 BeginFrameArgs FrameRateController::SetActive(bool active) { 70 if (active_ == active) 71 return BeginFrameArgs(); 72 TRACE_EVENT1("cc", "FrameRateController::SetActive", "active", active); 73 bool just_activated = active && !active_; 74 active_ = active; 75 76 if (is_time_source_throttling_) { 77 time_source_->SetActive(active); 78 } else { 79 if (active) 80 PostManualTick(); 81 else 82 weak_factory_.InvalidateWeakPtrs(); 83 } 84 85 if (just_activated) { 86 // TODO(brianderson): Use an adaptive parent compositor deadline. 87 base::TimeTicks frame_time = NextTickTime() - interval_; 88 base::TimeTicks deadline = NextTickTime(); 89 return BeginFrameArgs::Create(frame_time, deadline, interval_); 90 } 91 return BeginFrameArgs(); 92 } 93 94 void FrameRateController::SetMaxSwapsPending(int max_swaps_pending) { 95 DCHECK_GE(max_swaps_pending, 0); 96 max_swaps_pending_ = max_swaps_pending; 97 } 98 99 void FrameRateController::SetTimebaseAndInterval(base::TimeTicks timebase, 100 base::TimeDelta interval) { 101 interval_ = interval; 102 if (is_time_source_throttling_) 103 time_source_->SetTimebaseAndInterval(timebase, interval); 104 } 105 106 void FrameRateController::SetDeadlineAdjustment(base::TimeDelta delta) { 107 deadline_adjustment_ = delta; 108 } 109 110 void FrameRateController::OnTimerTick() { 111 TRACE_EVENT0("cc", "FrameRateController::OnTimerTick"); 112 DCHECK(active_); 113 114 // Check if we have too many frames in flight. 115 bool throttled = 116 max_swaps_pending_ && num_frames_pending_ >= max_swaps_pending_; 117 TRACE_COUNTER_ID1("cc", "ThrottledCompositor", task_runner_, throttled); 118 119 if (client_) { 120 // TODO(brianderson): Use an adaptive parent compositor deadline. 121 base::TimeTicks frame_time = LastTickTime(); 122 base::TimeTicks deadline = NextTickTime() + deadline_adjustment_; 123 client_->FrameRateControllerTick( 124 throttled, 125 BeginFrameArgs::Create(frame_time, deadline, interval_)); 126 } 127 128 if (!is_time_source_throttling_ && !throttled) 129 PostManualTick(); 130 } 131 132 void FrameRateController::PostManualTick() { 133 if (active_) { 134 task_runner_->PostTask(FROM_HERE, 135 base::Bind(&FrameRateController::ManualTick, 136 weak_factory_.GetWeakPtr())); 137 } 138 } 139 140 void FrameRateController::ManualTick() { 141 OnTimerTick(); 142 } 143 144 void FrameRateController::DidSwapBuffers() { 145 num_frames_pending_++; 146 } 147 148 void FrameRateController::DidSwapBuffersComplete() { 149 DCHECK_GT(num_frames_pending_, 0); 150 num_frames_pending_--; 151 if (!is_time_source_throttling_) 152 PostManualTick(); 153 } 154 155 void FrameRateController::DidAbortAllPendingFrames() { 156 num_frames_pending_ = 0; 157 } 158 159 base::TimeTicks FrameRateController::NextTickTime() { 160 if (is_time_source_throttling_) 161 return time_source_->NextTickTime(); 162 163 return base::TimeTicks(); 164 } 165 166 base::TimeTicks FrameRateController::LastTickTime() { 167 if (is_time_source_throttling_) 168 return time_source_->LastTickTime(); 169 170 return base::TimeTicks::Now(); 171 } 172 173 } // namespace cc 174