[PATCH xserver] xwayland: Flips on subsurfaces

Roman Gilg subdiff at gmail.com
Mon Jan 29 16:54:26 UTC 2018


Do flips for child windows via subsurfaces if the Wayland server
supports them.

Signed-off-by: Roman Gilg <subdiff at gmail.com>
---
 hw/xwayland/xwayland-present.c | 57 +++++++++++++++++++++++++++++++++---------
 hw/xwayland/xwayland.c         |  6 ++++-
 hw/xwayland/xwayland.h         |  2 ++
 present/present_wnmd.c         | 23 -----------------
 4 files changed, 52 insertions(+), 36 deletions(-)

diff --git a/hw/xwayland/xwayland-present.c b/hw/xwayland/xwayland-present.c
index d08c39e..f68bf92 100644
--- a/hw/xwayland/xwayland-present.c
+++ b/hw/xwayland/xwayland-present.c
@@ -55,15 +55,22 @@ xwl_present_cleanup(WindowPtr window)
      * And therefore need to cleanup.
      */
 
+    /* Clear frame callback */
     if (xwl_window->present_frame_callback) {
         wl_callback_destroy(xwl_window->present_frame_callback);
         xwl_window->present_frame_callback = NULL;
     }
 
+    /* Clear surfaces */
+    if (xwl_window->present_subsurface) {
+        wl_subsurface_destroy(xwl_window->present_subsurface);
+        wl_surface_destroy(xwl_window->present_surface);
+        xwl_window->present_subsurface = NULL;
+    }
+    xwl_window->present_surface = NULL;
+
     /* Reset base data */
     xorg_list_del(&xwl_window->present_link);
-
-    xwl_window->present_surface = NULL;
     xwl_window->present_window = NULL;
 
     TimerFree(xwl_window->present_frame_timer);
@@ -299,29 +306,31 @@ xwl_present_check_flip(RRCrtcPtr crtc,
         return FALSE;
 
     /*
-     * We currently only allow flips of windows, that have the same
-     * dimensions as their xwl_window parent window. For the case of
-     * different sizes subsurfaces are presumably the way forward.
+     * Allow different sizes for the presenting window and its associated
+     * xwl_window only if the Wayland server supports subsurfaces.
      */
-    if (!RegionEqual(&xwl_window->window->winSize, &present_window->winSize))
+    if (!RegionEqual(&xwl_window->window->winSize, &present_window->winSize) &&
+            !xwl_window->xwl_screen->subcompositor)
         return FALSE;
 
     return TRUE;
 }
 
-static void
+static Bool
 xwl_present_reset_present_window(struct xwl_window *xwl_window, WindowPtr present_window)
 {
     /* Do not reset if it is the same present_window. But this also means, that
      * we always switch to another child window, if it wants to present.
      */
     if (xwl_window->present_window == present_window)
-        return;
+        return FALSE;
 
     if (xwl_window->present_window)
         xwl_present_cleanup(xwl_window->present_window);
     xwl_window->present_window = present_window;
     xorg_list_add(&xwl_window->present_link, &xwl_present_windows);
+
+    return TRUE;
 }
 
 static Bool
@@ -334,18 +343,37 @@ xwl_present_flip(WindowPtr present_window,
                  RegionPtr damage)
 {
     struct xwl_window           *xwl_window = xwl_window_of_top(present_window);
-    BoxPtr                      present_box, damage_box;
+    BoxPtr                      win_box, present_box, damage_box;
+    struct xwl_screen           *xwl_screen = xwl_window->xwl_screen;
     Bool                        buffer_created;
     struct wl_buffer            *buffer;
     struct xwl_present_event    *event;
+    struct wl_region            *input_region;
 
+    win_box = RegionExtents(&xwl_window->window->winSize);
     present_box = RegionExtents(&present_window->winSize);
     damage_box = RegionExtents(damage);
 
     /* Potentially reset the presenting window */
-    xwl_present_reset_present_window(xwl_window, present_window);
-    /* We can flip directly to the main surface (full screen window without clips) */
-    xwl_window->present_surface = xwl_window->surface;
+    if ( xwl_present_reset_present_window(xwl_window, present_window) ) {
+
+        if (RegionEqual(&xwl_window->window->winSize, &present_window->winSize)) {
+            /* We can flip directly to the main surface (full screen window without clips) */
+            xwl_window->present_surface = xwl_window->surface;
+        } else {
+            xwl_window->present_surface =  wl_compositor_create_surface(xwl_screen->compositor);
+            wl_surface_set_user_data(xwl_window->present_surface, xwl_window);
+
+            xwl_window->present_subsurface =
+                    wl_subcompositor_get_subsurface(xwl_screen->subcompositor, xwl_window->present_surface, xwl_window->surface);
+            wl_subsurface_set_sync(xwl_window->present_subsurface);
+
+            input_region = wl_compositor_create_region(xwl_screen->compositor);
+            wl_surface_set_input_region(xwl_window->present_surface, input_region);
+            wl_region_destroy(input_region);
+        }
+
+    }
 
     event = malloc(sizeof *event);
     if (!event) {
@@ -353,6 +381,11 @@ xwl_present_flip(WindowPtr present_window,
         return FALSE;
     }
 
+    if (xwl_window->present_subsurface)
+        wl_subsurface_set_position(xwl_window->present_subsurface,
+                                   present_box->x1 - win_box->x1,
+                                   present_box->y1 - win_box->y1);
+
     buffer = xwl_glamor_pixmap_get_wl_buffer(pixmap,
                                              present_box->x2 - present_box->x1,
                                              present_box->y2 - present_box->y1,
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 386f11c..a83f718 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -698,7 +698,7 @@ xwl_screen_post_damage(struct xwl_screen *xwl_screen)
     xorg_list_for_each_entry_safe(xwl_window, next_xwl_window,
                                   &xwl_screen->damage_window_list, link_damage) {
         /* Present on the main surface. So don't commit here as well. */
-        if (xwl_window->present_surface)
+        if (xwl_window->present_surface && !xwl_window->present_subsurface)
             continue;
         /* If we're waiting on a frame callback from the server,
          * don't attach a new buffer. */
@@ -722,6 +722,10 @@ registry_global(void *data, struct wl_registry *registry, uint32_t id,
         xwl_screen->compositor =
             wl_registry_bind(registry, id, &wl_compositor_interface, 1);
     }
+    else if (strcmp(interface, "wl_subcompositor") == 0) {
+        xwl_screen->subcompositor =
+            wl_registry_bind(registry, id, &wl_subcompositor_interface, 1);
+    }
     else if (strcmp(interface, "wl_shm") == 0) {
         xwl_screen->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
     }
diff --git a/hw/xwayland/xwayland.h b/hw/xwayland/xwayland.h
index c294a92..464a90e 100644
--- a/hw/xwayland/xwayland.h
+++ b/hw/xwayland/xwayland.h
@@ -79,6 +79,7 @@ struct xwl_screen {
     struct wl_registry *registry;
     struct wl_registry *input_registry;
     struct wl_compositor *compositor;
+    struct wl_subcompositor *subcompositor;
     struct zwp_tablet_manager_v2 *tablet_manager;
     struct wl_shm *shm;
     struct wl_shell *shell;
@@ -135,6 +136,7 @@ struct xwl_window {
     struct xorg_list present_link;
     WindowPtr present_window;
     struct wl_surface *present_surface;
+    struct wl_subsurface *present_subsurface;
     uint64_t present_msc;
 
     Bool present_frame_timer_firing;
diff --git a/present/present_wnmd.c b/present/present_wnmd.c
index 77f4f19..cec7855 100644
--- a/present/present_wnmd.c
+++ b/present/present_wnmd.c
@@ -120,24 +120,6 @@ present_wnmd_free_idle_vblanks(WindowPtr window)
     }
 }
 
-static WindowPtr
-present_wnmd_toplvl_pixmap_window(WindowPtr window)
-{
-    ScreenPtr       screen = window->drawable.pScreen;
-    PixmapPtr       pixmap = (*screen->GetWindowPixmap)(window);
-    WindowPtr       w = window;
-    WindowPtr       next_w;
-
-    while(w->parent) {
-        next_w = w->parent;
-        if ( (*screen->GetWindowPixmap)(next_w) != pixmap) {
-            break;
-        }
-        w = next_w;
-    }
-    return w;
-}
-
 void
 present_wnmd_set_abort_flip(WindowPtr window)
 {
@@ -257,7 +239,6 @@ present_wnmd_check_flip(RRCrtcPtr    crtc,
 {
     ScreenPtr               screen = window->drawable.pScreen;
     present_screen_priv_ptr screen_priv = present_screen_priv(screen);
-    WindowPtr               toplvl_window = present_wnmd_toplvl_pixmap_window(window);
 
     if (!screen_priv)
         return FALSE;
@@ -287,10 +268,6 @@ present_wnmd_check_flip(RRCrtcPtr    crtc,
             window->drawable.height != pixmap->drawable.height)
         return FALSE;
 
-    /* Window must be same region as toplevel window */
-    if ( !RegionEqual(&window->winSize, &toplvl_window->winSize) )
-        return FALSE;
-
     /* Ask the driver for permission */
     if (screen_priv->wnmd_info->check_flip) {
         if (!(*screen_priv->wnmd_info->check_flip) (crtc, window, pixmap, sync_flip)) {
-- 
2.7.4



More information about the xorg-devel mailing list