From 868f498959a589b6577b126d5cf7c5e3d8ea8f8b Mon Sep 17 00:00:00 2001 From: Martin Stransky Date: Tue, 17 Sep 2019 13:22:34 +0200 Subject: [PATCH] Added fixes for mozbz#1581748 --- firefox.spec | 7 +- mozilla-1581748.patch | 574 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 580 insertions(+), 1 deletion(-) create mode 100644 mozilla-1581748.patch diff --git a/firefox.spec b/firefox.spec index 88f5fc6..3e96df4 100644 --- a/firefox.spec +++ b/firefox.spec @@ -94,7 +94,7 @@ ExcludeArch: ppc64le Summary: Mozilla Firefox Web browser Name: firefox Version: 69.0 -Release: 6%{?pre_tag}%{?dist} +Release: 7%{?pre_tag}%{?dist} URL: https://www.mozilla.org/firefox/ License: MPLv1.1 or GPLv2+ or LGPLv2+ Source0: https://archive.mozilla.org/pub/firefox/releases/%{version}%{?pre_version}/source/firefox-%{version}%{?pre_version}.source.tar.xz @@ -168,6 +168,7 @@ Patch584: mozilla-1579794-2.patch Patch585: mozilla-1579849.patch Patch586: mozilla-1579823.patch Patch587: mozilla-1580152.patch +Patch588: mozilla-1581748.patch # PGO/LTO patches Patch600: pgo.patch @@ -388,6 +389,7 @@ This package contains results of tests executed during build. %patch422 -p1 -b .1580174-webrtc-popup %patch586 -p1 -b .mozilla-1579823 %patch587 -p1 -b .mozilla-1580152 +%patch588 -p1 -b .mozilla-1581748 # PGO patches %patch600 -p1 -b .pgo @@ -964,6 +966,9 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : #--------------------------------------------------------------------- %changelog +* Tue Sep 17 2019 Martin Stransky - 69.0-7 +- Added fixes for mozbz#1581748 + * Mon Sep 16 2019 Martin Stransky - 69.0-6 - Added fixes for mozbz#1579823, mozbz#1580152 diff --git a/mozilla-1581748.patch b/mozilla-1581748.patch new file mode 100644 index 0000000..4fbffa8 --- /dev/null +++ b/mozilla-1581748.patch @@ -0,0 +1,574 @@ +diff -up firefox-69.0/widget/gtk/WindowSurfaceWayland.cpp.mozilla-1581748 firefox-69.0/widget/gtk/WindowSurfaceWayland.cpp +--- firefox-69.0/widget/gtk/WindowSurfaceWayland.cpp.mozilla-1581748 2019-09-17 13:19:47.190908284 +0200 ++++ firefox-69.0/widget/gtk/WindowSurfaceWayland.cpp 2019-09-17 13:19:47.196908262 +0200 +@@ -32,7 +32,7 @@ extern mozilla::LazyLogModule gWidgetWay + # define LOGWAYLAND(args) + #endif /* MOZ_LOGGING */ + +-// Maximal compositin timeout it miliseconds ++// Maximal compositing timeout it miliseconds + #define COMPOSITING_TIMEOUT 200 + + namespace mozilla { +@@ -513,13 +513,15 @@ WindowSurfaceWayland::WindowSurfaceWayla + mDelayedCommitHandle(nullptr), + mLastCommitTime(0), + mDrawToWaylandBufferDirectly(true), ++ mCanSwitchWaylandBuffer(true), + mBufferPendingCommit(false), + mBufferCommitAllowed(false), +- mWholeWindowBufferDamage(false), + mBufferNeedsClear(false), + mIsMainThread(NS_IsMainThread()), + mNeedScaleFactorUpdate(true) { + for (int i = 0; i < BACK_BUFFER_NUM; i++) mBackupBuffer[i] = nullptr; ++ mRenderingCacheMode = 0; ++ + } + + WindowSurfaceWayland::~WindowSurfaceWayland() { +@@ -591,8 +593,6 @@ WindowBackBuffer* WindowSurfaceWayland:: + + // There's no buffer created yet, create a new one. + if (!mWaylandBuffer) { +- MOZ_ASSERT(aCanSwitchBuffer && mWholeWindowBufferDamage, +- "Created new buffer for partial drawing!"); + LOGWAYLAND((" Created new buffer [%d x %d]\n", mBufferScreenRect.width, + mBufferScreenRect.height)); + +@@ -682,9 +682,8 @@ WindowBackBuffer* WindowSurfaceWayland:: + return mWaylandBuffer; + } + +-already_AddRefed WindowSurfaceWayland::LockWaylandBuffer( +- bool aCanSwitchBuffer) { +- WindowBackBuffer* buffer = GetWaylandBufferToDraw(aCanSwitchBuffer); ++already_AddRefed WindowSurfaceWayland::LockWaylandBuffer() { ++ WindowBackBuffer* buffer = GetWaylandBufferToDraw(mCanSwitchWaylandBuffer); + + LOGWAYLAND(("WindowSurfaceWayland::LockWaylandBuffer [%p] Got buffer %p\n", + (void*)this, (void*)buffer)); +@@ -698,7 +697,9 @@ already_AddRefed Window + return nullptr; + } + +- if (mBufferNeedsClear && mWholeWindowBufferDamage) { ++ mCanSwitchWaylandBuffer = false; ++ ++ if (mBufferNeedsClear) { + buffer->Clear(); + mBufferNeedsClear = false; + } +@@ -728,40 +729,30 @@ already_AddRefed Window + WindowBackBuffer::GetSurfaceFormat()); + } + +-static bool IsWindowFullScreenUpdate(LayoutDeviceIntRect& screenRect, +- const LayoutDeviceIntRegion& aRegion) { +- if (aRegion.GetNumRects() > 1) return false; +- +- IntRect rect = aRegion.RectIter().Get().ToUnknownRect(); +- return (rect.x == 0 && rect.y == 0 && screenRect.width == rect.width && +- screenRect.height == rect.height); ++static bool IsWindowFullScreenUpdate( ++ LayoutDeviceIntRect& aScreenRect, ++ const LayoutDeviceIntRegion& aUpdatedRegion) { ++ if (aUpdatedRegion.GetNumRects() > 1) return false; ++ ++ IntRect rect = aUpdatedRegion.RectIter().Get().ToUnknownRect(); ++ return (rect.x == 0 && rect.y == 0 && aScreenRect.width == rect.width && ++ aScreenRect.height == rect.height); + } + +-static bool IsPopupFullScreenUpdate(LayoutDeviceIntRect& screenRect, +- const LayoutDeviceIntRegion& aRegion) { ++static bool IsPopupFullScreenUpdate( ++ LayoutDeviceIntRect& aScreenRect, ++ const LayoutDeviceIntRegion& aUpdatedRegion) { + // We know that popups can be drawn from two parts; a panel and an arrow. + // Assume we redraw whole popups when we have two rects and bounding + // box is equal to window borders. +- if (aRegion.GetNumRects() > 2) return false; ++ if (aUpdatedRegion.GetNumRects() > 2) return false; + +- IntRect lockSize = aRegion.GetBounds().ToUnknownRect(); ++ gfx::IntRect lockSize = aUpdatedRegion.GetBounds().ToUnknownRect(); + return (lockSize.x == 0 && lockSize.y == 0 && +- screenRect.width == lockSize.width && +- screenRect.height == lockSize.height); ++ aScreenRect.width == lockSize.width && ++ aScreenRect.height == lockSize.height); + } + +-/* +- There are some situations which can happen here: +- +- 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. +- - mWaylandBuffer is available - that's an ideal situation. +- - mWaylandBuffer is locked by compositor - go B) +- +- B) Lock() is requested for part(s) of screen. We need to provide temporary +- surface to draw into and copy result (clipped) to target wl_surface. +- */ + already_AddRefed WindowSurfaceWayland::Lock( + const LayoutDeviceIntRegion& aRegion) { + MOZ_ASSERT(mIsMainThread == NS_IsMainThread()); +@@ -777,22 +768,31 @@ already_AddRefed Window + LayoutDeviceIntRect lockedScreenRect = mWindow->GetBounds(); + gfx::IntRect lockSize = aRegion.GetBounds().ToUnknownRect(); + +- // Are we asked for entire nsWindow to draw? + bool isTransparentPopup = + mWindow->IsWaylandPopup() && + (eTransparencyTransparent == mWindow->GetTransparencyMode()); + +- // We have request to lock whole buffer/window. +- mWholeWindowBufferDamage = +- isTransparentPopup ? IsPopupFullScreenUpdate(lockedScreenRect, aRegion) +- : IsWindowFullScreenUpdate(lockedScreenRect, aRegion); +- +- // Clear buffer when we (re)draw new transparent popup window, +- // otherwise leave it as-is, mBufferNeedsClear can be set from previous +- // (already pending) commits which are cached now. +- if (mWholeWindowBufferDamage) { ++ bool windowRedraw = isTransparentPopup ++ ? IsPopupFullScreenUpdate(lockedScreenRect, aRegion) ++ : IsWindowFullScreenUpdate(lockedScreenRect, aRegion); ++ if (windowRedraw) { ++ // Clear buffer when we (re)draw new transparent popup window, ++ // otherwise leave it as-is, mBufferNeedsClear can be set from previous ++ // (already pending) commits which are cached now. + mBufferNeedsClear = + mWindow->WaylandSurfaceNeedsClear() || isTransparentPopup; ++ ++ // Store info that we can switch WaylandBuffer when we flush ++ // mImageSurface / mDelayedImageCommits. Don't clear it - it's cleared ++ // at LockWaylandBuffer() when we actualy switch the buffer. ++ mCanSwitchWaylandBuffer = windowRedraw; ++ ++ // We do full buffer repaint so clear our cached drawings. ++ mDelayedImageCommits.Clear(); ++ mWaylandBufferDamage.SetEmpty(); ++ ++ // Also do scale factor update for whole window updates just to be sure. ++ mNeedScaleFactorUpdate = true; + } + + LOGWAYLAND( +@@ -808,7 +808,7 @@ already_AddRefed Window + LOGWAYLAND((" IsWindowFullScreenUpdate = %d\n", + IsWindowFullScreenUpdate(lockedScreenRect, aRegion))); + LOGWAYLAND((" mBufferNeedsClear = %d\n", mBufferNeedsClear)); +- LOGWAYLAND((" mWholeWindowBufferDamage = %d\n", mWholeWindowBufferDamage)); ++ LOGWAYLAND((" windowRedraw = %d\n", windowRedraw)); + + #if MOZ_LOGGING + if (!(mBufferScreenRect == lockedScreenRect)) { +@@ -822,8 +822,9 @@ already_AddRefed Window + // We can't commit them any more as they're for former window size, so + // scratch them. + mDelayedImageCommits.Clear(); ++ mWaylandBufferDamage.SetEmpty(); + +- if (!mWholeWindowBufferDamage) { ++ if (!windowRedraw) { + NS_WARNING("Partial screen update when window is resized!"); + // This should not happen. Screen size changed but we got only + // partal screen update instead of whole screen. Discard this painting +@@ -833,52 +834,56 @@ already_AddRefed Window + mBufferScreenRect = lockedScreenRect; + } + +- if (mWholeWindowBufferDamage) { +- // We can lock/commit entire buffer direcly. +- mDrawToWaylandBufferDirectly = true; +- +- // If there's any pending image commit scratch them as we're going +- // to redraw the whole sceen anyway. +- mDelayedImageCommits.Clear(); ++ mDrawToWaylandBufferDirectly = ++ (windowRedraw || mRenderingCacheMode != CACHE_ALL); + +- RefPtr dt = LockWaylandBuffer( +- /* aCanSwitchBuffer */ mWholeWindowBufferDamage); ++ if (mDrawToWaylandBufferDirectly) { ++ LOGWAYLAND((" Direct drawing\n")); ++ RefPtr dt = LockWaylandBuffer(); + if (dt) { ++ if (!windowRedraw) { ++ DrawDelayedImageCommits(dt, mWaylandBufferDamage); ++ } + return dt.forget(); + } + } + +- // We do indirect drawing due to: +- // +- // 1) We don't have any front buffer available. Try indirect drawing +- // to mImageSurface which is mirrored to front buffer at commit. +- // 2) Only part of the screen is locked. We can't lock entire screen for +- // such drawing as it produces visible artifacts. ++ // Any caching is disabled and we don't have any back buffer available. ++ if (mRenderingCacheMode == CACHE_NONE) { ++ return nullptr; ++ } ++ ++ // We do indirect drawing because there isn't any front buffer available. ++ // Do indirect drawing to mImageSurface which is commited to wayland ++ // wl_buffer by DrawDelayedImageCommits() later. + mDrawToWaylandBufferDirectly = false; + + LOGWAYLAND((" Indirect drawing.\n")); + return LockImageSurface(gfx::IntSize(lockSize.XMost(), lockSize.YMost())); + } + ++bool WindowImageSurface::OverlapsSurface( ++ class WindowImageSurface& aBottomSurface) { ++ return mUpdateRegion.Contains(aBottomSurface.mUpdateRegion); ++} ++ + void WindowImageSurface::Draw(gfx::SourceSurface* aSurface, + gfx::DrawTarget* aDest, + const LayoutDeviceIntRegion& aRegion) { +- uint32_t numRects = aRegion.GetNumRects(); +- if (numRects != 1) { +- AutoTArray rects; +- rects.SetCapacity(numRects); +- for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) { +- rects.AppendElement(iter.Get().ToUnknownRect()); +- } +- aDest->PushDeviceSpaceClipRects(rects.Elements(), rects.Length()); +- } +- ++#ifdef MOZ_LOGGING + gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect(); +- gfx::Rect rect(bounds); +- aDest->DrawSurface(aSurface, rect, rect); ++ LOGWAYLAND(("WindowImageSurface::Draw\n")); ++ LOGWAYLAND((" rects num %d\n", aRegion.GetNumRects())); ++ LOGWAYLAND((" bounds [ %d, %d] -> [%d x %d]\n", bounds.x, bounds.y, ++ bounds.width, bounds.height)); ++#endif + +- if (numRects != 1) { +- aDest->PopClip(); ++ for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) { ++ mozilla::LayoutDeviceIntRect r = iter.Get(); ++ gfx::Rect rect(r.ToUnknownRect()); ++ LOGWAYLAND((" draw rect [%f,%f] -> [%f x %f]\n", rect.x, rect.y, ++ rect.width, rect.height)); ++ aDest->DrawSurface(aSurface, rect, rect); + } + } + +@@ -896,6 +901,18 @@ WindowImageSurface::WindowImageSurface( + mImageSurface->Format()); + } + ++void WindowSurfaceWayland::DrawDelayedImageCommits( ++ gfx::DrawTarget* aDrawTarget, LayoutDeviceIntRegion& aWaylandBufferDamage) { ++ LOGWAYLAND( ++ ("WindowSurfaceWayland::DrawDelayedImageCommits [%p]\n", (void*)this)); ++ MOZ_ASSERT(mDelayedImageCommits.Length() > 0, "Nothing to draw?"); ++ ++ for (unsigned int i = 0; i < mDelayedImageCommits.Length(); i++) { ++ mDelayedImageCommits[i].Draw(aDrawTarget, aWaylandBufferDamage); ++ } ++ mDelayedImageCommits.Clear(); ++} ++ + void WindowSurfaceWayland::CacheImageSurface( + const LayoutDeviceIntRegion& aRegion) { + #ifdef MOZ_LOGGING +@@ -906,8 +923,26 @@ void WindowSurfaceWayland::CacheImageSur + bounds.width, bounds.height)); + #endif + +- mDelayedImageCommits.AppendElement( +- WindowImageSurface(mImageSurface, aRegion)); ++ WindowImageSurface surf = WindowImageSurface(mImageSurface, aRegion); ++ ++ if (mDelayedImageCommits.Length()) { ++ int lastSurf = mDelayedImageCommits.Length() - 1; ++ if (surf.OverlapsSurface(mDelayedImageCommits[lastSurf])) { ++#ifdef MOZ_LOGGING ++ { ++ gfx::IntRect size = mDelayedImageCommits[lastSurf] ++ .GetUpdateRegion() ++ ->GetBounds() ++ .ToUnknownRect(); ++ LOGWAYLAND((" removing [ %d, %d] -> [%d x %d]\n", size.x, size.y, ++ size.width, size.height)); ++ } ++#endif ++ mDelayedImageCommits.RemoveElementAt(lastSurf); ++ } ++ } ++ ++ mDelayedImageCommits.AppendElement(surf); + // mImageSurface is owned by mDelayedImageCommits + mImageSurface = nullptr; + +@@ -915,17 +950,6 @@ void WindowSurfaceWayland::CacheImageSur + (" There's %d cached images\n", int(mDelayedImageCommits.Length()))); + } + +-void WindowSurfaceWayland::DrawDelayedImageCommits( +- gfx::DrawTarget* aDrawTarget, LayoutDeviceIntRegion& aWaylandBufferDamage) { +- LOGWAYLAND( +- ("WindowSurfaceWayland::DrawDelayedImageCommits [%p]\n", (void*)this)); +- +- for (unsigned int i = 0; i < mDelayedImageCommits.Length(); i++) { +- mDelayedImageCommits[i].Draw(aDrawTarget, aWaylandBufferDamage); +- } +- mDelayedImageCommits.Clear(); +-} +- + bool WindowSurfaceWayland::CommitImageCacheToWaylandBuffer() { + if (!mDelayedImageCommits.Length()) { + return false; +@@ -933,8 +957,7 @@ bool WindowSurfaceWayland::CommitImageCa + + MOZ_ASSERT(!mDrawToWaylandBufferDirectly); + +- RefPtr dt = LockWaylandBuffer( +- /* aCanSwitchBuffer */ mWholeWindowBufferDamage); ++ RefPtr dt = LockWaylandBuffer(); + if (!dt) { + return false; + } +@@ -942,7 +965,6 @@ bool WindowSurfaceWayland::CommitImageCa + LOGWAYLAND((" Flushing %ld cached WindowImageSurfaces to Wayland buffer\n", + long(mDelayedImageCommits.Length()))); + +- // Draw any delayed image commits first + DrawDelayedImageCommits(dt, mWaylandBufferDamage); + UnlockWaylandBuffer(); + +@@ -967,7 +989,7 @@ void WindowSurfaceWayland::CommitWayland + LOGWAYLAND(("WindowSurfaceWayland::CommitWaylandBuffer [%p]\n", (void*)this)); + LOGWAYLAND( + (" mDrawToWaylandBufferDirectly = %d\n", mDrawToWaylandBufferDirectly)); +- LOGWAYLAND((" mWholeWindowBufferDamage = %d\n", mWholeWindowBufferDamage)); ++ LOGWAYLAND((" mCanSwitchWaylandBuffer = %d\n", mCanSwitchWaylandBuffer)); + LOGWAYLAND((" mDelayedCommitHandle = %p\n", mDelayedCommitHandle)); + LOGWAYLAND((" mFrameCallback = %p\n", mFrameCallback)); + LOGWAYLAND((" mLastCommittedSurface = %p\n", mLastCommittedSurface)); +@@ -1030,20 +1052,11 @@ void WindowSurfaceWayland::CommitWayland + mLastCommittedSurface = nullptr; + } + +- if (mWholeWindowBufferDamage) { +- LOGWAYLAND((" send whole screen damage\n")); +- wl_surface_damage(waylandSurface, 0, 0, mBufferScreenRect.width, +- mBufferScreenRect.height); +- mWholeWindowBufferDamage = false; +- mNeedScaleFactorUpdate = true; +- } else { +- for (auto iter = mWaylandBufferDamage.RectIter(); !iter.Done(); +- iter.Next()) { +- mozilla::LayoutDeviceIntRect r = iter.Get(); +- LOGWAYLAND((" wl_surface_damage_buffer [%d, %d] -> [%d, %d]\n", r.x, +- r.y, r.width, r.height)); +- wl_surface_damage_buffer(waylandSurface, r.x, r.y, r.width, r.height); +- } ++ for (auto iter = mWaylandBufferDamage.RectIter(); !iter.Done(); iter.Next()) { ++ mozilla::LayoutDeviceIntRect r = iter.Get(); ++ LOGWAYLAND((" wl_surface_damage_buffer [%d, %d] -> [%d, %d]\n", r.x, r.y, ++ r.width, r.height)); ++ wl_surface_damage_buffer(waylandSurface, r.x, r.y, r.width, r.height); + } + + // Clear all back buffer damage as we're committing +@@ -1062,9 +1075,9 @@ void WindowSurfaceWayland::CommitWayland + mLastCommittedSurface = waylandSurface; + mLastCommitTime = g_get_monotonic_time() / 1000; + +- // Ask wl_display to start events synchronization. We're going wait ++ // Ask wl_display to start events synchronization. We're going to wait + // until all events are processed before next WindowSurfaceWayland::Lock() +- // as we need freed wl_buffer there. ++ // as we hope for free wl_buffer there. + mWaylandDisplay->SyncBegin(); + + // There's no pending commit, all changes are sent to compositor. +@@ -1074,9 +1087,6 @@ void WindowSurfaceWayland::CommitWayland + void WindowSurfaceWayland::Commit(const LayoutDeviceIntRegion& aInvalidRegion) { + MOZ_ASSERT(mIsMainThread == NS_IsMainThread()); + +- // Flush all waiting events explicitly as we need +- // mWaylandDisplay->FlushEventQueue(); +- + #ifdef MOZ_LOGGING + { + gfx::IntRect lockSize = aInvalidRegion.GetBounds().ToUnknownRect(); +@@ -1087,17 +1097,12 @@ void WindowSurfaceWayland::Commit(const + mBufferScreenRect.width, mBufferScreenRect.height)); + LOGWAYLAND((" mDrawToWaylandBufferDirectly = %d\n", + mDrawToWaylandBufferDirectly)); +- LOGWAYLAND( +- (" mWholeWindowBufferDamage = %d\n", mWholeWindowBufferDamage)); + } + #endif + + if (mDrawToWaylandBufferDirectly) { + MOZ_ASSERT(mWaylandBuffer->IsLocked()); +- // If we're not at fullscreen damage add drawing area from aInvalidRegion +- if (!mWholeWindowBufferDamage) { +- mWaylandBufferDamage.OrWith(aInvalidRegion); +- } ++ mWaylandBufferDamage.OrWith(aInvalidRegion); + UnlockWaylandBuffer(); + mBufferPendingCommit = true; + } else { +diff -up firefox-69.0/widget/gtk/WindowSurfaceWayland.h.mozilla-1581748 firefox-69.0/widget/gtk/WindowSurfaceWayland.h +--- firefox-69.0/widget/gtk/WindowSurfaceWayland.h.mozilla-1581748 2019-09-17 13:19:47.191908280 +0200 ++++ firefox-69.0/widget/gtk/WindowSurfaceWayland.h 2019-09-17 13:19:47.197908258 +0200 +@@ -161,6 +161,10 @@ class WindowImageSurface { + WindowImageSurface(gfxImageSurface* aImageSurface, + const LayoutDeviceIntRegion& aUpdateRegion); + ++ bool OverlapsSurface(class WindowImageSurface& aBottomSurface); ++ ++ const LayoutDeviceIntRegion* GetUpdateRegion() { return &mUpdateRegion; }; ++ + private: + RefPtr mSurface; + RefPtr mImageSurface; +@@ -174,20 +178,59 @@ class WindowSurfaceWayland : public Wind + explicit WindowSurfaceWayland(nsWindow* aWindow); + ~WindowSurfaceWayland(); + ++ // Lock() / Commit() are called by gecko when Firefox ++ // wants to display something. Lock() returns a DrawTarget ++ // where gecko paints. When gecko is done it calls Commit() ++ // and we try to send the DrawTarget (backed by wl_buffer) ++ // to wayland compositor. ++ // ++ // If we fail (wayland compositor is busy, ++ // wl_surface is not created yet) we queue the painting ++ // and we send it to wayland compositor in FrameCallbackHandler()/ ++ // DelayedCommitHandler/CommitWaylandBuffer(). + already_AddRefed Lock( + const LayoutDeviceIntRegion& aRegion) override; + void Commit(const LayoutDeviceIntRegion& aInvalidRegion) final; ++ ++ // It's called from wayland compositor when there's the right ++ // time to send wl_buffer to display. It's no-op if there's no ++ // queued commits. + void FrameCallbackHandler(); ++ ++ // When a new window is created we may not have a valid wl_surface ++ // for drawing (Gtk haven't created it yet). All commits are queued ++ // and DelayedCommitHandler() is called by timer when wl_surface is ready ++ // for drawing. + void DelayedCommitHandler(); ++ ++ // Try to commit all queued drawings to Wayland compositor. This is usually ++ // called from other routines but can be used to explicitly flush ++ // all drawings as we do when wl_buffer is released ++ // (see WindowBackBufferShm::Detach() for instance). + void CommitWaylandBuffer(); + + nsWaylandDisplay* GetWaylandDisplay() { return mWaylandDisplay; }; + ++ // Image cache mode can be set by widget.wayland_cache_mode ++ typedef enum { ++ // Cache and clip all drawings, default. It's slowest ++ // but also without any rendered artifacts. ++ CACHE_ALL = 0, ++ // Cache drawing only when back buffer is missing. May produce ++ // some rendering artifacts and flickering when partial screen update ++ // is rendered. ++ CACHE_MISSING = 1, ++ // Don't cache anything, draw only when back buffer is available. ++ // Suitable for fullscreen content only like fullscreen video playback and ++ // may work well with dmabuf backend. ++ CACHE_NONE = 2 ++ } RenderingCacheMode; ++ + private: + WindowBackBuffer* CreateWaylandBuffer(int aWidth, int aHeight); + WindowBackBuffer* GetWaylandBufferToDraw(bool aCanSwitchBuffer); + +- already_AddRefed LockWaylandBuffer(bool aCanSwitchBuffer); ++ already_AddRefed LockWaylandBuffer(); + void UnlockWaylandBuffer(); + + already_AddRefed LockImageSurface( +@@ -206,23 +249,71 @@ class WindowSurfaceWayland : public Wind + // mBufferScreenRect is window size when our wayland buffer was allocated. + LayoutDeviceIntRect mBufferScreenRect; + nsWaylandDisplay* mWaylandDisplay; ++ ++ // Actual buffer (backed by wl_buffer) where all drawings go into. ++ // Drawn areas are stored at mWaylandBufferDamage and if there's ++ // any uncommited drawings which needs to be send to wayland compositor ++ // the mBufferPendingCommit is set. + WindowBackBuffer* mWaylandBuffer; +- LayoutDeviceIntRegion mWaylandBufferDamage; + WindowBackBuffer* mBackupBuffer[BACK_BUFFER_NUM]; ++ LayoutDeviceIntRegion mWaylandBufferDamage; ++ ++ // After every commit to wayland compositor a frame callback is requested. ++ // Any next commit to wayland compositor will happen when frame callback ++ // comes from wayland compositor back as it's the best time to do the commit. + wl_callback* mFrameCallback; + wl_surface* mLastCommittedSurface; ++ ++ // Registered reference to pending DelayedCommitHandler() call. + WindowSurfaceWayland** mDelayedCommitHandle; ++ ++ // Cached drawings. If we can't get WaylandBuffer (wl_buffer) at ++ // WindowSurfaceWayland::Lock() we direct gecko rendering to ++ // mImageSurface. ++ // If we can't get WaylandBuffer at WindowSurfaceWayland::Commit() ++ // time, mImageSurface is moved to mDelayedImageCommits which ++ // holds all cached drawings. ++ // mDelayedImageCommits can be drawn by FrameCallbackHandler(), ++ // DelayedCommitHandler() or when WaylandBuffer is detached. + RefPtr mImageSurface; + AutoTArray mDelayedImageCommits; ++ + int64_t mLastCommitTime; ++ ++ // Indicates that we don't have any cached drawings at mDelayedImageCommits ++ // and WindowSurfaceWayland::Lock() returned WaylandBuffer to gecko ++ // to draw into. + bool mDrawToWaylandBufferDirectly; ++ ++ // Set when our cached drawings (mDelayedImageCommits) contains ++ // full screen damage. That means we can safely switch WaylandBuffer ++ // at LockWaylandBuffer(). ++ bool mCanSwitchWaylandBuffer; ++ ++ // Set when actual WaylandBuffer contains drawings which are not send to ++ // wayland compositor yet. + bool mBufferPendingCommit; ++ ++ // We can't send WaylandBuffer (wl_buffer) to compositor when gecko ++ // is rendering into it (i.e. between WindowSurfaceWayland::Lock() / ++ // WindowSurfaceWayland::Commit()). ++ // Thus we use mBufferCommitAllowed to disable commit by callbacks ++ // (FrameCallbackHandler(), DelayedCommitHandler()) + bool mBufferCommitAllowed; +- bool mWholeWindowBufferDamage; ++ ++ // We need to clear WaylandBuffer when entire transparent window is repainted. ++ // This typically apply to popup windows. + bool mBufferNeedsClear; ++ + bool mIsMainThread; ++ ++ // When new WaylandBuffer (wl_buffer) is send to wayland compositor ++ // (buffer switch or resize) we also need to set its scale factor. + bool mNeedScaleFactorUpdate; + ++ // Image caching strategy, see RenderingCacheMode for details. ++ RenderingCacheMode mRenderingCacheMode; ++ + static bool UseDMABufBackend(); + static bool mUseDMABufInitialized; + static bool mUseDMABuf;