Bug 1498499 - [Wayland] Implement triple buffering at Wayland, r=jhorak
authorMartin Stransky <stransky@redhat.com>
Thu, 18 Oct 2018 14:30:21 +0000
changeset 441944 b815b16f74a14ce0173bae0000f47ebf5e277e17
parent 441943 1635530c393a0f80512a3cf695fe968eb53562f2
child 441945 545ff4f7bc5ca0cd013eda97efb96e5a5759c810
push id34880
push usercsabou@mozilla.com
push dateThu, 18 Oct 2018 21:53:44 +0000
treeherdermozilla-central@7b0a8e47d256 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjhorak
bugs1498499
milestone64.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 1498499 - [Wayland] Implement triple buffering at Wayland, r=jhorak Differential Revision: https://phabricator.services.mozilla.com/D8849
widget/gtk/WindowSurfaceWayland.cpp
widget/gtk/WindowSurfaceWayland.h
--- a/widget/gtk/WindowSurfaceWayland.cpp
+++ b/widget/gtk/WindowSurfaceWayland.cpp
@@ -558,27 +558,28 @@ frame_callback_handler(void *data, struc
 static const struct wl_callback_listener frame_listener = {
   frame_callback_handler
 };
 
 WindowSurfaceWayland::WindowSurfaceWayland(nsWindow *aWindow)
   : mWindow(aWindow)
   , mWaylandDisplay(WaylandDisplayGet(aWindow->GetWaylandDisplay()))
   , mWaylandBuffer(nullptr)
-  , mBackupBuffer(nullptr)
   , mFrameCallback(nullptr)
   , mLastCommittedSurface(nullptr)
   , mDisplayThreadMessageLoop(MessageLoop::current())
   , mDelayedCommitHandle(nullptr)
   , mDrawToWaylandBufferDirectly(true)
   , mPendingCommit(false)
   , mWaylandBufferFullScreenDamage(false)
   , mIsMainThread(NS_IsMainThread())
   , mNeedScaleFactorUpdate(true)
 {
+  for (int i = 0; i < BACK_BUFFER_NUM; i++)
+    mBackupBuffer[i] = nullptr;
 }
 
 WindowSurfaceWayland::~WindowSurfaceWayland()
 {
   if (mPendingCommit) {
     NS_WARNING("Deleted WindowSurfaceWayland with a pending commit!");
   }
 
@@ -589,17 +590,22 @@ WindowSurfaceWayland::~WindowSurfaceWayl
     *mDelayedCommitHandle = nullptr;
   }
 
   if (mFrameCallback) {
     wl_callback_destroy(mFrameCallback);
   }
 
   delete mWaylandBuffer;
-  delete mBackupBuffer;
+
+  for (int i = 0; i < BACK_BUFFER_NUM; i++) {
+    if (mBackupBuffer[i]) {
+      delete mBackupBuffer[i];
+    }
+  }
 
   if (!mIsMainThread) {
     // We can be destroyed from main thread even though we was created/used
     // in compositor thread. We have to unref/delete WaylandDisplay in compositor
     // thread then and we can't use MessageLoop::current() here.
     mDisplayThreadMessageLoop->PostTask(
       NewRunnableFunction("WaylandDisplayRelease",
                           &WaylandDisplayRelease,
@@ -609,48 +615,61 @@ WindowSurfaceWayland::~WindowSurfaceWayl
   }
 }
 
 WindowBackBuffer*
 WindowSurfaceWayland::GetWaylandBufferToDraw(int aWidth, int aHeight)
 {
   if (!mWaylandBuffer) {
     mWaylandBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight);
-    mBackupBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight);
     return mWaylandBuffer;
   }
 
   if (!mWaylandBuffer->IsAttached()) {
     if (!mWaylandBuffer->IsMatchingSize(aWidth, aHeight)) {
       mWaylandBuffer->Resize(aWidth, aHeight);
       // There's a chance that scale factor has been changed
       // when buffer size changed
       mNeedScaleFactorUpdate = true;
     }
     return mWaylandBuffer;
   }
 
-  // Front buffer is used by compositor, draw to back buffer
-  if (mBackupBuffer->IsAttached()) {
+  MOZ_ASSERT(!mPendingCommit,
+             "Uncommitted buffer switch, screen artifacts ahead.");
+
+  // Front buffer is used by compositor, select a back buffer
+  int availableBuffer;
+  for (availableBuffer = 0; availableBuffer < BACK_BUFFER_NUM;
+       availableBuffer++) {
+    if (!mBackupBuffer[availableBuffer]) {
+      mBackupBuffer[availableBuffer] =
+          new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight);
+      break;
+    }
+
+    if (!mBackupBuffer[availableBuffer]->IsAttached()) {
+      break;
+    }
+  }
+
+  if (MOZ_UNLIKELY(availableBuffer == BACK_BUFFER_NUM)) {
     NS_WARNING("No drawing buffer available");
     return nullptr;
   }
 
-  MOZ_ASSERT(!mPendingCommit,
-             "Uncommitted buffer switch, screen artifacts ahead.");
+  WindowBackBuffer *lastWaylandBuffer = mWaylandBuffer;
+  mWaylandBuffer = mBackupBuffer[availableBuffer];
+  mBackupBuffer[availableBuffer] = lastWaylandBuffer;
 
-  WindowBackBuffer *tmp = mWaylandBuffer;
-  mWaylandBuffer = mBackupBuffer;
-  mBackupBuffer = tmp;
-
-  if (mBackupBuffer->IsMatchingSize(aWidth, aHeight)) {
+  if (lastWaylandBuffer->IsMatchingSize(aWidth, aHeight)) {
     // Former front buffer has the same size as a requested one.
     // Gecko may expect a content already drawn on screen so copy
     // existing data to the new buffer.
-    mWaylandBuffer->SetImageDataFromBuffer(mBackupBuffer);
+    mWaylandBuffer->SetImageDataFromBuffer(lastWaylandBuffer);
     // When buffer switches we need to damage whole screen
     // (https://bugzilla.redhat.com/show_bug.cgi?id=1418260)
     mWaylandBufferFullScreenDamage = true;
   } else {
     // Former buffer has different size from the new request. Only resize
     // the new buffer and leave gecko to render new whole content.
     mWaylandBuffer->Resize(aWidth, aHeight);
   }
--- a/widget/gtk/WindowSurfaceWayland.h
+++ b/widget/gtk/WindowSurfaceWayland.h
@@ -5,16 +5,18 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_WAYLAND_H
 #define _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_WAYLAND_H
 
 #include <prthread.h>
 #include "mozilla/gfx/Types.h"
 
+#define  BACK_BUFFER_NUM 2
+
 namespace mozilla {
 namespace widget {
 
 // Our general connection to Wayland display server,
 // holds our display connection and runs event loop.
 class nsWaylandDisplay : public nsISupports {
   NS_DECL_THREADSAFE_ISUPPORTS
 
@@ -121,17 +123,17 @@ private:
   bool                      CommitImageSurfaceToWaylandBuffer(const LayoutDeviceIntRegion& aRegion);
   void                      CommitWaylandBuffer();
 
   // TODO: Do we need to hold a reference to nsWindow object?
   nsWindow*                 mWindow;
   nsWaylandDisplay*         mWaylandDisplay;
   WindowBackBuffer*         mWaylandBuffer;
   LayoutDeviceIntRegion     mWaylandBufferDamage;
-  WindowBackBuffer*         mBackupBuffer;
+  WindowBackBuffer*         mBackupBuffer[BACK_BUFFER_NUM];
   RefPtr<gfxImageSurface>   mImageSurface;
   wl_callback*              mFrameCallback;
   wl_surface*               mLastCommittedSurface;
   MessageLoop*              mDisplayThreadMessageLoop;
   WindowSurfaceWayland**    mDelayedCommitHandle;
   bool                      mDrawToWaylandBufferDirectly;
   bool                      mPendingCommit;
   bool                      mWaylandBufferFullScreenDamage;