diff options
Diffstat (limited to 'mozilla-1552590.patch')
-rw-r--r-- | mozilla-1552590.patch | 2701 |
1 files changed, 0 insertions, 2701 deletions
diff --git a/mozilla-1552590.patch b/mozilla-1552590.patch deleted file mode 100644 index 58d5b18..0000000 --- a/mozilla-1552590.patch +++ /dev/null @@ -1,2701 +0,0 @@ -changeset: 474982:24c0dda573b3 -parent: 474915:839cdad764d7 -user: Martin Stransky <stransky@redhat.com> -date: Fri May 17 11:24:33 2019 +0200 -summary: Implement dmabuf surfaces - -diff --git a/gfx/2d/WaylandDMABufSurface.cpp b/gfx/2d/WaylandDMABufSurface.cpp -new file mode 100644 ---- /dev/null -+++ b/gfx/2d/WaylandDMABufSurface.cpp -@@ -0,0 +1,274 @@ -+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -+/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -+/* This Source Code Form is subject to the terms of the Mozilla Public -+ * License, v. 2.0. If a copy of the MPL was not distributed with this -+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -+ -+// Based on weston/simple-dmabuf-egl.c -+ -+#include "WaylandDMABufSurface.h" -+ -+#include <fcntl.h> -+#include <getopt.h> -+#include <signal.h> -+#include <stdbool.h> -+#include <stdint.h> -+#include <stdio.h> -+#include <stdlib.h> -+#include <string.h> -+#include <unistd.h> -+#include <sys/time.h> -+#include <dlfcn.h> -+ -+#include <gbm.h> -+ -+using namespace mozilla; -+using namespace mozilla::widget; -+ -+#ifndef DRM_FORMAT_MOD_INVALID -+# define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1) -+#endif -+#define BUFFER_FLAGS 0 -+ -+bool WaylandDMABufSurface::mAvailable = false; -+bool WaylandDMABufSurface::mInitialized = false; -+ -+bool WaylandDMABufSurface::IsAvailable() { -+ if (!mInitialized) { -+ mInitialized = true; -+ if (!nsGbmLib::IsAvailable()) { -+ return false; -+ } -+ -+ // Test Alpha and non-alpha formats -+ nsWaylandDisplay* display = WaylandDisplayGet(); -+ if (!display->GetGbmFormat(false) || !display->GetGbmFormat(true)) { -+ return false; -+ } -+ mAvailable = true; -+ } -+ return static_cast<bool>(mAvailable); -+} -+ -+static void buffer_release(void* data, wl_buffer* buffer) { -+ auto surface = reinterpret_cast<WaylandDMABufSurface*>(data); -+ surface->WLBufferDetach(); -+} -+ -+static const struct wl_buffer_listener buffer_listener = {buffer_release}; -+ -+static void buffer_created(void* data, -+ struct zwp_linux_buffer_params_v1* params, -+ struct wl_buffer* new_buffer) { -+ auto surface = static_cast<WaylandDMABufSurface*>(data); -+ -+ surface->SetWLBuffer(new_buffer); -+ -+ nsWaylandDisplay* display = WaylandDisplayGet(); -+ /* When not using explicit synchronization listen to wl_buffer.release -+ * for release notifications, otherwise we are going to use -+ * zwp_linux_buffer_release_v1. */ -+ if (!display->IsExplicitSyncEnabled()) { -+ wl_buffer_add_listener(new_buffer, &buffer_listener, surface); -+ } -+ zwp_linux_buffer_params_v1_destroy(params); -+} -+ -+static void buffer_create_failed(void* data, -+ struct zwp_linux_buffer_params_v1* params) { -+ zwp_linux_buffer_params_v1_destroy(params); -+} -+ -+static const struct zwp_linux_buffer_params_v1_listener params_listener = { -+ buffer_created, buffer_create_failed}; -+ -+WaylandDMABufSurface::WaylandDMABufSurface() -+ : mWidth(0), -+ mHeight(0), -+ mGmbFormat(nullptr), -+ mWLBuffer(nullptr), -+ mMappedRegion(nullptr), -+ mGbmBufferObject(nullptr), -+ mBufferModifier(DRM_FORMAT_MOD_INVALID), -+ mBufferPlaneCount(1), -+ mWLBufferAttached(false), -+ mFastWLBufferCreation(true) { -+ for (int i = 0; i < DMABUF_BUFFER_PLANES; i++) { -+ mDmabufFds[i] = -1; -+ mStrides[i] = 0; -+ mOffsets[i] = 0; -+ } -+} -+ -+WaylandDMABufSurface::~WaylandDMABufSurface() { Release(); } -+ -+bool WaylandDMABufSurface::Create(int aWidth, int aHeight, bool aHasAlpha) { -+ MOZ_ASSERT(mWLBuffer == nullptr); -+ -+ mWidth = aWidth; -+ mHeight = aHeight; -+ -+ nsWaylandDisplay* display = WaylandDisplayGet(); -+ mGmbFormat = display->GetGbmFormat(aHasAlpha); -+ if (!mGmbFormat) { -+ // Requested DRM format is not supposed. -+ return false; -+ } -+ -+#ifdef HAVE_GBM_MODIFIERS -+ if (nsGbmLib::IsModifierAvailable() && mGmbFormat->mModifiersCount > 0) { -+ mGbmBufferObject = nsGbmLib::CreateWithModifiers( -+ display->GetGbmDevice(), mWidth, mHeight, mGmbFormat->mFormat, -+ mGmbFormat->mModifiers, mGmbFormat->mModifiersCount); -+ if (mGbmBufferObject) { -+ mBufferModifier = nsGbmLib::GetModifier(mGbmBufferObject); -+ } -+ } -+#endif -+ -+ if (!mGbmBufferObject) { -+ mGbmBufferObject = -+ nsGbmLib::Create(display->GetGbmDevice(), mWidth, mHeight, -+ mGmbFormat->mFormat, GBM_BO_USE_RENDERING); -+ } -+ -+ if (!mGbmBufferObject) { -+ return false; -+ } -+ -+#ifdef HAVE_GBM_MODIFIERS -+ if (nsGbmLib::IsModifierAvailable()) { -+ mBufferPlaneCount = nsGbmLib::GetPlaneCount(mGbmBufferObject); -+ for (int i = 0; i < mBufferPlaneCount; i++) { -+ uint32_t handle = nsGbmLib::GetHandleForPlane(mGbmBufferObject, i).u32; -+ int ret = nsGbmLib::DrmPrimeHandleToFD(display->GetGbmDeviceFd(), handle, -+ 0, &mDmabufFds[i]); -+ if (ret < 0 || mDmabufFds[i] < 0) { -+ Release(); -+ return false; -+ } -+ mStrides[i] = nsGbmLib::GetStrideForPlane(mGbmBufferObject, i); -+ mOffsets[i] = nsGbmLib::GetOffset(mGbmBufferObject, i); -+ } -+ } else -+#endif -+ { -+ mBufferPlaneCount = 1; -+ mStrides[0] = nsGbmLib::GetStride(mGbmBufferObject); -+ mDmabufFds[0] = nsGbmLib::GetFd(mGbmBufferObject); -+ if (mDmabufFds[0] < 0) { -+ Release(); -+ return false; -+ } -+ } -+ -+ struct zwp_linux_buffer_params_v1* params = -+ zwp_linux_dmabuf_v1_create_params(display->GetDmabuf()); -+ for (int i = 0; i < mBufferPlaneCount; i++) { -+ zwp_linux_buffer_params_v1_add(params, mDmabufFds[i], i, mOffsets[i], -+ mStrides[i], mBufferModifier >> 32, -+ mBufferModifier & 0xffffffff); -+ } -+ zwp_linux_buffer_params_v1_add_listener(params, ¶ms_listener, this); -+ -+ if (mFastWLBufferCreation) { -+ mWLBuffer = zwp_linux_buffer_params_v1_create_immed( -+ params, mWidth, mHeight, mGmbFormat->mFormat, BUFFER_FLAGS); -+ /* When not using explicit synchronization listen to -+ * wl_buffer.release for release notifications, otherwise we -+ * are going to use zwp_linux_buffer_release_v1. */ -+ if (!display->IsExplicitSyncEnabled()) { -+ wl_buffer_add_listener(mWLBuffer, &buffer_listener, this); -+ } -+ } else { -+ zwp_linux_buffer_params_v1_create(params, mWidth, mHeight, -+ mGmbFormat->mFormat, BUFFER_FLAGS); -+ } -+ -+ return true; -+} -+ -+void WaylandDMABufSurface::Release() { -+ MOZ_ASSERT(!IsMapped(), "We can't release mapped buffer!"); -+ -+ if (mWLBuffer) { -+ wl_buffer_destroy(mWLBuffer); -+ mWLBuffer = nullptr; -+ } -+ -+ if (mGbmBufferObject) { -+ nsGbmLib::Destroy(mGbmBufferObject); -+ mGbmBufferObject = nullptr; -+ } -+ -+ for (int i = 0; i < mBufferPlaneCount; i++) { -+ if (mDmabufFds[i] >= 0) { -+ close(mDmabufFds[i]); -+ mDmabufFds[i] = 0; -+ } -+ } -+} -+ -+void* WaylandDMABufSurface::MapReadOnly(uint32_t aX, uint32_t aY, -+ uint32_t aWidth, uint32_t aHeight, -+ uint32_t* aStride) { -+ NS_ASSERTION(mMappedRegion == nullptr, "Already mapped?"); -+ void* map_data = nullptr; -+ *aStride = 0; -+ mMappedRegion = nsGbmLib::Map(mGbmBufferObject, aX, aY, aWidth, aHeight, -+ GBM_BO_TRANSFER_READ, aStride, &map_data); -+ return mMappedRegion; -+} -+ -+void* WaylandDMABufSurface::MapReadOnly(uint32_t* aStride) { -+ return MapReadOnly(0, 0, mWidth, mHeight, aStride); -+} -+ -+void* WaylandDMABufSurface::Map(uint32_t aX, uint32_t aY, uint32_t aWidth, -+ uint32_t aHeight, uint32_t* aStride) { -+ NS_ASSERTION(mMappedRegion == nullptr, "Already mapped?"); -+ void* map_data = nullptr; -+ *aStride = 0; -+ mMappedRegion = nsGbmLib::Map(mGbmBufferObject, aX, aY, aWidth, aHeight, -+ GBM_BO_TRANSFER_READ_WRITE, aStride, &map_data); -+ return mMappedRegion; -+} -+ -+void* WaylandDMABufSurface::Map(uint32_t* aStride) { -+ return Map(0, 0, mWidth, mHeight, aStride); -+} -+ -+void WaylandDMABufSurface::Unmap() { -+ if (mMappedRegion) { -+ nsGbmLib::Unmap(mGbmBufferObject, mMappedRegion); -+ mMappedRegion = nullptr; -+ } -+} -+ -+bool WaylandDMABufSurface::Resize(int aWidth, int aHeight) { -+ if (aWidth == mWidth && aHeight == mHeight) { -+ return true; -+ } -+ -+ if (IsMapped()) { -+ NS_WARNING("We can't resize mapped surface!"); -+ return false; -+ } -+ -+ Release(); -+ return Create(aWidth, aHeight, mGmbFormat->mHasAlpha); -+} -+ -+bool WaylandDMABufSurface::CopyFrom( -+ class WaylandDMABufSurface* aSourceSurface) { -+ // Not implemented - we should not call that. -+ MOZ_CRASH(); -+} -+ -+// TODO - EGL clear -+void WaylandDMABufSurface::Clear() { -+ uint32_t destStride; -+ void* destData = Map(&destStride); -+ memset(destData, 0, GetHeight() * destStride); -+ Unmap(); -+} -diff --git a/gfx/2d/WaylandDMABufSurface.h b/gfx/2d/WaylandDMABufSurface.h -new file mode 100644 ---- /dev/null -+++ b/gfx/2d/WaylandDMABufSurface.h -@@ -0,0 +1,73 @@ -+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -+/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -+/* This Source Code Form is subject to the terms of the Mozilla Public -+ * License, v. 2.0. If a copy of the MPL was not distributed with this -+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -+ -+#ifndef WaylandDMABufSurface_h__ -+#define WaylandDMABufSurface_h__ -+ -+#include <stdint.h> -+#include "mozilla/widget/nsWaylandDisplay.h" -+ -+#define DMABUF_BUFFER_PLANES 4 -+ -+class WaylandDMABufSurface { -+ public: -+ static bool IsAvailable(); -+ -+ bool CreateFrameBuffer(int aWidth, int aHeight); -+ bool CreateEGLImage(int aWidth, int aHeight); -+ -+ bool Create(int aWidth, int aHeight, bool aHasAlpha = true); -+ bool Resize(int aWidth, int aHeight); -+ void Release(); -+ void Clear(); -+ -+ bool CopyFrom(class WaylandDMABufSurface* aSourceSurface); -+ -+ int GetWidth() { return mWidth; }; -+ int GetHeight() { return mHeight; }; -+ -+ void* MapReadOnly(uint32_t aX, uint32_t aY, uint32_t aWidth, uint32_t aHeight, -+ uint32_t* aStride); -+ void* MapReadOnly(uint32_t* aStride); -+ void* Map(uint32_t aX, uint32_t aY, uint32_t aWidth, uint32_t aHeight, -+ uint32_t* aStride); -+ void* Map(uint32_t* aStride); -+ bool IsMapped() { return mMappedRegion; }; -+ void Unmap(); -+ -+ void SetWLBuffer(struct wl_buffer* aWLBuffer) { mWLBuffer = aWLBuffer; }; -+ wl_buffer* GetWLBuffer() { return mWLBuffer; }; -+ -+ void WLBufferDetach() { mWLBufferAttached = false; }; -+ bool WLBufferIsAttached() { return mWLBufferAttached; }; -+ void WLBufferSetAttached() { mWLBufferAttached = true; }; -+ -+ WaylandDMABufSurface(); -+ ~WaylandDMABufSurface(); -+ -+ private: -+ int mWidth; -+ int mHeight; -+ mozilla::widget::GbmFormat* mGmbFormat; -+ -+ wl_buffer* mWLBuffer; -+ void* mMappedRegion; -+ -+ struct gbm_bo* mGbmBufferObject; -+ uint64_t mBufferModifier; -+ int mBufferPlaneCount; -+ int mDmabufFds[DMABUF_BUFFER_PLANES]; -+ uint32_t mStrides[DMABUF_BUFFER_PLANES]; -+ uint32_t mOffsets[DMABUF_BUFFER_PLANES]; -+ -+ bool mWLBufferAttached; -+ bool mFastWLBufferCreation; -+ -+ static bool mAvailable; -+ static bool mInitialized; -+}; -+ -+#endif -diff --git a/gfx/2d/moz.build b/gfx/2d/moz.build ---- a/gfx/2d/moz.build -+++ b/gfx/2d/moz.build -@@ -255,8 +255,20 @@ if CONFIG['MOZ_ENABLE_SKIA']: - '/gfx/skia/skia/include/private', - '/gfx/skia/skia/src/core', - '/gfx/skia/skia/src/image', - ] - if CONFIG['MOZ_ENABLE_SKIA_GPU']: - LOCAL_INCLUDES += [ - '/gfx/skia/skia/src/gpu', - ] -+ -+#if CONFIG['MOZ_WAYLAND'] and CONFIG['HAVE_LIBDRM']: -+if CONFIG['HAVE_LIBDRM']: -+ SOURCES += [ -+ 'WaylandDMABufSurface.cpp', -+ ] -+ EXPORTS.mozilla.gfx += [ -+ 'WaylandDMABufSurface.h', -+ ] -+ CFLAGS += CONFIG['TK_CFLAGS'] -+ CXXFLAGS += CONFIG['TK_CFLAGS'] -+ -diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js ---- a/modules/libpref/init/all.js -+++ b/modules/libpref/init/all.js -@@ -5091,16 +5091,21 @@ pref("gfx.apitrace.enabled",false); - - #ifdef MOZ_X11 - #ifdef MOZ_WIDGET_GTK - pref("gfx.xrender.enabled",false); - pref("widget.chrome.allow-gtk-dark-theme", false); - pref("widget.content.allow-gtk-dark-theme", false); - #endif - #endif -+#ifdef MOZ_WAYLAND -+#ifdef HAVE_LIBDRM -+pref("gfx.wayland_dmabuf_backend.enabled", false); -+#endif -+#endif - - pref("widget.window-transforms.disabled", false); - - #ifdef XP_WIN - // Whether to disable the automatic detection and use of direct2d. - pref("gfx.direct2d.disabled", false); - - // Whether to attempt to enable Direct2D regardless of automatic detection or -diff --git a/toolkit/moz.configure b/toolkit/moz.configure ---- a/toolkit/moz.configure -+++ b/toolkit/moz.configure -@@ -260,16 +260,24 @@ def wayland_headers(wayland, toolkit_gtk - if toolkit_gtk and artifacts: - return True - return wayland - - - set_config('MOZ_WAYLAND', depends_if(wayland_headers)(lambda _: True)) - set_define('MOZ_WAYLAND', depends_if(wayland_headers)(lambda _: True)) - -+drm_headers = pkg_check_modules('HAVE_LIBDRM', 'libdrm > 2.4', when=wayland_headers) -+set_config('HAVE_LIBDRM', depends_if(drm_headers)(lambda _: True)) -+set_define('HAVE_LIBDRM', depends_if(drm_headers)(lambda _: True)) -+ -+gbm_modifiers = pkg_check_modules('HAVE_GBM_MODIFIERS', 'gbm >= 17.1', when=drm_headers) -+set_config('HAVE_GBM_MODIFIERS', depends_if(gbm_modifiers)(lambda _: True)) -+set_define('HAVE_GBM_MODIFIERS', depends_if(gbm_modifiers)(lambda _: True)) -+ - # GL Provider - # ============================================================== - option('--with-gl-provider', nargs=1, help='Set GL provider backend type') - - @depends('--with-gl-provider') - def gl_provider(value): - if value: - return value[0] -diff --git a/widget/gtk/WindowSurfaceWayland.cpp b/widget/gtk/WindowSurfaceWayland.cpp ---- a/widget/gtk/WindowSurfaceWayland.cpp -+++ b/widget/gtk/WindowSurfaceWayland.cpp -@@ -30,16 +30,19 @@ extern mozilla::LazyLogModule gWidgetWay - MOZ_LOG(gWidgetWaylandLog, mozilla::LogLevel::Debug, args) - #else - # define LOGWAYLAND(args) - #endif /* MOZ_LOGGING */ - - namespace mozilla { - namespace widget { - -+bool WindowSurfaceWayland::mUseDMABuf = false; -+bool WindowSurfaceWayland::mUseDMABufInitialized = false; -+ - /* - Wayland multi-thread rendering scheme - - Every rendering thread (main thread, compositor thread) contains its own - nsWaylandDisplay object connected to Wayland compositor (Mutter, Weston, etc.) - - WindowSurfaceWayland implements WindowSurface class and draws nsWindow by - WindowSurface interface (Lock, Commit) to screen through nsWaylandDisplay. -@@ -255,120 +258,183 @@ WaylandShmPool::~WaylandShmPool() { - - static void buffer_release(void* data, wl_buffer* buffer) { - auto surface = reinterpret_cast<WindowBackBuffer*>(data); - surface->Detach(buffer); - } - - static const struct wl_buffer_listener buffer_listener = {buffer_release}; - --void WindowBackBuffer::Create(int aWidth, int aHeight) { -+void WindowBackBufferShm::Create(int aWidth, int aHeight) { - MOZ_ASSERT(!IsAttached(), "We can't resize attached buffers."); - - int newBufferSize = aWidth * aHeight * BUFFER_BPP; - mShmPool.Resize(newBufferSize); - - mWaylandBuffer = - wl_shm_pool_create_buffer(mShmPool.GetShmPool(), 0, aWidth, aHeight, - aWidth * BUFFER_BPP, WL_SHM_FORMAT_ARGB8888); - wl_proxy_set_queue((struct wl_proxy*)mWaylandBuffer, -- mWaylandDisplay->GetEventQueue()); -+ GetWaylandDisplay()->GetEventQueue()); - wl_buffer_add_listener(mWaylandBuffer, &buffer_listener, this); - - mWidth = aWidth; - mHeight = aHeight; - - LOGWAYLAND(( - "%s [%p] wl_buffer %p ID %d\n", __PRETTY_FUNCTION__, (void*)this, - (void*)mWaylandBuffer, - mWaylandBuffer ? wl_proxy_get_id((struct wl_proxy*)mWaylandBuffer) : -1)); - } - --void WindowBackBuffer::Release() { -+void WindowBackBufferShm::Release() { - LOGWAYLAND(("%s [%p]\n", __PRETTY_FUNCTION__, (void*)this)); - - wl_buffer_destroy(mWaylandBuffer); - mWidth = mHeight = 0; - } - --void WindowBackBuffer::Clear() { -+void WindowBackBufferShm::Clear() { - memset(mShmPool.GetImageData(), 0, mHeight * mWidth * BUFFER_BPP); - } - --WindowBackBuffer::WindowBackBuffer(nsWaylandDisplay* aWaylandDisplay, -- int aWidth, int aHeight) -- : mShmPool(aWaylandDisplay, aWidth * aHeight * BUFFER_BPP), -+WindowBackBufferShm::WindowBackBufferShm(nsWaylandDisplay* aWaylandDisplay, -+ int aWidth, int aHeight) -+ : WindowBackBuffer(aWaylandDisplay), -+ mShmPool(aWaylandDisplay, aWidth * aHeight * BUFFER_BPP), - mWaylandBuffer(nullptr), - mWidth(aWidth), - mHeight(aHeight), -- mAttached(false), -- mWaylandDisplay(aWaylandDisplay) { -+ mAttached(false) { - Create(aWidth, aHeight); - } - --WindowBackBuffer::~WindowBackBuffer() { Release(); } -+WindowBackBufferShm::~WindowBackBufferShm() { Release(); } - --bool WindowBackBuffer::Resize(int aWidth, int aHeight) { -+bool WindowBackBufferShm::Resize(int aWidth, int aHeight) { - if (aWidth == mWidth && aHeight == mHeight) return true; - - LOGWAYLAND( - ("%s [%p] %d %d\n", __PRETTY_FUNCTION__, (void*)this, aWidth, aHeight)); - - Release(); - Create(aWidth, aHeight); - - return (mWaylandBuffer != nullptr); - } - - void WindowBackBuffer::Attach(wl_surface* aSurface) { -- LOGWAYLAND(( -- "%s [%p] wl_surface %p ID %d wl_buffer %p ID %d\n", __PRETTY_FUNCTION__, -- (void*)this, (void*)aSurface, -- aSurface ? wl_proxy_get_id((struct wl_proxy*)aSurface) : -1, -- (void*)mWaylandBuffer, -- mWaylandBuffer ? wl_proxy_get_id((struct wl_proxy*)mWaylandBuffer) : -1)); -+ LOGWAYLAND( -+ ("%s [%p] wl_surface %p ID %d wl_buffer %p ID %d\n", __PRETTY_FUNCTION__, -+ (void*)this, (void*)aSurface, -+ aSurface ? wl_proxy_get_id((struct wl_proxy*)aSurface) : -1, -+ (void*)GetWlBuffer(), -+ GetWlBuffer() ? wl_proxy_get_id((struct wl_proxy*)GetWlBuffer()) : -1)); - -- wl_surface_attach(aSurface, mWaylandBuffer, 0, 0); -+ wl_surface_attach(aSurface, GetWlBuffer(), 0, 0); - wl_surface_commit(aSurface); -- wl_display_flush(mWaylandDisplay->GetDisplay()); -- mAttached = true; -+ wl_display_flush(GetWaylandDisplay()->GetDisplay()); -+ SetAttached(); - } - --void WindowBackBuffer::Detach(wl_buffer* aBuffer) { -+void WindowBackBufferShm::Detach(wl_buffer* aBuffer) { - LOGWAYLAND(("%s [%p] wl_buffer %p ID %d\n", __PRETTY_FUNCTION__, (void*)this, - (void*)aBuffer, - aBuffer ? wl_proxy_get_id((struct wl_proxy*)aBuffer) : -1)); - - mAttached = false; - } - --bool WindowBackBuffer::SetImageDataFromBuffer( -+bool WindowBackBufferShm::SetImageDataFromBuffer( - class WindowBackBuffer* aSourceBuffer) { -- if (!IsMatchingSize(aSourceBuffer)) { -- Resize(aSourceBuffer->mWidth, aSourceBuffer->mHeight); -+ auto sourceBuffer = static_cast<class WindowBackBufferShm*>(aSourceBuffer); -+ if (!IsMatchingSize(sourceBuffer)) { -+ Resize(sourceBuffer->mWidth, sourceBuffer->mHeight); - } - - mShmPool.SetImageDataFromPool( -- &aSourceBuffer->mShmPool, -- aSourceBuffer->mWidth * aSourceBuffer->mHeight * BUFFER_BPP); -+ &sourceBuffer->mShmPool, -+ sourceBuffer->mWidth * sourceBuffer->mHeight * BUFFER_BPP); - return true; - } - --already_AddRefed<gfx::DrawTarget> WindowBackBuffer::Lock() { -+already_AddRefed<gfx::DrawTarget> WindowBackBufferShm::Lock() { - LOGWAYLAND(( - "%s [%p] [%d x %d] wl_buffer %p ID %d\n", __PRETTY_FUNCTION__, - (void*)this, mWidth, mHeight, (void*)mWaylandBuffer, - mWaylandBuffer ? wl_proxy_get_id((struct wl_proxy*)mWaylandBuffer) : -1)); - - gfx::IntSize lockSize(mWidth, mHeight); - return gfxPlatform::CreateDrawTargetForData( - static_cast<unsigned char*>(mShmPool.GetImageData()), lockSize, -- BUFFER_BPP * mWidth, mFormat); -+ BUFFER_BPP * mWidth, GetSurfaceFormat()); -+} -+ -+#ifdef HAVE_LIBDRM -+WindowBackBufferDMABuf::WindowBackBufferDMABuf( -+ nsWaylandDisplay* aWaylandDisplay, int aWidth, int aHeight) -+ : WindowBackBuffer(aWaylandDisplay) { -+ mDMAbufSurface.Create(aWidth, aHeight); -+} -+ -+WindowBackBufferDMABuf::~WindowBackBufferDMABuf() { mDMAbufSurface.Release(); } -+ -+already_AddRefed<gfx::DrawTarget> WindowBackBufferDMABuf::Lock() { -+ LOGWAYLAND( -+ ("%s [%p] [%d x %d] wl_buffer %p ID %d\n", __PRETTY_FUNCTION__, -+ (void*)this, GetWidth(), GetHeight(), (void*)GetWlBuffer(), -+ GetWlBuffer() ? wl_proxy_get_id((struct wl_proxy*)GetWlBuffer()) : -1)); -+ -+ uint32_t stride; -+ void* pixels = mDMAbufSurface.Map(&stride); -+ gfx::IntSize lockSize(GetWidth(), GetHeight()); -+ return gfxPlatform::CreateDrawTargetForData( -+ static_cast<unsigned char*>(pixels), lockSize, stride, -+ GetSurfaceFormat()); -+} -+ -+void WindowBackBufferDMABuf::Unlock() { mDMAbufSurface.Unmap(); } -+ -+bool WindowBackBufferDMABuf::IsAttached() { -+ return mDMAbufSurface.WLBufferIsAttached(); - } - -+void WindowBackBufferDMABuf::SetAttached() { -+ return mDMAbufSurface.WLBufferSetAttached(); -+} -+ -+int WindowBackBufferDMABuf::GetWidth() { return mDMAbufSurface.GetWidth(); } -+ -+int WindowBackBufferDMABuf::GetHeight() { return mDMAbufSurface.GetHeight(); } -+ -+wl_buffer* WindowBackBufferDMABuf::GetWlBuffer() { -+ return mDMAbufSurface.GetWLBuffer(); -+} -+ -+bool WindowBackBufferDMABuf::IsLocked() { return mDMAbufSurface.IsMapped(); } -+ -+bool WindowBackBufferDMABuf::Resize(int aWidth, int aHeight) { -+ return mDMAbufSurface.Resize(aWidth, aHeight); -+} -+ -+bool WindowBackBufferDMABuf::SetImageDataFromBuffer( -+ class WindowBackBuffer* aSourceBuffer) { -+ WindowBackBufferDMABuf* source = -+ static_cast<WindowBackBufferDMABuf*>(aSourceBuffer); -+ mDMAbufSurface.CopyFrom(&source->mDMAbufSurface); -+ return true; -+} -+ -+void WindowBackBufferDMABuf::Detach(wl_buffer* aBuffer) { -+ mDMAbufSurface.WLBufferDetach(); -+} -+ -+void WindowBackBufferDMABuf::Clear() { mDMAbufSurface.Clear(); } -+#endif -+ - static void frame_callback_handler(void* data, struct wl_callback* callback, - uint32_t time) { - auto surface = reinterpret_cast<WindowSurfaceWayland*>(data); - surface->FrameCallbackHandler(); - - gfxPlatformGtk::GetPlatform()->SetWaylandLastVsync(time); - } - -@@ -412,23 +478,60 @@ WindowSurfaceWayland::~WindowSurfaceWayl - - for (int i = 0; i < BACK_BUFFER_NUM; i++) { - if (mBackupBuffer[i]) { - delete mBackupBuffer[i]; - } - } - } - --WindowBackBuffer* WindowSurfaceWayland::GetWaylandBufferToDraw(int aWidth, -- int aHeight) { -+bool WindowSurfaceWayland::UseDMABufBackend() { -+ if (!mUseDMABufInitialized) { -+#ifdef HAVE_LIBDRM -+ if (WaylandDMABufSurface::IsAvailable()) { -+ mUseDMABuf = -+ Preferences::GetBool("gfx.wayland_dmabuf_backend.enabled", false); -+ } -+#endif -+ mUseDMABufInitialized = true; -+ } -+ return mUseDMABuf; -+} -+ -+WindowBackBuffer* WindowSurfaceWayland::CreateWaylandBuffer(int aWidth, -+ int aHeight) { -+ if (UseDMABufBackend()) { -+ static bool sDMABufBufferCreated = false; -+ WindowBackBuffer* buffer = -+ new WindowBackBufferDMABuf(mWaylandDisplay, aWidth, aHeight); -+ if (buffer) { -+ sDMABufBufferCreated = true; -+ return buffer; -+ } -+ // If this is the first failure and there's no dmabuf already active -+ // we can safely fallback to Shm. Otherwise we can't mix DMAbuf and -+ // SHM buffers so just fails now. -+ if (sDMABufBufferCreated) { -+ NS_WARNING("Failed to allocate DMABuf buffer!"); -+ return nullptr; -+ } else { -+ NS_WARNING("Wayland DMABuf failed, switched back to Shm backend!"); -+ mUseDMABuf = false; -+ } -+ } -+ return new WindowBackBufferShm(mWaylandDisplay, aWidth, aHeight); -+} -+ -+WindowBackBuffer* WindowSurfaceWayland::GetWaylandBufferToDraw( -+ int aWidth, int aHeight, bool aFullScreenUpdate, bool aNoBackBufferCopy) { - if (!mWaylandBuffer) { - LOGWAYLAND(("%s [%p] Create [%d x %d]\n", __PRETTY_FUNCTION__, (void*)this, - aWidth, aHeight)); - -- mWaylandBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight); -+ mWaylandBuffer = CreateWaylandBuffer(aWidth, aHeight); - mWaitToFullScreenUpdate = true; - return mWaylandBuffer; - } - - if (!mWaylandBuffer->IsAttached()) { - if (!mWaylandBuffer->IsMatchingSize(aWidth, aHeight)) { - mWaylandBuffer->Resize(aWidth, aHeight); - // There's a chance that scale factor has been changed -@@ -444,75 +547,89 @@ WindowBackBuffer* WindowSurfaceWayland:: - 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); -+ mBackupBuffer[availableBuffer] = CreateWaylandBuffer(aWidth, aHeight); - break; - } - - if (!mBackupBuffer[availableBuffer]->IsAttached()) { - break; - } - } - - if (MOZ_UNLIKELY(availableBuffer == BACK_BUFFER_NUM)) { - LOGWAYLAND(("%s [%p] No drawing buffer available!\n", __PRETTY_FUNCTION__, - (void*)this)); - NS_WARNING("No drawing buffer available"); - return nullptr; - } - -+ bool bufferFlip = mWaylandBuffer->IsMatchingSize(aWidth, aHeight); -+ if (bufferFlip && aNoBackBufferCopy && !aFullScreenUpdate) { -+ LOGWAYLAND(("%s [%p] Delayed hard copy from old buffer [%d x %d]\n", -+ __PRETTY_FUNCTION__, (void*)this, aWidth, aHeight)); -+ return nullptr; -+ } -+ - WindowBackBuffer* lastWaylandBuffer = mWaylandBuffer; - mWaylandBuffer = mBackupBuffer[availableBuffer]; - mBackupBuffer[availableBuffer] = lastWaylandBuffer; - -- if (lastWaylandBuffer->IsMatchingSize(aWidth, aHeight)) { -- LOGWAYLAND(("%s [%p] Copy from old buffer [%d x %d]\n", __PRETTY_FUNCTION__, -- (void*)this, aWidth, aHeight)); -+ if (bufferFlip) { - // 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(lastWaylandBuffer); -+ // existing data to the new buffer if we don't do fullscreen redraw. -+ if (!aFullScreenUpdate) { -+ LOGWAYLAND(("%s [%p] Copy from old buffer [%d x %d]\n", -+ __PRETTY_FUNCTION__, (void*)this, aWidth, aHeight)); -+ mWaylandBuffer->SetImageDataFromBuffer(lastWaylandBuffer); -+ } - // When buffer switches we need to damage whole screen - // (https://bugzilla.redhat.com/show_bug.cgi?id=1418260) - mWaylandBufferFullScreenDamage = true; - } else { - LOGWAYLAND(("%s [%p] Resize to [%d x %d]\n", __PRETTY_FUNCTION__, - (void*)this, aWidth, aHeight)); - // 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); - mWaitToFullScreenUpdate = true; - } - - return mWaylandBuffer; - } - - already_AddRefed<gfx::DrawTarget> WindowSurfaceWayland::LockWaylandBuffer( -- int aWidth, int aHeight, bool aClearBuffer) { -- WindowBackBuffer* buffer = GetWaylandBufferToDraw(aWidth, aHeight); -+ int aWidth, int aHeight, bool aClearBuffer, bool aFullScreenUpdate, -+ bool aNoBackBufferCopy) { -+ WindowBackBuffer* buffer = GetWaylandBufferToDraw( -+ aWidth, aHeight, aFullScreenUpdate, aNoBackBufferCopy); - if (!buffer) { -- NS_WARNING( -- "WindowSurfaceWayland::LockWaylandBuffer(): No buffer available"); -+ if (!aNoBackBufferCopy) { -+ NS_WARNING( -+ "WindowSurfaceWayland::LockWaylandBuffer(): No buffer available"); -+ } - return nullptr; - } - - if (aClearBuffer) { - buffer->Clear(); - } - - return buffer->Lock(); - } - -+void WindowSurfaceWayland::UnlockWaylandBuffer() { mWaylandBuffer->Unlock(); } -+ - already_AddRefed<gfx::DrawTarget> WindowSurfaceWayland::LockImageSurface( - const gfx::IntSize& aLockSize) { - if (!mImageSurface || mImageSurface->CairoStatus() || - !(aLockSize <= mImageSurface->GetSize())) { - mImageSurface = new gfxImageSurface( - aLockSize, - SurfaceFormatToImageFormat(WindowBackBuffer::GetSurfaceFormat())); - if (mImageSurface->CairoStatus()) { -@@ -552,20 +669,28 @@ already_AddRefed<gfx::DrawTarget> Window - - // Are we asked for entire nsWindow to draw? - mDrawToWaylandBufferDirectly = - (aRegion.GetNumRects() == 1 && bounds.x == 0 && bounds.y == 0 && - lockSize.width == screenRect.width && - lockSize.height == screenRect.height); - - if (mDrawToWaylandBufferDirectly) { -- RefPtr<gfx::DrawTarget> dt = -- LockWaylandBuffer(screenRect.width, screenRect.height, -- mWindow->WaylandSurfaceNeedsClear()); -+ // If there's any pending image commit scratch them as we're going -+ // to redraw the whole sceen anyway. -+ mDelayedImageCommits.Clear(); -+ -+ bool needsClear = mWindow->WaylandSurfaceNeedsClear(); -+ RefPtr<gfx::DrawTarget> dt = LockWaylandBuffer( -+ screenRect.width, screenRect.height, needsClear, -+ /* aFullScreenUpdate */ true, /* aNoBackBufferCopy */ true); - if (dt) { -+ if (needsClear) { -+ mWindow->WaylandSurfaceCleared(); -+ } - // When we have a request to update whole screen at once - // (surface was created, resized or changed somehow) - // we also need update scale factor of the screen. - if (mWaitToFullScreenUpdate) { - mWaitToFullScreenUpdate = false; - mNeedScaleFactorUpdate = true; - } - return dt.forget(); -@@ -574,52 +699,94 @@ already_AddRefed<gfx::DrawTarget> Window - // We don't have any front buffer available. Try indirect drawing - // to mImageSurface which is mirrored to front buffer at commit. - mDrawToWaylandBufferDirectly = false; - } - - return LockImageSurface(lockSize); - } - -+void WindowImageSurface::Draw(gfx::SourceSurface* aSurface, -+ gfx::DrawTarget* aDest, -+ const LayoutDeviceIntRegion& aRegion) { -+ 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()); -+ } -+ aDest->PushDeviceSpaceClipRects(rects.Elements(), rects.Length()); -+ } -+ -+ gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect(); -+ gfx::Rect rect(bounds); -+ aDest->DrawSurface(aSurface, rect, rect); -+ -+ if (numRects != 1) { -+ aDest->PopClip(); -+ } -+} -+ -+void WindowImageSurface::Draw(gfx::DrawTarget* aDest, -+ LayoutDeviceIntRegion& aWaylandBufferDamage) { -+ Draw(mSurface.get(), aDest, mUpdateRegion); -+ aWaylandBufferDamage.OrWith(mUpdateRegion); -+} -+ -+WindowImageSurface::WindowImageSurface( -+ gfx::SourceSurface* aSurface, const LayoutDeviceIntRegion& aUpdateRegion) -+ : mSurface(aSurface), mUpdateRegion(aUpdateRegion){}; -+ -+void WindowSurfaceWayland::DrawDelayedImageCommits( -+ gfx::DrawTarget* aDrawTarget, LayoutDeviceIntRegion& aWaylandBufferDamage) { -+ for (unsigned int i = 0; i < mDelayedImageCommits.Length(); i++) { -+ mDelayedImageCommits[i].Draw(aDrawTarget, aWaylandBufferDamage); -+ } -+ mDelayedImageCommits.Clear(); -+} -+ - bool WindowSurfaceWayland::CommitImageSurfaceToWaylandBuffer( -- const LayoutDeviceIntRegion& aRegion) { -+ const LayoutDeviceIntRegion& aRegion, -+ LayoutDeviceIntRegion& aWaylandBufferDamage) { - MOZ_ASSERT(!mDrawToWaylandBufferDirectly); - - LayoutDeviceIntRect screenRect = mWindow->GetBounds(); - gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect(); - - gfx::Rect rect(bounds); - if (rect.IsEmpty()) { - return false; - } - -- RefPtr<gfx::DrawTarget> dt = LockWaylandBuffer( -- screenRect.width, screenRect.height, mWindow->WaylandSurfaceNeedsClear()); - RefPtr<gfx::SourceSurface> surf = - gfx::Factory::CreateSourceSurfaceForCairoSurface( - mImageSurface->CairoSurface(), mImageSurface->GetSize(), - mImageSurface->Format()); -- if (!dt || !surf) { -+ if (!surf) { - return false; - } - -- 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()); -+ bool needsClear = mWindow->WaylandSurfaceNeedsClear(); -+ RefPtr<gfx::DrawTarget> dt = LockWaylandBuffer( -+ screenRect.width, screenRect.height, needsClear, -+ /* fullscreenDrawing */ false, /* aNoBackBufferCopy */ true); -+ if (dt) { -+ if (needsClear) { -+ mWindow->WaylandSurfaceCleared(); - } -- dt->PushDeviceSpaceClipRects(rects.Elements(), rects.Length()); -- } -- -- dt->DrawSurface(surf, rect, rect); -- -- if (numRects != 1) { -- dt->PopClip(); -+ // Draw any delayed image commits first -+ DrawDelayedImageCommits(dt, aWaylandBufferDamage); -+ WindowImageSurface::Draw(surf, dt, aRegion); -+ // Submit all drawing to final Wayland buffer upload -+ aWaylandBufferDamage.OrWith(aRegion); -+ UnlockWaylandBuffer(); -+ } else { -+ mDelayedImageCommits.AppendElement(WindowImageSurface(surf, aRegion)); -+ return false; - } - - return true; - } - - static void WaylandBufferDelayCommitHandler(WindowSurfaceWayland** aSurface) { - if (*aSurface) { - (*aSurface)->DelayedCommitHandler(); -@@ -643,16 +810,34 @@ void WindowSurfaceWayland::CalcRectScale - - void WindowSurfaceWayland::CommitWaylandBuffer() { - MOZ_ASSERT(mPendingCommit, "Committing empty surface!"); - - if (mWaitToFullScreenUpdate) { - return; - } - -+ if (!mDrawToWaylandBufferDirectly) { -+ // There's some cached drawings - try to flush them now. -+ LayoutDeviceIntRect screenRect = mWindow->GetBounds(); -+ bool needsClear = mWindow->WaylandSurfaceNeedsClear(); -+ RefPtr<gfx::DrawTarget> dt = -+ LockWaylandBuffer(screenRect.width, screenRect.height, needsClear, -+ /* fullscreenInvalidate */ false, -+ /* aNoBackBufferCopy */ true); -+ if (dt) { -+ if (needsClear) { -+ mWindow->WaylandSurfaceCleared(); -+ } -+ DrawDelayedImageCommits(dt, mWaylandBufferDamage); -+ UnlockWaylandBuffer(); -+ mDrawToWaylandBufferDirectly = true; -+ } -+ } -+ - wl_surface* waylandSurface = mWindow->GetWaylandSurface(); - if (!waylandSurface) { - // Target window is not created yet - delay the commit. This can happen only - // when the window is newly created and there's no active - // frame callback pending. - MOZ_ASSERT(!mFrameCallback || waylandSurface != mLastCommittedSurface, - "Missing wayland surface at frame callback!"); - -@@ -735,24 +920,31 @@ void WindowSurfaceWayland::Commit(const - gfx::IntSize lockSize(bounds.XMost(), bounds.YMost()); - - LOGWAYLAND(("%s [%p] lockSize [%d x %d] screenSize [%d x %d]\n", - __PRETTY_FUNCTION__, (void*)this, lockSize.width, - lockSize.height, screenRect.width, lockSize.height)); - } - #endif - -- // We have new content at mImageSurface - copy data to mWaylandBuffer first. -- if (!mDrawToWaylandBufferDirectly) { -- CommitImageSurfaceToWaylandBuffer(aInvalidRegion); -- } -- -- // If we're not at fullscreen damage add drawing area from aInvalidRegion -- if (!mWaylandBufferFullScreenDamage) { -- mWaylandBufferDamage.OrWith(aInvalidRegion); -+ if (mDrawToWaylandBufferDirectly) { -+ MOZ_ASSERT(mWaylandBuffer->IsLocked()); -+ // If we're not at fullscreen damage add drawing area from aInvalidRegion -+ if (!mWaylandBufferFullScreenDamage) { -+ mWaylandBufferDamage.OrWith(aInvalidRegion); -+ } -+ UnlockWaylandBuffer(); -+ } 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; -+ } - } - - // We're ready to commit. - mPendingCommit = true; - CommitWaylandBuffer(); - } - - void WindowSurfaceWayland::FrameCallbackHandler() { -diff --git a/widget/gtk/WindowSurfaceWayland.h b/widget/gtk/WindowSurfaceWayland.h ---- a/widget/gtk/WindowSurfaceWayland.h -+++ b/widget/gtk/WindowSurfaceWayland.h -@@ -5,16 +5,19 @@ - * 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" - #include "nsWaylandDisplay.h" -+#ifdef HAVE_LIBDRM -+# include "mozilla/gfx/WaylandDMABufSurface.h" -+#endif - - #define BACK_BUFFER_NUM 2 - - namespace mozilla { - namespace widget { - - // Allocates and owns shared memory for Wayland drawing surface - class WaylandShmPool { -@@ -35,94 +38,192 @@ class WaylandShmPool { - int mShmPoolFd; - int mAllocatedSize; - void* mImageData; - }; - - // Holds actual graphics data for wl_surface - class WindowBackBuffer { - public: -- WindowBackBuffer(nsWaylandDisplay* aDisplay, int aWidth, int aHeight); -- ~WindowBackBuffer(); -+ virtual already_AddRefed<gfx::DrawTarget> Lock() = 0; -+ virtual void Unlock(){}; -+ virtual bool IsLocked() { return false; }; -+ -+ void Attach(wl_surface* aSurface); -+ virtual void Detach(wl_buffer* aBuffer) = 0; -+ virtual bool IsAttached() = 0; -+ -+ virtual void Clear() = 0; -+ virtual bool Resize(int aWidth, int aHeight) = 0; -+ -+ virtual int GetWidth() = 0; -+ virtual int GetHeight() = 0; -+ virtual wl_buffer* GetWlBuffer() = 0; -+ virtual void SetAttached() = 0; -+ -+ virtual bool SetImageDataFromBuffer( -+ class WindowBackBuffer* aSourceBuffer) = 0; -+ -+ bool IsMatchingSize(int aWidth, int aHeight) { -+ return aWidth == GetWidth() && aHeight == GetHeight(); -+ } -+ bool IsMatchingSize(class WindowBackBuffer* aBuffer) { -+ return aBuffer->IsMatchingSize(GetWidth(), GetHeight()); -+ } -+ -+ static gfx::SurfaceFormat GetSurfaceFormat() { return mFormat; } -+ -+ nsWaylandDisplay* GetWaylandDisplay() { return mWaylandDisplay; }; -+ -+ WindowBackBuffer(nsWaylandDisplay* aWaylandDisplay) -+ : mWaylandDisplay(aWaylandDisplay){}; -+ virtual ~WindowBackBuffer(){}; -+ -+ private: -+ static gfx::SurfaceFormat mFormat; -+ nsWaylandDisplay* mWaylandDisplay; -+}; -+ -+class WindowBackBufferShm : public WindowBackBuffer { -+ public: -+ WindowBackBufferShm(nsWaylandDisplay* aWaylandDisplay, int aWidth, -+ int aHeight); -+ ~WindowBackBufferShm(); - - already_AddRefed<gfx::DrawTarget> Lock(); - -- void Attach(wl_surface* aSurface); - void Detach(wl_buffer* aBuffer); - bool IsAttached() { return mAttached; } - - void Clear(); - bool Resize(int aWidth, int aHeight); - bool SetImageDataFromBuffer(class WindowBackBuffer* aSourceBuffer); - -- bool IsMatchingSize(int aWidth, int aHeight) { -- return aWidth == mWidth && aHeight == mHeight; -- } -- bool IsMatchingSize(class WindowBackBuffer* aBuffer) { -- return aBuffer->mWidth == mWidth && aBuffer->mHeight == mHeight; -- } -+ int GetWidth() { return mWidth; }; -+ int GetHeight() { return mHeight; }; - -- static gfx::SurfaceFormat GetSurfaceFormat() { return mFormat; } -+ wl_buffer* GetWlBuffer() { return mWaylandBuffer; }; -+ void SetAttached() { mAttached = true; }; - - private: - void Create(int aWidth, int aHeight); - void Release(); - - // WaylandShmPool provides actual shared memory we draw into - WaylandShmPool mShmPool; - - // wl_buffer is a wayland object that encapsulates the shared memory - // and passes it to wayland compositor by wl_surface object. - wl_buffer* mWaylandBuffer; - int mWidth; - int mHeight; - bool mAttached; -- nsWaylandDisplay* mWaylandDisplay; -- static gfx::SurfaceFormat mFormat; -+}; -+ -+#ifdef HAVE_LIBDRM -+class WindowBackBufferDMABuf : public WindowBackBuffer { -+ public: -+ WindowBackBufferDMABuf(nsWaylandDisplay* aWaylandDisplay, int aWidth, -+ int aHeight); -+ ~WindowBackBufferDMABuf(); -+ -+ bool IsAttached(); -+ void SetAttached(); -+ -+ int GetWidth(); -+ int GetHeight(); -+ wl_buffer* GetWlBuffer(); -+ -+ bool SetImageDataFromBuffer(class WindowBackBuffer* aSourceBuffer); -+ -+ already_AddRefed<gfx::DrawTarget> Lock(); -+ bool IsLocked(); -+ void Unlock(); -+ -+ void Clear(); -+ void Detach(wl_buffer* aBuffer); -+ bool Resize(int aWidth, int aHeight); -+ -+ private: -+ WaylandDMABufSurface mDMAbufSurface; -+}; -+#endif -+ -+class WindowImageSurface { -+ public: -+ static void Draw(gfx::SourceSurface* aSurface, gfx::DrawTarget* aDest, -+ const LayoutDeviceIntRegion& aRegion); -+ -+ void Draw(gfx::DrawTarget* aDest, -+ LayoutDeviceIntRegion& aWaylandBufferDamage); -+ -+ WindowImageSurface(gfx::SourceSurface* aSurface, -+ const LayoutDeviceIntRegion& aUpdateRegion); -+ -+ private: -+ RefPtr<gfx::SourceSurface> mSurface; -+ const LayoutDeviceIntRegion mUpdateRegion; - }; - - // WindowSurfaceWayland is an abstraction for wl_surface - // and related management - class WindowSurfaceWayland : public WindowSurface { - public: - explicit WindowSurfaceWayland(nsWindow* aWindow); - ~WindowSurfaceWayland(); - - already_AddRefed<gfx::DrawTarget> Lock( - const LayoutDeviceIntRegion& aRegion) override; - void Commit(const LayoutDeviceIntRegion& aInvalidRegion) final; - void FrameCallbackHandler(); - void DelayedCommitHandler(); - - private: -- WindowBackBuffer* GetWaylandBufferToDraw(int aWidth, int aHeight); -+ WindowBackBuffer* CreateWaylandBuffer(int aWidth, int aHeight); -+ WindowBackBuffer* GetWaylandBufferToDraw(int aWidth, int aHeight, -+ bool aFullScreenUpdate, -+ bool aNoBackBufferCopy); - - already_AddRefed<gfx::DrawTarget> LockWaylandBuffer(int aWidth, int aHeight, -- bool aClearBuffer); -+ bool aClearBuffer, -+ bool aFullScreenUpdate, -+ bool aNoBackBufferCopy); -+ void UnlockWaylandBuffer(); -+ - already_AddRefed<gfx::DrawTarget> LockImageSurface( - const gfx::IntSize& aLockSize); -- bool CommitImageSurfaceToWaylandBuffer(const LayoutDeviceIntRegion& aRegion); -+ bool CommitImageSurfaceToWaylandBuffer( -+ const LayoutDeviceIntRegion& aRegion, -+ LayoutDeviceIntRegion& aWaylandBufferDamage); - void CommitWaylandBuffer(); - void CalcRectScale(LayoutDeviceIntRect& aRect, int scale); - -+ void DrawDelayedImageCommits(gfx::DrawTarget* aDrawTarget, -+ LayoutDeviceIntRegion& aWaylandBufferDamage); -+ - // TODO: Do we need to hold a reference to nsWindow object? - nsWindow* mWindow; - nsWaylandDisplay* mWaylandDisplay; - WindowBackBuffer* mWaylandBuffer; - LayoutDeviceIntRegion mWaylandBufferDamage; - WindowBackBuffer* mBackupBuffer[BACK_BUFFER_NUM]; -- RefPtr<gfxImageSurface> mImageSurface; - wl_callback* mFrameCallback; - wl_surface* mLastCommittedSurface; - MessageLoop* mDisplayThreadMessageLoop; - WindowSurfaceWayland** mDelayedCommitHandle; -+ RefPtr<gfxImageSurface> mImageSurface; -+ AutoTArray<WindowImageSurface, 30> mDelayedImageCommits; - bool mDrawToWaylandBufferDirectly; - bool mPendingCommit; - bool mWaylandBufferFullScreenDamage; - bool mIsMainThread; - bool mNeedScaleFactorUpdate; - bool mWaitToFullScreenUpdate; -+ -+ static bool UseDMABufBackend(); -+ static bool mUseDMABufInitialized; -+ static bool mUseDMABuf; - }; - - } // namespace widget - } // namespace mozilla - - #endif // _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_WAYLAND_H -diff --git a/widget/gtk/moz.build b/widget/gtk/moz.build ---- a/widget/gtk/moz.build -+++ b/widget/gtk/moz.build -@@ -97,17 +97,18 @@ if CONFIG['MOZ_X11']: - - if CONFIG['MOZ_WAYLAND']: - UNIFIED_SOURCES += [ - 'nsClipboardWayland.cpp', - 'nsWaylandDisplay.cpp', - 'WindowSurfaceWayland.cpp', - ] - EXPORTS.mozilla.widget += [ -- 'nsWaylandDisplayShutdown.h' -+ 'nsWaylandDisplay.h', -+ 'nsWaylandDisplayShutdown.h', - ] - - if CONFIG['ACCESSIBILITY']: - UNIFIED_SOURCES += [ - 'maiRedundantObjectFactory.c', - ] - - UNIFIED_SOURCES += [ -diff --git a/widget/gtk/mozcontainer.cpp b/widget/gtk/mozcontainer.cpp ---- a/widget/gtk/mozcontainer.cpp -+++ b/widget/gtk/mozcontainer.cpp -@@ -641,17 +641,19 @@ struct wl_egl_window* moz_container_get_ - return container->eglwindow; - } - - gboolean moz_container_has_wl_egl_window(MozContainer* container) { - return container->eglwindow ? true : false; - } - - gboolean moz_container_surface_needs_clear(MozContainer* container) { -- gboolean state = container->surface_needs_clear; -+ return container->surface_needs_clear; -+} -+ -+void moz_container_surface_cleared(MozContainer* container) { - container->surface_needs_clear = false; -- return state; - } - #endif - - void moz_container_force_default_visual(MozContainer* container) { - container->force_default_visual = true; - } -diff --git a/widget/gtk/mozcontainer.h b/widget/gtk/mozcontainer.h ---- a/widget/gtk/mozcontainer.h -+++ b/widget/gtk/mozcontainer.h -@@ -96,15 +96,16 @@ void moz_container_put(MozContainer* con - void moz_container_force_default_visual(MozContainer* container); - - #ifdef MOZ_WAYLAND - struct wl_surface* moz_container_get_wl_surface(MozContainer* container); - struct wl_egl_window* moz_container_get_wl_egl_window(MozContainer* container); - - gboolean moz_container_has_wl_egl_window(MozContainer* container); - gboolean moz_container_surface_needs_clear(MozContainer* container); -+void moz_container_surface_cleared(MozContainer* container); - void moz_container_scale_changed(MozContainer* container, - GtkAllocation* aAllocation); - void moz_container_set_initial_draw_callback( - MozContainer* container, std::function<void(void)> inital_draw_cb); - #endif - - #endif /* __MOZ_CONTAINER_H__ */ -diff --git a/widget/gtk/mozwayland/moz.build b/widget/gtk/mozwayland/moz.build ---- a/widget/gtk/mozwayland/moz.build -+++ b/widget/gtk/mozwayland/moz.build -@@ -2,12 +2,16 @@ - # vim: set filetype=python: - # This Source Code Form is subject to the terms of the Mozilla Public - # License, v. 2.0. If a copy of the MPL was not distributed with this - # file, You can obtain one at http://mozilla.org/MPL/2.0/. - - SOURCES += [ - 'mozwayland.c', - ] -+EXPORTS.mozilla.widget += [ -+ 'mozwayland.h', -+] - - SharedLibrary('mozwayland') - - CFLAGS += CONFIG['TK_CFLAGS'] -+ -diff --git a/widget/gtk/nsWaylandDisplay.cpp b/widget/gtk/nsWaylandDisplay.cpp ---- a/widget/gtk/nsWaylandDisplay.cpp -+++ b/widget/gtk/nsWaylandDisplay.cpp -@@ -2,20 +2,16 @@ - /* vim:expandtab:shiftwidth=4:tabstop=4: - */ - /* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - - #include "nsWaylandDisplay.h" - --#include "base/message_loop.h" // for MessageLoop --#include "base/task.h" // for NewRunnableMethod, etc --#include "mozilla/StaticMutex.h" -- - namespace mozilla { - namespace widget { - - // nsWaylandDisplay needs to be created for each calling thread(main thread, - // compositor thread and render thread) - #define MAX_DISPLAY_CONNECTIONS 3 - - static nsWaylandDisplay* gWaylandDisplays[MAX_DISPLAY_CONNECTIONS]; -@@ -107,16 +103,67 @@ void nsWaylandDisplay::SetDataDeviceMana - - void nsWaylandDisplay::SetSeat(wl_seat* aSeat) { mSeat = aSeat; } - - void nsWaylandDisplay::SetPrimarySelectionDeviceManager( - gtk_primary_selection_device_manager* aPrimarySelectionDeviceManager) { - mPrimarySelectionDeviceManager = aPrimarySelectionDeviceManager; - } - -+#ifdef HAVE_LIBDRM -+void nsWaylandDisplay::SetDmabuf(zwp_linux_dmabuf_v1* aDmabuf) { -+ mDmabuf = aDmabuf; -+} -+ -+GbmFormat* nsWaylandDisplay::GetGbmFormat(bool aHasAlpha) { -+ GbmFormat* format = aHasAlpha ? &mARGBFormat : &mXRGBFormat; -+ return format->mIsSupported ? format : nullptr; -+} -+ -+void nsWaylandDisplay::AddFormatModifier(bool aHasAlpha, int aFormat, -+ uint32_t mModifierHi, -+ uint32_t mModifierLo) { -+ GbmFormat* format = aHasAlpha ? &mARGBFormat : &mXRGBFormat; -+ format->mIsSupported = true; -+ format->mHasAlpha = aHasAlpha; -+ format->mFormat = aFormat; -+ format->mModifiersCount++; -+ format->mModifiers = -+ (uint64_t*)realloc(format->mModifiers, -+ format->mModifiersCount * sizeof(*format->mModifiers)); -+ format->mModifiers[format->mModifiersCount - 1] = -+ ((uint64_t)mModifierHi << 32) | mModifierLo; -+} -+ -+static void dmabuf_modifiers(void* data, -+ struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf, -+ uint32_t format, uint32_t modifier_hi, -+ uint32_t modifier_lo) { -+ auto display = reinterpret_cast<nsWaylandDisplay*>(data); -+ switch (format) { -+ case DRM_FORMAT_ARGB8888: -+ display->AddFormatModifier(true, format, modifier_hi, modifier_lo); -+ break; -+ case DRM_FORMAT_XRGB8888: -+ display->AddFormatModifier(false, format, modifier_hi, modifier_lo); -+ break; -+ default: -+ break; -+ } -+} -+ -+static void dmabuf_format(void* data, -+ struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf, -+ uint32_t format) { -+ // XXX: deprecated -+} -+ -+static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = { -+ dmabuf_format, dmabuf_modifiers}; -+ - static void global_registry_handler(void* data, wl_registry* registry, - uint32_t id, const char* interface, - uint32_t version) { - auto display = reinterpret_cast<nsWaylandDisplay*>(data); - if (!display) return; - - if (strcmp(interface, "wl_shm") == 0) { - auto shm = static_cast<wl_shm*>( -@@ -144,16 +191,21 @@ static void global_registry_handler(void - display->GetEventQueue()); - display->SetPrimarySelectionDeviceManager(primary_selection_device_manager); - } else if (strcmp(interface, "wl_subcompositor") == 0) { - auto subcompositor = static_cast<wl_subcompositor*>( - wl_registry_bind(registry, id, &wl_subcompositor_interface, 1)); - wl_proxy_set_queue((struct wl_proxy*)subcompositor, - display->GetEventQueue()); - display->SetSubcompositor(subcompositor); -+ } else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0 && version > 2) { -+ auto dmabuf = static_cast<zwp_linux_dmabuf_v1*>( -+ wl_registry_bind(registry, id, &zwp_linux_dmabuf_v1_interface, 3)); -+ display->SetDmabuf(dmabuf); -+ zwp_linux_dmabuf_v1_add_listener(dmabuf, &dmabuf_listener, data); - } - } - - static void global_registry_remover(void* data, wl_registry* registry, - uint32_t id) {} - - static const struct wl_registry_listener registry_listener = { - global_registry_handler, global_registry_remover}; -@@ -162,27 +214,85 @@ bool nsWaylandDisplay::DispatchEventQueu - wl_display_dispatch_queue_pending(mDisplay, mEventQueue); - return true; - } - - bool nsWaylandDisplay::Matches(wl_display* aDisplay) { - return mThreadId == PR_GetCurrentThread() && aDisplay == mDisplay; - } - -+bool nsWaylandDisplay::ConfigureGbm() { -+ if (!nsGbmLib::IsAvailable()) { -+ return false; -+ } -+ -+ // TODO -+ const char* drm_render_node = getenv("MOZ_WAYLAND_DRM_DEVICE"); -+ if (!drm_render_node) { -+ drm_render_node = "/dev/dri/renderD128"; -+ } -+ -+ mGbmFd = open(drm_render_node, O_RDWR); -+ if (mGbmFd < 0) { -+ NS_WARNING( -+ nsPrintfCString("Failed to open drm render node %s\n", drm_render_node) -+ .get()); -+ return false; -+ } -+ -+ mGbmDevice = nsGbmLib::CreateDevice(mGbmFd); -+ if (mGbmDevice == nullptr) { -+ NS_WARNING(nsPrintfCString("Failed to create drm render device %s\n", -+ drm_render_node) -+ .get()); -+ close(mGbmFd); -+ return false; -+ } -+ -+ return true; -+} -+ -+gbm_device* nsWaylandDisplay::GetGbmDevice() { -+ if (!mGdmConfigured) { -+ ConfigureGbm(); -+ mGdmConfigured = true; -+ } -+ return mGbmDevice; -+} -+ -+int nsWaylandDisplay::GetGbmDeviceFd() { -+ if (!mGdmConfigured) { -+ ConfigureGbm(); -+ mGdmConfigured = true; -+ } -+ return mGbmFd; -+} -+#endif -+ - nsWaylandDisplay::nsWaylandDisplay(wl_display* aDisplay) - : mDispatcherThreadLoop(nullptr), - mThreadId(PR_GetCurrentThread()), - mDisplay(aDisplay), - mEventQueue(nullptr), - mDataDeviceManager(nullptr), - mSubcompositor(nullptr), - mSeat(nullptr), - mShm(nullptr), - mPrimarySelectionDeviceManager(nullptr), -- mRegistry(nullptr) { -+ mRegistry(nullptr) -+#ifdef HAVE_LIBDRM -+ , -+ mGbmDevice(nullptr), -+ mGbmFd(-1), -+ mGdmConfigured(false), -+ mExplicitSync(false), -+ mXRGBFormat({false, false, -1, nullptr, 0}), -+ mARGBFormat({false, false, -1, nullptr, 0}) -+#endif -+{ - mRegistry = wl_display_get_registry(mDisplay); - wl_registry_add_listener(mRegistry, ®istry_listener, this); - - if (NS_IsMainThread()) { - // Use default event queue in main thread operated by Gtk+. - mEventQueue = nullptr; - wl_display_roundtrip(mDisplay); - wl_display_roundtrip(mDisplay); -@@ -205,10 +315,84 @@ nsWaylandDisplay::~nsWaylandDisplay() { - mRegistry = nullptr; - - if (mEventQueue) { - wl_event_queue_destroy(mEventQueue); - mEventQueue = nullptr; - } - } - -+#ifdef HAVE_LIBDRM -+void* nsGbmLib::sGbmLibHandle = nullptr; -+void* nsGbmLib::sXf86DrmLibHandle = nullptr; -+bool nsGbmLib::sLibLoaded = false; -+CreateDeviceFunc nsGbmLib::sCreateDevice; -+CreateFunc nsGbmLib::sCreate; -+CreateWithModifiersFunc nsGbmLib::sCreateWithModifiers; -+GetModifierFunc nsGbmLib::sGetModifier; -+GetStrideFunc nsGbmLib::sGetStride; -+GetFdFunc nsGbmLib::sGetFd; -+DestroyFunc nsGbmLib::sDestroy; -+MapFunc nsGbmLib::sMap; -+UnmapFunc nsGbmLib::sUnmap; -+GetPlaneCountFunc nsGbmLib::sGetPlaneCount; -+GetHandleForPlaneFunc nsGbmLib::sGetHandleForPlane; -+GetStrideForPlaneFunc nsGbmLib::sGetStrideForPlane; -+GetOffsetFunc nsGbmLib::sGetOffset; -+DrmPrimeHandleToFDFunc nsGbmLib::sDrmPrimeHandleToFD; -+ -+bool nsGbmLib::IsAvailable() { -+ if (!Load()) { -+ return false; -+ } -+ return sCreateDevice != nullptr && sCreate != nullptr && -+ sCreateWithModifiers != nullptr && sGetModifier != nullptr && -+ sGetStride != nullptr && sGetFd != nullptr && sDestroy != nullptr && -+ sMap != nullptr && sUnmap != nullptr; -+} -+ -+bool nsGbmLib::IsModifierAvailable() { -+ if (!Load()) { -+ return false; -+ } -+ return sDrmPrimeHandleToFD != nullptr; -+} -+ -+bool nsGbmLib::Load() { -+ if (!sGbmLibHandle && !sLibLoaded) { -+ sLibLoaded = true; -+ -+ sGbmLibHandle = dlopen("libgbm.so", RTLD_LAZY | RTLD_LOCAL); -+ if (!sGbmLibHandle) { -+ return false; -+ } -+ -+ sCreateDevice = (CreateDeviceFunc)dlsym(sGbmLibHandle, "gbm_create_device"); -+ sCreate = (CreateFunc)dlsym(sGbmLibHandle, "gbm_bo_create"); -+ sCreateWithModifiers = (CreateWithModifiersFunc)dlsym( -+ sGbmLibHandle, "gbm_bo_create_with_modifiers"); -+ sGetModifier = (GetModifierFunc)dlsym(sGbmLibHandle, "gbm_bo_get_modifier"); -+ sGetStride = (GetStrideFunc)dlsym(sGbmLibHandle, "gbm_bo_get_stride"); -+ sGetFd = (GetFdFunc)dlsym(sGbmLibHandle, "gbm_bo_get_fd"); -+ sDestroy = (DestroyFunc)dlsym(sGbmLibHandle, "gbm_bo_destroy"); -+ sMap = (MapFunc)dlsym(sGbmLibHandle, "gbm_bo_map"); -+ sUnmap = (UnmapFunc)dlsym(sGbmLibHandle, "gbm_bo_unmap"); -+ sGetPlaneCount = -+ (GetPlaneCountFunc)dlsym(sGbmLibHandle, "gbm_bo_get_plane_count"); -+ sGetHandleForPlane = (GetHandleForPlaneFunc)dlsym( -+ sGbmLibHandle, "gbm_bo_get_handle_for_plane"); -+ sGetStrideForPlane = (GetStrideForPlaneFunc)dlsym( -+ sGbmLibHandle, "gbm_bo_get_stride_for_plane"); -+ sGetOffset = (GetOffsetFunc)dlsym(sGbmLibHandle, "gbm_bo_get_offset"); -+ -+ sXf86DrmLibHandle = dlopen("libdrm.so", RTLD_LAZY | RTLD_LOCAL); -+ if (sXf86DrmLibHandle) { -+ sDrmPrimeHandleToFD = (DrmPrimeHandleToFDFunc)dlsym(sXf86DrmLibHandle, -+ "drmPrimeHandleToFD"); -+ } -+ } -+ -+ return sGbmLibHandle; -+} -+#endif -+ - } // namespace widget - } // namespace mozilla -diff --git a/widget/gtk/nsWaylandDisplay.h b/widget/gtk/nsWaylandDisplay.h ---- a/widget/gtk/nsWaylandDisplay.h -+++ b/widget/gtk/nsWaylandDisplay.h -@@ -1,24 +1,43 @@ - /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ - /* vim:expandtab:shiftwidth=4:tabstop=4: - */ - /* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - --#ifndef __MOZ_WAYLAND_REGISTRY_H__ --#define __MOZ_WAYLAND_REGISTRY_H__ -+#ifndef __MOZ_WAYLAND_DISPLAY_H__ -+#define __MOZ_WAYLAND_DISPLAY_H__ -+ -+#include "mozilla/widget/mozwayland.h" -+#include "mozilla/widget/gtk-primary-selection-client-protocol.h" - --#include "mozwayland/mozwayland.h" --#include "wayland/gtk-primary-selection-client-protocol.h" -+#include "base/message_loop.h" // for MessageLoop -+#include "base/task.h" // for NewRunnableMethod, etc -+#include "mozilla/StaticMutex.h" -+ -+#ifdef HAVE_LIBDRM -+# include <drm/drm_fourcc.h> -+# include <xf86drm.h> -+# include <gbm.h> -+# include "mozilla/widget/linux-dmabuf-unstable-v1-client-protocol.h" -+#endif - - namespace mozilla { - namespace widget { - -+struct GbmFormat { -+ bool mIsSupported; -+ bool mHasAlpha; -+ int mFormat; -+ uint64_t* mModifiers; -+ int mModifiersCount; -+}; -+ - // Our general connection to Wayland display server, - // holds our display connection and runs event loop. - class nsWaylandDisplay { - public: - explicit nsWaylandDisplay(wl_display* aDisplay); - virtual ~nsWaylandDisplay(); - - bool DispatchEventQueue(); -@@ -41,28 +60,143 @@ class nsWaylandDisplay { - void SetSubcompositor(wl_subcompositor* aSubcompositor); - void SetDataDeviceManager(wl_data_device_manager* aDataDeviceManager); - void SetSeat(wl_seat* aSeat); - void SetPrimarySelectionDeviceManager( - gtk_primary_selection_device_manager* aPrimarySelectionDeviceManager); - - void Shutdown(); - -+#ifdef HAVE_LIBDRM -+ void SetDmabuf(zwp_linux_dmabuf_v1* aDmabuf); -+ zwp_linux_dmabuf_v1* GetDmabuf() { return mDmabuf; }; -+ gbm_device* GetGbmDevice(); -+ int GetGbmDeviceFd(); -+ bool IsExplicitSyncEnabled() { return mExplicitSync; } -+ GbmFormat* GetGbmFormat(bool aHasAlpha); -+ void AddFormatModifier(bool aHasAlpha, int aFormat, uint32_t mModifierHi, -+ uint32_t mModifierLo); -+#endif -+ - private: -+#ifdef HAVE_LIBDRM -+ bool ConfigureGbm(); -+#endif -+ - MessageLoop* mDispatcherThreadLoop; - PRThread* mThreadId; - wl_display* mDisplay; - wl_event_queue* mEventQueue; - wl_data_device_manager* mDataDeviceManager; - wl_subcompositor* mSubcompositor; - wl_seat* mSeat; - wl_shm* mShm; - gtk_primary_selection_device_manager* mPrimarySelectionDeviceManager; - wl_registry* mRegistry; -+#ifdef HAVE_LIBDRM -+ zwp_linux_dmabuf_v1* mDmabuf; -+ gbm_device* mGbmDevice; -+ int mGbmFd; -+ bool mGdmConfigured; -+ bool mExplicitSync; -+ GbmFormat mXRGBFormat; -+ GbmFormat mARGBFormat; -+#endif - }; - - void WaylandDispatchDisplays(); - nsWaylandDisplay* WaylandDisplayGet(GdkDisplay* aGdkDisplay = nullptr); - -+#ifdef HAVE_LIBDRM -+typedef struct gbm_device* (*CreateDeviceFunc)(int); -+typedef struct gbm_bo* (*CreateFunc)(struct gbm_device*, uint32_t, uint32_t, -+ uint32_t, uint32_t); -+typedef struct gbm_bo* (*CreateFunc)(struct gbm_device*, uint32_t, uint32_t, -+ uint32_t, uint32_t); -+typedef struct gbm_bo* (*CreateWithModifiersFunc)(struct gbm_device*, uint32_t, -+ uint32_t, uint32_t, -+ const uint64_t*, -+ const unsigned int); -+typedef uint64_t (*GetModifierFunc)(struct gbm_bo*); -+typedef uint32_t (*GetStrideFunc)(struct gbm_bo*); -+typedef int (*GetFdFunc)(struct gbm_bo*); -+typedef void (*DestroyFunc)(struct gbm_bo*); -+typedef void* (*MapFunc)(struct gbm_bo*, uint32_t, uint32_t, uint32_t, uint32_t, -+ uint32_t, uint32_t*, void**); -+typedef void (*UnmapFunc)(struct gbm_bo*, void*); -+typedef int (*GetPlaneCountFunc)(struct gbm_bo*); -+typedef union gbm_bo_handle (*GetHandleForPlaneFunc)(struct gbm_bo*, int); -+typedef uint32_t (*GetStrideForPlaneFunc)(struct gbm_bo*, int); -+typedef uint32_t (*GetOffsetFunc)(struct gbm_bo*, int); -+ -+typedef int (*DrmPrimeHandleToFDFunc)(int, uint32_t, uint32_t, int*); -+ -+class nsGbmLib { -+ public: -+ static bool Load(); -+ static bool IsAvailable(); -+ static bool IsModifierAvailable(); -+ -+ static struct gbm_device* CreateDevice(int fd) { return sCreateDevice(fd); }; -+ static struct gbm_bo* Create(struct gbm_device* gbm, uint32_t width, -+ uint32_t height, uint32_t format, -+ uint32_t flags) { -+ return sCreate(gbm, width, height, format, flags); -+ } -+ static void Destroy(struct gbm_bo* bo) { sDestroy(bo); } -+ static uint32_t GetStride(struct gbm_bo* bo) { return sGetStride(bo); } -+ static int GetFd(struct gbm_bo* bo) { return sGetFd(bo); } -+ static void* Map(struct gbm_bo* bo, uint32_t x, uint32_t y, uint32_t width, -+ uint32_t height, uint32_t flags, uint32_t* stride, -+ void** map_data) { -+ return sMap(bo, x, y, width, height, flags, stride, map_data); -+ } -+ static void Unmap(struct gbm_bo* bo, void* map_data) { sUnmap(bo, map_data); } -+ static struct gbm_bo* CreateWithModifiers(struct gbm_device* gbm, -+ uint32_t width, uint32_t height, -+ uint32_t format, -+ const uint64_t* modifiers, -+ const unsigned int count) { -+ return sCreateWithModifiers(gbm, width, height, format, modifiers, count); -+ } -+ static uint64_t GetModifier(struct gbm_bo* bo) { return sGetModifier(bo); } -+ static int GetPlaneCount(struct gbm_bo* bo) { return sGetPlaneCount(bo); } -+ static union gbm_bo_handle GetHandleForPlane(struct gbm_bo* bo, int plane) { -+ return sGetHandleForPlane(bo, plane); -+ } -+ static uint32_t GetStrideForPlane(struct gbm_bo* bo, int plane) { -+ return sGetStrideForPlane(bo, plane); -+ } -+ static uint32_t GetOffset(struct gbm_bo* bo, int plane) { -+ return sGetOffset(bo, plane); -+ } -+ -+ static int DrmPrimeHandleToFD(int fd, uint32_t handle, uint32_t flags, -+ int* prime_fd) { -+ return sDrmPrimeHandleToFD(fd, handle, flags, prime_fd); -+ } -+ -+ private: -+ static CreateDeviceFunc sCreateDevice; -+ static CreateFunc sCreate; -+ static CreateWithModifiersFunc sCreateWithModifiers; -+ static GetModifierFunc sGetModifier; -+ static GetStrideFunc sGetStride; -+ static GetFdFunc sGetFd; -+ static DestroyFunc sDestroy; -+ static MapFunc sMap; -+ static UnmapFunc sUnmap; -+ static GetPlaneCountFunc sGetPlaneCount; -+ static GetHandleForPlaneFunc sGetHandleForPlane; -+ static GetStrideForPlaneFunc sGetStrideForPlane; -+ static GetOffsetFunc sGetOffset; -+ static DrmPrimeHandleToFDFunc sDrmPrimeHandleToFD; -+ -+ static void* sGbmLibHandle; -+ static void* sXf86DrmLibHandle; -+ static bool sLibLoaded; -+}; -+#endif -+ - } // namespace widget - } // namespace mozilla - --#endif // __MOZ_WAYLAND_REGISTRY_H__ -+#endif // __MOZ_WAYLAND_DISPLAY_H__ -diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp ---- a/widget/gtk/nsWindow.cpp -+++ b/widget/gtk/nsWindow.cpp -@@ -4237,17 +4237,18 @@ LayoutDeviceIntSize nsWindow::GetSafeWin - // reads it as CARD16. Sizes of pixmaps, used for drawing, are (unsigned) - // CARD16 in the protocol, but the server's ProcCreatePixmap returns - // BadAlloc if dimensions cannot be represented by signed shorts. - // Because we are creating Cairo surfaces to represent window buffers, - // we also must ensure that the window can fit in a Cairo surface. - LayoutDeviceIntSize result = aSize; - int32_t maxSize = 32767; - if (mLayerManager && mLayerManager->AsKnowsCompositor()) { -- maxSize = std::min(maxSize, mLayerManager->AsKnowsCompositor()->GetMaxTextureSize()); -+ maxSize = std::min(maxSize, -+ mLayerManager->AsKnowsCompositor()->GetMaxTextureSize()); - } - if (result.width > maxSize) { - result.width = maxSize; - } - if (result.height > maxSize) { - result.height = maxSize; - } - return result; -@@ -6827,21 +6828,24 @@ wl_surface* nsWindow::GetWaylandSurface( - "drawing!"); - return nullptr; - } - - bool nsWindow::WaylandSurfaceNeedsClear() { - if (mContainer) { - return moz_container_surface_needs_clear(MOZ_CONTAINER(mContainer)); - } -- -- NS_WARNING( -- "nsWindow::WaylandSurfaceNeedsClear(): We don't have any mContainer!"); - return false; - } -+ -+void nsWindow::WaylandSurfaceCleared() { -+ if (mContainer) { -+ return moz_container_surface_cleared(MOZ_CONTAINER(mContainer)); -+ } -+} - #endif - - #ifdef MOZ_X11 - /* XApp progress support currently works by setting a property - * on a window with this Atom name. A supporting window manager - * will notice this and pass it along to whatever handling has - * been implemented on that end (e.g. passing it on to a taskbar - * widget.) There is no issue if WM support is lacking, this is -diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h ---- a/widget/gtk/nsWindow.h -+++ b/widget/gtk/nsWindow.h -@@ -341,16 +341,17 @@ class nsWindow final : public nsBaseWidg - - #ifdef MOZ_X11 - Display* XDisplay() { return mXDisplay; } - #endif - #ifdef MOZ_WAYLAND - wl_display* GetWaylandDisplay(); - wl_surface* GetWaylandSurface(); - bool WaylandSurfaceNeedsClear(); -+ void WaylandSurfaceCleared(); - #endif - virtual void GetCompositorWidgetInitData( - mozilla::widget::CompositorWidgetInitData* aInitData) override; - - virtual nsresult SetNonClientMargins( - LayoutDeviceIntMargin& aMargins) override; - void SetDrawsInTitlebar(bool aState) override; - virtual void UpdateWindowDraggingRegion( -diff --git a/widget/gtk/wayland/linux-dmabuf-unstable-v1-client-protocol.h b/widget/gtk/wayland/linux-dmabuf-unstable-v1-client-protocol.h -new file mode 100644 ---- /dev/null -+++ b/widget/gtk/wayland/linux-dmabuf-unstable-v1-client-protocol.h -@@ -0,0 +1,650 @@ -+/* Generated by wayland-scanner 1.17.0 */ -+ -+#ifndef LINUX_DMABUF_UNSTABLE_V1_CLIENT_PROTOCOL_H -+#define LINUX_DMABUF_UNSTABLE_V1_CLIENT_PROTOCOL_H -+ -+#include <stdint.h> -+#include <stddef.h> -+#include "wayland-client.h" -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/** -+ * @page page_linux_dmabuf_unstable_v1 The linux_dmabuf_unstable_v1 protocol -+ * @section page_ifaces_linux_dmabuf_unstable_v1 Interfaces -+ * - @subpage page_iface_zwp_linux_dmabuf_v1 - factory for creating dmabuf-based -+ * wl_buffers -+ * - @subpage page_iface_zwp_linux_buffer_params_v1 - parameters for creating a -+ * dmabuf-based wl_buffer -+ * @section page_copyright_linux_dmabuf_unstable_v1 Copyright -+ * <pre> -+ * -+ * Copyright © 2014, 2015 Collabora, Ltd. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice (including the next -+ * paragraph) shall be included in all copies or substantial portions of the -+ * Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ * </pre> -+ */ -+struct wl_buffer; -+struct zwp_linux_buffer_params_v1; -+struct zwp_linux_dmabuf_v1; -+ -+/** -+ * @page page_iface_zwp_linux_dmabuf_v1 zwp_linux_dmabuf_v1 -+ * @section page_iface_zwp_linux_dmabuf_v1_desc Description -+ * -+ * Following the interfaces from: -+ * https://www.khronos.org/registry/egl/extensions/EXT/EGL_EXT_image_dma_buf_import.txt -+ * and the Linux DRM sub-system's AddFb2 ioctl. -+ * -+ * This interface offers ways to create generic dmabuf-based -+ * wl_buffers. Immediately after a client binds to this interface, -+ * the set of supported formats and format modifiers is sent with -+ * 'format' and 'modifier' events. -+ * -+ * The following are required from clients: -+ * -+ * - Clients must ensure that either all data in the dma-buf is -+ * coherent for all subsequent read access or that coherency is -+ * correctly handled by the underlying kernel-side dma-buf -+ * implementation. -+ * -+ * - Don't make any more attachments after sending the buffer to the -+ * compositor. Making more attachments later increases the risk of -+ * the compositor not being able to use (re-import) an existing -+ * dmabuf-based wl_buffer. -+ * -+ * The underlying graphics stack must ensure the following: -+ * -+ * - The dmabuf file descriptors relayed to the server will stay valid -+ * for the whole lifetime of the wl_buffer. This means the server may -+ * at any time use those fds to import the dmabuf into any kernel -+ * sub-system that might accept it. -+ * -+ * To create a wl_buffer from one or more dmabufs, a client creates a -+ * zwp_linux_dmabuf_params_v1 object with a zwp_linux_dmabuf_v1.create_params -+ * request. All planes required by the intended format are added with -+ * the 'add' request. Finally, a 'create' or 'create_immed' request is -+ * issued, which has the following outcome depending on the import success. -+ * -+ * The 'create' request, -+ * - on success, triggers a 'created' event which provides the final -+ * wl_buffer to the client. -+ * - on failure, triggers a 'failed' event to convey that the server -+ * cannot use the dmabufs received from the client. -+ * -+ * For the 'create_immed' request, -+ * - on success, the server immediately imports the added dmabufs to -+ * create a wl_buffer. No event is sent from the server in this case. -+ * - on failure, the server can choose to either: -+ * - terminate the client by raising a fatal error. -+ * - mark the wl_buffer as failed, and send a 'failed' event to the -+ * client. If the client uses a failed wl_buffer as an argument to any -+ * request, the behaviour is compositor implementation-defined. -+ * -+ * Warning! The protocol described in this file is experimental and -+ * backward incompatible changes may be made. Backward compatible changes -+ * may be added together with the corresponding interface version bump. -+ * Backward incompatible changes are done by bumping the version number in -+ * the protocol and interface names and resetting the interface version. -+ * Once the protocol is to be declared stable, the 'z' prefix and the -+ * version number in the protocol and interface names are removed and the -+ * interface version number is reset. -+ * @section page_iface_zwp_linux_dmabuf_v1_api API -+ * See @ref iface_zwp_linux_dmabuf_v1. -+ */ -+/** -+ * @defgroup iface_zwp_linux_dmabuf_v1 The zwp_linux_dmabuf_v1 interface -+ * -+ * Following the interfaces from: -+ * https://www.khronos.org/registry/egl/extensions/EXT/EGL_EXT_image_dma_buf_import.txt -+ * and the Linux DRM sub-system's AddFb2 ioctl. -+ * -+ * This interface offers ways to create generic dmabuf-based -+ * wl_buffers. Immediately after a client binds to this interface, -+ * the set of supported formats and format modifiers is sent with -+ * 'format' and 'modifier' events. -+ * -+ * The following are required from clients: -+ * -+ * - Clients must ensure that either all data in the dma-buf is -+ * coherent for all subsequent read access or that coherency is -+ * correctly handled by the underlying kernel-side dma-buf -+ * implementation. -+ * -+ * - Don't make any more attachments after sending the buffer to the -+ * compositor. Making more attachments later increases the risk of -+ * the compositor not being able to use (re-import) an existing -+ * dmabuf-based wl_buffer. -+ * -+ * The underlying graphics stack must ensure the following: -+ * -+ * - The dmabuf file descriptors relayed to the server will stay valid -+ * for the whole lifetime of the wl_buffer. This means the server may -+ * at any time use those fds to import the dmabuf into any kernel -+ * sub-system that might accept it. -+ * -+ * To create a wl_buffer from one or more dmabufs, a client creates a -+ * zwp_linux_dmabuf_params_v1 object with a zwp_linux_dmabuf_v1.create_params -+ * request. All planes required by the intended format are added with -+ * the 'add' request. Finally, a 'create' or 'create_immed' request is -+ * issued, which has the following outcome depending on the import success. -+ * -+ * The 'create' request, -+ * - on success, triggers a 'created' event which provides the final -+ * wl_buffer to the client. -+ * - on failure, triggers a 'failed' event to convey that the server -+ * cannot use the dmabufs received from the client. -+ * -+ * For the 'create_immed' request, -+ * - on success, the server immediately imports the added dmabufs to -+ * create a wl_buffer. No event is sent from the server in this case. -+ * - on failure, the server can choose to either: -+ * - terminate the client by raising a fatal error. -+ * - mark the wl_buffer as failed, and send a 'failed' event to the -+ * client. If the client uses a failed wl_buffer as an argument to any -+ * request, the behaviour is compositor implementation-defined. -+ * -+ * Warning! The protocol described in this file is experimental and -+ * backward incompatible changes may be made. Backward compatible changes -+ * may be added together with the corresponding interface version bump. -+ * Backward incompatible changes are done by bumping the version number in -+ * the protocol and interface names and resetting the interface version. -+ * Once the protocol is to be declared stable, the 'z' prefix and the -+ * version number in the protocol and interface names are removed and the -+ * interface version number is reset. -+ */ -+extern const struct wl_interface zwp_linux_dmabuf_v1_interface; -+/** -+ * @page page_iface_zwp_linux_buffer_params_v1 zwp_linux_buffer_params_v1 -+ * @section page_iface_zwp_linux_buffer_params_v1_desc Description -+ * -+ * This temporary object is a collection of dmabufs and other -+ * parameters that together form a single logical buffer. The temporary -+ * object may eventually create one wl_buffer unless cancelled by -+ * destroying it before requesting 'create'. -+ * -+ * Single-planar formats only require one dmabuf, however -+ * multi-planar formats may require more than one dmabuf. For all -+ * formats, an 'add' request must be called once per plane (even if the -+ * underlying dmabuf fd is identical). -+ * -+ * You must use consecutive plane indices ('plane_idx' argument for 'add') -+ * from zero to the number of planes used by the drm_fourcc format code. -+ * All planes required by the format must be given exactly once, but can -+ * be given in any order. Each plane index can be set only once. -+ * @section page_iface_zwp_linux_buffer_params_v1_api API -+ * See @ref iface_zwp_linux_buffer_params_v1. -+ */ -+/** -+ * @defgroup iface_zwp_linux_buffer_params_v1 The zwp_linux_buffer_params_v1 -+ * interface -+ * -+ * This temporary object is a collection of dmabufs and other -+ * parameters that together form a single logical buffer. The temporary -+ * object may eventually create one wl_buffer unless cancelled by -+ * destroying it before requesting 'create'. -+ * -+ * Single-planar formats only require one dmabuf, however -+ * multi-planar formats may require more than one dmabuf. For all -+ * formats, an 'add' request must be called once per plane (even if the -+ * underlying dmabuf fd is identical). -+ * -+ * You must use consecutive plane indices ('plane_idx' argument for 'add') -+ * from zero to the number of planes used by the drm_fourcc format code. -+ * All planes required by the format must be given exactly once, but can -+ * be given in any order. Each plane index can be set only once. -+ */ -+extern const struct wl_interface zwp_linux_buffer_params_v1_interface; -+ -+/** -+ * @ingroup iface_zwp_linux_dmabuf_v1 -+ * @struct zwp_linux_dmabuf_v1_listener -+ */ -+struct zwp_linux_dmabuf_v1_listener { -+ /** -+ * supported buffer format -+ * -+ * This event advertises one buffer format that the server -+ * supports. All the supported formats are advertised once when the -+ * client binds to this interface. A roundtrip after binding -+ * guarantees that the client has received all supported formats. -+ * -+ * For the definition of the format codes, see the -+ * zwp_linux_buffer_params_v1::create request. -+ * -+ * Warning: the 'format' event is likely to be deprecated and -+ * replaced with the 'modifier' event introduced in -+ * zwp_linux_dmabuf_v1 version 3, described below. Please refrain -+ * from using the information received from this event. -+ * @param format DRM_FORMAT code -+ */ -+ void (*format)(void* data, struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf_v1, -+ uint32_t format); -+ /** -+ * supported buffer format modifier -+ * -+ * This event advertises the formats that the server supports, -+ * along with the modifiers supported for each format. All the -+ * supported modifiers for all the supported formats are advertised -+ * once when the client binds to this interface. A roundtrip after -+ * binding guarantees that the client has received all supported -+ * format-modifier pairs. -+ * -+ * For the definition of the format and modifier codes, see the -+ * zwp_linux_buffer_params_v1::create request. -+ * @param format DRM_FORMAT code -+ * @param modifier_hi high 32 bits of layout modifier -+ * @param modifier_lo low 32 bits of layout modifier -+ * @since 3 -+ */ -+ void (*modifier)(void* data, struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf_v1, -+ uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo); -+}; -+ -+/** -+ * @ingroup iface_zwp_linux_dmabuf_v1 -+ */ -+static inline int zwp_linux_dmabuf_v1_add_listener( -+ struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf_v1, -+ const struct zwp_linux_dmabuf_v1_listener* listener, void* data) { -+ return wl_proxy_add_listener((struct wl_proxy*)zwp_linux_dmabuf_v1, -+ (void (**)(void))listener, data); -+} -+ -+#define ZWP_LINUX_DMABUF_V1_DESTROY 0 -+#define ZWP_LINUX_DMABUF_V1_CREATE_PARAMS 1 -+ -+/** -+ * @ingroup iface_zwp_linux_dmabuf_v1 -+ */ -+#define ZWP_LINUX_DMABUF_V1_FORMAT_SINCE_VERSION 1 -+/** -+ * @ingroup iface_zwp_linux_dmabuf_v1 -+ */ -+#define ZWP_LINUX_DMABUF_V1_MODIFIER_SINCE_VERSION 3 -+ -+/** -+ * @ingroup iface_zwp_linux_dmabuf_v1 -+ */ -+#define ZWP_LINUX_DMABUF_V1_DESTROY_SINCE_VERSION 1 -+/** -+ * @ingroup iface_zwp_linux_dmabuf_v1 -+ */ -+#define ZWP_LINUX_DMABUF_V1_CREATE_PARAMS_SINCE_VERSION 1 -+ -+/** @ingroup iface_zwp_linux_dmabuf_v1 */ -+static inline void zwp_linux_dmabuf_v1_set_user_data( -+ struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf_v1, void* user_data) { -+ wl_proxy_set_user_data((struct wl_proxy*)zwp_linux_dmabuf_v1, user_data); -+} -+ -+/** @ingroup iface_zwp_linux_dmabuf_v1 */ -+static inline void* zwp_linux_dmabuf_v1_get_user_data( -+ struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf_v1) { -+ return wl_proxy_get_user_data((struct wl_proxy*)zwp_linux_dmabuf_v1); -+} -+ -+static inline uint32_t zwp_linux_dmabuf_v1_get_version( -+ struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf_v1) { -+ return wl_proxy_get_version((struct wl_proxy*)zwp_linux_dmabuf_v1); -+} -+ -+/** -+ * @ingroup iface_zwp_linux_dmabuf_v1 -+ * -+ * Objects created through this interface, especially wl_buffers, will -+ * remain valid. -+ */ -+static inline void zwp_linux_dmabuf_v1_destroy( -+ struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf_v1) { -+ wl_proxy_marshal((struct wl_proxy*)zwp_linux_dmabuf_v1, -+ ZWP_LINUX_DMABUF_V1_DESTROY); -+ -+ wl_proxy_destroy((struct wl_proxy*)zwp_linux_dmabuf_v1); -+} -+ -+/** -+ * @ingroup iface_zwp_linux_dmabuf_v1 -+ * -+ * This temporary object is used to collect multiple dmabuf handles into -+ * a single batch to create a wl_buffer. It can only be used once and -+ * should be destroyed after a 'created' or 'failed' event has been -+ * received. -+ */ -+static inline struct zwp_linux_buffer_params_v1* -+zwp_linux_dmabuf_v1_create_params( -+ struct zwp_linux_dmabuf_v1* zwp_linux_dmabuf_v1) { -+ struct wl_proxy* params_id; -+ -+ params_id = wl_proxy_marshal_constructor( -+ (struct wl_proxy*)zwp_linux_dmabuf_v1, ZWP_LINUX_DMABUF_V1_CREATE_PARAMS, -+ &zwp_linux_buffer_params_v1_interface, NULL); -+ -+ return (struct zwp_linux_buffer_params_v1*)params_id; -+} -+ -+#ifndef ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ENUM -+# define ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ENUM -+enum zwp_linux_buffer_params_v1_error { -+ /** -+ * the dmabuf_batch object has already been used to create a wl_buffer -+ */ -+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED = 0, -+ /** -+ * plane index out of bounds -+ */ -+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX = 1, -+ /** -+ * the plane index was already set -+ */ -+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET = 2, -+ /** -+ * missing or too many planes to create a buffer -+ */ -+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE = 3, -+ /** -+ * format not supported -+ */ -+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_FORMAT = 4, -+ /** -+ * invalid width or height -+ */ -+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS = 5, -+ /** -+ * offset + stride * height goes out of dmabuf bounds -+ */ -+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS = 6, -+ /** -+ * invalid wl_buffer resulted from importing dmabufs via the -+ * create_immed request on given buffer_params -+ */ -+ ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_WL_BUFFER = 7, -+}; -+#endif /* ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ENUM */ -+ -+#ifndef ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_ENUM -+# define ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_ENUM -+enum zwp_linux_buffer_params_v1_flags { -+ /** -+ * contents are y-inverted -+ */ -+ ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT = 1, -+ /** -+ * content is interlaced -+ */ -+ ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_INTERLACED = 2, -+ /** -+ * bottom field first -+ */ -+ ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_BOTTOM_FIRST = 4, -+}; -+#endif /* ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_ENUM */ -+ -+/** -+ * @ingroup iface_zwp_linux_buffer_params_v1 -+ * @struct zwp_linux_buffer_params_v1_listener -+ */ -+struct zwp_linux_buffer_params_v1_listener { -+ /** -+ * buffer creation succeeded -+ * -+ * This event indicates that the attempted buffer creation was -+ * successful. It provides the new wl_buffer referencing the -+ * dmabuf(s). -+ * -+ * Upon receiving this event, the client should destroy the -+ * zlinux_dmabuf_params object. -+ * @param buffer the newly created wl_buffer -+ */ -+ void (*created)(void* data, -+ struct zwp_linux_buffer_params_v1* zwp_linux_buffer_params_v1, -+ struct wl_buffer* buffer); -+ /** -+ * buffer creation failed -+ * -+ * This event indicates that the attempted buffer creation has -+ * failed. It usually means that one of the dmabuf constraints has -+ * not been fulfilled. -+ * -+ * Upon receiving this event, the client should destroy the -+ * zlinux_buffer_params object. -+ */ -+ void (*failed)(void* data, -+ struct zwp_linux_buffer_params_v1* zwp_linux_buffer_params_v1); -+}; -+ -+/** -+ * @ingroup iface_zwp_linux_buffer_params_v1 -+ */ -+static inline int zwp_linux_buffer_params_v1_add_listener( -+ struct zwp_linux_buffer_params_v1* zwp_linux_buffer_params_v1, -+ const struct zwp_linux_buffer_params_v1_listener* listener, void* data) { -+ return wl_proxy_add_listener((struct wl_proxy*)zwp_linux_buffer_params_v1, -+ (void (**)(void))listener, data); -+} -+ -+#define ZWP_LINUX_BUFFER_PARAMS_V1_DESTROY 0 -+#define ZWP_LINUX_BUFFER_PARAMS_V1_ADD 1 -+#define ZWP_LINUX_BUFFER_PARAMS_V1_CREATE 2 -+#define ZWP_LINUX_BUFFER_PARAMS_V1_CREATE_IMMED 3 -+ -+/** -+ * @ingroup iface_zwp_linux_buffer_params_v1 -+ */ -+#define ZWP_LINUX_BUFFER_PARAMS_V1_CREATED_SINCE_VERSION 1 -+/** -+ * @ingroup iface_zwp_linux_buffer_params_v1 -+ */ -+#define ZWP_LINUX_BUFFER_PARAMS_V1_FAILED_SINCE_VERSION 1 -+ -+/** -+ * @ingroup iface_zwp_linux_buffer_params_v1 -+ */ -+#define ZWP_LINUX_BUFFER_PARAMS_V1_DESTROY_SINCE_VERSION 1 -+/** -+ * @ingroup iface_zwp_linux_buffer_params_v1 -+ */ -+#define ZWP_LINUX_BUFFER_PARAMS_V1_ADD_SINCE_VERSION 1 -+/** -+ * @ingroup iface_zwp_linux_buffer_params_v1 -+ */ -+#define ZWP_LINUX_BUFFER_PARAMS_V1_CREATE_SINCE_VERSION 1 -+/** -+ * @ingroup iface_zwp_linux_buffer_params_v1 -+ */ -+#define ZWP_LINUX_BUFFER_PARAMS_V1_CREATE_IMMED_SINCE_VERSION 2 -+ -+/** @ingroup iface_zwp_linux_buffer_params_v1 */ -+static inline void zwp_linux_buffer_params_v1_set_user_data( -+ struct zwp_linux_buffer_params_v1* zwp_linux_buffer_params_v1, -+ void* user_data) { -+ wl_proxy_set_user_data((struct wl_proxy*)zwp_linux_buffer_params_v1, -+ user_data); -+} -+ -+/** @ingroup iface_zwp_linux_buffer_params_v1 */ -+static inline void* zwp_linux_buffer_params_v1_get_user_data( -+ struct zwp_linux_buffer_params_v1* zwp_linux_buffer_params_v1) { -+ return wl_proxy_get_user_data((struct wl_proxy*)zwp_linux_buffer_params_v1); -+} -+ -+static inline uint32_t zwp_linux_buffer_params_v1_get_version( -+ struct zwp_linux_buffer_params_v1* zwp_linux_buffer_params_v1) { -+ return wl_proxy_get_version((struct wl_proxy*)zwp_linux_buffer_params_v1); -+} -+ -+/** -+ * @ingroup iface_zwp_linux_buffer_params_v1 -+ * -+ * Cleans up the temporary data sent to the server for dmabuf-based -+ * wl_buffer creation. -+ */ -+static inline void zwp_linux_buffer_params_v1_destroy( -+ struct zwp_linux_buffer_params_v1* zwp_linux_buffer_params_v1) { -+ wl_proxy_marshal((struct wl_proxy*)zwp_linux_buffer_params_v1, -+ ZWP_LINUX_BUFFER_PARAMS_V1_DESTROY); -+ -+ wl_proxy_destroy((struct wl_proxy*)zwp_linux_buffer_params_v1); -+} -+ -+/** -+ * @ingroup iface_zwp_linux_buffer_params_v1 -+ * -+ * This request adds one dmabuf to the set in this -+ * zwp_linux_buffer_params_v1. -+ * -+ * The 64-bit unsigned value combined from modifier_hi and modifier_lo -+ * is the dmabuf layout modifier. DRM AddFB2 ioctl calls this the -+ * fb modifier, which is defined in drm_mode.h of Linux UAPI. -+ * This is an opaque token. Drivers use this token to express tiling, -+ * compression, etc. driver-specific modifications to the base format -+ * defined by the DRM fourcc code. -+ * -+ * This request raises the PLANE_IDX error if plane_idx is too large. -+ * The error PLANE_SET is raised if attempting to set a plane that -+ * was already set. -+ */ -+static inline void zwp_linux_buffer_params_v1_add( -+ struct zwp_linux_buffer_params_v1* zwp_linux_buffer_params_v1, int32_t fd, -+ uint32_t plane_idx, uint32_t offset, uint32_t stride, uint32_t modifier_hi, -+ uint32_t modifier_lo) { -+ wl_proxy_marshal((struct wl_proxy*)zwp_linux_buffer_params_v1, -+ ZWP_LINUX_BUFFER_PARAMS_V1_ADD, fd, plane_idx, offset, -+ stride, modifier_hi, modifier_lo); -+} -+ -+/** -+ * @ingroup iface_zwp_linux_buffer_params_v1 -+ * -+ * This asks for creation of a wl_buffer from the added dmabuf -+ * buffers. The wl_buffer is not created immediately but returned via -+ * the 'created' event if the dmabuf sharing succeeds. The sharing -+ * may fail at runtime for reasons a client cannot predict, in -+ * which case the 'failed' event is triggered. -+ * -+ * The 'format' argument is a DRM_FORMAT code, as defined by the -+ * libdrm's drm_fourcc.h. The Linux kernel's DRM sub-system is the -+ * authoritative source on how the format codes should work. -+ * -+ * The 'flags' is a bitfield of the flags defined in enum "flags". -+ * 'y_invert' means the that the image needs to be y-flipped. -+ * -+ * Flag 'interlaced' means that the frame in the buffer is not -+ * progressive as usual, but interlaced. An interlaced buffer as -+ * supported here must always contain both top and bottom fields. -+ * The top field always begins on the first pixel row. The temporal -+ * ordering between the two fields is top field first, unless -+ * 'bottom_first' is specified. It is undefined whether 'bottom_first' -+ * is ignored if 'interlaced' is not set. -+ * -+ * This protocol does not convey any information about field rate, -+ * duration, or timing, other than the relative ordering between the -+ * two fields in one buffer. A compositor may have to estimate the -+ * intended field rate from the incoming buffer rate. It is undefined -+ * whether the time of receiving wl_surface.commit with a new buffer -+ * attached, applying the wl_surface state, wl_surface.frame callback -+ * trigger, presentation, or any other point in the compositor cycle -+ * is used to measure the frame or field times. There is no support -+ * for detecting missed or late frames/fields/buffers either, and -+ * there is no support whatsoever for cooperating with interlaced -+ * compositor output. -+ * -+ * The composited image quality resulting from the use of interlaced -+ * buffers is explicitly undefined. A compositor may use elaborate -+ * hardware features or software to deinterlace and create progressive -+ * output frames from a sequence of interlaced input buffers, or it -+ * may produce substandard image quality. However, compositors that -+ * cannot guarantee reasonable image quality in all cases are recommended -+ * to just reject all interlaced buffers. -+ * -+ * Any argument errors, including non-positive width or height, -+ * mismatch between the number of planes and the format, bad -+ * format, bad offset or stride, may be indicated by fatal protocol -+ * errors: INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS, -+ * OUT_OF_BOUNDS. -+ * -+ * Dmabuf import errors in the server that are not obvious client -+ * bugs are returned via the 'failed' event as non-fatal. This -+ * allows attempting dmabuf sharing and falling back in the client -+ * if it fails. -+ * -+ * This request can be sent only once in the object's lifetime, after -+ * which the only legal request is destroy. This object should be -+ * destroyed after issuing a 'create' request. Attempting to use this -+ * object after issuing 'create' raises ALREADY_USED protocol error. -+ * -+ * It is not mandatory to issue 'create'. If a client wants to -+ * cancel the buffer creation, it can just destroy this object. -+ */ -+static inline void zwp_linux_buffer_params_v1_create( -+ struct zwp_linux_buffer_params_v1* zwp_linux_buffer_params_v1, -+ int32_t width, int32_t height, uint32_t format, uint32_t flags) { -+ wl_proxy_marshal((struct wl_proxy*)zwp_linux_buffer_params_v1, -+ ZWP_LINUX_BUFFER_PARAMS_V1_CREATE, width, height, format, -+ flags); -+} -+ -+/** -+ * @ingroup iface_zwp_linux_buffer_params_v1 -+ * -+ * This asks for immediate creation of a wl_buffer by importing the -+ * added dmabufs. -+ * -+ * In case of import success, no event is sent from the server, and the -+ * wl_buffer is ready to be used by the client. -+ * -+ * Upon import failure, either of the following may happen, as seen fit -+ * by the implementation: -+ * - the client is terminated with one of the following fatal protocol -+ * errors: -+ * - INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS, OUT_OF_BOUNDS, -+ * in case of argument errors such as mismatch between the number -+ * of planes and the format, bad format, non-positive width or -+ * height, or bad offset or stride. -+ * - INVALID_WL_BUFFER, in case the cause for failure is unknown or -+ * plaform specific. -+ * - the server creates an invalid wl_buffer, marks it as failed and -+ * sends a 'failed' event to the client. The result of using this -+ * invalid wl_buffer as an argument in any request by the client is -+ * defined by the compositor implementation. -+ * -+ * This takes the same arguments as a 'create' request, and obeys the -+ * same restrictions. -+ */ -+static inline struct wl_buffer* zwp_linux_buffer_params_v1_create_immed( -+ struct zwp_linux_buffer_params_v1* zwp_linux_buffer_params_v1, -+ int32_t width, int32_t height, uint32_t format, uint32_t flags) { -+ struct wl_proxy* buffer_id; -+ -+ buffer_id = wl_proxy_marshal_constructor( -+ (struct wl_proxy*)zwp_linux_buffer_params_v1, -+ ZWP_LINUX_BUFFER_PARAMS_V1_CREATE_IMMED, &wl_buffer_interface, NULL, -+ width, height, format, flags); -+ -+ return (struct wl_buffer*)buffer_id; -+} -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif -diff --git a/widget/gtk/wayland/linux-dmabuf-unstable-v1-protocol.c b/widget/gtk/wayland/linux-dmabuf-unstable-v1-protocol.c -new file mode 100644 ---- /dev/null -+++ b/widget/gtk/wayland/linux-dmabuf-unstable-v1-protocol.c -@@ -0,0 +1,81 @@ -+/* Generated by wayland-scanner 1.17.0 */ -+ -+/* -+ * Copyright © 2014, 2015 Collabora, Ltd. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice (including the next -+ * paragraph) shall be included in all copies or substantial portions of the -+ * Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ */ -+ -+#include <stdlib.h> -+#include <stdint.h> -+#include "wayland-util.h" -+ -+#pragma GCC visibility push(default) -+extern const struct wl_interface wl_buffer_interface; -+extern const struct wl_interface zwp_linux_buffer_params_v1_interface; -+#pragma GCC visibility pop -+ -+static const struct wl_interface* types[] = { -+ NULL, -+ NULL, -+ NULL, -+ NULL, -+ NULL, -+ NULL, -+ &zwp_linux_buffer_params_v1_interface, -+ &wl_buffer_interface, -+ NULL, -+ NULL, -+ NULL, -+ NULL, -+ &wl_buffer_interface, -+}; -+ -+static const struct wl_message zwp_linux_dmabuf_v1_requests[] = { -+ {"destroy", "", types + 0}, -+ {"create_params", "n", types + 6}, -+}; -+ -+static const struct wl_message zwp_linux_dmabuf_v1_events[] = { -+ {"format", "u", types + 0}, -+ {"modifier", "3uuu", types + 0}, -+}; -+ -+const struct wl_interface zwp_linux_dmabuf_v1_interface = { -+ "zwp_linux_dmabuf_v1", 3, 2, -+ zwp_linux_dmabuf_v1_requests, 2, zwp_linux_dmabuf_v1_events, -+}; -+ -+static const struct wl_message zwp_linux_buffer_params_v1_requests[] = { -+ {"destroy", "", types + 0}, -+ {"add", "huuuuu", types + 0}, -+ {"create", "iiuu", types + 0}, -+ {"create_immed", "2niiuu", types + 7}, -+}; -+ -+static const struct wl_message zwp_linux_buffer_params_v1_events[] = { -+ {"created", "n", types + 12}, -+ {"failed", "", types + 0}, -+}; -+ -+const struct wl_interface zwp_linux_buffer_params_v1_interface = { -+ "zwp_linux_buffer_params_v1", 3, 4, -+ zwp_linux_buffer_params_v1_requests, 2, zwp_linux_buffer_params_v1_events, -+}; -diff --git a/widget/gtk/wayland/moz.build b/widget/gtk/wayland/moz.build ---- a/widget/gtk/wayland/moz.build -+++ b/widget/gtk/wayland/moz.build -@@ -4,16 +4,22 @@ - # License, v. 2.0. If a copy of the MPL was not distributed with this - # file, You can obtain one at http://mozilla.org/MPL/2.0/. - - with Files("**"): - BUG_COMPONENT = ("Core", "Widget: Gtk") - - SOURCES += [ - 'gtk-primary-selection-protocol.c', -+ 'linux-dmabuf-unstable-v1-protocol.c' -+] -+ -+EXPORTS.mozilla.widget += [ -+ 'gtk-primary-selection-client-protocol.h', -+ 'linux-dmabuf-unstable-v1-client-protocol.h', - ] - - include('/ipc/chromium/chromium-config.mozbuild') - - FINAL_LIBRARY = 'xul' - - CFLAGS += CONFIG['TK_CFLAGS'] - CXXFLAGS += CONFIG['TK_CFLAGS'] - |