Home | History | Annotate | Download | only in scheduler
      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