Bug 1441916 - Introduce an APZSampler interface for APZCTreeManager. r=botond
authorKartikaya Gupta <kgupta@mozilla.com>
Thu, 01 Mar 2018 23:00:41 -0500
changeset 406304 da64726bf399abe8936889dc2e2c04acc8cec782
parent 406303 5bbb3e69e745abf1b9b2962a9134dbb07de105cb
child 406305 a170c4ecc80df942507efeb9bd6ecacbec0126d1
push id33553
push usershindli@mozilla.com
push dateFri, 02 Mar 2018 23:05:47 +0000
treeherdermozilla-central@9d34236d48ff [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond
bugs1441916
milestone60.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1441916 - Introduce an APZSampler interface for APZCTreeManager. r=botond This interface should be used for accessing any sampler-thread functions on APZCTreeManager. Eventually the interface will handle thread delegation so that if it is called from a thread that is not the sampler thread it will redirect the calls appropriately. For now it just allows to logically group the public APZCTreeManager methods that are to be run on the sampler thread. MozReview-Commit-ID: GArPvjfuYYr
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/ipc/CompositorBridgeParent.cpp
gfx/layers/ipc/CompositorBridgeParent.h
gfx/layers/moz.build
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/public/APZSampler.h
@@ -0,0 +1,63 @@
+/* -*- 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/. */
+
+#ifndef mozilla_layers_APZSampler_h
+#define mozilla_layers_APZSampler_h
+
+#include "mozilla/layers/APZTestData.h"
+#include "mozilla/Maybe.h"
+
+namespace mozilla {
+namespace layers {
+
+class APZCTreeManager;
+class FocusTarget;
+class Layer;
+class WebRenderScrollData;
+
+/**
+ * This interface is used to interact with the APZ code from the compositor
+ * thread. It internally redispatches the functions to the sampler thread
+ * in the case where the two threads are not the same.
+ */
+class APZSampler {
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(APZSampler)
+
+public:
+  explicit APZSampler(const RefPtr<APZCTreeManager>& aApz);
+
+  void ClearTree();
+  void UpdateFocusState(uint64_t aRootLayerTreeId,
+                        uint64_t aOriginatingLayersId,
+                        const FocusTarget& aFocusTarget);
+  void UpdateHitTestingTree(uint64_t aRootLayerTreeId,
+                            Layer* aRoot,
+                            bool aIsFirstPaint,
+                            uint64_t aOriginatingLayersId,
+                            uint32_t aPaintSequenceNumber);
+  void UpdateHitTestingTree(uint64_t aRootLayerTreeId,
+                            const WebRenderScrollData& aScrollData,
+                            bool aIsFirstPaint,
+                            uint64_t aOriginatingLayersId,
+                            uint32_t aPaintSequenceNumber);
+
+  void NotifyLayerTreeAdopted(uint64_t aLayersId,
+                              const RefPtr<APZSampler>& aOldSampler);
+  void NotifyLayerTreeRemoved(uint64_t aLayersId);
+
+  bool GetAPZTestData(uint64_t aLayersId, APZTestData* aOutData);
+
+protected:
+  virtual ~APZSampler();
+
+private:
+  RefPtr<APZCTreeManager> mApz;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_layers_APZSampler_h
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -328,18 +328,16 @@ APZCTreeManager::SetAllowedTouchBehavior
 
 template<class ScrollNode> void // ScrollNode is a LayerMetricsWrapper or a WebRenderScrollDataWrapper
 APZCTreeManager::UpdateHitTestingTreeImpl(uint64_t aRootLayerTreeId,
                                           const ScrollNode& aRoot,
                                           bool aIsFirstPaint,
                                           uint64_t aOriginatingLayersId,
                                           uint32_t aPaintSequenceNumber)
 {
-  APZThreadUtils::AssertOnSamplerThread();
-
   RecursiveMutexAutoLock lock(mTreeLock);
 
   // For testing purposes, we log some data to the APZTestData associated with
   // the layers id that originated this update.
   APZTestData* testData = nullptr;
   if (gfxPrefs::APZTestLoggingEnabled()) {
     MutexAutoLock lock(mTestDataLock);
     UniquePtr<APZTestData> ptr = MakeUnique<APZTestData>();
@@ -485,44 +483,50 @@ APZCTreeManager::UpdateHitTestingTreeImp
 #endif
 }
 
 void
 APZCTreeManager::UpdateFocusState(uint64_t aRootLayerTreeId,
                                   uint64_t aOriginatingLayersId,
                                   const FocusTarget& aFocusTarget)
 {
+  APZThreadUtils::AssertOnSamplerThread();
+
   if (!gfxPrefs::APZKeyboardEnabled()) {
     return;
   }
 
   mFocusState.Update(aRootLayerTreeId,
                      aOriginatingLayersId,
                      aFocusTarget);
 }
 
 void
 APZCTreeManager::UpdateHitTestingTree(uint64_t aRootLayerTreeId,
                                       Layer* aRoot,
                                       bool aIsFirstPaint,
                                       uint64_t aOriginatingLayersId,
                                       uint32_t aPaintSequenceNumber)
 {
+  APZThreadUtils::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();
+
   WebRenderScrollDataWrapper wrapper(&aScrollData);
   UpdateHitTestingTreeImpl(aRootLayerTreeId, wrapper, aIsFirstPaint,
                            aOriginatingLayersId, aPaintSequenceNumber);
 }
 
 bool
 APZCTreeManager::PushStateToWR(wr::TransactionBuilder& aTxn,
                                const TimeStamp& aSampleTime,
@@ -2030,16 +2034,18 @@ APZCTreeManager::AdjustScrollForSurfaceS
   if (apzc) {
     apzc->AdjustScrollForSurfaceShift(aShift);
   }
 }
 
 void
 APZCTreeManager::ClearTree()
 {
+  APZThreadUtils::AssertOnSamplerThread();
+
   // Ensure that no references to APZCs are alive in any lingering input
   // blocks. This breaks cycles from InputBlockState::mTargetApzc back to
   // the InputQueue.
   APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
     "layers::InputQueue::Clear", mInputQueue, &InputQueue::Clear));
 
   RecursiveMutexAutoLock lock(mTreeLock);
 
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -138,16 +138,17 @@ public:
    * also getting destroyed.
    * This function must be called on the sampler thread.
    */
   void NotifyLayerTreeRemoved(uint64_t aLayersId);
 
   /**
    * Rebuild the focus state based on the focus target from the layer tree update
    * that just occurred.
+   * This must be called on the sampler thread.
    *
    * @param aRootLayerTreeId The layer tree ID of the root layer corresponding
    *                         to this APZCTreeManager
    * @param aOriginatingLayersId The layer tree ID of the layer corresponding to
    *                             this layer tree update.
    */
   void UpdateFocusState(uint64_t aRootLayerTreeId,
                         uint64_t aOriginatingLayersId,
@@ -331,16 +332,17 @@ public:
   void AdjustScrollForSurfaceShift(const ScreenPoint& aShift);
 
   /**
    * Calls Destroy() on all APZC instances attached to the tree, and resets the
    * tree back to empty. This function must be called exactly once during the
    * lifetime of this APZCTreeManager, when this APZCTreeManager is no longer
    * needed. Failing to call this function may prevent objects from being freed
    * properly.
+   * This must be called on the sampler thread.
    */
   void ClearTree();
 
   /**
    * Tests if a screen point intersect an apz in the tree.
    */
   bool HitTestAPZC(const ScreenIntPoint& aPoint);
 
new file mode 100644
--- /dev/null
+++ b/gfx/layers/apz/src/APZSampler.cpp
@@ -0,0 +1,89 @@
+/* -*- 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/APZSampler.h"
+
+#include "mozilla/layers/APZCTreeManager.h"
+#include "mozilla/layers/CompositorThread.h"
+
+namespace mozilla {
+namespace layers {
+
+APZSampler::APZSampler(const RefPtr<APZCTreeManager>& aApz)
+  : mApz(aApz)
+{
+}
+
+APZSampler::~APZSampler()
+{
+}
+
+void
+APZSampler::ClearTree()
+{
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+  mApz->ClearTree();
+}
+
+void
+APZSampler::UpdateFocusState(uint64_t aRootLayerTreeId,
+                             uint64_t aOriginatingLayersId,
+                             const FocusTarget& aFocusTarget)
+{
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+  mApz->UpdateFocusState(aRootLayerTreeId, aOriginatingLayersId, aFocusTarget);
+}
+
+void
+APZSampler::UpdateHitTestingTree(uint64_t aRootLayerTreeId,
+                                 Layer* aRoot,
+                                 bool aIsFirstPaint,
+                                 uint64_t aOriginatingLayersId,
+                                 uint32_t aPaintSequenceNumber)
+{
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+  mApz->UpdateHitTestingTree(aRootLayerTreeId, aRoot, aIsFirstPaint,
+      aOriginatingLayersId, aPaintSequenceNumber);
+}
+
+void
+APZSampler::UpdateHitTestingTree(uint64_t aRootLayerTreeId,
+                                 const WebRenderScrollData& aScrollData,
+                                 bool aIsFirstPaint,
+                                 uint64_t aOriginatingLayersId,
+                                 uint32_t aPaintSequenceNumber)
+{
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+  mApz->UpdateHitTestingTree(aRootLayerTreeId, aScrollData, aIsFirstPaint,
+      aOriginatingLayersId, aPaintSequenceNumber);
+}
+
+void
+APZSampler::NotifyLayerTreeAdopted(uint64_t aLayersId,
+                                   const RefPtr<APZSampler>& aOldSampler)
+{
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+  MOZ_ASSERT(aOldSampler);
+  mApz->NotifyLayerTreeAdopted(aLayersId, aOldSampler->mApz);
+}
+
+void
+APZSampler::NotifyLayerTreeRemoved(uint64_t aLayersId)
+{
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+  mApz->NotifyLayerTreeRemoved(aLayersId);
+}
+
+bool
+APZSampler::GetAPZTestData(uint64_t aLayersId,
+                           APZTestData* aOutData)
+{
+  MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+  return mApz->GetAPZTestData(aLayersId, aOutData);
+}
+
+} // namespace layers
+} // namespace mozilla
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -34,17 +34,18 @@
 #include "mozilla/gfx/gfxVars.h"        // for gfxVars
 #include "VRManager.h"                  // for VRManager
 #include "mozilla/ipc/Transport.h"      // for Transport
 #include "mozilla/gfx/gfxVars.h"
 #include "mozilla/gfx/GPUParent.h"
 #include "mozilla/layers/AnimationHelper.h" // for CompositorAnimationStorage
 #include "mozilla/layers/APZCTreeManager.h"  // for APZCTreeManager
 #include "mozilla/layers/APZCTreeManagerParent.h"  // for APZCTreeManagerParent
-#include "mozilla/layers/APZThreadUtils.h"  // for APZCTreeManager
+#include "mozilla/layers/APZSampler.h"  // for APZSampler
+#include "mozilla/layers/APZThreadUtils.h"  // for APZThreadUtils
 #include "mozilla/layers/AsyncCompositionManager.h"
 #include "mozilla/layers/BasicCompositor.h"  // for BasicCompositor
 #include "mozilla/layers/Compositor.h"  // for Compositor
 #include "mozilla/layers/CompositorManagerParent.h" // for CompositorManagerParent
 #include "mozilla/layers/CompositorOGL.h"  // for CompositorOGL
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/CompositorTypes.h"
 #include "mozilla/layers/CompositorVsyncScheduler.h"
@@ -351,16 +352,17 @@ CompositorBridgeParent::InitSameProcess(
 {
   MOZ_ASSERT(XRE_IsParentProcess());
   MOZ_ASSERT(NS_IsMainThread());
 
   mWidget = aWidget;
   mRootLayerTreeID = aLayerTreeId;
   if (mOptions.UseAPZ()) {
     mApzcTreeManager = new APZCTreeManager(mRootLayerTreeID);
+    mApzSampler = new APZSampler(mApzcTreeManager);
   }
 
   Initialize();
 }
 
 mozilla::ipc::IPCResult
 CompositorBridgeParent::RecvInitialize(const uint64_t& aRootLayerTreeId)
 {
@@ -651,18 +653,20 @@ CompositorBridgeParent::ActorDestroy(Act
   mCanSend = false;
 
   StopAndClearResources();
 
   RemoveCompositor(mCompositorBridgeID);
 
   mCompositionManager = nullptr;
 
-  if (mApzcTreeManager) {
-    mApzcTreeManager->ClearTree();
+  MOZ_ASSERT((mApzSampler != nullptr) == (mApzcTreeManager != nullptr));
+  if (mApzSampler) {
+    mApzSampler->ClearTree();
+    mApzSampler = nullptr;
     mApzcTreeManager = nullptr;
   }
 
   { // scope lock
     MonitorAutoLock lock(*sIndirectLayerTreesLock);
     sIndirectLayerTrees.erase(mRootLayerTreeID);
   }
 
@@ -876,21 +880,20 @@ CompositorBridgeParent::NotifyShadowTree
 #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
     // If plugins haven't been updated, stop waiting.
     if (!pluginsUpdatedFlag) {
       mWaitForPluginsUntil = TimeStamp();
       mHaveBlockedForPlugins = false;
     }
 #endif
 
-    if (mApzcTreeManager) {
-      mApzcTreeManager->UpdateFocusState(mRootLayerTreeID, aId,
-                                         aFocusTarget);
+    if (mApzSampler) {
+      mApzSampler->UpdateFocusState(mRootLayerTreeID, aId, aFocusTarget);
       if (aHitTestUpdate) {
-        mApzcTreeManager->UpdateHitTestingTree(mRootLayerTreeID,
+        mApzSampler->UpdateHitTestingTree(mRootLayerTreeID,
             mLayerManager->GetRoot(), aIsFirstPaint, aId, aPaintSequenceNumber);
       }
     }
 
     mLayerManager->NotifyShadowTreeTransaction();
   }
   if (aScheduleComposite) {
     ScheduleComposition();
@@ -1118,23 +1121,25 @@ CompositorBridgeParent::AllocPAPZCTreeMa
   // We should only ever get this if APZ is enabled in this compositor.
   MOZ_ASSERT(mOptions.UseAPZ());
 
   // The main process should pass in 0 because we assume mRootLayerTreeID
   MOZ_ASSERT(aLayersId == 0);
 
   // This message doubles as initialization
   MOZ_ASSERT(!mApzcTreeManager);
+
   mApzcTreeManager = new APZCTreeManager(mRootLayerTreeID);
+  mApzSampler = new APZSampler(mApzcTreeManager);
 
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
   CompositorBridgeParent::LayerTreeState& state = sIndirectLayerTrees[mRootLayerTreeID];
-  MOZ_ASSERT(state.mParent);
+  MOZ_ASSERT(state.mParent.get() == this);
   MOZ_ASSERT(!state.mApzcTreeManagerParent);
-  state.mApzcTreeManagerParent = new APZCTreeManagerParent(mRootLayerTreeID, state.mParent->GetAPZCTreeManager());
+  state.mApzcTreeManagerParent = new APZCTreeManagerParent(mRootLayerTreeID, mApzcTreeManager);
 
   return state.mApzcTreeManagerParent;
 }
 
 bool
 CompositorBridgeParent::DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent* aActor)
 {
   delete aActor;
@@ -1170,16 +1175,22 @@ CompositorBridgeParent::DeallocPAPZParen
 }
 
 RefPtr<APZCTreeManager>
 CompositorBridgeParent::GetAPZCTreeManager()
 {
   return mApzcTreeManager;
 }
 
+RefPtr<APZSampler>
+CompositorBridgeParent::GetAPZSampler()
+{
+  return mApzSampler;
+}
+
 CompositorBridgeParent*
 CompositorBridgeParent::GetCompositorBridgeParentFromLayersId(const uint64_t& aLayersId)
 {
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
   return sIndirectLayerTrees[aLayersId].mParent;
 }
 
 bool
@@ -1228,25 +1239,25 @@ CompositorBridgeParent::ShadowLayersUpda
   if (mLayerManager->GetCompositor()) {
     mLayerManager->GetCompositor()->SetScreenRotation(targetConfig.rotation());
   }
 
   mCompositionManager->Updated(aInfo.isFirstPaint(), targetConfig);
   Layer* root = aLayerTree->GetRoot();
   mLayerManager->SetRoot(root);
 
-  if (mApzcTreeManager && !aInfo.isRepeatTransaction()) {
-    mApzcTreeManager->UpdateFocusState(mRootLayerTreeID,
-                                       mRootLayerTreeID,
-                                       aInfo.focusTarget());
+  if (mApzSampler && !aInfo.isRepeatTransaction()) {
+    mApzSampler->UpdateFocusState(mRootLayerTreeID,
+                                  mRootLayerTreeID,
+                                  aInfo.focusTarget());
 
     if (aHitTestUpdate) {
       AutoResolveRefLayers resolve(mCompositionManager);
 
-      mApzcTreeManager->UpdateHitTestingTree(
+      mApzSampler->UpdateHitTestingTree(
         mRootLayerTreeID, root, aInfo.isFirstPaint(),
         mRootLayerTreeID, aInfo.paintSequenceNumber());
     }
   }
 
   // The transaction ID might get reset to 1 if the page gets reloaded, see
   // https://bugzilla.mozilla.org/show_bug.cgi?id=1145295#c41
   // Otherwise, it should be continually increasing.
@@ -1372,18 +1383,18 @@ CompositorBridgeParent::FlushApzRepaints
     [=]() { self->mApzcTreeManager->FlushApzRepaints(layersId); }));
 }
 
 void
 CompositorBridgeParent::GetAPZTestData(const uint64_t& aLayersId,
                                        APZTestData* aOutData)
 {
   uint64_t layersId = (aLayersId == 0 ? mRootLayerTreeID : aLayersId);
-  if (mApzcTreeManager) {
-    mApzcTreeManager->GetAPZTestData(layersId, aOutData);
+  if (mApzSampler) {
+    mApzSampler->GetAPZTestData(layersId, aOutData);
   }
 }
 
 void
 CompositorBridgeParent::SetConfirmedTargetAPZC(const uint64_t& aLayersId,
                                                const uint64_t& aInputBlockId,
                                                const nsTArray<ScrollableLayerGuid>& aTargets)
 {
@@ -1656,24 +1667,24 @@ CompositorBridgeParent::RecvMapAndNotify
   NotifyChildCreated(aChild);
   *aOptions = mOptions;
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 CompositorBridgeParent::RecvAdoptChild(const uint64_t& child)
 {
-  RefPtr<APZCTreeManager> oldApzcTreeManager;
+  RefPtr<APZSampler> oldApzSampler;
   APZCTreeManagerParent* parent;
   {
     MonitorAutoLock lock(*sIndirectLayerTreesLock);
     // We currently don't support adopting children from one compositor to
     // another if the two compositors don't have the same options.
     MOZ_ASSERT(sIndirectLayerTrees[child].mParent->mOptions == mOptions);
-    oldApzcTreeManager = sIndirectLayerTrees[child].mParent->mApzcTreeManager;
+    oldApzSampler = sIndirectLayerTrees[child].mParent->mApzSampler;
     NotifyChildCreated(child);
     if (sIndirectLayerTrees[child].mLayerTree) {
       sIndirectLayerTrees[child].mLayerTree->SetLayerManager(mLayerManager, GetAnimationStorage());
       // Trigger composition to handle a case that mLayerTree was not composited yet
       // by previous CompositorBridgeParent, since nsRefreshDriver might wait composition complete.
       ScheduleComposition();
     }
     if (mWrBridge && sIndirectLayerTrees[child].mWrBridge) {
@@ -1691,22 +1702,23 @@ CompositorBridgeParent::RecvAdoptChild(c
       }
     }
     parent = sIndirectLayerTrees[child].mApzcTreeManagerParent;
   }
 
   // We don't support moving a child from a APZ-enabled compositor to a
   // APZ-disabled compostior. The mOptions assertion above should already
   // ensure this, since APZ-ness is one of the things in mOptions.
-  MOZ_ASSERT((oldApzcTreeManager != nullptr) == (mApzcTreeManager != nullptr));
-  if (mApzcTreeManager) {
+  MOZ_ASSERT((oldApzSampler != nullptr) == (mApzSampler != nullptr));
+  if (mApzSampler) {
     if (parent) {
+      MOZ_ASSERT(mApzcTreeManager);
       parent->ChildAdopted(mApzcTreeManager);
     }
-    mApzcTreeManager->NotifyLayerTreeAdopted(child, oldApzcTreeManager);
+    mApzSampler->NotifyLayerTreeAdopted(child, oldApzSampler);
   }
   return IPC_OK();
 }
 
 PWebRenderBridgeParent*
 CompositorBridgeParent::AllocPWebRenderBridgeParent(const wr::PipelineId& aPipelineId,
                                                     const LayoutDeviceIntSize& aSize,
                                                     TextureFactoryIdentifier* aTextureFactoryIdentifier,
@@ -1789,18 +1801,18 @@ EraseLayerState(uint64_t aId)
 {
   MonitorAutoLock lock(*sIndirectLayerTreesLock);
 
   auto iter = sIndirectLayerTrees.find(aId);
   if (iter != sIndirectLayerTrees.end()) {
     CompositorBridgeParent* parent = iter->second.mParent;
     if (parent) {
       parent->ClearApproximatelyVisibleRegions(aId, Nothing());
-      if (RefPtr<APZCTreeManager> apzctm = parent->GetAPZCTreeManager()) {
-        apzctm->NotifyLayerTreeRemoved(aId);
+      if (RefPtr<APZSampler> apz = parent->GetAPZSampler()) {
+        apz->NotifyLayerTreeRemoved(aId);
       }
     }
 
     sIndirectLayerTrees.erase(iter);
   }
 }
 
 /*static*/ void
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -59,16 +59,17 @@ class GPUParent;
 namespace ipc {
 class Shmem;
 } // namespace ipc
 
 namespace layers {
 
 class APZCTreeManager;
 class APZCTreeManagerParent;
+class APZSampler;
 class AsyncCompositionManager;
 class AsyncImagePipelineManager;
 class Compositor;
 class CompositorAnimationStorage;
 class CompositorBridgeParent;
 class CompositorManagerParent;
 class CompositorVsyncScheduler;
 class HostLayerManager;
@@ -441,16 +442,17 @@ public:
 
   PAPZCTreeManagerParent* AllocPAPZCTreeManagerParent(const uint64_t& aLayersId) override;
   bool DeallocPAPZCTreeManagerParent(PAPZCTreeManagerParent* aActor) override;
 
   PAPZParent* AllocPAPZParent(const uint64_t& aLayersId) override;
   bool DeallocPAPZParent(PAPZParent* aActor) override;
 
   RefPtr<APZCTreeManager> GetAPZCTreeManager();
+  RefPtr<APZSampler> GetAPZSampler();
 
   CompositorOptions GetOptions() const {
     return mOptions;
   }
 
   TimeDuration GetVsyncInterval() const {
     // the variable is called "rate" but really it's an interval
     return mVsyncRate;
@@ -606,16 +608,17 @@ protected:
 
   uint64_t mCompositorBridgeID;
   uint64_t mRootLayerTreeID;
 
   bool mOverrideComposeReadiness;
   RefPtr<CancelableRunnable> mForceCompositionTask;
 
   RefPtr<APZCTreeManager> mApzcTreeManager;
+  RefPtr<APZSampler> mApzSampler;
 
   RefPtr<CompositorVsyncScheduler> mCompositorScheduler;
   // This makes sure the compositorParent is not destroyed before receiving
   // confirmation that the channel is closed.
   // mSelfRef is cleared in DeferredDestroy which is scheduled by ActorDestroy.
   RefPtr<CompositorBridgeParent> mSelfRef;
   RefPtr<CompositorAnimationStorage> mAnimationStorage;
 
--- a/gfx/layers/moz.build
+++ b/gfx/layers/moz.build
@@ -87,16 +87,17 @@ EXPORTS.gfxipc += [
 
 EXPORTS.mozilla.dom += [
     'apz/util/CheckerboardReportService.h',
 ]
 
 EXPORTS.mozilla.layers += [
     'AnimationHelper.h',
     'AnimationInfo.h',
+    'apz/public/APZSampler.h',
     'apz/public/CompositorController.h',
     'apz/public/GeckoContentController.h',
     'apz/public/IAPZCTreeManager.h',
     'apz/public/MetricsSharingController.h',
     # exporting things from apz/src is temporary until we extract a
     # proper interface for the code there
     'apz/src/APZCTreeManager.h',
     'apz/src/APZUtils.h',
@@ -292,16 +293,17 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'andr
         'apz/src/AndroidDynamicToolbarAnimator.h',
     ]
 
 UNIFIED_SOURCES += [
     'AnimationHelper.cpp',
     'AnimationInfo.cpp',
     'apz/public/IAPZCTreeManager.cpp',
     'apz/src/APZCTreeManager.cpp',
+    'apz/src/APZSampler.cpp',
     'apz/src/AsyncPanZoomController.cpp',
     'apz/src/AutoscrollAnimation.cpp',
     'apz/src/Axis.cpp',
     'apz/src/CheckerboardEvent.cpp',
     'apz/src/DragTracker.cpp',
     'apz/src/FocusState.cpp',
     'apz/src/FocusTarget.cpp',
     'apz/src/GenericScrollAnimation.cpp',