Bug 1577024 - [Wayland] Enable experimental wayland backend modes by widget.wayland_cache_mode pref, r=jhorak
authorMartin Stransky <stransky@redhat.com>
Sat, 31 Aug 2019 00:19:03 +0300
changeset 551537 893a4487b58644284f8eace41f7604d370eacc93
parent 551536 c8ec40f7e5d5c4fe8e14a292caf353fbfe708d42
child 551538 2ce54fbea7dc53831e822d3af55871a4117b9629
push id11865
push userbtara@mozilla.com
push dateMon, 02 Sep 2019 08:54:37 +0000
treeherdermozilla-beta@37f59c4671b3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjhorak
bugs1577024
milestone70.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 1577024 - [Wayland] Enable experimental wayland backend modes by widget.wayland_cache_mode pref, r=jhorak Image cache mode can be set by widget.wayland_cache_mode. - widget.wayland_cache_mode = 0 (or missing): Cache and clip all drawings, default. It's slowest but also without any rendered artifacts. - widget.wayland_cache_mode = 1: Cache drawing only when back buffer is missing. May produce some rendering artifacts and flickering when partial screen update is rendered. - widget.wayland_cache_mode = 2: Don't cache anything, draw only when back buffer is available. Suitable for fullscreen content only like fullscreen video playback and may work well with dmabuf backend. Differential Revision: https://phabricator.services.mozilla.com/D43681
widget/gtk/WindowSurfaceWayland.cpp
widget/gtk/WindowSurfaceWayland.h
widget/gtk/nsWaylandDisplay.cpp
widget/gtk/nsWaylandDisplay.h
--- a/widget/gtk/WindowSurfaceWayland.cpp
+++ b/widget/gtk/WindowSurfaceWayland.cpp
@@ -184,17 +184,17 @@ handle to wayland compositor by WindowBa
 
 WindowBackBufferDMABuf
 
 It's WindowBackBuffer implementation based on DMA Buffer.
 It owns wl_buffer object, owns WaylandDMABufSurface
 (which provides the DMA Buffer) and ties them together.
 
 WindowBackBufferDMABuf backend is used only when WaylandDMABufSurface is
-available and gfx.wayland_dmabuf_backend.enabled preference is set.
+available and widget.wayland_dmabuf_backend.enabled preference is set.
 
 */
 
 #define EVENT_LOOP_DELAY (1000 / 240)
 
 #define BUFFER_BPP 4
 gfx::SurfaceFormat WindowBackBuffer::mFormat = gfx::SurfaceFormat::B8G8R8A8;
 
@@ -499,16 +499,18 @@ WindowSurfaceWayland::WindowSurfaceWayla
       mDelayedCommitHandle(nullptr),
       mDrawToWaylandBufferDirectly(true),
       mPendingCommit(false),
       mWholeWindowBufferDamage(false),
       mBufferNeedsClear(false),
       mIsMainThread(NS_IsMainThread()),
       mNeedScaleFactorUpdate(true) {
   for (int i = 0; i < BACK_BUFFER_NUM; i++) mBackupBuffer[i] = nullptr;
+  mRenderingCacheMode = static_cast<RenderingCacheMode>(
+      mWaylandDisplay->GetRenderingCacheModePref());
 }
 
 WindowSurfaceWayland::~WindowSurfaceWayland() {
   if (mPendingCommit) {
     NS_WARNING("Deleted WindowSurfaceWayland with a pending commit!");
   }
 
   if (mDelayedCommitHandle) {
@@ -805,31 +807,52 @@ already_AddRefed<gfx::DrawTarget> Window
       // This should not happen. Screen size changed but we got only
       // partal screen update instead of whole screen. Discard this painting
       // as it produces artifacts.
       return nullptr;
     }
     mBufferScreenRect = lockedScreenRect;
   }
 
-  if (mWholeWindowBufferDamage) {
+  if (mWholeWindowBufferDamage || mRenderingCacheMode != CACHE_ALL) {
     // We can lock/commit entire buffer direcly.
     mDrawToWaylandBufferDirectly = true;
+  }
 
+  if (mDrawToWaylandBufferDirectly) {
     // If there's any pending image commit scratch them as we're going
     // to redraw the whole sceen anyway.
     mDelayedImageCommits.Clear();
 
     RefPtr<gfx::DrawTarget> dt = LockWaylandBuffer(
         /* aCanSwitchBuffer */ mWholeWindowBufferDamage);
     if (dt) {
+      // TODO: Try to set clip regions according to given area provided by
+      // compositor, not sure it has any effect. Also disable when drawing
+      // without any cache to speed up rendering.
+      if (!mWholeWindowBufferDamage && mRenderingCacheMode != CACHE_NONE) {
+        uint32_t numRects = aRegion.GetNumRects();
+        if (numRects != 1) {
+          AutoTArray<IntRect, 32> rects;
+          rects.SetCapacity(numRects);
+          for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
+            rects.AppendElement(iter.Get().ToUnknownRect());
+          }
+          dt->PushDeviceSpaceClipRects(rects.Elements(), rects.Length());
+        }
+      }
       return dt.forget();
     }
   }
 
+  // Any caching is disabled and we don't have any back buffer available.
+  if (mRenderingCacheMode == CACHE_NONE) {
+    return nullptr;
+  }
+
   // We do indirect drawing due to:
   //
   // 1) We don't have any front buffer available. Try indirect drawing
   //    to mImageSurface which is mirrored to front buffer at commit.
   // 2) Only part of the screen is locked. We can't lock entire screen for
   //    such drawing as it produces visible artifacts.
   mDrawToWaylandBufferDirectly = false;
 
--- a/widget/gtk/WindowSurfaceWayland.h
+++ b/widget/gtk/WindowSurfaceWayland.h
@@ -170,16 +170,31 @@ class WindowSurfaceWayland : public Wind
   ~WindowSurfaceWayland();
 
   already_AddRefed<gfx::DrawTarget> Lock(
       const LayoutDeviceIntRegion& aRegion) override;
   void Commit(const LayoutDeviceIntRegion& aInvalidRegion) final;
   void FrameCallbackHandler();
   void DelayedCommitHandler();
 
+  // Image cache mode can be set by widget.wayland_cache_mode
+  typedef enum {
+    // Cache and clip all drawings, default. It's slowest
+    // but also without any rendered artifacts.
+    CACHE_ALL = 0,
+    // Cache drawing only when back buffer is missing. May produce
+    // some rendering artifacts and flickering when partial screen update
+    // is rendered.
+    CACHE_MISSING = 1,
+    // Don't cache anything, draw only when back buffer is available.
+    // Suitable for fullscreen content only like fullscreen video playback and
+    // may work well with dmabuf backend.
+    CACHE_NONE = 2
+  } RenderingCacheMode;
+
  private:
   WindowBackBuffer* CreateWaylandBuffer(int aWidth, int aHeight);
   WindowBackBuffer* GetWaylandBufferToDraw(bool aCanSwitchBuffer);
 
   already_AddRefed<gfx::DrawTarget> LockWaylandBuffer(bool aCanSwitchBuffer);
   void UnlockWaylandBuffer();
 
   already_AddRefed<gfx::DrawTarget> LockImageSurface(
@@ -210,16 +225,17 @@ class WindowSurfaceWayland : public Wind
   RefPtr<gfxImageSurface> mImageSurface;
   AutoTArray<WindowImageSurface, 30> mDelayedImageCommits;
   bool mDrawToWaylandBufferDirectly;
   bool mPendingCommit;
   bool mWholeWindowBufferDamage;
   bool mBufferNeedsClear;
   bool mIsMainThread;
   bool mNeedScaleFactorUpdate;
+  RenderingCacheMode mRenderingCacheMode;
 
   static bool UseDMABufBackend();
   static bool mUseDMABufInitialized;
   static bool mUseDMABuf;
 };
 
 }  // namespace widget
 }  // namespace mozilla
--- a/widget/gtk/nsWaylandDisplay.cpp
+++ b/widget/gtk/nsWaylandDisplay.cpp
@@ -8,20 +8,25 @@
 #include "nsWaylandDisplay.h"
 
 namespace mozilla {
 namespace widget {
 
 #define GBMLIB_NAME "libgbm.so.1"
 #define DRMLIB_NAME "libdrm.so.2"
 
+#define DMABUF_PREF "widget.wayland_dmabuf_backend.enabled"
+// See WindowSurfaceWayland::RenderingCacheMode for details.
+#define CACHE_MODE_PREF "widget.wayland_cache_mode"
+
 bool nsWaylandDisplay::mIsDMABufEnabled = false;
 // -1 mean the pref was not loaded yet
 int nsWaylandDisplay::mIsDMABufPrefState = -1;
 bool nsWaylandDisplay::mIsDMABufConfigured = false;
+int nsWaylandDisplay::mRenderingCacheModePref = -1;
 
 wl_display* WaylandDisplayGetWLDisplay(GdkDisplay* aGdkDisplay) {
   if (!aGdkDisplay) {
     aGdkDisplay = gdk_display_get_default();
   }
 
   // Available as of GTK 3.8+
   static auto sGdkWaylandDisplayGetWlDisplay = (wl_display * (*)(GdkDisplay*))
@@ -312,24 +317,25 @@ nsWaylandDisplay::nsWaylandDisplay(wl_di
       mXRGBFormat({false, false, -1, nullptr, 0}),
       mARGBFormat({false, false, -1, nullptr, 0}),
       mGdmConfigured(false),
       mExplicitSync(false) {
   mRegistry = wl_display_get_registry(mDisplay);
   wl_registry_add_listener(mRegistry, &registry_listener, this);
 
   if (NS_IsMainThread()) {
-    // We can't load the preference from compositor/render thread,
-    // only from main one. So we can't call it directly from
-    // nsWaylandDisplay::IsDMABufEnabled() as it can be called from various
-    // threads.
+    // We can't load the preference from compositor/render thread
+    // so load all Wayland prefs here.
     if (mIsDMABufPrefState == -1) {
-      mIsDMABufPrefState =
-          Preferences::GetBool("widget.wayland_dmabuf_backend.enabled", false);
+      mIsDMABufPrefState = Preferences::GetBool(DMABUF_PREF, false);
     }
+    if (mRenderingCacheModePref == -1) {
+      mRenderingCacheModePref = Preferences::GetInt(CACHE_MODE_PREF, 0);
+    }
+
     // 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);
     wl_proxy_set_queue((struct wl_proxy*)mRegistry, mEventQueue);
--- a/widget/gtk/nsWaylandDisplay.h
+++ b/widget/gtk/nsWaylandDisplay.h
@@ -72,16 +72,19 @@ class nsWaylandDisplay {
   bool IsExplicitSyncEnabled() { return mExplicitSync; }
   GbmFormat* GetGbmFormat(bool aHasAlpha);
   GbmFormat* GetExactGbmFormat(int aFormat);
 
   void AddFormatModifier(bool aHasAlpha, int aFormat, uint32_t mModifierHi,
                          uint32_t mModifierLo);
   static bool IsDMABufEnabled();
 
+  // See WindowSurfaceWayland::CacheMode for details.
+  int GetRenderingCacheModePref() { return mRenderingCacheModePref; };
+
  private:
   bool ConfigureGbm();
 
   MessageLoop* mDispatcherThreadLoop;
   PRThread* mThreadId;
   wl_display* mDisplay;
   wl_event_queue* mEventQueue;
   wl_data_device_manager* mDataDeviceManager;
@@ -95,16 +98,17 @@ class nsWaylandDisplay {
   int mGbmFd;
   GbmFormat mXRGBFormat;
   GbmFormat mARGBFormat;
   bool mGdmConfigured;
   bool mExplicitSync;
   static bool mIsDMABufEnabled;
   static int mIsDMABufPrefState;
   static bool mIsDMABufConfigured;
+  static int mRenderingCacheModePref;
 };
 
 void WaylandDispatchDisplays();
 void WaylandDisplayShutdown();
 nsWaylandDisplay* WaylandDisplayGet(GdkDisplay* aGdkDisplay = nullptr);
 wl_display* WaylandDisplayGetWLDisplay(GdkDisplay* aGdkDisplay = nullptr);
 
 typedef struct gbm_device* (*CreateDeviceFunc)(int);