diff -urp a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h --- a/include/GL/internal/dri_interface.h 2016-09-08 12:57:48.000000000 -0400 +++ b/include/GL/internal/dri_interface.h 2016-10-15 15:46:37.981674968 -0400 @@ -270,7 +270,7 @@ struct __DRItexBufferExtensionRec { * Used by drivers that implement DRI2 */ #define __DRI2_FLUSH "DRI2_Flush" -#define __DRI2_FLUSH_VERSION 4 +#define __DRI2_FLUSH_VERSION 5 #define __DRI2_FLUSH_DRAWABLE (1 << 0) /* the drawable should be flushed. */ #define __DRI2_FLUSH_CONTEXT (1 << 1) /* glFlush should be called */ @@ -316,6 +316,16 @@ struct __DRI2flushExtensionRec { __DRIdrawable *drawable, unsigned flags, enum __DRI2throttleReason throttle_reason); + + /** + * Ask the driver to call getBuffers/getBuffersWithFormat on all + * surfaces on this screen before it starts rendering again. + * + * \param screen the screen to invalidate + * + * \since 5 + */ + void (*invalidateScreen)(__DRIscreen *screen); }; diff -urp a/src/glx/dri2_glx.c b/src/glx/dri2_glx.c --- a/src/glx/dri2_glx.c 2016-09-08 12:57:48.000000000 -0400 +++ b/src/glx/dri2_glx.c 2016-10-15 15:46:37.981674968 -0400 @@ -633,7 +633,7 @@ dri2_copy_drawable(struct dri2_drawable } static void -dri2_wait_x(struct glx_context *gc) +__dri2_copy_x(struct glx_context *gc) { struct dri2_drawable *priv = (struct dri2_drawable *) GetGLXDRIDrawable(gc->currentDpy, gc->currentDrawable); @@ -645,6 +645,18 @@ dri2_wait_x(struct glx_context *gc) } static void +dri2_wait_x(struct glx_context *gc) +{ + struct dri2_context *pcp = (struct dri2_context *) gc; + struct dri2_screen *psc = (struct dri2_screen *) pcp->base.psc; + + if (psc->f && psc->f->base.version >= 5 && psc->f->invalidateScreen) + psc->f->invalidateScreen(psc->driScreen); + else + __dri2_copy_x(gc); +} + +static void dri2_wait_gl(struct glx_context *gc) { struct dri2_drawable *priv = (struct dri2_drawable *) @@ -979,7 +991,7 @@ dri2InvalidateBuffers(Display *dpy, XID psc = (struct dri2_screen *) pdraw->psc; - if (pdraw && psc->f && psc->f->base.version >= 3 && psc->f->invalidate) + if (psc->f && psc->f->base.version >= 3 && psc->f->invalidate) psc->f->invalidate(pdp->driDrawable); } diff -urp a/src/loader/loader_dri3_helper.c b/src/loader/loader_dri3_helper.c --- a/src/loader/loader_dri3_helper.c 2016-10-15 11:44:16.516706027 -0400 +++ b/src/loader/loader_dri3_helper.c 2016-10-15 15:50:14.491683486 -0400 @@ -118,6 +118,11 @@ loader_dri3_drawable_fini(struct loader_ dri3_free_render_buffer(draw, draw->buffers[i]); } + if (draw->sync_fence) { + xcb_sync_destroy_fence(draw->conn, draw->sync_fence); + xshmfence_unmap_shm(draw->shm_fence); + } + if (draw->special_event) xcb_unregister_for_special_event(draw->conn, draw->special_event); } @@ -548,7 +553,19 @@ loader_dri3_wait_x(struct loader_dri3_dr struct loader_dri3_buffer *front; __DRIcontext *dri_context; - if (draw == NULL || !draw->have_fake_front) + if (draw == NULL) + return; + + if (draw->sync_fence) { + xshmfence_reset(draw->shm_fence); + + xcb_sync_trigger_fence(draw->conn, draw->sync_fence); + xcb_flush(draw->conn); + + xshmfence_await(draw->shm_fence); + } + + if (!draw->have_fake_front) return; front = dri3_fake_front_buffer(draw); @@ -942,6 +959,29 @@ no_shm_fence: return NULL; } +static void +dri3_attach_sync(struct loader_dri3_drawable *draw) +{ + int fence_fd; + + fence_fd = xshmfence_alloc_shm(); + if (fence_fd < 0) + return; + + draw->shm_fence = xshmfence_map_shm(fence_fd); + if (draw->shm_fence == NULL) { + close(fence_fd); + return; + } + + draw->sync_fence = xcb_generate_id(draw->conn); + xcb_dri3_fence_from_fd(draw->conn, + draw->drawable, + draw->sync_fence, + false, + fence_fd); +} + /** loader_dri3_update_drawable * * Called the first time we use the drawable and then @@ -1031,6 +1071,8 @@ dri3_update_drawable(__DRIdrawable *driD xcb_unregister_for_special_event(draw->conn, draw->special_event); draw->special_event = NULL; } + + dri3_attach_sync(draw); } dri3_flush_present_events(draw); return true; @@ -1374,6 +1416,15 @@ loader_dri3_get_buffers(__DRIdrawable *d if (!front) return false; + + if (draw->sync_fence) { + xshmfence_reset(draw->shm_fence); + + xcb_sync_trigger_fence(draw->conn, draw->sync_fence); + xcb_flush(draw->conn); + + xshmfence_await(draw->shm_fence); + } } else { dri3_free_buffers(driDrawable, loader_dri3_buffer_front, draw); draw->have_fake_front = 0; diff -urp a/src/loader/loader_dri3_helper.h b/src/loader/loader_dri3_helper.h --- a/src/loader/loader_dri3_helper.h 2016-10-15 11:44:16.513372694 -0400 +++ b/src/loader/loader_dri3_helper.h 2016-10-15 15:46:37.985008301 -0400 @@ -156,6 +156,9 @@ struct loader_dri3_drawable { xcb_gcontext_t gc; xcb_special_event_t *special_event; + xcb_sync_fence_t sync_fence; + struct xshmfence *shm_fence; + bool first_init; struct loader_dri3_extensions *ext; diff -urp a/src/mesa/drivers/dri/common/dri_util.c b/src/mesa/drivers/dri/common/dri_util.c --- a/src/mesa/drivers/dri/common/dri_util.c 2016-05-24 15:19:37.000000000 -0400 +++ b/src/mesa/drivers/dri/common/dri_util.c 2016-10-15 15:46:37.985008301 -0400 @@ -805,6 +805,12 @@ dri2InvalidateDrawable(__DRIdrawable *dr drawable->dri2.stamp++; } +void +dri2InvalidateScreen(__DRIscreen *screen) +{ + screen->dri2.stamp++; +} + /** * Check that the gl_framebuffer associated with dPriv is the right size. * Resize the gl_framebuffer if needed. diff -urp a/src/mesa/drivers/dri/common/dri_util.h b/src/mesa/drivers/dri/common/dri_util.h --- a/src/mesa/drivers/dri/common/dri_util.h 2016-01-18 02:39:26.000000000 -0500 +++ b/src/mesa/drivers/dri/common/dri_util.h 2016-10-15 15:46:37.985008301 -0400 @@ -172,6 +172,7 @@ struct __DRIscreenRec { const __DRIdri2LoaderExtension *loader; const __DRIimageLookupExtension *image; const __DRIuseInvalidateExtension *useInvalidate; + unsigned int stamp; } dri2; struct { @@ -285,6 +286,9 @@ extern void dri2InvalidateDrawable(__DRIdrawable *drawable); extern void +dri2InvalidateScreen(__DRIscreen *screen); + +extern void driUpdateFramebufferSize(struct gl_context *ctx, const __DRIdrawable *dPriv); extern void diff -urp a/src/mesa/drivers/dri/i965/brw_context.c b/src/mesa/drivers/dri/i965/brw_context.c --- a/src/mesa/drivers/dri/i965/brw_context.c 2016-09-15 05:14:40.000000000 -0400 +++ b/src/mesa/drivers/dri/i965/brw_context.c 2016-10-15 15:49:09.228347588 -0400 @@ -1237,14 +1237,12 @@ intelMakeCurrent(__DRIcontext * driConte fb = _mesa_get_incomplete_framebuffer(); } else { fb = driDrawPriv->driverPrivate; - driContextPriv->dri2.draw_stamp = driDrawPriv->dri2.stamp - 1; } if (driReadPriv == NULL) { readFb = _mesa_get_incomplete_framebuffer(); } else { readFb = driReadPriv->driverPrivate; - driContextPriv->dri2.read_stamp = driReadPriv->dri2.stamp - 1; } /* The sRGB workaround changes the renderbuffer's format. We must change @@ -1332,11 +1330,6 @@ intel_update_dri2_buffers(struct brw_con int i, count; const char *region_name; - /* Set this up front, so that in case our buffers get invalidated - * while we're getting new buffers, we don't clobber the stamp and - * thus ignore the invalidate. */ - drawable->lastStamp = drawable->dri2.stamp; - if (unlikely(INTEL_DEBUG & DEBUG_DRI)) fprintf(stderr, "enter %s, drawable %p\n", __func__, drawable); @@ -1380,15 +1373,10 @@ intel_update_dri2_buffers(struct brw_con } void -intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable) +__intel_update_renderbuffers(__DRIcontext *context, __DRIdrawable *drawable) { + __DRIscreen *screen = context->driScreenPriv; struct brw_context *brw = context->driverPrivate; - __DRIscreen *screen = brw->intelScreen->driScrnPriv; - - /* Set this up front, so that in case our buffers get invalidated - * while we're getting new buffers, we don't clobber the stamp and - * thus ignore the invalidate. */ - drawable->lastStamp = drawable->dri2.stamp; if (unlikely(INTEL_DEBUG & DEBUG_DRI)) fprintf(stderr, "enter %s, drawable %p\n", __func__, drawable); @@ -1410,21 +1398,15 @@ intel_prepare_render(struct brw_context { struct gl_context *ctx = &brw->ctx; __DRIcontext *driContext = brw->driContext; - __DRIdrawable *drawable; - drawable = driContext->driDrawablePriv; - if (drawable && drawable->dri2.stamp != driContext->dri2.draw_stamp) { - if (drawable->lastStamp != drawable->dri2.stamp) - intel_update_renderbuffers(driContext, drawable); - driContext->dri2.draw_stamp = drawable->dri2.stamp; - } - - drawable = driContext->driReadablePriv; - if (drawable && drawable->dri2.stamp != driContext->dri2.read_stamp) { - if (drawable->lastStamp != drawable->dri2.stamp) - intel_update_renderbuffers(driContext, drawable); - driContext->dri2.read_stamp = drawable->dri2.stamp; - } + if (driContext->driDrawablePriv) + intel_update_renderbuffers(driContext, + driContext->driDrawablePriv, + false); + if (driContext->driReadablePriv) + intel_update_renderbuffers(driContext, + driContext->driReadablePriv, + false); /* If we're currently rendering to the front buffer, the rendering * that will happen next will probably dirty the front buffer. So diff -urp a/src/mesa/drivers/dri/i965/brw_context.h b/src/mesa/drivers/dri/i965/brw_context.h --- a/src/mesa/drivers/dri/i965/brw_context.h 2016-09-15 05:14:40.000000000 -0400 +++ b/src/mesa/drivers/dri/i965/brw_context.h 2016-10-15 15:46:37.985008301 -0400 @@ -1376,8 +1376,27 @@ enum { DRI_CONF_BO_REUSE_ALL }; -void intel_update_renderbuffers(__DRIcontext *context, - __DRIdrawable *drawable); +void __intel_update_renderbuffers(__DRIcontext *context, + __DRIdrawable *drawable); +static inline void +intel_update_renderbuffers(__DRIcontext *context, + __DRIdrawable *drawable, + bool force) +{ + __DRIscreen *dri_screen = context->driScreenPriv; + unsigned int stamp = drawable->dri2.stamp + dri_screen->dri2.stamp; + + if (stamp == drawable->lastStamp && !force) + return; + + /* Set this up front, so that in case our buffers get invalidated + * while we're getting new buffers, we don't clobber the stamp and + * thus ignore the invalidate. */ + drawable->lastStamp = stamp; + + __intel_update_renderbuffers(context, drawable); +} + void intel_prepare_render(struct brw_context *brw); void intel_resolve_for_dri2_flush(struct brw_context *brw, diff -urp a/src/mesa/drivers/dri/i965/intel_screen.c b/src/mesa/drivers/dri/i965/intel_screen.c --- a/src/mesa/drivers/dri/i965/intel_screen.c 2016-09-15 05:14:40.000000000 -0400 +++ b/src/mesa/drivers/dri/i965/intel_screen.c 2016-10-15 15:46:37.985008301 -0400 @@ -205,11 +205,12 @@ intel_dri2_flush(__DRIdrawable *drawable } static const struct __DRI2flushExtensionRec intelFlushExtension = { - .base = { __DRI2_FLUSH, 4 }, + .base = { __DRI2_FLUSH, 5 }, .flush = intel_dri2_flush, - .invalidate = dri2InvalidateDrawable, .flush_with_flags = intel_dri2_flush_with_flags, + .invalidate = dri2InvalidateDrawable, + .invalidateScreen = dri2InvalidateScreen, }; static struct intel_image_format intel_image_formats[] = { diff -urp a/src/mesa/drivers/dri/i965/intel_tex_image.c b/src/mesa/drivers/dri/i965/intel_tex_image.c --- a/src/mesa/drivers/dri/i965/intel_tex_image.c 2016-09-15 05:14:40.000000000 -0400 +++ b/src/mesa/drivers/dri/i965/intel_tex_image.c 2016-10-15 15:46:37.985008301 -0400 @@ -271,9 +271,8 @@ intelSetTexBuffer2(__DRIcontext *pDRICtx if (!texObj) return; - if (dPriv->lastStamp != dPriv->dri2.stamp || - !pDRICtx->driScreenPriv->dri2.useInvalidate) - intel_update_renderbuffers(pDRICtx, dPriv); + intel_update_renderbuffers(pDRICtx, dPriv, + !pDRICtx->driScreenPriv->dri2.useInvalidate); rb = intel_get_renderbuffer(fb, BUFFER_FRONT_LEFT); /* If the miptree isn't set, then intel_update_renderbuffers was unable