@@ -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)
@@ -991,6 +991,7 @@ struct __DRIdri3BufferRec {
uint32_t pixmap;
uint32_t sync_fence;
int32_t *shm_fence;
+ GLboolean busy;
void *driverPrivate;
};
@@ -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 */
@@ -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;
};
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(-)