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/scheduler.h"
      6 
      7 #include "base/auto_reset.h"
      8 #include "base/debug/trace_event.h"
      9 #include "base/logging.h"
     10 
     11 namespace cc {
     12 
     13 Scheduler::Scheduler(SchedulerClient* client,
     14                      const SchedulerSettings& scheduler_settings)
     15     : settings_(scheduler_settings),
     16       client_(client),
     17       weak_factory_(this),
     18       last_set_needs_begin_frame_(false),
     19       has_pending_begin_frame_(false),
     20       safe_to_expect_begin_frame_(false),
     21       state_machine_(scheduler_settings),
     22       inside_process_scheduled_actions_(false) {
     23   DCHECK(client_);
     24   DCHECK(!state_machine_.BeginFrameNeededToDrawByImplThread());
     25 }
     26 
     27 Scheduler::~Scheduler() {
     28   client_->SetNeedsBeginFrameOnImplThread(false);
     29 }
     30 
     31 void Scheduler::SetCanStart() {
     32   state_machine_.SetCanStart();
     33   ProcessScheduledActions();
     34 }
     35 
     36 void Scheduler::SetVisible(bool visible) {
     37   state_machine_.SetVisible(visible);
     38   ProcessScheduledActions();
     39 }
     40 
     41 void Scheduler::SetCanDraw(bool can_draw) {
     42   state_machine_.SetCanDraw(can_draw);
     43   ProcessScheduledActions();
     44 }
     45 
     46 void Scheduler::SetHasPendingTree(bool has_pending_tree) {
     47   state_machine_.SetHasPendingTree(has_pending_tree);
     48   ProcessScheduledActions();
     49 }
     50 
     51 void Scheduler::SetNeedsCommit() {
     52   state_machine_.SetNeedsCommit();
     53   ProcessScheduledActions();
     54 }
     55 
     56 void Scheduler::SetNeedsForcedCommit() {
     57   state_machine_.SetNeedsCommit();
     58   state_machine_.SetNeedsForcedCommit();
     59   ProcessScheduledActions();
     60 }
     61 
     62 void Scheduler::SetNeedsRedraw() {
     63   state_machine_.SetNeedsRedraw();
     64   ProcessScheduledActions();
     65 }
     66 
     67 void Scheduler::DidSwapUseIncompleteTile() {
     68   state_machine_.DidSwapUseIncompleteTile();
     69   ProcessScheduledActions();
     70 }
     71 
     72 void Scheduler::SetNeedsForcedRedraw() {
     73   state_machine_.SetNeedsForcedRedraw();
     74   ProcessScheduledActions();
     75 }
     76 
     77 void Scheduler::SetMainThreadNeedsLayerTextures() {
     78   state_machine_.SetMainThreadNeedsLayerTextures();
     79   ProcessScheduledActions();
     80 }
     81 
     82 void Scheduler::FinishCommit() {
     83   TRACE_EVENT0("cc", "Scheduler::FinishCommit");
     84   state_machine_.FinishCommit();
     85   ProcessScheduledActions();
     86 }
     87 
     88 void Scheduler::BeginFrameAbortedByMainThread(bool did_handle) {
     89   TRACE_EVENT0("cc", "Scheduler::BeginFrameAbortedByMainThread");
     90   state_machine_.BeginFrameAbortedByMainThread(did_handle);
     91   ProcessScheduledActions();
     92 }
     93 
     94 void Scheduler::DidLoseOutputSurface() {
     95   TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface");
     96   state_machine_.DidLoseOutputSurface();
     97   ProcessScheduledActions();
     98 }
     99 
    100 void Scheduler::DidCreateAndInitializeOutputSurface() {
    101   TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface");
    102   state_machine_.DidCreateAndInitializeOutputSurface();
    103   has_pending_begin_frame_ = false;
    104   last_set_needs_begin_frame_ = false;
    105   safe_to_expect_begin_frame_ = false;
    106   ProcessScheduledActions();
    107 }
    108 
    109 base::TimeTicks Scheduler::AnticipatedDrawTime() {
    110   TRACE_EVENT0("cc", "Scheduler::AnticipatedDrawTime");
    111 
    112   if (!last_set_needs_begin_frame_ ||
    113       last_begin_frame_args_.interval <= base::TimeDelta())
    114     return base::TimeTicks();
    115 
    116   // TODO(brianderson): Express this in terms of the deadline.
    117   base::TimeTicks now = base::TimeTicks::Now();
    118   int64 intervals = 1 + ((now - last_begin_frame_args_.frame_time) /
    119                          last_begin_frame_args_.interval);
    120   return last_begin_frame_args_.frame_time +
    121       (last_begin_frame_args_.interval * intervals);
    122 }
    123 
    124 base::TimeTicks Scheduler::LastBeginFrameOnImplThreadTime() {
    125   return last_begin_frame_args_.frame_time;
    126 }
    127 
    128 void Scheduler::SetupNextBeginFrameIfNeeded() {
    129   bool needs_begin_frame_to_draw =
    130       state_machine_.BeginFrameNeededToDrawByImplThread();
    131   // We want to avoid proactive begin frames with the synchronous compositor
    132   // because every SetNeedsBeginFrame will force a redraw.
    133   bool proactive_begin_frame_wanted =
    134       state_machine_.ProactiveBeginFrameWantedByImplThread() &&
    135       !settings_.using_synchronous_renderer_compositor &&
    136       settings_.throttle_frame_production;
    137   bool needs_begin_frame = needs_begin_frame_to_draw ||
    138                            proactive_begin_frame_wanted;
    139   bool immediate_disables_needed =
    140       settings_.using_synchronous_renderer_compositor;
    141 
    142   if (needs_begin_frame_to_draw)
    143     safe_to_expect_begin_frame_ = true;
    144 
    145   // Determine if we need BeginFrame notifications.
    146   // If we do, always request the BeginFrame immediately.
    147   // If not, only disable on the next BeginFrame to avoid unnecessary toggles.
    148   // The synchronous renderer compositor requires immediate disables though.
    149   if ((needs_begin_frame ||
    150        state_machine_.inside_begin_frame() ||
    151        immediate_disables_needed) &&
    152       (needs_begin_frame != last_set_needs_begin_frame_)) {
    153     has_pending_begin_frame_ = false;
    154     client_->SetNeedsBeginFrameOnImplThread(needs_begin_frame);
    155     if (safe_to_expect_begin_frame_)
    156       last_set_needs_begin_frame_ = needs_begin_frame;
    157   }
    158 
    159   // Request another BeginFrame if we haven't drawn for now until we have
    160   // deadlines implemented.
    161   if (state_machine_.inside_begin_frame() && has_pending_begin_frame_) {
    162     has_pending_begin_frame_ = false;
    163     client_->SetNeedsBeginFrameOnImplThread(true);
    164   }
    165 
    166   // Setup PollForAnticipatedDrawTriggers for cases where we want a proactive
    167   // BeginFrame but aren't requesting one.
    168   if (!needs_begin_frame &&
    169       state_machine_.ProactiveBeginFrameWantedByImplThread()) {
    170     if (poll_for_draw_triggers_closure_.IsCancelled()) {
    171       poll_for_draw_triggers_closure_.Reset(
    172           base::Bind(&Scheduler::PollForAnticipatedDrawTriggers,
    173                      weak_factory_.GetWeakPtr()));
    174       base::MessageLoop::current()->PostDelayedTask(
    175           FROM_HERE,
    176           poll_for_draw_triggers_closure_.callback(),
    177           last_begin_frame_args_.interval);
    178     }
    179   } else {
    180     poll_for_draw_triggers_closure_.Cancel();
    181   }
    182 }
    183 
    184 void Scheduler::BeginFrame(const BeginFrameArgs& args) {
    185   TRACE_EVENT0("cc", "Scheduler::BeginFrame");
    186   DCHECK(!has_pending_begin_frame_);
    187   has_pending_begin_frame_ = true;
    188   safe_to_expect_begin_frame_ = true;
    189   last_begin_frame_args_ = args;
    190   state_machine_.DidEnterBeginFrame(args);
    191   ProcessScheduledActions();
    192   state_machine_.DidLeaveBeginFrame();
    193 }
    194 
    195 void Scheduler::PollForAnticipatedDrawTriggers() {
    196   TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers");
    197   state_machine_.PollForAnticipatedDrawTriggers();
    198   ProcessScheduledActions();
    199 
    200   poll_for_draw_triggers_closure_.Cancel();
    201 }
    202 
    203 void Scheduler::DrawAndSwapIfPossible() {
    204   ScheduledActionDrawAndSwapResult result =
    205       client_->ScheduledActionDrawAndSwapIfPossible();
    206   state_machine_.DidDrawIfPossibleCompleted(result.did_draw);
    207   if (result.did_swap)
    208     has_pending_begin_frame_ = false;
    209 }
    210 
    211 void Scheduler::DrawAndSwapForced() {
    212   ScheduledActionDrawAndSwapResult result =
    213       client_->ScheduledActionDrawAndSwapForced();
    214   if (result.did_swap)
    215     has_pending_begin_frame_ = false;
    216 }
    217 
    218 void Scheduler::ProcessScheduledActions() {
    219   // We do not allow ProcessScheduledActions to be recursive.
    220   // The top-level call will iteratively execute the next action for us anyway.
    221   if (inside_process_scheduled_actions_)
    222     return;
    223 
    224   base::AutoReset<bool> mark_inside(&inside_process_scheduled_actions_, true);
    225 
    226   SchedulerStateMachine::Action action = state_machine_.NextAction();
    227   while (action != SchedulerStateMachine::ACTION_NONE) {
    228     state_machine_.UpdateState(action);
    229     switch (action) {
    230       case SchedulerStateMachine::ACTION_NONE:
    231         break;
    232       case SchedulerStateMachine::ACTION_SEND_BEGIN_FRAME_TO_MAIN_THREAD:
    233         client_->ScheduledActionSendBeginFrameToMainThread();
    234         break;
    235       case SchedulerStateMachine::ACTION_COMMIT:
    236         client_->ScheduledActionCommit();
    237         break;
    238       case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES:
    239         client_->ScheduledActionUpdateVisibleTiles();
    240         break;
    241       case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE_IF_NEEDED:
    242         client_->ScheduledActionActivatePendingTreeIfNeeded();
    243         break;
    244       case SchedulerStateMachine::ACTION_DRAW_IF_POSSIBLE:
    245         DrawAndSwapIfPossible();
    246         break;
    247       case SchedulerStateMachine::ACTION_DRAW_FORCED:
    248         DrawAndSwapForced();
    249         break;
    250       case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
    251         client_->ScheduledActionBeginOutputSurfaceCreation();
    252         break;
    253       case SchedulerStateMachine::ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD:
    254         client_->ScheduledActionAcquireLayerTexturesForMainThread();
    255         break;
    256     }
    257     action = state_machine_.NextAction();
    258   }
    259 
    260   SetupNextBeginFrameIfNeeded();
    261   client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime());
    262 }
    263 
    264 bool Scheduler::WillDrawIfNeeded() const {
    265   return !state_machine_.DrawSuspendedUntilCommit();
    266 }
    267 
    268 }  // namespace cc
    269