Bug 1449982 - Move the WebRenderScrollData storage from WebRenderBridgeParent to APZUpdater. r=botond
authorKartikaya Gupta <kgupta@mozilla.com>
Tue, 10 Apr 2018 12:29:56 -0400
changeset 412685 526faf04687507f9c5767a7033c2f87e4585dcb4
parent 412684 3eab97d46f5ae899f2e5567b8922fa4e276c535d
child 412686 1a6398d3f9b34038484ea85e6dc9a6e0381f9f23
push id101981
push useraiakab@mozilla.com
push dateTue, 10 Apr 2018 22:18:59 +0000
treeherdermozilla-inbound@9ad2b8aabfae [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond
bugs1449982
milestone61.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 1449982 - Move the WebRenderScrollData storage from WebRenderBridgeParent to APZUpdater. r=botond This allows us to easily store a handle to the APZUpdater on the WebRenderScrollDataWrapper class and walk around in the scroll data tree without having to query other classes like CompositorBridgeParent or WebRenderBridgeParent when we encounter a reflayer boundary. MozReview-Commit-ID: 6l7oMb7tBlW
gfx/layers/apz/public/APZSampler.h
gfx/layers/apz/public/APZUpdater.h
gfx/layers/apz/src/APZCTreeManager.cpp
gfx/layers/apz/src/APZCTreeManager.h
gfx/layers/apz/src/APZSampler.cpp
gfx/layers/apz/src/APZUpdater.cpp
gfx/layers/wr/WebRenderBridgeParent.cpp
gfx/layers/wr/WebRenderBridgeParent.h
gfx/layers/wr/WebRenderScrollDataWrapper.h
--- a/gfx/layers/apz/public/APZSampler.h
+++ b/gfx/layers/apz/public/APZSampler.h
@@ -70,22 +70,22 @@ public:
   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();
+  void AssertOnSamplerThread() const;
 
   /**
    * Returns true if currently on the APZSampler's "sampler thread".
    */
-  bool IsSamplerThread();
+  bool IsSamplerThread() const;
 
 protected:
   virtual ~APZSampler();
 
 private:
   RefPtr<APZCTreeManager> mApz;
 };
 
--- a/gfx/layers/apz/public/APZUpdater.h
+++ b/gfx/layers/apz/public/APZUpdater.h
@@ -8,16 +8,17 @@
 #define mozilla_layers_APZUpdater_h
 
 #include <deque>
 #include <unordered_map>
 
 #include "base/platform_thread.h"   // for PlatformThreadId
 #include "LayersTypes.h"
 #include "mozilla/layers/APZTestData.h"
+#include "mozilla/layers/WebRenderScrollData.h"
 #include "mozilla/StaticMutex.h"
 #include "nsThreadUtils.h"
 #include "Units.h"
 
 namespace mozilla {
 
 namespace wr {
 struct WrWindowId;
@@ -59,53 +60,60 @@ public:
   void UpdateFocusState(LayersId aRootLayerTreeId,
                         LayersId aOriginatingLayersId,
                         const FocusTarget& aFocusTarget);
   void UpdateHitTestingTree(LayersId aRootLayerTreeId,
                             Layer* aRoot,
                             bool aIsFirstPaint,
                             LayersId aOriginatingLayersId,
                             uint32_t aPaintSequenceNumber);
-  void UpdateHitTestingTree(LayersId aRootLayerTreeId,
-                            const WebRenderScrollData& aScrollData,
-                            bool aIsFirstPaint,
-                            LayersId aOriginatingLayersId,
-                            uint32_t aPaintSequenceNumber);
+  /**
+   * This should be called (in the WR-enabled case) when the compositor receives
+   * a new WebRenderScrollData for a layers id. The |aScrollData| parameter is
+   * the scroll data for |aOriginatingLayersId|. This function will store
+   * the new scroll data and update the focus state and hit-testing tree.
+   */
+  void UpdateScrollDataAndTreeState(LayersId aRootLayerTreeId,
+                                    LayersId aOriginatingLayersId,
+                                    WebRenderScrollData&& aScrollData);
 
   void NotifyLayerTreeAdopted(LayersId aLayersId,
                               const RefPtr<APZUpdater>& aOldUpdater);
   void NotifyLayerTreeRemoved(LayersId aLayersId);
 
   bool GetAPZTestData(LayersId aLayersId, APZTestData* aOutData);
 
   void SetTestAsyncScrollOffset(LayersId aLayersId,
                                 const FrameMetrics::ViewID& aScrollId,
                                 const CSSPoint& aOffset);
   void SetTestAsyncZoom(LayersId aLayersId,
                         const FrameMetrics::ViewID& aScrollId,
                         const LayerToParentLayerScale& aZoom);
 
+  // This can only be called on the updater thread.
+  const WebRenderScrollData* GetScrollData(LayersId aLayersId) const;
+
   /**
    * This can be used to assert that the current thread is the
    * updater thread (which samples the async transform).
    * This does nothing if thread assertions are disabled.
    */
-  void AssertOnUpdaterThread();
+  void AssertOnUpdaterThread() const;
 
   /**
    * Runs the given task on the APZ "updater thread" for this APZUpdater. If
    * this function is called from the updater thread itself then the task is
    * run immediately without getting queued.
    */
   void RunOnUpdaterThread(already_AddRefed<Runnable> aTask);
 
   /**
    * Returns true if currently on the APZUpdater's "updater thread".
    */
-  bool IsUpdaterThread();
+  bool IsUpdaterThread() const;
 
   /**
    * Dispatches the given task to the APZ "controller thread", but does it *from*
    * the updater thread. That is, if the thread on which this function is called
    * is not the updater thread, the task is first dispatched to the updater thread.
    * When the updater thread runs it (or if this is called directly on the updater
    * thread), that is when the task gets dispatched to the controller thread.
    * The controller thread then actually runs the task.
@@ -116,16 +124,22 @@ protected:
   virtual ~APZUpdater();
 
   bool UsingWebRenderUpdaterThread() const;
   static already_AddRefed<APZUpdater> GetUpdater(const wr::WrWindowId& aWindowId);
 
 private:
   RefPtr<APZCTreeManager> mApz;
 
+  // Map from layers id to WebRenderScrollData. This can only be touched on
+  // the updater thread.
+  std::unordered_map<LayersId,
+                     WebRenderScrollData,
+                     LayersId::HashFn> mScrollData;
+
   // Used to manage the mapping from a WR window id to APZUpdater. These are only
   // used if WebRender is enabled. Both sWindowIdMap and mWindowId should only
   // be used while holding the sWindowIdLock.
   static StaticMutex sWindowIdLock;
   static std::unordered_map<uint64_t, APZUpdater*> sWindowIdMap;
   Maybe<wr::WrWindowId> mWindowId;
 
   // If WebRender and async scene building are enabled, this holds the thread id
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -514,25 +514,24 @@ APZCTreeManager::UpdateHitTestingTree(La
 
   LayerMetricsWrapper root(aRoot);
   UpdateHitTestingTreeImpl(aRootLayerTreeId, root, aIsFirstPaint,
                            aOriginatingLayersId, aPaintSequenceNumber);
 }
 
 void
 APZCTreeManager::UpdateHitTestingTree(LayersId aRootLayerTreeId,
-                                      const WebRenderScrollData& aScrollData,
+                                      const WebRenderScrollDataWrapper& aScrollWrapper,
                                       bool aIsFirstPaint,
                                       LayersId aOriginatingLayersId,
                                       uint32_t aPaintSequenceNumber)
 {
   AssertOnUpdaterThread();
 
-  WebRenderScrollDataWrapper wrapper(&aScrollData);
-  UpdateHitTestingTreeImpl(aRootLayerTreeId, wrapper, aIsFirstPaint,
+  UpdateHitTestingTreeImpl(aRootLayerTreeId, aScrollWrapper, aIsFirstPaint,
                            aOriginatingLayersId, aPaintSequenceNumber);
 }
 
 bool
 APZCTreeManager::PushStateToWR(wr::TransactionBuilder& aTxn,
                                const TimeStamp& aSampleTime,
                                nsTArray<wr::WrTransformProperty>& aTransformArray)
 {
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -52,17 +52,17 @@ class OverscrollHandoffChain;
 struct OverscrollHandoffState;
 class FocusTarget;
 struct FlingHandoffState;
 struct ScrollableLayerGuidHash;
 class LayerMetricsWrapper;
 class InputQueue;
 class GeckoContentController;
 class HitTestingTreeNode;
-class WebRenderScrollData;
+class WebRenderScrollDataWrapper;
 struct AncestorTransform;
 struct ScrollThumbData;
 
 /**
  * ****************** NOTE ON LOCK ORDERING IN APZ **************************
  *
  * There are two main kinds of locks used by APZ: APZCTreeManager::mTreeLock
  * ("the tree lock") and AsyncPanZoomController::mRecursiveMutex ("APZC locks").
@@ -184,17 +184,17 @@ public:
 
   /**
    * Same as the above UpdateHitTestingTree, except slightly modified to take
    * the scrolling data passed over PWebRenderBridge instead of the raw layer
    * tree. This version is used when WebRender is enabled because we don't have
    * shadow layers in that scenario.
    */
   void UpdateHitTestingTree(LayersId aRootLayerTreeId,
-                            const WebRenderScrollData& aScrollData,
+                            const WebRenderScrollDataWrapper& aScrollWrapper,
                             bool aIsFirstPaint,
                             LayersId aOriginatingLayersId,
                             uint32_t aPaintSequenceNumber);
 
   /**
    * Called when webrender is enabled, from the sampler thread. This function
    * walks through the tree of APZC instances and tells webrender about the
    * async scroll position. It also advances APZ animations to the specified
--- a/gfx/layers/apz/src/APZSampler.cpp
+++ b/gfx/layers/apz/src/APZSampler.cpp
@@ -141,23 +141,23 @@ APZSampler::HasUnusedAsyncTransform(cons
 
   AsyncPanZoomController* apzc = aLayer.GetApzc();
   return apzc
       && !apzc->GetAsyncTransformAppliedToContent()
       && !AsyncTransformComponentMatrix(apzc->GetCurrentAsyncTransform(AsyncPanZoomController::eForCompositing)).IsIdentity();
 }
 
 void
-APZSampler::AssertOnSamplerThread()
+APZSampler::AssertOnSamplerThread() const
 {
   if (APZThreadUtils::GetThreadAssertionsEnabled()) {
     MOZ_ASSERT(IsSamplerThread());
   }
 }
 
 bool
-APZSampler::IsSamplerThread()
+APZSampler::IsSamplerThread() const
 {
   return CompositorThreadHolder::IsInCompositorThread();
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/apz/src/APZUpdater.cpp
+++ b/gfx/layers/apz/src/APZUpdater.cpp
@@ -7,17 +7,17 @@
 #include "mozilla/layers/APZUpdater.h"
 
 #include "APZCTreeManager.h"
 #include "AsyncPanZoomController.h"
 #include "base/task.h"
 #include "mozilla/layers/APZThreadUtils.h"
 #include "mozilla/layers/CompositorThread.h"
 #include "mozilla/layers/SynchronousTask.h"
-#include "mozilla/layers/WebRenderScrollData.h"
+#include "mozilla/layers/WebRenderScrollDataWrapper.h"
 #include "mozilla/webrender/WebRenderAPI.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 
 namespace mozilla {
 namespace layers {
 
 StaticMutex APZUpdater::sWindowIdLock;
 std::unordered_map<uint64_t, APZUpdater*> APZUpdater::sWindowIdMap;
@@ -128,43 +128,39 @@ APZUpdater::UpdateHitTestingTree(LayersI
 {
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   AssertOnUpdaterThread();
   mApz->UpdateHitTestingTree(aRootLayerTreeId, aRoot, aIsFirstPaint,
       aOriginatingLayersId, aPaintSequenceNumber);
 }
 
 void
-APZUpdater::UpdateHitTestingTree(LayersId aRootLayerTreeId,
-                                 const WebRenderScrollData& aScrollData,
-                                 bool aIsFirstPaint,
-                                 LayersId aOriginatingLayersId,
-                                 uint32_t aPaintSequenceNumber)
+APZUpdater::UpdateScrollDataAndTreeState(LayersId aRootLayerTreeId,
+                                         LayersId aOriginatingLayersId,
+                                         WebRenderScrollData&& aScrollData)
 {
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
-  // use the local variable to resolve the function overload.
-  auto func = static_cast<void (APZCTreeManager::*)(LayersId,
-                                                    const WebRenderScrollData&,
-                                                    bool,
-                                                    LayersId,
-                                                    uint32_t)>
-      (&APZCTreeManager::UpdateHitTestingTree);
-  RunOnUpdaterThread(NewRunnableMethod<LayersId,
-                                       WebRenderScrollData,
-                                       bool,
-                                       LayersId,
-                                       uint32_t>(
-      "APZUpdater::UpdateHitTestingTree",
-      mApz,
-      func,
-      aRootLayerTreeId,
-      aScrollData,
-      aIsFirstPaint,
-      aOriginatingLayersId,
-      aPaintSequenceNumber));
+  RefPtr<APZUpdater> self = this;
+  RunOnUpdaterThread(NS_NewRunnableFunction(
+    "APZUpdater::UpdateHitTestingTree",
+    [=,aScrollData=Move(aScrollData)]() {
+      self->mApz->UpdateFocusState(aRootLayerTreeId,
+          aOriginatingLayersId, aScrollData.GetFocusTarget());
+
+      self->mScrollData[aOriginatingLayersId] = aScrollData;
+      auto root = self->mScrollData.find(aRootLayerTreeId);
+      if (root == self->mScrollData.end()) {
+        return;
+      }
+      self->mApz->UpdateHitTestingTree(aRootLayerTreeId,
+          WebRenderScrollDataWrapper(*self, &(root->second)),
+          aScrollData.IsFirstPaint(), aOriginatingLayersId,
+          aScrollData.GetPaintSequenceNumber());
+    }
+  ));
 }
 
 void
 APZUpdater::NotifyLayerTreeAdopted(LayersId aLayersId,
                                    const RefPtr<APZUpdater>& aOldUpdater)
 {
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
   RunOnUpdaterThread(NewRunnableMethod<LayersId, RefPtr<APZCTreeManager>>(
@@ -174,21 +170,24 @@ APZUpdater::NotifyLayerTreeAdopted(Layer
       aLayersId,
       aOldUpdater ? aOldUpdater->mApz : nullptr));
 }
 
 void
 APZUpdater::NotifyLayerTreeRemoved(LayersId aLayersId)
 {
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
-  RunOnUpdaterThread(NewRunnableMethod<LayersId>(
-      "APZUpdater::NotifyLayerTreeRemoved",
-      mApz,
-      &APZCTreeManager::NotifyLayerTreeRemoved,
-      aLayersId));
+  RefPtr<APZUpdater> self = this;
+  RunOnUpdaterThread(NS_NewRunnableFunction(
+    "APZUpdater::NotifyLayerTreeRemoved",
+    [=]() {
+      self->mScrollData.erase(aLayersId);
+      self->mApz->NotifyLayerTreeRemoved(aLayersId);
+    }
+  ));
 }
 
 bool
 APZUpdater::GetAPZTestData(LayersId aLayersId,
                            APZTestData* aOutData)
 {
   MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
 
@@ -244,18 +243,26 @@ APZUpdater::SetTestAsyncZoom(LayersId aL
         apzc->SetTestAsyncZoom(aZoom);
       } else {
         NS_WARNING("Unable to find APZC in SetTestAsyncZoom");
       }
     }
   ));
 }
 
+const WebRenderScrollData*
+APZUpdater::GetScrollData(LayersId aLayersId) const
+{
+  AssertOnUpdaterThread();
+  auto it = mScrollData.find(aLayersId);
+  return (it == mScrollData.end() ? nullptr : &(it->second));
+}
+
 void
-APZUpdater::AssertOnUpdaterThread()
+APZUpdater::AssertOnUpdaterThread() const
 {
   if (APZThreadUtils::GetThreadAssertionsEnabled()) {
     MOZ_ASSERT(IsUpdaterThread());
   }
 }
 
 void
 APZUpdater::RunOnUpdaterThread(already_AddRefed<Runnable> aTask)
@@ -295,17 +302,17 @@ APZUpdater::RunOnUpdaterThread(already_A
     loop->PostTask(task.forget());
   } else {
     // Could happen during startup
     NS_WARNING("Dropping task posted to updater thread");
   }
 }
 
 bool
-APZUpdater::IsUpdaterThread()
+APZUpdater::IsUpdaterThread() const
 {
   if (UsingWebRenderUpdaterThread()) {
     return PlatformThread::CurrentId() == *mUpdaterThreadId;
   }
   return CompositorThreadHolder::IsInCompositorThread();
 }
 
 void
--- a/gfx/layers/wr/WebRenderBridgeParent.cpp
+++ b/gfx/layers/wr/WebRenderBridgeParent.cpp
@@ -501,35 +501,38 @@ WebRenderBridgeParent::GetRootCompositor
       CompositorBridgeParent::GetIndirectShadowTree(GetLayersId());
   if (!lts) {
     return nullptr;
   }
   return lts->mParent;
 }
 
 void
-WebRenderBridgeParent::UpdateAPZ(bool aUpdateHitTestingTree)
+WebRenderBridgeParent::UpdateAPZFocusState(const FocusTarget& aFocus)
 {
   CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
   if (!cbp) {
     return;
   }
   LayersId rootLayersId = cbp->RootLayerTreeId();
-  RefPtr<WebRenderBridgeParent> rootWrbp = cbp->GetWebRenderBridgeParent();
-  if (!rootWrbp) {
+  if (RefPtr<APZUpdater> apz = cbp->GetAPZUpdater()) {
+    apz->UpdateFocusState(rootLayersId, GetLayersId(), aFocus);
+  }
+}
+
+void
+WebRenderBridgeParent::UpdateAPZScrollData(WebRenderScrollData&& aData)
+{
+  CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
+  if (!cbp) {
     return;
   }
+  LayersId rootLayersId = cbp->RootLayerTreeId();
   if (RefPtr<APZUpdater> apz = cbp->GetAPZUpdater()) {
-    apz->UpdateFocusState(rootLayersId, GetLayersId(),
-                          mScrollData.GetFocusTarget());
-    if (aUpdateHitTestingTree) {
-      apz->UpdateHitTestingTree(rootLayersId, rootWrbp->GetScrollData(),
-          mScrollData.IsFirstPaint(), GetLayersId(),
-          mScrollData.GetPaintSequenceNumber());
-    }
+    apz->UpdateScrollDataAndTreeState(rootLayersId, GetLayersId(), Move(aData));
   }
 }
 
 bool
 WebRenderBridgeParent::PushAPZStateToWR(wr::TransactionBuilder& aTxn,
                                         nsTArray<wr::WrTransformProperty>& aTransformArray)
 {
   CompositorBridgeParent* cbp = GetRootCompositorBridgeParent();
@@ -545,23 +548,16 @@ WebRenderBridgeParent::PushAPZStateToWR(
     if (frameInterval != TimeDuration::Forever()) {
       animationTime += frameInterval;
     }
     return apz->PushStateToWR(aTxn, animationTime, aTransformArray);
   }
   return false;
 }
 
-const WebRenderScrollData&
-WebRenderBridgeParent::GetScrollData() const
-{
-  MOZ_ASSERT(mozilla::layers::CompositorThreadHolder::IsInCompositorThread());
-  return mScrollData;
-}
-
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvSetDisplayList(const gfx::IntSize& aSize,
                                           InfallibleTArray<WebRenderParentCommand>&& aCommands,
                                           InfallibleTArray<OpDestroy>&& aToDestroy,
                                           const uint64_t& aFwdTransactionId,
                                           const uint64_t& aTransactionId,
                                           const wr::LayoutSize& aContentSize,
                                           ipc::ByteBuf&& dl,
@@ -623,18 +619,21 @@ WebRenderBridgeParent::RecvSetDisplayLis
 
     if (ShouldParentObserveEpoch()) {
       mCompositorBridge->ObserveLayerUpdate(GetLayersId(), GetChildLayerObserverEpoch(), true);
     }
   }
 
   HoldPendingTransactionId(wrEpoch, aTransactionId, aTxnStartTime, aFwdTime);
 
-  mScrollData = aScrollData;
-  UpdateAPZ(true);
+  // aScrollData is moved into this function but that is not reflected by the
+  // function signature due to the way the IPDL generator works. We remove the
+  // const so that we can move this structure all the way to the desired
+  // destination.
+  UpdateAPZScrollData(Move(const_cast<WebRenderScrollData&>(aScrollData)));
 
   if (mIdNamespace != aIdNamespace) {
     // Pretend we composited since someone is wating for this event,
     // though DisplayList was not pushed to webrender.
     TimeStamp now = TimeStamp::Now();
     mCompositorBridge->DidComposite(GetLayersId(), now, now);
   }
 
@@ -668,18 +667,17 @@ WebRenderBridgeParent::RecvEmptyTransact
   AutoWebRenderBridgeParentAsyncMessageSender autoAsyncMessageSender(this, &aToDestroy);
 
   if (!aCommands.IsEmpty()) {
     mAsyncImageManager->SetCompositionTime(TimeStamp::Now());
     ProcessWebRenderParentCommands(aCommands);
     ScheduleGenerateFrame();
   }
 
-  mScrollData.SetFocusTarget(aFocusTarget);
-  UpdateAPZ(false);
+  UpdateAPZFocusState(aFocusTarget);
 
   if (!aCommands.IsEmpty()) {
     wr::TransactionBuilder txn;
     wr::Epoch wrEpoch = GetNextWrEpoch();
     txn.UpdateEpoch(mPipelineId, wrEpoch);
     mApi->SendTransaction(txn);
 
     HoldPendingTransactionId(wrEpoch, aTransactionId, aTxnStartTime, aFwdTime);
@@ -698,18 +696,17 @@ WebRenderBridgeParent::RecvEmptyTransact
   }
 
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvSetFocusTarget(const FocusTarget& aFocusTarget)
 {
-  mScrollData.SetFocusTarget(aFocusTarget);
-  UpdateAPZ(false);
+  UpdateAPZFocusState(aFocusTarget);
   return IPC_OK();
 }
 
 mozilla::ipc::IPCResult
 WebRenderBridgeParent::RecvParentCommands(nsTArray<WebRenderParentCommand>&& aCommands)
 {
   if (mDestroyed) {
     return IPC_OK();
--- a/gfx/layers/wr/WebRenderBridgeParent.h
+++ b/gfx/layers/wr/WebRenderBridgeParent.h
@@ -165,18 +165,18 @@ public:
 
   void ExtractImageCompositeNotifications(nsTArray<ImageCompositeNotificationInfo>* aNotifications);
 
   wr::IdNamespace GetIdNamespace()
   {
     return mIdNamespace;
   }
 
-  void UpdateAPZ(bool aUpdateHitTestingTree);
-  const WebRenderScrollData& GetScrollData() const;
+  void UpdateAPZFocusState(const FocusTarget& aFocus);
+  void UpdateAPZScrollData(WebRenderScrollData&& aData);
 
   void FlushRendering();
   void FlushRenderingAsync();
 
   /**
    * Schedule generating WebRender frame definitely at next composite timing.
    *
    * WebRenderBridgeParent uses composite timing to check if there is an update
@@ -266,17 +266,14 @@ private:
   std::queue<PendingTransactionId> mPendingTransactionIds;
   wr::Epoch mWrEpoch;
   wr::IdNamespace mIdNamespace;
 
   bool mPaused;
   bool mDestroyed;
   bool mForceRendering;
   bool mReceivedDisplayList;
-
-  // Can only be accessed on the compositor thread.
-  WebRenderScrollData mScrollData;
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // mozilla_layers_WebRenderBridgeParent_h
--- a/gfx/layers/wr/WebRenderScrollDataWrapper.h
+++ b/gfx/layers/wr/WebRenderScrollDataWrapper.h
@@ -39,18 +39,20 @@ namespace layers {
  * This class being declared a MOZ_STACK_CLASS should help with that.
  *
  * Refer to LayerMetricsWrapper.h for actual documentation on the exposed API.
  */
 class MOZ_STACK_CLASS WebRenderScrollDataWrapper {
 public:
   // Basic constructor for external callers. Starts the walker at the root of
   // the tree.
-  explicit WebRenderScrollDataWrapper(const WebRenderScrollData* aData = nullptr)
-    : mData(aData)
+  explicit WebRenderScrollDataWrapper(const APZUpdater& aUpdater,
+                                      const WebRenderScrollData* aData = nullptr)
+    : mUpdater(&aUpdater)
+    , mData(aData)
     , mLayerIndex(0)
     , mContainingSubtreeLastIndex(0)
     , mLayer(nullptr)
     , mMetadataIndex(0)
   {
     if (!mData) {
       return;
     }
@@ -70,20 +72,22 @@ public:
       mMetadataIndex--;
     }
   }
 
 private:
   // Internal constructor for walking from one WebRenderLayerScrollData to
   // another. In this case we need to recompute the mMetadataIndex to be the
   // "topmost" scroll metadata on the new layer.
-  WebRenderScrollDataWrapper(const WebRenderScrollData* aData,
+  WebRenderScrollDataWrapper(const APZUpdater* aUpdater,
+                             const WebRenderScrollData* aData,
                              size_t aLayerIndex,
                              size_t aContainingSubtreeLastIndex)
-    : mData(aData)
+    : mUpdater(aUpdater)
+    , mData(aData)
     , mLayerIndex(aLayerIndex)
     , mContainingSubtreeLastIndex(aContainingSubtreeLastIndex)
     , mLayer(nullptr)
     , mMetadataIndex(0)
   {
     MOZ_ASSERT(mData);
     mLayer = mData->GetLayerData(mLayerIndex);
     MOZ_ASSERT(mLayer);
@@ -93,22 +97,24 @@ private:
     mMetadataIndex = mLayer->GetScrollMetadataCount();
     if (mMetadataIndex > 0) {
       mMetadataIndex--;
     }
   }
 
   // Internal constructor for walking from one metadata to another metadata on
   // the same WebRenderLayerScrollData.
-  WebRenderScrollDataWrapper(const WebRenderScrollData* aData,
+  WebRenderScrollDataWrapper(const APZUpdater* aUpdater,
+                             const WebRenderScrollData* aData,
                              size_t aLayerIndex,
                              size_t aContainingSubtreeLastIndex,
                              const WebRenderLayerScrollData* aLayer,
                              uint32_t aMetadataIndex)
-    : mData(aData)
+    : mUpdater(aUpdater)
+    , mData(aData)
     , mLayerIndex(aLayerIndex)
     , mContainingSubtreeLastIndex(aContainingSubtreeLastIndex)
     , mLayer(aLayer)
     , mMetadataIndex(aMetadataIndex)
   {
     MOZ_ASSERT(mData);
     MOZ_ASSERT(mLayer);
     MOZ_ASSERT(mLayer == mData->GetLayerData(mLayerIndex));
@@ -129,66 +135,63 @@ public:
   WebRenderScrollDataWrapper GetLastChild() const
   {
     MOZ_ASSERT(IsValid());
 
     if (!AtBottomLayer()) {
       // If we're still walking around in the virtual container layers created
       // by the ScrollMetadata array, we just need to update the metadata index
       // and that's it.
-      return WebRenderScrollDataWrapper(mData, mLayerIndex,
+      return WebRenderScrollDataWrapper(mUpdater, mData, mLayerIndex,
           mContainingSubtreeLastIndex, mLayer, mMetadataIndex - 1);
     }
 
     // Otherwise, we need to walk to a different WebRenderLayerScrollData in
     // mData.
 
     // Since mData contains the layer in depth-first, last-to-first order,
     // the index after mLayerIndex must be mLayerIndex's last child, if it
     // has any children (indicated by GetDescendantCount() > 0). Furthermore
     // we compute the first index outside the subtree rooted at this node
     // (in |subtreeLastIndex|) and pass that in to the child wrapper to use as
     // its mContainingSubtreeLastIndex.
     if (mLayer->GetDescendantCount() > 0) {
       size_t prevSiblingIndex = mLayerIndex + 1 + mLayer->GetDescendantCount();
       size_t subtreeLastIndex = std::min(mContainingSubtreeLastIndex, prevSiblingIndex);
-      return WebRenderScrollDataWrapper(mData, mLayerIndex + 1, subtreeLastIndex);
+      return WebRenderScrollDataWrapper(mUpdater, mData, mLayerIndex + 1, subtreeLastIndex);
     }
 
     // We've run out of descendants. But! If the original layer was a RefLayer,
     // then it connects to another layer tree and we need to traverse that too.
     // So return a WebRenderScrollDataWrapper for the root of the child layer
     // tree.
     if (mLayer->GetReferentId()) {
-      CompositorBridgeParent::LayerTreeState* lts =
-          CompositorBridgeParent::GetIndirectShadowTree(mLayer->GetReferentId().value());
-      if (lts && lts->mWrBridge) {
-        return WebRenderScrollDataWrapper(&(lts->mWrBridge->GetScrollData()));
-      }
+      return WebRenderScrollDataWrapper(*mUpdater,
+          mUpdater->GetScrollData(*mLayer->GetReferentId()));
     }
 
-    return WebRenderScrollDataWrapper();
+    return WebRenderScrollDataWrapper(*mUpdater);
   }
 
   WebRenderScrollDataWrapper GetPrevSibling() const
   {
     MOZ_ASSERT(IsValid());
 
     if (!AtTopLayer()) {
       // The virtual container layers don't have siblings
-      return WebRenderScrollDataWrapper();
+      return WebRenderScrollDataWrapper(*mUpdater);
     }
 
     // Skip past the descendants to get to the previous sibling. However, we
     // might be at the last sibling already.
     size_t prevSiblingIndex = mLayerIndex + 1 + mLayer->GetDescendantCount();
     if (prevSiblingIndex < mContainingSubtreeLastIndex) {
-      return WebRenderScrollDataWrapper(mData, prevSiblingIndex, mContainingSubtreeLastIndex);
+      return WebRenderScrollDataWrapper(mUpdater, mData, prevSiblingIndex, mContainingSubtreeLastIndex);
     }
-    return WebRenderScrollDataWrapper();
+    return WebRenderScrollDataWrapper(*mUpdater);
   }
 
   const ScrollMetadata& Metadata() const
   {
     MOZ_ASSERT(IsValid());
 
     if (mMetadataIndex >= mLayer->GetScrollMetadataCount()) {
       return *ScrollMetadata::sNullMetadata;
@@ -335,16 +338,17 @@ private:
   }
 
   bool AtTopLayer() const
   {
     return mLayer->GetScrollMetadataCount() == 0 || mMetadataIndex == mLayer->GetScrollMetadataCount() - 1;
   }
 
 private:
+  const APZUpdater* mUpdater;
   const WebRenderScrollData* mData;
   // The index (in mData->mLayerScrollData) of the WebRenderLayerScrollData this
   // wrapper is pointing to.
   size_t mLayerIndex;
   // The upper bound on the set of valid indices inside the subtree rooted at
   // the parent of this "layer". That is, any layer index |i| in the range
   // mLayerIndex <= i < mContainingSubtreeLastIndex is guaranteed to point to
   // a layer that is a descendant of "parent", where "parent" is the parent