This uses the Present extension with DRI3, which includes OML_Sync extension support.
Signed-off-by: Keith Packard keithp@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; };