tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit a0d567ff3daa66e23a72d032b9b7e43dadf3a2dc
parent c3999a869557cb3a4c99357a3833ad39156a3bc4
Author: stransky <stransky@redhat.com>
Date:   Thu, 20 Nov 2025 13:18:13 +0000

Bug 1998657 [Wayland] Make WaylandSurface ready to draw right after its created r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D271772

Diffstat:
Mwidget/gtk/MozContainerWayland.cpp | 35+----------------------------------
Mwidget/gtk/MozContainerWayland.h | 7-------
Mwidget/gtk/WaylandSurface.cpp | 120++++---------------------------------------------------------------------------
Mwidget/gtk/WaylandSurface.h | 34+++++++++-------------------------
Mwidget/gtk/WindowSurfaceWaylandMultiBuffer.cpp | 25+------------------------
Mwidget/gtk/WindowSurfaceWaylandMultiBuffer.h | 4----
Mwidget/gtk/nsWindow.cpp | 64++++++++++++----------------------------------------------------
Mwidget/gtk/nsWindow.h | 4----
8 files changed, 28 insertions(+), 265 deletions(-)

diff --git a/widget/gtk/MozContainerWayland.cpp b/widget/gtk/MozContainerWayland.cpp @@ -99,11 +99,6 @@ static void moz_container_wayland_invalidate(MozContainer* container) { gdk_window_invalidate_rect(window, nullptr, true); } -void moz_container_wayland_add_or_fire_initial_draw_callback( - MozContainer* container, const std::function<void(void)>& initial_draw_cb) { - MOZ_WL_SURFACE(container)->AddOrFireReadyToDrawCallback(initial_draw_cb); -} - void moz_container_wayland_unmap(GtkWidget* widget) { g_return_if_fail(IS_MOZ_CONTAINER(widget)); @@ -143,23 +138,9 @@ gboolean moz_container_wayland_map_event(GtkWidget* widget, // below. MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread()); - // Set waiting_to_show flag. It means the mozcontainer is cofigured/mapped - // and it's supposed to be visible. *But* it's really visible when we get - // moz_container_wayland_add_or_fire_initial_draw_callback() which means - // wayland compositor makes it live. - MOZ_WL_CONTAINER(widget)->waiting_to_show = true; - MozContainer* container = MOZ_CONTAINER(widget); - MOZ_WL_SURFACE(container)->AddOrFireReadyToDrawCallback( - [container]() -> void { - LOGCONTAINER( - "[%p] moz_container_wayland_add_or_fire_initial_draw_callback set " - "visible", - moz_container_get_nsWindow(container)); - moz_container_wayland_clear_waiting_to_show_flag(container); - }); - // Don't create wl_subsurface in map_event when it's already created or // if we create it for the first time. + MozContainer* container = MOZ_CONTAINER(widget); if (MOZ_WL_SURFACE(container)->IsMapped() || MOZ_WL_CONTAINER(container)->before_first_size_alloc) { return false; @@ -300,21 +281,7 @@ struct wl_egl_window* moz_container_wayland_get_egl_window( return MOZ_WL_SURFACE(container)->GetEGLWindow(size); } -gboolean moz_container_wayland_can_draw(MozContainer* container) { - return MOZ_WL_SURFACE(container)->IsReadyToDraw(); -} - double moz_container_wayland_get_scale(MozContainer* container) { nsWindow* window = moz_container_get_nsWindow(container); return window ? window->FractionalScaleFactor() : 1.0; } - -bool moz_container_wayland_is_waiting_to_show(MozContainer* container) { - MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread()); - return MOZ_WL_CONTAINER(container)->waiting_to_show; -} - -void moz_container_wayland_clear_waiting_to_show_flag(MozContainer* container) { - MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread()); - MOZ_WL_CONTAINER(container)->waiting_to_show = false; -} diff --git a/widget/gtk/MozContainerWayland.h b/widget/gtk/MozContainerWayland.h @@ -43,7 +43,6 @@ struct MozContainerWayland { RefPtr<mozilla::widget::WaylandSurface> mSurface; gboolean before_first_size_alloc = false; - gboolean waiting_to_show = false; }; void moz_container_wayland_map(GtkWidget*); @@ -54,13 +53,7 @@ void moz_container_wayland_unmap(GtkWidget*); struct wl_egl_window* moz_container_wayland_get_egl_window( MozContainer* container); -void moz_container_wayland_add_or_fire_initial_draw_callback( - MozContainer* container, const std::function<void(void)>& initial_draw_cb); - wl_surface* moz_gtk_widget_get_wl_surface(GtkWidget* aWidget); -gboolean moz_container_wayland_can_draw(MozContainer* container); double moz_container_wayland_get_scale(MozContainer* container); -bool moz_container_wayland_is_waiting_to_show(MozContainer* container); -void moz_container_wayland_clear_waiting_to_show_flag(MozContainer* container); #endif /* __MOZ_CONTAINER_WAYLAND_H__ */ diff --git a/widget/gtk/WaylandSurface.cpp b/widget/gtk/WaylandSurface.cpp @@ -117,104 +117,6 @@ WaylandSurface::~WaylandSurface() { "We can't release WaylandSurface with numap callback!"); } -void WaylandSurface::ReadyToDrawFrameCallbackHandler( - struct wl_callback* callback) { - LOGWAYLAND( - "WaylandSurface::ReadyToDrawFrameCallbackHandler() " - "mReadyToDrawFrameCallback %p mIsReadyToDraw %d initial_draw callback " - "%zd\n", - (void*)mReadyToDrawFrameCallback, (bool)mIsReadyToDraw, - mReadyToDrawCallbacks.size()); - - // We're supposed to run on main thread only. - AssertIsOnMainThread(); - - // mReadyToDrawFrameCallback/callback can be nullptr when redering directly - // to GtkWidget and ReadyToDrawFrameCallbackHandler is called by us from main - // thread by WaylandSurface::Map(). - MOZ_RELEASE_ASSERT(mReadyToDrawFrameCallback == callback); - - std::vector<std::function<void(void)>> cbs; - { - WaylandSurfaceLock lock(this); - MozClearPointer(mReadyToDrawFrameCallback, wl_callback_destroy); - // It's possible that we're already unmapped so quit in such case. - if (!mIsMapped) { - LOGWAYLAND(" WaylandSurface is unmapped, quit."); - if (!mReadyToDrawCallbacks.empty()) { - NS_WARNING("Unmapping WaylandSurface with active draw callback!"); - mReadyToDrawCallbacks.clear(); - } - return; - } - if (mIsReadyToDraw) { - return; - } - mIsReadyToDraw = true; - cbs = std::move(mReadyToDrawCallbacks); - - RequestFrameCallbackLocked(lock); - } - - // We can't call the callbacks under lock -#ifdef MOZ_LOGGING - int callbackNum = 0; -#endif - for (auto const& cb : cbs) { - LOGWAYLAND(" initial callback fire [%d]", callbackNum++); - cb(); - } -} - -static void ReadyToDrawFrameCallbackHandler(void* aWaylandSurface, - struct wl_callback* callback, - uint32_t time) { - auto* waylandSurface = static_cast<WaylandSurface*>(aWaylandSurface); - waylandSurface->ReadyToDrawFrameCallbackHandler(callback); -} - -static const struct wl_callback_listener - sWaylandSurfaceReadyToDrawFrameListener = { - ::ReadyToDrawFrameCallbackHandler}; - -void WaylandSurface::AddReadyToDrawCallbackLocked( - const WaylandSurfaceLock& aProofOfLock, - const std::function<void(void)>& aDrawCB) { - LOGVERBOSE("WaylandSurface::AddReadyToDrawCallbackLocked()"); - MOZ_DIAGNOSTIC_ASSERT(&aProofOfLock == mSurfaceLock); - mReadyToDrawCallbacks.push_back(aDrawCB); -} - -void WaylandSurface::AddOrFireReadyToDrawCallback( - const std::function<void(void)>& aDrawCB) { - { - WaylandSurfaceLock lock(this); - if (!mIsReadyToDraw) { - LOGVERBOSE( - "WaylandSurface::AddOrFireReadyToDrawCallback() callback stored"); - mReadyToDrawCallbacks.push_back(aDrawCB); - return; - } - } - - LOGWAYLAND("WaylandSurface::AddOrFireReadyToDrawCallback() callback fire"); - - // We're ready to draw and we have a surface to draw into. - aDrawCB(); -} - -void WaylandSurface::ClearReadyToDrawCallbacksLocked( - const WaylandSurfaceLock& aProofOfLock) { - MOZ_DIAGNOSTIC_ASSERT(&aProofOfLock == mSurfaceLock); - MozClearPointer(mReadyToDrawFrameCallback, wl_callback_destroy); - mReadyToDrawCallbacks.clear(); -} - -void WaylandSurface::ClearReadyToDrawCallbacks() { - WaylandSurfaceLock lock(this); - ClearReadyToDrawCallbacksLocked(lock); -} - bool WaylandSurface::HasEmulatedFrameCallbackLocked( const WaylandSurfaceLock& aProofOfLock) const { return mFrameCallbackHandler.IsSet() && mFrameCallbackHandler.mEmulated; @@ -233,7 +135,7 @@ void WaylandSurface::FrameCallbackHandler(struct wl_callback* aCallback, WaylandSurfaceLock lock(this); // Don't run emulated callbacks on hidden surfaces - if ((emulatedCallback || aRoutedFromChildSurface) && !mIsReadyToDraw) { + if ((emulatedCallback || aRoutedFromChildSurface) && !mIsVisible) { return; } @@ -259,6 +161,7 @@ void WaylandSurface::FrameCallbackHandler(struct wl_callback* aCallback, // We're getting regular frame callback from this surface so we must // have buffer attached. if (!emulatedCallback && !aRoutedFromChildSurface) { + mIsVisible = true; mBufferAttached = true; } @@ -478,8 +381,7 @@ bool WaylandSurface::MapLocked(const WaylandSurfaceLock& aProofOfLock, wl_surface* aParentWLSurface, WaylandSurfaceLock* aParentWaylandSurfaceLock, gfx::IntPoint aSubsurfacePosition, - bool aSubsurfaceDesync, - bool aUseReadyToDrawCallback) { + bool aSubsurfaceDesync) { LOGWAYLAND("WaylandSurface::MapLocked()"); MOZ_DIAGNOSTIC_ASSERT(&aProofOfLock == mSurfaceLock); MOZ_DIAGNOSTIC_ASSERT(!mIsMapped, "Already mapped?"); @@ -519,14 +421,6 @@ bool WaylandSurface::MapLocked(const WaylandSurfaceLock& aProofOfLock, LOGWAYLAND(" subsurface position [%d,%d]", (int)mSubsurfacePosition.x, (int)mSubsurfacePosition.y); - if (aUseReadyToDrawCallback) { - mReadyToDrawFrameCallback = wl_surface_frame(mParentSurface); - wl_callback_add_listener(mReadyToDrawFrameCallback, - &sWaylandSurfaceReadyToDrawFrameListener, this); - LOGWAYLAND(" created ready to draw frame callback ID %d\n", - wl_proxy_get_id((struct wl_proxy*)mReadyToDrawFrameCallback)); - } - LOGWAYLAND(" register frame callback"); RequestFrameCallbackLocked(aProofOfLock); @@ -556,8 +450,7 @@ bool WaylandSurface::MapLocked(const WaylandSurfaceLock& aProofOfLock, gfx::IntPoint aSubsurfacePosition) { return MapLocked(aProofOfLock, nullptr, aParentWaylandSurfaceLock, aSubsurfacePosition, - /* aSubsurfaceDesync */ false, - /* aUseReadyToDrawCallback */ false); + /* aSubsurfaceDesync */ false); } void WaylandSurface::SetUnmapCallbackLocked( @@ -609,11 +502,11 @@ void WaylandSurface::UnmapLocked(WaylandSurfaceLock& aSurfaceLock) { return; } mIsMapped = false; + mIsVisible = false; LOGWAYLAND("WaylandSurface::UnmapLocked()"); RemoveAttachedBufferLocked(aSurfaceLock); - ClearReadyToDrawCallbacksLocked(aSurfaceLock); ClearFrameCallbackLocked(aSurfaceLock); ClearScaleLocked(aSurfaceLock); @@ -633,9 +526,6 @@ void WaylandSurface::UnmapLocked(WaylandSurfaceLock& aSurfaceLock) { MozClearPointer(mPendingOpaqueRegion, wl_region_destroy); MozClearPointer(mOpaqueRegionFrameCallback, wl_callback_destroy); - mIsReadyToDraw = false; - mBufferAttached = false; - // Remove references to WaylandBuffers attached to mSurface, // we don't want to get any buffer release callback when we're unmapped. ReleaseAllWaylandTransactionsLocked(aSurfaceLock); diff --git a/widget/gtk/WaylandSurface.h b/widget/gtk/WaylandSurface.h @@ -43,10 +43,6 @@ class WaylandSurface final { void SetLoggingWidget(void* aWidget) { mLoggingWidget = aWidget; } #endif - void ReadyToDrawFrameCallbackHandler(struct wl_callback* aCallback); - void AddOrFireReadyToDrawCallback(const std::function<void(void)>& aDrawCB); - void ClearReadyToDrawCallbacks(); - void FrameCallbackHandler(struct wl_callback* aCallback, uint32_t aTime, bool aRoutedFromChildSurface); @@ -78,11 +74,12 @@ class WaylandSurface final { bool SetEGLWindowSize(LayoutDeviceIntSize aSize); bool HasEGLWindow() const { return !!mEGLWindow; } - // Read to draw means we got frame callback from parent surface - // where we attached to. - bool IsReadyToDraw() const { return mIsReadyToDraw; } // Mapped means we have all internals created. bool IsMapped() const { return mIsMapped; } + + // We've got first frame callback so we're really visible now. + bool IsVisible() const { return mIsVisible; } + // Indicate that Wayland surface uses Gdk resources which // need to be released on main thread by GdkCleanUpLocked(). // It may be called after Unmap() to make sure @@ -122,10 +119,6 @@ class WaylandSurface final { bool CreateViewportLocked(const WaylandSurfaceLock& aProofOfLock, bool aFollowsSizeChanges); - void AddReadyToDrawCallbackLocked( - const WaylandSurfaceLock& aProofOfLock, - const std::function<void(void)>& aInitialDrawCB); - // Attach WaylandBuffer which shows WaylandBuffer content // on screen. bool AttachLocked(const WaylandSurfaceLock& aSurfaceLock, @@ -281,8 +274,7 @@ class WaylandSurface final { bool MapLocked(const WaylandSurfaceLock& aProofOfLock, wl_surface* aParentWLSurface, WaylandSurfaceLock* aParentWaylandSurfaceLock, - gfx::IntPoint aSubsurfacePosition, bool aSubsurfaceDesync, - bool aUseReadyToDrawCallback = true); + gfx::IntPoint aSubsurfacePosition, bool aSubsurfaceDesync); void SetSizeLocked(const WaylandSurfaceLock& aProofOfLock, gfx::IntSize aSizeScaled, gfx::IntSize aUnscaledSize); @@ -304,21 +296,18 @@ class WaylandSurface final { bool HasEmulatedFrameCallbackLocked( const WaylandSurfaceLock& aProofOfLock) const; - void ClearReadyToDrawCallbacksLocked(const WaylandSurfaceLock& aProofOfLock); - void ClearScaleLocked(const WaylandSurfaceLock& aProofOfLock); // Weak ref to owning widget (nsWindow or NativeLayerWayland), // used for diagnostics/logging only. void* mLoggingWidget = nullptr; - // WaylandSurface mapped - we have valid wl_surface where we can paint to. + // mIsMapped means we're supposed to be visible + // (or not if Wayland compositor decides so). mozilla::Atomic<bool, mozilla::Relaxed> mIsMapped{false}; - // Wayland shows only subsurfaces of visible parent surfaces. - // mIsReadyToDraw means our parent wl_surface has content so - // this WaylandSurface can be visible on screen and get get frame callback. - mozilla::Atomic<bool, mozilla::Relaxed> mIsReadyToDraw{false}; + // mIsVisible means we're really visible as we've got frame callback. + mozilla::Atomic<bool, mozilla::Relaxed> mIsVisible{false}; // We used Gdk functions which needs clean up in main thread. mozilla::Atomic<bool, mozilla::Relaxed> mIsPendingGdkCleanup{false}; @@ -385,11 +374,6 @@ class WaylandSurface final { bool mBufferTransformFlippedX = false; bool mBufferTransformFlippedY = false; - // Frame callback registered to parent surface. When we get it we know - // parent surface is ready and we can paint. - wl_callback* mReadyToDrawFrameCallback = nullptr; - std::vector<std::function<void(void)>> mReadyToDrawCallbacks; - // Frame callbacks of this surface wl_callback* mFrameCallback = nullptr; diff --git a/widget/gtk/WindowSurfaceWaylandMultiBuffer.cpp b/widget/gtk/WindowSurfaceWaylandMultiBuffer.cpp @@ -156,9 +156,7 @@ WindowSurfaceWaylandMB::WindowSurfaceWaylandMB( RefPtr<nsWindow> aWindow, GtkCompositorWidget* aCompositorWidget) : mSurfaceLock("WindowSurfaceWayland lock"), mWindow(std::move(aWindow)), - mCompositorWidget(aCompositorWidget), - mFrameInProcess(false), - mCallbackRequested(false) {} + mCompositorWidget(aCompositorWidget) {} bool WindowSurfaceWaylandMB::MaybeUpdateWindowSize() { // We want to get window size from compositor widget as it matches window @@ -189,7 +187,6 @@ already_AddRefed<DrawTarget> WindowSurfaceWaylandMB::Lock( if (mWindow->GetWindowType() == WindowType::Invisible) { return nullptr; } - mFrameInProcess = true; CollectPendingSurfaces(lock); @@ -281,30 +278,10 @@ void WindowSurfaceWaylandMB::Commit( // invisible window return; } - mFrameInProcess = false; MozContainer* container = mWindow->GetMozContainer(); WaylandSurface* waylandSurface = MOZ_WL_SURFACE(container); WaylandSurfaceLock lock(waylandSurface); - if (!waylandSurface->IsMapped()) { - LOGWAYLAND( - "WindowSurfaceWaylandMB::Commit [%p] frame queued: can't lock " - "wl_surface\n", - (void*)mWindow.get()); - if (!mCallbackRequested) { - RefPtr<WindowSurfaceWaylandMB> self(this); - waylandSurface->AddReadyToDrawCallbackLocked( - lock, [self, aInvalidRegion]() -> void { - MutexAutoLock lock(self->mSurfaceLock); - if (!self->mFrameInProcess) { - self->Commit(lock, aInvalidRegion); - } - self->mCallbackRequested = false; - }); - mCallbackRequested = true; - } - return; - } waylandSurface->InvalidateRegionLocked(lock, aInvalidRegion.ToUnknownRegion()); diff --git a/widget/gtk/WindowSurfaceWaylandMultiBuffer.h b/widget/gtk/WindowSurfaceWaylandMultiBuffer.h @@ -73,10 +73,6 @@ class WindowSurfaceWaylandMB : public WindowSurface { nsTArray<RefPtr<WaylandBufferSHM>> mInUseBuffers; nsTArray<RefPtr<WaylandBufferSHM>> mPendingBuffers; nsTArray<RefPtr<WaylandBufferSHM>> mAvailableBuffers; - - // delayed commits - bool mFrameInProcess; - bool mCallbackRequested; }; } // namespace mozilla::widget diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp @@ -1371,15 +1371,6 @@ void nsWindow::HideWaylandPopupWindow(bool aTemporaryHide, if (mPopupClosed) { LOG(" Clearing mMoveToRectPopupSize\n"); mMoveToRectPopupSize = {}; -#ifdef MOZ_WAYLAND - if (moz_container_wayland_is_waiting_to_show(mContainer)) { - // We need to clear rendering queue, see Bug 1782948. - LOG(" popup failed to show by Wayland compositor, clear rendering " - "queue."); - moz_container_wayland_clear_waiting_to_show_flag(mContainer); - ClearRenderingQueue(); - } -#endif } } @@ -1440,8 +1431,7 @@ void nsWindow::WaylandPopupCloseOrphanedPopups() { nsWindow* popup = mWaylandPopupNext; bool dangling = false; while (popup) { - if (!dangling && - moz_container_wayland_is_waiting_to_show(popup->GetMozContainer())) { + if (!dangling && !MOZ_WL_SURFACE(popup->GetMozContainer())->IsVisible()) { LOG(" popup [%p] is waiting to show, close all child popups", popup); dangling = true; } else if (dangling) { @@ -4117,13 +4107,6 @@ gboolean nsWindow::OnExposeEvent(cairo_t* cr) { LOG("quit, !mGdkWindow || !mHasMappedToplevel"); return FALSE; } -#ifdef MOZ_WAYLAND - if (!mIsDragPopup && GdkIsWaylandDisplay() && - !moz_container_wayland_can_draw(mContainer)) { - LOG("quit, !moz_container_wayland_can_draw()"); - return FALSE; - } -#endif if (!GetPaintListener()) { LOG("quit, !GetPaintListener()"); @@ -6230,33 +6213,19 @@ void nsWindow::ConfigureCompositor() { MOZ_DIAGNOSTIC_ASSERT(mIsMapped); LOG("nsWindow::ConfigureCompositor()"); - auto startCompositing = [self = RefPtr{this}, this]() -> void { - LOG(" moz_container_wayland_add_or_fire_initial_draw_callback " - "ConfigureCompositor"); - - // too late - if (mIsDestroyed || !mIsMapped) { - LOG(" quit, mIsDestroyed = %d mIsMapped = %d", !!mIsDestroyed, - !!mIsMapped); - return; - } - // Compositor will be resumed at nsWindow::SetCompositorWidgetDelegate(). - if (!mCompositorWidgetDelegate) { - LOG(" quit, missing mCompositorWidgetDelegate"); - return; - } - ResumeCompositorImpl(); - }; - - if (GdkIsWaylandDisplay()) { -#ifdef MOZ_WAYLAND - moz_container_wayland_add_or_fire_initial_draw_callback(mContainer, - startCompositing); -#endif - } else { - startCompositing(); + if (mIsDestroyed || !mIsMapped) { + LOG(" quit, mIsDestroyed = %d mIsMapped = %d", !!mIsDestroyed, + !!mIsMapped); + return; } + // Compositor will be resumed at nsWindow::SetCompositorWidgetDelegate(). + if (!mCompositorWidgetDelegate) { + LOG(" quit, missing mCompositorWidgetDelegate"); + return; + } + + ResumeCompositorImpl(); } nsresult nsWindow::Create(nsIWidget* aParent, const LayoutDeviceIntRect& aRect, @@ -9981,15 +9950,6 @@ nsWindow* nsWindow::GetWindow(GdkWindow* window) { return get_window_for_gdk_window(window); } -void nsWindow::ClearRenderingQueue() { - LOG("nsWindow::ClearRenderingQueue()"); - - if (mWidgetListener) { - mWidgetListener->RequestWindowClose(this); - } - DestroyLayerManager(); -} - // nsWindow::OnMap() / nsWindow::OnUnmap() is called from map/unmap mContainer // handlers directly as we paint to mContainer. void nsWindow::OnMap() { diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h @@ -498,10 +498,6 @@ class nsWindow final : public nsIWidget { void ResumeCompositorImpl(); - // Force hide this window, remove compositor etc. to avoid - // rendering queue blocking (see Bug 1782948). - void ClearRenderingQueue(); - bool ApplyEnterLeaveMutterWorkaround(); void NotifyOcclusionState(mozilla::widget::OcclusionState aState) override;