Bug 1447299 - Move the sampler thread util functions from APZThreadUtils to APZSampler. r?botond draft
authorKartikaya Gupta <kgupta@mozilla.com>
Thu, 22 Mar 2018 16:35:23 -0400
changeset 771265 137ce36e461701ea60e49c38f31768d11f9af3d1
parent 771264 9e32ccaacf52d87e3e4d26a0e28ca96f9a1a8a2c
child 771266 82138e76aa6e8e716e60886fe9fa9e0b6c588b7f
push id103646
push userkgupta@mozilla.com
push dateThu, 22 Mar 2018 21:38:36 +0000
reviewersbotond
bugs1447299
milestone61.0a1
Bug 1447299 - Move the sampler thread util functions from APZThreadUtils to APZSampler. r?botond Note that this also makes the utility functions instance methods, because each APZSampler might have a different sampler thread instance. MozReview-Commit-ID: ECtfqYCVuTS
gfx/layers/apz/public/APZSampler.h
gfx/layers/apz/src/APZCTreeManager.cpp
gfx/layers/apz/src/APZCTreeManager.h
gfx/layers/apz/src/APZSampler.cpp
gfx/layers/apz/src/AsyncPanZoomController.cpp
gfx/layers/apz/src/FocusState.cpp
gfx/layers/apz/src/HitTestingTreeNode.cpp
gfx/layers/apz/test/gtest/APZCBasicTester.h
gfx/layers/apz/test/gtest/APZCTreeManagerTester.h
gfx/layers/apz/util/APZThreadUtils.cpp
gfx/layers/apz/util/APZThreadUtils.h
--- a/gfx/layers/apz/public/APZSampler.h
+++ b/gfx/layers/apz/public/APZSampler.h
@@ -99,16 +99,35 @@ public:
   ParentLayerPoint GetCurrentAsyncScrollOffset(const LayerMetricsWrapper& aLayer);
   AsyncTransform GetCurrentAsyncTransform(const LayerMetricsWrapper& aLayer);
   AsyncTransformComponentMatrix GetOverscrollTransform(const LayerMetricsWrapper& aLayer);
   AsyncTransformComponentMatrix GetCurrentAsyncTransformWithOverscroll(const LayerMetricsWrapper& aLayer);
 
   void MarkAsyncTransformAppliedToContent(const LayerMetricsWrapper& aLayer);
   bool HasUnusedAsyncTransform(const LayerMetricsWrapper& aLayer);
 
+  /**
+   * This can be used to assert that the current thread is the
+   * sampler thread (which samples the async transform).
+   * This does nothing if thread assertions are disabled.
+   */
+  void AssertOnSamplerThread();
+
+  /**
+   * Runs the given task on the APZ "sampler thread" for this APZSampler. If
+   * this function is called from the sampler thread itself then the task is
+   * run immediately without getting queued.
+   */
+  void RunOnSamplerThread(already_AddRefed<Runnable> aTask);
+
+  /**
+   * Returns true if currently on the APZSampler's "sampler thread".
+   */
+  bool IsSamplerThread();
+
 protected:
   virtual ~APZSampler();
 
 private:
   RefPtr<APZCTreeManager> mApz;
 };
 
 } // namespace layers
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -256,17 +256,17 @@ APZCTreeManager::SetSampler(APZSampler* 
   MOZ_ASSERT(!mSampler);
   mSampler = aSampler;
 }
 
 void
 APZCTreeManager::NotifyLayerTreeAdopted(uint64_t aLayersId,
                                         const RefPtr<APZCTreeManager>& aOldApzcTreeManager)
 {
-  APZThreadUtils::AssertOnSamplerThread();
+  AssertOnSamplerThread();
 
   if (aOldApzcTreeManager) {
     aOldApzcTreeManager->mFocusState.RemoveFocusTarget(aLayersId);
     // While we could move the focus target information from the old APZC tree
     // manager into this one, it's safer to not do that, as we'll probably have
     // that information repopulated soon anyway (on the next layers update).
   }
 
@@ -283,17 +283,17 @@ APZCTreeManager::NotifyLayerTreeAdopted(
     MutexAutoLock lock(mTestDataLock);
     mTestData[aLayersId] = Move(adoptedData);
   }
 }
 
 void
 APZCTreeManager::NotifyLayerTreeRemoved(uint64_t aLayersId)
 {
-  APZThreadUtils::AssertOnSamplerThread();
+  AssertOnSamplerThread();
 
   mFocusState.RemoveFocusTarget(aLayersId);
 
   { // scope lock
     MutexAutoLock lock(mTestDataLock);
     mTestData.erase(aLayersId);
   }
 }
@@ -478,17 +478,17 @@ APZCTreeManager::UpdateHitTestingTreeImp
 #endif
 }
 
 void
 APZCTreeManager::UpdateFocusState(uint64_t aRootLayerTreeId,
                                   uint64_t aOriginatingLayersId,
                                   const FocusTarget& aFocusTarget)
 {
-  APZThreadUtils::AssertOnSamplerThread();
+  AssertOnSamplerThread();
 
   if (!gfxPrefs::APZKeyboardEnabled()) {
     return;
   }
 
   mFocusState.Update(aRootLayerTreeId,
                      aOriginatingLayersId,
                      aFocusTarget);
@@ -496,43 +496,43 @@ APZCTreeManager::UpdateFocusState(uint64
 
 void
 APZCTreeManager::UpdateHitTestingTree(uint64_t aRootLayerTreeId,
                                       Layer* aRoot,
                                       bool aIsFirstPaint,
                                       uint64_t aOriginatingLayersId,
                                       uint32_t aPaintSequenceNumber)
 {
-  APZThreadUtils::AssertOnSamplerThread();
+  AssertOnSamplerThread();
 
   LayerMetricsWrapper root(aRoot);
   UpdateHitTestingTreeImpl(aRootLayerTreeId, root, aIsFirstPaint,
                            aOriginatingLayersId, aPaintSequenceNumber);
 }
 
 void
 APZCTreeManager::UpdateHitTestingTree(uint64_t aRootLayerTreeId,
                                       const WebRenderScrollData& aScrollData,
                                       bool aIsFirstPaint,
                                       uint64_t aOriginatingLayersId,
                                       uint32_t aPaintSequenceNumber)
 {
-  APZThreadUtils::AssertOnSamplerThread();
+  AssertOnSamplerThread();
 
   WebRenderScrollDataWrapper wrapper(&aScrollData);
   UpdateHitTestingTreeImpl(aRootLayerTreeId, wrapper, aIsFirstPaint,
                            aOriginatingLayersId, aPaintSequenceNumber);
 }
 
 bool
 APZCTreeManager::PushStateToWR(wr::TransactionBuilder& aTxn,
                                const TimeStamp& aSampleTime,
                                nsTArray<wr::WrTransformProperty>& aTransformArray)
 {
-  APZThreadUtils::AssertOnSamplerThread();
+  AssertOnSamplerThread();
 
   RecursiveMutexAutoLock lock(mTreeLock);
 
   // During the first pass through the tree, we build a cache of guid->HTTN so
   // that we can find the relevant APZC instances quickly in subsequent passes,
   // such as the one below to generate scrollbar transforms. Without this, perf
   // could end up being O(n^2) instead of O(n log n) because we'd have to search
   // the tree to find the corresponding APZC every time we hit a thumb node.
@@ -1953,33 +1953,34 @@ APZCTreeManager::SetTargetAPZC(uint64_t 
   RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aTarget);
   mInputQueue->SetConfirmedTargetApzc(aInputBlockId, apzc);
 }
 
 void
 APZCTreeManager::UpdateZoomConstraints(const ScrollableLayerGuid& aGuid,
                                        const Maybe<ZoomConstraints>& aConstraints)
 {
-  if (!APZThreadUtils::IsSamplerThread()) {
+  MOZ_ASSERT(mSampler);
+  if (!mSampler->IsSamplerThread()) {
     // This can happen if we're in the UI process and got a call directly from
     // nsBaseWidget (as opposed to over PAPZCTreeManager). We want this function
     // to run on the sampler thread, so bounce it over.
     MOZ_ASSERT(XRE_IsParentProcess());
 
-    APZThreadUtils::RunOnSamplerThread(
+    mSampler->RunOnSamplerThread(
         NewRunnableMethod<ScrollableLayerGuid, Maybe<ZoomConstraints>>(
             "APZCTreeManager::UpdateZoomConstraints",
             this,
             &APZCTreeManager::UpdateZoomConstraints,
             aGuid,
             aConstraints));
     return;
   }
 
-  APZThreadUtils::AssertOnSamplerThread();
+  AssertOnSamplerThread();
 
   RecursiveMutexAutoLock lock(mTreeLock);
   RefPtr<HitTestingTreeNode> node = GetTargetNode(aGuid, nullptr);
   MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC
 
   // Propagate the zoom constraints down to the subtree, stopping at APZCs
   // which have their own zoom constraints or are in a different layers id.
   if (aConstraints) {
@@ -2064,17 +2065,17 @@ APZCTreeManager::AdjustScrollForSurfaceS
   if (apzc) {
     apzc->AdjustScrollForSurfaceShift(aShift);
   }
 }
 
 void
 APZCTreeManager::ClearTree()
 {
-  APZThreadUtils::AssertOnSamplerThread();
+  AssertOnSamplerThread();
 
 #if defined(MOZ_WIDGET_ANDROID)
   mToolbarAnimator->ClearTreeManager();
 #endif
 
   // Ensure that no references to APZCs are alive in any lingering input
   // blocks. This breaks cycles from InputBlockState::mTargetApzc back to
   // the InputQueue.
@@ -3020,17 +3021,17 @@ APZCTreeManager::GetContentController(ui
     });
   return controller.forget();
 }
 
 bool
 APZCTreeManager::GetAPZTestData(uint64_t aLayersId,
                                 APZTestData* aOutData)
 {
-  APZThreadUtils::AssertOnSamplerThread();
+  AssertOnSamplerThread();
   MutexAutoLock lock(mTestDataLock);
   auto it = mTestData.find(aLayersId);
   if (it == mTestData.end()) {
     return false;
   }
   *aOutData = *(it->second);
   return true;
 }
@@ -3193,16 +3194,23 @@ APZCTreeManager::ComputeTransformForScro
     }
   }
   transform = transform * compensation;
 
   return transform;
 }
 
 void
+APZCTreeManager::AssertOnSamplerThread()
+{
+  MOZ_ASSERT(mSampler);
+  mSampler->AssertOnSamplerThread();
+}
+
+void
 APZCTreeManager::SetDPI(float aDpiValue)
 {
   APZThreadUtils::AssertOnControllerThread();
   mDPI = aDpiValue;
 }
 
 float
 APZCTreeManager::GetDPI() const
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -520,16 +520,19 @@ public:
       const LayerToParentLayerMatrix4x4& aCurrentTransform,
       const gfx::Matrix4x4& aScrollableContentTransform,
       AsyncPanZoomController* aApzc,
       const FrameMetrics& aMetrics,
       const ScrollThumbData& aThumbData,
       bool aScrollbarIsDescendant,
       AsyncTransformComponentMatrix* aOutClipTransform);
 
+  // Assert that the current thread is the sampler thread for this APZCTM.
+  void AssertOnSamplerThread();
+
 protected:
   // Protected destructor, to discourage deletion outside of Release():
   virtual ~APZCTreeManager();
 
   // Protected hooks for gtests subclass
   virtual AsyncPanZoomController* NewAPZCInstance(uint64_t aLayersId,
                                                   GeckoContentController* aController);
 public:
--- a/gfx/layers/apz/src/APZSampler.cpp
+++ b/gfx/layers/apz/src/APZSampler.cpp
@@ -3,16 +3,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/layers/APZSampler.h"
 
 #include "APZCTreeManager.h"
 #include "AsyncPanZoomController.h"
+#include "mozilla/layers/APZThreadUtils.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/LayerMetricsWrapper.h"
 #include "TreeTraversal.h"
 
 namespace mozilla {
 namespace layers {
 
 APZSampler::APZSampler(const RefPtr<APZCTreeManager>& aApz)
@@ -207,10 +208,43 @@ bool
 APZSampler::HasUnusedAsyncTransform(const LayerMetricsWrapper& aLayer)
 {
   AsyncPanZoomController* apzc = aLayer.GetApzc();
   return apzc
       && !apzc->GetAsyncTransformAppliedToContent()
       && !AsyncTransformComponentMatrix(apzc->GetCurrentAsyncTransform(AsyncPanZoomController::eForCompositing)).IsIdentity();
 }
 
+void
+APZSampler::AssertOnSamplerThread()
+{
+  if (APZThreadUtils::GetThreadAssertionsEnabled()) {
+    MOZ_ASSERT(IsSamplerThread());
+  }
+}
+
+void
+APZSampler::RunOnSamplerThread(already_AddRefed<Runnable> aTask)
+{
+  RefPtr<Runnable> task = aTask;
+
+  MessageLoop* loop = CompositorThreadHolder::Loop();
+  if (!loop) {
+    // Could happen during startup
+    NS_WARNING("Dropping task posted to sampler thread");
+    return;
+  }
+
+  if (IsSamplerThread()) {
+    task->Run();
+  } else {
+    loop->PostTask(task.forget());
+  }
+}
+
+bool
+APZSampler::IsSamplerThread()
+{
+  return CompositorThreadHolder::IsInCompositorThread();
+}
+
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp
+++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp
@@ -839,17 +839,19 @@ AsyncPanZoomController::GetGestureEventL
 const RefPtr<InputQueue>&
 AsyncPanZoomController::GetInputQueue() const {
   return mInputQueue;
 }
 
 void
 AsyncPanZoomController::Destroy()
 {
-  APZThreadUtils::AssertOnSamplerThread();
+  if (APZCTreeManager* treeManagerLocal = GetApzcTreeManager()) {
+    treeManagerLocal->AssertOnSamplerThread();
+  }
 
   CancelAnimation(CancelAnimationFlags::ScrollSnap);
 
   { // scope the lock
     MonitorAutoLock lock(mRefPtrMonitor);
     mGeckoContentController = nullptr;
     mGestureEventListener = nullptr;
   }
@@ -3472,17 +3474,19 @@ AsyncPanZoomController::RequestContentRe
   controller->RequestContentRepaint(aFrameMetrics);
   mExpectedGeckoMetrics = aFrameMetrics;
   mLastPaintRequestMetrics = aFrameMetrics;
 }
 
 bool AsyncPanZoomController::UpdateAnimation(const TimeStamp& aSampleTime,
                                              nsTArray<RefPtr<Runnable>>* aOutDeferredTasks)
 {
-  APZThreadUtils::AssertOnSamplerThread();
+  if (APZCTreeManager* treeManagerLocal = GetApzcTreeManager()) {
+    treeManagerLocal->AssertOnSamplerThread();
+  }
 
   // This function may get called multiple with the same sample time, because
   // there may be multiple layers with this APZC, and each layer invokes this
   // function during composition. However we only want to do one animation step
   // per composition so we need to deduplicate these calls first.
   if (mLastSampleTime == aSampleTime) {
     return false;
   }
@@ -3531,17 +3535,19 @@ AsyncPanZoomController::GetOverscrollTra
   // The overscroll effect is a simple translation by the overscroll offset.
   ParentLayerPoint overscrollOffset(-mX.GetOverscroll(), -mY.GetOverscroll());
   return AsyncTransformComponentMatrix()
       .PostTranslate(overscrollOffset.x, overscrollOffset.y, 0);
 }
 
 bool AsyncPanZoomController::AdvanceAnimations(const TimeStamp& aSampleTime)
 {
-  APZThreadUtils::AssertOnSamplerThread();
+  if (APZCTreeManager* treeManagerLocal = GetApzcTreeManager()) {
+    treeManagerLocal->AssertOnSamplerThread();
+  }
 
   // Don't send any state-change notifications until the end of the function,
   // because we may go through some intermediate states while we finish
   // animations and start new ones.
   StateChangeNotificationBlocker blocker(this);
 
   // The eventual return value of this function. The compositor needs to know
   // whether or not to advance by a frame as soon as it can. For example, if a
@@ -3810,17 +3816,19 @@ bool AsyncPanZoomController::IsCurrently
     this, Stringify(painted).c_str(), Stringify(visible).c_str());
   return true;
 }
 
 void AsyncPanZoomController::NotifyLayersUpdated(const ScrollMetadata& aScrollMetadata,
                                                  bool aIsFirstPaint,
                                                  bool aThisLayerTreeUpdated)
 {
-  APZThreadUtils::AssertOnSamplerThread();
+  if (APZCTreeManager* treeManagerLocal = GetApzcTreeManager()) {
+    treeManagerLocal->AssertOnSamplerThread();
+  }
 
   RecursiveMutexAutoLock lock(mRecursiveMutex);
   bool isDefault = mScrollMetadata.IsDefault();
 
   const FrameMetrics& aLayerMetrics = aScrollMetadata.GetMetrics();
 
   if ((aScrollMetadata == mLastContentPaintMetadata) && !isDefault) {
     // No new information here, skip it.
@@ -4428,17 +4436,19 @@ void AsyncPanZoomController::UpdateShare
     mSharedLock->Lock();
     *frame = mFrameMetrics;
     mSharedLock->Unlock();
   }
 }
 
 void AsyncPanZoomController::ShareCompositorFrameMetrics()
 {
-  APZThreadUtils::AssertOnSamplerThread();
+  if (APZCTreeManager* treeManagerLocal = GetApzcTreeManager()) {
+    treeManagerLocal->AssertOnSamplerThread();
+  }
 
   // Only create the shared memory buffer if it hasn't already been created,
   // we are using progressive tile painting, and we have a
   // controller to pass the shared memory back to the content process/thread.
   if (!mSharedFrameMetricsBuffer && mMetricsSharingController && gfxPrefs::ProgressivePaint()) {
 
     // Create shared memory and initialize it with the current FrameMetrics value
     mSharedFrameMetricsBuffer = new ipc::SharedMemoryBasic;
--- a/gfx/layers/apz/src/FocusState.cpp
+++ b/gfx/layers/apz/src/FocusState.cpp
@@ -65,17 +65,19 @@ FocusState::ReceiveFocusChangingEvent()
          mLastAPZProcessedEvent);
 }
 
 void
 FocusState::Update(uint64_t aRootLayerTreeId,
                    uint64_t aOriginatingLayersId,
                    const FocusTarget& aState)
 {
-  APZThreadUtils::AssertOnSamplerThread();
+  // This runs on the sampler thread, it's not worth passing around extra raw
+  // pointers just to assert it.
+
   MutexAutoLock lock(mMutex);
 
   FS_LOG("Update with rlt=%" PRIu64 ", olt=%" PRIu64 ", ft=(%s, %" PRIu64 ")\n",
          aRootLayerTreeId,
          aOriginatingLayersId,
          aState.Type(),
          aState.mSequenceNumber);
   mReceivedUpdate = true;
@@ -177,17 +179,18 @@ FocusState::Update(uint64_t aRootLayerTr
       return;
     }
   }
 }
 
 void
 FocusState::RemoveFocusTarget(uint64_t aLayersId)
 {
-  APZThreadUtils::AssertOnSamplerThread();
+  // This runs on the sampler thread, it's not worth passing around extra raw
+  // pointers just to assert it.
   MutexAutoLock lock(mMutex);
 
   mFocusTree.erase(aLayersId);
 }
 
 Maybe<ScrollableLayerGuid>
 FocusState::GetHorizontalTarget() const
 {
--- a/gfx/layers/apz/src/HitTestingTreeNode.cpp
+++ b/gfx/layers/apz/src/HitTestingTreeNode.cpp
@@ -5,17 +5,16 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "HitTestingTreeNode.h"
 
 #include "AsyncPanZoomController.h"                     // for AsyncPanZoomController
 #include "gfxPrefs.h"
 #include "LayersLogging.h"                              // for Stringify
 #include "mozilla/gfx/Point.h"                          // for Point4D
-#include "mozilla/layers/APZThreadUtils.h"              // for AssertOnSamplerThread
 #include "mozilla/layers/APZUtils.h"                    // for CompleteAsyncTransform
 #include "mozilla/layers/AsyncCompositionManager.h"     // for ViewTransform::operator Matrix4x4()
 #include "mozilla/layers/AsyncDragMetrics.h"            // for AsyncDragMetrics
 #include "nsPrintfCString.h"                            // for nsPrintfCString
 #include "UnitTransforms.h"                             // for ViewAs
 
 namespace mozilla {
 namespace layers {
@@ -54,17 +53,18 @@ HitTestingTreeNode::RecycleWith(AsyncPan
 
 HitTestingTreeNode::~HitTestingTreeNode()
 {
 }
 
 void
 HitTestingTreeNode::Destroy()
 {
-  APZThreadUtils::AssertOnSamplerThread();
+  // This runs on the sampler thread, it's not worth passing around extra raw
+  // pointers just to assert it.
 
   mPrevSibling = nullptr;
   mLastChild = nullptr;
   mParent = nullptr;
 
   if (mApzc) {
     if (mIsPrimaryApzcHolder) {
       mApzc->Destroy();
--- a/gfx/layers/apz/test/gtest/APZCBasicTester.h
+++ b/gfx/layers/apz/test/gtest/APZCBasicTester.h
@@ -8,32 +8,34 @@
 #define mozilla_layers_APZCBasicTester_h
 
 /**
  * Defines a test fixture used for testing a single APZC.
  */
 
 #include "APZTestCommon.h"
 #include "gfxPrefs.h"
+#include "mozilla/layers/APZSampler.h"
 
 class APZCBasicTester : public APZCTesterBase {
 public:
   explicit APZCBasicTester(AsyncPanZoomController::GestureBehavior aGestureBehavior = AsyncPanZoomController::DEFAULT_GESTURES)
     : mGestureBehavior(aGestureBehavior)
   {
   }
 
 protected:
   virtual void SetUp()
   {
     gfxPrefs::GetSingleton();
     APZThreadUtils::SetThreadAssertionsEnabled(false);
     APZThreadUtils::SetControllerThread(MessageLoop::current());
 
     tm = new TestAPZCTreeManager(mcc);
+    sampler = new APZSampler(tm);
     apzc = new TestAsyncPanZoomController(0, mcc, tm, mGestureBehavior);
     apzc->SetFrameMetrics(TestFrameMetrics());
     apzc->GetScrollMetadata().SetIsLayersIdRoot(true);
   }
 
   /**
    * Get the APZC's scroll range in CSS pixels.
    */
@@ -110,12 +112,13 @@ protected:
     EXPECT_TRUE(recoveredFromOverscroll);
     apzc->AssertStateIsReset();
   }
 
   void TestOverscroll();
 
   AsyncPanZoomController::GestureBehavior mGestureBehavior;
   RefPtr<TestAPZCTreeManager> tm;
+  RefPtr<APZSampler> sampler;
   RefPtr<TestAsyncPanZoomController> apzc;
 };
 
 #endif // mozilla_layers_APZCBasicTester_h
--- a/gfx/layers/apz/test/gtest/APZCTreeManagerTester.h
+++ b/gfx/layers/apz/test/gtest/APZCTreeManagerTester.h
@@ -10,26 +10,28 @@
 /**
  * Defines a test fixture used for testing multiple APZCs interacting in
  * an APZCTreeManager.
  */
 
 #include "APZTestCommon.h"
 #include "gfxPlatform.h"
 #include "gfxPrefs.h"
+#include "mozilla/layers/APZSampler.h"
 
 class APZCTreeManagerTester : public APZCTesterBase {
 protected:
   virtual void SetUp() {
     gfxPrefs::GetSingleton();
     gfxPlatform::GetPlatform();
     APZThreadUtils::SetThreadAssertionsEnabled(false);
     APZThreadUtils::SetControllerThread(MessageLoop::current());
 
     manager = new TestAPZCTreeManager(mcc);
+    sampler = new APZSampler(manager);
   }
 
   virtual void TearDown() {
     while (mcc->RunThroughDelayedTasks());
     manager->ClearTree();
     manager->ClearContentController();
   }
 
@@ -49,16 +51,17 @@ protected:
     }
   }
 
   nsTArray<RefPtr<Layer> > layers;
   RefPtr<LayerManager> lm;
   RefPtr<Layer> root;
 
   RefPtr<TestAPZCTreeManager> manager;
+  RefPtr<APZSampler> sampler;
 
 protected:
   static ScrollMetadata BuildScrollMetadata(FrameMetrics::ViewID aScrollId,
                                             const CSSRect& aScrollableRect,
                                             const ParentLayerRect& aCompositionBounds)
   {
     ScrollMetadata metadata;
     FrameMetrics& metrics = metadata.GetMetrics();
--- a/gfx/layers/apz/util/APZThreadUtils.cpp
+++ b/gfx/layers/apz/util/APZThreadUtils.cpp
@@ -1,18 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/layers/APZThreadUtils.h"
 
-#include "mozilla/layers/CompositorThread.h"
-
 namespace mozilla {
 namespace layers {
 
 static bool sThreadAssertionsEnabled = true;
 static MessageLoop* sControllerThread;
 
 /*static*/ void
 APZThreadUtils::SetThreadAssertionsEnabled(bool aEnabled) {
@@ -61,45 +59,12 @@ APZThreadUtils::RunOnControllerThread(al
 }
 
 /*static*/ bool
 APZThreadUtils::IsControllerThread()
 {
   return sControllerThread == MessageLoop::current();
 }
 
-/*static*/ void
-APZThreadUtils::AssertOnSamplerThread()
-{
-  if (GetThreadAssertionsEnabled()) {
-    MOZ_ASSERT(IsSamplerThread());
-  }
-}
-
-/*static*/ void
-APZThreadUtils::RunOnSamplerThread(already_AddRefed<Runnable> aTask)
-{
-  RefPtr<Runnable> task = aTask;
-
-  MessageLoop* loop = CompositorThreadHolder::Loop();
-  if (!loop) {
-    // Could happen during startup
-    NS_WARNING("Dropping task posted to sampler thread");
-    return;
-  }
-
-  if (IsSamplerThread()) {
-    task->Run();
-  } else {
-    loop->PostTask(task.forget());
-  }
-}
-
-/*static*/ bool
-APZThreadUtils::IsSamplerThread()
-{
-  return CompositorThreadHolder::IsInCompositorThread();
-}
-
 NS_IMPL_ISUPPORTS(GenericNamedTimerCallbackBase, nsITimerCallback, nsINamed)
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/apz/util/APZThreadUtils.h
+++ b/gfx/layers/apz/util/APZThreadUtils.h
@@ -46,35 +46,16 @@ public:
    * run immediately without getting queued.
    */
   static void RunOnControllerThread(already_AddRefed<Runnable> aTask);
 
   /**
    * Returns true if currently on APZ "controller thread".
    */
   static bool IsControllerThread();
-
-  /**
-   * This can be used to assert that the current thread is the
-   * sampler thread (which samples the async transform).
-   * This does nothing if thread assertions are disabled.
-   */
-  static void AssertOnSamplerThread();
-
-  /**
-   * Runs the given task on the APZ "sampler thread" for this platform. If
-   * this function is called from the sampler thread itself then the task is
-   * run immediately without getting queued.
-   */
-  static void RunOnSamplerThread(already_AddRefed<Runnable> aTask);
-
-  /**
-   * Returns true if currently on the APZ "sampler thread".
-   */
-  static bool IsSamplerThread();
 };
 
 // A base class for GenericNamedTimerCallback<Function>.
 // This is necessary because NS_IMPL_ISUPPORTS doesn't work for a class
 // template.
 class GenericNamedTimerCallbackBase : public nsITimerCallback,
                                       public nsINamed
 {