Bug 1422966 - implement WaylandShmPool to manage shared memory for wl_buffer, r?jhorak draft
authorMartin Stransky <stransky@redhat.com>
Mon, 04 Dec 2017 22:22:04 +0100
changeset 711989 c4e9f9cdca02b5cb957d437c63e07b5e9512ee8a
parent 711988 1f9ab9a5af76afdf2cc2f4661431f2f17a4c36e8
child 711990 7d281617386ca8b6042763ade14cd0adb66a790a
push id93216
push userstransky@redhat.com
push dateFri, 15 Dec 2017 09:42:38 +0000
reviewersjhorak
bugs1422966
milestone59.0a1
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