Bug 1441916 - Move APZTestData from the LayerTreeState structure into the APZ. r?botond draft
authorKartikaya Gupta <kgupta@mozilla.com>
Thu, 01 Mar 2018 23:00:40 -0500
changeset 762498 81abbeee00b0210811844d6d20b297b2946ca673
parent 762497 1d4b6bca069b32e4e075512d84dd261676355292
child 762499 a99abc3cff3bf8a8a27910260f53b692967f5718
push id101178
push userkgupta@mozilla.com
push dateFri, 02 Mar 2018 13:48:39 +0000
reviewersbotond
bugs1441916
milestone60.0a1
Bug 1441916 - Move APZTestData from the LayerTreeState structure into the APZ. r?botond This encapsulates the APZTestData better inside APZCTreeManager, which we will want once we allow the hit-test tree update to happen on a thread other than the compositor thread. MozReview-Commit-ID: 66uSsagVfEu
gfx/layers/apz/src/APZCTreeManager.cpp
gfx/layers/apz/src/APZCTreeManager.h
gfx/layers/ipc/CompositorBridgeParent.cpp
gfx/layers/ipc/CompositorBridgeParent.h
gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -229,17 +229,18 @@ APZCTreeManager::CalculatePendingDisplay
 
 APZCTreeManager::APZCTreeManager(uint64_t aRootLayersId)
     : mInputQueue(new InputQueue()),
       mRootLayersId(aRootLayersId),
       mTreeLock("APZCTreeLock"),
       mHitResultForInputBlock(CompositorHitTestInfo::eInvisibleToHitTest),
       mRetainedTouchIdentifier(-1),
       mInScrollbarTouchDrag(false),
-      mApzcTreeLog("apzctree")
+      mApzcTreeLog("apzctree"),
+      mTestDataLock("APZTestDataLock")
 {
   RefPtr<APZCTreeManager> self(this);
   NS_DispatchToMainThread(
     NS_NewRunnableFunction("layers::APZCTreeManager::APZCTreeManager", [self] {
       self->mFlushObserver = new CheckerboardFlushObserver(self);
     }));
   AsyncPanZoomController::InitializeGlobalState();
   mApzcTreeLog.ConditionOnPrefFunction(gfxPrefs::APZPrintTree);
@@ -265,24 +266,43 @@ APZCTreeManager::NotifyLayerTreeAdopted(
 {
   APZThreadUtils::AssertOnCompositorThread();
 
   MOZ_ASSERT(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).
+
+  UniquePtr<APZTestData> adoptedData;
+  { // scope lock for removal on oldApzcTreeManager
+    MutexAutoLock lock(aOldApzcTreeManager->mTestDataLock);
+    auto it = aOldApzcTreeManager->mTestData.find(aLayersId);
+    if (it != aOldApzcTreeManager->mTestData.end()) {
+      adoptedData = Move(it->second);
+      aOldApzcTreeManager->mTestData.erase(it);
+    }
+  }
+  if (adoptedData) {
+    MutexAutoLock lock(mTestDataLock);
+    mTestData[aLayersId] = Move(adoptedData);
+  }
 }
 
 void
 APZCTreeManager::NotifyLayerTreeRemoved(uint64_t aLayersId)
 {
   APZThreadUtils::AssertOnCompositorThread();
 
   mFocusState.RemoveFocusTarget(aLayersId);
+
+  { // scope lock
+    MutexAutoLock lock(mTestDataLock);
+    mTestData.erase(aLayersId);
+  }
 }
 
 AsyncPanZoomController*
 APZCTreeManager::NewAPZCInstance(uint64_t aLayersId,
                                  GeckoContentController* aController)
 {
   return new AsyncPanZoomController(aLayersId, this, mInputQueue,
     aController, AsyncPanZoomController::USE_GESTURE_DETECTOR);
@@ -311,20 +331,21 @@ APZCTreeManager::UpdateHitTestingTreeImp
   APZThreadUtils::AssertOnCompositorThread();
 
   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()) {
-    if (LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(aOriginatingLayersId)) {
-      testData = &state->mApzTestData;
-      testData->StartNewPaint(aPaintSequenceNumber);
-    }
+    MutexAutoLock lock(mTestDataLock);
+    UniquePtr<APZTestData> ptr = MakeUnique<APZTestData>();
+    auto result = mTestData.insert(std::make_pair(aOriginatingLayersId, Move(ptr)));
+    testData = result.first->second.get();
+    testData->StartNewPaint(aPaintSequenceNumber);
   }
 
   const LayerTreeState* treeState =
     CompositorBridgeParent::GetIndirectShadowTree(aRootLayerTreeId);
   MOZ_ASSERT(treeState);
   TreeBuildingState state(treeState, aIsFirstPaint, aOriginatingLayersId,
                           testData, aPaintSequenceNumber);
 
@@ -1133,20 +1154,21 @@ APZCTreeManager::ReceiveInputEvent(Input
         if (!apzc && mRootNode) {
           apzc = mRootNode->GetApzc();
         }
       }
 
       if (apzc) {
         if (gfxPrefs::APZTestLoggingEnabled() && mouseInput.mType == MouseInput::MOUSE_HITTEST) {
           ScrollableLayerGuid guid = apzc->GetGuid();
-          CompositorBridgeParent::CallWithIndirectShadowTree(guid.mLayersId,
-            [&](LayerTreeState& aState) -> void {
-              aState.mApzTestData.RecordHitResult(mouseInput.mOrigin, hitResult, guid.mScrollId);
-            });
+
+          MutexAutoLock lock(mTestDataLock);
+          auto it = mTestData.find(guid.mLayersId);
+          MOZ_ASSERT(it != mTestData.end());
+          it->second->RecordHitResult(mouseInput.mOrigin, hitResult, guid.mScrollId);
         }
 
         TargetConfirmationFlags confFlags{hitResult};
         bool apzDragEnabled = gfxPrefs::APZDragEnabled();
         if (apzDragEnabled && hitScrollbar) {
           // If scrollbar dragging is enabled and we hit a scrollbar, wait
           // for the main-thread confirmation because it contains drag metrics
           // that we need.
@@ -2937,16 +2959,30 @@ APZCTreeManager::GetContentController(ui
   RefPtr<GeckoContentController> controller;
   CompositorBridgeParent::CallWithIndirectShadowTree(aLayersId,
     [&](LayerTreeState& aState) -> void {
       controller = aState.mController;
     });
   return controller.forget();
 }
 
+bool
+APZCTreeManager::GetAPZTestData(uint64_t aLayersId,
+                                APZTestData* aOutData)
+{
+  APZThreadUtils::AssertOnCompositorThread();
+  MutexAutoLock lock(mTestDataLock);
+  auto it = mTestData.find(aLayersId);
+  if (it == mTestData.end()) {
+    return false;
+  }
+  *aOutData = *(it->second);
+  return true;
+}
+
 #if defined(MOZ_WIDGET_ANDROID)
 void
 APZCTreeManager::InitializeDynamicToolbarAnimator(const int64_t& aRootLayerTreeId)
 {
   MOZ_ASSERT(mToolbarAnimator);
   mToolbarAnimator->Initialize(aRootLayerTreeId);
 }
 
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -9,23 +9,25 @@
 
 #include <unordered_map>                          // for std::unordered_map
 
 #include "gfxPoint.h"                   // for gfxPoint
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT_HELPER2
 #include "mozilla/gfx/CompositorHitTestInfo.h"
 #include "mozilla/gfx/Logging.h"        // for gfx::TreeLog
 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4
-#include "mozilla/layers/TouchCounter.h"// for TouchCounter
+#include "mozilla/layers/APZTestData.h" // for APZTestData
+#include "mozilla/layers/FocusState.h"  // for FocusState
 #include "mozilla/layers/IAPZCTreeManager.h" // for IAPZCTreeManager
 #include "mozilla/layers/KeyboardMap.h" // for KeyboardMap
-#include "mozilla/layers/FocusState.h"  // for FocusState
+#include "mozilla/layers/TouchCounter.h"// for TouchCounter
 #include "mozilla/RecursiveMutex.h"     // for RecursiveMutex
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/TimeStamp.h"          // for mozilla::TimeStamp
+#include "mozilla/UniquePtr.h"          // for UniquePtr
 #include "nsCOMPtr.h"                   // for already_AddRefed
 
 #if defined(MOZ_WIDGET_ANDROID)
 #include "mozilla/layers/AndroidDynamicToolbarAnimator.h"
 #endif // defined(MOZ_WIDGET_ANDROID)
 
 namespace mozilla {
 class MultiTouchInput;
@@ -52,22 +54,23 @@ class InputQueue;
 class GeckoContentController;
 class HitTestingTreeNode;
 class WebRenderScrollData;
 struct AncestorTransform;
 
 /**
  * ****************** NOTE ON LOCK ORDERING IN APZ **************************
  *
- * There are two kinds of locks used by APZ: APZCTreeManager::mTreeLock
+ * There are two main kinds of locks used by APZ: APZCTreeManager::mTreeLock
  * ("the tree lock") and AsyncPanZoomController::mRecursiveMutex ("APZC locks").
+ * There is also the APZCTreeManager::mTestDataLock ("test lock").
  *
  * To avoid deadlock, we impose a lock ordering between these locks, which is:
  *
- *      tree lock -> APZC locks
+ *      tree lock -> APZC locks -> test lock
  *
  * The interpretation of the lock ordering is that if lock A precedes lock B
  * in the ordering sequence, then you must NOT wait on A while holding B.
  *
  * **************************************************************************
  */
 
 /**
@@ -489,16 +492,18 @@ public:
       LayoutDeviceIntPoint* aRefPoint,
       ScrollableLayerGuid*  aOutTargetGuid,
       uint64_t*             aOutFocusSequenceNumber) override;
 
   void UpdateWheelTransaction(
       LayoutDeviceIntPoint aRefPoint,
       EventMessage aEventMessage) override;
 
+  bool GetAPZTestData(uint64_t aLayersId, APZTestData* aOutData);
+
 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:
@@ -713,16 +718,21 @@ private:
   /* For logging the APZC tree for debugging (enabled by the apz.printtree
    * pref). */
   gfx::TreeLog mApzcTreeLog;
 
   class CheckerboardFlushObserver;
   friend class CheckerboardFlushObserver;
   RefPtr<CheckerboardFlushObserver> mFlushObserver;
 
+  // Map from layers id to APZTestData. Accesses and mutations must be
+  // protected by the mTestDataLock.
+  std::unordered_map<uint64_t, UniquePtr<APZTestData>> mTestData;
+  mutable mozilla::Mutex mTestDataLock;
+
   static float sDPI;
 
 #if defined(MOZ_WIDGET_ANDROID)
 public:
   void InitializeDynamicToolbarAnimator(const int64_t& aRootLayerTreeId);
   AndroidDynamicToolbarAnimator* GetAndroidDynamicToolbarAnimator();
 
 private:
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -1371,19 +1371,20 @@ CompositorBridgeParent::FlushApzRepaints
     "layers::CompositorBridgeParent::FlushApzRepaints",
     [=]() { self->mApzcTreeManager->FlushApzRepaints(layersId); }));
 }
 
 void
 CompositorBridgeParent::GetAPZTestData(const uint64_t& aLayersId,
                                        APZTestData* aOutData)
 {
-  MOZ_ASSERT(aLayersId == 0 || aLayersId == mRootLayerTreeID);
-  MonitorAutoLock lock(*sIndirectLayerTreesLock);
-  *aOutData = sIndirectLayerTrees[mRootLayerTreeID].mApzTestData;
+  uint64_t layersId = (aLayersId == 0 ? mRootLayerTreeID : aLayersId);
+  if (mApzcTreeManager) {
+    mApzcTreeManager->GetAPZTestData(layersId, aOutData);
+  }
 }
 
 void
 CompositorBridgeParent::SetConfirmedTargetAPZC(const uint64_t& aLayersId,
                                                const uint64_t& aInputBlockId,
                                                const nsTArray<ScrollableLayerGuid>& aTargets)
 {
   if (!mApzcTreeManager) {
--- a/gfx/layers/ipc/CompositorBridgeParent.h
+++ b/gfx/layers/ipc/CompositorBridgeParent.h
@@ -355,17 +355,16 @@ public:
     RefPtr<CompositorBridgeParent> mParent;
     HostLayerManager* mLayerManager;
     RefPtr<WebRenderBridgeParent> mWrBridge;
     // Pointer to the CrossProcessCompositorBridgeParent. Used by APZCs to share
     // their FrameMetrics with the corresponding child process that holds
     // the PCompositorBridgeChild
     CrossProcessCompositorBridgeParent* mCrossProcessParent;
     TargetConfig mTargetConfig;
-    APZTestData mApzTestData;
     LayerTransactionParent* mLayerTree;
     nsTArray<PluginWindowData> mPluginData;
     bool mUpdatedPluginDataAvailable;
 
     CompositorController* GetCompositorController() const;
     MetricsSharingController* CrossProcessSharingController() const;
     MetricsSharingController* InProcessSharingController() const;
     RefPtr<UiCompositorControllerParent> mUiControllerParent;
--- a/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CrossProcessCompositorBridgeParent.cpp
@@ -481,18 +481,23 @@ CrossProcessCompositorBridgeParent::Flus
 }
 
 void
 CrossProcessCompositorBridgeParent::GetAPZTestData(
   const uint64_t& aLayersId,
   APZTestData* aOutData)
 {
   MOZ_ASSERT(aLayersId != 0);
-  MonitorAutoLock lock(*sIndirectLayerTreesLock);
-  *aOutData = sIndirectLayerTrees[aLayersId].mApzTestData;
+  const CompositorBridgeParent::LayerTreeState* state =
+    CompositorBridgeParent::GetIndirectShadowTree(aLayersId);
+  if (!state || !state->mParent) {
+    return;
+  }
+
+  state->mParent->GetAPZTestData(aLayersId, aOutData);
 }
 
 void
 CrossProcessCompositorBridgeParent::SetConfirmedTargetAPZC(
   const uint64_t& aLayersId,
   const uint64_t& aInputBlockId,
   const nsTArray<ScrollableLayerGuid>& aTargets)
 {