[PATCH 1/2] Initial Present Wayland support

Axel Davy axel.davy at ens.fr
Sat Jan 25 09:04:13 PST 2014


Signed-off-by: Axel Davy <axel.davy at ens.fr>
---
 present/present.c         |  77 +++++++++++----
 present/present_priv.h    |  37 +++++++
 present/present_wayland.c | 240 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 333 insertions(+), 21 deletions(-)
 create mode 100644 present/present_wayland.c

diff --git a/present/present.c b/present/present.c
index 30cd3b9..931e8ce 100644
--- a/present/present.c
+++ b/present/present.c
@@ -45,7 +45,7 @@ static struct xorg_list present_flip_queue;
 /*
  * Copies the update region from a pixmap to the target drawable
  */
-static void
+void
 present_copy_region(DrawablePtr drawable,
                     PixmapPtr pixmap,
                     RegionPtr update,
@@ -167,7 +167,7 @@ present_flip(RRCrtcPtr crtc,
     return (*screen_priv->info->flip) (crtc, event_id, target_msc, pixmap, sync_flip);
 }
 
-static void
+void
 present_vblank_notify(present_vblank_ptr vblank, CARD8 kind, CARD8 mode, uint64_t ust, uint64_t crtc_msc)
 {
     int         n;
@@ -183,7 +183,7 @@ present_vblank_notify(present_vblank_ptr vblank, CARD8 kind, CARD8 mode, uint64_
     }
 }
 
-static void
+void
 present_pixmap_idle(PixmapPtr pixmap, WindowPtr window, CARD32 serial, struct present_fence *present_fence)
 {
     if (present_fence)
@@ -329,7 +329,7 @@ present_set_tree_pixmap_visit(WindowPtr window, pointer data)
     return WT_WALKCHILDREN;
 }
     
-static void
+void
 present_set_tree_pixmap(WindowPtr window, PixmapPtr pixmap)
 {
     struct pixmap_visit visit;
@@ -462,7 +462,12 @@ present_check_flip_window (WindowPtr window)
 
     if (screen_priv->unflip_event_id)
         return;
-
+#ifdef PRESENT_WAYLAND
+    if (xorgWayland) {
+        /* We don't need to do anything */
+        return;
+    }
+#endif
     if (flip_pending) {
         /*
          * Check pending flip
@@ -663,15 +668,23 @@ present_pixmap(WindowPtr window,
         if (!target_crtc)
             target_crtc = present_get_crtc(window);
     }
+#ifdef PRESENT_WAYLAND
+    if (!xorgWayland) {
+#endif
+        present_get_ust_msc(window, target_crtc, &ust, &crtc_msc);
 
-    present_get_ust_msc(window, target_crtc, &ust, &crtc_msc);
-
-    target_msc = present_window_to_crtc_msc(window, target_crtc, window_msc, crtc_msc);
-
-    /* Stash the current MSC away in case we need it later
-     */
-    window_priv->msc = crtc_msc;
+        target_msc = present_window_to_crtc_msc(window, target_crtc, window_msc, crtc_msc);
 
+        /* Stash the current MSC away in case we need it later
+         */
+        window_priv->msc = crtc_msc;
+#ifdef PRESENT_WAYLAND
+    } else {
+        /* for now msc is a per-window thing for XWayland */
+        crtc_msc = window_priv->msc;
+        target_msc = window_msc;
+    }
+#endif
     /* Adjust target_msc to match modulus
      */
     if (crtc_msc >= target_msc) {
@@ -686,7 +699,11 @@ present_pixmap(WindowPtr window,
             }
         } else {
             target_msc = crtc_msc;
+#ifdef PRESENT_WAYLAND
+            if (!xorgWayland && !(options & PresentOptionAsync))
+#else
             if (!(options & PresentOptionAsync))
+#endif
                 target_msc++;
         }
     }
@@ -760,16 +777,25 @@ present_pixmap(WindowPtr window,
     vblank->msc_offset = window_priv->msc_offset;
     vblank->notifies = notifies;
     vblank->num_notifies = num_notifies;
+#ifdef PRESENT_WAYLAND
+    if (xorgWayland) {
+        if (crtc_msc >= target_msc)
+            vblank->flip_allowed = FALSE;
+        else
+            vblank->flip_allowed = TRUE;
+    } else {
+#endif
+        if (!screen_priv->info || !(screen_priv->info->capabilities & PresentCapabilityAsync))
+            vblank->sync_flip = TRUE;
 
-    if (!screen_priv->info || !(screen_priv->info->capabilities & PresentCapabilityAsync))
-        vblank->sync_flip = TRUE;
-
-    if (pixmap && present_check_flip (target_crtc, window, pixmap, vblank->sync_flip, valid, x_off, y_off)) {
-        vblank->flip = TRUE;
-        if (vblank->sync_flip)
-            target_msc--;
+        if (pixmap && present_check_flip (target_crtc, window, pixmap, vblank->sync_flip, valid, x_off, y_off)) {
+            vblank->flip = TRUE;
+            if (vblank->sync_flip)
+                target_msc--;
+        }
+#ifdef PRESENT_WAYLAND
     }
-
+#endif
     if (wait_fence) {
         vblank->wait_fence = present_fence_create(wait_fence);
         if (!vblank->wait_fence)
@@ -788,8 +814,17 @@ present_pixmap(WindowPtr window,
                       vblank->pixmap->drawable.id, vblank->window->drawable.id,
                       target_crtc));
 
-    xorg_list_add(&vblank->event_queue, &present_exec_queue);
     vblank->queued = TRUE;
+
+#ifdef PRESENT_WAYLAND
+    if (xorgWayland) {
+        present_wayland_execute(vblank);
+        return Success;
+    }
+#endif
+
+    xorg_list_add(&vblank->event_queue, &present_exec_queue);
+
     if (target_msc >= crtc_msc) {
         ret = present_queue_vblank(screen, target_crtc, vblank->event_id, target_msc);
         if (ret != Success) {
diff --git a/present/present_priv.h b/present/present_priv.h
index 8d3e007..3949ddb 100644
--- a/present/present_priv.h
+++ b/present/present_priv.h
@@ -39,6 +39,10 @@ extern int present_request;
 
 extern DevPrivateKeyRec present_screen_private_key;
 
+#ifdef PRESENT_WAYLAND
+extern _X_EXPORT Bool xorgWayland;
+#endif
+
 typedef struct present_fence *present_fence_ptr;
 
 typedef struct present_notify present_notify_rec, *present_notify_ptr;
@@ -73,6 +77,11 @@ struct present_vblank {
     Bool                flip;           /* planning on using flip */
     Bool                sync_flip;      /* do flip synchronous to vblank */
     Bool                abort_flip;     /* aborting this flip */
+#ifdef PRESENT_WAYLAND
+    Bool                flip_allowed;
+    Bool                flip_presented;
+    Bool                flip_released;
+#endif
 };
 
 typedef struct present_screen_priv {
@@ -129,6 +138,10 @@ typedef struct present_window_priv {
     RRCrtcPtr              crtc;        /* Last reported CRTC from get_ust_msc */
     uint64_t               msc_offset;
     uint64_t               msc;         /* Last reported MSC from the current crtc */
+#ifdef PRESENT_WAYLAND
+    uint32_t               last_msc_update;
+    Bool                   pixmap_is_flip;
+#endif
     struct xorg_list       vblank;
     struct xorg_list       notifies;
 } present_window_priv_rec, *present_window_priv_ptr;
@@ -149,6 +162,22 @@ extern RESTYPE present_event_type;
 /*
  * present.c
  */
+void
+present_copy_region(DrawablePtr drawable,
+                    PixmapPtr pixmap,
+                    RegionPtr update,
+                    int16_t x_off,
+                    int16_t y_off);
+
+void
+present_vblank_notify(present_vblank_ptr vblank, CARD8 kind, CARD8 mode, uint64_t ust, uint64_t crtc_msc);
+
+void
+present_pixmap_idle(PixmapPtr pixmap, WindowPtr window, CARD32 serial, struct present_fence *present_fence);
+
+void
+present_set_tree_pixmap(WindowPtr window, PixmapPtr pixmap);
+
 int
 present_pixmap(WindowPtr window,
                PixmapPtr pixmap,
@@ -298,5 +327,13 @@ sproc_present_dispatch(ClientPtr client);
 /*
  * present_screen.c
  */
+#ifdef PRESENT_WAYLAND
+/*
+ * present_wayland.c
+ */
+void
+present_wayland_execute(present_vblank_ptr vblank);
+
+#endif
 
 #endif /*  _PRESENT_PRIV_H_ */
diff --git a/present/present_wayland.c b/present/present_wayland.c
new file mode 100644
index 0000000..6302b33
--- /dev/null
+++ b/present/present_wayland.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright © 2014 Axel Davy
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of the
+ * copyright holders not be used in advertising or publicity
+ * pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no
+ * representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+ * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#ifdef HAVE_XORG_CONFIG_H
+#include <xorg-config.h>
+#endif
+
+#include "present_priv.h"
+#include <gcstruct.h>
+#include <misync.h>
+#include <misyncstr.h>
+#ifdef MONOTONIC_CLOCK
+#include <time.h>
+#endif
+
+typedef ScrnInfoPtr (void*);
+#include "xwayland.h"
+
+/* in XWayland Rootless model, a child of the screen Window
+ * is shown to the Wayland compositor. We should expect frame
+ * events only from these windows.*/
+static WindowPtr GetTopParent(WindowPtr pWindow)
+{
+    WindowPtr current = pWindow;
+    while(current->parent && current->parent->parent)
+      current = current->parent;
+    return current;
+}
+
+static Bool present_wayland_add_frame_todo(WindowPtr window, todo_func_frame tocall, void *arg)
+{
+    return xwl_add_frame_todo(GetTopParent(window), tocall, arg);
+}
+
+static Bool present_wayland_can_flip(present_vblank_ptr vblank)
+{
+    ScreenPtr screen = vblank->window->drawable.pScreen;
+    WindowPtr window = vblank->window;
+    PixmapPtr pixmap = vblank->pixmap;
+    if (window != GetTopParent(window)
+        || screen->GetWindowPixmap(window) == pixmap
+        || (vblank->valid && !RegionEqual(&window->clipList,vblank->valid))
+        || vblank->x_off || vblank->y_off
+        || window->drawable.width != pixmap->drawable.width
+        || window->drawable.height != pixmap->drawable.height)
+        return FALSE;
+    return TRUE;
+}
+
+static void present_wayland_flip_window(WindowPtr window, PixmapPtr new_pixmap)
+{
+    ScreenPtr screen = window->drawable.pScreen;
+    PixmapPtr old_pixmap = screen->GetWindowPixmap(window);
+
+    new_pixmap->refcnt++;
+    present_set_tree_pixmap(window, new_pixmap);
+    dixDestroyPixmap(old_pixmap, old_pixmap->drawable.id);
+}
+
+static
+void present_wayland_cancel_flip(WindowPtr window)
+{
+    ScreenPtr screen = window->drawable.pScreen;
+    PixmapPtr old_pixmap = screen->GetWindowPixmap(window);
+    PixmapPtr new_pixmap = screen->CreatePixmap(screen, window->drawable.width, window->drawable.height, window->drawable.depth, 0);
+
+    if (!new_pixmap) {
+        ErrorF("Memory Error: cannot allocate pixmap");
+        return;
+    }
+    present_copy_region(&new_pixmap->drawable, old_pixmap, NULL, 0, 0);
+    present_wayland_flip_window(window, new_pixmap);
+}
+
+static void count_msc(int flags, uint32_t time, void *arg)
+{
+    WindowPtr window = arg;
+    present_window_priv_ptr priv = present_window_priv(window);
+    priv->msc++;
+    priv->last_msc_update = time;
+    if (!flags)
+        present_wayland_add_frame_todo(window, count_msc, arg);
+}
+
+static Bool present_wayland_init_for_window(WindowPtr window)
+{
+    present_window_priv_ptr priv = present_window_priv(window);
+    if (priv->msc > 0)
+        return TRUE;
+    else if (present_wayland_add_frame_todo(window, count_msc, window)) {
+        priv->msc = 1;
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static void handle_buffer_release(int flags, void *arg)
+{
+    present_vblank_ptr vblank = arg;
+    present_window_priv_ptr priv;
+
+    if (flags & XWL_TODO_OBJECT_DESTRUCTION)
+        /* not supposed to happen, since the pixmap still has a reference on it
+         * in vblank */
+        return;
+
+    if (flags & XWL_WINDOW_UNREALIZE) {
+        priv = present_window_priv(vblank->window);
+        priv->pixmap_is_flip = FALSE;
+    }
+    else
+        present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
+
+    vblank->flip_released = TRUE;
+    if (vblank->flip_presented || flags & XWL_WINDOW_UNREALIZE)
+        present_vblank_destroy(vblank);
+}
+
+static void handle_presented(int flags, uint32_t time, void *arg)
+{
+    present_vblank_ptr vblank = arg;
+    present_window_priv_ptr priv;
+    uint64_t msc;
+
+    if (flags)
+        /* freeing vblank is handled elsewhere */
+        return;
+
+    priv = present_window_priv(vblank->window);
+    msc = priv->last_msc_update >= time ? priv->msc : priv->msc+1;
+    present_vblank_notify(vblank, vblank->kind, PresentCompleteModeFlip, GetTimeInMicros(), msc);
+    vblank->flip_presented = TRUE;
+    if (vblank->flip_released)
+        present_vblank_destroy(vblank);
+}
+
+static void handle_present(int flags, uint32_t time, void *arg)
+{
+    present_vblank_ptr vblank = arg;
+    /* vblank->window can't be null */
+    WindowPtr window = vblank->window;
+    present_window_priv_ptr priv = present_window_priv(window);
+    uint64_t msc = priv->last_msc_update >= time ? priv->msc : priv->msc+1;
+    RegionPtr damage;
+
+    if (flags) {
+        present_vblank_destroy(vblank);
+        return;
+    }
+    if (vblank->target_msc > msc+1) {
+        (void) present_wayland_add_frame_todo(window, handle_present, arg);
+        return;
+    }
+    if (!vblank->pixmap) {
+        if (vblank->target_msc == msc+1) {
+            (void) present_wayland_add_frame_todo(window, handle_present, arg);
+            return;
+        } else {
+            vblank->queued = FALSE;
+            if (vblank->kind == PresentCompleteKindPixmap)
+                present_vblank_notify(vblank, vblank->kind, PresentCompleteModeSkip, GetTimeInMicros(), msc);
+            else
+                present_vblank_notify(vblank, vblank->kind, PresentCompleteModeCopy, GetTimeInMicros(), msc);
+            present_vblank_destroy(vblank);
+            return;
+        }
+    }
+    if (vblank->target_msc <= msc) {
+        if (priv->pixmap_is_flip) {
+            present_wayland_cancel_flip(window);
+            priv->pixmap_is_flip = FALSE;
+        }
+        present_copy_region(&window->drawable, vblank->pixmap, vblank->update, vblank->x_off, vblank->y_off);
+        vblank->queued = FALSE;
+        vblank->update = NULL;
+        present_pixmap_idle(vblank->pixmap, vblank->window, vblank->serial, vblank->idle_fence);
+        present_vblank_notify(vblank, vblank->kind, PresentCompleteModeCopy, GetTimeInMicros(), msc);
+        present_vblank_destroy(vblank);
+        return;
+    }
+    if (vblank->flip_allowed && present_wayland_can_flip(vblank)) {
+        present_wayland_flip_window(window, vblank->pixmap);
+        priv->pixmap_is_flip = TRUE;
+        if (vblank->update) {
+            damage = vblank->update;
+            RegionIntersect(damage, damage, &window->clipList);
+        } else
+            damage = &window->clipList;
+        DamageDamageRegion(&window->drawable, damage);
+        vblank->queued = FALSE;
+        vblank->flip_presented = FALSE;
+        vblank->flip_released = FALSE;
+        present_wayland_add_frame_todo(window, handle_presented, arg);
+        xwl_add_buffer_release_todo(window, handle_buffer_release, arg);
+    } else
+        (void) present_wayland_add_frame_todo(window, handle_present, arg);
+}
+
+static void
+present_wayland_wait_fence_triggered(void *param)
+{
+    present_vblank_ptr vblank = param;
+    handle_present(0, 0, vblank);
+}
+
+void present_wayland_execute(present_vblank_ptr vblank)
+{
+    if (!present_wayland_init_for_window(vblank->window)) {
+        /* The window has not yet been made visible on the screen.
+         * Execute the Present operation right away */
+        vblank->flip_allowed = FALSE;
+        vblank->target_msc = 0;
+    }
+    if (vblank->wait_fence && !present_fence_check_triggered(vblank->wait_fence))
+        present_fence_set_callback(vblank->wait_fence, present_wayland_wait_fence_triggered, vblank);
+    else
+        handle_present(0, 0, vblank);
+}
\ No newline at end of file
-- 
1.8.3.2



More information about the wayland-devel mailing list