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 <kei...@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 _______________________________________________ xorg-devel@lists.x.org: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel