Bug 1422966 - implement WaylandShmPool to manage shared memory for wl_buffer, r=jhorak
authorMartin Stransky <stransky@redhat.com>
Mon, 04 Dec 2017 22:22:04 +0100
changeset 396542 9e720457902784c5584c9c2872772f8d412ea55a
parent 396541 8870736e152c95d897e691581f1d239f06729d82
child 396543 4a82861a13995730173b1436aac8a48ee0f0c22b
push id33098
push userncsoregi@mozilla.com
push dateSat, 16 Dec 2017 09:35:50 +0000
treeherdermozilla-central@c7b126878814 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjhorak
bugs1422966
milestone59.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 1422966 - implement WaylandShmPool to manage shared memory for wl_buffer, r=jhorak We allocate shared memory (shm) by mmap(..., MAP_SHARED,...) as an interface between wayland based application and wayland compositor. We draw our graphics data to the shm and handle to wayland compositor by wl_buffer/wl_surface. WaylandShmPool acts as a manager of the allocated memory. Allocates it, holds reference to it and releases it. MozReview-Commit-ID: CY6oEIl4Vxa
widget/gtk/WindowSurfaceWayland.cpp
widget/gtk/WindowSurfaceWayland.h
--- a/widget/gtk/WindowSurfaceWayland.cpp
+++ b/widget/gtk/WindowSurfaceWayland.cpp
@@ -315,10 +315,114 @@ nsWaylandDisplay::~nsWaylandDisplay()
   mDisplay = nullptr;
 
   if (mEventQueue) {
     wl_event_queue_destroy(mEventQueue);
     mEventQueue = nullptr;
   }
 }
 
+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);
+
+  char* filename;
+  int fd = -1;
+  int ret = 0;
+
+  if (tmpname.GetMutableData(&filename)) {
+    fd = mkstemp(filename);
+    if (fd >= 0) {
+      int flags = fcntl(fd, F_GETFD);
+      if (flags >= 0) {
+        fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
+      }
+    }
+  }
+
+  if (fd >= 0) {
+    unlink(tmpname.get());
+  } else {
+    printf_stderr("Unable to create mapping file %s\n", filename);
+    MOZ_CRASH();
+  }
+
+#ifdef HAVE_POSIX_FALLOCATE
+  do {
+    ret = posix_fallocate(fd, 0, aSize);
+  } while (ret == EINTR);
+  if (ret != 0) {
+    close(fd);
+  }
+#else
+  do {
+    ret = ftruncate(fd, aSize);
+  } while (ret < 0 && errno == EINTR);
+  if (ret < 0) {
+    close(fd);
+  }
+#endif
+  MOZ_RELEASE_ASSERT(ret == 0, "Mapping file allocation failed.");
+
+  return fd;
+}
+
+WaylandShmPool::WaylandShmPool(nsWaylandDisplay* aWaylandDisplay, int aSize)
+  : mAllocatedSize(aSize)
+{
+  mShmPoolFd = CreateTemporaryFile(mAllocatedSize);
+  mImageData = mmap(nullptr, mAllocatedSize,
+                     PROT_READ | PROT_WRITE, MAP_SHARED, mShmPoolFd, 0);
+  MOZ_RELEASE_ASSERT(mImageData != MAP_FAILED,
+                     "Unable to map drawing surface!");
+
+  mShmPool = wl_shm_create_pool(aWaylandDisplay->GetShm(),
+                                mShmPoolFd, mAllocatedSize);
+
+  // We set our queue to get mShmPool events at compositor thread.
+  wl_proxy_set_queue((struct wl_proxy *)mShmPool,
+                     aWaylandDisplay->GetEventQueue());
+}
+
+bool
+WaylandShmPool::Resize(int aSize)
+{
+  // We do size increase only
+  if (aSize <= mAllocatedSize)
+    return true;
+
+  if (ftruncate(mShmPoolFd, aSize) < 0)
+    return false;
+
+#ifdef HAVE_POSIX_FALLOCATE
+  do {
+    errno = posix_fallocate(mShmPoolFd, 0, aSize);
+  } while (errno == EINTR);
+  if (errno != 0)
+    return false;
+#endif
+
+  wl_shm_pool_resize(mShmPool, aSize);
+
+  munmap(mImageData, mAllocatedSize);
+
+  mImageData = mmap(nullptr, aSize,
+                    PROT_READ | PROT_WRITE, MAP_SHARED, mShmPoolFd, 0);
+  if (mImageData == MAP_FAILED)
+    return false;
+
+  mAllocatedSize = aSize;
+  return true;
+}
+
+WaylandShmPool::~WaylandShmPool()
+{
+  munmap(mImageData, mAllocatedSize);
+  wl_shm_pool_destroy(mShmPool);
+  close(mShmPoolFd);
+}
+
 }  // namespace widget
 }  // namespace mozilla
--- a/widget/gtk/WindowSurfaceWayland.h
+++ b/widget/gtk/WindowSurfaceWayland.h
@@ -34,12 +34,31 @@ private:
 
   PRThread*           mThreadId;
   gfx::SurfaceFormat  mFormat;
   wl_shm*             mShm;
   wl_event_queue*     mEventQueue;
   wl_display*         mDisplay;
 };
 
+// Allocates and owns shared memory for Wayland drawing surface
+class WaylandShmPool {
+public:
+  WaylandShmPool(nsWaylandDisplay* aDisplay, int aSize);
+  ~WaylandShmPool();
+
+  bool                Resize(int aSize);
+  wl_shm_pool*        GetShmPool()    { return mShmPool;   };
+  void*               GetImageData()  { return mImageData; };
+
+private:
+  int CreateTemporaryFile(int aSize);
+
+  wl_shm_pool*        mShmPool;
+  int                 mShmPoolFd;
+  int                 mAllocatedSize;
+  void*               mImageData;
+};
+
 }  // namespace widget
 }  // namespace mozilla
 
 #endif // _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_WAYLAND_H