[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, ¤t_crtc, ¤t_ust, ¤t_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