[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