@@ -117,6 +117,104 @@ WaylandSurface::~WaylandSurface() {
117117 "We can't release WaylandSurface with numap callback!" );
118118}
119119
120+ void WaylandSurface ::ReadyToDrawFrameCallbackHandler (
121+ struct wl_callback * callback ) {
122+ LOGWAYLAND (
123+ "WaylandSurface::ReadyToDrawFrameCallbackHandler() "
124+ "mReadyToDrawFrameCallback %p mIsReadyToDraw %d initial_draw callback "
125+ "%zd\n" ,
126+ (void * )mReadyToDrawFrameCallback , (bool )mIsReadyToDraw ,
127+ mReadyToDrawCallbacks .size ());
128+
129+ // We're supposed to run on main thread only.
130+ AssertIsOnMainThread ();
131+
132+ // mReadyToDrawFrameCallback/callback can be nullptr when redering directly
133+ // to GtkWidget and ReadyToDrawFrameCallbackHandler is called by us from main
134+ // thread by WaylandSurface::Map().
135+ MOZ_RELEASE_ASSERT (mReadyToDrawFrameCallback == callback );
136+
137+ std ::vector < std ::function < void (void )>> cbs ;
138+ {
139+ WaylandSurfaceLock lock (this );
140+ MozClearPointer (mReadyToDrawFrameCallback , wl_callback_destroy );
141+ // It's possible that we're already unmapped so quit in such case.
142+ if (!mIsMapped ) {
143+ LOGWAYLAND (" WaylandSurface is unmapped, quit." );
144+ if (!mReadyToDrawCallbacks .empty ()) {
145+ NS_WARNING ("Unmapping WaylandSurface with active draw callback!" );
146+ mReadyToDrawCallbacks .clear ();
147+ }
148+ return ;
149+ }
150+ if (mIsReadyToDraw ) {
151+ return ;
152+ }
153+ mIsReadyToDraw = true;
154+ cbs = std ::move (mReadyToDrawCallbacks );
155+
156+ RequestFrameCallbackLocked (lock );
157+ }
158+
159+ // We can't call the callbacks under lock
160+ #ifdef MOZ_LOGGING
161+ int callbackNum = 0 ;
162+ #endif
163+ for (auto const & cb : cbs ) {
164+ LOGWAYLAND (" initial callback fire [%d]" , callbackNum ++ );
165+ cb ();
166+ }
167+ }
168+
169+ static void ReadyToDrawFrameCallbackHandler (void * aWaylandSurface ,
170+ struct wl_callback * callback ,
171+ uint32_t time ) {
172+ auto* waylandSurface = static_cast < WaylandSurface * > (aWaylandSurface );
173+ waylandSurface -> ReadyToDrawFrameCallbackHandler (callback );
174+ }
175+
176+ static const struct wl_callback_listener
177+ sWaylandSurfaceReadyToDrawFrameListener = {
178+ ::ReadyToDrawFrameCallbackHandler };
179+
180+ void WaylandSurface ::AddReadyToDrawCallbackLocked (
181+ const WaylandSurfaceLock & aProofOfLock ,
182+ const std ::function < void (void )> & aDrawCB ) {
183+ LOGVERBOSE ("WaylandSurface::AddReadyToDrawCallbackLocked()" );
184+ MOZ_DIAGNOSTIC_ASSERT (& aProofOfLock == mSurfaceLock );
185+ mReadyToDrawCallbacks .push_back (aDrawCB );
186+ }
187+
188+ void WaylandSurface ::AddOrFireReadyToDrawCallback (
189+ const std ::function < void (void )> & aDrawCB ) {
190+ {
191+ WaylandSurfaceLock lock (this );
192+ if (!mIsReadyToDraw ) {
193+ LOGVERBOSE (
194+ "WaylandSurface::AddOrFireReadyToDrawCallback() callback stored" );
195+ mReadyToDrawCallbacks .push_back (aDrawCB );
196+ return ;
197+ }
198+ }
199+
200+ LOGWAYLAND ("WaylandSurface::AddOrFireReadyToDrawCallback() callback fire" );
201+
202+ // We're ready to draw and we have a surface to draw into.
203+ aDrawCB ();
204+ }
205+
206+ void WaylandSurface ::ClearReadyToDrawCallbacksLocked (
207+ const WaylandSurfaceLock & aProofOfLock ) {
208+ MOZ_DIAGNOSTIC_ASSERT (& aProofOfLock == mSurfaceLock );
209+ MozClearPointer (mReadyToDrawFrameCallback , wl_callback_destroy );
210+ mReadyToDrawCallbacks .clear ();
211+ }
212+
213+ void WaylandSurface ::ClearReadyToDrawCallbacks () {
214+ WaylandSurfaceLock lock (this );
215+ ClearReadyToDrawCallbacksLocked (lock );
216+ }
217+
120218bool WaylandSurface ::HasEmulatedFrameCallbackLocked (
121219 const WaylandSurfaceLock & aProofOfLock ) const {
122220 return mFrameCallbackHandler .IsSet () && mFrameCallbackHandler .mEmulated ;
@@ -135,7 +233,7 @@ void WaylandSurface::FrameCallbackHandler(struct wl_callback* aCallback,
135233 WaylandSurfaceLock lock (this );
136234
137235 // Don't run emulated callbacks on hidden surfaces
138- if ((emulatedCallback || aRoutedFromChildSurface ) && !mIsVisible ) {
236+ if ((emulatedCallback || aRoutedFromChildSurface ) && !mIsReadyToDraw ) {
139237 return ;
140238 }
141239
@@ -161,7 +259,6 @@ void WaylandSurface::FrameCallbackHandler(struct wl_callback* aCallback,
161259 // We're getting regular frame callback from this surface so we must
162260 // have buffer attached.
163261 if (!emulatedCallback && !aRoutedFromChildSurface ) {
164- mIsVisible = true;
165262 mBufferAttached = true;
166263 }
167264
@@ -381,7 +478,8 @@ bool WaylandSurface::MapLocked(const WaylandSurfaceLock& aProofOfLock,
381478 wl_surface * aParentWLSurface ,
382479 WaylandSurfaceLock * aParentWaylandSurfaceLock ,
383480 gfx ::IntPoint aSubsurfacePosition ,
384- bool aSubsurfaceDesync ) {
481+ bool aSubsurfaceDesync ,
482+ bool aUseReadyToDrawCallback ) {
385483 LOGWAYLAND ("WaylandSurface::MapLocked()" );
386484 MOZ_DIAGNOSTIC_ASSERT (& aProofOfLock == mSurfaceLock );
387485 MOZ_DIAGNOSTIC_ASSERT (!mIsMapped , "Already mapped?" );
@@ -421,6 +519,14 @@ bool WaylandSurface::MapLocked(const WaylandSurfaceLock& aProofOfLock,
421519 LOGWAYLAND (" subsurface position [%d,%d]" , (int )mSubsurfacePosition .x ,
422520 (int )mSubsurfacePosition .y );
423521
522+ if (aUseReadyToDrawCallback ) {
523+ mReadyToDrawFrameCallback = wl_surface_frame (mParentSurface );
524+ wl_callback_add_listener (mReadyToDrawFrameCallback ,
525+ & sWaylandSurfaceReadyToDrawFrameListener , this );
526+ LOGWAYLAND (" created ready to draw frame callback ID %d\n" ,
527+ wl_proxy_get_id ((struct wl_proxy * )mReadyToDrawFrameCallback ));
528+ }
529+
424530 LOGWAYLAND (" register frame callback" );
425531 RequestFrameCallbackLocked (aProofOfLock );
426532
@@ -450,7 +556,8 @@ bool WaylandSurface::MapLocked(const WaylandSurfaceLock& aProofOfLock,
450556 gfx ::IntPoint aSubsurfacePosition ) {
451557 return MapLocked (aProofOfLock , nullptr , aParentWaylandSurfaceLock ,
452558 aSubsurfacePosition ,
453- /* aSubsurfaceDesync */ false);
559+ /* aSubsurfaceDesync */ false,
560+ /* aUseReadyToDrawCallback */ false);
454561}
455562
456563void WaylandSurface ::SetUnmapCallbackLocked (
@@ -502,11 +609,11 @@ void WaylandSurface::UnmapLocked(WaylandSurfaceLock& aSurfaceLock) {
502609 return ;
503610 }
504611 mIsMapped = false;
505- mIsVisible = false;
506612
507613 LOGWAYLAND ("WaylandSurface::UnmapLocked()" );
508614
509615 RemoveAttachedBufferLocked (aSurfaceLock );
616+ ClearReadyToDrawCallbacksLocked (aSurfaceLock );
510617 ClearFrameCallbackLocked (aSurfaceLock );
511618 ClearScaleLocked (aSurfaceLock );
512619
@@ -526,6 +633,9 @@ void WaylandSurface::UnmapLocked(WaylandSurfaceLock& aSurfaceLock) {
526633 MozClearPointer (mPendingOpaqueRegion , wl_region_destroy );
527634 MozClearPointer (mOpaqueRegionFrameCallback , wl_callback_destroy );
528635
636+ mIsReadyToDraw = false;
637+ mBufferAttached = false;
638+
529639 // Remove references to WaylandBuffers attached to mSurface,
530640 // we don't want to get any buffer release callback when we're unmapped.
531641 ReleaseAllWaylandTransactionsLocked (aSurfaceLock );
0 commit comments