Bug 1467127 - Post wl_display_dispatch_queue_pending tasks from ProcessNextNativeEvent. r=stransky
authorKenny Levinsen <kl@kl.wtf>
Tue, 30 Apr 2019 09:37:37 +0000
changeset 530810 c02b1c12158fafe0ea00083765ac809cba44cdab
parent 530809 fffbf387d2d6c549aeeea33e16e191677969e2e4
child 530811 26d207ba289e2b3e04eabe5da8dde3c67c32cf2e
push id11265
push userffxbld-merge
push dateMon, 13 May 2019 10:53:39 +0000
treeherdermozilla-beta@77e0fe8dbdd3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersstransky
bugs1467127
milestone68.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 1467127 - Post wl_display_dispatch_queue_pending tasks from ProcessNextNativeEvent. r=stransky Send tasks to dispatch our other wayland event queues from their respective threads whenever we service the GTK main event loop. Differential Revision: https://phabricator.services.mozilla.com/D28819
gfx/thebes/gfxPlatform.cpp
widget/gtk/WindowSurfaceWayland.cpp
widget/gtk/moz.build
widget/gtk/nsAppShell.cpp
widget/gtk/nsWaylandDisplay.cpp
widget/gtk/nsWaylandDisplay.h
widget/gtk/nsWaylandDisplayShutdown.h
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -65,16 +65,20 @@
 #  include "mozilla/jni/Utils.h"  // for IsFennec
 #endif
 
 #ifdef XP_WIN
 #  include "mozilla/WindowsVersion.h"
 #  include "mozilla/gfx/DeviceManagerDx.h"
 #endif
 
+#ifdef MOZ_WAYLAND
+#  include "mozilla/widget/nsWaylandDisplayShutdown.h"
+#endif
+
 #include "nsGkAtoms.h"
 #include "gfxPlatformFontList.h"
 #include "gfxContext.h"
 #include "gfxImageSurface.h"
 #include "nsUnicodeProperties.h"
 #include "harfbuzz/hb.h"
 #include "gfxGraphiteShaper.h"
 #include "gfx2DGlue.h"
@@ -1271,16 +1275,19 @@ void gfxPlatform::ShutdownLayersIPC() {
       layers::CompositorManagerChild::Shutdown();
       layers::ImageBridgeChild::ShutDown();
     }
 
     if (gfxVars::UseOMTP() && !recordreplay::IsRecordingOrReplaying()) {
       layers::PaintThread::Shutdown();
     }
   } else if (XRE_IsParentProcess()) {
+#ifdef MOZ_WAYLAND
+    widget::WaylandDisplayShutdown();
+#endif
     gfx::VRManagerChild::ShutDown();
     layers::CompositorManagerChild::Shutdown();
     layers::ImageBridgeChild::ShutDown();
     // This has to happen after shutting down the child protocols.
     layers::CompositorThreadHolder::Shutdown();
     image::ImageMemoryReporter::ShutdownForWebRender();
     // There is a case that RenderThread exists when gfxVars::UseWebRender() is
     // false. This could happen when WebRender was fallbacked to compositor.
--- a/widget/gtk/WindowSurfaceWayland.cpp
+++ b/widget/gtk/WindowSurfaceWayland.cpp
@@ -139,16 +139,18 @@ WaylandShmPool acts as a manager of shar
 Allocates it, holds reference to it and releases it.
 
 We allocate shared memory (shm) by mmap(..., MAP_SHARED,...) as an interface
 between us and wayland compositor. We draw our graphics data to the shm and
 handle to wayland compositor by WindowBackBuffer/WindowSurfaceWayland
 (wl_buffer/wl_surface).
 */
 
+#define EVENT_LOOP_DELAY (1000 / 240)
+
 #define BUFFER_BPP 4
 gfx::SurfaceFormat WindowBackBuffer::mFormat = gfx::SurfaceFormat::B8G8R8A8;
 
 int WaylandShmPool::CreateTemporaryFile(int aSize) {
   const char* tmppath = getenv("XDG_RUNTIME_DIR");
   MOZ_RELEASE_ASSERT(tmppath, "Missing XDG_RUNTIME_DIR env variable.");
 
   nsPrintfCString tmpname("%s/mozilla-shared-XXXXXX", tmppath);
--- a/widget/gtk/moz.build
+++ b/widget/gtk/moz.build
@@ -96,16 +96,19 @@ if CONFIG['MOZ_X11']:
     ]
 
 if CONFIG['MOZ_WAYLAND']:
     UNIFIED_SOURCES += [
         'nsClipboardWayland.cpp',
         'nsWaylandDisplay.cpp',
         'WindowSurfaceWayland.cpp',
     ]
+    EXPORTS.mozilla.widget += [
+        'nsWaylandDisplayShutdown.h'
+    ]
 
 if CONFIG['ACCESSIBILITY']:
     UNIFIED_SOURCES += [
         'maiRedundantObjectFactory.c',
     ]
 
 UNIFIED_SOURCES += [
     'gtk3drawing.cpp',
--- a/widget/gtk/nsAppShell.cpp
+++ b/widget/gtk/nsAppShell.cpp
@@ -22,16 +22,19 @@
 #include "nsIPowerManagerService.h"
 #ifdef MOZ_ENABLE_DBUS
 #  include "WakeLockListener.h"
 #endif
 #include "gfxPlatform.h"
 #include "ScreenHelperGTK.h"
 #include "HeadlessScreenHelper.h"
 #include "mozilla/widget/ScreenManager.h"
+#ifdef MOZ_WAYLAND
+#  include "nsWaylandDisplay.h"
+#endif
 
 using mozilla::LazyLogModule;
 using mozilla::Unused;
 using mozilla::widget::HeadlessScreenHelper;
 using mozilla::widget::ScreenHelperGTK;
 using mozilla::widget::ScreenManager;
 
 #define NOTIFY_TOKEN 0xFA
@@ -262,10 +265,14 @@ failed:
 }
 
 void nsAppShell::ScheduleNativeEventCallback() {
   unsigned char buf[] = {NOTIFY_TOKEN};
   Unused << write(mPipeFDs[1], buf, 1);
 }
 
 bool nsAppShell::ProcessNextNativeEvent(bool mayWait) {
-  return g_main_context_iteration(nullptr, mayWait);
+  bool ret = g_main_context_iteration(nullptr, mayWait);
+#ifdef MOZ_WAYLAND
+  WaylandDispatchDisplays();
+#endif
+  return ret;
 }
--- a/widget/gtk/nsWaylandDisplay.cpp
+++ b/widget/gtk/nsWaylandDisplay.cpp
@@ -16,31 +16,52 @@ namespace widget {
 
 // nsWaylandDisplay needs to be created for each calling thread(main thread,
 // compositor thread and render thread)
 #define MAX_DISPLAY_CONNECTIONS 3
 
 static nsWaylandDisplay *gWaylandDisplays[MAX_DISPLAY_CONNECTIONS];
 static StaticMutex gWaylandDisplaysMutex;
 
+void WaylandDisplayShutdown() {
+  StaticMutexAutoLock lock(gWaylandDisplaysMutex);
+  for (auto &display : gWaylandDisplays) {
+    if (display) {
+      display->Shutdown();
+    }
+  }
+}
+
 static void ReleaseDisplaysAtExit() {
   for (int i = 0; i < MAX_DISPLAY_CONNECTIONS; i++) {
     delete gWaylandDisplays[i];
     gWaylandDisplays[i] = nullptr;
   }
 }
 
+static void DispatchDisplay(nsWaylandDisplay *aDisplay) {
+  aDisplay->DispatchEventQueue();
+}
+
 // Each thread which is using wayland connection (wl_display) has to operate
 // its own wl_event_queue. Main Firefox thread wl_event_queue is handled
 // by Gtk main loop, other threads/wl_event_queue has to be handled by us.
 //
 // nsWaylandDisplay is our interface to wayland compositor. It provides wayland
 // global objects as we need (wl_display, wl_shm) and operates wl_event_queue on
 // compositor (not the main) thread.
-static void WaylandDisplayLoop(wl_display *aDisplay);
+void WaylandDispatchDisplays() {
+  StaticMutexAutoLock lock(gWaylandDisplaysMutex);
+  for (auto &display : gWaylandDisplays) {
+    if (display && display->GetDispatcherThreadLoop()) {
+      display->GetDispatcherThreadLoop()->PostTask(NewRunnableFunction(
+          "WaylandDisplayDispatch", &DispatchDisplay, display));
+    }
+  }
+}
 
 // Get WaylandDisplay for given wl_display and actual calling thread.
 static nsWaylandDisplay *WaylandDisplayGetLocked(GdkDisplay *aGdkDisplay,
                                                  const StaticMutexAutoLock &) {
   // Available as of GTK 3.8+
   static auto sGdkWaylandDisplayGetWlDisplay = (wl_display * (*)(GdkDisplay *))
       dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_display");
   wl_display *waylandDisplay = sGdkWaylandDisplayGetWlDisplay(aGdkDisplay);
@@ -68,37 +89,16 @@ nsWaylandDisplay *WaylandDisplayGet(GdkD
   if (!aGdkDisplay) {
     aGdkDisplay = gdk_display_get_default();
   }
 
   StaticMutexAutoLock lock(gWaylandDisplaysMutex);
   return WaylandDisplayGetLocked(aGdkDisplay, lock);
 }
 
-static void WaylandDisplayLoopLocked(wl_display *aDisplay,
-                                     const StaticMutexAutoLock &) {
-  for (auto &display : gWaylandDisplays) {
-    if (display && display->Matches(aDisplay)) {
-      if (display->DisplayLoop()) {
-        MessageLoop::current()->PostDelayedTask(
-            NewRunnableFunction("WaylandDisplayLoop", &WaylandDisplayLoop,
-                                aDisplay),
-            EVENT_LOOP_DELAY);
-      }
-      break;
-    }
-  }
-}
-
-static void WaylandDisplayLoop(wl_display *aDisplay) {
-  MOZ_ASSERT(!NS_IsMainThread());
-  StaticMutexAutoLock lock(gWaylandDisplaysMutex);
-  WaylandDisplayLoopLocked(aDisplay, lock);
-}
-
 void nsWaylandDisplay::SetShm(wl_shm *aShm) { mShm = aShm; }
 
 void nsWaylandDisplay::SetSubcompositor(wl_subcompositor *aSubcompositor) {
   mSubcompositor = aSubcompositor;
 }
 
 void nsWaylandDisplay::SetDataDeviceManager(
     wl_data_device_manager *aDataDeviceManager) {
@@ -153,27 +153,28 @@ static void global_registry_handler(void
 }
 
 static void global_registry_remover(void *data, wl_registry *registry,
                                     uint32_t id) {}
 
 static const struct wl_registry_listener registry_listener = {
     global_registry_handler, global_registry_remover};
 
-bool nsWaylandDisplay::DisplayLoop() {
+bool nsWaylandDisplay::DispatchEventQueue() {
   wl_display_dispatch_queue_pending(mDisplay, mEventQueue);
   return true;
 }
 
 bool nsWaylandDisplay::Matches(wl_display *aDisplay) {
   return mThreadId == PR_GetCurrentThread() && aDisplay == mDisplay;
 }
 
 nsWaylandDisplay::nsWaylandDisplay(wl_display *aDisplay)
-    : mThreadId(PR_GetCurrentThread()),
+    : mDispatcherThreadLoop(nullptr),
+      mThreadId(PR_GetCurrentThread()),
       mDisplay(aDisplay),
       mEventQueue(nullptr),
       mDataDeviceManager(nullptr),
       mSubcompositor(nullptr),
       mSeat(nullptr),
       mShm(nullptr),
       mPrimarySelectionDeviceManager(nullptr),
       mRegistry(nullptr) {
@@ -181,25 +182,26 @@ nsWaylandDisplay::nsWaylandDisplay(wl_di
   wl_registry_add_listener(mRegistry, &registry_listener, this);
 
   if (NS_IsMainThread()) {
     // Use default event queue in main thread operated by Gtk+.
     mEventQueue = nullptr;
     wl_display_roundtrip(mDisplay);
     wl_display_roundtrip(mDisplay);
   } else {
+    mDispatcherThreadLoop = MessageLoop::current();
     mEventQueue = wl_display_create_queue(mDisplay);
-    MessageLoop::current()->PostTask(NewRunnableFunction(
-        "WaylandDisplayLoop", &WaylandDisplayLoop, mDisplay));
     wl_proxy_set_queue((struct wl_proxy *)mRegistry, mEventQueue);
     wl_display_roundtrip_queue(mDisplay, mEventQueue);
     wl_display_roundtrip_queue(mDisplay, mEventQueue);
   }
 }
 
+void nsWaylandDisplay::Shutdown() { mDispatcherThreadLoop = nullptr; }
+
 nsWaylandDisplay::~nsWaylandDisplay() {
   // Owned by Gtk+, we don't need to release
   mDisplay = nullptr;
 
   wl_registry_destroy(mRegistry);
   mRegistry = nullptr;
 
   if (mEventQueue) {
--- a/widget/gtk/nsWaylandDisplay.h
+++ b/widget/gtk/nsWaylandDisplay.h
@@ -9,30 +9,27 @@
 #define __MOZ_WAYLAND_REGISTRY_H__
 
 #include "mozwayland/mozwayland.h"
 #include "wayland/gtk-primary-selection-client-protocol.h"
 
 namespace mozilla {
 namespace widget {
 
-// TODO: Bug 1467125 - We need to integrate wl_display_dispatch_queue_pending()
-// with compositor event loop.
-#define EVENT_LOOP_DELAY (1000 / 240)
-
 // Our general connection to Wayland display server,
 // holds our display connection and runs event loop.
 class nsWaylandDisplay {
  public:
   explicit nsWaylandDisplay(wl_display* aDisplay);
   virtual ~nsWaylandDisplay();
 
-  bool DisplayLoop();
+  bool DispatchEventQueue();
   bool Matches(wl_display* aDisplay);
 
+  MessageLoop* GetDispatcherThreadLoop() { return mDispatcherThreadLoop; }
   wl_display* GetDisplay() { return mDisplay; };
   wl_event_queue* GetEventQueue() { return mEventQueue; };
   wl_subcompositor* GetSubcompositor(void) { return mSubcompositor; };
   wl_data_device_manager* GetDataDeviceManager(void) {
     return mDataDeviceManager;
   };
   wl_seat* GetSeat(void) { return mSeat; };
   wl_shm* GetShm(void) { return mShm; };
@@ -42,26 +39,30 @@ class nsWaylandDisplay {
 
   void SetShm(wl_shm* aShm);
   void SetSubcompositor(wl_subcompositor* aSubcompositor);
   void SetDataDeviceManager(wl_data_device_manager* aDataDeviceManager);
   void SetSeat(wl_seat* aSeat);
   void SetPrimarySelectionDeviceManager(
       gtk_primary_selection_device_manager* aPrimarySelectionDeviceManager);
 
+  void Shutdown();
+
  private:
+  MessageLoop* mDispatcherThreadLoop;
   PRThread* mThreadId;
   wl_display* mDisplay;
   wl_event_queue* mEventQueue;
   wl_data_device_manager* mDataDeviceManager;
   wl_subcompositor* mSubcompositor;
   wl_seat* mSeat;
   wl_shm* mShm;
   gtk_primary_selection_device_manager* mPrimarySelectionDeviceManager;
   wl_registry* mRegistry;
 };
 
+void WaylandDispatchDisplays();
 nsWaylandDisplay* WaylandDisplayGet(GdkDisplay* aGdkDisplay = nullptr);
 
 }  // namespace widget
 }  // namespace mozilla
 
 #endif  // __MOZ_WAYLAND_REGISTRY_H__
new file mode 100644
--- /dev/null
+++ b/widget/gtk/nsWaylandDisplayShutdown.h
@@ -0,0 +1,19 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:expandtab:shiftwidth=4:tabstop=4:
+ */
+/* 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 __MOZ_WAYLAND_DISPLAY_SHUTDOWN_H__
+#define __MOZ_WAYLAND_DISPLAY_SHUTDOWN_H__
+
+namespace mozilla {
+namespace widget {
+
+void WaylandDisplayShutdown();
+
+}  // namespace widget
+}  // namespace mozilla
+
+#endif  // __MOZ_WAYLAND_DISPLAY_SHUTDOWN_H__