Allow dispatching to the APZ controller thread from any thread. (bug 1147681 part 1, r=kats)
authorDavid Anderson <danderson@mozilla.com>
Thu, 26 Mar 2015 14:23:02 -0700
changeset 266342 c2179c027c28922befd5617fdb5c5728cc387b10
parent 266341 7c4d2ceadd89cca6d2a8ec8b1ae367401e5c4c70
child 266343 6f42f8ee82468d18acd65e0c2b5bf6c040696224
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats
bugs1147681
milestone39.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
Allow dispatching to the APZ controller thread from any thread. (bug 1147681 part 1, r=kats)
gfx/layers/apz/util/APZThreadUtils.cpp
gfx/layers/apz/util/APZThreadUtils.h
widget/gonk/nsWindow.cpp
widget/gonk/nsWindow.h
widget/nsBaseWidget.cpp
widget/nsBaseWidget.h
--- a/gfx/layers/apz/util/APZThreadUtils.cpp
+++ b/gfx/layers/apz/util/APZThreadUtils.cpp
@@ -6,72 +6,66 @@
 #include "mozilla/layers/APZThreadUtils.h"
 
 #include "mozilla/layers/Compositor.h"
 
 namespace mozilla {
 namespace layers {
 
 static bool sThreadAssertionsEnabled = true;
-static PRThread* sControllerThread;
+static MessageLoop* sControllerThread;
 
 /*static*/ void
 APZThreadUtils::SetThreadAssertionsEnabled(bool aEnabled) {
   sThreadAssertionsEnabled = aEnabled;
 }
 
 /*static*/ bool
 APZThreadUtils::GetThreadAssertionsEnabled() {
   return sThreadAssertionsEnabled;
 }
 
 /*static*/ void
+APZThreadUtils::SetControllerThread(MessageLoop* aLoop)
+{
+  // We must either be setting the initial controller thread, or removing it,
+  // or re-using an existing controller thread.
+  MOZ_ASSERT(!sControllerThread || !aLoop || sControllerThread == aLoop);
+  sControllerThread = aLoop;
+}
+
+/*static*/ void
 APZThreadUtils::AssertOnControllerThread() {
   if (!GetThreadAssertionsEnabled()) {
     return;
   }
 
-  static bool sControllerThreadDetermined = false;
-  if (!sControllerThreadDetermined) {
-    // Technically this may not actually pick up the correct controller thread,
-    // if the first call to this method happens from a non-controller thread.
-    // If the assertion below fires, it is possible that it is because
-    // sControllerThread is not actually the controller thread.
-    sControllerThread = PR_GetCurrentThread();
-    sControllerThreadDetermined = true;
-  }
-  MOZ_ASSERT(sControllerThread == PR_GetCurrentThread());
+  MOZ_ASSERT(sControllerThread == MessageLoop::current());
 }
 
 /*static*/ void
 APZThreadUtils::AssertOnCompositorThread()
 {
   if (GetThreadAssertionsEnabled()) {
     Compositor::AssertOnCompositorThread();
   }
 }
 
 /*static*/ void
 APZThreadUtils::RunOnControllerThread(Task* aTask)
 {
-#ifdef MOZ_WIDGET_GONK
-  // On B2G the controller thread is the compositor thread, and this function
-  // is always called from the libui thread or the main thread.
-  MessageLoop* loop = CompositorParent::CompositorLoop();
-  if (!loop) {
+  if (!sControllerThread) {
     // Could happen on startup
     NS_WARNING("Dropping task posted to controller thread\n");
     delete aTask;
     return;
   }
-  MOZ_ASSERT(MessageLoop::current() != loop);
-  loop->PostTask(FROM_HERE, aTask);
-#else
-  // On non-B2G platforms this is only ever called from the controller thread
-  // itself.
-  AssertOnControllerThread();
-  aTask->Run();
-  delete aTask;
-#endif
+
+  if (sControllerThread == MessageLoop::current()) {
+    aTask->Run();
+    delete aTask;
+  } else {
+    sControllerThread->PostTask(FROM_HERE, aTask);
+  }
 }
 
 } // namespace layers
 } // namespace mozilla
--- a/gfx/layers/apz/util/APZThreadUtils.h
+++ b/gfx/layers/apz/util/APZThreadUtils.h
@@ -18,16 +18,21 @@ public:
    * In the gtest environment everything runs on one thread, so we
    * shouldn't assert that we're on a particular thread. This enables
    * that behaviour.
    */
   static void SetThreadAssertionsEnabled(bool aEnabled);
   static bool GetThreadAssertionsEnabled();
 
   /**
+   * Set the controller thread.
+   */
+  static void SetControllerThread(MessageLoop* aLoop);
+
+  /**
    * This can be used to assert that the current thread is the
    * controller/UI thread (on which input events are received).
    * This does nothing if thread assertions are disabled.
    */
   static void AssertOnControllerThread();
 
   /**
    * This can be used to assert that the current thread is the
--- a/widget/gonk/nsWindow.cpp
+++ b/widget/gonk/nsWindow.cpp
@@ -222,16 +222,22 @@ nsWindow::DoDraw(void)
     }
 
     listener = targetWindow->GetWidgetListener();
     if (listener) {
         listener->DidPaintWindow();
     }
 }
 
+void
+nsWindow::ConfigureAPZControllerThread()
+{
+  APZThreadUtils::SetControllerThread(CompositorParent::CompositorLoop());
+}
+
 /*static*/ nsEventStatus
 nsWindow::DispatchInputEvent(WidgetGUIEvent& aEvent)
 {
     if (!gFocusedWindow) {
         return nsEventStatus_eIgnore;
     }
 
     gFocusedWindow->UserActivity();
--- a/widget/gonk/nsWindow.h
+++ b/widget/gonk/nsWindow.h
@@ -127,16 +127,18 @@ public:
 
     virtual uint32_t GetGLFrameBufferFormat() override;
 
     virtual nsIntRect GetNaturalBounds() override;
     virtual bool NeedsPaint();
 
     virtual Composer2D* GetComposer2D() override;
 
+    void ConfigureAPZControllerThread() override;
+
 protected:
     nsWindow* mParent;
     bool mVisible;
     InputContext mInputContext;
     nsCOMPtr<nsIIdleServiceInternal> mIdleService;
     // If we're using a BasicCompositor, these fields are temporarily
     // set during frame composition.  They wrap the hardware
     // framebuffer.
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -973,28 +973,36 @@ private:
 
 
 void nsBaseWidget::ConfigureAPZCTreeManager()
 {
   uint64_t rootLayerTreeId = mCompositorParent->RootLayerTreeId();
   mAPZC = CompositorParent::GetAPZCTreeManager(rootLayerTreeId);
   MOZ_ASSERT(mAPZC);
 
+  ConfigureAPZControllerThread();
+
   mAPZC->SetDPI(GetDPI());
   mAPZEventState = new APZEventState(this,
       new ChromeProcessContentReceivedInputBlockCallback(mAPZC));
   mSetTargetAPZCCallback = new ChromeProcessSetTargetAPZCCallback(mAPZC);
   mSetAllowedTouchBehaviorCallback = new ChromeProcessSetAllowedTouchBehaviorCallback(mAPZC);
 
   nsRefPtr<GeckoContentController> controller = CreateRootContentController();
   if (controller) {
     CompositorParent::SetControllerForLayerTree(rootLayerTreeId, controller);
   }
 }
 
+void nsBaseWidget::ConfigureAPZControllerThread()
+{
+  // By default the controller thread is the main thread.
+  APZThreadUtils::SetControllerThread(MessageLoop::current());
+}
+
 nsEventStatus
 nsBaseWidget::ProcessUntransformedAPZEvent(WidgetInputEvent* aEvent,
                                            const ScrollableLayerGuid& aGuid,
                                            uint64_t aInputBlockId,
                                            nsEventStatus aApzResponse)
 {
   MOZ_ASSERT(NS_IsMainThread());
   InputAPZContext context(aGuid, aInputBlockId);
--- a/widget/nsBaseWidget.h
+++ b/widget/nsBaseWidget.h
@@ -326,16 +326,17 @@ protected:
                                   const nsAString &aIconSuffix,
                                   nsIFile **aResult);
   virtual void    OnDestroy();
   void            BaseCreate(nsIWidget *aParent,
                              const nsIntRect &aRect,
                              nsWidgetInitData *aInitData);
 
   virtual void ConfigureAPZCTreeManager();
+  virtual void ConfigureAPZControllerThread();
   virtual already_AddRefed<GeckoContentController> CreateRootContentController();
 
   // Dispatch an event that has already been routed through APZ.
   nsEventStatus ProcessUntransformedAPZEvent(mozilla::WidgetInputEvent* aEvent,
                                              const ScrollableLayerGuid& aGuid,
                                              uint64_t aInputBlockId,
                                              nsEventStatus aApzResponse);