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
This commit is contained in:
stransky 2022-09-22 09:41:04 +00:00
parent 24d8cfd0dd
commit cb46f7b2dd
3 changed files with 41 additions and 0 deletions

View File

@ -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) {

View File

@ -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();

View File

@ -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));
}