Bug 1527804 - Trigger composite from frame_callback_handler() r=stransky
authorsotaro <sotaro.ikeda.g@gmail.com>
Mon, 25 Feb 2019 12:15:50 +0000
changeset 518771 902743b5cc59aa0835b9e20e5df51e9f1fc529a6
parent 518770 ce6cff27290efa10e6e4fe63fe9889633a965fbb
child 518772 20b65c43871bfc0a0552932c445ec11bdabb5c5b
push id10862
push userffxbld-merge
push dateMon, 11 Mar 2019 13:01:11 +0000
treeherdermozilla-beta@a2e7f5c935da [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersstransky
bugs1527804, 1514156
milestone67.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 1527804 - Trigger composite from frame_callback_handler() r=stransky Bug 1514156 expects that nsWindow::OnExposeEvent() is called after frame_callback_handler() called. But it did not happen during opening add-ons(gecko profiler). Then we need to trigger rendering directly from frame_callback_handler() call. Differential Revision: https://phabricator.services.mozilla.com/D20272
widget/gtk/mozcontainer.cpp
widget/gtk/mozcontainer.h
widget/gtk/nsWindow.cpp
widget/gtk/nsWindow.h
--- a/widget/gtk/mozcontainer.cpp
+++ b/widget/gtk/mozcontainer.cpp
@@ -155,17 +155,17 @@ void moz_container_init(MozContainer *co
 #if defined(MOZ_WAYLAND)
   container->surface = nullptr;
   container->subsurface = nullptr;
   container->eglwindow = nullptr;
   container->frame_callback_handler = nullptr;
   // We can draw to x11 window any time.
   container->ready_to_draw = GDK_IS_X11_DISPLAY(gdk_display_get_default());
   container->surface_needs_clear = true;
-  container->egl_surface_needs_update = false;
+  container->inital_draw_cb = nullptr;
 #endif
 }
 
 #if defined(MOZ_WAYLAND)
 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");
@@ -173,22 +173,28 @@ static wl_surface *moz_container_get_gtk
   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);
-  if (!container->ready_to_draw) {
-    container->egl_surface_needs_update = true;
+  if (!container->ready_to_draw && container->inital_draw_cb) {
+    container->inital_draw_cb();
   }
   container->ready_to_draw = true;
 }
 
+void moz_container_set_initial_draw_callback(
+    MozContainer *container,
+    std::function<void(void)> inital_draw_cb) {
+  container->inital_draw_cb = inital_draw_cb;
+}
+
 static const struct wl_callback_listener frame_listener = {
     frame_callback_handler};
 
 static gboolean moz_container_map_wayland(GtkWidget *widget,
                                           GdkEventAny *event) {
   MozContainer *container = MOZ_CONTAINER(widget);
 
   if (container->ready_to_draw || container->frame_callback_handler) {
@@ -209,18 +215,18 @@ static gboolean moz_container_map_waylan
 
 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);
   g_clear_pointer(&container->frame_callback_handler, wl_callback_destroy);
 
   container->surface_needs_clear = true;
-  container->egl_surface_needs_update = false;
   container->ready_to_draw = false;
+  container->inital_draw_cb = nullptr;
 }
 
 static gint moz_container_get_scale(MozContainer *container) {
   static auto sGdkWindowGetScaleFactorPtr =
       (gint(*)(GdkWindow *))dlsym(RTLD_DEFAULT, "gdk_window_get_scale_factor");
 
   if (sGdkWindowGetScaleFactorPtr) {
     GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container));
@@ -555,19 +561,13 @@ gboolean moz_container_has_wl_egl_window
   return container->eglwindow ? true : false;
 }
 
 gboolean moz_container_surface_needs_clear(MozContainer *container) {
   gboolean state = container->surface_needs_clear;
   container->surface_needs_clear = false;
   return state;
 }
-
-gboolean moz_container_egl_surface_needs_update(MozContainer *container) {
-  gboolean state = container->egl_surface_needs_update;
-  container->egl_surface_needs_update = false;
-  return state;
-}
 #endif
 
 void moz_container_force_default_visual(MozContainer *container) {
   container->force_default_visual = true;
 }
--- a/widget/gtk/mozcontainer.h
+++ b/widget/gtk/mozcontainer.h
@@ -4,16 +4,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef __MOZ_CONTAINER_H__
 #define __MOZ_CONTAINER_H__
 
 #include <gtk/gtk.h>
+#include <functional>
 
 /*
  * MozContainer
  *
  * This class serves three purposes in the nsIWidget implementation.
  *
  *   - It provides objects to receive signals from GTK for events on native
  *     windows.
@@ -72,18 +73,18 @@ struct _MozContainer {
   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 egl_surface_needs_update;
   gboolean ready_to_draw;
+  std::function<void(void)> inital_draw_cb;
 #endif
   gboolean force_default_visual;
 };
 
 struct _MozContainerClass {
   GtkContainerClass parent_class;
 };
 
@@ -96,12 +97,14 @@ void moz_container_force_default_visual(
 #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);
 void moz_container_scale_changed(MozContainer *container,
                                  GtkAllocation *aAllocation);
-gboolean moz_container_egl_surface_needs_update(MozContainer *container);
+void moz_container_set_initial_draw_callback(
+    MozContainer *container,
+    std::function<void(void)> inital_draw_cb);
 #endif
 
 #endif /* __MOZ_CONTAINER_H__ */
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -670,16 +670,22 @@ void nsWindow::Destroy() {
   }
 
   // make sure that we remove ourself as the focus window
   if (gFocusWindow == this) {
     LOGFOCUS(("automatically losing focus...\n"));
     gFocusWindow = nullptr;
   }
 
+#ifdef MOZ_WAYLAND
+  if (mContainer) {
+    moz_container_set_initial_draw_callback(mContainer, nullptr);
+  }
+#endif
+
   GtkWidget *owningWidget = GetMozContainerWidget();
   if (mShell) {
     gtk_widget_destroy(mShell);
     mShell = nullptr;
     mContainer = nullptr;
     MOZ_ASSERT(!mGdkWindow,
                "mGdkWindow should be NULL when mContainer is destroyed");
   } else if (mContainer) {
@@ -1855,16 +1861,33 @@ static bool ExtractExposeRegion(LayoutDe
                LayoutDeviceIntRect::Truncate(r.x, r.y, r.width, r.height));
     LOGDRAW(("\t%f %f %f %f\n", r.x, r.y, r.width, r.height));
   }
 
   cairo_rectangle_list_destroy(rects);
   return true;
 }
 
+#ifdef MOZ_WAYLAND
+void nsWindow::WaylandEGLSurfaceForceRedraw() {
+  MOZ_RELEASE_ASSERT(NS_IsMainThread());
+
+  if (mIsDestroyed) {
+    return;
+  }
+
+  if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) {
+    if (mCompositorWidgetDelegate) {
+      mCompositorWidgetDelegate->RequestsUpdatingEGLSurface();
+    }
+    remoteRenderer->SendForcePresent();
+  }
+}
+#endif
+
 gboolean nsWindow::OnExposeEvent(cairo_t *cr) {
   // Send any pending resize events so that layout can update.
   // May run event loop.
   MaybeDispatchResized();
 
   if (mIsDestroyed) {
     return FALSE;
   }
@@ -1883,21 +1906,16 @@ gboolean nsWindow::OnExposeEvent(cairo_t
     return FALSE;
   }
 
   gint scale = GdkScaleFactor();
   LayoutDeviceIntRegion region = exposeRegion;
   region.ScaleRoundOut(scale, scale);
 
   if (GetLayerManager()->AsKnowsCompositor() && mCompositorSession) {
-#ifdef MOZ_WAYLAND
-    if (mCompositorWidgetDelegate && WaylandRequestsUpdatingEGLSurface()) {
-      mCompositorWidgetDelegate->RequestsUpdatingEGLSurface();
-    }
-#endif
     // We need to paint to the screen even if nothing changed, since if we
     // don't have a compositing window manager, our pixels could be stale.
     GetLayerManager()->SetNeedsComposite(true);
     GetLayerManager()->SendInvalidRegion(region.ToUnknownRegion());
   }
 
   RefPtr<nsWindow> strongThis(this);
 
@@ -3449,16 +3467,25 @@ nsresult nsWindow::Create(nsIWidget *aPa
         GtkWindowGroup *group = gtk_window_group_new();
         gtk_window_group_add_window(group, GTK_WINDOW(mShell));
         g_object_unref(group);
       }
 
       // Create a container to hold child windows and child GtkWidgets.
       GtkWidget *container = moz_container_new();
       mContainer = MOZ_CONTAINER(container);
+#ifdef MOZ_WAYLAND
+      if (!mIsX11Display && ComputeShouldAccelerate()) {
+        RefPtr<nsWindow> self(this);
+        moz_container_set_initial_draw_callback(mContainer,
+            [self]() -> void {
+              self->WaylandEGLSurfaceForceRedraw();
+            });
+      }
+#endif
 
       // "csd" style is set when widget is realized so we need to call
       // it explicitly now.
       gtk_widget_realize(mShell);
 
       /* There are several cases here:
        *
        * 1) We're running on Gtk+ without client side decorations.
@@ -6559,27 +6586,16 @@ bool nsWindow::WaylandSurfaceNeedsClear(
   if (mContainer) {
     return moz_container_surface_needs_clear(MOZ_CONTAINER(mContainer));
   }
 
   NS_WARNING(
       "nsWindow::WaylandSurfaceNeedsClear(): We don't have any mContainer!");
   return false;
 }
-
-bool nsWindow::WaylandRequestsUpdatingEGLSurface() {
-  if (mContainer) {
-    return moz_container_egl_surface_needs_update(MOZ_CONTAINER(mContainer));
-  }
-
-  NS_WARNING(
-      "nsWindow::WaylandSurfaceNeedsClear(): We don't have any mContainer!");
-  return false;
-}
-
 #endif
 
 #ifdef MOZ_X11
 /* XApp progress support currently works by setting a property
  * on a window with this Atom name.  A supporting window manager
  * will notice this and pass it along to whatever handling has
  * been implemented on that end (e.g. passing it on to a taskbar
  * widget.)  There is no issue if WM support is lacking, this is
--- a/widget/gtk/nsWindow.h
+++ b/widget/gtk/nsWindow.h
@@ -240,16 +240,19 @@ class nsWindow final : public nsBaseWidg
   void EnsureGrabs(void);
   void GrabPointer(guint32 aTime);
   void ReleaseGrabs(void);
 
   void UpdateClientOffset();
 
   void DispatchContextMenuEventFromMouseEvent(uint16_t domButton,
                                               GdkEventButton* aEvent);
+#ifdef MOZ_WAYLAND
+  void WaylandEGLSurfaceForceRedraw();
+#endif
 
  public:
   void ThemeChanged(void);
   void OnDPIChanged(void);
   void OnCheckResize(void);
   void OnCompositedChanged(void);
   void OnScaleChanged(GtkAllocation* aAllocation);
 
@@ -337,17 +340,16 @@ class nsWindow final : public nsBaseWidg
 
 #ifdef MOZ_X11
   Display* XDisplay() { return mXDisplay; }
 #endif
 #ifdef MOZ_WAYLAND
   wl_display* GetWaylandDisplay();
   wl_surface* GetWaylandSurface();
   bool WaylandSurfaceNeedsClear();
-  bool WaylandRequestsUpdatingEGLSurface();
 #endif
   virtual void GetCompositorWidgetInitData(
       mozilla::widget::CompositorWidgetInitData* aInitData) override;
 
   virtual nsresult SetNonClientMargins(
       LayoutDeviceIntMargin& aMargins) override;
   void SetDrawsInTitlebar(bool aState) override;
   virtual void UpdateWindowDraggingRegion(