Hook up ui::Compositor to Display's BeginFrameSource

This hooks up the first SurfaceFactoryClient to the real
BeginFrameSource owned by the OnScreenDisplayClient.  This is done by
adding an OutputSurfaceClient::SetBeginFrameSource method.  As the
SurfaceDisplayOutputSurface is also a SurfaceFactoryClient, it can hand
the real begin frame source directly to ui::Compositor's scheduler.

This allows the removal of some of the browser vsync plumbing, but not
all of it.  Once the renderer compositors have been hooked up to use
this path as well, then this and all of the VSyncObserver code can be
ripped out.

The BeginFrameSource is created by the BrowserCompositorOutputSurface
which updates it based on vsync information that it receives.  This
BeginFrameSource is passed to the Display (via OutputSurfaceClient),
which informs the SurfaceManager that the compositor using
that Display should be driven by that BeginFrameSource.  The
SurfaceManager then informs the SurfaceDisplayOutputSurface about
the BeginFrameSource, which passes it into the single thread proxy's
cc::Scheduler for that ui::Compositor's instance.  Plumbing!

The path from SurfaceManager to SurfaceDisplayOutputSurface was
added in https://codereview.chromium.org/1673783004, but the rest
of the plumbing is new to this patch.

CQ_INCLUDE_TRYBOTS=tryserver.blink:linux_blink_rel

Review URL: https://codereview.chromium.org/1821863002

Cr-Commit-Position: refs/heads/master@{#387228}
diff --git a/cc/output/output_surface.cc b/cc/output/output_surface.cc
index 64b1d3b..2263174 100644
--- a/cc/output/output_surface.cc
+++ b/cc/output/output_surface.cc
@@ -189,17 +189,6 @@
                     std::move(software_device)) {
 }
 
-void OutputSurface::CommitVSyncParameters(base::TimeTicks timebase,
-                                          base::TimeDelta interval) {
-  TRACE_EVENT2("cc",
-               "OutputSurface::CommitVSyncParameters",
-               "timebase",
-               (timebase - base::TimeTicks()).InSecondsF(),
-               "interval",
-               interval.InSecondsF());
-  client_->CommitVSyncParameters(timebase, interval);
-}
-
 // Forwarded to OutputSurfaceClient
 void OutputSurface::SetNeedsRedrawRect(const gfx::Rect& damage_rect) {
   TRACE_EVENT0("cc", "OutputSurface::SetNeedsRedrawRect");
diff --git a/cc/output/output_surface.h b/cc/output/output_surface.h
index 062fd00..da4b647 100644
--- a/cc/output/output_surface.h
+++ b/cc/output/output_surface.h
@@ -199,9 +199,6 @@
   bool has_alpha_;
   base::ThreadChecker client_thread_checker_;
 
-  void CommitVSyncParameters(base::TimeTicks timebase,
-                             base::TimeDelta interval);
-
   void SetNeedsRedrawRect(const gfx::Rect& damage_rect);
   void ReclaimResources(const CompositorFrameAck* ack);
   void SetExternalStencilTest(bool enabled);
diff --git a/cc/output/output_surface_client.h b/cc/output/output_surface_client.h
index 8f7f36e..dae7358 100644
--- a/cc/output/output_surface_client.h
+++ b/cc/output/output_surface_client.h
@@ -18,13 +18,20 @@
 
 namespace cc {
 
+class BeginFrameSource;
 class CompositorFrameAck;
 struct ManagedMemoryPolicy;
 
 class CC_EXPORT OutputSurfaceClient {
  public:
+  // TODO(enne): Remove this in favor of using SetBeginFrameSource.
   virtual void CommitVSyncParameters(base::TimeTicks timebase,
                                      base::TimeDelta interval) = 0;
+  // Pass the begin frame source for the client to observe.  Client does not own
+  // the BeginFrameSource.  OutputSurface should call this once after binding to
+  // the client and then call again with a null while detaching.
+  virtual void SetBeginFrameSource(BeginFrameSource* source) = 0;
+
   virtual void SetNeedsRedrawRect(const gfx::Rect& damage_rect) = 0;
   virtual void DidSwapBuffers() = 0;
   virtual void DidSwapBuffersComplete() = 0;
@@ -39,7 +46,7 @@
   // valid for the lifetime of the OutputSurfaceClient or until unregisted --
   // use SetTreeActivationCallback(base::Closure()) to unregister it.
   virtual void SetTreeActivationCallback(const base::Closure& callback) = 0;
-  // This allows the output surface to ask it's client for a draw.
+  // This allows the output surface to ask its client for a draw.
   virtual void OnDraw(const gfx::Transform& transform,
                       const gfx::Rect& viewport,
                       const gfx::Rect& clip,
diff --git a/cc/output/output_surface_unittest.cc b/cc/output/output_surface_unittest.cc
index 1014ad1..bebd245 100644
--- a/cc/output/output_surface_unittest.cc
+++ b/cc/output/output_surface_unittest.cc
@@ -42,11 +42,6 @@
     client_->DidSwapBuffersComplete();
   }
 
-  void CommitVSyncParametersForTesting(base::TimeTicks timebase,
-                                       base::TimeDelta interval) {
-    CommitVSyncParameters(timebase, interval);
-  }
-
   void DidSwapBuffersForTesting() { client_->DidSwapBuffers(); }
 
   void OnSwapBuffersCompleteForTesting() { client_->DidSwapBuffersComplete(); }
diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc
index 2632827..7c1941d 100644
--- a/cc/surfaces/display.cc
+++ b/cc/surfaces/display.cc
@@ -24,50 +24,94 @@
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "ui/gfx/buffer_types.h"
 
+namespace {
+
+class EmptyBeginFrameSource : public cc::BeginFrameSource {
+ public:
+  void DidFinishFrame(size_t remaining_frames) override{};
+  void AddObserver(cc::BeginFrameObserver* obs) override{};
+  void RemoveObserver(cc::BeginFrameObserver* obs) override{};
+  void AsValueInto(base::trace_event::TracedValue* dict) const override{};
+};
+
+}  // namespace
+
 namespace cc {
 
 Display::Display(DisplayClient* client,
                  SurfaceManager* manager,
                  SharedBitmapManager* bitmap_manager,
                  gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-                 const RendererSettings& settings)
+                 const RendererSettings& settings,
+                 uint32_t compositor_surface_namespace)
     : client_(client),
-      manager_(manager),
+      surface_manager_(manager),
       bitmap_manager_(bitmap_manager),
       gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
       settings_(settings),
+      compositor_surface_namespace_(compositor_surface_namespace),
       device_scale_factor_(1.f),
       swapped_since_resize_(false),
-      scheduler_(nullptr),
+      vsync_begin_frame_source_(nullptr),
+      observed_begin_frame_source_(nullptr),
       texture_mailbox_deleter_(new TextureMailboxDeleter(nullptr)) {
-  manager_->AddObserver(this);
+  surface_manager_->AddObserver(this);
 }
 
 Display::~Display() {
-  manager_->RemoveObserver(this);
+  if (observed_begin_frame_source_)
+    surface_manager_->UnregisterBeginFrameSource(observed_begin_frame_source_);
+  surface_manager_->RemoveObserver(this);
   if (aggregator_) {
     for (const auto& id_entry : aggregator_->previous_contained_surfaces()) {
-      Surface* surface = manager_->GetSurfaceForId(id_entry.first);
+      Surface* surface = surface_manager_->GetSurfaceForId(id_entry.first);
       if (surface)
         surface->RunDrawCallbacks(SurfaceDrawStatus::DRAW_SKIPPED);
     }
   }
 }
 
+void Display::CreateScheduler(base::SingleThreadTaskRunner* task_runner) {
+  DCHECK(!scheduler_);
+  if (!task_runner) {
+    // WebView doesn't have a task runner or a real begin frame source,
+    // so just create something fake here.
+    internal_begin_frame_source_.reset(new EmptyBeginFrameSource());
+    vsync_begin_frame_source_ = internal_begin_frame_source_.get();
+    observed_begin_frame_source_ = vsync_begin_frame_source_;
+  } else {
+    DCHECK(vsync_begin_frame_source_);
+
+    observed_begin_frame_source_ = vsync_begin_frame_source_;
+    if (settings_.disable_display_vsync) {
+      internal_begin_frame_source_.reset(
+          new BackToBackBeginFrameSource(task_runner));
+      observed_begin_frame_source_ = internal_begin_frame_source_.get();
+    }
+  }
+
+  scheduler_.reset(
+      new DisplayScheduler(this, observed_begin_frame_source_, task_runner,
+                           output_surface_->capabilities().max_frames_pending));
+  surface_manager_->RegisterBeginFrameSource(observed_begin_frame_source_,
+                                             compositor_surface_namespace_);
+}
+
 bool Display::Initialize(std::unique_ptr<OutputSurface> output_surface,
-                         DisplayScheduler* scheduler) {
-  // TODO(enne): register/unregister BeginFrameSource with SurfaceManager here.
+                         base::SingleThreadTaskRunner* task_runner) {
   output_surface_ = std::move(output_surface);
-  scheduler_ = scheduler;
-  return output_surface_->BindToClient(this);
+  if (!output_surface_->BindToClient(this))
+    return false;
+  CreateScheduler(task_runner);
+  return true;
 }
 
 void Display::SetSurfaceId(SurfaceId id, float device_scale_factor) {
+  DCHECK_EQ(id.id_namespace(), compositor_surface_namespace_);
   if (current_surface_id_ == id && device_scale_factor_ == device_scale_factor)
     return;
 
   TRACE_EVENT0("cc", "Display::SetSurfaceId");
-
   current_surface_id_ = id;
   device_scale_factor_ = device_scale_factor;
 
@@ -136,8 +180,8 @@
   // overlays.
   bool output_partial_list = renderer_->Capabilities().using_partial_swap &&
                              !output_surface_->GetOverlayCandidateValidator();
-  aggregator_.reset(new SurfaceAggregator(manager_, resource_provider_.get(),
-                                          output_partial_list));
+  aggregator_.reset(new SurfaceAggregator(
+      surface_manager_, resource_provider_.get(), output_partial_list));
 }
 
 void Display::DidLoseOutputSurface() {
@@ -149,7 +193,7 @@
 }
 
 void Display::UpdateRootSurfaceResourcesLocked() {
-  Surface* surface = manager_->GetSurfaceForId(current_surface_id_);
+  Surface* surface = surface_manager_->GetSurfaceForId(current_surface_id_);
   bool root_surface_resources_locked = !surface || !surface->GetEligibleFrame();
   if (scheduler_)
     scheduler_->SetRootSurfaceResourcesLocked(root_surface_resources_locked);
@@ -179,7 +223,7 @@
 
   // Run callbacks early to allow pipelining.
   for (const auto& id_entry : aggregator_->previous_contained_surfaces()) {
-    Surface* surface = manager_->GetSurfaceForId(id_entry.first);
+    Surface* surface = surface_manager_->GetSurfaceForId(id_entry.first);
     if (surface)
       surface->RunDrawCallbacks(SurfaceDrawStatus::DRAWN);
   }
@@ -277,9 +321,15 @@
     renderer_->SwapBuffersComplete();
 }
 
-void Display::CommitVSyncParameters(base::TimeTicks timebase,
-                                    base::TimeDelta interval) {
-  client_->CommitVSyncParameters(timebase, interval);
+void Display::SetBeginFrameSource(BeginFrameSource* source) {
+  // It's expected that there's only a single source from the
+  // BrowserCompositorOutputSurface that corresponds to vsync.  The BFS is
+  // passed BrowserCompositorOutputSurface -> Display -> DisplayScheduler as an
+  // input.  DisplayScheduler makes a decision about which BFS to use and
+  // calls back to Display as DisplaySchedulerClient to register for that
+  // surface id.
+  DCHECK(!vsync_begin_frame_source_);
+  vsync_begin_frame_source_ = source;
 }
 
 void Display::SetMemoryPolicy(const ManagedMemoryPolicy& policy) {
@@ -321,7 +371,7 @@
 void Display::OnSurfaceDamaged(SurfaceId surface_id, bool* changed) {
   if (aggregator_ &&
       aggregator_->previous_contained_surfaces().count(surface_id)) {
-    Surface* surface = manager_->GetSurfaceForId(surface_id);
+    Surface* surface = surface_manager_->GetSurfaceForId(surface_id);
     if (surface) {
       const CompositorFrame* current_frame = surface->GetEligibleFrame();
       if (!current_frame || !current_frame->delegated_frame_data ||
diff --git a/cc/surfaces/display.h b/cc/surfaces/display.h
index 3ab9cefb..d3e256d 100644
--- a/cc/surfaces/display.h
+++ b/cc/surfaces/display.h
@@ -55,11 +55,12 @@
           SurfaceManager* manager,
           SharedBitmapManager* bitmap_manager,
           gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-          const RendererSettings& settings);
+          const RendererSettings& settings,
+          uint32_t compositor_surface_namespace);
   ~Display() override;
 
   bool Initialize(std::unique_ptr<OutputSurface> output_surface,
-                  DisplayScheduler* scheduler);
+                  base::SingleThreadTaskRunner* task_runner);
 
   // device_scale_factor is used to communicate to the external window system
   // what scale this was rendered at.
@@ -74,7 +75,8 @@
 
   // OutputSurfaceClient implementation.
   void CommitVSyncParameters(base::TimeTicks timebase,
-                             base::TimeDelta interval) override;
+                             base::TimeDelta interval) override {}
+  void SetBeginFrameSource(BeginFrameSource* source) override;
   void SetNeedsRedrawRect(const gfx::Rect& damage_rect) override;
   void DidSwapBuffers() override;
   void DidSwapBuffersComplete() override;
@@ -96,28 +98,39 @@
   // SurfaceDamageObserver implementation.
   void OnSurfaceDamaged(SurfaceId surface, bool* changed) override;
 
- private:
+ protected:
+  // Virtual for tests.
+  virtual void CreateScheduler(base::SingleThreadTaskRunner* task_runner);
+
   void InitializeRenderer();
   void UpdateRootSurfaceResourcesLocked();
 
   DisplayClient* client_;
-  SurfaceManager* manager_;
+  SurfaceManager* surface_manager_;
   SharedBitmapManager* bitmap_manager_;
   gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;
   RendererSettings settings_;
   SurfaceId current_surface_id_;
+  uint32_t compositor_surface_namespace_;
   gfx::Size current_surface_size_;
   float device_scale_factor_;
   bool swapped_since_resize_;
   gfx::Rect external_clip_;
   std::unique_ptr<OutputSurface> output_surface_;
-  DisplayScheduler* scheduler_;
+  // An internal synthetic BFS. May be null when not used.
+  std::unique_ptr<BeginFrameSource> internal_begin_frame_source_;
+  // The real BFS tied to vsync provided by the BrowserCompositorOutputSurface.
+  BeginFrameSource* vsync_begin_frame_source_;
+  // The current BFS driving the Display/DisplayScheduler.
+  BeginFrameSource* observed_begin_frame_source_;
+  std::unique_ptr<DisplayScheduler> scheduler_;
   std::unique_ptr<ResourceProvider> resource_provider_;
   std::unique_ptr<SurfaceAggregator> aggregator_;
   std::unique_ptr<DirectRenderer> renderer_;
   std::unique_ptr<TextureMailboxDeleter> texture_mailbox_deleter_;
   std::vector<ui::LatencyInfo> stored_latency_info_;
 
+ private:
   DISALLOW_COPY_AND_ASSIGN(Display);
 };
 
diff --git a/cc/surfaces/display_client.h b/cc/surfaces/display_client.h
index 1e3ccb2..bc455bb9 100644
--- a/cc/surfaces/display_client.h
+++ b/cc/surfaces/display_client.h
@@ -11,12 +11,11 @@
 
 namespace cc {
 
+class BeginFrameSource;
 struct ManagedMemoryPolicy;
 
 class DisplayClient {
  public:
-  virtual void CommitVSyncParameters(base::TimeTicks timebase,
-                                     base::TimeDelta interval) = 0;
   virtual void OutputSurfaceLost() = 0;
   virtual void SetMemoryPolicy(const ManagedMemoryPolicy& policy) = 0;
 
diff --git a/cc/surfaces/display_scheduler.cc b/cc/surfaces/display_scheduler.cc
index 9f19fdcb..dd524b88 100644
--- a/cc/surfaces/display_scheduler.cc
+++ b/cc/surfaces/display_scheduler.cc
@@ -33,10 +33,6 @@
       weak_ptr_factory_(this) {
   begin_frame_deadline_closure_ = base::Bind(
       &DisplayScheduler::OnBeginFrameDeadline, weak_ptr_factory_.GetWeakPtr());
-
-  // TODO(tansell): Set this to something useful.
-  begin_frame_source_for_children_.reset(new SyntheticBeginFrameSource(
-      task_runner, BeginFrameArgs::DefaultInterval()));
 }
 
 DisplayScheduler::~DisplayScheduler() {
diff --git a/cc/surfaces/display_scheduler.h b/cc/surfaces/display_scheduler.h
index cd4b5db..fd868b8d 100644
--- a/cc/surfaces/display_scheduler.h
+++ b/cc/surfaces/display_scheduler.h
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
+#include "cc/output/renderer_settings.h"
 #include "cc/scheduler/begin_frame_source.h"
 #include "cc/surfaces/surface_id.h"
 #include "cc/surfaces/surfaces_export.h"
@@ -50,10 +51,6 @@
   bool OnBeginFrameDerivedImpl(const BeginFrameArgs& args) override;
   void OnBeginFrameSourcePausedChanged(bool paused) override;
 
-  BeginFrameSource* begin_frame_source_for_children() {
-    return begin_frame_source_for_children_.get();
-  }
-
  protected:
   base::TimeTicks DesiredBeginFrameDeadlineTime();
   virtual void ScheduleBeginFrameDeadline();
@@ -70,9 +67,6 @@
   base::CancelableClosure begin_frame_deadline_task_;
   base::TimeTicks begin_frame_deadline_task_time_;
 
-  // TODO(tansell): Set this to something useful.
-  std::unique_ptr<BeginFrameSource> begin_frame_source_for_children_;
-
   bool output_surface_lost_;
   bool root_surface_resources_locked_;
 
diff --git a/cc/surfaces/display_unittest.cc b/cc/surfaces/display_unittest.cc
index 4a2de66..312c3a4 100644
--- a/cc/surfaces/display_unittest.cc
+++ b/cc/surfaces/display_unittest.cc
@@ -57,8 +57,11 @@
  public:
   DisplayTest()
       : factory_(&manager_, &surface_factory_client_),
+        id_allocator_(kArbitrarySurfaceNamespace),
         software_output_device_(nullptr),
-        task_runner_(new base::NullTaskRunner) {}
+        task_runner_(new base::NullTaskRunner) {
+    id_allocator_.RegisterSurfaceIdNamespace(&manager_);
+  }
 
  protected:
   void SetUpContext(std::unique_ptr<TestWebGraphicsContext3D> context) {
@@ -87,13 +90,15 @@
                                    SurfaceFactory::DrawCallback());
   }
 
+  enum { kArbitrarySurfaceNamespace = 3 };
+
   SurfaceManager manager_;
   FakeSurfaceFactoryClient surface_factory_client_;
   SurfaceFactory factory_;
+  SurfaceIdAllocator id_allocator_;
   TestSoftwareOutputDevice* software_output_device_;
   std::unique_ptr<FakeOutputSurface> output_surface_;
   FakeOutputSurface* output_surface_ptr_;
-  FakeBeginFrameSource fake_begin_frame_source_;
   scoped_refptr<base::NullTaskRunner> task_runner_;
   std::unique_ptr<SharedBitmapManager> shared_bitmap_manager_;
 };
@@ -103,8 +108,6 @@
   TestDisplayClient() {}
   ~TestDisplayClient() override {}
 
-  void CommitVSyncParameters(base::TimeTicks timebase,
-                             base::TimeDelta interval) override {}
   void OutputSurfaceLost() override {}
   void SetMemoryPolicy(const ManagedMemoryPolicy& policy) override {}
 };
@@ -113,14 +116,12 @@
  public:
   TestDisplayScheduler(DisplaySchedulerClient* client,
                        BeginFrameSource* begin_frame_source,
-                       base::NullTaskRunner* task_runner)
+                       base::SingleThreadTaskRunner* task_runner)
       : DisplayScheduler(client, begin_frame_source, task_runner, 1),
         damaged(false),
         display_resized_(false),
         has_new_root_surface(false),
-        swapped(false) {
-    begin_frame_source_for_children_.reset(new FakeBeginFrameSource);
-  }
+        swapped(false) {}
 
   ~TestDisplayScheduler() override {}
 
@@ -147,6 +148,35 @@
   bool display_resized_;
   bool has_new_root_surface;
   bool swapped;
+
+ private:
+  RendererSettings settings_;
+};
+
+class TestDisplay : public Display {
+ public:
+  TestDisplay(DisplayClient* client,
+              SurfaceManager* manager,
+              SharedBitmapManager* bitmap_manager,
+              gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+              const RendererSettings& settings,
+              uint32_t compositor_surface_namespace)
+      : Display(client,
+                manager,
+                bitmap_manager,
+                gpu_memory_buffer_manager,
+                settings,
+                compositor_surface_namespace) {}
+
+  TestDisplayScheduler& scheduler() {
+    return *static_cast<TestDisplayScheduler*>(scheduler_.get());
+  }
+
+ protected:
+  void CreateScheduler(base::SingleThreadTaskRunner* task_runner) override {
+    scheduler_.reset(
+        new TestDisplayScheduler(this, vsync_begin_frame_source_, task_runner));
+  }
 };
 
 void CopyCallback(bool* called, std::unique_ptr<CopyOutputResult> result) {
@@ -160,14 +190,12 @@
   RendererSettings settings;
   settings.partial_swap_enabled = true;
   settings.finish_rendering_on_resize = true;
-  Display display(&client, &manager_, shared_bitmap_manager_.get(), nullptr,
-                  settings);
+  TestDisplay display(&client, &manager_, shared_bitmap_manager_.get(), nullptr,
+                      settings, id_allocator_.id_namespace());
+  display.Initialize(std::move(output_surface_), task_runner_.get());
+  TestDisplayScheduler& scheduler = display.scheduler();
 
-  TestDisplayScheduler scheduler(&display, &fake_begin_frame_source_,
-                                 task_runner_.get());
-  display.Initialize(std::move(output_surface_), &scheduler);
-
-  SurfaceId surface_id(7u);
+  SurfaceId surface_id(id_allocator_.GenerateId());
   EXPECT_FALSE(scheduler.damaged);
   EXPECT_FALSE(scheduler.has_new_root_surface);
   display.SetSurfaceId(surface_id, 1.f);
@@ -422,18 +450,17 @@
   SetUpContext(std::move(context));
 
   EXPECT_CALL(*context_ptr, shallowFinishCHROMIUM()).Times(0);
+
+  SurfaceId surface_id(id_allocator_.GenerateId());
+
   TestDisplayClient client;
   RendererSettings settings;
   settings.partial_swap_enabled = true;
   settings.finish_rendering_on_resize = true;
-  Display display(&client, &manager_, shared_bitmap_manager_.get(), nullptr,
-                  settings);
+  TestDisplay display(&client, &manager_, shared_bitmap_manager_.get(), nullptr,
+                      settings, surface_id.id_namespace());
+  display.Initialize(std::move(output_surface_), task_runner_.get());
 
-  TestDisplayScheduler scheduler(&display, &fake_begin_frame_source_,
-                                 task_runner_.get());
-  display.Initialize(std::move(output_surface_), &scheduler);
-
-  SurfaceId surface_id(7u);
   display.SetSurfaceId(surface_id, 1.f);
 
   display.Resize(gfx::Size(100, 100));
diff --git a/cc/surfaces/onscreen_display_client.cc b/cc/surfaces/onscreen_display_client.cc
index 0f34a20..b408ed4 100644
--- a/cc/surfaces/onscreen_display_client.cc
+++ b/cc/surfaces/onscreen_display_client.cc
@@ -20,51 +20,24 @@
     SharedBitmapManager* bitmap_manager,
     gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
     const RendererSettings& settings,
-    scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+    uint32_t compositor_surface_namespace)
     : output_surface_(std::move(output_surface)),
       task_runner_(task_runner),
       display_(new Display(this,
                            manager,
                            bitmap_manager,
                            gpu_memory_buffer_manager,
-                           settings)),
-      output_surface_lost_(false),
-      disable_display_vsync_(settings.disable_display_vsync) {}
+                           settings,
+                           compositor_surface_namespace)),
+      output_surface_lost_(false) {}
 
 OnscreenDisplayClient::~OnscreenDisplayClient() {
 }
 
 bool OnscreenDisplayClient::Initialize() {
   DCHECK(output_surface_);
-
-  BeginFrameSource* frame_source;
-  if (disable_display_vsync_) {
-    unthrottled_frame_source_.reset(
-        new BackToBackBeginFrameSource(task_runner_.get()));
-    frame_source = unthrottled_frame_source_.get();
-  } else {
-    synthetic_frame_source_.reset(new SyntheticBeginFrameSource(
-        task_runner_.get(), BeginFrameArgs::DefaultInterval()));
-    frame_source = synthetic_frame_source_.get();
-  }
-
-  scheduler_.reset(
-      new DisplayScheduler(display_.get(), frame_source, task_runner_.get(),
-                           output_surface_->capabilities().max_frames_pending));
-
-  return display_->Initialize(std::move(output_surface_), scheduler_.get());
-}
-
-void OnscreenDisplayClient::CommitVSyncParameters(base::TimeTicks timebase,
-                                                  base::TimeDelta interval) {
-  if (interval == base::TimeDelta()) {
-    // TODO(brianderson): We should not be receiving 0 intervals.
-    interval = BeginFrameArgs::DefaultInterval();
-  }
-
-  surface_display_output_surface_->ReceivedVSyncParameters(timebase, interval);
-  if (synthetic_frame_source_.get())
-    synthetic_frame_source_->OnUpdateVSyncParameters(timebase, interval);
+  return display_->Initialize(std::move(output_surface_), task_runner_.get());
 }
 
 void OnscreenDisplayClient::OutputSurfaceLost() {
diff --git a/cc/surfaces/onscreen_display_client.h b/cc/surfaces/onscreen_display_client.h
index bf87523..91bb5c09 100644
--- a/cc/surfaces/onscreen_display_client.h
+++ b/cc/surfaces/onscreen_display_client.h
@@ -19,7 +19,6 @@
 }
 
 namespace cc {
-class BeginFrameSource;
 class ContextProvider;
 class DisplayScheduler;
 class SurfaceManager;
@@ -30,13 +29,13 @@
 class CC_SURFACES_EXPORT OnscreenDisplayClient
     : NON_EXPORTED_BASE(DisplayClient) {
  public:
-  OnscreenDisplayClient(
-      std::unique_ptr<OutputSurface> output_surface,
-      SurfaceManager* manager,
-      SharedBitmapManager* bitmap_manager,
-      gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
-      const RendererSettings& settings,
-      scoped_refptr<base::SingleThreadTaskRunner> task_runner);
+  OnscreenDisplayClient(std::unique_ptr<OutputSurface> output_surface,
+                        SurfaceManager* manager,
+                        SharedBitmapManager* bitmap_manager,
+                        gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+                        const RendererSettings& settings,
+                        scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+                        uint32_t compositor_surface_namespace);
   ~OnscreenDisplayClient() override;
 
   bool Initialize();
@@ -46,8 +45,6 @@
   }
 
   // DisplayClient implementation.
-  void CommitVSyncParameters(base::TimeTicks timebase,
-                             base::TimeDelta interval) override;
   void OutputSurfaceLost() override;
   void SetMemoryPolicy(const ManagedMemoryPolicy& policy) override;
 
@@ -59,13 +56,9 @@
   // Display depends on DisplayScheduler depends on *BeginFrameSource
   // depends on TaskRunner.
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-  std::unique_ptr<SyntheticBeginFrameSource> synthetic_frame_source_;
-  std::unique_ptr<BackToBackBeginFrameSource> unthrottled_frame_source_;
-  std::unique_ptr<DisplayScheduler> scheduler_;
   std::unique_ptr<Display> display_;
   SurfaceDisplayOutputSurface* surface_display_output_surface_;
   bool output_surface_lost_;
-  bool disable_display_vsync_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(OnscreenDisplayClient);
diff --git a/cc/surfaces/surface_display_output_surface.cc b/cc/surfaces/surface_display_output_surface.cc
index 396f7bb..260e5cd 100644
--- a/cc/surfaces/surface_display_output_surface.cc
+++ b/cc/surfaces/surface_display_output_surface.cc
@@ -21,7 +21,7 @@
     scoped_refptr<ContextProvider> worker_context_provider)
     : OutputSurface(std::move(context_provider),
                     std::move(worker_context_provider)),
-      display_client_(NULL),
+      display_client_(nullptr),
       factory_(surface_manager, this),
       allocator_(allocator) {
   factory_.set_needs_sync_points(false);
@@ -41,12 +41,6 @@
   }
 }
 
-void SurfaceDisplayOutputSurface::ReceivedVSyncParameters(
-    base::TimeTicks timebase,
-    base::TimeDelta interval) {
-  CommitVSyncParameters(timebase, interval);
-}
-
 void SurfaceDisplayOutputSurface::SwapBuffers(CompositorFrame* frame) {
   gfx::Size frame_size =
       frame->delegated_frame_data->render_pass_list.back()->output_rect.size();
@@ -74,10 +68,10 @@
 bool SurfaceDisplayOutputSurface::BindToClient(OutputSurfaceClient* client) {
   DCHECK(client);
   DCHECK(display_client_);
+  client_ = client;
   factory_.manager()->RegisterSurfaceFactoryClient(allocator_->id_namespace(),
                                                    this);
 
-  client_ = client;
   // Avoid initializing GL context here, as this should be sharing the
   // Display's context.
   return display_client_->Initialize();
@@ -109,7 +103,8 @@
 
 void SurfaceDisplayOutputSurface::SetBeginFrameSource(
     BeginFrameSource* begin_frame_source) {
-  // TODO(tansell): Hook this up.
+  DCHECK(client_);
+  client_->SetBeginFrameSource(begin_frame_source);
 }
 
 void SurfaceDisplayOutputSurface::SwapBuffersComplete(SurfaceDrawStatus drawn) {
diff --git a/cc/surfaces/surface_display_output_surface.h b/cc/surfaces/surface_display_output_surface.h
index cececd3..098a3e18 100644
--- a/cc/surfaces/surface_display_output_surface.h
+++ b/cc/surfaces/surface_display_output_surface.h
@@ -33,11 +33,10 @@
   ~SurfaceDisplayOutputSurface() override;
 
   void set_display_client(OnscreenDisplayClient* display_client) {
+    DCHECK(!display_client_);
     display_client_ = display_client;
   }
   SurfaceFactory* factory() { return &factory_; }
-  void ReceivedVSyncParameters(base::TimeTicks timebase,
-                               base::TimeDelta interval);
 
   // OutputSurface implementation.
   void SwapBuffers(CompositorFrame* frame) override;
diff --git a/cc/surfaces/surface_display_output_surface_unittest.cc b/cc/surfaces/surface_display_output_surface_unittest.cc
index de06bd3..8315130 100644
--- a/cc/surfaces/surface_display_output_surface_unittest.cc
+++ b/cc/surfaces/surface_display_output_surface_unittest.cc
@@ -25,13 +25,15 @@
       SharedBitmapManager* bitmap_manager,
       gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
       const RendererSettings& settings,
-      scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+      scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+      uint32_t compositor_surface_namespace)
       : OnscreenDisplayClient(FakeOutputSurface::Create3d(),
                               manager,
                               bitmap_manager,
                               gpu_memory_buffer_manager,
                               settings,
-                              task_runner) {
+                              task_runner,
+                              compositor_surface_namespace) {
     // Ownership is passed to another object later, store a pointer
     // to it now for future reference.
     fake_output_surface_ =
@@ -57,7 +59,8 @@
                         &bitmap_manager_,
                         &gpu_memory_buffer_manager_,
                         renderer_settings_,
-                        task_runner_),
+                        task_runner_,
+                        allocator_.id_namespace()),
         context_provider_(TestContextProvider::Create()),
         surface_display_output_surface_(&surface_manager_,
                                         &allocator_,
@@ -68,8 +71,16 @@
     display_client_.set_surface_output_surface(
         &surface_display_output_surface_);
     surface_display_output_surface_.set_display_client(&display_client_);
+
+    // Set the Display's begin frame source like a real browser compositor
+    // output surface would.
+    begin_frame_source_.reset(
+        new BackToBackBeginFrameSource(task_runner_.get()));
+    display_client_.display()->SetBeginFrameSource(begin_frame_source_.get());
+
     surface_display_output_surface_.BindToClient(
         &surface_display_output_surface_client_);
+
     display_client_.display()->Resize(display_size_);
 
     EXPECT_FALSE(surface_display_output_surface_client_
@@ -104,6 +115,7 @@
  protected:
   std::unique_ptr<base::SimpleTestTickClock> now_src_;
   scoped_refptr<OrderedSimpleTaskRunner> task_runner_;
+  scoped_ptr<BackToBackBeginFrameSource> begin_frame_source_;
   SurfaceIdAllocator allocator_;
 
   const gfx::Size display_size_;
diff --git a/cc/test/fake_layer_tree_host_impl_client.h b/cc/test/fake_layer_tree_host_impl_client.h
index 9f0f433..f3e8e98 100644
--- a/cc/test/fake_layer_tree_host_impl_client.h
+++ b/cc/test/fake_layer_tree_host_impl_client.h
@@ -18,6 +18,7 @@
   void DidLoseOutputSurfaceOnImplThread() override {}
   void CommitVSyncParameters(base::TimeTicks timebase,
                              base::TimeDelta interval) override {}
+  void SetBeginFrameSource(BeginFrameSource* source) override {}
   void SetEstimatedParentDrawTime(base::TimeDelta draw_time) override {}
   void DidSwapBuffersOnImplThread() override {}
   void DidSwapBuffersCompleteOnImplThread() override {}
diff --git a/cc/test/fake_output_surface_client.h b/cc/test/fake_output_surface_client.h
index c9a5efa..bb03715 100644
--- a/cc/test/fake_output_surface_client.h
+++ b/cc/test/fake_output_surface_client.h
@@ -21,6 +21,7 @@
 
   void CommitVSyncParameters(base::TimeTicks timebase,
                              base::TimeDelta interval) override {}
+  void SetBeginFrameSource(BeginFrameSource* source) override {}
   void SetNeedsRedrawRect(const gfx::Rect& damage_rect) override {}
   void DidSwapBuffers() override;
   void DidSwapBuffersComplete() override {}
diff --git a/cc/test/layer_tree_pixel_test.cc b/cc/test/layer_tree_pixel_test.cc
index aaf0b5a..db48d97 100644
--- a/cc/test/layer_tree_pixel_test.cc
+++ b/cc/test/layer_tree_pixel_test.cc
@@ -8,7 +8,6 @@
 #include <stdint.h>
 
 #include "base/command_line.h"
-#include "base/memory/ptr_util.h"
 #include "base/path_service.h"
 #include "cc/base/switches.h"
 #include "cc/layers/solid_color_layer.h"
@@ -49,8 +48,8 @@
           new PixelTestSoftwareOutputDevice);
       software_output_device->set_surface_expansion_size(
           surface_expansion_size);
-      output_surface = base::WrapUnique(
-          new PixelTestOutputSurface(std::move(software_output_device)));
+      output_surface = base::WrapUnique(new PixelTestOutputSurface(
+          std::move(software_output_device), nullptr));
       break;
     }
     case PIXEL_TEST_GL: {
@@ -59,8 +58,9 @@
           new TestInProcessContextProvider(nullptr));
       scoped_refptr<TestInProcessContextProvider> worker(
           new TestInProcessContextProvider(compositor.get()));
-      output_surface = base::WrapUnique(new PixelTestOutputSurface(
-          std::move(compositor), std::move(worker), flipped_output_surface));
+      output_surface = base::WrapUnique(
+          new PixelTestOutputSurface(std::move(compositor), std::move(worker),
+                                     flipped_output_surface, nullptr));
       break;
     }
   }
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc
index 918eafbf..515faf6 100644
--- a/cc/test/pixel_test.cc
+++ b/cc/test/pixel_test.cc
@@ -5,7 +5,6 @@
 #include "cc/test/pixel_test.h"
 
 #include "base/command_line.h"
-#include "base/memory/ptr_util.h"
 #include "base/path_service.h"
 #include "base/run_loop.h"
 #include "base/thread_task_runner_handle.h"
@@ -19,6 +18,7 @@
 #include "cc/output/texture_mailbox_deleter.h"
 #include "cc/raster/tile_task_worker_pool.h"
 #include "cc/resources/resource_provider.h"
+#include "cc/scheduler/begin_frame_source.h"
 #include "cc/test/fake_output_surface_client.h"
 #include "cc/test/paths.h"
 #include "cc/test/pixel_test_output_surface.h"
@@ -128,8 +128,9 @@
       new TestInProcessContextProvider(nullptr));
   scoped_refptr<TestInProcessContextProvider> worker(
       new TestInProcessContextProvider(compositor.get()));
-  output_surface_.reset(new PixelTestOutputSurface(
-      std::move(compositor), std::move(worker), flipped_output_surface));
+  output_surface_.reset(
+      new PixelTestOutputSurface(std::move(compositor), std::move(worker),
+                                 flipped_output_surface, nullptr));
   output_surface_->BindToClient(output_surface_client_.get());
 
   shared_bitmap_manager_.reset(new TestSharedBitmapManager);
@@ -174,7 +175,7 @@
 void PixelTest::SetUpSoftwareRenderer() {
   std::unique_ptr<SoftwareOutputDevice> device(
       new PixelTestSoftwareOutputDevice());
-  output_surface_.reset(new PixelTestOutputSurface(std::move(device)));
+  output_surface_.reset(new PixelTestOutputSurface(std::move(device), nullptr));
   output_surface_->BindToClient(output_surface_client_.get());
   shared_bitmap_manager_.reset(new TestSharedBitmapManager());
   resource_provider_ = ResourceProvider::Create(
diff --git a/cc/test/pixel_test_output_surface.cc b/cc/test/pixel_test_output_surface.cc
index 883f809..9250ee44 100644
--- a/cc/test/pixel_test_output_surface.cc
+++ b/cc/test/pixel_test_output_surface.cc
@@ -5,6 +5,7 @@
 #include "cc/test/pixel_test_output_surface.h"
 
 #include "cc/output/output_surface_client.h"
+#include "cc/scheduler/begin_frame_source.h"
 #include "ui/gfx/transform.h"
 
 namespace cc {
@@ -12,8 +13,10 @@
 PixelTestOutputSurface::PixelTestOutputSurface(
     scoped_refptr<ContextProvider> context_provider,
     scoped_refptr<ContextProvider> worker_context_provider,
-    bool flipped_output_surface)
+    bool flipped_output_surface,
+    std::unique_ptr<BeginFrameSource> begin_frame_source)
     : OutputSurface(context_provider, worker_context_provider),
+      begin_frame_source_(std::move(begin_frame_source)),
       external_stencil_test_(false) {
   capabilities_.adjust_deadline_for_parent = false;
   capabilities_.flipped_output_surface = flipped_output_surface;
@@ -21,17 +24,33 @@
 
 PixelTestOutputSurface::PixelTestOutputSurface(
     scoped_refptr<ContextProvider> context_provider,
-    bool flipped_output_surface)
+    bool flipped_output_surface,
+    std::unique_ptr<BeginFrameSource> begin_frame_source)
     : PixelTestOutputSurface(context_provider,
                              nullptr,
-                             flipped_output_surface) {
-}
+                             flipped_output_surface,
+                             std::move(begin_frame_source)) {}
 
 PixelTestOutputSurface::PixelTestOutputSurface(
-    std::unique_ptr<SoftwareOutputDevice> software_device)
+    std::unique_ptr<SoftwareOutputDevice> software_device,
+    std::unique_ptr<BeginFrameSource> begin_frame_source)
     : OutputSurface(std::move(software_device)),
+      begin_frame_source_(std::move(begin_frame_source)),
       external_stencil_test_(false) {}
 
+PixelTestOutputSurface::~PixelTestOutputSurface() {}
+
+bool PixelTestOutputSurface::BindToClient(OutputSurfaceClient* client) {
+  if (!OutputSurface::BindToClient(client))
+    return false;
+
+  // TODO(enne): Once the renderer uses begin frame sources, this will
+  // always be valid.
+  if (begin_frame_source_)
+    client->SetBeginFrameSource(begin_frame_source_.get());
+  return true;
+}
+
 void PixelTestOutputSurface::Reshape(const gfx::Size& size,
                                      float scale_factor,
                                      bool has_alpha) {
diff --git a/cc/test/pixel_test_output_surface.h b/cc/test/pixel_test_output_surface.h
index e0ddcb5..6cd4191 100644
--- a/cc/test/pixel_test_output_surface.h
+++ b/cc/test/pixel_test_output_surface.h
@@ -9,18 +9,25 @@
 
 namespace cc {
 
+class BeginFrameSource;
+
 class PixelTestOutputSurface : public OutputSurface {
  public:
   explicit PixelTestOutputSurface(
       scoped_refptr<ContextProvider> context_provider,
       scoped_refptr<ContextProvider> worker_context_provider,
-      bool flipped_output_surface);
+      bool flipped_output_surface,
+      std::unique_ptr<BeginFrameSource> begin_frame_source);
   explicit PixelTestOutputSurface(
       scoped_refptr<ContextProvider> context_provider,
-      bool flipped_output_surface);
+      bool flipped_output_surface,
+      std::unique_ptr<BeginFrameSource> begin_frame_source);
   explicit PixelTestOutputSurface(
-      std::unique_ptr<SoftwareOutputDevice> software_device);
+      std::unique_ptr<SoftwareOutputDevice> software_device,
+      std::unique_ptr<BeginFrameSource> begin_frame_source);
+  ~PixelTestOutputSurface() override;
 
+  bool BindToClient(OutputSurfaceClient* client) override;
   void Reshape(const gfx::Size& size, float scale_factor, bool alpha) override;
   bool HasExternalStencilTest() const override;
   void SwapBuffers(CompositorFrame* frame) override;
@@ -33,6 +40,7 @@
   }
 
  private:
+  std::unique_ptr<BeginFrameSource> begin_frame_source_;
   gfx::Size surface_expansion_size_;
   bool external_stencil_test_;
 };
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index af18e6cd5..03004e1e 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -2368,6 +2368,10 @@
   client_->CommitVSyncParameters(timebase, interval);
 }
 
+void LayerTreeHostImpl::SetBeginFrameSource(BeginFrameSource* source) {
+  client_->SetBeginFrameSource(source);
+}
+
 void LayerTreeHostImpl::SetViewportSize(const gfx::Size& device_viewport_size) {
   if (device_viewport_size == device_viewport_size_)
     return;
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index fc31bff..9feb348 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -99,6 +99,7 @@
   virtual void DidLoseOutputSurfaceOnImplThread() = 0;
   virtual void CommitVSyncParameters(base::TimeTicks timebase,
                                      base::TimeDelta interval) = 0;
+  virtual void SetBeginFrameSource(BeginFrameSource* source) = 0;
   virtual void SetEstimatedParentDrawTime(base::TimeDelta draw_time) = 0;
   virtual void DidSwapBuffersOnImplThread() = 0;
   virtual void DidSwapBuffersCompleteOnImplThread() = 0;
@@ -354,6 +355,7 @@
   // OutputSurfaceClient implementation.
   void CommitVSyncParameters(base::TimeTicks timebase,
                              base::TimeDelta interval) override;
+  void SetBeginFrameSource(BeginFrameSource* source) override;
   void SetNeedsRedrawRect(const gfx::Rect& rect) override;
   void SetExternalTilePriorityConstraints(
       const gfx::Rect& viewport_rect,
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 4a763091..3c2bb86d 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -124,6 +124,7 @@
   void DidLoseOutputSurfaceOnImplThread() override {}
   void CommitVSyncParameters(base::TimeTicks timebase,
                              base::TimeDelta interval) override {}
+  void SetBeginFrameSource(BeginFrameSource* source) override {}
   void SetEstimatedParentDrawTime(base::TimeDelta draw_time) override {}
   void DidSwapBuffersOnImplThread() override {}
   void DidSwapBuffersCompleteOnImplThread() override {}
diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc
index 7d548b84..26a5462 100644
--- a/cc/trees/layer_tree_settings.cc
+++ b/cc/trees/layer_tree_settings.cc
@@ -57,6 +57,7 @@
 LayerTreeSettings::LayerTreeSettings()
     : single_thread_proxy_scheduler(true),
       use_external_begin_frame_source(false),
+      use_output_surface_begin_frame_source(false),
       main_frame_before_activation_enabled(false),
       using_synchronous_renderer_compositor(false),
       can_use_lcd_text(true),
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index 285f6e6..0ed9ee9 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -38,7 +38,10 @@
 
   RendererSettings renderer_settings;
   bool single_thread_proxy_scheduler;
+  // TODO(enne): Remove this after everything uses output surface begin frames.
   bool use_external_begin_frame_source;
+  // TODO(enne): Temporary staging for unified begin frame source work.
+  bool use_output_surface_begin_frame_source;
   bool main_frame_before_activation_enabled;
   bool using_synchronous_renderer_compositor;
   bool can_use_lcd_text;
diff --git a/cc/trees/proxy_impl.cc b/cc/trees/proxy_impl.cc
index 39be373..bca90cb 100644
--- a/cc/trees/proxy_impl.cc
+++ b/cc/trees/proxy_impl.cc
@@ -303,6 +303,12 @@
   synthetic_begin_frame_source_->OnUpdateVSyncParameters(timebase, interval);
 }
 
+void ProxyImpl::SetBeginFrameSource(BeginFrameSource* source) {
+  // TODO(enne): this overrides any preexisting begin frame source.  Those
+  // other sources will eventually be removed and this will be the only path.
+  scheduler_->SetBeginFrameSource(source);
+}
+
 void ProxyImpl::SetEstimatedParentDrawTime(base::TimeDelta draw_time) {
   DCHECK(IsImplThread());
   scheduler_->SetEstimatedParentDrawTime(draw_time);
diff --git a/cc/trees/proxy_impl.h b/cc/trees/proxy_impl.h
index 5aa4655..ba4c8df03 100644
--- a/cc/trees/proxy_impl.h
+++ b/cc/trees/proxy_impl.h
@@ -79,6 +79,7 @@
   void DidLoseOutputSurfaceOnImplThread() override;
   void CommitVSyncParameters(base::TimeTicks timebase,
                              base::TimeDelta interval) override;
+  void SetBeginFrameSource(BeginFrameSource* source) override;
   void SetEstimatedParentDrawTime(base::TimeDelta draw_time) override;
   void DidSwapBuffersOnImplThread() override;
   void DidSwapBuffersCompleteOnImplThread() override;
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 8194f38..3d991c0 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -73,18 +73,21 @@
             CompositorTimingHistory::BROWSER_UMA,
             layer_tree_host_->rendering_stats_instrumentation()));
 
-    BeginFrameSource* frame_source = external_begin_frame_source_.get();
-    if (!scheduler_settings.throttle_frame_production) {
-      // Unthrottled source takes precedence over external sources.
-      unthrottled_begin_frame_source_.reset(new BackToBackBeginFrameSource(
-          task_runner_provider_->MainThreadTaskRunner()));
-      frame_source = unthrottled_begin_frame_source_.get();
-    }
-    if (!frame_source) {
-      synthetic_begin_frame_source_.reset(new SyntheticBeginFrameSource(
-          task_runner_provider_->MainThreadTaskRunner(),
-          BeginFrameArgs::DefaultInterval()));
-      frame_source = synthetic_begin_frame_source_.get();
+    BeginFrameSource* frame_source = nullptr;
+    if (!layer_tree_host_->settings().use_output_surface_begin_frame_source) {
+      frame_source = external_begin_frame_source_.get();
+      if (!scheduler_settings.throttle_frame_production) {
+        // Unthrottled source takes precedence over external sources.
+        unthrottled_begin_frame_source_.reset(new BackToBackBeginFrameSource(
+            task_runner_provider_->MainThreadTaskRunner()));
+        frame_source = unthrottled_begin_frame_source_.get();
+      }
+      if (!frame_source) {
+        synthetic_begin_frame_source_.reset(new SyntheticBeginFrameSource(
+            task_runner_provider_->MainThreadTaskRunner(),
+            BeginFrameArgs::DefaultInterval()));
+        frame_source = synthetic_begin_frame_source_.get();
+      }
     }
 
     scheduler_on_impl_thread_ =
@@ -491,6 +494,16 @@
     synthetic_begin_frame_source_->OnUpdateVSyncParameters(timebase, interval);
 }
 
+void SingleThreadProxy::SetBeginFrameSource(BeginFrameSource* source) {
+  DCHECK(layer_tree_host_->settings().single_thread_proxy_scheduler);
+  // TODO(enne): this overrides any preexisting begin frame source.  Those
+  // other sources will eventually be removed and this will be the only path.
+  if (!layer_tree_host_->settings().use_output_surface_begin_frame_source)
+    return;
+  if (scheduler_on_impl_thread_)
+    scheduler_on_impl_thread_->SetBeginFrameSource(source);
+}
+
 void SingleThreadProxy::SetEstimatedParentDrawTime(base::TimeDelta draw_time) {
   if (scheduler_on_impl_thread_)
     scheduler_on_impl_thread_->SetEstimatedParentDrawTime(draw_time);
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h
index e3ee4f1..6f515299 100644
--- a/cc/trees/single_thread_proxy.h
+++ b/cc/trees/single_thread_proxy.h
@@ -84,6 +84,7 @@
   void DidLoseOutputSurfaceOnImplThread() override;
   void CommitVSyncParameters(base::TimeTicks timebase,
                              base::TimeDelta interval) override;
+  void SetBeginFrameSource(BeginFrameSource* source) override;
   void SetEstimatedParentDrawTime(base::TimeDelta draw_time) override;
   void DidSwapBuffersOnImplThread() override;
   void DidSwapBuffersCompleteOnImplThread() override;