Blob Blame History Raw
diff -up firefox-69.0/widget/gtk/mozwayland/mozwayland.h.mozilla-1580152 firefox-69.0/widget/gtk/mozwayland/mozwayland.h
--- firefox-69.0/widget/gtk/mozwayland/mozwayland.h.mozilla-1580152	2019-09-16 11:11:30.081299217 +0200
+++ firefox-69.0/widget/gtk/mozwayland/mozwayland.h	2019-09-16 11:11:30.089299191 +0200
@@ -27,6 +27,9 @@ MOZ_EXPORT struct wl_proxy* wl_proxy_mar
     struct wl_proxy* proxy, uint32_t opcode,
     const struct wl_interface* interface, ...);
 
+MOZ_EXPORT void* wl_proxy_create_wrapper(void* proxy);
+MOZ_EXPORT void wl_proxy_wrapper_destroy(void* proxy_wrapper);
+
 /* We need implement some missing functions from wayland-client-protocol.h
  */
 #ifndef WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM
diff -up firefox-69.0/widget/gtk/nsWaylandDisplay.cpp.mozilla-1580152 firefox-69.0/widget/gtk/nsWaylandDisplay.cpp
--- firefox-69.0/widget/gtk/nsWaylandDisplay.cpp.mozilla-1580152	2019-09-16 11:11:30.081299217 +0200
+++ firefox-69.0/widget/gtk/nsWaylandDisplay.cpp	2019-09-16 11:11:30.089299191 +0200
@@ -243,6 +243,61 @@ bool nsWaylandDisplay::DispatchEventQueu
   return true;
 }
 
+void nsWaylandDisplay::SyncEnd() {
+  wl_callback_destroy(mSyncCallback);
+  mSyncCallback = NULL;
+}
+
+static void wayland_sync_callback(void* data, struct wl_callback* callback,
+                                  uint32_t time) {
+  auto display = static_cast<nsWaylandDisplay*>(data);
+  display->SyncEnd();
+}
+
+static const struct wl_callback_listener sync_callback_listener = {
+    .done = wayland_sync_callback};
+
+void nsWaylandDisplay::SyncBegin() {
+  WaitForSyncEnd();
+
+  // Use wl_display_sync() to synchronize wayland events.
+  // See dri2_wl_swap_buffers_with_damage() from MESA
+  // or wl_display_roundtrip_queue() from wayland-client.
+  struct wl_display* displayWrapper =
+      static_cast<wl_display*>(wl_proxy_create_wrapper((void*)mDisplay));
+  if (!displayWrapper) {
+    NS_WARNING("Failed to create wl_proxy wrapper!");
+    return;
+  }
+
+  wl_proxy_set_queue((struct wl_proxy*)displayWrapper, mEventQueue);
+  mSyncCallback = wl_display_sync(displayWrapper);
+  wl_proxy_wrapper_destroy((void*)displayWrapper);
+
+  if (!mSyncCallback) {
+    NS_WARNING("Failed to create wl_display_sync callback!");
+    return;
+  }
+
+  wl_callback_add_listener(mSyncCallback, &sync_callback_listener, this);
+  wl_display_flush(mDisplay);
+}
+
+void nsWaylandDisplay::WaitForSyncEnd() {
+  // We're done here
+  if (!mSyncCallback) {
+    return;
+  }
+
+  while (mSyncCallback != NULL) {
+    if (wl_display_dispatch_queue(mDisplay, mEventQueue) == -1) {
+      NS_WARNING("wl_display_dispatch_queue failed!");
+      SyncEnd();
+      return;
+    }
+  }
+}
+
 bool nsWaylandDisplay::Matches(wl_display* aDisplay) {
   return mThreadId == PR_GetCurrentThread() && aDisplay == mDisplay;
 }
@@ -305,6 +360,7 @@ nsWaylandDisplay::nsWaylandDisplay(wl_di
       mSubcompositor(nullptr),
       mSeat(nullptr),
       mShm(nullptr),
+      mSyncCallback(nullptr),
       mPrimarySelectionDeviceManager(nullptr),
       mRegistry(nullptr),
       mGbmDevice(nullptr),
diff -up firefox-69.0/widget/gtk/nsWaylandDisplay.h.mozilla-1580152 firefox-69.0/widget/gtk/nsWaylandDisplay.h
--- firefox-69.0/widget/gtk/nsWaylandDisplay.h.mozilla-1580152	2019-09-16 11:11:30.081299217 +0200
+++ firefox-69.0/widget/gtk/nsWaylandDisplay.h	2019-09-16 11:11:30.089299191 +0200
@@ -41,6 +41,11 @@ class nsWaylandDisplay {
   virtual ~nsWaylandDisplay();
 
   bool DispatchEventQueue();
+
+  void SyncBegin();
+  void SyncEnd();
+  void WaitForSyncEnd();
+
   bool Matches(wl_display* aDisplay);
 
   MessageLoop* GetDispatcherThreadLoop() { return mDispatcherThreadLoop; }
@@ -90,6 +95,7 @@ class nsWaylandDisplay {
   wl_subcompositor* mSubcompositor;
   wl_seat* mSeat;
   wl_shm* mShm;
+  wl_callback* mSyncCallback;
   gtk_primary_selection_device_manager* mPrimarySelectionDeviceManager;
   wl_registry* mRegistry;
   zwp_linux_dmabuf_v1* mDmabuf;
diff -up firefox-69.0/widget/gtk/WindowSurfaceWayland.cpp.mozilla-1580152 firefox-69.0/widget/gtk/WindowSurfaceWayland.cpp
--- firefox-69.0/widget/gtk/WindowSurfaceWayland.cpp.mozilla-1580152	2019-09-16 11:11:30.086299200 +0200
+++ firefox-69.0/widget/gtk/WindowSurfaceWayland.cpp	2019-09-16 11:57:35.462193492 +0200
@@ -32,6 +32,9 @@ extern mozilla::LazyLogModule gWidgetWay
 #  define LOGWAYLAND(args)
 #endif /* MOZ_LOGGING */
 
+// Maximal compositin timeout it miliseconds
+#define COMPOSITING_TIMEOUT 200
+
 namespace mozilla {
 namespace widget {
 
@@ -198,6 +201,10 @@ available and gfx.wayland_dmabuf_backend
 #define BUFFER_BPP 4
 gfx::SurfaceFormat WindowBackBuffer::mFormat = gfx::SurfaceFormat::B8G8R8A8;
 
+nsWaylandDisplay* WindowBackBuffer::GetWaylandDisplay() {
+  return mWindowSurfaceWayland->GetWaylandDisplay();
+}
+
 int WaylandShmPool::CreateTemporaryFile(int aSize) {
   const char* tmppath = getenv("XDG_RUNTIME_DIR");
   MOZ_RELEASE_ASSERT(tmppath, "Missing XDG_RUNTIME_DIR env variable.");
@@ -342,10 +349,11 @@ void WindowBackBufferShm::Clear() {
   memset(mShmPool.GetImageData(), 0, mHeight * mWidth * BUFFER_BPP);
 }
 
-WindowBackBufferShm::WindowBackBufferShm(nsWaylandDisplay* aWaylandDisplay,
-                                         int aWidth, int aHeight)
-    : WindowBackBuffer(aWaylandDisplay),
-      mShmPool(aWaylandDisplay, aWidth * aHeight * BUFFER_BPP),
+WindowBackBufferShm::WindowBackBufferShm(
+    WindowSurfaceWayland* aWindowSurfaceWayland, int aWidth, int aHeight)
+    : WindowBackBuffer(aWindowSurfaceWayland),
+      mShmPool(aWindowSurfaceWayland->GetWaylandDisplay(),
+               aWidth * aHeight * BUFFER_BPP),
       mWaylandBuffer(nullptr),
       mWidth(aWidth),
       mHeight(aHeight),
@@ -387,6 +395,9 @@ void WindowBackBufferShm::Detach(wl_buff
               aBuffer ? wl_proxy_get_id((struct wl_proxy*)aBuffer) : -1));
 
   mAttached = false;
+
+  // Commit any potential cached drawings from latest Lock()/Commit() cycle.
+  mWindowSurfaceWayland->CommitWaylandBuffer();
 }
 
 bool WindowBackBufferShm::SetImageDataFromBuffer(
@@ -416,8 +427,8 @@ already_AddRefed<gfx::DrawTarget> Window
 }
 
 WindowBackBufferDMABuf::WindowBackBufferDMABuf(
-    nsWaylandDisplay* aWaylandDisplay, int aWidth, int aHeight)
-    : WindowBackBuffer(aWaylandDisplay) {
+    WindowSurfaceWayland* aWindowSurfaceWayland, int aWidth, int aHeight)
+    : WindowBackBuffer(aWindowSurfaceWayland) {
   mDMAbufSurface.Create(aWidth, aHeight);
   LOGWAYLAND(
       ("WindowBackBufferDMABuf::WindowBackBufferDMABuf [%p] Created DMABuf "
@@ -475,6 +486,9 @@ bool WindowBackBufferDMABuf::SetImageDat
 
 void WindowBackBufferDMABuf::Detach(wl_buffer* aBuffer) {
   mDMAbufSurface.WLBufferDetach();
+
+  // Commit any potential cached drawings from latest Lock()/Commit() cycle.
+  mWindowSurfaceWayland->CommitWaylandBuffer();
 }
 
 void WindowBackBufferDMABuf::Clear() { mDMAbufSurface.Clear(); }
@@ -496,10 +510,11 @@ WindowSurfaceWayland::WindowSurfaceWayla
       mWaylandBuffer(nullptr),
       mFrameCallback(nullptr),
       mLastCommittedSurface(nullptr),
-      mDisplayThreadMessageLoop(MessageLoop::current()),
       mDelayedCommitHandle(nullptr),
+      mLastCommitTime(0),
       mDrawToWaylandBufferDirectly(true),
-      mPendingCommit(false),
+      mBufferPendingCommit(false),
+      mBufferCommitAllowed(false),
       mWholeWindowBufferDamage(false),
       mBufferNeedsClear(false),
       mIsMainThread(NS_IsMainThread()),
@@ -508,7 +523,7 @@ WindowSurfaceWayland::WindowSurfaceWayla
 }
 
 WindowSurfaceWayland::~WindowSurfaceWayland() {
-  if (mPendingCommit) {
+  if (mBufferPendingCommit) {
     NS_WARNING("Deleted WindowSurfaceWayland with a pending commit!");
   }
 
@@ -547,7 +562,7 @@ WindowBackBuffer* WindowSurfaceWayland::
   if (UseDMABufBackend()) {
     static bool sDMABufBufferCreated = false;
     WindowBackBuffer* buffer =
-        new WindowBackBufferDMABuf(mWaylandDisplay, aWidth, aHeight);
+        new WindowBackBufferDMABuf(this, aWidth, aHeight);
     if (buffer) {
       sDMABufBufferCreated = true;
       return buffer;
@@ -564,7 +579,7 @@ WindowBackBuffer* WindowSurfaceWayland::
     }
   }
 
-  return new WindowBackBufferShm(mWaylandDisplay, aWidth, aHeight);
+  return new WindowBackBufferShm(this, aWidth, aHeight);
 }
 
 WindowBackBuffer* WindowSurfaceWayland::GetWaylandBufferToDraw(
@@ -675,6 +690,11 @@ already_AddRefed<gfx::DrawTarget> Window
               (void*)this, (void*)buffer));
 
   if (!buffer) {
+    if (mLastCommitTime && (g_get_monotonic_time() / 1000) - mLastCommitTime >
+                               COMPOSITING_TIMEOUT) {
+      NS_WARNING(
+          "Slow response from Wayland compositor, visual glitches ahead.");
+    }
     return nullptr;
   }
 
@@ -724,10 +744,9 @@ static bool IsPopupFullScreenUpdate(Layo
   // box is equal to window borders.
   if (aRegion.GetNumRects() > 2) return false;
 
-  gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect();
-  gfx::IntSize lockSize(bounds.XMost(), bounds.YMost());
-
-  return (screenRect.width == lockSize.width &&
+  IntRect lockSize = aRegion.GetBounds().ToUnknownRect();
+  return (lockSize.x == 0 && lockSize.y == 0 &&
+          screenRect.width == lockSize.width &&
           screenRect.height == lockSize.height);
 }
 
@@ -738,8 +757,7 @@ static bool IsPopupFullScreenUpdate(Layo
      to clip/buffer the drawing and we can return wl_buffer directly
      for drawing.
        - mWaylandBuffer is available - that's an ideal situation.
-       - mWaylandBuffer is locked by compositor - flip buffers and draw.
-          - if we can't flip buffers - go B)
+       - mWaylandBuffer is locked by compositor - go B)
 
   B) Lock() is requested for part(s) of screen. We need to provide temporary
      surface to draw into and copy result (clipped) to target wl_surface.
@@ -747,14 +765,17 @@ static bool IsPopupFullScreenUpdate(Layo
 already_AddRefed<gfx::DrawTarget> WindowSurfaceWayland::Lock(
     const LayoutDeviceIntRegion& aRegion) {
   MOZ_ASSERT(mIsMainThread == NS_IsMainThread());
-  
-  // Disable all commits from frame callback handler and delayed comit handler
-  // as we're updated by gecko compositor.
-  mPendingCommit = false;
+
+  // Wait until all pending events are processed. There may be queued
+  // wl_buffer release event which releases our wl_buffer for further rendering.
+  mWaylandDisplay->WaitForSyncEnd();
+
+  // Disable all commits (from potential frame callback/delayed handlers)
+  // until next WindowSurfaceWayland::Commit() call.
+  mBufferCommitAllowed = false;
 
   LayoutDeviceIntRect lockedScreenRect = mWindow->GetBounds();
-  gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect();
-  gfx::IntSize lockSize(bounds.XMost(), bounds.YMost());
+  gfx::IntRect lockSize = aRegion.GetBounds().ToUnknownRect();
 
   // Are we asked for entire nsWindow to draw?
   bool isTransparentPopup =
@@ -775,10 +796,10 @@ already_AddRefed<gfx::DrawTarget> Window
   }
 
   LOGWAYLAND(
-      ("WindowSurfaceWayland::Lock [%p] lockSize [%d x %d] windowSize [%d x "
-       "%d]\n",
-       (void*)this, lockSize.width, lockSize.height, lockedScreenRect.width,
-       lockedScreenRect.height));
+      ("WindowSurfaceWayland::Lock [%p] [%d,%d] -> [%d x %d] rects %d "
+       "windowSize [%d x %d]\n",
+       (void*)this, lockSize.x, lockSize.y, lockSize.width, lockSize.height,
+       aRegion.GetNumRects(), lockedScreenRect.width, lockedScreenRect.height));
   LOGWAYLAND(("   nsWindow = %p\n", mWindow));
   LOGWAYLAND(("   isPopup = %d\n", mWindow->IsWaylandPopup()));
   LOGWAYLAND(("   isTransparentPopup = %d\n", isTransparentPopup));
@@ -789,7 +810,7 @@ already_AddRefed<gfx::DrawTarget> Window
   LOGWAYLAND(("   mBufferNeedsClear = %d\n", mBufferNeedsClear));
   LOGWAYLAND(("   mWholeWindowBufferDamage = %d\n", mWholeWindowBufferDamage));
 
-#if DEBUG
+#if MOZ_LOGGING
   if (!(mBufferScreenRect == lockedScreenRect)) {
     LOGWAYLAND(("   screen size changed\n"));
   }
@@ -836,7 +857,7 @@ already_AddRefed<gfx::DrawTarget> Window
   mDrawToWaylandBufferDirectly = false;
 
   LOGWAYLAND(("   Indirect drawing.\n"));
-  return LockImageSurface(lockSize);
+  return LockImageSurface(gfx::IntSize(lockSize.XMost(), lockSize.YMost()));
 }
 
 void WindowImageSurface::Draw(gfx::SourceSurface* aSurface,
@@ -875,34 +896,42 @@ WindowImageSurface::WindowImageSurface(
       mImageSurface->Format());
 }
 
+void WindowSurfaceWayland::CacheImageSurface(
+    const LayoutDeviceIntRegion& aRegion) {
+#ifdef MOZ_LOGGING
+  gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect();
+  LOGWAYLAND(("WindowSurfaceWayland::CacheImageSurface [%p]\n", (void*)this));
+  LOGWAYLAND(("    rects num %d\n", aRegion.GetNumRects()));
+  LOGWAYLAND(("    bounds [ %d, %d] -> [%d x %d]\n", bounds.x, bounds.y,
+              bounds.width, bounds.height));
+#endif
+
+  mDelayedImageCommits.AppendElement(
+      WindowImageSurface(mImageSurface, aRegion));
+  // mImageSurface is owned by mDelayedImageCommits
+  mImageSurface = nullptr;
+
+  LOGWAYLAND(
+      ("    There's %d cached images\n", int(mDelayedImageCommits.Length())));
+}
+
 void WindowSurfaceWayland::DrawDelayedImageCommits(
     gfx::DrawTarget* aDrawTarget, LayoutDeviceIntRegion& aWaylandBufferDamage) {
+  LOGWAYLAND(
+      ("WindowSurfaceWayland::DrawDelayedImageCommits [%p]\n", (void*)this));
+
   for (unsigned int i = 0; i < mDelayedImageCommits.Length(); i++) {
     mDelayedImageCommits[i].Draw(aDrawTarget, aWaylandBufferDamage);
   }
   mDelayedImageCommits.Clear();
 }
 
-bool WindowSurfaceWayland::CommitImageSurfaceToWaylandBuffer(
-    const LayoutDeviceIntRegion& aRegion,
-    LayoutDeviceIntRegion& aWaylandBufferDamage) {
-  MOZ_ASSERT(!mDrawToWaylandBufferDirectly);
-
-#ifdef DEBUG
-  gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect();
-  gfx::Rect rect(bounds);
-  MOZ_ASSERT(!rect.IsEmpty(), "Empty drawing?");
-#endif
-
-  LOGWAYLAND(
-      ("WindowSurfaceWayland::CommitImageSurfaceToWaylandBuffer [%p] "
-       "screenSize [%d x %d]\n",
-       (void*)this, mBufferScreenRect.width, mBufferScreenRect.height));
+bool WindowSurfaceWayland::CommitImageCacheToWaylandBuffer() {
+  if (!mDelayedImageCommits.Length()) {
+    return false;
+  }
 
-  mDelayedImageCommits.AppendElement(
-      WindowImageSurface(mImageSurface, aRegion));
-  // mImageSurface is owned by mDelayedImageCommits
-  mImageSurface = nullptr;
+  MOZ_ASSERT(!mDrawToWaylandBufferDirectly);
 
   RefPtr<gfx::DrawTarget> dt = LockWaylandBuffer(
       /* aCanSwitchBuffer */ mWholeWindowBufferDamage);
@@ -911,10 +940,10 @@ bool WindowSurfaceWayland::CommitImageSu
   }
 
   LOGWAYLAND(("   Flushing %ld cached WindowImageSurfaces to Wayland buffer\n",
-              long(mDelayedImageCommits.Length() + 1)));
+              long(mDelayedImageCommits.Length())));
 
   // Draw any delayed image commits first
-  DrawDelayedImageCommits(dt, aWaylandBufferDamage);
+  DrawDelayedImageCommits(dt, mWaylandBufferDamage);
   UnlockWaylandBuffer();
 
   return true;
@@ -932,7 +961,8 @@ static void WaylandBufferDelayCommitHand
 }
 
 void WindowSurfaceWayland::CommitWaylandBuffer() {
-  MOZ_ASSERT(mPendingCommit, "Committing empty surface!");
+  MOZ_ASSERT(!mWaylandBuffer->IsAttached(),
+             "We can't draw to attached wayland buffer!");
 
   LOGWAYLAND(("WindowSurfaceWayland::CommitWaylandBuffer [%p]\n", (void*)this));
   LOGWAYLAND(
@@ -941,6 +971,21 @@ void WindowSurfaceWayland::CommitWayland
   LOGWAYLAND(("   mDelayedCommitHandle = %p\n", mDelayedCommitHandle));
   LOGWAYLAND(("   mFrameCallback = %p\n", mFrameCallback));
   LOGWAYLAND(("   mLastCommittedSurface = %p\n", mLastCommittedSurface));
+  LOGWAYLAND(("   mBufferPendingCommit = %d\n", mBufferPendingCommit));
+  LOGWAYLAND(("   mBufferCommitAllowed = %d\n", mBufferCommitAllowed));
+
+  if (!mBufferCommitAllowed) {
+    return;
+  }
+
+  if (CommitImageCacheToWaylandBuffer()) {
+    mBufferPendingCommit = true;
+  }
+
+  // There's nothing to do here
+  if (!mBufferPendingCommit) {
+    return;
+  }
 
   wl_surface* waylandSurface = mWindow->GetWaylandSurface();
   if (!waylandSurface) {
@@ -986,6 +1031,7 @@ void WindowSurfaceWayland::CommitWayland
   }
 
   if (mWholeWindowBufferDamage) {
+    LOGWAYLAND(("   send whole screen damage\n"));
     wl_surface_damage(waylandSurface, 0, 0, mBufferScreenRect.width,
                       mBufferScreenRect.height);
     mWholeWindowBufferDamage = false;
@@ -994,6 +1040,8 @@ void WindowSurfaceWayland::CommitWayland
     for (auto iter = mWaylandBufferDamage.RectIter(); !iter.Done();
          iter.Next()) {
       mozilla::LayoutDeviceIntRect r = iter.Get();
+      LOGWAYLAND(("   wl_surface_damage_buffer [%d, %d] -> [%d, %d]\n", r.x,
+                  r.y, r.width, r.height));
       wl_surface_damage_buffer(waylandSurface, r.x, r.y, r.width, r.height);
     }
   }
@@ -1012,24 +1060,31 @@ void WindowSurfaceWayland::CommitWayland
 
   mWaylandBuffer->Attach(waylandSurface);
   mLastCommittedSurface = waylandSurface;
+  mLastCommitTime = g_get_monotonic_time() / 1000;
+
+  // Ask wl_display to start events synchronization. We're going wait
+  // until all events are processed before next WindowSurfaceWayland::Lock()
+  // as we need freed wl_buffer there.
+  mWaylandDisplay->SyncBegin();
 
   // There's no pending commit, all changes are sent to compositor.
-  mPendingCommit = false;
+  mBufferPendingCommit = false;
 }
 
 void WindowSurfaceWayland::Commit(const LayoutDeviceIntRegion& aInvalidRegion) {
   MOZ_ASSERT(mIsMainThread == NS_IsMainThread());
 
-#ifdef DEBUG
-  {
-    gfx::IntRect bounds = aInvalidRegion.GetBounds().ToUnknownRect();
-    gfx::IntSize lockSize(bounds.XMost(), bounds.YMost());
+  // Flush all waiting events explicitly as we need
+  // mWaylandDisplay->FlushEventQueue();
 
+#ifdef MOZ_LOGGING
+  {
+    gfx::IntRect lockSize = aInvalidRegion.GetBounds().ToUnknownRect();
     LOGWAYLAND(
-        ("WindowSurfaceWayland::Commit [%p] lockSize [%d x %d] screenSize [%d "
-         "x %d]\n",
-         (void*)this, lockSize.width, lockSize.height, mBufferScreenRect.width,
-         mBufferScreenRect.height));
+        ("WindowSurfaceWayland::Commit [%p] damage size [%d, %d] -> [%d x %d]"
+         "screenSize [%d x %d]\n",
+         (void*)this, lockSize.x, lockSize.y, lockSize.width, lockSize.height,
+         mBufferScreenRect.width, mBufferScreenRect.height));
     LOGWAYLAND(("    mDrawToWaylandBufferDirectly = %d\n",
                 mDrawToWaylandBufferDirectly));
     LOGWAYLAND(
@@ -1044,21 +1099,15 @@ void WindowSurfaceWayland::Commit(const
       mWaylandBufferDamage.OrWith(aInvalidRegion);
     }
     UnlockWaylandBuffer();
-    mPendingCommit = true;
+    mBufferPendingCommit = true;
   } else {
     MOZ_ASSERT(!mWaylandBuffer->IsLocked(),
                "Drawing to already locked buffer?");
-    if (CommitImageSurfaceToWaylandBuffer(aInvalidRegion,
-                                          mWaylandBufferDamage)) {
-      // Our cached drawing is flushed, we can draw fullscreen again.
-      mDrawToWaylandBufferDirectly = true;
-      mPendingCommit = true;
-    }
+    CacheImageSurface(aInvalidRegion);
   }
 
-  if (mPendingCommit) {
-    CommitWaylandBuffer();
-  }
+  mBufferCommitAllowed = true;
+  CommitWaylandBuffer();
 }
 
 void WindowSurfaceWayland::FrameCallbackHandler() {
@@ -1074,9 +1123,7 @@ void WindowSurfaceWayland::FrameCallback
   wl_callback_destroy(mFrameCallback);
   mFrameCallback = nullptr;
 
-  if (mPendingCommit) {
-    CommitWaylandBuffer();
-  }
+  CommitWaylandBuffer();
 }
 
 void WindowSurfaceWayland::DelayedCommitHandler() {
@@ -1089,9 +1136,7 @@ void WindowSurfaceWayland::DelayedCommit
   free(mDelayedCommitHandle);
   mDelayedCommitHandle = nullptr;
 
-  if (mPendingCommit) {
-    CommitWaylandBuffer();
-  }
+  CommitWaylandBuffer();
 }
 
 }  // namespace widget
diff -up firefox-69.0/widget/gtk/WindowSurfaceWayland.h.mozilla-1580152 firefox-69.0/widget/gtk/WindowSurfaceWayland.h
--- firefox-69.0/widget/gtk/WindowSurfaceWayland.h.mozilla-1580152	2019-09-16 11:11:30.080299221 +0200
+++ firefox-69.0/widget/gtk/WindowSurfaceWayland.h	2019-09-16 11:11:30.090299187 +0200
@@ -17,6 +17,8 @@
 namespace mozilla {
 namespace widget {
 
+class WindowSurfaceWayland;
+
 // Allocates and owns shared memory for Wayland drawing surface
 class WaylandShmPool {
  public:
@@ -69,20 +71,22 @@ class WindowBackBuffer {
 
   static gfx::SurfaceFormat GetSurfaceFormat() { return mFormat; }
 
-  nsWaylandDisplay* GetWaylandDisplay() { return mWaylandDisplay; };
+  nsWaylandDisplay* GetWaylandDisplay();
 
-  WindowBackBuffer(nsWaylandDisplay* aWaylandDisplay)
-      : mWaylandDisplay(aWaylandDisplay){};
+  WindowBackBuffer(WindowSurfaceWayland* aWindowSurfaceWayland)
+      : mWindowSurfaceWayland(aWindowSurfaceWayland){};
   virtual ~WindowBackBuffer(){};
 
+ protected:
+  WindowSurfaceWayland* mWindowSurfaceWayland;
+
  private:
   static gfx::SurfaceFormat mFormat;
-  nsWaylandDisplay* mWaylandDisplay;
 };
 
 class WindowBackBufferShm : public WindowBackBuffer {
  public:
-  WindowBackBufferShm(nsWaylandDisplay* aWaylandDisplay, int aWidth,
+  WindowBackBufferShm(WindowSurfaceWayland* aWindowSurfaceWayland, int aWidth,
                       int aHeight);
   ~WindowBackBufferShm();
 
@@ -121,8 +125,8 @@ class WindowBackBufferShm : public Windo
 
 class WindowBackBufferDMABuf : public WindowBackBuffer {
  public:
-  WindowBackBufferDMABuf(nsWaylandDisplay* aWaylandDisplay, int aWidth,
-                         int aHeight);
+  WindowBackBufferDMABuf(WindowSurfaceWayland* aWindowSurfaceWayland,
+                         int aWidth, int aHeight);
   ~WindowBackBufferDMABuf();
 
   bool IsAttached();
@@ -175,6 +179,9 @@ class WindowSurfaceWayland : public Wind
   void Commit(const LayoutDeviceIntRegion& aInvalidRegion) final;
   void FrameCallbackHandler();
   void DelayedCommitHandler();
+  void CommitWaylandBuffer();
+
+  nsWaylandDisplay* GetWaylandDisplay() { return mWaylandDisplay; };
 
  private:
   WindowBackBuffer* CreateWaylandBuffer(int aWidth, int aHeight);
@@ -185,10 +192,9 @@ class WindowSurfaceWayland : public Wind
 
   already_AddRefed<gfx::DrawTarget> LockImageSurface(
       const gfx::IntSize& aLockSize);
-  bool CommitImageSurfaceToWaylandBuffer(
-      const LayoutDeviceIntRegion& aRegion,
-      LayoutDeviceIntRegion& aWaylandBufferDamage);
-  void CommitWaylandBuffer();
+
+  void CacheImageSurface(const LayoutDeviceIntRegion& aRegion);
+  bool CommitImageCacheToWaylandBuffer();
 
   void DrawDelayedImageCommits(gfx::DrawTarget* aDrawTarget,
                                LayoutDeviceIntRegion& aWaylandBufferDamage);
@@ -205,12 +211,13 @@ class WindowSurfaceWayland : public Wind
   WindowBackBuffer* mBackupBuffer[BACK_BUFFER_NUM];
   wl_callback* mFrameCallback;
   wl_surface* mLastCommittedSurface;
-  MessageLoop* mDisplayThreadMessageLoop;
   WindowSurfaceWayland** mDelayedCommitHandle;
   RefPtr<gfxImageSurface> mImageSurface;
   AutoTArray<WindowImageSurface, 30> mDelayedImageCommits;
+  int64_t mLastCommitTime;
   bool mDrawToWaylandBufferDirectly;
-  bool mPendingCommit;
+  bool mBufferPendingCommit;
+  bool mBufferCommitAllowed;
   bool mWholeWindowBufferDamage;
   bool mBufferNeedsClear;
   bool mIsMainThread;