Bug 866232 - Break assumption of a single global root layer tree. r=BenWa, mattwoodrow
authorKartikaya Gupta <kgupta@mozilla.com>
Tue, 30 Jul 2013 14:03:43 -0400
changeset 140637 bdf483d094bf047baac630561720e5c91820e4bf
parent 140636 2d30f705e17f5a8944810b65f9a05d7f0a19f5d2
child 140638 ca9bf5ddb290e47e5cfdf7f2b0c157f4b88b59a0
push id31813
push userryanvm@gmail.com
push dateTue, 30 Jul 2013 22:08:24 +0000
treeherdermozilla-inbound@0d8409268f42 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersBenWa, mattwoodrow
bugs866232
milestone25.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 866232 - Break assumption of a single global root layer tree. r=BenWa, mattwoodrow
gfx/layers/composite/APZCTreeManager.cpp
gfx/layers/ipc/CompositorParent.cpp
gfx/layers/ipc/CompositorParent.h
gfx/tests/gtest/TestAsyncPanZoomController.cpp
widget/android/AndroidJNI.cpp
widget/android/nsWindow.cpp
widget/android/nsWindow.h
--- a/gfx/layers/composite/APZCTreeManager.cpp
+++ b/gfx/layers/composite/APZCTreeManager.cpp
@@ -59,17 +59,19 @@ APZCTreeManager::UpdatePanZoomController
   // as part of a recursive tree walk is hard and so maintaining a list and removing
   // APZCs that are still alive is much simpler.
   nsTArray< nsRefPtr<AsyncPanZoomController> > apzcsToDestroy;
   Collect(mRootApzc, &apzcsToDestroy);
   mRootApzc = nullptr;
 
   if (aRoot) {
     UpdatePanZoomControllerTree(aCompositor,
-                                aRoot, CompositorParent::ROOT_LAYER_TREE_ID,
+                                aRoot,
+                                // aCompositor is null in gtest scenarios
+                                aCompositor ? aCompositor->RootLayerTreeId() : 0,
                                 nullptr, nullptr,
                                 aIsFirstPaint, aFirstPaintLayersId,
                                 &apzcsToDestroy);
   }
 
   for (int i = apzcsToDestroy.Length() - 1; i >= 0; i--) {
     APZC_LOG("Destroying APZC at %p\n", apzcsToDestroy[i].get());
     apzcsToDestroy[i]->Destroy();
--- a/gfx/layers/ipc/CompositorParent.cpp
+++ b/gfx/layers/ipc/CompositorParent.cpp
@@ -149,49 +149,60 @@ CompositorParent::CompositorParent(nsIWi
   MOZ_COUNT_CTOR(CompositorParent);
   mCompositorID = 0;
   // FIXME: This holds on the the fact that right now the only thing that
   // can destroy this instance is initialized on the compositor thread after
   // this task has been processed.
   CompositorLoop()->PostTask(FROM_HERE, NewRunnableFunction(&AddCompositor,
                                                           this, &mCompositorID));
 
+  mRootLayerTreeID = AllocateLayerTreeId();
+  sIndirectLayerTrees[mRootLayerTreeID].mParent = this;
+
   mApzcTreeManager = new APZCTreeManager();
   ++sCompositorThreadRefCount;
 }
 
 PlatformThreadId
 CompositorParent::CompositorThreadID()
 {
   return sCompositorThread ? sCompositorThread->thread_id() : sCompositorThreadID;
 }
 
 bool
 CompositorParent::IsInCompositorThread()
 {
   return CompositorThreadID() == PlatformThread::CurrentId();
 }
 
+uint64_t
+CompositorParent::RootLayerTreeId()
+{
+  return mRootLayerTreeID;
+}
+
 CompositorParent::~CompositorParent()
 {
   MOZ_COUNT_DTOR(CompositorParent);
 
-  mApzcTreeManager->ClearTree();
   ReleaseCompositorThread();
 }
 
 void
 CompositorParent::Destroy()
 {
   NS_ABORT_IF_FALSE(ManagedPLayerTransactionParent().Length() == 0,
                     "CompositorParent destroyed before managed PLayerTransactionParent");
 
   // Ensure that the layer manager is destructed on the compositor thread.
   mLayerManager = nullptr;
   mCompositionManager = nullptr;
+  mApzcTreeManager->ClearTree();
+  mApzcTreeManager = nullptr;
+  sIndirectLayerTrees.erase(mRootLayerTreeID);
 }
 
 void
 CompositorParent::ForceIsFirstPaint()
 {
   mCompositionManager->ForceIsFirstPaint();
 }
 
@@ -563,17 +574,17 @@ CompositorParent::ShadowLayersUpdated(La
   mLayerManager->UpdateRenderBounds(aTargetConfig.clientBounds());
 
   mCompositionManager->Updated(isFirstPaint, aTargetConfig);
   Layer* root = aLayerTree->GetRoot();
   mLayerManager->SetRoot(root);
 
   if (mApzcTreeManager) {
     AutoResolveRefLayers resolve(mCompositionManager);
-    mApzcTreeManager->UpdatePanZoomControllerTree(this, root, isFirstPaint, ROOT_LAYER_TREE_ID);
+    mApzcTreeManager->UpdatePanZoomControllerTree(this, root, isFirstPaint, mRootLayerTreeID);
   }
 
   if (root) {
     SetShadowProperties(root);
     if (mIsTesting) {
       mCompositionManager->TransformShadowTree(mTestTime);
     }
   }
@@ -704,27 +715,22 @@ CompositorParent::RecvNotifyChildCreated
 }
 
 void
 CompositorParent::NotifyChildCreated(uint64_t aChild)
 {
   sIndirectLayerTrees[aChild].mParent = this;
 }
 
-// Ensure all layer tree IDs are greater than zero, so if we
-// ever see a zero-valued layer tree id we know it's actually
-// uninitialized and/or garbage.
-uint64_t CompositorParent::ROOT_LAYER_TREE_ID = 1;
-
 /*static*/ uint64_t
 CompositorParent::AllocateLayerTreeId()
 {
   MOZ_ASSERT(CompositorLoop());
   MOZ_ASSERT(NS_IsMainThread());
-  static uint64_t ids = ROOT_LAYER_TREE_ID;
+  static uint64_t ids = 0;
   return ++ids;
 }
 
 static void
 EraseLayerState(uint64_t aId)
 {
   sIndirectLayerTrees.erase(aId);
 }
--- a/gfx/layers/ipc/CompositorParent.h
+++ b/gfx/layers/ipc/CompositorParent.h
@@ -99,16 +99,22 @@ public:
    * otherwise.
    */
   bool ScheduleResumeOnCompositorThread(int width, int height);
 
   virtual void ScheduleComposition();
   void NotifyShadowTreeTransaction(uint64_t aId, bool aIsFirstPaint);
 
   /**
+   * Returns the unique layer tree identifier that corresponds to the root
+   * tree of this compositor.
+   */
+  uint64_t RootLayerTreeId();
+
+  /**
    * Returns a pointer to the compositor corresponding to the given ID.
    */
   static CompositorParent* GetCompositor(uint64_t id);
 
   /**
    * Returns the compositor thread's message loop.
    *
    * This message loop is used by CompositorParent and ImageBridgeParent.
@@ -121,21 +127,16 @@ public:
   static void StartUp();
 
   /**
    * Destroys the compositor thread and the global compositor map.
    */
   static void ShutDown();
 
   /**
-   * The reserved layer tree ID for the root of the layer tree.
-   */
-  static uint64_t ROOT_LAYER_TREE_ID;
-
-  /**
    * Allocate an ID that can be used to refer to a layer tree and
    * associated resources that live only on the compositor thread.
    *
    * Must run on the content main thread.
    */
   static uint64_t AllocateLayerTreeId();
   /**
    * Release compositor-thread resources referred to by |aID|.
@@ -282,16 +283,17 @@ private:
 
   bool mUseExternalSurfaceSize;
   nsIntSize mEGLSurfaceSize;
 
   mozilla::Monitor mPauseCompositionMonitor;
   mozilla::Monitor mResumeCompositionMonitor;
 
   uint64_t mCompositorID;
+  uint64_t mRootLayerTreeID;
 
   bool mOverrideComposeReadiness;
   CancelableTask* mForceCompositionTask;
 
   nsRefPtr<APZCTreeManager> mApzcTreeManager;
 
   DISALLOW_EVIL_CONSTRUCTORS(CompositorParent);
 };
--- a/gfx/tests/gtest/TestAsyncPanZoomController.cpp
+++ b/gfx/tests/gtest/TestAsyncPanZoomController.cpp
@@ -368,45 +368,45 @@ SetScrollableFrameMetrics(Layer* aLayer,
 TEST(APZCTreeManager, GetAPZCAtPoint) {
   nsTArray<nsRefPtr<Layer> > layers;
   nsRefPtr<LayerManager> lm;
   nsRefPtr<Layer> root = CreateTestLayerTree(lm, layers);
 
   TimeStamp testStartTime = TimeStamp::Now();
   AsyncPanZoomController::SetFrameTime(testStartTime);
   nsRefPtr<MockContentController> mcc = new MockContentController();
-  ScopedLayerTreeRegistration controller(CompositorParent::ROOT_LAYER_TREE_ID, root, mcc);
+  ScopedLayerTreeRegistration controller(0, root, mcc);
 
   nsRefPtr<APZCTreeManager> manager = new TestAPZCTreeManager();
 
   // No APZC attached so hit testing will return no APZC at (20,20)
   nsRefPtr<AsyncPanZoomController> hit = manager->GetTargetAPZC(ScreenPoint(20, 20));
   AsyncPanZoomController* nullAPZC = nullptr;
   EXPECT_EQ(nullAPZC, hit.get());
 
   // Now we have a root APZC that will match the page
   SetScrollableFrameMetrics(root, FrameMetrics::ROOT_SCROLL_ID, mcc);
-  manager->UpdatePanZoomControllerTree(nullptr, root, CompositorParent::ROOT_LAYER_TREE_ID, false);
+  manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
   hit = manager->GetTargetAPZC(ScreenPoint(15, 15));
   EXPECT_EQ(root->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
   // expect hit point at LayerIntPoint(15, 15)
 
   // Now we have a sub APZC with a better fit
   SetScrollableFrameMetrics(layers[3], FrameMetrics::START_SCROLL_ID, mcc);
-  manager->UpdatePanZoomControllerTree(nullptr, root, CompositorParent::ROOT_LAYER_TREE_ID, false);
+  manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
   EXPECT_NE(root->AsContainerLayer()->GetAsyncPanZoomController(), layers[3]->AsContainerLayer()->GetAsyncPanZoomController());
   hit = manager->GetTargetAPZC(ScreenPoint(15, 15));
   EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
   // expect hit point at LayerIntPoint(15, 15)
 
   // Now test hit testing when we have two scrollable layers
   hit = manager->GetTargetAPZC(ScreenPoint(15, 15));
   EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
   SetScrollableFrameMetrics(layers[4], FrameMetrics::START_SCROLL_ID + 1, mcc);
-  manager->UpdatePanZoomControllerTree(nullptr, root, CompositorParent::ROOT_LAYER_TREE_ID, false);
+  manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
   hit = manager->GetTargetAPZC(ScreenPoint(15, 15));
   EXPECT_EQ(layers[4]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
   // expect hit point at LayerIntPoint(15, 15)
 
   // Hit test ouside the reach of layer[3,4] but inside root
   hit = manager->GetTargetAPZC(ScreenPoint(90, 90));
   EXPECT_EQ(root->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
   // expect hit point at LayerIntPoint(90, 90)
@@ -417,30 +417,30 @@ TEST(APZCTreeManager, GetAPZCAtPoint) {
   hit = manager->GetTargetAPZC(ScreenPoint(-1000, 10));
   EXPECT_EQ(nullAPZC, hit.get());
 
   // Test layer transform
   gfx3DMatrix transform;
   transform.ScalePost(0.1, 0.1, 1);
   root->SetBaseTransform(transform);
   root->ComputeEffectiveTransforms(gfx3DMatrix());
-  manager->UpdatePanZoomControllerTree(nullptr, root, CompositorParent::ROOT_LAYER_TREE_ID, false);
+  manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
   hit = manager->GetTargetAPZC(ScreenPoint(50, 50)); // This point is now outside the root layer
   EXPECT_EQ(nullAPZC, hit.get());
 
   hit = manager->GetTargetAPZC(ScreenPoint(2, 2));
   EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
   // expect hit point at LayerPoint(20, 20)
 
   // Scale layer[4] outside the range
   layers[4]->SetBaseTransform(transform);
   // layer 4 effective visible screenrect: (0.05, 0.05, 0.2, 0.2)
   // Does not contain (2, 2)
   root->ComputeEffectiveTransforms(gfx3DMatrix());
-  manager->UpdatePanZoomControllerTree(nullptr, root, CompositorParent::ROOT_LAYER_TREE_ID, false);
+  manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
   hit = manager->GetTargetAPZC(ScreenPoint(2, 2));
   EXPECT_EQ(layers[3]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
   // expect hit point at LayerPoint(20, 20)
 
   // Transformation chain to layer 7
   SetScrollableFrameMetrics(layers[7], FrameMetrics::START_SCROLL_ID + 2, mcc);
 
   gfx3DMatrix translateTransform;
@@ -451,17 +451,17 @@ TEST(APZCTreeManager, GetAPZCAtPoint) {
   translateTransform2.Translate(gfxPoint3D(-20, 0, 0));
   layers[6]->SetBaseTransform(translateTransform2);
 
   gfx3DMatrix translateTransform3;
   translateTransform3.ScalePost(1,15,1);
   layers[7]->SetBaseTransform(translateTransform3);
 
   root->ComputeEffectiveTransforms(gfx3DMatrix());
-  manager->UpdatePanZoomControllerTree(nullptr, root, CompositorParent::ROOT_LAYER_TREE_ID, false);
+  manager->UpdatePanZoomControllerTree(nullptr, root, 0, false);
   // layer 7 effective visible screenrect (0,16,4,60) but clipped by parent layers
   hit = manager->GetTargetAPZC(ScreenPoint(1, 45));
   EXPECT_EQ(layers[7]->AsContainerLayer()->GetAsyncPanZoomController(), hit.get());
   // expect hit point at LayerPoint(20, 29)
 
   manager->ClearTree();
 }
 
--- a/widget/android/AndroidJNI.cpp
+++ b/widget/android/AndroidJNI.cpp
@@ -842,41 +842,40 @@ NS_EXPORT jdouble JNICALL
 Java_org_mozilla_gecko_GeckoJavaSampler_getProfilerTime(JNIEnv *jenv, jclass jc)
 {
   return profiler_time();
 }
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_abortAnimation(JNIEnv* env, jobject instance)
 {
-    APZCTreeManager *controller = CompositorParent::GetAPZCTreeManager(CompositorParent::ROOT_LAYER_TREE_ID);
+    APZCTreeManager *controller = nsWindow::GetAPZCTreeManager();
     if (controller) {
-        controller->CancelAnimation(ScrollableLayerGuid(CompositorParent::ROOT_LAYER_TREE_ID));
+        controller->CancelAnimation(ScrollableLayerGuid(nsWindow::RootLayerTreeId()));
     }
 }
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_init(JNIEnv* env, jobject instance)
 {
     if (!AndroidBridge::Bridge()) {
         return;
     }
 
     jobject oldRef = AndroidBridge::Bridge()->SetNativePanZoomController(env->NewGlobalRef(instance));
     if (oldRef) {
         MOZ_ASSERT(false, "Registering a new NPZC when we already have one");
         env->DeleteGlobalRef(oldRef);
     }
-    CompositorParent::SetControllerForLayerTree(CompositorParent::ROOT_LAYER_TREE_ID, AndroidBridge::Bridge());
 }
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_handleTouchEvent(JNIEnv* env, jobject instance, jobject event)
 {
-    APZCTreeManager *controller = CompositorParent::GetAPZCTreeManager(CompositorParent::ROOT_LAYER_TREE_ID);
+    APZCTreeManager *controller = nsWindow::GetAPZCTreeManager();
     if (controller) {
         AndroidGeckoEvent* wrapper = AndroidGeckoEvent::MakeFromJavaObject(env, event);
         const MultiTouchInput& input = wrapper->MakeMultiTouchInput(nsWindow::TopWindow());
         delete wrapper;
         if (input.mType >= 0) {
             controller->ReceiveInputEvent(input);
         }
     }
@@ -911,19 +910,19 @@ Java_org_mozilla_gecko_gfx_NativePanZoom
     } else {
         env->DeleteGlobalRef(oldRef);
     }
 }
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_notifyDefaultActionPrevented(JNIEnv* env, jobject instance, jboolean prevented)
 {
-    APZCTreeManager *controller = CompositorParent::GetAPZCTreeManager(CompositorParent::ROOT_LAYER_TREE_ID);
+    APZCTreeManager *controller = nsWindow::GetAPZCTreeManager();
     if (controller) {
-        controller->ContentReceivedTouch(ScrollableLayerGuid(CompositorParent::ROOT_LAYER_TREE_ID), prevented);
+        controller->ContentReceivedTouch(ScrollableLayerGuid(nsWindow::RootLayerTreeId()), prevented);
     }
 }
 
 NS_EXPORT jboolean JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_getRedrawHint(JNIEnv* env, jobject instance)
 {
     // FIXME implement this
     return true;
@@ -940,19 +939,19 @@ Java_org_mozilla_gecko_gfx_NativePanZoom
 {
     // FIXME implement this
     return 0;
 }
 
 NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_gfx_NativePanZoomController_updateScrollOffset(JNIEnv* env, jobject instance, jfloat cssX, jfloat cssY)
 {
-    APZCTreeManager *controller = CompositorParent::GetAPZCTreeManager(CompositorParent::ROOT_LAYER_TREE_ID);
+    APZCTreeManager *controller = nsWindow::GetAPZCTreeManager();
     if (controller) {
-        controller->UpdateScrollOffset(ScrollableLayerGuid(CompositorParent::ROOT_LAYER_TREE_ID), CSSPoint(cssX, cssY));
+        controller->UpdateScrollOffset(ScrollableLayerGuid(nsWindow::RootLayerTreeId()), CSSPoint(cssX, cssY));
     }
 }
 
 NS_EXPORT jboolean JNICALL
 Java_org_mozilla_gecko_ANRReporter_requestNativeStack(JNIEnv*, jclass)
 {
     if (profiler_is_active()) {
         // Don't proceed if profiler is already running
--- a/widget/android/nsWindow.cpp
+++ b/widget/android/nsWindow.cpp
@@ -2412,16 +2412,17 @@ nsWindow::DrawWindowOverlay(LayerManager
     if (!mLayerRendererFrame.DrawForeground(&jniFrame)) return;
     if (!mLayerRendererFrame.EndDrawing(&jniFrame)) return;
     if (!client.DeactivateProgram(&jniFrame)) return;
     mLayerRendererFrame.Dispose(env);
 }
 
 // off-main-thread compositor fields and functions
 
+nsRefPtr<mozilla::layers::APZCTreeManager> nsWindow::sApzcTreeManager = 0;
 nsRefPtr<mozilla::layers::LayerManager> nsWindow::sLayerManager = 0;
 nsRefPtr<mozilla::layers::CompositorParent> nsWindow::sCompositorParent = 0;
 nsRefPtr<mozilla::layers::CompositorChild> nsWindow::sCompositorChild = 0;
 bool nsWindow::sCompositorPaused = true;
 
 void
 nsWindow::SetCompositor(mozilla::layers::LayerManager* aLayerManager,
                         mozilla::layers::CompositorParent* aCompositorParent,
@@ -2495,8 +2496,30 @@ nsWindow::NeedsPaint()
   return nsIWidget::NeedsPaint();
 }
 
 CompositorParent*
 nsWindow::NewCompositorParent(int aSurfaceWidth, int aSurfaceHeight)
 {
     return new CompositorParent(this, true, aSurfaceWidth, aSurfaceHeight);
 }
+
+mozilla::layers::APZCTreeManager*
+nsWindow::GetAPZCTreeManager()
+{
+    if (!sApzcTreeManager) {
+        CompositorParent* compositor = sCompositorParent;
+        if (!compositor) {
+            return nullptr;
+        }
+        uint64_t rootLayerTreeId = compositor->RootLayerTreeId();
+        CompositorParent::SetControllerForLayerTree(rootLayerTreeId, AndroidBridge::Bridge());
+        sApzcTreeManager = CompositorParent::GetAPZCTreeManager(rootLayerTreeId);
+    }
+    return sApzcTreeManager;
+}
+
+uint64_t
+nsWindow::RootLayerTreeId()
+{
+    MOZ_ASSERT(sCompositorParent);
+    return sCompositorParent->RootLayerTreeId();
+}
--- a/widget/android/nsWindow.h
+++ b/widget/android/nsWindow.h
@@ -150,16 +150,19 @@ public:
 
     static void SetCompositor(mozilla::layers::LayerManager* aLayerManager,
                               mozilla::layers::CompositorParent* aCompositorParent,
                               mozilla::layers::CompositorChild* aCompositorChild);
     static void ScheduleComposite();
     static void ScheduleResumeComposition(int width, int height);
     static void ForceIsFirstPaint();
     static float ComputeRenderIntegrity();
+    static mozilla::layers::APZCTreeManager* GetAPZCTreeManager();
+    /* RootLayerTreeId() can only be called when GetAPZCTreeManager() returns non-null */
+    static uint64_t RootLayerTreeId();
 
     virtual bool WidgetPaintsBackground();
 
 protected:
     void BringToFront();
     nsWindow *FindTopLevel();
     bool DrawTo(gfxASurface *targetSurface);
     bool DrawTo(gfxASurface *targetSurface, const nsIntRect &aRect);
@@ -224,15 +227,16 @@ private:
     void DispatchGestureEvent(uint32_t msg, uint32_t direction, double delta,
                               const nsIntPoint &refPoint, uint64_t time);
     void HandleSpecialKey(mozilla::AndroidGeckoEvent *ae);
     void CreateLayerManager(int aCompositorWidth, int aCompositorHeight);
     void RedrawAll();
 
     mozilla::AndroidLayerRendererFrame mLayerRendererFrame;
 
+    static nsRefPtr<mozilla::layers::APZCTreeManager> sApzcTreeManager;
     static nsRefPtr<mozilla::layers::LayerManager> sLayerManager;
     static nsRefPtr<mozilla::layers::CompositorParent> sCompositorParent;
     static nsRefPtr<mozilla::layers::CompositorChild> sCompositorChild;
     static bool sCompositorPaused;
 };
 
 #endif /* NSWINDOW_H_ */