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 
     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