From d37312c85acfb1a4754989329dfe326b15e88f02 Mon Sep 17 00:00:00 2001 From: Martin Stransky Date: Mon, 8 Oct 2018 14:09:44 +0200 Subject: Added new Wayland patches from Firefox 63, Added pipewire patch, Enabled Wayland by default for Fedora 30 --- mozilla-wayland-trunk.patch | 519 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 519 insertions(+) create mode 100644 mozilla-wayland-trunk.patch (limited to 'mozilla-wayland-trunk.patch') diff --git a/mozilla-wayland-trunk.patch b/mozilla-wayland-trunk.patch new file mode 100644 index 0000000..8c3746a --- /dev/null +++ b/mozilla-wayland-trunk.patch @@ -0,0 +1,519 @@ +Wayland patches from Firefox 63. + +diff -up firefox-62.0.3/widget/gtk/mozcontainer.cpp.old firefox-62.0.3/widget/gtk/mozcontainer.cpp +--- firefox-62.0.3/widget/gtk/mozcontainer.cpp.old 2018-10-08 11:52:33.442449788 +0200 ++++ firefox-62.0.3/widget/gtk/mozcontainer.cpp 2018-08-21 14:22:12.668885853 +0200 +@@ -605,6 +605,15 @@ moz_container_get_wl_surface(MozContaine + return nullptr; + + moz_container_map_surface(container); ++ // Set the scale factor for the buffer right after we create it. ++ if (container->surface) { ++ static auto sGdkWindowGetScaleFactorPtr = (gint (*)(GdkWindow*)) ++ dlsym(RTLD_DEFAULT, "gdk_window_get_scale_factor"); ++ if (sGdkWindowGetScaleFactorPtr && window) { ++ gint scaleFactor = (*sGdkWindowGetScaleFactorPtr)(window); ++ wl_surface_set_buffer_scale(container->surface, scaleFactor); ++ } ++ } + } + + return container->surface; +diff -up firefox-62.0.3/widget/gtk/WindowSurfaceWayland.cpp.old firefox-62.0.3/widget/gtk/WindowSurfaceWayland.cpp +--- firefox-62.0.3/widget/gtk/WindowSurfaceWayland.cpp.old 2018-10-08 11:52:47.907392869 +0200 ++++ firefox-62.0.3/widget/gtk/WindowSurfaceWayland.cpp 2018-09-06 11:01:18.801964790 +0200 +@@ -151,8 +151,9 @@ static nsWaylandDisplay* WaylandDisplayG + static void WaylandDisplayRelease(wl_display *aDisplay); + static void WaylandDisplayLoop(wl_display *aDisplay); + +-// TODO: is the 60pfs loop correct? +-#define EVENT_LOOP_DELAY (1000/60) ++// TODO: Bug 1467125 - We need to integrate wl_display_dispatch_queue_pending() with ++// compositor event loop. ++#define EVENT_LOOP_DELAY (1000/240) + + // Get WaylandDisplay for given wl_display and actual calling thread. + static nsWaylandDisplay* +@@ -523,7 +524,7 @@ WindowBackBuffer::Detach() + } + + bool +-WindowBackBuffer::SetImageDataFromBackBuffer( ++WindowBackBuffer::SetImageDataFromBuffer( + class WindowBackBuffer* aSourceBuffer) + { + if (!IsMatchingSize(aSourceBuffer)) { +@@ -550,6 +551,8 @@ frame_callback_handler(void *data, struc + { + auto surface = reinterpret_cast(data); + surface->FrameCallbackHandler(); ++ ++ gfxPlatformGtk::GetPlatform()->SetWaylandLastVsync(time); + } + + static const struct wl_callback_listener frame_listener = { +@@ -559,27 +562,40 @@ static const struct wl_callback_listener + WindowSurfaceWayland::WindowSurfaceWayland(nsWindow *aWindow) + : mWindow(aWindow) + , mWaylandDisplay(WaylandDisplayGet(aWindow->GetWaylandDisplay())) +- , mFrontBuffer(nullptr) +- , mBackBuffer(nullptr) ++ , mWaylandBuffer(nullptr) ++ , mBackupBuffer(nullptr) + , mFrameCallback(nullptr) +- , mFrameCallbackSurface(nullptr) ++ , mLastCommittedSurface(nullptr) + , mDisplayThreadMessageLoop(MessageLoop::current()) +- , mDirectWlBufferDraw(true) +- , mDelayedCommit(false) +- , mFullScreenDamage(false) ++ , mDelayedCommitHandle(nullptr) ++ , mDrawToWaylandBufferDirectly(true) ++ , mPendingCommit(false) ++ , mWaylandBufferFullScreenDamage(false) + , mIsMainThread(NS_IsMainThread()) ++ , mNeedScaleFactorUpdate(true) + { + } + + WindowSurfaceWayland::~WindowSurfaceWayland() + { +- delete mFrontBuffer; +- delete mBackBuffer; ++ if (mPendingCommit) { ++ NS_WARNING("Deleted WindowSurfaceWayland with a pending commit!"); ++ } ++ ++ if (mDelayedCommitHandle) { ++ // Delete reference to this to prevent WaylandBufferDelayCommitHandler() ++ // operate on released this. mDelayedCommitHandle itself will ++ // be released at WaylandBufferDelayCommitHandler(). ++ *mDelayedCommitHandle = nullptr; ++ } + + if (mFrameCallback) { + wl_callback_destroy(mFrameCallback); + } + ++ delete mWaylandBuffer; ++ delete mBackupBuffer; ++ + if (!mIsMainThread) { + // We can be destroyed from main thread even though we was created/used + // in compositor thread. We have to unref/delete WaylandDisplay in compositor +@@ -593,73 +609,64 @@ WindowSurfaceWayland::~WindowSurfaceWayl + } + } + +-void +-WindowSurfaceWayland::UpdateScaleFactor() +-{ +- wl_surface* waylandSurface = mWindow->GetWaylandSurface(); +- if (waylandSurface) { +- wl_surface_set_buffer_scale(waylandSurface, mWindow->GdkScaleFactor()); +- } +-} +- + WindowBackBuffer* +-WindowSurfaceWayland::GetFrontBufferToDraw(int aWidth, int aHeight) ++WindowSurfaceWayland::GetWaylandBufferToDraw(int aWidth, int aHeight) + { +- if (!mFrontBuffer) { +- mFrontBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight); +- mBackBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight); +- return mFrontBuffer; ++ if (!mWaylandBuffer) { ++ mWaylandBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight); ++ mBackupBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight); ++ return mWaylandBuffer; + } + +- if (!mFrontBuffer->IsAttached()) { +- if (!mFrontBuffer->IsMatchingSize(aWidth, aHeight)) { +- mFrontBuffer->Resize(aWidth, aHeight); ++ if (!mWaylandBuffer->IsAttached()) { ++ if (!mWaylandBuffer->IsMatchingSize(aWidth, aHeight)) { ++ mWaylandBuffer->Resize(aWidth, aHeight); + // There's a chance that scale factor has been changed + // when buffer size changed +- UpdateScaleFactor(); ++ mNeedScaleFactorUpdate = true; + } +- return mFrontBuffer; ++ return mWaylandBuffer; + } + + // Front buffer is used by compositor, draw to back buffer +- if (mBackBuffer->IsAttached()) { ++ if (mBackupBuffer->IsAttached()) { + NS_WARNING("No drawing buffer available"); + return nullptr; + } + +- MOZ_ASSERT(!mDelayedCommit, ++ MOZ_ASSERT(!mPendingCommit, + "Uncommitted buffer switch, screen artifacts ahead."); + +- WindowBackBuffer *tmp = mFrontBuffer; +- mFrontBuffer = mBackBuffer; +- mBackBuffer = tmp; ++ WindowBackBuffer *tmp = mWaylandBuffer; ++ mWaylandBuffer = mBackupBuffer; ++ mBackupBuffer = tmp; + +- if (mBackBuffer->IsMatchingSize(aWidth, aHeight)) { ++ if (mBackupBuffer->IsMatchingSize(aWidth, aHeight)) { + // Former front buffer has the same size as a requested one. + // Gecko may expect a content already drawn on screen so copy + // existing data to the new buffer. +- mFrontBuffer->SetImageDataFromBackBuffer(mBackBuffer); ++ mWaylandBuffer->SetImageDataFromBuffer(mBackupBuffer); + // When buffer switches we need to damage whole screen + // (https://bugzilla.redhat.com/show_bug.cgi?id=1418260) +- mFullScreenDamage = true; ++ mWaylandBufferFullScreenDamage = true; + } else { + // Former buffer has different size from the new request. Only resize + // the new buffer and leave gecko to render new whole content. +- mFrontBuffer->Resize(aWidth, aHeight); ++ mWaylandBuffer->Resize(aWidth, aHeight); + } + +- return mFrontBuffer; ++ return mWaylandBuffer; + } + + already_AddRefed +-WindowSurfaceWayland::LockFrontBuffer(int aWidth, int aHeight) ++WindowSurfaceWayland::LockWaylandBuffer(int aWidth, int aHeight) + { +- WindowBackBuffer* buffer = GetFrontBufferToDraw(aWidth, aHeight); ++ WindowBackBuffer* buffer = GetWaylandBufferToDraw(aWidth, aHeight); + if (buffer) { + return buffer->Lock(); + } + +- NS_WARNING("WindowSurfaceWayland::LockFrontBuffer(): No buffer available"); ++ NS_WARNING("WindowSurfaceWayland::LockWaylandBuffer(): No buffer available"); + return nullptr; + } + +@@ -687,8 +694,8 @@ WindowSurfaceWayland::LockImageSurface(c + A) Lock() is called to whole surface. In that case we don't need + to clip/buffer the drawing and we can return wl_buffer directly + for drawing. +- - mFrontBuffer is available - that's an ideal situation. +- - mFrontBuffer is locked by compositor - flip buffers and draw. ++ - mWaylandBuffer is available - that's an ideal situation. ++ - mWaylandBuffer is locked by compositor - flip buffers and draw. + - if we can't flip buffers - go B) + + B) Lock() is requested for part(s) of screen. We need to provide temporary +@@ -704,30 +711,30 @@ WindowSurfaceWayland::Lock(const LayoutD + gfx::IntSize lockSize(bounds.XMost(), bounds.YMost()); + + // Are we asked for entire nsWindow to draw? +- mDirectWlBufferDraw = (aRegion.GetNumRects() == 1 && +- bounds.x == 0 && bounds.y == 0 && +- lockSize.width == screenRect.width && +- lockSize.height == screenRect.height); +- +- if (mDirectWlBufferDraw) { +- RefPtr dt = LockFrontBuffer(screenRect.width, +- screenRect.height); ++ mDrawToWaylandBufferDirectly = (aRegion.GetNumRects() == 1 && ++ bounds.x == 0 && bounds.y == 0 && ++ lockSize.width == screenRect.width && ++ lockSize.height == screenRect.height); ++ ++ if (mDrawToWaylandBufferDirectly) { ++ RefPtr dt = LockWaylandBuffer(screenRect.width, ++ screenRect.height); + if (dt) { + return dt.forget(); + } + + // We don't have any front buffer available. Try indirect drawing + // to mImageSurface which is mirrored to front buffer at commit. +- mDirectWlBufferDraw = false; ++ mDrawToWaylandBufferDirectly = false; + } + + return LockImageSurface(lockSize); + } + + bool +-WindowSurfaceWayland::CommitImageSurface(const LayoutDeviceIntRegion& aRegion) ++WindowSurfaceWayland::CommitImageSurfaceToWaylandBuffer(const LayoutDeviceIntRegion& aRegion) + { +- MOZ_ASSERT(!mDirectWlBufferDraw); ++ MOZ_ASSERT(!mDrawToWaylandBufferDirectly); + + LayoutDeviceIntRect screenRect = mWindow->GetBounds(); + gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect(); +@@ -737,8 +744,8 @@ WindowSurfaceWayland::CommitImageSurface + return false; + } + +- RefPtr dt = LockFrontBuffer(screenRect.width, +- screenRect.height); ++ RefPtr dt = LockWaylandBuffer(screenRect.width, ++ screenRect.height); + RefPtr surf = + gfx::Factory::CreateSourceSurfaceForCairoSurface(mImageSurface->CairoSurface(), + mImageSurface->GetSize(), +@@ -766,92 +773,145 @@ WindowSurfaceWayland::CommitImageSurface + return true; + } + ++static void ++WaylandBufferDelayCommitHandler(WindowSurfaceWayland **aSurface) ++{ ++ if (*aSurface) { ++ (*aSurface)->DelayedCommitHandler(); ++ } else { ++ // Referenced WindowSurfaceWayland is already deleted. ++ // Do nothing but just release the mDelayedCommitHandle allocated at ++ // WindowSurfaceWayland::CommitWaylandBuffer(). ++ free(aSurface); ++ } ++} ++ + void +-WindowSurfaceWayland::Commit(const LayoutDeviceIntRegion& aInvalidRegion) ++WindowSurfaceWayland::CommitWaylandBuffer() + { +- MOZ_ASSERT(mIsMainThread == NS_IsMainThread()); ++ MOZ_ASSERT(mPendingCommit, "Committing empty surface!"); + + wl_surface* waylandSurface = mWindow->GetWaylandSurface(); + if (!waylandSurface) { +- // Target window is already destroyed - don't bother to render there. +- NS_WARNING("WindowSurfaceWayland::Commit(): parent wl_surface is already hidden/deleted."); ++ // 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!"); ++ ++ // Do nothing if there's already mDelayedCommitHandle pending. ++ if (!mDelayedCommitHandle) { ++ mDelayedCommitHandle = static_cast( ++ moz_xmalloc(sizeof(*mDelayedCommitHandle))); ++ *mDelayedCommitHandle = this; ++ ++ MessageLoop::current()->PostDelayedTask( ++ NewRunnableFunction("WaylandBackBufferCommit", ++ &WaylandBufferDelayCommitHandler, ++ mDelayedCommitHandle), ++ EVENT_LOOP_DELAY); ++ } + return; + } + wl_proxy_set_queue((struct wl_proxy *)waylandSurface, + mWaylandDisplay->GetEventQueue()); + +- if (!mDirectWlBufferDraw) { +- // We have new content at mImageSurface - copy data to mFrontBuffer first. +- CommitImageSurface(aInvalidRegion); ++ // We have an active frame callback request so handle it. ++ if (mFrameCallback) { ++ if (waylandSurface == mLastCommittedSurface) { ++ // We have an active frame callback pending from our recent surface. ++ // It means we should defer the commit to FrameCallbackHandler(). ++ return; ++ } ++ // If our stored wl_surface does not match the actual one it means the frame ++ // callback is no longer active and we should release it. ++ wl_callback_destroy(mFrameCallback); ++ mFrameCallback = nullptr; ++ mLastCommittedSurface = nullptr; + } + +- if (mFullScreenDamage) { ++ if (mWaylandBufferFullScreenDamage) { + LayoutDeviceIntRect rect = mWindow->GetBounds(); + wl_surface_damage(waylandSurface, 0, 0, rect.width, rect.height); +- mFullScreenDamage = false; ++ mWaylandBufferFullScreenDamage = false; + } else { +- for (auto iter = aInvalidRegion.RectIter(); !iter.Done(); iter.Next()) { ++ gint scaleFactor = mWindow->GdkScaleFactor(); ++ for (auto iter = mWaylandBufferDamage.RectIter(); !iter.Done(); iter.Next()) { + const mozilla::LayoutDeviceIntRect &r = iter.Get(); +- wl_surface_damage(waylandSurface, r.x, r.y, r.width, r.height); ++ // We need to remove the scale factor because the wl_surface_damage ++ // also multiplies by current scale factor. ++ wl_surface_damage(waylandSurface, r.x/scaleFactor, r.y/scaleFactor, ++ r.width/scaleFactor, r.height/scaleFactor); + } + } + +- // Frame callback is always connected to actual wl_surface. When the surface +- // is unmapped/deleted the frame callback is never called. Unfortunatelly +- // we don't know if the frame callback is not going to be called. +- // But our mozcontainer code deletes wl_surface when the GdkWindow is hidden +- // creates a new one when is visible. +- if (mFrameCallback && mFrameCallbackSurface == waylandSurface) { +- // Do nothing here - we have a valid wl_surface and the buffer will be +- // commited to compositor in next frame callback event. +- mDelayedCommit = true; +- return; +- } else { +- if (mFrameCallback) { +- // Delete frame callback connected to obsoleted wl_surface. +- wl_callback_destroy(mFrameCallback); +- } ++ // Clear all back buffer damage as we're committing ++ // all requested regions. ++ mWaylandBufferDamage.SetEmpty(); ++ ++ mFrameCallback = wl_surface_frame(waylandSurface); ++ wl_callback_add_listener(mFrameCallback, &frame_listener, this); + +- mFrameCallback = wl_surface_frame(waylandSurface); +- wl_callback_add_listener(mFrameCallback, &frame_listener, this); +- mFrameCallbackSurface = waylandSurface; +- +- // There's no pending frame callback so we can draw immediately +- // and create frame callback for possible subsequent drawing. +- mFrontBuffer->Attach(waylandSurface); +- mDelayedCommit = false; ++ if (mNeedScaleFactorUpdate || mLastCommittedSurface != waylandSurface) { ++ wl_surface_set_buffer_scale(waylandSurface, mWindow->GdkScaleFactor()); ++ mNeedScaleFactorUpdate = false; + } ++ ++ mWaylandBuffer->Attach(waylandSurface); ++ mLastCommittedSurface = waylandSurface; ++ ++ // There's no pending commit, all changes are sent to compositor. ++ mPendingCommit = false; ++} ++ ++void ++WindowSurfaceWayland::Commit(const LayoutDeviceIntRegion& aInvalidRegion) ++{ ++ MOZ_ASSERT(mIsMainThread == NS_IsMainThread()); ++ ++ // 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); ++ } ++ ++ // We're ready to commit. ++ mPendingCommit = true; ++ CommitWaylandBuffer(); + } + + void + WindowSurfaceWayland::FrameCallbackHandler() + { + MOZ_ASSERT(mIsMainThread == NS_IsMainThread()); ++ MOZ_ASSERT(mFrameCallback != nullptr, ++ "FrameCallbackHandler() called without valid frame callback!"); ++ MOZ_ASSERT(mLastCommittedSurface != nullptr, ++ "FrameCallbackHandler() called without valid wl_surface!"); + +- if (mFrameCallback) { +- wl_callback_destroy(mFrameCallback); +- mFrameCallback = nullptr; +- mFrameCallbackSurface = nullptr; ++ wl_callback_destroy(mFrameCallback); ++ mFrameCallback = nullptr; ++ ++ if (mPendingCommit) { ++ CommitWaylandBuffer(); + } ++} + +- if (mDelayedCommit) { +- wl_surface* waylandSurface = mWindow->GetWaylandSurface(); +- if (!waylandSurface) { +- // Target window is already destroyed - don't bother to render there. +- NS_WARNING("WindowSurfaceWayland::FrameCallbackHandler(): parent wl_surface is already hidden/deleted."); +- return; +- } +- wl_proxy_set_queue((struct wl_proxy *)waylandSurface, +- mWaylandDisplay->GetEventQueue()); ++void ++WindowSurfaceWayland::DelayedCommitHandler() ++{ ++ MOZ_ASSERT(mDelayedCommitHandle != nullptr, "Missing mDelayedCommitHandle!"); + +- // Send pending surface to compositor and register frame callback +- // for possible subsequent drawing. +- mFrameCallback = wl_surface_frame(waylandSurface); +- wl_callback_add_listener(mFrameCallback, &frame_listener, this); +- mFrameCallbackSurface = waylandSurface; ++ *mDelayedCommitHandle = nullptr; ++ free(mDelayedCommitHandle); ++ mDelayedCommitHandle = nullptr; + +- mFrontBuffer->Attach(waylandSurface); +- mDelayedCommit = false; ++ if (mPendingCommit) { ++ CommitWaylandBuffer(); + } + } + +diff -up firefox-62.0.3/widget/gtk/WindowSurfaceWayland.h.old firefox-62.0.3/widget/gtk/WindowSurfaceWayland.h +--- firefox-62.0.3/widget/gtk/WindowSurfaceWayland.h.old 2018-10-08 11:52:52.154376159 +0200 ++++ firefox-62.0.3/widget/gtk/WindowSurfaceWayland.h 2018-09-06 11:01:18.802964787 +0200 +@@ -74,7 +74,7 @@ public: + bool IsAttached() { return mAttached; } + + bool Resize(int aWidth, int aHeight); +- bool SetImageDataFromBackBuffer(class WindowBackBuffer* aSourceBuffer); ++ bool SetImageDataFromBuffer(class WindowBackBuffer* aSourceBuffer); + + bool IsMatchingSize(int aWidth, int aHeight) + { +@@ -111,28 +111,32 @@ public: + already_AddRefed Lock(const LayoutDeviceIntRegion& aRegion) override; + void Commit(const LayoutDeviceIntRegion& aInvalidRegion) final; + void FrameCallbackHandler(); ++ void DelayedCommitHandler(); + + private: +- WindowBackBuffer* GetFrontBufferToDraw(int aWidth, int aHeight); +- void UpdateScaleFactor(); ++ WindowBackBuffer* GetWaylandBufferToDraw(int aWidth, int aHeight); + +- already_AddRefed LockFrontBuffer(int aWidth, int aHeight); ++ already_AddRefed LockWaylandBuffer(int aWidth, int aHeight); + already_AddRefed LockImageSurface(const gfx::IntSize& aLockSize); +- bool CommitImageSurface(const LayoutDeviceIntRegion& aRegion); ++ bool CommitImageSurfaceToWaylandBuffer(const LayoutDeviceIntRegion& aRegion); ++ void CommitWaylandBuffer(); + + // TODO: Do we need to hold a reference to nsWindow object? + nsWindow* mWindow; + nsWaylandDisplay* mWaylandDisplay; +- WindowBackBuffer* mFrontBuffer; +- WindowBackBuffer* mBackBuffer; ++ WindowBackBuffer* mWaylandBuffer; ++ LayoutDeviceIntRegion mWaylandBufferDamage; ++ WindowBackBuffer* mBackupBuffer; + RefPtr mImageSurface; + wl_callback* mFrameCallback; +- wl_surface* mFrameCallbackSurface; ++ wl_surface* mLastCommittedSurface; + MessageLoop* mDisplayThreadMessageLoop; +- bool mDirectWlBufferDraw; +- bool mDelayedCommit; +- bool mFullScreenDamage; ++ WindowSurfaceWayland** mDelayedCommitHandle; ++ bool mDrawToWaylandBufferDirectly; ++ bool mPendingCommit; ++ bool mWaylandBufferFullScreenDamage; + bool mIsMainThread; ++ bool mNeedScaleFactorUpdate; + }; + + } // namespace widget -- cgit