From patchwork Thu Oct 31 23:13:16 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Keith Packard X-Patchwork-Id: 3122641 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id AF56F9F3E3 for ; Thu, 31 Oct 2013 23:26:09 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id C3544201B7 for ; Thu, 31 Oct 2013 23:31:52 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id E8530202F0 for ; Thu, 31 Oct 2013 23:31:50 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 1BCF8F0036 for ; Thu, 31 Oct 2013 16:31:50 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from lists.sourceforge.net (lists.sourceforge.net [216.34.181.88]) by gabe.freedesktop.org (Postfix) with ESMTP id 4940EEE6B8; Thu, 31 Oct 2013 16:31:18 -0700 (PDT) Received: from localhost ([127.0.0.1] helo=sfs-ml-4.v29.ch3.sourceforge.com) by sfs-ml-4.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1Vc1hl-0003SP-4c; Thu, 31 Oct 2013 23:31:09 +0000 Received: from sog-mx-4.v43.ch3.sourceforge.com ([172.29.43.194] helo=mx.sourceforge.net) by sfs-ml-4.v29.ch3.sourceforge.com with esmtp (Exim 4.76) (envelope-from ) id 1Vc1hj-0003SG-ET; Thu, 31 Oct 2013 23:31:07 +0000 X-ACL-Warn: Received: from home.keithp.com ([63.227.221.253] helo=keithp.com) by sog-mx-4.v43.ch3.sourceforge.com with esmtp (Exim 4.76) id 1Vc1hg-0002zr-5J; Thu, 31 Oct 2013 23:31:07 +0000 Received: from localhost (localhost [127.0.0.1]) by keithp.com (Postfix) with ESMTP id 875DE1584009; Thu, 31 Oct 2013 16:13:40 -0700 (PDT) X-Virus-Scanned: Debian amavisd-new at keithp.com Received: from keithp.com ([127.0.0.1]) by localhost (keithp.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id MKxNyRhVFQqT; Thu, 31 Oct 2013 16:13:31 -0700 (PDT) Received: by keithp.com (Postfix, from userid 1033) id 414BF158400B; Thu, 31 Oct 2013 16:13:18 -0700 (PDT) Received: from miki.keithp.com (localhost [127.0.0.1]) by keithp.com (Postfix) with ESMTP id 9CF1814A8035; Thu, 31 Oct 2013 16:13:18 -0700 (PDT) Received: by miki.keithp.com (Postfix, from userid 1001) id 84DF6DBA; Thu, 31 Oct 2013 16:13:17 -0700 (PDT) From: Keith Packard To: mesa3d-dev@lists.sourceforge.net Subject: [PATCH 6/6] Make GLX/dri3 use the Present extension when available Date: Thu, 31 Oct 2013 16:13:16 -0700 Message-Id: <1383261196-25093-7-git-send-email-keithp@keithp.com> X-Mailer: git-send-email 1.8.4.2 In-Reply-To: <1383261196-25093-1-git-send-email-keithp@keithp.com> References: <1383261196-25093-1-git-send-email-keithp@keithp.com> X-Spam-Score: -0.5 (/) X-Headers-End: 1Vc1hg-0002zr-5J X-BeenThere: dri-devel@lists.sourceforge.net X-Mailman-Version: 2.1.9 Precedence: list MIME-Version: 1.0 Cc: dri-devel@lists.sourceforge.net X-BeenThere: dri-devel@lists.freedesktop.org List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org Errors-To: dri-devel-bounces+patchwork-dri-devel=patchwork.kernel.org@lists.freedesktop.org X-Spam-Status: No, score=-4.7 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP This uses the Present extension with DRI3, which includes OML_Sync extension support. Signed-off-by: Keith Packard --- configure.ac | 4 +- include/GL/internal/dri_interface.h | 1 + src/glx/dri3_glx.c | 421 ++++++++++++++++++++++-------------- src/glx/dri3_priv.h | 50 ++++- 4 files changed, 313 insertions(+), 163 deletions(-) diff --git a/configure.ac b/configure.ac index b6158d9..c91f031 100644 --- a/configure.ac +++ b/configure.ac @@ -39,6 +39,7 @@ LIBDRM_NOUVEAU_REQUIRED="2.4.33 libdrm >= 2.4.41" LIBDRM_FREEDRENO_REQUIRED=2.4.39 DRI2PROTO_REQUIRED=2.6 DRI3PROTO_REQUIRED=1.0 +PRESENTPROTO_REQUIRED=1.0 LIBUDEV_REQUIRED=151 GLPROTO_REQUIRED=1.4.14 LIBDRM_XORG_REQUIRED=2.4.24 @@ -823,11 +824,12 @@ xyesno) PKG_CHECK_MODULES([DRI2PROTO], [dri2proto >= $DRI2PROTO_REQUIRED]) GL_PC_REQ_PRIV="$GL_PC_REQ_PRIV libdrm >= $LIBDRM_REQUIRED" PKG_CHECK_MODULES([DRI3PROTO], [dri3proto >= $DRI3PROTO_REQUIRED]) + PKG_CHECK_MODULES([PRESENTPROTO], [presentproto >= $PRESENTPROTO_REQUIRED]) PKG_CHECK_MODULES([LIBUDEV], [libudev >= $LIBUDEV_REQUIRED]) fi # find the DRI deps for libGL - dri_modules="x11 xext xdamage xfixes x11-xcb xcb-glx >= 1.8.1 xcb-dri2 >= 1.8 xcb-dri3 xcb-sync xshmfence" + dri_modules="x11 xext xdamage xfixes x11-xcb xcb-glx >= 1.8.1 xcb-dri2 >= 1.8 xcb-dri3 xcb-present xcb-sync xshmfence" # add xf86vidmode if available PKG_CHECK_MODULES([XF86VIDMODE], [xxf86vm], HAVE_XF86VIDMODE=yes, HAVE_XF86VIDMODE=no) diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h index b06ad8d..b508a18 100644 --- a/include/GL/internal/dri_interface.h +++ b/include/GL/internal/dri_interface.h @@ -991,6 +991,7 @@ struct __DRIdri3BufferRec { uint32_t pixmap; uint32_t sync_fence; int32_t *shm_fence; + GLboolean busy; void *driverPrivate; }; diff --git a/src/glx/dri3_glx.c b/src/glx/dri3_glx.c index 4d275f2..6db984a 100644 --- a/src/glx/dri3_glx.c +++ b/src/glx/dri3_glx.c @@ -74,39 +74,24 @@ #include #include #include + #include "xf86drm.h" #include "dri_common.h" #include "dri3_priv.h" static const struct glx_context_vtable dri3_context_vtable; -#define HAS_SBC 0 - -#if HAS_SBC - -/* For XCB's handling of ust/msc/sbc counters, we have to hand it the high and - * low halves separately. This helps you split them. - */ -static void -split_counter(uint64_t counter, uint32_t *hi, uint32_t *lo) -{ - *hi = (counter >> 32); - *lo = counter & 0xffffffff; -} - -static uint64_t -merge_counter(uint32_t hi, uint32_t lo) -{ - return ((uint64_t)hi << 32) | lo; -} -#endif /* HAS_SBC */ - static inline void dri3_fence_reset(xcb_connection_t *c, __DRIdri3Buffer *buffer) { xshmfence_reset(buffer->shm_fence); } static inline void +dri3_fence_set(__DRIdri3Buffer *buffer) { + xshmfence_trigger(buffer->shm_fence); +} + +static inline void dri3_fence_trigger(xcb_connection_t *c, __DRIdri3Buffer *buffer) { xcb_sync_trigger_fence(c, buffer->sync_fence); } @@ -117,6 +102,11 @@ dri3_fence_await(xcb_connection_t *c, __DRIdri3Buffer *buffer) { xshmfence_await(buffer->shm_fence); } +static inline Bool +dri3_fence_triggered(__DRIdri3Buffer *buffer) { + return xshmfence_query(buffer->shm_fence); +} + static void dri3_destroy_context(struct glx_context *context) { @@ -375,27 +365,44 @@ dri3_create_drawable(struct glx_screen *base, XID xDrawable, return &pdraw->base; } -#if HAS_SBC -static int -dri3_drawable_get_msc(struct glx_screen *psc, __GLXDRIdrawable *pdraw, - int64_t *ust, int64_t *msc, int64_t *sbc) +static void +present_handle_special_event(struct dri3_drawable *priv, xcb_present_generic_event_t *ge) { - xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy); - xcb_dri2_get_msc_cookie_t get_msc_cookie; - xcb_dri2_get_msc_reply_t *get_msc_reply; + switch (ge->evtype) { + case XCB_PRESENT_CONFIGURE_NOTIFY: { + xcb_present_configure_notify_event_t *ce = (void *) ge; - get_msc_cookie = xcb_dri2_get_msc_unchecked(c, pdraw->xDrawable); - get_msc_reply = xcb_dri2_get_msc_reply(c, get_msc_cookie, NULL); + priv->width = ce->width; + priv->height = ce->height; + break; + } + case XCB_PRESENT_COMPLETE_NOTIFY: { + xcb_present_complete_notify_event_t *ce = (void *) ge; - if (!get_msc_reply) - return 0; + if (ce->kind == XCB_PRESENT_COMPLETE_KIND_PIXMAP) + priv->present_event_serial = ce->serial; + else + priv->present_msc_event_serial = ce->serial; + priv->ust = ce->ust; + priv->msc = ce->msc; + break; + } + case XCB_PRESENT_EVENT_IDLE_NOTIFY: { + xcb_present_idle_notify_event_t *ie = (void *) ge; + int b; - *ust = merge_counter(get_msc_reply->ust_hi, get_msc_reply->ust_lo); - *msc = merge_counter(get_msc_reply->msc_hi, get_msc_reply->msc_lo); - *sbc = merge_counter(get_msc_reply->sbc_hi, get_msc_reply->sbc_lo); - free(get_msc_reply); + for (b = 0; b < sizeof (priv->buffers) / sizeof (priv->buffers[0]); b++) { + __DRIdri3Buffer *buf = priv->buffers[b]; - return 1; + if (buf && buf->pixmap == ie->pixmap) { + buf->busy = 0; + break; + } + } + break; + } + } + free(ge); } static int @@ -403,59 +410,58 @@ dri3_wait_for_msc(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, int64_t remainder, int64_t *ust, int64_t *msc, int64_t *sbc) { xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy); - xcb_dri2_wait_msc_cookie_t wait_msc_cookie; - xcb_dri2_wait_msc_reply_t *wait_msc_reply; - uint32_t target_msc_hi, target_msc_lo; - uint32_t divisor_hi, divisor_lo; - uint32_t remainder_hi, remainder_lo; - - split_counter(target_msc, &target_msc_hi, &target_msc_lo); - split_counter(divisor, &divisor_hi, &divisor_lo); - split_counter(remainder, &remainder_hi, &remainder_lo); - - wait_msc_cookie = xcb_dri2_wait_msc_unchecked(c, pdraw->xDrawable, - target_msc_hi, target_msc_lo, - divisor_hi, divisor_lo, - remainder_hi, remainder_lo); - wait_msc_reply = xcb_dri2_wait_msc_reply(c, wait_msc_cookie, NULL); - - if (!wait_msc_reply) - return 0; + struct dri3_drawable *priv = (struct dri3_drawable *) pdraw; + xcb_generic_event_t *ev; + xcb_present_generic_event_t *ge; + + /* Ask for the an event for the target MSC */ + ++priv->present_msc_request_serial; + xcb_present_notify_msc(c, + priv->base.xDrawable, + priv->present_msc_request_serial, + target_msc, + divisor, + remainder); - *ust = merge_counter(wait_msc_reply->ust_hi, wait_msc_reply->ust_lo); - *msc = merge_counter(wait_msc_reply->msc_hi, wait_msc_reply->msc_lo); - *sbc = merge_counter(wait_msc_reply->sbc_hi, wait_msc_reply->sbc_lo); - free(wait_msc_reply); + xcb_flush(c); + + /* Wait for the event */ + if (priv->special_event) { + while (priv->present_msc_request_serial != priv->present_msc_event_serial) { + ev = xcb_wait_for_special_event(c, priv->special_event); + if (!ev) + break; + ge = (void *) ev; + present_handle_special_event(priv, ge); + } + } + + *ust = priv->ust; + *msc = priv->msc; + + *sbc = priv->sbc; return 1; } static int +dri3_drawable_get_msc(struct glx_screen *psc, __GLXDRIdrawable *pdraw, + int64_t *ust, int64_t *msc, int64_t *sbc) +{ + return dri3_wait_for_msc(pdraw, 0, 0, 0, ust, msc,sbc); +} + +static int dri3_wait_for_sbc(__GLXDRIdrawable *pdraw, int64_t target_sbc, int64_t *ust, int64_t *msc, int64_t *sbc) { - xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy); - xcb_dri2_wait_sbc_cookie_t wait_sbc_cookie; - xcb_dri2_wait_sbc_reply_t *wait_sbc_reply; - uint32_t target_sbc_hi, target_sbc_lo; - - split_counter(target_sbc, &target_sbc_hi, &target_sbc_lo); - - wait_sbc_cookie = xcb_dri2_wait_sbc_unchecked(c, pdraw->xDrawable, - target_sbc_hi, target_sbc_lo); - wait_sbc_reply = xcb_dri2_wait_sbc_reply(c, wait_sbc_cookie, NULL); - - if (!wait_sbc_reply) - return 0; - - *ust = merge_counter(wait_sbc_reply->ust_hi, wait_sbc_reply->ust_lo); - *msc = merge_counter(wait_sbc_reply->msc_hi, wait_sbc_reply->msc_lo); - *sbc = merge_counter(wait_sbc_reply->sbc_hi, wait_sbc_reply->sbc_lo); - free(wait_sbc_reply); + struct dri3_drawable *priv = (struct dri3_drawable *) pdraw; - return 1; + while (priv->sbc < target_sbc) { + sleep(1); + } + return dri3_wait_for_msc(pdraw, 0, 0, 0, ust, msc, sbc); } -#endif /* HAS_SBC */ static __DRIcontext * dri3_get_current_context(void) @@ -531,13 +537,13 @@ dri3_drawable_gc(struct dri3_drawable *priv) static __DRIdri3Buffer * dri3_back_buffer(struct dri3_drawable *priv) { - return priv->buffers[__DRI3_BUFFER_BACK]; + return priv->buffers[DRI3_BACK_ID(priv->cur_back)]; } static __DRIdri3Buffer * dri3_fake_front_buffer(struct dri3_drawable *priv) { - return priv->buffers[__DRI3_BUFFER_FRONT]; + return priv->buffers[DRI3_FRONT_ID]; } static void @@ -739,6 +745,10 @@ dri3_alloc_render_buffer(struct glx_screen *glx_screen, Drawable draw, unsigned buffer->shm_fence = shm_fence; buffer->width = width; buffer->height = height; + + /* Mark the buffer as idle */ + dri3_fence_set(buffer); + return buffer; no_buffer_fd: @@ -762,6 +772,26 @@ dri3_free_render_buffer(struct dri3_drawable *pdraw, __DRIdri3Buffer *buffer) (*psc->dri3->releaseBuffer)(psc->driScreen, buffer); } + + +static void +present_flush_events(struct dri3_drawable *priv) +{ + xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy); + + /* Check to see if any configuration changes have occurred + * since we were last invoked + */ + if (priv->special_event) { + xcb_generic_event_t *ev; + + while ((ev = xcb_check_for_special_event(c, priv->special_event)) != NULL) { + xcb_present_generic_event_t *ge = (void *) ev; + present_handle_special_event(priv, ge); + } + } +} + static int dri3_update_drawable(__DRIdrawable *driDrawable, void *loaderPrivate) { @@ -781,6 +811,7 @@ dri3_update_drawable(__DRIdrawable *driDrawable, void *loaderPrivate) (priv->eid = xcb_generate_id(c)), priv->base.xDrawable, XCB_PRESENT_EVENT_MASK_CONFIGURE_NOTIFY| + XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY| XCB_PRESENT_EVENT_MASK_IDLE_NOTIFY); if (!priv->present_extension) { @@ -821,30 +852,7 @@ dri3_update_drawable(__DRIdrawable *driDrawable, void *loaderPrivate) priv->special_event = NULL; } } - - /* Check to see if any configuration changes have occurred - * since we were last invoked - */ - if (priv->special_event) { - xcb_generic_event_t *ev; - - while ((ev = xcb_check_for_special_event(c, priv->special_event)) != NULL) { - xcb_present_generic_event_t *pe = (void *) ev; - - switch (pe->evtype) { - case XCB_PRESENT_EVENT_CONFIGURE_NOTIFY: { - xcb_configure_notify_event_t *ce = (void *) ev; - - priv->width = ce->width; - priv->height = ce->height; - break; - } - case XCB_PRESENT_EVENT_IDLE_NOTIFY: - break; - } - free(ev); - } - } + present_flush_events(priv); return true; } @@ -855,7 +863,8 @@ dri3_get_pixmap_buffer(__DRIdrawable *driDrawable, void *loaderPrivate) { struct dri3_drawable *pdraw = loaderPrivate; - __DRIdri3Buffer *buffer = pdraw->buffers[buffer_type]; + int buf_id = buffer_type == dri3_pixmap_buf_id(buffer_type); + __DRIdri3Buffer *buffer = pdraw->buffers[buf_id]; Pixmap pixmap; xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie; xcb_dri3_buffer_from_pixmap_reply_t *bp_reply; @@ -915,7 +924,7 @@ dri3_get_pixmap_buffer(__DRIdrawable *driDrawable, buffer->shm_fence = shm_fence; buffer->sync_fence = sync_fence; - pdraw->buffers[buffer_type] = buffer; + pdraw->buffers[buf_id] = buffer; return buffer; no_pixmap: @@ -924,6 +933,32 @@ no_pixmap: return NULL; } +static int +dri3_find_back(xcb_connection_t *c, struct dri3_drawable *priv) +{ + int b; + xcb_generic_event_t *ev; + xcb_present_generic_event_t *ge; + + for (;;) { + + for (b = 0; b < DRI3_MAX_BACK; b++) { + int id = DRI3_BACK_ID(b); + __DRIdri3Buffer *buffer = priv->buffers[id]; + + if (!buffer) + return b; + if (!buffer->busy) + return b; + } + ev = xcb_wait_for_special_event(c, priv->special_event); + if (!ev) + return -1; + ge = (void *) ev; + present_handle_special_event(priv, ge); + } +} + static __DRIdri3Buffer * dri3_get_buffer(__DRIdrawable *driDrawable, unsigned int format, @@ -931,10 +966,24 @@ dri3_get_buffer(__DRIdrawable *driDrawable, void *loaderPrivate) { struct dri3_drawable *priv = loaderPrivate; - __DRIdri3Buffer *buffer = priv->buffers[buffer_type]; + xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy); + __DRIdri3Buffer *buffer; + int buf_id; + + if (buffer_type == __DRI3_BUFFER_BACK) { + int back = dri3_find_back(c, priv); + + if (back < 0) + return NULL; + priv->cur_back = back; + buf_id = DRI3_BACK_ID(priv->cur_back); + } else { + buf_id = DRI3_FRONT_ID; + } + + buffer = priv->buffers[buf_id]; if (!buffer || buffer->width != priv->width || buffer->height != priv->height) { - xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy); __DRIdri3Buffer *new_buffer; /* Allocate the new buffers @@ -956,7 +1005,6 @@ dri3_get_buffer(__DRIdrawable *driDrawable, 0, 0, 0, 0, priv->width, priv->height); dri3_fence_trigger(c, new_buffer); dri3_free_render_buffer(priv, buffer); - dri3_fence_await(c, new_buffer); } break; case __DRI3_BUFFER_FRONT: @@ -967,29 +1015,45 @@ dri3_get_buffer(__DRIdrawable *driDrawable, dri3_drawable_gc(priv), 0, 0, 0, 0, priv->width, priv->height); dri3_fence_trigger(c, new_buffer); - dri3_fence_await(c, new_buffer); break; } buffer = new_buffer; buffer->buffer_type = buffer_type; - priv->buffers[buffer_type] = buffer; - } + priv->buffers[buf_id] = buffer; + } + dri3_fence_await(c, buffer); /* Return the requested buffer */ return buffer; } static void -dri3_free_buffer(__DRIdrawable *driDrawable, +dri3_free_buffers(__DRIdrawable *driDrawable, enum __DRI3bufferType buffer_type, void *loaderPrivate) { struct dri3_drawable *priv = loaderPrivate; - __DRIdri3Buffer *buffer = priv->buffers[buffer_type]; + __DRIdri3Buffer *buffer; + int first_id; + int n_id; + int buf_id; + + switch (buffer_type) { + case __DRI3_BUFFER_BACK: + first_id = DRI3_BACK_ID(0); + n_id = DRI3_MAX_BACK; + break; + case __DRI3_BUFFER_FRONT: + first_id = DRI3_FRONT_ID; + n_id = 1; + } - if (buffer) { - dri3_free_render_buffer(priv, buffer); - priv->buffers[buffer_type] = NULL; + for (buf_id = first_id; buf_id < first_id + n_id; buf_id++) { + buffer = priv->buffers[buf_id]; + if (buffer) { + dri3_free_render_buffer(priv, buffer); + priv->buffers[buf_id] = NULL; + } } } @@ -1030,7 +1094,7 @@ dri3_get_buffers(__DRIdrawable *driDrawable, return false; priv->have_fake_front = !priv->is_pixmap; } else { - dri3_free_buffer(driDrawable, __DRI3_BUFFER_FRONT, loaderPrivate); + dri3_free_buffers(driDrawable, __DRI3_BUFFER_FRONT, loaderPrivate); priv->have_fake_front = 0; } @@ -1043,7 +1107,7 @@ dri3_get_buffers(__DRIdrawable *driDrawable, return false; priv->have_back = 1; } else { - dri3_free_buffer(driDrawable, __DRI3_BUFFER_BACK, loaderPrivate); + dri3_free_buffers(driDrawable, __DRI3_BUFFER_BACK, loaderPrivate); priv->have_back = 0; } @@ -1059,7 +1123,9 @@ dri3_swap_buffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, { struct dri3_drawable *priv = (struct dri3_drawable *) pdraw; struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc; - xcb_connection_t *c = XGetXCBConnection(priv->base.psc->dpy); + Display *dpy = priv->base.psc->dpy; + xcb_connection_t *c = XGetXCBConnection(dpy); + int buf_id = DRI3_BACK_ID(priv->cur_back); int64_t ret = 0; __DRIcontext *ctx = dri3_get_current_context(); @@ -1068,26 +1134,46 @@ dri3_swap_buffers(__GLXDRIdrawable *pdraw, int64_t target_msc, int64_t divisor, flags |= __DRI2_FLUSH_CONTEXT; dri3_flush(psc, ctx, priv, flags, __DRI2_THROTTLE_SWAPBUFFER); - if (priv->buffers[0] && !priv->is_pixmap) { - dri3_fence_reset(c, priv->buffers[0]); - dri3_copy_area(c, - priv->buffers[0]->pixmap, - priv->base.xDrawable, - dri3_drawable_gc(priv), - 0, 0, 0, 0, priv->width, priv->height); - dri3_fence_trigger(c, priv->buffers[0]); + present_flush_events(priv); + + if (priv->buffers[buf_id] && !priv->is_pixmap) { + dri3_fence_reset(c, priv->buffers[buf_id]); + + /* Compute when we want the frame shown by taking the last known successful + * MSC and adding in a swap interval for each outstanding swap request + */ + ++priv->present_request_serial; + if (target_msc == 0) + target_msc = priv->msc + priv->swap_interval * (priv->present_request_serial - priv->present_event_serial); + + priv->buffers[buf_id]->busy = 1; + xcb_present_pixmap(c, + priv->base.xDrawable, + priv->buffers[buf_id]->pixmap, + priv->present_request_serial, + 0, /* valid */ + 0, /* update */ + 0, /* x_off */ + 0, /* y_off */ + None, /* target_crtc */ + None, + priv->buffers[buf_id]->sync_fence, + XCB_PRESENT_OPTION_NONE, + target_msc, + divisor, + remainder, 0, NULL); + ret = ++priv->sbc; if (priv->have_fake_front) { - dri3_fence_reset(c, priv->buffers[1]); + dri3_fence_reset(c, priv->buffers[DRI3_FRONT_ID]); dri3_copy_area(c, - priv->buffers[0]->pixmap, - priv->buffers[1]->pixmap, + priv->buffers[buf_id]->pixmap, + priv->buffers[DRI3_FRONT_ID]->pixmap, dri3_drawable_gc(priv), 0, 0, 0, 0, priv->width, priv->height); - dri3_fence_trigger(c, priv->buffers[1]); + dri3_fence_trigger(c, priv->buffers[DRI3_FRONT_ID]); } - dri3_fence_await(c, priv->buffers[0]); - if (priv->have_fake_front) - dri3_fence_await(c, priv->buffers[1]); + xcb_flush(c); + ++ (*psc->dri3->stamp(priv->driDrawable)); } return ret; @@ -1118,6 +1204,30 @@ dri3_query_version(Display *dpy, int *major, int *minor) } static int +present_query_version(Display *dpy, int *major, int *minor) +{ + xcb_present_query_version_cookie_t cookie; + xcb_present_query_version_reply_t *reply; + xcb_connection_t *c = XGetXCBConnection(dpy); + xcb_generic_error_t *error; + + cookie = xcb_present_query_version(c, + XCB_PRESENT_MAJOR_VERSION, + XCB_PRESENT_MINOR_VERSION); + reply = xcb_present_query_version_reply(c, cookie, &error); + if (!reply) { + if (error) { + free(error); + } + return 0; + } + *major = reply->major_version; + *minor = reply->minor_version; + free(reply); + return 1; +} + +static int dri3_open(Display *dpy, Window root, CARD32 provider) @@ -1160,11 +1270,9 @@ dri3_destroy_screen(struct glx_screen *base) free(psc); } -#if HAS_SBC static int dri3_set_swap_interval(__GLXDRIdrawable *pdraw, int interval) { - xcb_connection_t *c = XGetXCBConnection(pdraw->psc->dpy); struct dri3_drawable *priv = (struct dri3_drawable *) pdraw; GLint vblank_mode = DRI_CONF_VBLANK_DEF_INTERVAL_1; struct dri3_screen *psc = (struct dri3_screen *) priv->base.psc; @@ -1186,7 +1294,6 @@ dri3_set_swap_interval(__GLXDRIdrawable *pdraw, int interval) break; } - xcb_dri2_swap_interval(c, priv->base.xDrawable, interval); priv->swap_interval = interval; return 0; @@ -1199,7 +1306,6 @@ dri3_get_swap_interval(__GLXDRIdrawable *pdraw) return priv->swap_interval; } -#endif static const __DRIdri3LoaderExtension dri3LoaderExtension = { {__DRI_DRI3_LOADER, __DRI_DRI3_LOADER_VERSION}, @@ -1443,22 +1549,13 @@ dri3_create_screen(int screen, struct glx_display * priv) psp->destroyScreen = dri3_destroy_screen; psp->createDrawable = dri3_create_drawable; psp->swapBuffers = dri3_swap_buffers; - psp->getDrawableMSC = NULL; - psp->waitForMSC = NULL; - psp->waitForSBC = NULL; - psp->setSwapInterval = NULL; - psp->getSwapInterval = NULL; - -#if HAS_SBC - if (pdp->driMinor >= 2) { - psp->getDrawableMSC = dri3DrawableGetMSC; - psp->waitForMSC = dri3WaitForMSC; - psp->waitForSBC = dri3WaitForSBC; - psp->setSwapInterval = dri3SetSwapInterval; - psp->getSwapInterval = dri3GetSwapInterval; - __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control"); - } -#endif + + psp->getDrawableMSC = dri3_drawable_get_msc; + psp->waitForMSC = dri3_wait_for_msc; + psp->waitForSBC = dri3_wait_for_sbc; + psp->setSwapInterval = dri3_set_swap_interval; + psp->getSwapInterval = dri3_get_swap_interval; + __glXEnableDirectExtension(&psc->base, "GLX_OML_sync_control"); psp->copySubBuffer = dri3_copy_sub_buffer; __glXEnableDirectExtension(&psc->base, "GLX_MESA_copy_sub_buffer"); @@ -1517,10 +1614,11 @@ dri3_create_display(Display * dpy) if (pdp == NULL) return NULL; - if (!dri3_query_version(dpy, &pdp->dri3Major, &pdp->dri3Minor)) { - free(pdp); - return NULL; - } + if (!dri3_query_version(dpy, &pdp->dri3Major, &pdp->dri3Minor)) + goto no_extension; + + if (!present_query_version(dpy, &pdp->presentMajor, &pdp->presentMinor)) + goto no_extension; pdp->base.destroyDisplay = dri3_destroy_display; pdp->base.createScreen = dri3_create_screen; @@ -1534,6 +1632,9 @@ dri3_create_display(Display * dpy) pdp->loader_extensions[i++] = NULL; return &pdp->base; +no_extension: + free(pdp); + return NULL; } #endif /* GLX_DIRECT_RENDERING */ diff --git a/src/glx/dri3_priv.h b/src/glx/dri3_priv.h index 8703b39..8426253 100644 --- a/src/glx/dri3_priv.h +++ b/src/glx/dri3_priv.h @@ -56,6 +56,7 @@ #include #include +#include #include /* From xmlpool/options.h, user exposed so should be stable */ @@ -73,6 +74,11 @@ struct dri3_display /* DRI3 bits */ int dri3Major; int dri3Minor; + + /* Present bits */ + int hasPresent; + int presentMajor; + int presentMinor; }; struct dri3_screen { @@ -101,6 +107,35 @@ struct dri3_context __DRIcontext *driContext; }; +#define DRI3_MAX_BACK 2 +#define DRI3_BACK_ID(i) (i) +#define DRI3_FRONT_ID (DRI3_MAX_BACK) + +static inline int +dri3_buf_id_next(int buf_id) +{ + if (buf_id == DRI3_MAX_BACK - 1) + return 0; + return buf_id + 1; +} + +static inline int +dri3_buf_id_prev(int buf_id) +{ + if (buf_id == 0) + return DRI3_MAX_BACK - 1; + return buf_id - 1; +} + +static inline int +dri3_pixmap_buf_id(enum __DRI3bufferType buffer_type) +{ + if (buffer_type == __DRI3_BUFFER_BACK) + return DRI3_BACK_ID(0); + else + return DRI3_FRONT_ID; +} + struct dri3_drawable { __GLXDRIdrawable base; @@ -111,15 +146,26 @@ struct dri3_drawable uint8_t have_fake_front; uint8_t is_pixmap; + uint32_t present_request_serial; + uint32_t present_event_serial; + + uint64_t sbc; + + uint64_t ust, msc; + + /* For WaitMSC */ + uint32_t present_msc_request_serial; + uint32_t present_msc_event_serial; + uint64_t previous_time; unsigned frames; - __DRIdri3Buffer *buffers[2]; + __DRIdri3Buffer *buffers[1 + DRI3_MAX_BACK]; + int cur_back; int depth; xcb_present_event_t eid; xcb_gcontext_t gc; - const xcb_query_extension_reply_t *dri3_extension; const xcb_query_extension_reply_t *present_extension; xcb_special_event_t *special_event; };