[go: nahoru, domu]

Make SingleThreadProxy a SchedulerClient

All compositors that use SingleThreadProxy are left calling composite
synchronously and now pass a flag to indicate that this is their
intention.  This patch doesn't remove synchronous composite, but now
makes it mutually exclusive with scheduling.

Only cc unittests are exercising this code at this point, although it
also unifies a lot of the code for CompositeImmediately with the
scheduled path.

BUG=329552, 287250

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

Cr-Commit-Position: refs/heads/master@{#291451}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@291451 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/android_webview/browser/hardware_renderer.cc b/android_webview/browser/hardware_renderer.cc
index c2d1a6d..28cec80 100644
--- a/android_webview/browser/hardware_renderer.cc
+++ b/android_webview/browser/hardware_renderer.cc
@@ -96,6 +96,9 @@
   // Webview does not own the surface so should not clear it.
   settings.should_clear_root_render_pass = false;
 
+  // TODO(enne): Update this this compositor to use a synchronous scheduler.
+  settings.single_thread_proxy_scheduler = false;
+
   layer_tree_host_ =
       cc::LayerTreeHost::CreateSingleThreaded(this, this, NULL, settings, NULL);
   layer_tree_host_->SetRootLayer(root_layer_);
diff --git a/android_webview/browser/hardware_renderer.h b/android_webview/browser/hardware_renderer.h
index c4d3449..bdb7fb75 100644
--- a/android_webview/browser/hardware_renderer.h
+++ b/android_webview/browser/hardware_renderer.h
@@ -54,8 +54,6 @@
   virtual void DidCompleteSwapBuffers() OVERRIDE {}
 
   // cc::LayerTreeHostSingleThreadClient overrides.
-  virtual void ScheduleComposite() OVERRIDE {}
-  virtual void ScheduleAnimation() OVERRIDE {}
   virtual void DidPostSwapBuffers() OVERRIDE {}
   virtual void DidAbortSwapBuffers() OVERRIDE {}
 
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 4f97e0e..109b54b 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -456,6 +456,7 @@
     "trees/proxy.h",
     "trees/proxy_timing_history.cc",
     "trees/proxy_timing_history.h",
+    "trees/scoped_abort_remaining_swap_promises.h",
     "trees/single_thread_proxy.cc",
     "trees/single_thread_proxy.h",
     "trees/thread_proxy.cc",
diff --git a/cc/cc.gyp b/cc/cc.gyp
index b9b72908..88314c1 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -484,6 +484,7 @@
         'trees/proxy.h',
         'trees/proxy_timing_history.cc',
         'trees/proxy_timing_history.h',
+        'trees/scoped_abort_remaining_swap_promises.h',
         'trees/single_thread_proxy.cc',
         'trees/single_thread_proxy.h',
         'trees/thread_proxy.cc',
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index 1451237..a20bfd2b 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -79,11 +79,11 @@
     SchedulerClient* client,
     const SchedulerSettings& scheduler_settings,
     int layer_tree_host_id,
-    const scoped_refptr<base::SingleThreadTaskRunner>& impl_task_runner)
+    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
     : settings_(scheduler_settings),
       client_(client),
       layer_tree_host_id_(layer_tree_host_id),
-      impl_task_runner_(impl_task_runner),
+      task_runner_(task_runner),
       vsync_interval_(BeginFrameArgs::DefaultInterval()),
       last_set_needs_begin_frame_(false),
       begin_unthrottled_frame_posted_(false),
@@ -128,7 +128,7 @@
 void Scheduler::SetupSyntheticBeginFrames() {
   DCHECK(!synthetic_begin_frame_source_);
   synthetic_begin_frame_source_.reset(
-      new SyntheticBeginFrameSource(this, impl_task_runner_.get()));
+      new SyntheticBeginFrameSource(this, task_runner_.get()));
 }
 
 void Scheduler::CommitVSyncParameters(base::TimeTicks timebase,
@@ -274,6 +274,9 @@
 }
 
 void Scheduler::SetupNextBeginFrameIfNeeded() {
+  if (!task_runner_)
+    return;
+
   bool needs_begin_frame = state_machine_.BeginFrameNeeded();
 
   if (settings_.throttle_frame_production) {
@@ -328,7 +331,7 @@
   }
 
   begin_unthrottled_frame_posted_ = true;
-  impl_task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_);
+  task_runner_->PostTask(FROM_HERE, begin_unthrottled_frame_closure_);
 }
 
 // BeginUnthrottledFrame is used when we aren't throttling frame production.
@@ -362,7 +365,7 @@
       base::TimeDelta delay = begin_impl_frame_args_.IsValid()
                                   ? begin_impl_frame_args_.interval
                                   : BeginFrameArgs::DefaultInterval();
-      impl_task_runner_->PostDelayedTask(
+      task_runner_->PostDelayedTask(
           FROM_HERE, poll_for_draw_triggers_task_.callback(), delay);
     }
   } else {
@@ -387,9 +390,9 @@
       // Since we'd rather get a BeginImplFrame by the normal mechanism, we
       // set the interval to twice the interval from the previous frame.
       advance_commit_state_task_.Reset(advance_commit_state_closure_);
-      impl_task_runner_->PostDelayedTask(FROM_HERE,
-                                         advance_commit_state_task_.callback(),
-                                         begin_impl_frame_args_.interval * 2);
+      task_runner_->PostDelayedTask(FROM_HERE,
+                                    advance_commit_state_task_.callback(),
+                                    begin_impl_frame_args_.interval * 2);
     }
   } else {
     advance_commit_state_task_.Cancel();
@@ -491,7 +494,7 @@
     return;
 
   begin_retro_frame_posted_ = true;
-  impl_task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_);
+  task_runner_->PostTask(FROM_HERE, begin_retro_frame_closure_);
 }
 
 // BeginImplFrame starts a compositor frame that will wait up until a deadline
@@ -499,8 +502,8 @@
 // any asynchronous animation and scroll/pinch updates.
 void Scheduler::BeginImplFrame(const BeginFrameArgs& args) {
   TRACE_EVENT1("cc", "Scheduler::BeginImplFrame", "args", args.AsValue());
-  DCHECK(state_machine_.begin_impl_frame_state() ==
-         SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
+  DCHECK_EQ(state_machine_.begin_impl_frame_state(),
+            SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
   DCHECK(state_machine_.HasInitializedOutputSurface());
 
   advance_commit_state_task_.Cancel();
@@ -567,7 +570,7 @@
   base::TimeDelta delta = deadline - gfx::FrameTime::Now();
   if (delta <= base::TimeDelta())
     delta = base::TimeDelta();
-  impl_task_runner_->PostDelayedTask(
+  task_runner_->PostDelayedTask(
       FROM_HERE, begin_impl_frame_deadline_task_.callback(), delta);
 }
 
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h
index f6dd2bc..ce3fed7 100644
--- a/cc/scheduler/scheduler.h
+++ b/cc/scheduler/scheduler.h
@@ -57,9 +57,9 @@
       SchedulerClient* client,
       const SchedulerSettings& scheduler_settings,
       int layer_tree_host_id,
-      const scoped_refptr<base::SingleThreadTaskRunner>& impl_task_runner) {
+      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
     return make_scoped_ptr(new Scheduler(
-        client, scheduler_settings, layer_tree_host_id, impl_task_runner));
+        client, scheduler_settings, layer_tree_host_id, task_runner));
   }
 
   virtual ~Scheduler();
@@ -180,16 +180,15 @@
     scoped_refptr<DelayBasedTimeSource> time_source_;
   };
 
-  Scheduler(
-      SchedulerClient* client,
-      const SchedulerSettings& scheduler_settings,
-      int layer_tree_host_id,
-      const scoped_refptr<base::SingleThreadTaskRunner>& impl_task_runner);
+  Scheduler(SchedulerClient* client,
+            const SchedulerSettings& scheduler_settings,
+            int layer_tree_host_id,
+            const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
 
   const SchedulerSettings settings_;
   SchedulerClient* client_;
   int layer_tree_host_id_;
-  scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner_;
+  scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
   base::TimeDelta vsync_interval_;
   base::TimeDelta estimated_parent_draw_time_;
diff --git a/cc/test/fake_layer_tree_host_client.h b/cc/test/fake_layer_tree_host_client.h
index 802aec9..85a3751 100644
--- a/cc/test/fake_layer_tree_host_client.h
+++ b/cc/test/fake_layer_tree_host_client.h
@@ -42,8 +42,6 @@
   virtual void DidCompleteSwapBuffers() OVERRIDE {}
 
   // LayerTreeHostSingleThreadClient implementation.
-  virtual void ScheduleComposite() OVERRIDE {}
-  virtual void ScheduleAnimation() OVERRIDE {}
   virtual void DidPostSwapBuffers() OVERRIDE {}
   virtual void DidAbortSwapBuffers() OVERRIDE {}
 
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index 4493671..949c802 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -312,14 +312,6 @@
     test_hooks_->DidCompleteSwapBuffers();
   }
 
-  virtual void ScheduleComposite() OVERRIDE {
-    test_hooks_->ScheduleComposite();
-  }
-
-  virtual void ScheduleAnimation() OVERRIDE {
-    test_hooks_->ScheduleAnimation();
-  }
-
   virtual void DidPostSwapBuffers() OVERRIDE {}
   virtual void DidAbortSwapBuffers() OVERRIDE {}
 
@@ -394,7 +386,6 @@
       end_when_begin_returns_(false),
       timed_out_(false),
       scheduled_(false),
-      schedule_when_set_visible_true_(false),
       started_(false),
       ended_(false),
       delegating_renderer_(false),
@@ -558,15 +549,6 @@
   EndTest();
 }
 
-void LayerTreeTest::ScheduleComposite() {
-  if (!started_ || scheduled_)
-    return;
-  scheduled_ = true;
-  main_task_runner_->PostTask(
-      FROM_HERE,
-      base::Bind(&LayerTreeTest::DispatchComposite, main_thread_weak_ptr_));
-}
-
 void LayerTreeTest::RealEndTest() {
   if (layer_tree_host_ && !timed_out_ &&
       proxy()->MainFrameWillHappenForTesting()) {
@@ -619,16 +601,8 @@
 
 void LayerTreeTest::DispatchSetVisible(bool visible) {
   DCHECK(!proxy() || proxy()->IsMainThread());
-
-  if (!layer_tree_host_)
-    return;
-
-  layer_tree_host_->SetVisible(visible);
-
-  // If the LTH is being made visible and a previous ScheduleComposite() was
-  // deferred because the LTH was not visible, re-schedule the composite now.
-  if (layer_tree_host_->visible() && schedule_when_set_visible_true_)
-    ScheduleComposite();
+  if (layer_tree_host_)
+    layer_tree_host_->SetVisible(visible);
 }
 
 void LayerTreeTest::DispatchSetNextCommitForcesRedraw() {
@@ -638,24 +612,6 @@
     layer_tree_host_->SetNextCommitForcesRedraw();
 }
 
-void LayerTreeTest::DispatchComposite() {
-  scheduled_ = false;
-
-  if (!layer_tree_host_)
-    return;
-
-  // If the LTH is not visible, defer the composite until the LTH is made
-  // visible.
-  if (!layer_tree_host_->visible()) {
-    schedule_when_set_visible_true_ = true;
-    return;
-  }
-
-  schedule_when_set_visible_true_ = false;
-  base::TimeTicks now = gfx::FrameTime::Now();
-  layer_tree_host_->Composite(now);
-}
-
 void LayerTreeTest::RunTest(bool threaded,
                             bool delegating_renderer,
                             bool impl_side_painting) {
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h
index 8e469c4..2705833 100644
--- a/cc/test/layer_tree_test.h
+++ b/cc/test/layer_tree_test.h
@@ -71,8 +71,6 @@
   virtual void DidCommit() {}
   virtual void DidCommitAndDrawFrame() {}
   virtual void DidCompleteSwapBuffers() {}
-  virtual void ScheduleComposite() {}
-  virtual void ScheduleAnimation() {}
   virtual void DidDeferCommit() {}
   virtual void DidSetVisibleOnImplTree(LayerTreeHostImpl* host_impl,
                                        bool visible) {}
@@ -139,8 +137,6 @@
 
   virtual void InitializeSettings(LayerTreeSettings* settings) {}
 
-  virtual void ScheduleComposite() OVERRIDE;
-
   void RealEndTest();
 
   virtual void DispatchAddAnimation(Layer* layer_to_receive_animation,
@@ -151,7 +147,6 @@
   void DispatchSetNeedsRedrawRect(const gfx::Rect& damage_rect);
   void DispatchSetVisible(bool visible);
   void DispatchSetNextCommitForcesRedraw();
-  void DispatchComposite();
   void DispatchDidAddAnimation();
 
   virtual void AfterTest() = 0;
@@ -204,7 +199,6 @@
   bool end_when_begin_returns_;
   bool timed_out_;
   bool scheduled_;
-  bool schedule_when_set_visible_true_;
   bool started_;
   bool ended_;
   bool delegating_renderer_;
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 343c5039..e80256d 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -700,8 +700,12 @@
 
 void LayerTreeHost::Composite(base::TimeTicks frame_begin_time) {
   DCHECK(!proxy_->HasImplThread());
+  // This function is only valid when not using the scheduler.
+  DCHECK(!settings_.single_thread_proxy_scheduler);
   SingleThreadProxy* proxy = static_cast<SingleThreadProxy*>(proxy_.get());
 
+  SetLayerTreeHostClientReady();
+
   if (output_surface_lost_)
     proxy->CreateAndInitializeOutputSurface();
   if (output_surface_lost_)
diff --git a/cc/trees/layer_tree_host_perftest.cc b/cc/trees/layer_tree_host_perftest.cc
index cd1ba44..49ef6e1 100644
--- a/cc/trees/layer_tree_host_perftest.cc
+++ b/cc/trees/layer_tree_host_perftest.cc
@@ -228,6 +228,8 @@
   }
 
   virtual void Layout() OVERRIDE {
+    if (TestEnded())
+      return;
     static const gfx::Vector2d delta = gfx::Vector2d(0, 10);
     scrollable_->SetScrollOffset(scrollable_->scroll_offset() + delta);
   }
diff --git a/cc/trees/layer_tree_host_single_thread_client.h b/cc/trees/layer_tree_host_single_thread_client.h
index cb61450..dbca28c 100644
--- a/cc/trees/layer_tree_host_single_thread_client.h
+++ b/cc/trees/layer_tree_host_single_thread_client.h
@@ -10,10 +10,10 @@
 class LayerTreeHostSingleThreadClient {
  public:
   // Request that the client schedule a composite.
-  virtual void ScheduleComposite() = 0;
+  virtual void ScheduleComposite() {}
   // Request that the client schedule a composite now, and calculate appropriate
   // delay for potential future frame.
-  virtual void ScheduleAnimation() = 0;
+  virtual void ScheduleAnimation() {}
 
   // Called whenever the compositor posts a SwapBuffers (either full or
   // partial). After DidPostSwapBuffers(), exactly one of
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 3ac7aa1..7c1bb81 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -1893,7 +1893,7 @@
   int num_complete_commits_;
 };
 
-MULTI_THREAD_TEST_F(LayerTreeHostTestDeferCommits);
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestDeferCommits);
 
 class LayerTreeHostWithProxy : public LayerTreeHost {
  public:
@@ -1966,6 +1966,7 @@
 
   LayerTreeSettings settings;
   settings.max_partial_texture_updates = 4;
+  settings.single_thread_proxy_scheduler = false;
 
   scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
       new TestSharedBitmapManager());
@@ -1985,6 +1986,7 @@
 
   LayerTreeSettings settings;
   settings.max_partial_texture_updates = 4;
+  settings.single_thread_proxy_scheduler = false;
 
   scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
       new TestSharedBitmapManager());
@@ -2004,6 +2006,7 @@
 
   LayerTreeSettings settings;
   settings.max_partial_texture_updates = 4;
+  settings.single_thread_proxy_scheduler = false;
 
   scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
       new TestSharedBitmapManager());
@@ -2024,6 +2027,7 @@
 
   LayerTreeSettings settings;
   settings.max_partial_texture_updates = 4;
+  settings.single_thread_proxy_scheduler = false;
 
   scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
       new TestSharedBitmapManager());
@@ -4572,7 +4576,7 @@
   TestSwapPromiseResult swap_promise_result_;
 };
 
-MULTI_THREAD_TEST_F(
+SINGLE_AND_MULTI_THREAD_TEST_F(
     LayerTreeHostTestBreakSwapPromiseForVisibilityAbortedCommit);
 
 class LayerTreeHostTestBreakSwapPromiseForContextAbortedCommit
@@ -4623,7 +4627,8 @@
   TestSwapPromiseResult swap_promise_result_;
 };
 
-MULTI_THREAD_TEST_F(LayerTreeHostTestBreakSwapPromiseForContextAbortedCommit);
+SINGLE_AND_MULTI_THREAD_TEST_F(
+    LayerTreeHostTestBreakSwapPromiseForContextAbortedCommit);
 
 class SimpleSwapPromiseMonitor : public SwapPromiseMonitor {
  public:
@@ -4708,7 +4713,7 @@
   virtual void AfterTest() OVERRIDE {}
 };
 
-MULTI_THREAD_TEST_F(LayerTreeHostTestSimpleSwapPromiseMonitor);
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSimpleSwapPromiseMonitor);
 
 class LayerTreeHostTestHighResRequiredAfterEvictingUIResources
     : public LayerTreeHostTest {
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
index 638d27f..8fcfa28 100644
--- a/cc/trees/layer_tree_host_unittest_context.cc
+++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -65,6 +65,9 @@
   }
 
   void LoseContext() {
+    // For sanity-checking tests, they should only call this when the
+    // context is not lost.
+    CHECK(context3d_);
     context3d_->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
                                     GL_INNOCENT_CONTEXT_RESET_ARB);
     context3d_ = NULL;
@@ -308,7 +311,8 @@
   }
 };
 
-MULTI_THREAD_TEST_F(LayerTreeHostClientNotReadyDoesNotCreateOutputSurface);
+SINGLE_AND_MULTI_THREAD_TEST_F(
+    LayerTreeHostClientNotReadyDoesNotCreateOutputSurface);
 
 class LayerTreeHostContextTestLostContextSucceedsWithContent
     : public LayerTreeHostContextTestLostContextSucceeds {
@@ -366,10 +370,11 @@
       : times_to_fail_(times_to_fail),
         expect_fallback_attempt_(expect_fallback_attempt),
         did_attempt_fallback_(false),
-        times_initialized_(0) {}
+        times_initialized_(0) {
+    times_to_fail_create_ = times_to_fail_;
+  }
 
   virtual void BeginTest() OVERRIDE {
-    times_to_fail_create_ = times_to_fail_;
     PostSetNeedsCommitToMainThread();
   }
 
@@ -983,12 +988,6 @@
         EXPECT_EQ(2, scrollbar_layer_->update_count());
         EndTest();
         break;
-      case 3:
-        // Single thread proxy issues extra commits after context lost.
-        // http://crbug.com/287250
-        if (HasImplThread())
-          NOTREACHED();
-        break;
       default:
         NOTREACHED();
     }
@@ -1032,12 +1031,10 @@
 
   void PostLoseContextToImplThread() {
     EXPECT_TRUE(layer_tree_host()->proxy()->IsMainThread());
-    base::SingleThreadTaskRunner* task_runner =
-        HasImplThread() ? ImplThreadTaskRunner()
-                        : base::MessageLoopProxy::current();
-    task_runner->PostTask(FROM_HERE,
-                          base::Bind(&LayerTreeHostContextTest::LoseContext,
-                                     base::Unretained(this)));
+    ImplThreadTaskRunner()->PostTask(
+        FROM_HERE,
+        base::Bind(&LayerTreeHostContextTest::LoseContext,
+                   base::Unretained(this)));
   }
 
  protected:
@@ -1092,13 +1089,8 @@
         EndTest();
         break;
       case 5:
-        // Single thread proxy issues extra commits after context lost.
-        // http://crbug.com/287250
-        if (HasImplThread())
-          NOTREACHED();
-        break;
-      case 6:
         NOTREACHED();
+        break;
     }
   }
 
@@ -1186,13 +1178,8 @@
         EndTest();
         break;
       case 6:
-        // Single thread proxy issues extra commits after context lost.
-        // http://crbug.com/287250
-        if (HasImplThread())
-          NOTREACHED();
-        break;
-      case 8:
         NOTREACHED();
+        break;
     }
   }
 
@@ -1213,15 +1200,8 @@
         // Sequence 2 (continued):
         // The previous resource should have been deleted.
         EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id0_));
-        if (HasImplThread()) {
-          // The second resource should have been created.
-          EXPECT_NE(0u, impl->ResourceIdForUIResource(test_id1_));
-        } else {
-          // The extra commit that happens at context lost in the single thread
-          // proxy changes the timing so that the resource has been destroyed.
-          // http://crbug.com/287250
-          EXPECT_EQ(0u, impl->ResourceIdForUIResource(test_id1_));
-        }
+        // The second resource should have been created.
+        EXPECT_NE(0u, impl->ResourceIdForUIResource(test_id1_));
         // The second resource called the resource callback once and since the
         // context is lost, a "resource lost" callback was also issued.
         EXPECT_EQ(2, ui_resource_->resource_create_count);
@@ -1537,8 +1517,8 @@
   bool deferred_;
 };
 
-// TODO(danakj): We don't use scheduler with SingleThreadProxy yet.
-MULTI_THREAD_TEST_F(LayerTreeHostContextTestLoseAfterSendingBeginMainFrame);
+SINGLE_AND_MULTI_THREAD_TEST_F(
+    LayerTreeHostContextTestLoseAfterSendingBeginMainFrame);
 
 }  // namespace
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host_unittest_no_message_loop.cc b/cc/trees/layer_tree_host_unittest_no_message_loop.cc
index 1756132c..1769ab7e 100644
--- a/cc/trees/layer_tree_host_unittest_no_message_loop.cc
+++ b/cc/trees/layer_tree_host_unittest_no_message_loop.cc
@@ -74,8 +74,6 @@
   virtual void DidCompleteSwapBuffers() OVERRIDE {}
 
   // LayerTreeHostSingleThreadClient overrides.
-  virtual void ScheduleComposite() OVERRIDE {}
-  virtual void ScheduleAnimation() OVERRIDE {}
   virtual void DidPostSwapBuffers() OVERRIDE {}
   virtual void DidAbortSwapBuffers() OVERRIDE {}
 
@@ -96,6 +94,7 @@
 
   void SetupLayerTreeHost() {
     LayerTreeSettings settings;
+    settings.single_thread_proxy_scheduler = false;
     layer_tree_host_ =
         LayerTreeHost::CreateSingleThreaded(this, this, NULL, settings, NULL);
     layer_tree_host_->SetViewportSize(size_);
diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc
index bf72893..56e18a2 100644
--- a/cc/trees/layer_tree_settings.cc
+++ b/cc/trees/layer_tree_settings.cc
@@ -16,6 +16,7 @@
     : impl_side_painting(false),
       allow_antialiasing(true),
       throttle_frame_production(true),
+      single_thread_proxy_scheduler(true),
       begin_frame_scheduling_enabled(false),
       main_frame_before_draw_enabled(true),
       main_frame_before_activation_enabled(false),
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index 14cec67c..bad3bf4f 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -21,6 +21,7 @@
   bool impl_side_painting;
   bool allow_antialiasing;
   bool throttle_frame_production;
+  bool single_thread_proxy_scheduler;
   bool begin_frame_scheduling_enabled;
   bool main_frame_before_draw_enabled;
   bool main_frame_before_activation_enabled;
diff --git a/cc/trees/scoped_abort_remaining_swap_promises.h b/cc/trees/scoped_abort_remaining_swap_promises.h
new file mode 100644
index 0000000..f8dfc01
--- /dev/null
+++ b/cc/trees/scoped_abort_remaining_swap_promises.h
@@ -0,0 +1,30 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_TREES_SCOPED_ABORT_REMAINING_SWAP_PROMISES_H_
+#define CC_TREES_SCOPED_ABORT_REMAINING_SWAP_PROMISES_H_
+
+#include "cc/base/swap_promise.h"
+#include "cc/trees/layer_tree_host.h"
+
+namespace cc {
+
+class ScopedAbortRemainingSwapPromises {
+ public:
+  explicit ScopedAbortRemainingSwapPromises(LayerTreeHost* layer_tree_host)
+      : layer_tree_host_(layer_tree_host) {}
+
+  ~ScopedAbortRemainingSwapPromises() {
+    layer_tree_host_->BreakSwapPromises(SwapPromise::COMMIT_FAILS);
+  }
+
+ private:
+  LayerTreeHost* layer_tree_host_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScopedAbortRemainingSwapPromises);
+};
+
+}  // namespace cc
+
+#endif  // CC_TREES_SCOPED_ABORT_REMAINING_SWAP_PROMISES_H_
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index ab77579..12898df9 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -16,6 +16,7 @@
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_host_single_thread_client.h"
 #include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/scoped_abort_remaining_swap_promises.h"
 #include "ui/gfx/frame_time.h"
 
 namespace cc {
@@ -36,8 +37,13 @@
     : Proxy(main_task_runner, NULL),
       layer_tree_host_(layer_tree_host),
       client_(client),
+      timing_history_(layer_tree_host->rendering_stats_instrumentation()),
       next_frame_is_newly_committed_frame_(false),
-      inside_draw_(false) {
+      inside_draw_(false),
+      defer_commits_(false),
+      commit_was_deferred_(false),
+      commit_requested_(false),
+      weak_factory_(this) {
   TRACE_EVENT0("cc", "SingleThreadProxy::SingleThreadProxy");
   DCHECK(Proxy::IsMainThread());
   DCHECK(layer_tree_host);
@@ -77,13 +83,26 @@
   TRACE_EVENT0("cc", "SingleThreadProxy::SetLayerTreeHostClientReady");
   // Scheduling is controlled by the embedder in the single thread case, so
   // nothing to do.
+  DCHECK(Proxy::IsMainThread());
+  DebugScopedSetImplThread impl(this);
+  if (layer_tree_host_->settings().single_thread_proxy_scheduler &&
+      !scheduler_on_impl_thread_) {
+    SchedulerSettings scheduler_settings(layer_tree_host_->settings());
+    scheduler_on_impl_thread_ = Scheduler::Create(this,
+                                                  scheduler_settings,
+                                                  layer_tree_host_->id(),
+                                                  MainThreadTaskRunner());
+    scheduler_on_impl_thread_->SetCanStart();
+    scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible());
+  }
 }
 
 void SingleThreadProxy::SetVisible(bool visible) {
   TRACE_EVENT0("cc", "SingleThreadProxy::SetVisible");
   DebugScopedSetImplThread impl(this);
   layer_tree_host_impl_->SetVisible(visible);
-
+  if (scheduler_on_impl_thread_)
+    scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible());
   // Changing visibility could change ShouldComposite().
   UpdateBackgroundAnimateTicking();
 }
@@ -110,9 +129,14 @@
 
   layer_tree_host_->OnCreateAndInitializeOutputSurfaceAttempted(success);
 
-  if (!success) {
-    // Force another recreation attempt to happen by requesting another commit.
-    SetNeedsCommit();
+  if (success) {
+    if (scheduler_on_impl_thread_)
+      scheduler_on_impl_thread_->DidCreateAndInitializeOutputSurface();
+  } else if (Proxy::MainThreadTaskRunner()) {
+    MainThreadTaskRunner()->PostTask(
+        FROM_HERE,
+        base::Bind(&SingleThreadProxy::CreateAndInitializeOutputSurface,
+                   weak_factory_.GetWeakPtr()));
   }
 }
 
@@ -126,17 +150,40 @@
   TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsAnimate");
   DCHECK(Proxy::IsMainThread());
   client_->ScheduleAnimation();
+  SetNeedsCommit();
 }
 
 void SingleThreadProxy::SetNeedsUpdateLayers() {
   TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsUpdateLayers");
   DCHECK(Proxy::IsMainThread());
-  client_->ScheduleComposite();
+  SetNeedsCommit();
 }
 
-void SingleThreadProxy::DoCommit(scoped_ptr<ResourceUpdateQueue> queue) {
+void SingleThreadProxy::DoCommit(const BeginFrameArgs& begin_frame_args) {
   TRACE_EVENT0("cc", "SingleThreadProxy::DoCommit");
   DCHECK(Proxy::IsMainThread());
+  layer_tree_host_->WillBeginMainFrame();
+  layer_tree_host_->BeginMainFrame(begin_frame_args);
+  layer_tree_host_->AnimateLayers(begin_frame_args.frame_time);
+  layer_tree_host_->Layout();
+  commit_requested_ = false;
+
+  if (PrioritizedResourceManager* contents_texture_manager =
+          layer_tree_host_->contents_texture_manager()) {
+    contents_texture_manager->UnlinkAndClearEvictedBackings();
+    contents_texture_manager->SetMaxMemoryLimitBytes(
+        layer_tree_host_impl_->memory_allocation_limit_bytes());
+    contents_texture_manager->SetExternalPriorityCutoff(
+        layer_tree_host_impl_->memory_allocation_priority_cutoff());
+  }
+
+  scoped_ptr<ResourceUpdateQueue> queue =
+      make_scoped_ptr(new ResourceUpdateQueue);
+
+  layer_tree_host_->UpdateLayers(queue.get());
+
+  layer_tree_host_->WillCommit();
+
   // Commit immediately.
   {
     DebugScopedSetMainThreadBlocked main_thread_blocked(this);
@@ -158,7 +205,7 @@
     scoped_ptr<ResourceUpdateController> update_controller =
         ResourceUpdateController::Create(
             NULL,
-            Proxy::MainThreadTaskRunner(),
+            MainThreadTaskRunner(),
             queue.Pass(),
             layer_tree_host_impl_->resource_provider());
     update_controller->Finalize();
@@ -170,6 +217,8 @@
 
     layer_tree_host_impl_->CommitComplete();
 
+    UpdateBackgroundAnimateTicking();
+
 #if DCHECK_IS_ON
     // In the single-threaded case, the scale and scroll deltas should never be
     // touched on the impl layer tree.
@@ -186,33 +235,66 @@
     stats_instrumentation->AccumulateAndClearMainThreadStats();
   }
   layer_tree_host_->CommitComplete();
+  layer_tree_host_->DidBeginMainFrame();
+  timing_history_.DidCommit();
+
   next_frame_is_newly_committed_frame_ = true;
 }
 
 void SingleThreadProxy::SetNeedsCommit() {
   DCHECK(Proxy::IsMainThread());
+  DebugScopedSetImplThread impl(this);
   client_->ScheduleComposite();
+  if (scheduler_on_impl_thread_)
+    scheduler_on_impl_thread_->SetNeedsCommit();
+  commit_requested_ = true;
 }
 
 void SingleThreadProxy::SetNeedsRedraw(const gfx::Rect& damage_rect) {
   TRACE_EVENT0("cc", "SingleThreadProxy::SetNeedsRedraw");
-  SetNeedsRedrawRectOnImplThread(damage_rect);
+  DCHECK(Proxy::IsMainThread());
+  DebugScopedSetImplThread impl(this);
   client_->ScheduleComposite();
+  SetNeedsRedrawRectOnImplThread(damage_rect);
 }
 
 void SingleThreadProxy::SetNextCommitWaitsForActivation() {
   // There is no activation here other than commit. So do nothing.
+  DCHECK(Proxy::IsMainThread());
 }
 
 void SingleThreadProxy::SetDeferCommits(bool defer_commits) {
+  DCHECK(Proxy::IsMainThread());
+  // Deferring commits only makes sense if there's a scheduler.
+  if (!scheduler_on_impl_thread_)
+    return;
+  if (defer_commits_ == defer_commits)
+    return;
+
+  if (defer_commits)
+    TRACE_EVENT_ASYNC_BEGIN0("cc", "SingleThreadProxy::SetDeferCommits", this);
+  else
+    TRACE_EVENT_ASYNC_END0("cc", "SingleThreadProxy::SetDeferCommits", this);
+
+  defer_commits_ = defer_commits;
+  if (!defer_commits_ && commit_was_deferred_) {
+    commit_was_deferred_ = false;
+    BeginMainFrame();
+  }
 }
 
 bool SingleThreadProxy::CommitRequested() const {
-  return false;
+  DCHECK(Proxy::IsMainThread());
+  return commit_requested_;
 }
 
 bool SingleThreadProxy::BeginMainFrameRequested() const {
-  return false;
+  DCHECK(Proxy::IsMainThread());
+  // If there is no scheduler, then there can be no pending begin frame,
+  // as all frames are all manually initiated by the embedder of cc.
+  if (!scheduler_on_impl_thread_)
+    return false;
+  return commit_requested_;
 }
 
 size_t SingleThreadProxy::MaxPartialTextureUpdates() const {
@@ -229,6 +311,7 @@
     BlockingTaskRunner::CapturePostTasks blocked;
     layer_tree_host_->DeleteContentsTexturesOnImplThread(
         layer_tree_host_impl_->resource_provider());
+    scheduler_on_impl_thread_.reset();
     layer_tree_host_impl_.reset();
   }
   layer_tree_host_ = NULL;
@@ -239,15 +322,19 @@
       "cc", "SingleThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw);
   DCHECK(Proxy::IsImplThread());
   UpdateBackgroundAnimateTicking();
+  if (scheduler_on_impl_thread_)
+    scheduler_on_impl_thread_->SetCanDraw(can_draw);
 }
 
 void SingleThreadProxy::NotifyReadyToActivate() {
-  // Thread-only feature.
+  // Impl-side painting only.
   NOTREACHED();
 }
 
 void SingleThreadProxy::SetNeedsRedrawOnImplThread() {
   client_->ScheduleComposite();
+  if (scheduler_on_impl_thread_)
+    scheduler_on_impl_thread_->SetNeedsRedraw();
 }
 
 void SingleThreadProxy::SetNeedsAnimateOnImplThread() {
@@ -255,17 +342,14 @@
 }
 
 void SingleThreadProxy::SetNeedsManageTilesOnImplThread() {
-  // Thread-only/Impl-side-painting-only feature.
+  // Impl-side painting only.
   NOTREACHED();
 }
 
 void SingleThreadProxy::SetNeedsRedrawRectOnImplThread(
     const gfx::Rect& damage_rect) {
-  // TODO(brianderson): Once we move render_widget scheduling into this class,
-  // we can treat redraw requests more efficiently than CommitAndRedraw
-  // requests.
   layer_tree_host_impl_->SetViewportDamage(damage_rect);
-  SetNeedsCommit();
+  SetNeedsRedrawOnImplThread();
 }
 
 void SingleThreadProxy::DidInitializeVisibleTileOnImplThread() {
@@ -275,6 +359,8 @@
 
 void SingleThreadProxy::SetNeedsCommitOnImplThread() {
   client_->ScheduleComposite();
+  if (scheduler_on_impl_thread_)
+    scheduler_on_impl_thread_->SetNeedsCommit();
 }
 
 void SingleThreadProxy::PostAnimationEventsToMainThreadOnImplThread(
@@ -311,66 +397,55 @@
       layer_tree_host_impl_->GetRendererCapabilities().MainThreadCapabilities();
 }
 
+void SingleThreadProxy::DidManageTiles() {
+  // Impl-side painting only.
+  NOTREACHED();
+}
+
 void SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() {
   TRACE_EVENT0("cc", "SingleThreadProxy::DidLoseOutputSurfaceOnImplThread");
-  // Cause a commit so we can notice the lost context.
-  SetNeedsCommitOnImplThread();
+  {
+    DebugScopedSetMainThread main(this);
+    // This must happen before we notify the scheduler as it may try to recreate
+    // the output surface if already in BEGIN_IMPL_FRAME_STATE_IDLE.
+    layer_tree_host_->DidLoseOutputSurface();
+  }
   client_->DidAbortSwapBuffers();
+  if (scheduler_on_impl_thread_)
+    scheduler_on_impl_thread_->DidLoseOutputSurface();
 }
 
 void SingleThreadProxy::DidSwapBuffersOnImplThread() {
+  TRACE_EVENT0("cc", "SingleThreadProxy::DidSwapBuffersOnImplThread");
+  if (scheduler_on_impl_thread_)
+    scheduler_on_impl_thread_->DidSwapBuffers();
   client_->DidPostSwapBuffers();
 }
 
 void SingleThreadProxy::DidSwapBuffersCompleteOnImplThread() {
   TRACE_EVENT0("cc", "SingleThreadProxy::DidSwapBuffersCompleteOnImplThread");
-  client_->DidCompleteSwapBuffers();
+  if (scheduler_on_impl_thread_)
+    scheduler_on_impl_thread_->DidSwapBuffersComplete();
+  layer_tree_host_->DidCompleteSwapBuffers();
 }
 
-// Called by the legacy scheduling path (e.g. where render_widget does the
-// scheduling)
+void SingleThreadProxy::BeginFrame(const BeginFrameArgs& args) {
+  TRACE_EVENT0("cc", "SingleThreadProxy::BeginFrame");
+  if (scheduler_on_impl_thread_)
+    scheduler_on_impl_thread_->BeginImplFrame(args);
+}
+
 void SingleThreadProxy::CompositeImmediately(base::TimeTicks frame_begin_time) {
   TRACE_EVENT0("cc", "SingleThreadProxy::CompositeImmediately");
   DCHECK(Proxy::IsMainThread());
   DCHECK(!layer_tree_host_->output_surface_lost());
 
-  layer_tree_host_->AnimateLayers(frame_begin_time);
-
-  if (PrioritizedResourceManager* contents_texture_manager =
-          layer_tree_host_->contents_texture_manager()) {
-    contents_texture_manager->UnlinkAndClearEvictedBackings();
-    contents_texture_manager->SetMaxMemoryLimitBytes(
-        layer_tree_host_impl_->memory_allocation_limit_bytes());
-    contents_texture_manager->SetExternalPriorityCutoff(
-        layer_tree_host_impl_->memory_allocation_priority_cutoff());
-  }
-
-  scoped_ptr<ResourceUpdateQueue> queue =
-      make_scoped_ptr(new ResourceUpdateQueue);
-  layer_tree_host_->UpdateLayers(queue.get());
-  layer_tree_host_->WillCommit();
-  DoCommit(queue.Pass());
-  layer_tree_host_->DidBeginMainFrame();
+  BeginFrameArgs begin_frame_args = BeginFrameArgs::Create(
+      frame_begin_time, base::TimeTicks(), BeginFrameArgs::DefaultInterval());
+  DoCommit(begin_frame_args);
 
   LayerTreeHostImpl::FrameData frame;
-  if (DoComposite(frame_begin_time, &frame)) {
-    {
-      DebugScopedSetMainThreadBlocked main_thread_blocked(this);
-      DebugScopedSetImplThread impl(this);
-
-      // This CapturePostTasks should be destroyed before
-      // DidCommitAndDrawFrame() is called since that goes out to the embedder,
-      // and we want the embedder to receive its callbacks before that.
-      // NOTE: This maintains consistent ordering with the ThreadProxy since
-      // the DidCommitAndDrawFrame() must be post-tasked from the impl thread
-      // there as the main thread is not blocked, so any posted tasks inside
-      // the swap buffers will execute first.
-      BlockingTaskRunner::CapturePostTasks blocked;
-
-      layer_tree_host_impl_->SwapBuffers(frame);
-    }
-    DidSwapFrame();
-  }
+  DoComposite(frame_begin_time, &frame);
 }
 
 void SingleThreadProxy::AsValueInto(base::debug::TracedValue* state) const {
@@ -410,12 +485,11 @@
       !ShouldComposite() && layer_tree_host_impl_->active_tree()->root_layer());
 }
 
-bool SingleThreadProxy::DoComposite(base::TimeTicks frame_begin_time,
-                                    LayerTreeHostImpl::FrameData* frame) {
+DrawResult SingleThreadProxy::DoComposite(base::TimeTicks frame_begin_time,
+                                          LayerTreeHostImpl::FrameData* frame) {
   TRACE_EVENT0("cc", "SingleThreadProxy::DoComposite");
   DCHECK(!layer_tree_host_->output_surface_lost());
 
-  bool lost_output_surface = false;
   {
     DebugScopedSetImplThread impl(this);
     base::AutoReset<bool> mark_inside(&inside_draw_, true);
@@ -426,9 +500,11 @@
     // CanDraw() as well.
     if (!ShouldComposite()) {
       UpdateBackgroundAnimateTicking();
-      return false;
+      return DRAW_ABORTED_CANT_DRAW;
     }
 
+    timing_history_.DidStartDrawing();
+
     layer_tree_host_impl_->Animate(
         layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time);
     UpdateBackgroundAnimateTicking();
@@ -438,24 +514,43 @@
       layer_tree_host_impl_->DrawLayers(frame, frame_begin_time);
       layer_tree_host_impl_->DidDrawAllLayers(*frame);
     }
-    lost_output_surface = layer_tree_host_impl_->IsContextLost();
 
     bool start_ready_animations = true;
     layer_tree_host_impl_->UpdateAnimationState(start_ready_animations);
 
     layer_tree_host_impl_->ResetCurrentBeginFrameArgsForNextFrame();
+
+    timing_history_.DidFinishDrawing();
   }
 
-  if (lost_output_surface) {
-    layer_tree_host_->DidLoseOutputSurface();
-    return false;
-  }
+  {
+    DebugScopedSetImplThread impl(this);
 
-  return true;
+    if (layer_tree_host_impl_->IsContextLost()) {
+      DidLoseOutputSurfaceOnImplThread();
+    } else {
+      // This CapturePostTasks should be destroyed before
+      // DidCommitAndDrawFrame() is called since that goes out to the
+      // embedder,
+      // and we want the embedder to receive its callbacks before that.
+      // NOTE: This maintains consistent ordering with the ThreadProxy since
+      // the DidCommitAndDrawFrame() must be post-tasked from the impl thread
+      // there as the main thread is not blocked, so any posted tasks inside
+      // the swap buffers will execute first.
+      DebugScopedSetMainThreadBlocked main_thread_blocked(this);
+
+      BlockingTaskRunner::CapturePostTasks blocked;
+      layer_tree_host_impl_->SwapBuffers(*frame);
+    }
+  }
+  DidCommitAndDrawFrame();
+
+  return DRAW_SUCCESS;
 }
 
-void SingleThreadProxy::DidSwapFrame() {
+void SingleThreadProxy::DidCommitAndDrawFrame() {
   if (next_frame_is_newly_committed_frame_) {
+    DebugScopedSetMainThread main(this);
     next_frame_is_newly_committed_frame_ = false;
     layer_tree_host_->DidCommitAndDrawFrame();
   }
@@ -465,4 +560,147 @@
   return false;
 }
 
+void SingleThreadProxy::SetNeedsBeginFrame(bool enable) {
+  layer_tree_host_impl_->SetNeedsBeginFrame(enable);
+}
+
+void SingleThreadProxy::WillBeginImplFrame(const BeginFrameArgs& args) {
+  layer_tree_host_impl_->WillBeginImplFrame(args);
+}
+
+void SingleThreadProxy::ScheduledActionSendBeginMainFrame() {
+  TRACE_EVENT0("cc", "SingleThreadProxy::ScheduledActionSendBeginMainFrame");
+  // Although this proxy is single-threaded, it's problematic to synchronously
+  // have BeginMainFrame happen after ScheduledActionSendBeginMainFrame.  This
+  // could cause a commit to occur in between a series of SetNeedsCommit calls
+  // (i.e. property modifications) causing some to fall on one frame and some to
+  // fall on the next.  Doing it asynchronously instead matches the semantics of
+  // ThreadProxy::SetNeedsCommit where SetNeedsCommit will not cause a
+  // synchronous commit.
+  MainThreadTaskRunner()->PostTask(
+      FROM_HERE,
+      base::Bind(&SingleThreadProxy::BeginMainFrame,
+                 weak_factory_.GetWeakPtr()));
+}
+
+void SingleThreadProxy::BeginMainFrame() {
+  if (defer_commits_) {
+    DCHECK(!commit_was_deferred_);
+    commit_was_deferred_ = true;
+    layer_tree_host_->DidDeferCommit();
+    return;
+  }
+
+  // This checker assumes NotifyReadyToCommit below causes a synchronous commit.
+  ScopedAbortRemainingSwapPromises swap_promise_checker(layer_tree_host_);
+
+  if (!layer_tree_host_->visible()) {
+    TRACE_EVENT_INSTANT0("cc", "EarlyOut_NotVisible", TRACE_EVENT_SCOPE_THREAD);
+    BeginMainFrameAbortedOnImplThread();
+    return;
+  }
+
+  if (layer_tree_host_->output_surface_lost()) {
+    TRACE_EVENT_INSTANT0(
+        "cc", "EarlyOut_OutputSurfaceLost", TRACE_EVENT_SCOPE_THREAD);
+    BeginMainFrameAbortedOnImplThread();
+    return;
+  }
+
+  timing_history_.DidBeginMainFrame();
+
+  DCHECK(scheduler_on_impl_thread_);
+  scheduler_on_impl_thread_->NotifyBeginMainFrameStarted();
+  scheduler_on_impl_thread_->NotifyReadyToCommit();
+}
+
+void SingleThreadProxy::BeginMainFrameAbortedOnImplThread() {
+  DebugScopedSetImplThread impl(this);
+  DCHECK(scheduler_on_impl_thread_->CommitPending());
+  DCHECK(!layer_tree_host_impl_->pending_tree());
+
+  // TODO(enne): SingleThreadProxy does not support cancelling commits yet so
+  // did_handle is always false.
+  bool did_handle = false;
+  layer_tree_host_impl_->BeginMainFrameAborted(did_handle);
+  scheduler_on_impl_thread_->BeginMainFrameAborted(did_handle);
+}
+
+DrawResult SingleThreadProxy::ScheduledActionDrawAndSwapIfPossible() {
+  DebugScopedSetImplThread impl(this);
+  if (layer_tree_host_impl_->IsContextLost()) {
+    DidCommitAndDrawFrame();
+    return DRAW_SUCCESS;
+  }
+
+  LayerTreeHostImpl::FrameData frame;
+  return DoComposite(layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time,
+                     &frame);
+}
+
+DrawResult SingleThreadProxy::ScheduledActionDrawAndSwapForced() {
+  NOTREACHED();
+  return INVALID_RESULT;
+}
+
+void SingleThreadProxy::ScheduledActionCommit() {
+  DebugScopedSetMainThread main(this);
+  DoCommit(layer_tree_host_impl_->CurrentBeginFrameArgs());
+}
+
+void SingleThreadProxy::ScheduledActionAnimate() {
+  TRACE_EVENT0("cc", "ScheduledActionAnimate");
+  layer_tree_host_impl_->Animate(
+      layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time);
+}
+
+void SingleThreadProxy::ScheduledActionUpdateVisibleTiles() {
+  // Impl-side painting only.
+  NOTREACHED();
+}
+
+void SingleThreadProxy::ScheduledActionActivateSyncTree() {
+}
+
+void SingleThreadProxy::ScheduledActionBeginOutputSurfaceCreation() {
+  DebugScopedSetMainThread main(this);
+  DCHECK(scheduler_on_impl_thread_);
+  // If possible, create the output surface in a post task.  Synchronously
+  // creating the output surface makes tests more awkward since this differs
+  // from the ThreadProxy behavior.  However, sometimes there is no
+  // task runner.
+  if (Proxy::MainThreadTaskRunner()) {
+    MainThreadTaskRunner()->PostTask(
+        FROM_HERE,
+        base::Bind(&SingleThreadProxy::CreateAndInitializeOutputSurface,
+                   weak_factory_.GetWeakPtr()));
+  } else {
+    CreateAndInitializeOutputSurface();
+  }
+}
+
+void SingleThreadProxy::ScheduledActionManageTiles() {
+  // Impl-side painting only.
+  NOTREACHED();
+}
+
+void SingleThreadProxy::DidAnticipatedDrawTimeChange(base::TimeTicks time) {
+}
+
+base::TimeDelta SingleThreadProxy::DrawDurationEstimate() {
+  return timing_history_.DrawDurationEstimate();
+}
+
+base::TimeDelta SingleThreadProxy::BeginMainFrameToCommitDurationEstimate() {
+  return timing_history_.BeginMainFrameToCommitDurationEstimate();
+}
+
+base::TimeDelta SingleThreadProxy::CommitToActivateDurationEstimate() {
+  return timing_history_.CommitToActivateDurationEstimate();
+}
+
+void SingleThreadProxy::DidBeginImplFrameDeadline() {
+  layer_tree_host_impl_->ResetCurrentBeginFrameArgsForNextFrame();
+}
+
 }  // namespace cc
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h
index 685b11a8..b3a55b4 100644
--- a/cc/trees/single_thread_proxy.h
+++ b/cc/trees/single_thread_proxy.h
@@ -10,8 +10,10 @@
 #include "base/time/time.h"
 #include "cc/animation/animation_events.h"
 #include "cc/output/begin_frame_args.h"
+#include "cc/scheduler/scheduler.h"
 #include "cc/trees/layer_tree_host_impl.h"
 #include "cc/trees/proxy.h"
+#include "cc/trees/proxy_timing_history.h"
 
 namespace cc {
 
@@ -20,7 +22,8 @@
 class LayerTreeHostSingleThreadClient;
 
 class CC_EXPORT SingleThreadProxy : public Proxy,
-                                    NON_EXPORTED_BASE(LayerTreeHostImplClient) {
+                                    NON_EXPORTED_BASE(LayerTreeHostImplClient),
+                                    SchedulerClient {
  public:
   static scoped_ptr<Proxy> Create(
       LayerTreeHost* layer_tree_host,
@@ -52,6 +55,24 @@
   virtual void AsValueInto(base::debug::TracedValue* state) const OVERRIDE;
   virtual bool MainFrameWillHappenForTesting() OVERRIDE;
 
+  // SchedulerClient implementation
+  virtual void SetNeedsBeginFrame(bool enable) OVERRIDE;
+  virtual void WillBeginImplFrame(const BeginFrameArgs& args) OVERRIDE;
+  virtual void ScheduledActionSendBeginMainFrame() OVERRIDE;
+  virtual DrawResult ScheduledActionDrawAndSwapIfPossible() OVERRIDE;
+  virtual DrawResult ScheduledActionDrawAndSwapForced() OVERRIDE;
+  virtual void ScheduledActionCommit() OVERRIDE;
+  virtual void ScheduledActionAnimate() OVERRIDE;
+  virtual void ScheduledActionUpdateVisibleTiles() OVERRIDE;
+  virtual void ScheduledActionActivateSyncTree() OVERRIDE;
+  virtual void ScheduledActionBeginOutputSurfaceCreation() OVERRIDE;
+  virtual void ScheduledActionManageTiles() OVERRIDE;
+  virtual void DidAnticipatedDrawTimeChange(base::TimeTicks time) OVERRIDE;
+  virtual base::TimeDelta DrawDurationEstimate() OVERRIDE;
+  virtual base::TimeDelta BeginMainFrameToCommitDurationEstimate() OVERRIDE;
+  virtual base::TimeDelta CommitToActivateDurationEstimate() OVERRIDE;
+  virtual void DidBeginImplFrameDeadline() OVERRIDE;
+
   // LayerTreeHostImplClient implementation
   virtual void UpdateRendererCapabilitiesOnImplThread() OVERRIDE;
   virtual void DidLoseOutputSurfaceOnImplThread() OVERRIDE;
@@ -61,7 +82,7 @@
   virtual void SetMaxSwapsPendingOnImplThread(int max) OVERRIDE {}
   virtual void DidSwapBuffersOnImplThread() OVERRIDE;
   virtual void DidSwapBuffersCompleteOnImplThread() OVERRIDE;
-  virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE {}
+  virtual void BeginFrame(const BeginFrameArgs& args) OVERRIDE;
   virtual void OnCanDrawStateChanged(bool can_draw) OVERRIDE;
   virtual void NotifyReadyToActivate() OVERRIDE;
   virtual void SetNeedsRedrawOnImplThread() OVERRIDE;
@@ -82,7 +103,7 @@
       const base::Closure& start_fade,
       base::TimeDelta delay) OVERRIDE {}
   virtual void DidActivateSyncTree() OVERRIDE {}
-  virtual void DidManageTiles() OVERRIDE {}
+  virtual void DidManageTiles() OVERRIDE;
   virtual void SetDebugState(const LayerTreeDebugState& debug_state) OVERRIDE {}
 
   // Attempts to create the context and renderer synchronously. Calls
@@ -98,10 +119,13 @@
       LayerTreeHostSingleThreadClient* client,
       scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
 
-  void DoCommit(scoped_ptr<ResourceUpdateQueue> queue);
-  bool DoComposite(base::TimeTicks frame_begin_time,
-                   LayerTreeHostImpl::FrameData* frame);
-  void DidSwapFrame();
+  void BeginMainFrame();
+  void BeginMainFrameAbortedOnImplThread();
+  void DoCommit(const BeginFrameArgs& begin_frame_args);
+  DrawResult DoComposite(base::TimeTicks frame_begin_time,
+                         LayerTreeHostImpl::FrameData* frame);
+  void DoSwap();
+  void DidCommitAndDrawFrame();
 
   bool ShouldComposite() const;
   void UpdateBackgroundAnimateTicking();
@@ -115,9 +139,18 @@
   scoped_ptr<LayerTreeHostImpl> layer_tree_host_impl_;
   RendererCapabilities renderer_capabilities_for_main_thread_;
 
+  // Accessed from both threads.
+  scoped_ptr<Scheduler> scheduler_on_impl_thread_;
+  ProxyTimingHistory timing_history_;
+
   bool next_frame_is_newly_committed_frame_;
 
   bool inside_draw_;
+  bool defer_commits_;
+  bool commit_was_deferred_;
+  bool commit_requested_;
+
+  base::WeakPtrFactory<SingleThreadProxy> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(SingleThreadProxy);
 };
diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc
index 2e41ea7d..4a95140 100644
--- a/cc/trees/thread_proxy.cc
+++ b/cc/trees/thread_proxy.cc
@@ -25,6 +25,7 @@
 #include "cc/trees/blocking_task_runner.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/scoped_abort_remaining_swap_promises.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "ui/gfx/frame_time.h"
 
@@ -37,19 +38,6 @@
 
 unsigned int nextBeginFrameId = 0;
 
-class SwapPromiseChecker {
- public:
-  explicit SwapPromiseChecker(LayerTreeHost* layer_tree_host)
-      : layer_tree_host_(layer_tree_host) {}
-
-  ~SwapPromiseChecker() {
-    layer_tree_host_->BreakSwapPromises(SwapPromise::COMMIT_FAILS);
-  }
-
- private:
-  LayerTreeHost* layer_tree_host_;
-};
-
 }  // namespace
 
 struct ThreadProxy::SchedulerStateRequest {
@@ -453,9 +441,10 @@
 
 void ThreadProxy::SetDeferCommits(bool defer_commits) {
   DCHECK(IsMainThread());
-  DCHECK_NE(main().defer_commits, defer_commits);
-  main().defer_commits = defer_commits;
+  if (main().defer_commits == defer_commits)
+    return;
 
+  main().defer_commits = defer_commits;
   if (main().defer_commits)
     TRACE_EVENT_ASYNC_BEGIN0("cc", "ThreadProxy::SetDeferCommits", this);
   else
@@ -735,9 +724,9 @@
   }
 
   // If the commit finishes, LayerTreeHost will transfer its swap promises to
-  // LayerTreeImpl. The destructor of SwapPromiseChecker checks LayerTressHost's
-  // swap promises.
-  SwapPromiseChecker swap_promise_checker(layer_tree_host());
+  // LayerTreeImpl. The destructor of ScopedSwapPromiseChecker aborts the
+  // remaining swap promises.
+  ScopedAbortRemainingSwapPromises swap_promise_checker(layer_tree_host());
 
   main().commit_requested = false;
   main().commit_request_sent_to_impl_thread = false;
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 3ca74a2b..13b0735 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -314,7 +314,6 @@
   // animation updates that will already be reflected in the current frame
   // we are about to draw.
   ignore_schedule_composite_ = true;
-  client_->Layout();
 
   const base::TimeTicks frame_time = gfx::FrameTime::Now();
   if (needs_animate_) {
@@ -426,7 +425,6 @@
   } else if (!host_) {
     DCHECK(!WillComposite());
     needs_composite_ = false;
-    needs_animate_ = false;
     pending_swapbuffers_ = 0;
     cc::LayerTreeSettings settings;
     settings.refresh_rate = 60.0;
@@ -441,6 +439,8 @@
         command_line->HasSwitch(cc::switches::kEnableGpuBenchmarking));
     settings.initial_debug_state.show_fps_counter =
         command_line->HasSwitch(cc::switches::kUIShowFPSCounter);
+    // TODO(enne): Update this this compositor to use the scheduler.
+    settings.single_thread_proxy_scheduler = false;
 
     host_ = cc::LayerTreeHost::CreateSingleThreaded(
         this,
@@ -523,10 +523,9 @@
 }
 
 void CompositorImpl::Layout() {
-  // TODO: If we get this callback from the SingleThreadProxy, we need
-  // to stop calling it ourselves in CompositorImpl::Composite().
-  NOTREACHED();
+  ignore_schedule_composite_ = true;
   client_->Layout();
+  ignore_schedule_composite_ = false;
 }
 
 scoped_ptr<cc::OutputSurface> CompositorImpl::CreateOutputSurface(
@@ -575,7 +574,6 @@
 }
 
 void CompositorImpl::ScheduleAnimation() {
-  DCHECK(!needs_animate_ || needs_composite_);
   DCHECK(!needs_composite_ || WillComposite());
   needs_animate_ = true;
 
@@ -605,6 +603,7 @@
   // This really gets called only once from
   // SingleThreadProxy::DidLoseOutputSurfaceOnImplThread() when the
   // context was lost.
+  ScheduleComposite();
   client_->OnSwapBuffersCompleted(0);
 }
 
diff --git a/content/public/common/content_switches.cc b/content/public/common/content_switches.cc
index bdc9f56..1747428 100644
--- a/content/public/common/content_switches.cc
+++ b/content/public/common/content_switches.cc
@@ -237,6 +237,10 @@
 // Disable shared workers.
 const char kDisableSharedWorkers[]          = "disable-shared-workers";
 
+// For tests, disable single thread scheduler and only manually composite.
+const char kDisableSingleThreadProxyScheduler[] =
+    "disable-single-thread-proxy-scheduler";
+
 // Disable smooth scrolling for testing.
 const char kDisableSmoothScrolling[]        = "disable-smooth-scrolling";
 
diff --git a/content/public/common/content_switches.h b/content/public/common/content_switches.h
index 8c11ed6f..dd0a730 100644
--- a/content/public/common/content_switches.h
+++ b/content/public/common/content_switches.h
@@ -77,6 +77,7 @@
 extern const char kDisableSessionStorage[];
 CONTENT_EXPORT extern const char kDisableSetuidSandbox[];
 CONTENT_EXPORT extern const char kDisableSharedWorkers[];
+CONTENT_EXPORT extern const char kDisableSingleThreadProxyScheduler[];
 CONTENT_EXPORT extern const char kDisableSmoothScrolling[];
 CONTENT_EXPORT extern const char kDisableSoftwareRasterizer[];
 CONTENT_EXPORT extern const char kDisableThreadedCompositing[];
diff --git a/content/renderer/gpu/render_widget_compositor.cc b/content/renderer/gpu/render_widget_compositor.cc
index 814157a5..e4335ab 100644
--- a/content/renderer/gpu/render_widget_compositor.cc
+++ b/content/renderer/gpu/render_widget_compositor.cc
@@ -279,6 +279,8 @@
       cmd->HasSwitch(cc::switches::kEnablePinchVirtualViewport);
   settings.allow_antialiasing &=
       !cmd->HasSwitch(cc::switches::kDisableCompositedAntialiasing);
+  settings.single_thread_proxy_scheduler =
+      !cmd->HasSwitch(switches::kDisableSingleThreadProxyScheduler);
 
   // These flags should be mirrored by UI versions in ui/compositor/.
   settings.initial_debug_state.show_debug_borders =
@@ -411,7 +413,6 @@
 RenderWidgetCompositor::RenderWidgetCompositor(RenderWidget* widget,
                                                bool threaded)
     : threaded_(threaded),
-      suppress_schedule_composite_(false),
       widget_(widget) {
 }
 
@@ -422,19 +423,6 @@
   return layer_tree_host_->GetInputHandler();
 }
 
-void RenderWidgetCompositor::SetSuppressScheduleComposite(bool suppress) {
-  if (suppress_schedule_composite_ == suppress)
-    return;
-
-  if (suppress)
-    TRACE_EVENT_ASYNC_BEGIN0(
-        "gpu", "RenderWidgetCompositor::SetSuppressScheduleComposite", this);
-  else
-    TRACE_EVENT_ASYNC_END0(
-        "gpu", "RenderWidgetCompositor::SetSuppressScheduleComposite", this);
-  suppress_schedule_composite_ = suppress;
-}
-
 bool RenderWidgetCompositor::BeginMainFrameRequested() const {
   return layer_tree_host_->BeginMainFrameRequested();
 }
@@ -547,7 +535,10 @@
 }
 
 void RenderWidgetCompositor::setSurfaceReady() {
-  layer_tree_host_->SetLayerTreeHostClientReady();
+  // In tests without a RenderThreadImpl, don't set ready as this kicks
+  // off creating output surfaces that the test can't create.
+  if (RenderThreadImpl::current())
+    layer_tree_host_->SetLayerTreeHostClientReady();
 }
 
 void RenderWidgetCompositor::setRootLayer(const blink::WebLayer& layer) {
@@ -701,9 +692,9 @@
       cc::CopyOutputRequest::CreateBitmapRequest(
           base::Bind(&CompositeAndReadbackAsyncCallback, callback));
   layer_tree_host_->root_layer()->RequestCopyOfOutput(request.Pass());
-  if (!threaded_) {
-    widget_->webwidget()->animate(0.0);
-    widget_->webwidget()->layout();
+
+  if (!threaded_ &&
+      !layer_tree_host_->settings().single_thread_proxy_scheduler) {
     layer_tree_host_->Composite(gfx::FrameTime::Now());
   }
 }
@@ -800,11 +791,6 @@
     widget_->OnSwapBuffersComplete();
 }
 
-void RenderWidgetCompositor::ScheduleComposite() {
-  if (!suppress_schedule_composite_)
-    widget_->scheduleComposite();
-}
-
 void RenderWidgetCompositor::ScheduleAnimation() {
   widget_->scheduleAnimation();
 }
diff --git a/content/renderer/gpu/render_widget_compositor.h b/content/renderer/gpu/render_widget_compositor.h
index b223f3d..fc8d60e 100644
--- a/content/renderer/gpu/render_widget_compositor.h
+++ b/content/renderer/gpu/render_widget_compositor.h
@@ -44,7 +44,6 @@
   virtual ~RenderWidgetCompositor();
 
   const base::WeakPtr<cc::InputHandler>& GetInputHandler();
-  void SetSuppressScheduleComposite(bool suppress);
   bool BeginMainFrameRequested() const;
   void SetNeedsDisplayOnAllLayers();
   void SetRasterizeOnlyVisibleContent();
@@ -142,7 +141,6 @@
   virtual void RateLimitSharedMainThreadContext() OVERRIDE;
 
   // cc::LayerTreeHostSingleThreadClient implementation.
-  virtual void ScheduleComposite() OVERRIDE;
   virtual void ScheduleAnimation() OVERRIDE;
   virtual void DidPostSwapBuffers() OVERRIDE;
   virtual void DidAbortSwapBuffers() OVERRIDE;
@@ -153,7 +151,6 @@
   void Initialize(cc::LayerTreeSettings settings);
 
   bool threaded_;
-  bool suppress_schedule_composite_;
   RenderWidget* widget_;
   scoped_ptr<cc::LayerTreeHost> layer_tree_host_;
 };
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index e27a3d45..b0b4e8f 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -397,6 +397,7 @@
       handling_event_type_(WebInputEvent::Undefined),
       ignore_ack_for_mouse_move_from_debugger_(false),
       closing_(false),
+      host_closing_(false),
       is_swapped_out_(swapped_out),
       input_method_is_active_(false),
       text_input_type_(ui::TEXT_INPUT_TYPE_NONE),
@@ -1209,6 +1210,8 @@
 }
 
 void RenderWidget::initializeLayerTreeView() {
+  DCHECK(!host_closing_);
+
   compositor_ =
       RenderWidgetCompositor::Create(this, IsThreadedCompositingEnabled());
   compositor_->setViewportSize(size_, physical_backing_size_);
@@ -1216,20 +1219,21 @@
     StartCompositor();
 }
 
+void RenderWidget::DestroyLayerTreeView() {
+  // Always send this notification to prevent new layer tree views from
+  // being created, even if one hasn't been created yet.
+  if (webwidget_)
+    webwidget_->willCloseLayerTreeView();
+  compositor_.reset();
+}
+
 blink::WebLayerTreeView* RenderWidget::layerTreeView() {
   return compositor_.get();
 }
 
-void RenderWidget::suppressCompositorScheduling(bool enable) {
-  if (compositor_)
-    compositor_->SetSuppressScheduleComposite(enable);
-}
-
 void RenderWidget::willBeginCompositorFrame() {
   TRACE_EVENT0("gpu", "RenderWidget::willBeginCompositorFrame");
 
-  DCHECK(RenderThreadImpl::current()->compositor_message_loop_proxy().get());
-
   // The following two can result in further layout and possibly
   // enable GPU acceleration so they need to be called before any painting
   // is done.
@@ -1386,6 +1390,12 @@
 }
 
 void RenderWidget::DoDeferredClose() {
+  // No more compositing is possible.  This prevents shutdown races between
+  // previously posted CreateOutputSurface tasks and the host being unable to
+  // create them because the close message was handled.
+  DestroyLayerTreeView();
+  // Also prevent new compositors from being created.
+  host_closing_ = true;
   Send(new ViewHostMsg_Close(routing_id_));
 }
 
@@ -1425,9 +1435,8 @@
 
 void RenderWidget::Close() {
   screen_metrics_emulator_.reset();
+  DestroyLayerTreeView();
   if (webwidget_) {
-    webwidget_->willCloseLayerTreeView();
-    compositor_.reset();
     webwidget_->close();
     webwidget_ = NULL;
   }
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index f299a191..de04e32 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -142,7 +142,6 @@
   virtual bool Send(IPC::Message* msg) OVERRIDE;
 
   // blink::WebWidgetClient
-  virtual void suppressCompositorScheduling(bool enable);
   virtual void willBeginCompositorFrame();
   virtual void didAutoResize(const blink::WebSize& new_size);
   virtual void initializeLayerTreeView();
@@ -173,6 +172,9 @@
   // Begins the compositor's scheduler to start producing frames.
   void StartCompositor();
 
+  // Stop compositing.
+  void DestroyLayerTreeView();
+
   // Called when a plugin is moved.  These events are queued up and sent with
   // the next paint or scroll message to the host.
   void SchedulePluginMove(const WebPluginGeometry& move);
@@ -627,6 +629,9 @@
   // be sent, except for a Close.
   bool closing_;
 
+  // True if it is known that the host is in the process of being shut down.
+  bool host_closing_;
+
   // Whether this RenderWidget is currently swapped out, such that the view is
   // being rendered by another process.  If all RenderWidgets in a process are
   // swapped out, the process can exit.
diff --git a/content/shell/renderer/test_runner/web_test_proxy.cc b/content/shell/renderer/test_runner/web_test_proxy.cc
index 7e36976..18086de 100644
--- a/content/shell/renderer/test_runner/web_test_proxy.cc
+++ b/content/shell/renderer/test_runner/web_test_proxy.cc
@@ -7,9 +7,11 @@
 #include <cctype>
 
 #include "base/callback_helpers.h"
+#include "base/command_line.h"
 #include "base/debug/trace_event.h"
 #include "base/logging.h"
 #include "base/strings/stringprintf.h"
+#include "content/public/common/content_switches.h"
 #include "content/shell/renderer/test_runner/TestPlugin.h"
 #include "content/shell/renderer/test_runner/WebTestDelegate.h"
 #include "content/shell/renderer/test_runner/WebTestInterfaces.h"
@@ -313,6 +315,10 @@
       web_widget_(NULL),
       spellcheck_(new SpellCheckClient(this)),
       chooser_count_(0) {
+  // TODO(enne): using the scheduler introduces additional composite steps
+  // that create flakiness.  This should go away eventually.
+  base::CommandLine::ForCurrentProcess()->AppendSwitch(
+      switches::kDisableSingleThreadProxyScheduler);
   Reset();
 }
 
diff --git a/content/test/web_layer_tree_view_impl_for_testing.h b/content/test/web_layer_tree_view_impl_for_testing.h
index 26a62600..e2403bc 100644
--- a/content/test/web_layer_tree_view_impl_for_testing.h
+++ b/content/test/web_layer_tree_view_impl_for_testing.h
@@ -80,8 +80,6 @@
   virtual void DidCompleteSwapBuffers() OVERRIDE {}
 
   // cc::LayerTreeHostSingleThreadClient implementation.
-  virtual void ScheduleComposite() OVERRIDE {}
-  virtual void ScheduleAnimation() OVERRIDE {}
   virtual void DidPostSwapBuffers() OVERRIDE {}
   virtual void DidAbortSwapBuffers() OVERRIDE {}
 
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index 34dca93..600134bb 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -136,6 +136,7 @@
 
   settings.impl_side_painting = IsUIImplSidePaintingEnabled();
   settings.use_zero_copy = IsUIZeroCopyEnabled();
+  settings.single_thread_proxy_scheduler = false;
 
   base::TimeTicks before_create = base::TimeTicks::Now();
   if (compositor_thread_loop_) {