Bug 1464823 - [Wayland] Don't paint until we have a visible wl_surface, r=jhorak,lsalzman
authorMartin Stransky <stransky@redhat.com>
Wed, 06 Jun 2018 11:30:27 +0200
changeset 476752 f13d1acd73da207fdd38f6e113bfca8742b6d933
parent 476751 51bd0147c06b33d17127ca6aa1f8aad79c2ebb01
child 476753 684094d78fb48f4847db152fcbc83e6196448a72
push id9374
push userjlund@mozilla.com
push dateMon, 18 Jun 2018 21:43:20 +0000
treeherdermozilla-beta@160e085dfb0b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjhorak, lsalzman
bugs1464823
milestone62.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 1464823 - [Wayland] Don't paint until we have a visible wl_surface, r=jhorak,lsalzman It's based on a solution by Takuro Ashie <ashie@clear-code.com> MozReview-Commit-ID: FqcdUJQJLdl
widget/gtk/mozcontainer.cpp
widget/gtk/mozcontainer.h
widget/gtk/nsWindow.cpp
--- a/widget/gtk/mozcontainer.cpp
+++ b/widget/gtk/mozcontainer.cpp
@@ -207,16 +207,17 @@ moz_container_init (MozContainer *contai
     gtk_widget_set_redraw_on_allocate(GTK_WIDGET(container), FALSE);
 
 #if defined(MOZ_WAYLAND)
     {
       container->subcompositor = nullptr;
       container->surface = nullptr;
       container->subsurface = nullptr;
       container->eglwindow = nullptr;
+      container->committed = false;
 
       GdkDisplay *gdk_display = gtk_widget_get_display(GTK_WIDGET(container));
       if (GDK_IS_WAYLAND_DISPLAY (gdk_display)) {
           // Available as of GTK 3.8+
           static auto sGdkWaylandDisplayGetWlDisplay =
               (wl_display *(*)(GdkDisplay *))
               dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_display");
 
@@ -226,33 +227,44 @@ moz_container_init (MozContainer *contai
           wl_display_dispatch(display);
           wl_display_roundtrip(display);
         }
     }
 #endif
 }
 
 #if defined(MOZ_WAYLAND)
+static void
+moz_container_after_paint(GdkFrameClock *clock, MozContainer *container)
+{
+    container->committed = true;
+    g_signal_handlers_disconnect_by_func(clock,
+         reinterpret_cast<gpointer>(moz_container_after_paint), container);
+}
+
 /* We want to draw to GdkWindow owned by mContainer from Compositor thread but
  * Gtk+ can be used in main thread only. So we create wayland wl_surface
  * and attach it as an overlay to GdkWindow.
  *
  * see gtk_clutter_embed_ensure_subsurface() at gtk-clutter-embed.c
-*  for reference.
+ * for reference.
  */
 static gboolean
 moz_container_map_surface(MozContainer *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 sGdkWindowGetFrameClock =
+        (GdkFrameClock *(*)(GdkWindow *))
+        dlsym(RTLD_DEFAULT, "gdk_window_get_frame_clock");
 
     GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(container));
     if (GDK_IS_X11_DISPLAY(display))
         return false;
 
     if (container->subsurface && container->surface)
         return true;
 
@@ -267,16 +279,21 @@ moz_container_map_surface(MozContainer *
         wl_surface* gtk_surface = sGdkWaylandWindowGetWlSurface(window);
         if (!gtk_surface) {
           // We requested the underlying wl_surface too early when container
           // is not realized yet. We'll try again before first rendering
           // to mContainer.
           return false;
         }
 
+        GdkFrameClock *clock = sGdkWindowGetFrameClock(window);
+        g_signal_connect_after(clock, "after-paint",
+                               G_CALLBACK(moz_container_after_paint),
+                               container);
+
         container->subsurface =
           wl_subcompositor_get_subsurface (container->subcompositor,
                                            container->surface,
                                            gtk_surface);
         gint x, y;
         gdk_window_get_position(window, &x, &y);
         wl_subsurface_set_position(container->subsurface, x, y);
         wl_subsurface_set_desync(container->subsurface);
@@ -293,16 +310,17 @@ moz_container_map_surface(MozContainer *
 }
 
 static void
 moz_container_unmap_surface(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);
+    container->committed = false;
 }
 
 #endif
 
 void
 moz_container_map (GtkWidget *widget)
 {
     MozContainer *container;
@@ -564,17 +582,17 @@ moz_container_get_wl_surface(MozContaine
     if (!container->subsurface || !container->surface) {
         GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container));
         if (!gdk_window_is_visible(window))
             return nullptr;
 
         moz_container_map_surface(container);
     }
 
-    return container->surface;
+    return container->committed ? container->surface : nullptr;
 }
 
 struct wl_egl_window *
 moz_container_get_wl_egl_window(MozContainer *container)
 {
     if (!container->eglwindow) {
         struct wl_surface *wlsurf = moz_container_get_wl_surface(container);
         if (!wlsurf)
--- a/widget/gtk/mozcontainer.h
+++ b/widget/gtk/mozcontainer.h
@@ -68,16 +68,17 @@ struct _MozContainer
     GtkContainer   container;
     GList         *children;
 
 #ifdef MOZ_WAYLAND
     struct wl_subcompositor *subcompositor;
     struct wl_surface       *surface;
     struct wl_subsurface    *subsurface;
     struct wl_egl_window    *eglwindow;
+    gboolean                 committed;
 #endif
 };
 
 struct _MozContainerClass
 {
     GtkContainerClass parent_class;
 };
 
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -2062,16 +2062,22 @@ nsWindow::OnExposeEvent(cairo_t *cr)
     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 wl_surface yet.
+    if (!mIsX11Display && !GetWaylandSurface())
+        return FALSE;
+#endif
+
     nsIWidgetListener *listener = GetListener();
     if (!listener)
         return FALSE;
 
     LayoutDeviceIntRegion exposeRegion;
     if (!ExtractExposeRegion(exposeRegion, cr)) {
         return FALSE;
     }