[PATCH 6/6] Make GLX/dri3 use the Present extension when available

Keith Packard keithp at keithp.com
Fri Nov 1 00:13:16 CET 2013


This uses the Present extension with DRI3, which includes OML_Sync extension
support.

Signed-off-by: Keith Packard <keithp at keithp.com>
---
 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 <sys/types.h>
 #include <sys/mman.h>
 #include <sys/time.h>
+
 #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 <xcb/xcb.h>
 #include <xcb/dri3.h>
+#include <xcb/present.h>
 #include <xcb/sync.h>
 
 /* 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;
 };
-- 
1.8.4.2


------------------------------------------------------------------------------
Android is increasing in popularity, but the open development platform that
developers love is also attractive to malware creators. Download this white
paper to learn more about secure code signing practices that can help keep
Android apps secure.
http://pubads.g.doubleclick.net/gampad/clk?id=65839951&iu=/4140/ostg.clktrk
--
_______________________________________________
Dri-devel mailing list
Dri-devel at lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel


More information about the dri-devel mailing list