This source file includes following definitions.
- weak_factory_
 
- SetCanStart
 
- SetVisible
 
- SetCanDraw
 
- NotifyReadyToActivate
 
- ActivatePendingTree
 
- SetNeedsCommit
 
- SetNeedsForcedCommitForReadback
 
- SetNeedsRedraw
 
- SetNeedsManageTiles
 
- SetSwapUsedIncompleteTile
 
- SetSmoothnessTakesPriority
 
- SetMainThreadNeedsLayerTextures
 
- NotifyReadyToCommit
 
- BeginMainFrameAborted
 
- DidManageTiles
 
- DidLoseOutputSurface
 
- DidCreateAndInitializeOutputSurface
 
- NotifyBeginMainFrameStarted
 
- AnticipatedDrawTime
 
- LastBeginImplFrameTime
 
- SetupNextBeginImplFrameIfNeeded
 
- BeginImplFrame
 
- AdjustedBeginImplFrameDeadline
 
- ScheduleBeginImplFrameDeadline
 
- OnBeginImplFrameDeadline
 
- PollForAnticipatedDrawTriggers
 
- PollToAdvanceCommitState
 
- IsBeginMainFrameSent
 
- DrawAndSwapIfPossible
 
- DrawAndSwapForced
 
- DrawAndReadback
 
- ProcessScheduledActions
 
- WillDrawIfNeeded
 
- StateAsValue
 
- CanCommitAndActivateBeforeDeadline
 
- IsBeginMainFrameSentOrStarted
 
#include "cc/scheduler/scheduler.h"
#include <algorithm>
#include "base/auto_reset.h"
#include "base/debug/trace_event.h"
#include "base/logging.h"
#include "cc/debug/devtools_instrumentation.h"
#include "cc/debug/traced_value.h"
#include "ui/gfx/frame_time.h"
namespace cc {
Scheduler::Scheduler(
    SchedulerClient* client,
    const SchedulerSettings& scheduler_settings,
    int layer_tree_host_id,
    const scoped_refptr<base::SequencedTaskRunner>& impl_task_runner)
    : settings_(scheduler_settings),
      client_(client),
      layer_tree_host_id_(layer_tree_host_id),
      impl_task_runner_(impl_task_runner),
      last_set_needs_begin_impl_frame_(false),
      state_machine_(scheduler_settings),
      inside_process_scheduled_actions_(false),
      inside_action_(SchedulerStateMachine::ACTION_NONE),
      weak_factory_(this) {
  DCHECK(client_);
  DCHECK(!state_machine_.BeginImplFrameNeeded());
  if (settings_.main_frame_before_activation_enabled) {
    DCHECK(settings_.main_frame_before_draw_enabled);
  }
  begin_impl_frame_deadline_closure_ = base::Bind(
      &Scheduler::OnBeginImplFrameDeadline, weak_factory_.GetWeakPtr());
  poll_for_draw_triggers_closure_ = base::Bind(
      &Scheduler::PollForAnticipatedDrawTriggers, weak_factory_.GetWeakPtr());
  advance_commit_state_closure_ = base::Bind(
      &Scheduler::PollToAdvanceCommitState, weak_factory_.GetWeakPtr());
}
Scheduler::~Scheduler() {}
void Scheduler::SetCanStart() {
  state_machine_.SetCanStart();
  ProcessScheduledActions();
}
void Scheduler::SetVisible(bool visible) {
  state_machine_.SetVisible(visible);
  ProcessScheduledActions();
}
void Scheduler::SetCanDraw(bool can_draw) {
  state_machine_.SetCanDraw(can_draw);
  ProcessScheduledActions();
}
void Scheduler::NotifyReadyToActivate() {
  state_machine_.NotifyReadyToActivate();
  ProcessScheduledActions();
}
void Scheduler::ActivatePendingTree() {
  client_->ScheduledActionActivatePendingTree();
}
void Scheduler::SetNeedsCommit() {
  state_machine_.SetNeedsCommit();
  ProcessScheduledActions();
}
void Scheduler::SetNeedsForcedCommitForReadback() {
  state_machine_.SetNeedsForcedCommitForReadback();
  ProcessScheduledActions();
}
void Scheduler::SetNeedsRedraw() {
  state_machine_.SetNeedsRedraw();
  ProcessScheduledActions();
}
void Scheduler::SetNeedsManageTiles() {
  DCHECK(!IsInsideAction(SchedulerStateMachine::ACTION_MANAGE_TILES));
  state_machine_.SetNeedsManageTiles();
  ProcessScheduledActions();
}
void Scheduler::SetSwapUsedIncompleteTile(bool used_incomplete_tile) {
  state_machine_.SetSwapUsedIncompleteTile(used_incomplete_tile);
  ProcessScheduledActions();
}
void Scheduler::SetSmoothnessTakesPriority(bool smoothness_takes_priority) {
  state_machine_.SetSmoothnessTakesPriority(smoothness_takes_priority);
  ProcessScheduledActions();
}
void Scheduler::SetMainThreadNeedsLayerTextures() {
  state_machine_.SetMainThreadNeedsLayerTextures();
  ProcessScheduledActions();
}
void Scheduler::NotifyReadyToCommit() {
  TRACE_EVENT0("cc", "Scheduler::NotifyReadyToCommit");
  state_machine_.NotifyReadyToCommit();
  ProcessScheduledActions();
}
void Scheduler::BeginMainFrameAborted(bool did_handle) {
  TRACE_EVENT0("cc", "Scheduler::BeginMainFrameAborted");
  state_machine_.BeginMainFrameAborted(did_handle);
  ProcessScheduledActions();
}
void Scheduler::DidManageTiles() {
  state_machine_.DidManageTiles();
}
void Scheduler::DidLoseOutputSurface() {
  TRACE_EVENT0("cc", "Scheduler::DidLoseOutputSurface");
  state_machine_.DidLoseOutputSurface();
  last_set_needs_begin_impl_frame_ = false;
  ProcessScheduledActions();
}
void Scheduler::DidCreateAndInitializeOutputSurface() {
  TRACE_EVENT0("cc", "Scheduler::DidCreateAndInitializeOutputSurface");
  DCHECK(!last_set_needs_begin_impl_frame_);
  DCHECK(begin_impl_frame_deadline_task_.IsCancelled());
  state_machine_.DidCreateAndInitializeOutputSurface();
  ProcessScheduledActions();
}
void Scheduler::NotifyBeginMainFrameStarted() {
  TRACE_EVENT0("cc", "Scheduler::NotifyBeginMainFrameStarted");
  state_machine_.NotifyBeginMainFrameStarted();
}
base::TimeTicks Scheduler::AnticipatedDrawTime() const {
  if (!last_set_needs_begin_impl_frame_ ||
      last_begin_impl_frame_args_.interval <= base::TimeDelta())
    return base::TimeTicks();
  base::TimeTicks now = gfx::FrameTime::Now();
  base::TimeTicks timebase = std::max(last_begin_impl_frame_args_.frame_time,
                                      last_begin_impl_frame_args_.deadline);
  int64 intervals =
      1 + ((now - timebase) / last_begin_impl_frame_args_.interval);
  return timebase + (last_begin_impl_frame_args_.interval * intervals);
}
base::TimeTicks Scheduler::LastBeginImplFrameTime() {
  return last_begin_impl_frame_args_.frame_time;
}
void Scheduler::SetupNextBeginImplFrameIfNeeded() {
  bool needs_begin_impl_frame =
      state_machine_.BeginImplFrameNeeded();
  bool at_end_of_deadline =
      state_machine_.begin_impl_frame_state() ==
          SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE;
  bool should_call_set_needs_begin_impl_frame =
      
      
      (needs_begin_impl_frame && !last_set_needs_begin_impl_frame_) ||
      
      at_end_of_deadline;
  if (should_call_set_needs_begin_impl_frame) {
    client_->SetNeedsBeginImplFrame(needs_begin_impl_frame);
    last_set_needs_begin_impl_frame_ = needs_begin_impl_frame;
  }
  bool needs_advance_commit_state_timer = false;
  
  
  
  if (state_machine_.ShouldPollForAnticipatedDrawTriggers()) {
    DCHECK(!state_machine_.SupportsProactiveBeginImplFrame());
    DCHECK(!needs_begin_impl_frame);
    if (poll_for_draw_triggers_task_.IsCancelled()) {
      poll_for_draw_triggers_task_.Reset(poll_for_draw_triggers_closure_);
      base::TimeDelta delay = last_begin_impl_frame_args_.IsValid()
                                  ? last_begin_impl_frame_args_.interval
                                  : BeginFrameArgs::DefaultInterval();
      impl_task_runner_->PostDelayedTask(
          FROM_HERE, poll_for_draw_triggers_task_.callback(), delay);
    }
  } else {
    poll_for_draw_triggers_task_.Cancel();
    
    
    
    
    
    
    
    if (IsBeginMainFrameSentOrStarted() &&
        !settings_.using_synchronous_renderer_compositor) {
      needs_advance_commit_state_timer = true;
    }
  }
  if (needs_advance_commit_state_timer) {
    if (advance_commit_state_task_.IsCancelled() &&
        last_begin_impl_frame_args_.IsValid()) {
      
      
      advance_commit_state_task_.Reset(advance_commit_state_closure_);
      impl_task_runner_->PostDelayedTask(
          FROM_HERE,
          advance_commit_state_task_.callback(),
          last_begin_impl_frame_args_.interval * 2);
    }
  } else {
    advance_commit_state_task_.Cancel();
  }
}
void Scheduler::BeginImplFrame(const BeginFrameArgs& args) {
  TRACE_EVENT0("cc", "Scheduler::BeginImplFrame");
  DCHECK(state_machine_.begin_impl_frame_state() ==
         SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
  DCHECK(state_machine_.HasInitializedOutputSurface());
  advance_commit_state_task_.Cancel();
  last_begin_impl_frame_args_ = args;
  last_begin_impl_frame_args_.deadline -= client_->DrawDurationEstimate();
  if (!state_machine_.smoothness_takes_priority() &&
      state_machine_.MainThreadIsInHighLatencyMode() &&
      CanCommitAndActivateBeforeDeadline()) {
    state_machine_.SetSkipNextBeginMainFrameToReduceLatency();
  }
  state_machine_.OnBeginImplFrame(last_begin_impl_frame_args_);
  devtools_instrumentation::DidBeginFrame(layer_tree_host_id_);
  ProcessScheduledActions();
  if (!state_machine_.HasInitializedOutputSurface())
    return;
  state_machine_.OnBeginImplFrameDeadlinePending();
  base::TimeTicks adjusted_deadline = AdjustedBeginImplFrameDeadline();
  ScheduleBeginImplFrameDeadline(adjusted_deadline);
}
base::TimeTicks Scheduler::AdjustedBeginImplFrameDeadline() const {
  if (settings_.using_synchronous_renderer_compositor) {
    
    return base::TimeTicks();
  } else if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) {
    
    return base::TimeTicks();
  } else if (state_machine_.needs_redraw()) {
    
    
    return last_begin_impl_frame_args_.deadline;
  } else {
    
    
    
    
    
    
    
    return last_begin_impl_frame_args_.frame_time +
           last_begin_impl_frame_args_.interval;
  }
}
void Scheduler::ScheduleBeginImplFrameDeadline(base::TimeTicks deadline) {
  if (settings_.using_synchronous_renderer_compositor) {
    
    
    
    
    
    OnBeginImplFrameDeadline();
    return;
  }
  begin_impl_frame_deadline_task_.Cancel();
  begin_impl_frame_deadline_task_.Reset(begin_impl_frame_deadline_closure_);
  base::TimeDelta delta = deadline - gfx::FrameTime::Now();
  if (delta <= base::TimeDelta())
    delta = base::TimeDelta();
  impl_task_runner_->PostDelayedTask(
      FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta);
}
void Scheduler::OnBeginImplFrameDeadline() {
  TRACE_EVENT0("cc", "Scheduler::OnBeginImplFrameDeadline");
  begin_impl_frame_deadline_task_.Cancel();
  
  
  
  
  
  
  
  state_machine_.OnBeginImplFrameDeadline();
  ProcessScheduledActions();
  state_machine_.OnBeginImplFrameIdle();
  ProcessScheduledActions();
  client_->DidBeginImplFrameDeadline();
}
void Scheduler::PollForAnticipatedDrawTriggers() {
  TRACE_EVENT0("cc", "Scheduler::PollForAnticipatedDrawTriggers");
  poll_for_draw_triggers_task_.Cancel();
  state_machine_.DidEnterPollForAnticipatedDrawTriggers();
  ProcessScheduledActions();
  state_machine_.DidLeavePollForAnticipatedDrawTriggers();
}
void Scheduler::PollToAdvanceCommitState() {
  TRACE_EVENT0("cc", "Scheduler::PollToAdvanceCommitState");
  advance_commit_state_task_.Cancel();
  ProcessScheduledActions();
}
bool Scheduler::IsBeginMainFrameSent() const {
  return state_machine_.commit_state() ==
         SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT;
}
void Scheduler::DrawAndSwapIfPossible() {
  DrawSwapReadbackResult result =
      client_->ScheduledActionDrawAndSwapIfPossible();
  state_machine_.DidDrawIfPossibleCompleted(result.draw_result);
}
void Scheduler::DrawAndSwapForced() {
  client_->ScheduledActionDrawAndSwapForced();
}
void Scheduler::DrawAndReadback() {
  DrawSwapReadbackResult result = client_->ScheduledActionDrawAndReadback();
  DCHECK(!result.did_swap);
}
void Scheduler::ProcessScheduledActions() {
  
  
  if (inside_process_scheduled_actions_)
    return;
  base::AutoReset<bool> mark_inside(&inside_process_scheduled_actions_, true);
  SchedulerStateMachine::Action action;
  do {
    state_machine_.CheckInvariants();
    action = state_machine_.NextAction();
    TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
                 "SchedulerStateMachine",
                 "state",
                 TracedValue::FromValue(StateAsValue().release()));
    state_machine_.UpdateState(action);
    base::AutoReset<SchedulerStateMachine::Action>
        mark_inside_action(&inside_action_, action);
    switch (action) {
      case SchedulerStateMachine::ACTION_NONE:
        break;
      case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME:
        client_->ScheduledActionSendBeginMainFrame();
        break;
      case SchedulerStateMachine::ACTION_COMMIT:
        client_->ScheduledActionCommit();
        break;
      case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES:
        client_->ScheduledActionUpdateVisibleTiles();
        break;
      case SchedulerStateMachine::ACTION_ACTIVATE_PENDING_TREE:
        ActivatePendingTree();
        break;
      case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
        DrawAndSwapIfPossible();
        break;
      case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED:
        DrawAndSwapForced();
        break;
      case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT:
        
        
        break;
      case SchedulerStateMachine::ACTION_DRAW_AND_READBACK:
        DrawAndReadback();
        break;
      case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
        client_->ScheduledActionBeginOutputSurfaceCreation();
        break;
      case SchedulerStateMachine::ACTION_ACQUIRE_LAYER_TEXTURES_FOR_MAIN_THREAD:
        client_->ScheduledActionAcquireLayerTexturesForMainThread();
        break;
      case SchedulerStateMachine::ACTION_MANAGE_TILES:
        client_->ScheduledActionManageTiles();
        break;
    }
  } while (action != SchedulerStateMachine::ACTION_NONE);
  SetupNextBeginImplFrameIfNeeded();
  client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime());
  if (state_machine_.ShouldTriggerBeginImplFrameDeadlineEarly()) {
    DCHECK(!settings_.using_synchronous_renderer_compositor);
    ScheduleBeginImplFrameDeadline(base::TimeTicks());
  }
}
bool Scheduler::WillDrawIfNeeded() const {
  return !state_machine_.PendingDrawsShouldBeAborted();
}
scoped_ptr<base::Value> Scheduler::StateAsValue() const {
  scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue);
  state->Set("state_machine", state_machine_.AsValue().release());
  scoped_ptr<base::DictionaryValue> scheduler_state(new base::DictionaryValue);
  scheduler_state->SetDouble(
      "time_until_anticipated_draw_time_ms",
      (AnticipatedDrawTime() - base::TimeTicks::Now()).InMillisecondsF());
  scheduler_state->SetBoolean("last_set_needs_begin_impl_frame_",
                              last_set_needs_begin_impl_frame_);
  scheduler_state->SetBoolean("begin_impl_frame_deadline_task_",
                              !begin_impl_frame_deadline_task_.IsCancelled());
  scheduler_state->SetBoolean("poll_for_draw_triggers_task_",
                              !poll_for_draw_triggers_task_.IsCancelled());
  scheduler_state->SetBoolean("advance_commit_state_task_",
                              !advance_commit_state_task_.IsCancelled());
  state->Set("scheduler_state", scheduler_state.release());
  scoped_ptr<base::DictionaryValue> client_state(new base::DictionaryValue);
  client_state->SetDouble("draw_duration_estimate_ms",
                          client_->DrawDurationEstimate().InMillisecondsF());
  client_state->SetDouble(
      "begin_main_frame_to_commit_duration_estimate_ms",
      client_->BeginMainFrameToCommitDurationEstimate().InMillisecondsF());
  client_state->SetDouble(
      "commit_to_activate_duration_estimate_ms",
      client_->CommitToActivateDurationEstimate().InMillisecondsF());
  state->Set("client_state", client_state.release());
  return state.PassAs<base::Value>();
}
bool Scheduler::CanCommitAndActivateBeforeDeadline() const {
  
  
  base::TimeTicks estimated_draw_time =
      last_begin_impl_frame_args_.frame_time +
      client_->BeginMainFrameToCommitDurationEstimate() +
      client_->CommitToActivateDurationEstimate();
  TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
               "CanCommitAndActivateBeforeDeadline",
               "time_left_after_drawing_ms",
               (last_begin_impl_frame_args_.deadline - estimated_draw_time)
                   .InMillisecondsF(),
               "state",
               TracedValue::FromValue(StateAsValue().release()));
  return estimated_draw_time < last_begin_impl_frame_args_.deadline;
}
bool Scheduler::IsBeginMainFrameSentOrStarted() const {
  return (state_machine_.commit_state() ==
              SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_SENT ||
          state_machine_.commit_state() ==
              SchedulerStateMachine::COMMIT_STATE_BEGIN_MAIN_FRAME_STARTED);
}
}