From cb46f7b2dd544062d77b629135cd1974587e83d2 Mon Sep 17 00:00:00 2001 From: stransky Date: Thu, 22 Sep 2022 09:41:04 +0000 Subject: [PATCH] Bug 1645677 [Wayland] Update EGLSurface when wl_surface is deleted r=emilio,jgilbert When GtkWidget is hidden, underlying wl_surface is deleted. We need to also update EGLSurface of GtkWidget (GtkCompositorWidget) as EGLSurface is directly linked to wl_surface: - When GtkWidget is hidden, call GtkCompositorWidget::DisableRendering(). That releases GtkCompositorWidget resources related to GtkWidget (XWindow/XVisual etc.) and marks the widget as hidden. - If GtkWidget is backed by EGL call compositor resume which forces compositor to create new EGLSurface. - Make sure GLContextEGL can create EGLSurface even when GtkWidget is hidden and wl_surface is missing. It prevents fallback to SW rendering or pause RenderCompositorEGL which leads to Bug 1777664 (whole browser UI freeze). - Return early from RenderCompositorEGL::BeginFrame()/RenderCompositorEGL::EndFrame() when GtkCompositorWidget is hidden. Depends on D157357 Differential Revision: https://phabricator.services.mozilla.com/D157358 --- gfx/gl/GLContextProviderEGL.cpp | 12 ++++++++++ .../RenderCompositorEGL.cpp | 5 ++++ widget/gtk/nsWindow.cpp | 24 +++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/gfx/gl/GLContextProviderEGL.cpp b/gfx/gl/GLContextProviderEGL.cpp index 9285533c1638..78d1ac21bf23 100644 --- a/gfx/gl/GLContextProviderEGL.cpp +++ b/gfx/gl/GLContextProviderEGL.cpp @@ -346,6 +346,18 @@ EGLSurface GLContextEGL::CreateEGLSurfaceForCompositorWidget( } MOZ_ASSERT(aCompositorWidget); +#ifdef MOZ_WAYLAND + // RenderCompositorEGL does not like EGL_NO_SURFACE as it fallbacks + // to SW rendering or claims itself as paused. + // In case we're missing valid native window because aCompositorWidget hidden, + // just create a fallback EGLSurface. + // Actual EGLSurface will be created by widget code later when + // aCompositorWidget becomes visible. + if (widget::GdkIsWaylandDisplay() && aCompositorWidget->IsHidden()) { + mozilla::gfx::IntSize pbSize(16, 16); + return CreateWaylandBufferSurface(*egl, aConfig, pbSize); + } +#endif EGLNativeWindowType window = GET_NATIVE_WINDOW_FROM_COMPOSITOR_WIDGET(aCompositorWidget); if (!window) { diff --git a/gfx/webrender_bindings/RenderCompositorEGL.cpp b/gfx/webrender_bindings/RenderCompositorEGL.cpp index 11cf1932b827..b6b855b2d8ea 100644 --- a/gfx/webrender_bindings/RenderCompositorEGL.cpp +++ b/gfx/webrender_bindings/RenderCompositorEGL.cpp @@ -127,6 +127,11 @@ RenderedFrameId RenderCompositorEGL::EndFrame( #endif RenderedFrameId frameId = GetNextRenderFrameId(); +#ifdef MOZ_WAYLAND + if (mWidget->IsHidden()) { + return frameId; + } +#endif if (mEGLSurface != EGL_NO_SURFACE && aDirtyRects.Length() > 0) { gfx::IntRegion bufferInvalid; const auto bufferSize = GetBufferSize(); diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index ebc675720ed7..45f4d17847e7 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -3442,6 +3442,10 @@ void* nsWindow::GetNativeData(uint32_t aDataType) { #endif #ifdef MOZ_WAYLAND if (GdkIsWaylandDisplay()) { + if (mCompositorWidgetDelegate) { + MOZ_DIAGNOSTIC_ASSERT( + !mCompositorWidgetDelegate->AsGtkCompositorWidget()->IsHidden()); + } eglWindow = moz_container_wayland_get_egl_window( mContainer, FractionalScaleFactor()); } @@ -4059,6 +4063,26 @@ void nsWindow::OnMap() { void nsWindow::OnUnmap() { LOG("nsWindow::OnUnmap"); + + // wl_surface owned by mContainer is going to be deleted. + // Make sure we don't paint to it on Wayland. + if (GdkIsWaylandDisplay() && mCompositorWidgetDelegate) { + mCompositorWidgetDelegate->DisableRendering(); + } +#ifdef MOZ_WAYLAND + if (moz_container_wayland_has_egl_window(mContainer)) { + // Widget is backed by OpenGL EGLSurface created over wl_surface + // owned by mContainer. + // RenderCompositorEGL::Resume() deletes recent EGLSurface based on + // wl_surface owned by mContainer and creates a new fallback EGLSurface. + // Then we can delete wl_surface in moz_container_wayland_unmap(). + // We don't want to pause compositor as it may lead to whole + // browser freeze (Bug 1777664). + if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) { + remoteRenderer->SendResume(); + } + } +#endif moz_container_wayland_unmap(GTK_WIDGET(mContainer)); }