| Index: cc/surfaces/display_scheduler.cc | 
| diff --git a/cc/surfaces/display_scheduler.cc b/cc/surfaces/display_scheduler.cc | 
| index 229bc6306ccb1ecf4af4056e074b35a56ac9f429..11a6d04f53e48224f337d4cfe6e03dd58ce1f1cc 100644 | 
| --- a/cc/surfaces/display_scheduler.cc | 
| +++ b/cc/surfaces/display_scheduler.cc | 
| @@ -13,10 +13,10 @@ | 
|  | 
| namespace cc { | 
|  | 
| -DisplayScheduler::DisplayScheduler(BeginFrameSource* begin_frame_source, | 
| -                                   base::SingleThreadTaskRunner* task_runner, | 
| +DisplayScheduler::DisplayScheduler(base::SingleThreadTaskRunner* task_runner, | 
| int max_pending_swaps) | 
| -    : begin_frame_source_(begin_frame_source), | 
| +    : client_(nullptr), | 
| +      begin_frame_source_(nullptr), | 
| task_runner_(task_runner), | 
| inside_surface_damaged_(false), | 
| visible_(false), | 
| @@ -25,12 +25,9 @@ DisplayScheduler::DisplayScheduler(BeginFrameSource* begin_frame_source, | 
| inside_begin_frame_deadline_interval_(false), | 
| needs_draw_(false), | 
| expecting_root_surface_damage_because_of_resize_(false), | 
| -      all_active_child_surfaces_ready_to_draw_(false), | 
| pending_swaps_(0), | 
| max_pending_swaps_(max_pending_swaps), | 
| -      observing_begin_frame_source_(false), | 
| -      root_surface_damaged_(false), | 
| -      expect_damage_from_root_surface_(false), | 
| +      observing_begin_frames_(false), | 
| weak_ptr_factory_(this) { | 
| begin_frame_deadline_closure_ = base::Bind( | 
| &DisplayScheduler::OnBeginFrameDeadline, weak_ptr_factory_.GetWeakPtr()); | 
| @@ -44,6 +41,12 @@ void DisplayScheduler::SetClient(DisplaySchedulerClient* client) { | 
| client_ = client; | 
| } | 
|  | 
| +void DisplayScheduler::SetBeginFrameSource( | 
| +    DisplayBeginFrameSource* begin_frame_source) { | 
| +  begin_frame_source_ = begin_frame_source; | 
| +  begin_frame_source_->SetClient(this); | 
| +} | 
| + | 
| void DisplayScheduler::SetVisible(bool visible) { | 
| if (visible_ == visible) | 
| return; | 
| @@ -68,14 +71,13 @@ void DisplayScheduler::SetRootSurfaceResourcesLocked(bool locked) { | 
| void DisplayScheduler::ForceImmediateSwapIfPossible() { | 
| TRACE_EVENT0("cc", "DisplayScheduler::ForceImmediateSwapIfPossible"); | 
| bool in_begin = inside_begin_frame_deadline_interval_; | 
| -  AttemptDrawAndSwap(); | 
| +  bool did_draw = AttemptDrawAndSwap(); | 
| if (in_begin) | 
| -    begin_frame_source_->DidFinishFrame(this, 0); | 
| +    begin_frame_source_->FinishClientFrame(did_draw, needs_draw_); | 
| } | 
|  | 
| void DisplayScheduler::DisplayResized() { | 
| expecting_root_surface_damage_because_of_resize_ = true; | 
| -  expect_damage_from_root_surface_ = true; | 
| needs_draw_ = true; | 
| ScheduleBeginFrameDeadline(); | 
| } | 
| @@ -102,16 +104,8 @@ void DisplayScheduler::SurfaceDamaged(const SurfaceId& surface_id) { | 
|  | 
| needs_draw_ = true; | 
|  | 
| -  if (surface_id == root_surface_id_) { | 
| -    root_surface_damaged_ = true; | 
| +  if (surface_id == root_surface_id_) | 
| expecting_root_surface_damage_because_of_resize_ = false; | 
| -  } else { | 
| -    child_surface_ids_damaged_.insert(surface_id); | 
| - | 
| -    // TODO(mithro): Use hints from SetNeedsBeginFrames and SwapAborts. | 
| -    all_active_child_surfaces_ready_to_draw_ = base::STLIncludes( | 
| -        child_surface_ids_damaged_, child_surface_ids_to_expect_damage_from_); | 
| -  } | 
|  | 
| StartObservingBeginFrames(); | 
| ScheduleBeginFrameDeadline(); | 
| @@ -123,35 +117,27 @@ void DisplayScheduler::OutputSurfaceLost() { | 
| ScheduleBeginFrameDeadline(); | 
| } | 
|  | 
| -void DisplayScheduler::DrawAndSwap() { | 
| +bool DisplayScheduler::DrawAndSwap() { | 
| TRACE_EVENT0("cc", "DisplayScheduler::DrawAndSwap"); | 
| DCHECK_LT(pending_swaps_, max_pending_swaps_); | 
| DCHECK(!output_surface_lost_); | 
|  | 
| bool success = client_->DrawAndSwap(); | 
| if (!success) | 
| -    return; | 
| - | 
| -  child_surface_ids_to_expect_damage_from_ = | 
| -      base::STLSetIntersection<std::vector<SurfaceId>>( | 
| -          child_surface_ids_damaged_, child_surface_ids_damaged_prev_); | 
| - | 
| -  child_surface_ids_damaged_prev_.swap(child_surface_ids_damaged_); | 
| -  child_surface_ids_damaged_.clear(); | 
| +    return false; | 
|  | 
| needs_draw_ = false; | 
| -  all_active_child_surfaces_ready_to_draw_ = | 
| -      child_surface_ids_to_expect_damage_from_.empty(); | 
| - | 
| -  expect_damage_from_root_surface_ = root_surface_damaged_; | 
| -  root_surface_damaged_ = false; | 
| +  return true; | 
| } | 
|  | 
| -bool DisplayScheduler::OnBeginFrameDerivedImpl(const BeginFrameArgs& args) { | 
| +void DisplayScheduler::OnBeginFrame(const BeginFrameArgs& args) { | 
| base::TimeTicks now = base::TimeTicks::Now(); | 
| TRACE_EVENT2("cc", "DisplayScheduler::BeginFrame", "args", args.AsValue(), | 
| "now", now); | 
|  | 
| +  // We always use the args, even if we post a missing_begin_frame_task. | 
| +  last_used_begin_frame_args_ = args; | 
| + | 
| if (inside_surface_damaged_) { | 
| // Repost this so that we don't run a missed BeginFrame on the same | 
| // callstack. Otherwise we end up running unexpected scheduler actions | 
| @@ -160,12 +146,12 @@ bool DisplayScheduler::OnBeginFrameDerivedImpl(const BeginFrameArgs& args) { | 
| DCHECK_EQ(args.type, BeginFrameArgs::MISSED); | 
| DCHECK(missed_begin_frame_task_.IsCancelled()); | 
| missed_begin_frame_task_.Reset(base::Bind( | 
| -        base::IgnoreResult(&DisplayScheduler::OnBeginFrameDerivedImpl), | 
| +        base::IgnoreResult(&DisplayScheduler::OnBeginFrame), | 
| // The CancelableCallback will not run after it is destroyed, which | 
| // happens when |this| is destroyed. | 
| base::Unretained(this), args)); | 
| task_runner_->PostTask(FROM_HERE, missed_begin_frame_task_.callback()); | 
| -    return true; | 
| +    return; | 
| } | 
|  | 
| // Save the |BeginFrameArgs| as the callback (missed_begin_frame_task_) can be | 
| @@ -189,21 +175,24 @@ bool DisplayScheduler::OnBeginFrameDerivedImpl(const BeginFrameArgs& args) { | 
| BeginFrameArgs::DefaultEstimatedParentDrawTime(); | 
| inside_begin_frame_deadline_interval_ = true; | 
| ScheduleBeginFrameDeadline(); | 
| +} | 
|  | 
| -  return true; | 
| +const BeginFrameArgs& DisplayScheduler::LastUsedBeginFrameArgs() const { | 
| +  return last_used_begin_frame_args_; | 
| } | 
|  | 
| void DisplayScheduler::StartObservingBeginFrames() { | 
| -  if (!observing_begin_frame_source_ && ShouldDraw()) { | 
| -    begin_frame_source_->AddObserver(this); | 
| -    observing_begin_frame_source_ = true; | 
| +  if (!observing_begin_frames_ && | 
| +      (ShouldDraw() || begin_frame_source_->HasObservers())) { | 
| +    begin_frame_source_->SetClientNeedsBeginFrames(true); | 
| +    observing_begin_frames_ = true; | 
| } | 
| } | 
|  | 
| void DisplayScheduler::StopObservingBeginFrames() { | 
| -  if (observing_begin_frame_source_) { | 
| -    begin_frame_source_->RemoveObserver(this); | 
| -    observing_begin_frame_source_ = false; | 
| +  if (observing_begin_frames_) { | 
| +    begin_frame_source_->SetClientNeedsBeginFrames(false); | 
| +    observing_begin_frames_ = false; | 
|  | 
| // A missed BeginFrame may be queued, so drop that too if we're going to | 
| // stop listening. | 
| @@ -217,11 +206,12 @@ bool DisplayScheduler::ShouldDraw() { | 
| return needs_draw_ && !output_surface_lost_ && visible_; | 
| } | 
|  | 
| -void DisplayScheduler::OnBeginFrameSourcePausedChanged(bool paused) { | 
| -  // BeginFrameSources used with DisplayScheduler do not make use of this | 
| -  // feature. | 
| -  if (paused) | 
| -    NOTIMPLEMENTED(); | 
| +void DisplayScheduler::BeginFrameObserverStatusChanged() { | 
| +  // We proactively start observing if any observer requests BeginFrames to | 
| +  // ensure that we call FinishClientFrame() for all of the source's frames. | 
| +  StartObservingBeginFrames(); | 
| +  // Schedules an immediate deadline if all observers have responded. | 
| +  ScheduleBeginFrameDeadline(); | 
| } | 
|  | 
| base::TimeTicks DisplayScheduler::DesiredBeginFrameDeadlineTime() { | 
| @@ -236,7 +226,10 @@ base::TimeTicks DisplayScheduler::DesiredBeginFrameDeadlineTime() { | 
| current_begin_frame_args_.interval; | 
| } | 
|  | 
| -  if (!needs_draw_) { | 
| +  bool observers_finished_frame = | 
| +      begin_frame_source_->AllObserversFinishedFrame(); | 
| + | 
| +  if (!needs_draw_ && !observers_finished_frame) { | 
| TRACE_EVENT_INSTANT0("cc", "No damage yet", TRACE_EVENT_SCOPE_THREAD); | 
| return current_begin_frame_args_.frame_time + | 
| current_begin_frame_args_.interval; | 
| @@ -249,10 +242,8 @@ base::TimeTicks DisplayScheduler::DesiredBeginFrameDeadlineTime() { | 
| current_begin_frame_args_.interval; | 
| } | 
|  | 
| -  bool root_ready_to_draw = | 
| -      !expect_damage_from_root_surface_ || root_surface_damaged_; | 
| - | 
| -  if (all_active_child_surfaces_ready_to_draw_ && root_ready_to_draw) { | 
| +  if (observers_finished_frame && | 
| +      !expecting_root_surface_damage_because_of_resize_) { | 
| TRACE_EVENT_INSTANT0("cc", "All active surfaces ready", | 
| TRACE_EVENT_SCOPE_THREAD); | 
| return base::TimeTicks(); | 
| @@ -266,27 +257,6 @@ base::TimeTicks DisplayScheduler::DesiredBeginFrameDeadlineTime() { | 
| current_begin_frame_args_.interval; | 
| } | 
|  | 
| -  // Use an earlier deadline if we are only waiting for the root surface | 
| -  // in case our expect_damage_from_root_surface heuristic is incorrect. | 
| -  // TODO(mithro): Replace this with SetNeedsBeginFrame and SwapAbort | 
| -  // logic. | 
| -  if (all_active_child_surfaces_ready_to_draw_ && | 
| -      expect_damage_from_root_surface_) { | 
| -    TRACE_EVENT_INSTANT0("cc", "Waiting for damage from root surface", | 
| -                         TRACE_EVENT_SCOPE_THREAD); | 
| -    // This adjusts the deadline by DefaultEstimatedParentDrawTime for | 
| -    // a second time. The first one represented the Surfaces draw to display | 
| -    // latency. This one represents root surface commit+raster+draw latency. | 
| -    // We treat the root surface differently since it lives on the same thread | 
| -    // as Surfaces and waiting for it too long may push out the Surfaces draw. | 
| -    // If we also assume the root surface is fast to start a commit after the | 
| -    // beginning of a frame, it'll have a chance to lock its resources, which | 
| -    // will cause us to wait for it to unlock its resources above. | 
| -    // TODO(mithro): Replace hard coded estimates. | 
| -    return current_begin_frame_args_.deadline - | 
| -           BeginFrameArgs::DefaultEstimatedParentDrawTime(); | 
| -  } | 
| - | 
| TRACE_EVENT_INSTANT0("cc", "More damage expected soon", | 
| TRACE_EVENT_SCOPE_THREAD); | 
| return current_begin_frame_args_.deadline; | 
| @@ -327,31 +297,32 @@ void DisplayScheduler::ScheduleBeginFrameDeadline() { | 
| "desired_deadline", desired_deadline); | 
| } | 
|  | 
| -void DisplayScheduler::AttemptDrawAndSwap() { | 
| +bool DisplayScheduler::AttemptDrawAndSwap() { | 
| inside_begin_frame_deadline_interval_ = false; | 
| begin_frame_deadline_task_.Cancel(); | 
| begin_frame_deadline_task_time_ = base::TimeTicks(); | 
|  | 
| if (ShouldDraw()) { | 
| if (pending_swaps_ < max_pending_swaps_ && !root_surface_resources_locked_) | 
| -      DrawAndSwap(); | 
| -  } else { | 
| +      return DrawAndSwap(); | 
| +  } else if (!begin_frame_source_->HasObservers()) { | 
| // We are going idle, so reset expectations. | 
| -    child_surface_ids_to_expect_damage_from_.clear(); | 
| -    child_surface_ids_damaged_prev_.clear(); | 
| -    child_surface_ids_damaged_.clear(); | 
| -    all_active_child_surfaces_ready_to_draw_ = true; | 
| -    expect_damage_from_root_surface_ = false; | 
| +    // TODO(eseckler): Should we avoid going idle if | 
| +    // expecting_root_surface_damage_because_of_resize_ is true? | 
| +    expecting_root_surface_damage_because_of_resize_ = false; | 
|  | 
| StopObservingBeginFrames(); | 
| } | 
| + | 
| +  return false; | 
| } | 
|  | 
| void DisplayScheduler::OnBeginFrameDeadline() { | 
| TRACE_EVENT0("cc", "DisplayScheduler::OnBeginFrameDeadline"); | 
| +  DCHECK(inside_begin_frame_deadline_interval_); | 
|  | 
| -  AttemptDrawAndSwap(); | 
| -  begin_frame_source_->DidFinishFrame(this, 0); | 
| +  bool did_draw = AttemptDrawAndSwap(); | 
| +  begin_frame_source_->FinishClientFrame(did_draw, needs_draw_); | 
| } | 
|  | 
| void DisplayScheduler::DidSwapBuffers() { | 
|  |