Bug 1489902 - [Wayland/OpenGL] Don't draw to wl_surface owned by GtkWidget (mozcontainer) until it's commited, r=jhorak
authorMartin Stransky <stransky@redhat.com>
Thu, 06 Dec 2018 11:02:46 +0000
changeset 508728 c6467f04bcd9b1b538bf355ded9e100bda485403
parent 508727 faf53bfff31ea53d112f9b219fff32deeb160fd2
child 508729 32b8595b7c207bec915e39450d565ada6f50bc48
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjhorak
bugs1489902
milestone65.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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
widget/gtk/mozcontainer.cpp
widget/gtk/mozcontainer.h
widget/gtk/nsWindow.cpp
--- a/widget/gtk/mozcontainer.cpp
+++ b/widget/gtk/mozcontainer.cpp
@@ -142,65 +142,58 @@ void moz_container_init(MozContainer *co
   gtk_widget_set_can_focus(GTK_WIDGET(container), TRUE);
   gtk_container_set_resize_mode(GTK_CONTAINER(container), GTK_RESIZE_IMMEDIATE);
   gtk_widget_set_redraw_on_allocate(GTK_WIDGET(container), FALSE);
 
 #if defined(MOZ_WAYLAND)
   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) {
+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));
+  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;
-  g_signal_handler_disconnect(clock,
-                              container->frame_clock_after_paint_handler);
-  container->frame_clock_after_paint_handler = 0;
 }
 
+static const struct wl_callback_listener frame_listener = {
+    frame_callback_handler};
+
 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;
+  container->ready_to_draw = false;
 
-  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);
-  container->frame_clock_after_paint_handler = g_signal_connect_after(
-      clock, "after-paint", G_CALLBACK(moz_on_frame_clock_after_paint),
-      container);
+  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
 
 void moz_container_map(GtkWidget *widget) {
   MozContainer *container;
   GList *tmp_list;
   GtkWidget *tmp_child;
@@ -218,30 +211,34 @@ void moz_container_map(GtkWidget *widget
       if (!gtk_widget_get_mapped(tmp_child)) gtk_widget_map(tmp_child);
     }
     tmp_list = tmp_list->next;
   }
 
   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
   }
 }
 
 void moz_container_unmap(GtkWidget *widget) {
   g_return_if_fail(IS_MOZ_CONTAINER(widget));
 
   gtk_widget_set_mapped(widget, FALSE);
 
   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
   }
 }
 
 void moz_container_realize(GtkWidget *widget) {
   GdkWindow *parent = gtk_widget_get_parent_window(widget);
   GdkWindow *window;
 
@@ -424,57 +421,50 @@ MozContainerChild *moz_container_get_chi
 }
 
 static void moz_container_add(GtkContainer *container, GtkWidget *widget) {
   moz_container_put(MOZ_CONTAINER(container), widget, 0, 0);
 }
 
 #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));
 
-  if (!container->surface) {
     // 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);
     wl_subsurface_set_desync(container->subsurface);
 
     // Route input to parent wl_surface owned by Gtk+ so we get input
     // events from Gtk+.
     wl_region *region = wl_compositor_create_region(compositor);
     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);
     }
   }
 
   return container->surface;
 }
--- a/widget/gtk/mozcontainer.h
+++ b/widget/gtk/mozcontainer.h
@@ -70,31 +70,32 @@ struct wl_subsurface;
 struct _MozContainer {
   GtkContainer container;
   GList *children;
 
 #ifdef MOZ_WAYLAND
   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
 };
 
 struct _MozContainerClass {
   GtkContainerClass parent_class;
 };
 
 GType moz_container_get_type(void);
 GtkWidget *moz_container_new(void);
 void moz_container_put(MozContainer *container, GtkWidget *child_widget, gint x,
                        gint y);
 
 #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
 
 #endif /* __MOZ_CONTAINER_H__ */
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -1865,23 +1865,16 @@ gboolean nsWindow::OnExposeEvent(cairo_t
 
   if (mIsDestroyed) {
     return FALSE;
   }
 
   // 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;
 
   LayoutDeviceIntRegion exposeRegion;
   if (!ExtractExposeRegion(exposeRegion, cr)) {
     return FALSE;
   }