From 45555dc042e3485c14e10aa56bb2cf3f1b790e39 Mon Sep 17 00:00:00 2001 From: Martin Stransky Date: Thu, 6 Dec 2018 11:02:46 +0000 Subject: [PATCH] Bug 1489902 - [Wayland/OpenGL] Don't draw to wl_surface owned by GtkWidget (mozcontainer) until it's commited, r=jhorak Use frame callback to determine if we can draw to wl_surface owned by GtkWidget and use it as a base for EGL Window. Differential Revision: https://phabricator.services.mozilla.com/D13722 --HG-- extra : moz-landing-system : lando --- widget/gtk/mozcontainer.cpp | 98 +++++++++++++++++-------------------- widget/gtk/mozcontainer.h | 3 +- widget/gtk/nsWindow.cpp | 7 --- 3 files changed, 46 insertions(+), 62 deletions(-) diff --git a/widget/gtk/mozcontainer.cpp b/widget/gtk/mozcontainer.cpp index c49354ead6c4..f99f976da173 100644 --- a/widget/gtk/mozcontainer.cpp +++ b/widget/gtk/mozcontainer.cpp @@ -147,55 +147,48 @@ void moz_container_init(MozContainer *container) { container->surface = nullptr; container->subsurface = nullptr; container->eglwindow = nullptr; + container->frame_callback_handler = nullptr; container->ready_to_draw = false; container->surface_needs_clear = true; #endif } #if defined(MOZ_WAYLAND) -static void moz_on_frame_clock_after_paint(GdkFrameClock *clock, - MozContainer *container) { - container->ready_to_draw = true; - g_signal_handler_disconnect(clock, - container->frame_clock_after_paint_handler); - container->frame_clock_after_paint_handler = 0; -} - -static void moz_container_map_wayland(MozContainer *container) { - MOZ_ASSERT(!container->ready_to_draw, "MozContainer is already mapped."); - MOZ_ASSERT(!container->frame_clock_after_paint_handler, - "Repeated gdk_window_get_frame_clock() request?"); - - GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(container)); - if (GDK_IS_X11_DISPLAY(display)) return; - - container->surface_needs_clear = true; - - static auto sGdkWindowGetFrameClock = (GdkFrameClock * (*)(GdkWindow *)) - dlsym(RTLD_DEFAULT, "gdk_window_get_frame_clock"); +static wl_surface *moz_container_get_gtk_container_surface( + MozContainer *container) { + static auto sGdkWaylandWindowGetWlSurface = (wl_surface * (*)(GdkWindow *)) + dlsym(RTLD_DEFAULT, "gdk_wayland_window_get_wl_surface"); GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container)); - GdkFrameClock *clock = sGdkWindowGetFrameClock(window); - container->frame_clock_after_paint_handler = g_signal_connect_after( - clock, "after-paint", G_CALLBACK(moz_on_frame_clock_after_paint), - container); + return sGdkWaylandWindowGetWlSurface(window); +} + +static void frame_callback_handler(void *data, struct wl_callback *callback, + uint32_t time) { + MozContainer *container = MOZ_CONTAINER(data); + g_clear_pointer(&container->frame_callback_handler, wl_callback_destroy); + container->ready_to_draw = true; +} + +static const struct wl_callback_listener frame_listener = { + frame_callback_handler}; + +static void moz_container_map_wayland(MozContainer *container) { + container->surface_needs_clear = true; + container->ready_to_draw = false; + + static wl_surface *gtk_container_surface = + moz_container_get_gtk_container_surface(container); + container->frame_callback_handler = wl_surface_frame(gtk_container_surface); + wl_callback_add_listener(container->frame_callback_handler, &frame_listener, + container); } static void moz_container_unmap_wayland(MozContainer *container) { g_clear_pointer(&container->eglwindow, wl_egl_window_destroy); g_clear_pointer(&container->subsurface, wl_subsurface_destroy); g_clear_pointer(&container->surface, wl_surface_destroy); - - if (container->frame_clock_after_paint_handler) { - static auto sGdkWindowGetFrameClock = (GdkFrameClock * (*)(GdkWindow *)) - dlsym(RTLD_DEFAULT, "gdk_window_get_frame_clock"); - GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container)); - GdkFrameClock *clock = sGdkWindowGetFrameClock(window); - - g_signal_handler_disconnect(clock, - container->frame_clock_after_paint_handler); - container->frame_clock_after_paint_handler = 0; - } + g_clear_pointer(&container->frame_callback_handler, wl_callback_destroy); container->ready_to_draw = false; } #endif @@ -223,7 +216,9 @@ void moz_container_map(GtkWidget *widget) { if (gtk_widget_get_has_window(widget)) { gdk_window_show(gtk_widget_get_window(widget)); #if defined(MOZ_WAYLAND) - moz_container_map_wayland(MOZ_CONTAINER(widget)); + if (!GDK_IS_X11_DISPLAY(gdk_display_get_default())) { + moz_container_map_wayland(MOZ_CONTAINER(widget)); + } #endif } } @@ -236,7 +231,9 @@ void moz_container_unmap(GtkWidget *widget) { if (gtk_widget_get_has_window(widget)) { gdk_window_hide(gtk_widget_get_window(widget)); #if defined(MOZ_WAYLAND) - moz_container_unmap_wayland(MOZ_CONTAINER(widget)); + if (!GDK_IS_X11_DISPLAY(gdk_display_get_default())) { + moz_container_unmap_wayland(MOZ_CONTAINER(widget)); + } #endif } } @@ -429,34 +426,27 @@ static void moz_container_add(GtkContainer *container, GtkWidget *widget) { #ifdef MOZ_WAYLAND struct wl_surface *moz_container_get_wl_surface(MozContainer *container) { - // We're not mapped yet. - if (!container->ready_to_draw) return nullptr; - if (!container->surface) { + if (!container->ready_to_draw) { + return nullptr; + } + GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(container)); + // Available as of GTK 3.8+ static auto sGdkWaylandDisplayGetWlCompositor = (wl_compositor * (*)(GdkDisplay *)) dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_compositor"); - static auto sGdkWaylandWindowGetWlSurface = (wl_surface * (*)(GdkWindow *)) - dlsym(RTLD_DEFAULT, "gdk_wayland_window_get_wl_surface"); - static auto sGdkWindowGetScaleFactorPtr = (gint(*)(GdkWindow *))dlsym( - RTLD_DEFAULT, "gdk_window_get_scale_factor"); - - GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container)); - GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(container)); - struct wl_compositor *compositor = sGdkWaylandDisplayGetWlCompositor(display); container->surface = wl_compositor_create_surface(compositor); - wl_surface *parent_surface = sGdkWaylandWindowGetWlSurface(window); - nsWaylandDisplay *waylandDisplay = WaylandDisplayGet(display); - wl_subcompositor *subcompositor = waylandDisplay->GetSubcompositor(); container->subsurface = wl_subcompositor_get_subsurface( - subcompositor, container->surface, parent_surface); + waylandDisplay->GetSubcompositor(), container->surface, + moz_container_get_gtk_container_surface(container)); WaylandDisplayRelease(waylandDisplay); + GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container)); gint x, y; gdk_window_get_position(window, &x, &y); wl_subsurface_set_position(container->subsurface, x, y); @@ -468,8 +458,8 @@ struct wl_surface *moz_container_get_wl_surface(MozContainer *container) { wl_surface_set_input_region(container->surface, region); wl_region_destroy(region); - container->surface_needs_clear = true; - + static auto sGdkWindowGetScaleFactorPtr = (gint(*)(GdkWindow *))dlsym( + RTLD_DEFAULT, "gdk_window_get_scale_factor"); if (sGdkWindowGetScaleFactorPtr) { gint scaleFactor = (*sGdkWindowGetScaleFactorPtr)(window); wl_surface_set_buffer_scale(container->surface, scaleFactor); diff --git a/widget/gtk/mozcontainer.h b/widget/gtk/mozcontainer.h index a7173a1ab653..450292273f41 100644 --- a/widget/gtk/mozcontainer.h +++ b/widget/gtk/mozcontainer.h @@ -75,9 +75,9 @@ struct _MozContainer { struct wl_surface *surface; struct wl_subsurface *subsurface; struct wl_egl_window *eglwindow; + struct wl_callback *frame_callback_handler; gboolean surface_needs_clear; gboolean ready_to_draw; - gulong frame_clock_after_paint_handler; #endif }; @@ -93,6 +93,7 @@ void moz_container_put(MozContainer *container, GtkWidget *child_widget, gint x, #ifdef MOZ_WAYLAND struct wl_surface *moz_container_get_wl_surface(MozContainer *container); struct wl_egl_window *moz_container_get_wl_egl_window(MozContainer *container); + gboolean moz_container_has_wl_egl_window(MozContainer *container); gboolean moz_container_surface_needs_clear(MozContainer *container); #endif diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index 718a8008be07..f032693813c2 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -1870,13 +1870,6 @@ gboolean nsWindow::OnExposeEvent(cairo_t *cr) { // Windows that are not visible will be painted after they become visible. if (!mGdkWindow || mIsFullyObscured || !mHasMappedToplevel) return FALSE; -#ifdef MOZ_WAYLAND - // Window does not have visible MozContainer/wl_surface yet. - if (!mIsX11Display && (!mContainer || !mContainer->ready_to_draw)) { - return FALSE; - } -#endif - nsIWidgetListener *listener = GetListener(); if (!listener) return FALSE;