[PATCH 4/6] present: Create an internal server API to perform operations at vblank time

Keith Packard keithp at keithp.com
Wed Aug 6 22:21:05 PDT 2014


present_vblank_window_queue asks for a callback function to be invoked
when a specific (absolute or relative) frame starts. This allows for
vblank-synchronized rendering operations without needing
driver-specific hooks.

Signed-off-by: Keith Packard <keithp at keithp.com>
---
 present/Makefile.am      |   5 +-
 present/present.c        |  14 ++--
 present/present_priv.h   |  27 +++++++
 present/present_screen.c |   2 +
 present/present_vblank.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++
 present/present_vblank.h |  68 +++++++++++++++++
 6 files changed, 300 insertions(+), 8 deletions(-)
 create mode 100644 present/present_vblank.c
 create mode 100644 present/present_vblank.h

diff --git a/present/Makefile.am b/present/Makefile.am
index 7fea669..64c8be4 100644
--- a/present/Makefile.am
+++ b/present/Makefile.am
@@ -12,6 +12,7 @@ libpresent_la_SOURCES = \
 	present_notify.c \
 	present_priv.h \
 	present_request.c \
-	present_screen.c
+	present_screen.c \
+	present_vblank.c
 
-sdk_HEADERS = present.h presentext.h
+sdk_HEADERS = present.h presentext.h present_vblank.h
diff --git a/present/present.c b/present/present.c
index af98ef7..744cb99 100644
--- a/present/present.c
+++ b/present/present.c
@@ -32,7 +32,7 @@
 #include <time.h>
 #endif
 
-static uint64_t         present_event_id;
+uint64_t                present_event_id;
 static struct xorg_list present_exec_queue;
 static struct xorg_list present_flip_queue;
 
@@ -85,7 +85,7 @@ present_flip_pending_pixmap(ScreenPtr screen)
 
     if (!screen_priv->flip_pending)
         return NULL;
-        
+
     return screen_priv->flip_pending->pixmap;
 }
 
@@ -235,7 +235,7 @@ present_query_capabilities(RRCrtcPtr crtc)
     return screen_priv->info->capabilities;
 }
 
-static int
+int
 present_get_ust_msc(ScreenPtr screen, RRCrtcPtr crtc, uint64_t *ust, uint64_t *msc)
 {
     present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
@@ -261,7 +261,7 @@ present_flush(WindowPtr window)
     (*screen_priv->info->flush) (window);
 }
 
-static int
+int
 present_queue_vblank(ScreenPtr screen,
                      RRCrtcPtr crtc,
                      uint64_t event_id,
@@ -279,7 +279,7 @@ present_queue_vblank(ScreenPtr screen,
     return ret;
 }
 
-static uint64_t
+uint64_t
 present_window_to_crtc_msc(WindowPtr window, RRCrtcPtr crtc, uint64_t window_msc, uint64_t new_msc)
 {
     present_window_priv_ptr     window_priv = present_get_window_priv(window, TRUE);
@@ -368,7 +368,7 @@ present_set_tree_pixmap_visit(WindowPtr window, void *data)
     (*screen->SetWindowPixmap)(window, visit->new);
     return WT_WALKCHILDREN;
 }
-    
+
 static void
 present_set_tree_pixmap(WindowPtr window, PixmapPtr pixmap)
 {
@@ -499,6 +499,8 @@ present_event_notify(uint64_t event_id, uint64_t ust, uint64_t msc)
             return;
         }
     }
+
+    present_vblank_event_notify(event_id, ust, msc);
 }
 
 void
diff --git a/present/present_priv.h b/present/present_priv.h
index 1542726..a409e97 100644
--- a/present/present_priv.h
+++ b/present/present_priv.h
@@ -37,6 +37,8 @@
 
 extern int present_request;
 
+extern uint64_t         present_event_id;
+
 extern DevPrivateKeyRec present_screen_private_key;
 
 typedef struct present_fence *present_fence_ptr;
@@ -158,6 +160,18 @@ extern RESTYPE present_event_type;
 /*
  * present.c
  */
+uint64_t
+present_window_to_crtc_msc(WindowPtr window, RRCrtcPtr crtc, uint64_t window_msc, uint64_t new_msc);
+
+int
+present_get_ust_msc(ScreenPtr screen, RRCrtcPtr crtc, uint64_t *ust, uint64_t *msc);
+
+int
+present_queue_vblank(ScreenPtr screen,
+                     RRCrtcPtr crtc,
+                     uint64_t event_id,
+                     uint64_t msc);
+
 int
 present_pixmap(WindowPtr window,
                PixmapPtr pixmap,
@@ -308,4 +322,17 @@ sproc_present_dispatch(ClientPtr client);
  * present_screen.c
  */
 
+/*
+ * present_vblank.c
+ */
+
+void
+present_vblank_event_notify(uint64_t event_id, uint64_t msc, uint64_t utc);
+
+void
+present_vblank_screen_init(ScreenPtr screen);
+
+void
+present_vblank_screen_close(ScreenPtr screen);
+
 #endif /*  _PRESENT_PRIV_H_ */
diff --git a/present/present_screen.c b/present/present_screen.c
index 2f91ac7..bfffae9 100644
--- a/present/present_screen.c
+++ b/present/present_screen.c
@@ -195,6 +195,8 @@ present_screen_init(ScreenPtr screen, present_screen_info_ptr info)
         present_fake_screen_init(screen);
     }
 
+    present_vblank_screen_init(screen);
+
     return TRUE;
 }
 
diff --git a/present/present_vblank.c b/present/present_vblank.c
new file mode 100644
index 0000000..deebade
--- /dev/null
+++ b/present/present_vblank.c
@@ -0,0 +1,192 @@
+/*
+ * Copyright © 2014 Keith Packard
+ *
+ * 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 "present_vblank.h"
+
+typedef struct {
+    struct xorg_list                    list;
+    uint64_t                            event_id;
+    WindowPtr                           window;
+    uint64_t                            msc_offset;
+    present_vblank_window_callback      callback;
+    uint32_t                            flags;
+    void                                *closure;
+} present_queue_t;
+
+static struct xorg_list present_queue;
+
+int
+present_vblank_window_get(WindowPtr     window,
+                          RRCrtcPtr     *crtc,
+                          uint64_t      *ust,
+                          uint64_t      *window_msc)
+{
+    ScreenPtr                   screen = window->drawable.pScreen;
+    present_window_priv_ptr     window_priv = present_get_window_priv(window, TRUE);
+    present_screen_priv_ptr     screen_priv = present_screen_priv(screen);
+    uint64_t                    msc_offset, crtc_msc;
+    RRCrtcPtr                   target_crtc;
+
+    if (!window_priv)
+        return BadAlloc;
+
+    if (!screen_priv || !screen_priv->info)
+        target_crtc = NULL;
+    else {
+        target_crtc = window_priv->crtc;
+
+        if (!target_crtc || target_crtc == PresentCrtcNeverSet)
+            target_crtc = present_get_crtc(window);
+    }
+
+    present_get_ust_msc(screen, target_crtc, ust, &crtc_msc);
+
+    msc_offset = present_window_to_crtc_msc(window, target_crtc, 0, crtc_msc);
+
+    *window_msc = crtc_msc - msc_offset;
+    *crtc = window_priv->crtc;
+
+    return Success;
+}
+
+uint64_t
+present_vblank_window_queue(WindowPtr                           window,
+                            enum present_whence                 whence,
+                            uint64_t                            window_msc,
+                            uint32_t                            flags,
+                            present_vblank_window_callback      callback,
+                            void                                *closure)
+{
+    present_window_priv_ptr     window_priv = present_get_window_priv(window, TRUE);
+    present_queue_t             *q;
+    RRCrtcPtr                   current_crtc;
+    uint64_t                    current_ust, current_msc;
+    uint64_t                    event_id;
+
+    if (!window_priv)
+        return PRESENT_VBLANK_QUEUE_FAILED;
+
+    if (present_vblank_window_get(window, &current_crtc, &current_ust, &current_msc) != Success)
+        return PRESENT_VBLANK_QUEUE_FAILED;
+
+    q = calloc(1, sizeof (present_queue_t));
+    if (!q)
+        return PRESENT_VBLANK_QUEUE_FAILED;
+
+    event_id = ++present_event_id;
+
+    q->window = window;
+    q->callback = callback;
+    q->msc_offset = window_priv->msc_offset;
+
+    if (whence == present_whence_relative)
+        window_msc += current_msc;
+
+    q->flags = flags;
+    q->closure = closure;
+
+    q->event_id = event_id;
+    xorg_list_add(&q->list, &present_queue);
+
+    if ((int64_t) (window_msc - current_msc) <= 0) {
+        DebugPresent(("ve %lld %p %8lld (request %8lld)\n",
+                      (long long) event_id, q,
+                      (long long) current_msc,
+                      (long long) window_msc));
+        present_vblank_event_notify(event_id, current_ust, current_msc + q->msc_offset);
+        event_id = PRESENT_VBLANK_QUEUE_EXECUTED;
+    } else {
+        DebugPresent(("vq %lld %p %8lld (request %8lld)\n",
+                      (long long) event_id, q,
+                      (long long) current_msc, (long long) q->msc));
+        present_queue_vblank(window->drawable.pScreen,
+                             current_crtc,
+                             q->event_id,
+                             window_msc + q->msc_offset);
+    }
+
+    return event_id;
+}
+
+Bool
+present_vblank_cancel(ScreenPtr screen, uint64_t event_id)
+{
+    present_queue_t     *q, *tmp;
+
+    xorg_list_for_each_entry_safe(q, tmp, &present_queue, list) {
+        if (q->event_id == event_id) {
+            xorg_list_del(&q->list);
+            /* could call the driver to cancel the event */
+            free(q);
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+static void
+present_queue_notify(present_queue_t *q, uint64_t ust, uint64_t crtc_msc)
+{
+    xorg_list_del(&q->list);
+    (*q->callback)(q->window, q->closure, ust, crtc_msc - q->msc_offset);
+    free(q);
+}
+
+static void
+present_queue_abort(present_queue_t *q)
+{
+    present_queue_notify(q, 0, q->msc_offset);
+}
+
+void
+present_vblank_event_notify(uint64_t event_id, uint64_t ust, uint64_t crtc_msc)
+{
+    present_queue_t     *q, *tmp;
+
+    xorg_list_for_each_entry_safe(q, tmp, &present_queue, list) {
+        if (q->event_id == event_id) {
+            DebugPresent(("\tvn %8lld %p %8lld\n",
+                          (long long) q->event_id, q, (long long) msc));
+            present_queue_notify(q, ust, crtc_msc);
+        }
+    }
+}
+
+void
+present_vblank_screen_init(ScreenPtr screen)
+{
+    xorg_list_init(&present_queue);
+}
+
+void
+present_vblank_screen_close(ScreenPtr screen)
+{
+    present_queue_t     *q, *tmp;
+
+    xorg_list_for_each_entry_safe(q, tmp, &present_queue, list)
+        present_queue_abort(q);
+}
diff --git a/present/present_vblank.h b/present/present_vblank.h
new file mode 100644
index 0000000..4479014
--- /dev/null
+++ b/present/present_vblank.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright © 2014 Keith Packard
+ *
+ * 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.
+ */
+
+#ifndef _PRESENT_VBLANK_H_
+#define _PRESENT_VBLANK_H_
+
+#include <X11/X.h>
+#include "scrnintstr.h"
+#include "misc.h"
+#include "list.h"
+#include "windowstr.h"
+#include "dixstruct.h"
+#include "present.h"
+#include <syncsdk.h>
+#include <syncsrv.h>
+#include <xfixes.h>
+#include <randrstr.h>
+
+enum present_whence {
+    present_whence_absolute,
+    present_whence_relative
+};
+
+typedef void (*present_vblank_window_callback) (WindowPtr       window,
+                                                void            *closure,
+                                                uint64_t        ust,
+                                                uint64_t        msc);
+
+extern _X_EXPORT int
+present_vblank_window_get(WindowPtr     window,
+                          RRCrtcPtr     *crtc,
+                          uint64_t      *ust,
+                          uint64_t      *msc);
+
+#define PRESENT_VBLANK_QUEUE_FAILED     ((uint64_t) 0)
+#define PRESENT_VBLANK_QUEUE_EXECUTED   ((uint64_t) -1)
+
+extern _X_EXPORT uint64_t
+present_vblank_window_queue(WindowPtr                           window,
+                            enum present_whence                 whence,
+                            uint64_t                            msc,
+                            uint32_t                            flags,
+                            present_vblank_window_callback      callback,
+                            void                                *closure);
+
+extern _X_EXPORT Bool
+present_vblank_cancel(ScreenPtr screen, uint64_t id);
+
+#endif /* _PRESENT_VBLANK_H_ */
-- 
2.0.1



More information about the xorg-devel mailing list