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