xserver: Branch 'master' - 3 commits

Keith Packard keithp at kemper.freedesktop.org
Wed Jan 13 10:19:42 PST 2010


 configure.ac                |    4 
 glx/extension_string.c      |    1 
 glx/extension_string.h      |    1 
 glx/glxcmds.c               |    2 
 glx/glxcontext.h            |    4 
 glx/glxdrawable.h           |    2 
 glx/glxdri.c                |    2 
 glx/glxdri2.c               |  102 +++++++++--
 glx/glxdriswrast.c          |    2 
 glx/glxext.c                |    5 
 glx/glxscreens.c            |    1 
 glx/glxserver.h             |   20 +-
 glx/swap_interval.c         |    7 
 hw/xfree86/dri2/dri2.c      |  403 +++++++++++++++++++++++++++++++++++++++++++-
 hw/xfree86/dri2/dri2.h      |  129 +++++++++++++-
 hw/xfree86/dri2/dri2ext.c   |  217 +++++++++++++++++++++++
 include/protocol-versions.h |    2 
 17 files changed, 864 insertions(+), 40 deletions(-)

New commits:
commit 44f9c3d16c9c9b3362306a9ba26ee52e7baafeca
Merge: 032f978... 84956ca...
Author: Keith Packard <keithp at keithp.com>
Date:   Wed Jan 13 10:19:21 2010 -0800

    Merge remote branch 'jbarnes/master'

commit 84956ca43b087600d9db297cffd62e960c516d9e
Author: Jesse Barnes <jbarnes at virtuousgeek.org>
Date:   Mon Jan 11 14:56:24 2010 -0500

    GLX/DRI2: add INTEL_swap_event support
    
    This allows clients to easily check for swap completion status in their
    main loop.
    
    Reviewed-by: Kristian Høgsberg <krh at bitplanet.net>
    Reviewed-by: Adam Jackson <ajax at nwnk.net>
    Signed-off-by: Jesse Barnes <jbarnes at virtuousgeek.org>

diff --git a/configure.ac b/configure.ac
index 1b20fc6..029c9b4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -755,7 +755,7 @@ XINERAMAPROTO="xineramaproto"
 BIGFONTPROTO="xf86bigfontproto >= 1.2.0"
 XCALIBRATEPROTO="xcalibrateproto"
 DGAPROTO="xf86dgaproto >= 2.0.99.1"
-GLPROTO="glproto >= 1.4.9"
+GLPROTO="glproto >= 1.4.10"
 DMXPROTO="dmxproto >= 2.2.99.1"
 VIDMODEPROTO="xf86vidmodeproto >= 2.2.99.1"
 WINDOWSWMPROTO="windowswmproto"
diff --git a/glx/extension_string.c b/glx/extension_string.c
index 9d110cf..7721cb0 100644
--- a/glx/extension_string.c
+++ b/glx/extension_string.c
@@ -82,6 +82,7 @@ static const struct extension_info known_glx_extensions[] = {
    { GLX(SGIX_fbconfig),               VER(1,3), Y, },
    { GLX(SGIX_pbuffer),                VER(1,3), Y, },
    { GLX(SGIX_visual_select_group),    VER(0,0), Y, },
+   { GLX(INTEL_swap_event),            VER(1,4), N, },
    { NULL }
 };
 
diff --git a/glx/extension_string.h b/glx/extension_string.h
index 98e91bc..912534a 100644
--- a/glx/extension_string.h
+++ b/glx/extension_string.h
@@ -50,6 +50,7 @@ enum {
    SGIX_fbconfig_bit,
    SGIX_pbuffer_bit,
    SGIX_visual_select_group_bit,
+   INTEL_swap_event_bit,
    __NUM_GLX_EXTS,
 };
 
diff --git a/glx/glxdri2.c b/glx/glxdri2.c
index 58e4684..69fd39b 100644
--- a/glx/glxdri2.c
+++ b/glx/glxdri2.c
@@ -167,6 +167,43 @@ __glXDRIdrawableWaitGL(__GLXdrawable *drawable)
 		   DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
 }
 
+static void
+__glXdriSwapEvent(ClientPtr client, void *data, int type, CARD64 ust,
+		  CARD64 msc, CARD64 sbc)
+{
+    __GLXdrawable *drawable = data;
+    xGLXBufferSwapComplete wire;
+
+    if (!drawable->eventMask & GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK)
+	return;
+
+    wire.type = __glXEventBase + GLX_BufferSwapComplete;
+    switch (type) {
+    case DRI2_EXCHANGE_COMPLETE:
+	wire.event_type = GLX_EXCHANGE_COMPLETE_INTEL;
+	break;
+    case DRI2_BLIT_COMPLETE:
+	wire.event_type = GLX_BLIT_COMPLETE_INTEL;
+	break;
+    case DRI2_FLIP_COMPLETE:
+	wire.event_type = GLX_FLIP_COMPLETE_INTEL;
+	break;
+    default:
+	/* unknown swap completion type */
+	break;
+    }
+    wire.sequenceNumber = client->sequence;
+    wire.drawable = drawable->drawId;
+    wire.ust_hi = ust >> 32;
+    wire.ust_lo = ust & 0xffffffff;
+    wire.msc_hi = msc >> 32;
+    wire.msc_lo = msc & 0xffffffff;
+    wire.sbc_hi = sbc >> 32;
+    wire.sbc_lo = sbc & 0xffffffff;
+
+    WriteEventsToClient(client, 1, (xEvent *) &wire);
+}
+
 /*
  * Copy or flip back to front, honoring the swap interval if possible.
  *
@@ -184,7 +221,7 @@ __glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable *drawable)
 	(*screen->flush->flushInvalidate)(priv->driDrawable);
 
     if (DRI2SwapBuffers(client, drawable->pDraw, 0, 0, 0, &unused,
-			NULL, drawable->pDraw) != Success)
+			__glXdriSwapEvent, drawable->pDraw) != Success)
 	return FALSE;
 
     return TRUE;
@@ -581,6 +618,10 @@ initializeExtensions(__GLXDRIscreen *screen)
 			 "GLX_MESA_copy_sub_buffer");
     LogMessage(X_INFO, "AIGLX: enabled GLX_MESA_copy_sub_buffer\n");
 
+    /* FIXME: only if DDX supports it */
+    __glXEnableExtension(screen->glx_enable_bits, "GLX_INTEL_swap_event");
+    LogMessage(X_INFO, "AIGLX: enabled GLX_INTEL_swap_event\n");
+
     for (i = 0; extensions[i]; i++) {
 #ifdef __DRI_READ_DRAWABLE
 	if (strcmp(extensions[i]->name, __DRI_READ_DRAWABLE) == 0) {
diff --git a/glx/glxext.c b/glx/glxext.c
index 913c624..59bcfbe 100644
--- a/glx/glxext.c
+++ b/glx/glxext.c
@@ -267,6 +267,7 @@ GLboolean __glXErrorOccured(void)
 }
 
 static int __glXErrorBase;
+int __glXEventBase;
 
 int __glXError(int error)
 {
@@ -403,6 +404,7 @@ void GlxExtensionInit(void)
     }
 
     __glXErrorBase = extEntry->errorBase;
+    __glXEventBase = extEntry->eventBase;
 }
 
 /************************************************************************/
diff --git a/glx/glxscreens.c b/glx/glxscreens.c
index 674e2c6..58d8ee0 100644
--- a/glx/glxscreens.c
+++ b/glx/glxscreens.c
@@ -181,6 +181,7 @@ static char GLXServerExtensions[] =
 			"GLX_SGIX_fbconfig "
 			"GLX_SGIX_pbuffer "
 			"GLX_MESA_copy_sub_buffer "
+                        "GLX_INTEL_swap_event"
 			;
 
 /*
diff --git a/glx/glxserver.h b/glx/glxserver.h
index 10c4889..1daf977 100644
--- a/glx/glxserver.h
+++ b/glx/glxserver.h
@@ -249,4 +249,6 @@ extern int __glXImageSize(GLenum format, GLenum type,
 extern unsigned glxMajorVersion;
 extern unsigned glxMinorVersion;
 
+extern int __glXEventBase;
+
 #endif /* !__GLX_server_h__ */
diff --git a/hw/xfree86/dri2/dri2.h b/hw/xfree86/dri2/dri2.h
index be14b9d..dd59297 100644
--- a/hw/xfree86/dri2/dri2.h
+++ b/hw/xfree86/dri2/dri2.h
@@ -169,6 +169,8 @@ typedef struct {
     DRI2ScheduleWaitMSCProcPtr	ScheduleWaitMSC;
 }  DRI2InfoRec, *DRI2InfoPtr;
 
+extern _X_EXPORT int DRI2EventBase;
+
 extern _X_EXPORT Bool DRI2ScreenInit(ScreenPtr	pScreen,
 		    DRI2InfoPtr info);
 
diff --git a/hw/xfree86/dri2/dri2ext.c b/hw/xfree86/dri2/dri2ext.c
index fb8f908..3e6b03e 100644
--- a/hw/xfree86/dri2/dri2ext.c
+++ b/hw/xfree86/dri2/dri2ext.c
@@ -348,6 +348,25 @@ vals_to_card64(CARD32 lo, CARD32 hi)
     return (CARD64)hi << 32 | lo;
 }
 
+static void
+DRI2SwapEvent(ClientPtr client, void *data, int type, CARD64 ust, CARD64 msc,
+	      CARD64 sbc)
+{
+    xDRI2BufferSwapComplete event;
+
+    event.type = DRI2EventBase + DRI2_BufferSwapComplete;
+    event.sequenceNumber = client->sequence;
+    event.event_type = type;
+    event.ust_hi = (CARD64)ust >> 32;
+    event.ust_lo = ust & 0xffffffff;
+    event.msc_hi = (CARD64)msc >> 32;
+    event.msc_lo = msc & 0xffffffff;
+    event.sbc_hi = (CARD64)sbc >> 32;
+    event.sbc_lo = sbc & 0xffffffff;
+
+    WriteEventsToClient(client, 1, (xEvent *)&event);
+}
+
 static int
 ProcDRI2SwapBuffers(ClientPtr client)
 {
@@ -368,7 +387,7 @@ ProcDRI2SwapBuffers(ClientPtr client)
     remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi);
 
     status = DRI2SwapBuffers(client, pDrawable, target_msc, divisor, remainder,
-			     &swap_target, NULL, pDrawable);
+			     &swap_target, DRI2SwapEvent, pDrawable);
     if (status != Success)
 	return BadDrawable;
 
@@ -608,6 +627,8 @@ static int DRI2DrawableGone(pointer p, XID id)
     return Success;
 }
 
+int DRI2EventBase;
+
 static void
 DRI2ExtensionInit(void)
 {
@@ -624,6 +645,7 @@ DRI2ExtensionInit(void)
 				 NULL,
 				 StandardMinorOpcode);
 
+    DRI2EventBase = dri2Extension->eventBase;
 }
 
 extern Bool noDRI2Extension;
commit 04a54f69a8085ab3fe11a8713bd8b6b16ed1db27
Author: Jesse Barnes <jbarnes at virtuousgeek.org>
Date:   Thu Jul 16 09:01:17 2009 -0400

    DRI2: add support for new DRI2 protocol requests
    
    Support the new DRI2 2.2 protocol requests: DRI2SwapBuffers, DRI2GetMSC,
    DRI2WaitMSC, DRI2WaitSBC and DRI2SwapInterval.
    
    These requests allow the server to support the SGI_video_sync,
    SGI_swap_interval, and OML_sync_control GLX extensions if DDX support is
    present.  The new DDX APIs are documented in dri2.h.
    
    Reviewed-by: Kristian Høgsberg <krh at bitplanet.net>
    Reviewed-by: Adam Jackson <ajax at nwnk.net>
    Signed-off-by: Jesse Barnes <jbarnes at virtuousgeek.org>

diff --git a/configure.ac b/configure.ac
index 7e2c6a5..1b20fc6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -750,7 +750,7 @@ RECORDPROTO="recordproto >= 1.13.99.1"
 SCRNSAVERPROTO="scrnsaverproto >= 1.1"
 RESOURCEPROTO="resourceproto"
 DRIPROTO="xf86driproto >= 2.1.0"
-DRI2PROTO="dri2proto >= 2.1"
+DRI2PROTO="dri2proto >= 2.2"
 XINERAMAPROTO="xineramaproto"
 BIGFONTPROTO="xf86bigfontproto >= 1.2.0"
 XCALIBRATEPROTO="xcalibrateproto"
diff --git a/glx/glxcmds.c b/glx/glxcmds.c
index eedab65..77afbf4 100644
--- a/glx/glxcmds.c
+++ b/glx/glxcmds.c
@@ -1481,7 +1481,7 @@ int __glXDisp_SwapBuffers(__GLXclientState *cl, GLbyte *pc)
 	return error;
 
     if (pGlxDraw->type == DRAWABLE_WINDOW &&
-	(*pGlxDraw->swapBuffers)(pGlxDraw) == GL_FALSE)
+	(*pGlxDraw->swapBuffers)(cl->client, pGlxDraw) == GL_FALSE)
 	return __glXError(GLXBadDrawable);
 
     return Success;
diff --git a/glx/glxcontext.h b/glx/glxcontext.h
index 70a1411..79bc083 100644
--- a/glx/glxcontext.h
+++ b/glx/glxcontext.h
@@ -55,6 +55,10 @@ struct __GLXcontext {
 				     unsigned long mask);
     int            (*forceCurrent)  (__GLXcontext *context);
 
+    Bool           (*wait)          (__GLXcontext *context,
+				     __GLXclientState *cl,
+				     int *error);
+
     __GLXtextureFromPixmap *textureFromPixmap;
 
     /*
diff --git a/glx/glxdrawable.h b/glx/glxdrawable.h
index 3f165ed..2a365c5 100644
--- a/glx/glxdrawable.h
+++ b/glx/glxdrawable.h
@@ -45,7 +45,7 @@ enum {
 
 struct __GLXdrawable {
     void (*destroy)(__GLXdrawable *private);
-    GLboolean (*swapBuffers)(__GLXdrawable *);
+    GLboolean (*swapBuffers)(ClientPtr client, __GLXdrawable *);
     void      (*copySubBuffer)(__GLXdrawable *drawable,
 			       int x, int y, int w, int h);
     void      (*waitX)(__GLXdrawable *);
diff --git a/glx/glxdri.c b/glx/glxdri.c
index 6122653..21e44d1 100644
--- a/glx/glxdri.c
+++ b/glx/glxdri.c
@@ -245,7 +245,7 @@ __glXDRIdrawableDestroy(__GLXdrawable *drawable)
 }
 
 static GLboolean
-__glXDRIdrawableSwapBuffers(__GLXdrawable *basePrivate)
+__glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable *basePrivate)
 {
     __GLXDRIdrawable *private = (__GLXDRIdrawable *) basePrivate;
     __GLXDRIscreen *screen =
diff --git a/glx/glxdri2.c b/glx/glxdri2.c
index ed7dc80..58e4684 100644
--- a/glx/glxdri2.c
+++ b/glx/glxdri2.c
@@ -70,6 +70,7 @@ struct __GLXDRIscreen {
 
     const __DRIcoreExtension *core;
     const __DRIdri2Extension *dri2;
+    const __DRI2flushExtension *flush;
     const __DRIcopySubBufferExtension *copySubBuffer;
     const __DRIswapControlExtension *swapControl;
     const __DRItexBufferExtension *texBuffer;
@@ -132,17 +133,6 @@ __glXDRIdrawableCopySubBuffer(__GLXdrawable *drawable,
 		   DRI2BufferFrontLeft, DRI2BufferBackLeft);
 }
 
-static GLboolean
-__glXDRIdrawableSwapBuffers(__GLXdrawable *drawable)
-{
-    __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
-
-    __glXDRIdrawableCopySubBuffer(drawable, 0, 0,
-				  private->width, private->height);
-
-    return TRUE;
-}
-
 static void
 __glXDRIdrawableWaitX(__GLXdrawable *drawable)
 {
@@ -177,9 +167,37 @@ __glXDRIdrawableWaitGL(__GLXdrawable *drawable)
 		   DRI2BufferFrontLeft, DRI2BufferFakeFrontLeft);
 }
 
+/*
+ * Copy or flip back to front, honoring the swap interval if possible.
+ *
+ * If the kernel supports it, we request an event for the frame when the
+ * swap should happen, then perform the copy when we receive it.
+ */
+static GLboolean
+__glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable *drawable)
+{
+    __GLXDRIdrawable *priv = (__GLXDRIdrawable *) drawable;
+    __GLXDRIscreen *screen = priv->screen;
+    CARD64 unused;
+
+    if (screen->flush)
+	(*screen->flush->flushInvalidate)(priv->driDrawable);
+
+    if (DRI2SwapBuffers(client, drawable->pDraw, 0, 0, 0, &unused,
+			NULL, drawable->pDraw) != Success)
+	return FALSE;
+
+    return TRUE;
+}
+
 static int
 __glXDRIdrawableSwapInterval(__GLXdrawable *drawable, int interval)
 {
+    if (interval <= 0) /* || interval > BIGNUM? */
+	return GLX_BAD_VALUE;
+
+    DRI2SwapInterval(drawable->pDraw, interval);
+
     return 0;
 }
 
@@ -241,6 +259,18 @@ __glXDRIcontextForceCurrent(__GLXcontext *baseContext)
 					read->driDrawable);
 }
 
+static Bool
+__glXDRIcontextWait(__GLXcontext *baseContext,
+		    __GLXclientState *cl, int *error)
+{
+    if (DRI2WaitSwap(cl->client, baseContext->drawPriv->pDraw)) {
+	*error = cl->client->noClientException;
+	return TRUE;
+    }
+
+    return FALSE;
+}
+
 #ifdef __DRI_TEX_BUFFER
 
 static int
@@ -346,6 +376,7 @@ __glXDRIscreenCreateContext(__GLXscreen *baseScreen,
     context->base.copy              = __glXDRIcontextCopy;
     context->base.forceCurrent      = __glXDRIcontextForceCurrent;
     context->base.textureFromPixmap = &__glXDRItextureFromPixmap;
+    context->base.wait              = __glXDRIcontextWait;
 
     context->driContext =
 	(*screen->dri2->createNewContext)(screen->driScreen,
@@ -581,6 +612,14 @@ initializeExtensions(__GLXDRIscreen *screen)
 	    LogMessage(X_INFO, "AIGLX: GLX_EXT_texture_from_pixmap backed by buffer objects\n");
 	}
 #endif
+
+#ifdef __DRI2_FLUSH
+	if (strcmp(extensions[i]->name, __DRI2_FLUSH) == 0 &&
+	    extensions[i]->version >= __DRI2_FLUSH_VERSION) {
+		screen->flush = (__DRI2flushExtension *) extensions[i];
+	}
+#endif
+
 	/* Ignore unknown extensions */
     }
 }
diff --git a/glx/glxdriswrast.c b/glx/glxdriswrast.c
index 20f9f90..c647d83 100644
--- a/glx/glxdriswrast.c
+++ b/glx/glxdriswrast.c
@@ -108,7 +108,7 @@ __glXDRIdrawableDestroy(__GLXdrawable *drawable)
 }
 
 static GLboolean
-__glXDRIdrawableSwapBuffers(__GLXdrawable *drawable)
+__glXDRIdrawableSwapBuffers(ClientPtr client, __GLXdrawable *drawable)
 {
     __GLXDRIdrawable *private = (__GLXDRIdrawable *) drawable;
     const __DRIcoreExtension *core = private->screen->core;
diff --git a/glx/glxext.c b/glx/glxext.c
index 751ea72..913c624 100644
--- a/glx/glxext.c
+++ b/glx/glxext.c
@@ -446,6 +446,9 @@ __GLXcontext *__glXForceCurrent(__GLXclientState *cl, GLXContextTag tag,
     	}
     }
     
+    if (cx->wait && (*cx->wait)(cx, cl, error))
+	return NULL;
+
     if (cx == __glXLastContext) {
 	/* No need to re-bind */
 	return cx;
diff --git a/glx/glxserver.h b/glx/glxserver.h
index 80f1b28..10c4889 100644
--- a/glx/glxserver.h
+++ b/glx/glxserver.h
@@ -56,7 +56,14 @@
 #include <GL/gl.h>
 #include <GL/glxproto.h>
 
-/* For glxscreens.h */
+/*
+** GLX resources.
+*/
+typedef XID GLXContextID;
+typedef XID GLXPixmap;
+typedef XID GLXDrawable;
+
+typedef struct __GLXclientStateRec __GLXclientState;
 typedef struct __GLXdrawable __GLXdrawable;
 typedef struct __GLXcontext __GLXcontext;
 
@@ -71,15 +78,6 @@ typedef struct __GLXcontext __GLXcontext;
 #define False 0
 #endif
 
-/*
-** GLX resources.
-*/
-typedef XID GLXContextID;
-typedef XID GLXPixmap;
-typedef XID GLXDrawable;
-
-typedef struct __GLXclientStateRec __GLXclientState;
-
 extern __GLXscreen *glxGetScreen(ScreenPtr pScreen);
 extern __GLXclientState *glxGetClient(ClientPtr pClient);
 
diff --git a/glx/swap_interval.c b/glx/swap_interval.c
index 3a52420..0bae324 100644
--- a/glx/swap_interval.c
+++ b/glx/swap_interval.c
@@ -53,8 +53,6 @@ int DoSwapInterval(__GLXclientState *cl, GLbyte *pc, int do_swap)
 
     cx = __glXLookupContextByTag(cl, tag);
 
-    LogMessage(X_ERROR, "%s: cx = %p, GLX screen = %p\n", __func__,
-	       cx, (cx == NULL) ? NULL : cx->pGlxScreen);
     if ((cx == NULL) || (cx->pGlxScreen == NULL)) {
 	client->errorValue = tag;
 	return __glXError(GLXBadContext);
@@ -68,7 +66,7 @@ int DoSwapInterval(__GLXclientState *cl, GLbyte *pc, int do_swap)
 
     if (cx->drawPriv == NULL) {
 	client->errorValue = tag;
-	return __glXError(GLXBadDrawable);
+	return BadValue;
     }
     
     pc += __GLX_VENDPRIV_HDR_SIZE;
@@ -76,6 +74,9 @@ int DoSwapInterval(__GLXclientState *cl, GLbyte *pc, int do_swap)
       ? bswap_32(*(int *)(pc + 0))
       :          *(int *)(pc + 0);
 
+    if (interval <= 0)
+	return BadValue;
+
     (void) (*cx->pGlxScreen->swapInterval)(cx->drawPriv, interval);
     return Success;
 }
diff --git a/hw/xfree86/dri2/dri2.c b/hw/xfree86/dri2/dri2.c
index d15ced1..3db826e 100644
--- a/hw/xfree86/dri2/dri2.c
+++ b/hw/xfree86/dri2/dri2.c
@@ -34,10 +34,12 @@
 #include <xorg-config.h>
 #endif
 
+#include <errno.h>
 #include <xf86drm.h>
 #include "xf86Module.h"
 #include "scrnintstr.h"
 #include "windowstr.h"
+#include "dixstruct.h"
 #include "dri2.h"
 #include "xf86VGAarbiter.h"
 
@@ -56,9 +58,17 @@ typedef struct _DRI2Drawable {
     int			 height;
     DRI2BufferPtr	*buffers;
     int			 bufferCount;
-    unsigned int	 pendingSequence;
+    unsigned int	 swapsPending;
+    ClientPtr		 blockedClient;
+    int			 swap_interval;
+    CARD64		 swap_count;
+    CARD64		 target_sbc; /* -1 means no SBC wait outstanding */
+    CARD64		 last_swap_target; /* most recently queued swap target */
+    int			 swap_limit; /* for N-buffering */
 } DRI2DrawableRec, *DRI2DrawablePtr;
 
+typedef struct _DRI2Screen *DRI2ScreenPtr;
+
 typedef struct _DRI2Screen {
     const char			*driverName;
     const char			*deviceName;
@@ -68,9 +78,12 @@ typedef struct _DRI2Screen {
     DRI2CreateBufferProcPtr	 CreateBuffer;
     DRI2DestroyBufferProcPtr	 DestroyBuffer;
     DRI2CopyRegionProcPtr	 CopyRegion;
+    DRI2ScheduleSwapProcPtr	 ScheduleSwap;
+    DRI2GetMSCProcPtr		 GetMSC;
+    DRI2ScheduleWaitMSCProcPtr	 ScheduleWaitMSC;
 
     HandleExposuresProcPtr       HandleExposures;
-} DRI2ScreenRec, *DRI2ScreenPtr;
+} DRI2ScreenRec;
 
 static DRI2ScreenPtr
 DRI2GetScreen(ScreenPtr pScreen)
@@ -84,6 +97,9 @@ DRI2GetDrawable(DrawablePtr pDraw)
     WindowPtr		  pWin;
     PixmapPtr		  pPixmap;
 
+    if (!pDraw)
+	return NULL;
+
     if (pDraw->type == DRAWABLE_WINDOW)
     {
 	pWin = (WindowPtr) pDraw;
@@ -119,6 +135,13 @@ DRI2CreateDrawable(DrawablePtr pDraw)
     pPriv->height = pDraw->height;
     pPriv->buffers = NULL;
     pPriv->bufferCount = 0;
+    pPriv->swapsPending = 0;
+    pPriv->blockedClient = NULL;
+    pPriv->swap_count = 0;
+    pPriv->target_sbc = -1;
+    pPriv->swap_interval = 1;
+    pPriv->last_swap_target = -1;
+    pPriv->swap_limit = 1; /* default to double buffering */
 
     if (pDraw->type == DRAWABLE_WINDOW)
     {
@@ -308,6 +331,50 @@ DRI2GetBuffersWithFormat(DrawablePtr pDraw, int *width, int *height,
 			  out_count, TRUE);
 }
 
+/*
+ * In the direct rendered case, we throttle the clients that have more
+ * than their share of outstanding swaps (and thus busy buffers) when a
+ * new GetBuffers request is received.  In the AIGLX case, we allow the
+ * client to get the new buffers, but throttle when the next GLX request
+ * comes in (see __glXDRIcontextWait()).
+ */
+Bool
+DRI2ThrottleClient(ClientPtr client, DrawablePtr pDraw)
+{
+    DRI2DrawablePtr pPriv;
+
+    pPriv = DRI2GetDrawable(pDraw);
+    if (pPriv == NULL)
+	return FALSE;
+
+    /* Throttle to swap limit */
+    if ((pPriv->swapsPending >= pPriv->swap_limit) &&
+	!pPriv->blockedClient) {
+	ResetCurrentRequest(client);
+	client->sequence--;
+	IgnoreClient(client);
+	pPriv->blockedClient = client;
+	return TRUE;
+    }
+
+    return FALSE;
+}
+
+void
+DRI2BlockClient(ClientPtr client, DrawablePtr pDraw)
+{
+    DRI2DrawablePtr pPriv;
+
+    pPriv = DRI2GetDrawable(pDraw);
+    if (pPriv == NULL)
+	return;
+
+    if (pPriv->blockedClient == NULL) {
+	IgnoreClient(client);
+	pPriv->blockedClient = client;
+    }
+}
+
 int
 DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
 	       unsigned int dest, unsigned int src)
@@ -338,6 +405,324 @@ DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion,
     return Success;
 }
 
+/* Can this drawable be page flipped? */
+Bool
+DRI2CanFlip(DrawablePtr pDraw)
+{
+    ScreenPtr pScreen = pDraw->pScreen;
+    WindowPtr pWin, pRoot;
+    PixmapPtr pWinPixmap, pRootPixmap;
+
+    if (pDraw->type == DRAWABLE_PIXMAP)
+	return TRUE;
+
+    pRoot = WindowTable[pScreen->myNum];
+    pRootPixmap = pScreen->GetWindowPixmap(pRoot);
+
+    pWin = (WindowPtr) pDraw;
+    pWinPixmap = pScreen->GetWindowPixmap(pWin);
+    if (pRootPixmap != pWinPixmap)
+	return FALSE;
+    if (!REGION_EQUAL(pScreen, &pWin->clipList, &pRoot->winSize))
+	return FALSE;
+
+    return TRUE;
+}
+
+/* Can we do a pixmap exchange instead of a blit? */
+Bool
+DRI2CanExchange(DrawablePtr pDraw)
+{
+    return FALSE;
+}
+
+void
+DRI2WaitMSCComplete(ClientPtr client, DrawablePtr pDraw, int frame,
+		    unsigned int tv_sec, unsigned int tv_usec)
+{
+    DRI2DrawablePtr pPriv;
+
+    pPriv = DRI2GetDrawable(pDraw);
+    if (pPriv == NULL)
+	return;
+
+    ProcDRI2WaitMSCReply(client, ((CARD64)tv_sec * 1000000) + tv_usec,
+			 frame, pPriv->swap_count);
+
+    if (pPriv->blockedClient)
+	AttendClient(pPriv->blockedClient);
+
+    pPriv->blockedClient = NULL;
+}
+
+static void
+DRI2WakeClient(ClientPtr client, DrawablePtr pDraw, int frame,
+	       unsigned int tv_sec, unsigned int tv_usec)
+{
+    ScreenPtr	    pScreen = pDraw->pScreen;
+    DRI2DrawablePtr pPriv;
+
+    pPriv = DRI2GetDrawable(pDraw);
+    if (pPriv == NULL) {
+        xf86DrvMsg(pScreen->myNum, X_ERROR,
+		   "[DRI2] %s: bad drawable\n", __func__);
+	return;
+    }
+
+    /*
+     * Swap completed.  Either wake up an SBC waiter or a client that was
+     * blocked due to GLX activity during a swap.
+     */
+    if (pPriv->target_sbc != -1 &&
+	pPriv->target_sbc >= pPriv->swap_count) {
+	ProcDRI2WaitMSCReply(client, ((CARD64)tv_sec * 1000000) + tv_usec,
+			     frame, pPriv->swap_count);
+	pPriv->target_sbc = -1;
+
+	AttendClient(pPriv->blockedClient);
+	pPriv->blockedClient = NULL;
+    } else if (pPriv->target_sbc == -1) {
+	if (pPriv->blockedClient)
+	    AttendClient(pPriv->blockedClient);
+	pPriv->blockedClient = NULL;
+    }
+}
+
+void
+DRI2SwapComplete(ClientPtr client, DrawablePtr pDraw, int frame,
+		   unsigned int tv_sec, unsigned int tv_usec, int type,
+		   DRI2SwapEventPtr swap_complete, void *swap_data)
+{
+    ScreenPtr	    pScreen = pDraw->pScreen;
+    DRI2DrawablePtr pPriv;
+    CARD64          ust = 0;
+
+    pPriv = DRI2GetDrawable(pDraw);
+    if (pPriv == NULL) {
+        xf86DrvMsg(pScreen->myNum, X_ERROR,
+		   "[DRI2] %s: bad drawable\n", __func__);
+	return;
+    }
+
+    if (pPriv->refCount == 0) {
+        xf86DrvMsg(pScreen->myNum, X_ERROR,
+		   "[DRI2] %s: bad drawable refcount\n", __func__);
+	xfree(pPriv);
+	return;
+    }
+
+    ust = ((CARD64)tv_sec * 1000000) + tv_usec;
+    if (swap_complete)
+	swap_complete(client, swap_data, type, ust, frame, pPriv->swap_count);
+
+    pPriv->swapsPending--;
+    pPriv->swap_count++;
+
+    DRI2WakeClient(client, pDraw, frame, tv_sec, tv_usec);
+}
+
+Bool
+DRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable)
+{
+    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable);
+
+    /* If we're currently waiting for a swap on this drawable, reset
+     * the request and suspend the client.  We only support one
+     * blocked client per drawable. */
+    if ((pPriv->swapsPending) &&
+	pPriv->blockedClient == NULL) {
+	ResetCurrentRequest(client);
+	client->sequence--;
+	DRI2BlockClient(client, pDrawable);
+	return TRUE;
+    }
+
+    return FALSE;
+}
+
+int
+DRI2SwapBuffers(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
+		CARD64 divisor, CARD64 remainder, CARD64 *swap_target,
+		DRI2SwapEventPtr func, void *data)
+{
+    ScreenPtr       pScreen = pDraw->pScreen;
+    DRI2ScreenPtr   ds = DRI2GetScreen(pDraw->pScreen);
+    DRI2DrawablePtr pPriv;
+    DRI2BufferPtr   pDestBuffer = NULL, pSrcBuffer = NULL;
+    CARD64          ust;
+    int             ret, i;
+
+    pPriv = DRI2GetDrawable(pDraw);
+    if (pPriv == NULL) {
+        xf86DrvMsg(pScreen->myNum, X_ERROR,
+		   "[DRI2] %s: bad drawable\n", __func__);
+	return BadDrawable;
+    }
+
+    for (i = 0; i < pPriv->bufferCount; i++) {
+	if (pPriv->buffers[i]->attachment == DRI2BufferFrontLeft)
+	    pDestBuffer = (DRI2BufferPtr) pPriv->buffers[i];
+	if (pPriv->buffers[i]->attachment == DRI2BufferBackLeft)
+	    pSrcBuffer = (DRI2BufferPtr) pPriv->buffers[i];
+    }
+    if (pSrcBuffer == NULL || pDestBuffer == NULL) {
+        xf86DrvMsg(pScreen->myNum, X_ERROR,
+		   "[DRI2] %s: drawable has no back or front?\n", __func__);
+	return BadDrawable;
+    }
+
+    /* Old DDX, just blit */
+    if (!ds->ScheduleSwap) {
+	BoxRec box;
+	RegionRec region;
+
+	box.x1 = 0;
+	box.y1 = 0;
+	box.x2 = pDraw->width;
+	box.y2 = pDraw->height;
+	REGION_INIT(pScreen, &region, &box, 0);
+
+	pPriv->swapsPending++;
+
+	(*ds->CopyRegion)(pDraw, &region, pDestBuffer, pSrcBuffer);
+	DRI2SwapComplete(client, pDraw, target_msc, 0, 0, DRI2_BLIT_COMPLETE,
+			 func, data);
+	return Success;
+    }
+
+    /*
+     * In the simple glXSwapBuffers case, all params will be 0, and we just
+     * need to schedule a swap for the last swap target + the swap interval.
+     * If the last swap target hasn't been set yet, call into the driver
+     * to get the current count.
+     */
+    if (target_msc == 0 && divisor == 0 && remainder == 0 &&
+	pPriv->last_swap_target < 0) {
+	ret = (*ds->GetMSC)(pDraw, &ust, &target_msc);
+	if (!ret) {
+	    xf86DrvMsg(pScreen->myNum, X_ERROR,
+		       "[DRI2] %s: driver failed to return current MSC\n",
+		       __func__);
+	    return BadDrawable;
+	}
+    }
+
+    /* First swap needs to initialize last_swap_target */
+    if (pPriv->last_swap_target < 0)
+	pPriv->last_swap_target = target_msc;
+
+    /*
+     * Swap target for this swap is last swap target + swap interval since
+     * we have to account for the current swap count, interval, and the
+     * number of pending swaps.
+     */
+    *swap_target = pPriv->last_swap_target + pPriv->swap_interval;
+
+    ret = (*ds->ScheduleSwap)(client, pDraw, pDestBuffer, pSrcBuffer,
+			      swap_target, divisor, remainder, func, data);
+    if (!ret) {
+        xf86DrvMsg(pScreen->myNum, X_ERROR,
+		   "[DRI2] %s: driver failed to schedule swap\n", __func__);
+	return BadDrawable;
+    }
+
+    pPriv->swapsPending++;
+    pPriv->last_swap_target = *swap_target;
+
+    return Success;
+}
+
+void
+DRI2SwapInterval(DrawablePtr pDrawable, int interval)
+{
+    DRI2DrawablePtr pPriv = DRI2GetDrawable(pDrawable);
+
+    /* fixme: check against arbitrary max? */
+
+    pPriv->swap_interval = interval;
+}
+
+int
+DRI2GetMSC(DrawablePtr pDraw, CARD64 *ust, CARD64 *msc, CARD64 *sbc)
+{
+    ScreenPtr pScreen = pDraw->pScreen;
+    DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
+    DRI2DrawablePtr pPriv;
+    Bool ret;
+
+    pPriv = DRI2GetDrawable(pDraw);
+    if (pPriv == NULL) {
+        xf86DrvMsg(pScreen->myNum, X_ERROR,
+		   "[DRI2] %s: bad drawable\n", __func__);
+	return BadDrawable;
+    }
+
+    if (!ds->GetMSC) {
+	*ust = 0;
+	*msc = 0;
+	*sbc = pPriv->swap_count;
+	return Success;
+    }
+
+    /*
+     * Spec needs to be updated to include unmapped or redirected
+     * drawables
+     */
+
+    ret = (*ds->GetMSC)(pDraw, ust, msc);
+    if (!ret)
+	return BadDrawable;
+
+    *sbc = pPriv->swap_count;
+
+    return Success;
+}
+
+int
+DRI2WaitMSC(ClientPtr client, DrawablePtr pDraw, CARD64 target_msc,
+	    CARD64 divisor, CARD64 remainder)
+{
+    DRI2ScreenPtr ds = DRI2GetScreen(pDraw->pScreen);
+    DRI2DrawablePtr pPriv;
+    Bool ret;
+
+    pPriv = DRI2GetDrawable(pDraw);
+    if (pPriv == NULL)
+	return BadDrawable;
+
+    /* Old DDX just completes immediately */
+    if (!ds->ScheduleWaitMSC) {
+	DRI2WaitMSCComplete(client, pDraw, target_msc, 0, 0);
+
+	return Success;
+    }
+
+    ret = (*ds->ScheduleWaitMSC)(client, pDraw, target_msc, divisor, remainder);
+    if (!ret)
+	return BadDrawable;
+
+    return Success;
+}
+
+int
+DRI2WaitSBC(ClientPtr client, DrawablePtr pDraw, CARD64 target_sbc,
+	    CARD64 *ust, CARD64 *msc, CARD64 *sbc)
+{
+    DRI2DrawablePtr pPriv;
+
+    pPriv = DRI2GetDrawable(pDraw);
+    if (pPriv == NULL)
+	return BadDrawable;
+
+    if (pPriv->swap_count >= target_sbc)
+	return Success;
+
+    pPriv->target_sbc = target_sbc;
+    DRI2BlockClient(client, pDraw);
+
+    return Success;
+}
+
 void
 DRI2DestroyDrawable(DrawablePtr pDraw)
 {
@@ -363,7 +748,11 @@ DRI2DestroyDrawable(DrawablePtr pDraw)
 	xfree(pPriv->buffers);
     }
 
-    xfree(pPriv);
+    /* If the window is destroyed while we have a swap pending, don't
+     * actually free the priv yet.  We'll need it in the DRI2SwapComplete()
+     * callback and we'll free it there once we're done. */
+    if (!pPriv->swapsPending)
+	xfree(pPriv);
 
     if (pDraw->type == DRAWABLE_WINDOW)
     {
@@ -421,7 +810,7 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
         return FALSE;
     }
 
-    ds = xalloc(sizeof *ds);
+    ds = xcalloc(1, sizeof *ds);
     if (!ds)
 	return FALSE;
 
@@ -433,6 +822,12 @@ DRI2ScreenInit(ScreenPtr pScreen, DRI2InfoPtr info)
     ds->DestroyBuffer  = info->DestroyBuffer;
     ds->CopyRegion     = info->CopyRegion;
 
+    if (info->version >= 4) {
+	ds->ScheduleSwap = info->ScheduleSwap;
+	ds->ScheduleWaitMSC = info->ScheduleWaitMSC;
+	ds->GetMSC = info->GetMSC;
+    }
+
     dixSetPrivate(&pScreen->devPrivates, dri2ScreenPrivateKey, ds);
 
     xf86DrvMsg(pScreen->myNum, X_INFO, "[DRI2] Setup complete\n");
diff --git a/hw/xfree86/dri2/dri2.h b/hw/xfree86/dri2/dri2.h
index 175471a..be14b9d 100644
--- a/hw/xfree86/dri2/dri2.h
+++ b/hw/xfree86/dri2/dri2.h
@@ -47,6 +47,9 @@ typedef struct {
 } DRI2BufferRec, *DRI2BufferPtr;
 
 typedef DRI2BufferRec DRI2Buffer2Rec, *DRI2Buffer2Ptr;
+typedef void (*DRI2SwapEventPtr)(ClientPtr client, void *data, int type,
+				 CARD64 ust, CARD64 msc, CARD64 sbc);
+
 
 typedef DRI2BufferPtr	(*DRI2CreateBuffersProcPtr)(DrawablePtr pDraw,
 						    unsigned int *attachments,
@@ -58,20 +61,98 @@ typedef void		(*DRI2CopyRegionProcPtr)(DrawablePtr pDraw,
 						 RegionPtr pRegion,
 						 DRI2BufferPtr pDestBuffer,
 						 DRI2BufferPtr pSrcBuffer);
-
 typedef void		(*DRI2WaitProcPtr)(WindowPtr pWin,
 					   unsigned int sequence);
-
+/**
+ * Schedule a buffer swap
+ *
+ * This callback is used to support glXSwapBuffers and the OML_sync_control
+ * extension (see it for a description of the params).
+ *
+ * Drivers should queue an event for the frame count that satisfies the
+ * parameters passed in.  If the event is in the future (i.e. the conditions
+ * aren't currently satisfied), the server may block the client at the next
+ * GLX request using DRI2WaitSwap. When the event arrives, drivers should call
+ * \c DRI2SwapComplete, which will handle waking the client and returning
+ * the appropriate data.
+ *
+ * The DDX is responsible for doing a flip, exchange, or blit of the swap
+ * when the corresponding event arrives.  The \c DRI2CanFlip and
+ * \c DRI2CanExchange functions can be used as helpers for this purpose.
+ *
+ * \param client client pointer (used for block/unblock)
+ * \param pDraw drawable whose count we want
+ * \param pDestBuffer current front buffer
+ * \param pSrcBuffer current back buffer
+ * \param target_msc frame count to wait for
+ * \param divisor divisor for condition equation
+ * \param remainder remainder for division equation
+ * \param func function to call when the swap completes
+ * \param data data for the callback \p func.
+ */
+typedef int		(*DRI2ScheduleSwapProcPtr)(ClientPtr client,
+						   DrawablePtr pDraw,
+						   DRI2BufferPtr pDestBuffer,
+						   DRI2BufferPtr pSrcBuffer,
+						   CARD64 *target_msc,
+						   CARD64 divisor,
+						   CARD64 remainder,
+						   DRI2SwapEventPtr func,
+						   void *data);
 typedef DRI2BufferPtr	(*DRI2CreateBufferProcPtr)(DrawablePtr pDraw,
 						   unsigned int attachment,
 						   unsigned int format);
 typedef void		(*DRI2DestroyBufferProcPtr)(DrawablePtr pDraw,
 						    DRI2BufferPtr buffer);
-
+/**
+ * Get current media stamp counter values
+ *
+ * This callback is used to support the SGI_video_sync and OML_sync_control
+ * extensions.
+ *
+ * Drivers should return the current frame counter and the timestamp from
+ * when the returned frame count was last incremented.
+ *
+ * The count should correspond to the screen where the drawable is currently
+ * visible.  If the drawable isn't visible (e.g. redirected), the server
+ * should return BadDrawable to the client, pending GLX spec updates to
+ * define this behavior.
+ *
+ * \param pDraw drawable whose count we want
+ * \param ust timestamp from when the count was last incremented.
+ * \param mst current frame count
+ */
+typedef int		(*DRI2GetMSCProcPtr)(DrawablePtr pDraw, CARD64 *ust,
+					     CARD64 *msc);
+/**
+ * Schedule a frame count related wait
+ *
+ * This callback is used to support the SGI_video_sync and OML_sync_control
+ * extensions.  See those specifications for details on how to handle
+ * the divisor and remainder parameters.
+ *
+ * Drivers should queue an event for the frame count that satisfies the
+ * parameters passed in.  If the event is in the future (i.e. the conditions
+ * aren't currently satisfied), the driver should block the client using
+ * \c DRI2BlockClient.  When the event arrives, drivers should call
+ * \c DRI2WaitMSCComplete, which will handle waking the client and returning
+ * the appropriate data.
+ *
+ * \param client client pointer (used for block/unblock)
+ * \param pDraw drawable whose count we want
+ * \param target_msc frame count to wait for
+ * \param divisor divisor for condition equation
+ * \param remainder remainder for division equation
+ */
+typedef int		(*DRI2ScheduleWaitMSCProcPtr)(ClientPtr client,
+						      DrawablePtr pDraw,
+						      CARD64 target_msc,
+						      CARD64 divisor,
+						      CARD64 remainder);
 /**
  * Version of the DRI2InfoRec structure defined in this header
  */
-#define DRI2INFOREC_VERSION 3
+#define DRI2INFOREC_VERSION 4
 
 typedef struct {
     unsigned int version;	/**< Version of this struct */
@@ -83,7 +164,9 @@ typedef struct {
     DRI2DestroyBufferProcPtr	DestroyBuffer;
     DRI2CopyRegionProcPtr	CopyRegion;
     DRI2WaitProcPtr		Wait;
-
+    DRI2ScheduleSwapProcPtr	ScheduleSwap;
+    DRI2GetMSCProcPtr		GetMSC;
+    DRI2ScheduleWaitMSCProcPtr	ScheduleWaitMSC;
 }  DRI2InfoRec, *DRI2InfoPtr;
 
 extern _X_EXPORT Bool DRI2ScreenInit(ScreenPtr	pScreen,
@@ -137,4 +220,38 @@ extern _X_EXPORT DRI2BufferPtr *DRI2GetBuffersWithFormat(DrawablePtr pDraw,
 	int *width, int *height, unsigned int *attachments, int count,
 	int *out_count);
 
+extern _X_EXPORT void DRI2SwapInterval(DrawablePtr pDrawable, int interval);
+extern _X_EXPORT int DRI2SwapBuffers(ClientPtr client, DrawablePtr pDrawable,
+				     CARD64 target_msc, CARD64 divisor,
+				     CARD64 remainder, CARD64 *swap_target,
+				     DRI2SwapEventPtr func, void *data);
+extern _X_EXPORT Bool DRI2WaitSwap(ClientPtr client, DrawablePtr pDrawable);
+
+extern _X_EXPORT int DRI2GetMSC(DrawablePtr pDrawable, CARD64 *ust,
+				CARD64 *msc, CARD64 *sbc);
+extern _X_EXPORT int DRI2WaitMSC(ClientPtr client, DrawablePtr pDrawable,
+				 CARD64 target_msc, CARD64 divisor,
+				 CARD64 remainder);
+extern _X_EXPORT int ProcDRI2WaitMSCReply(ClientPtr client, CARD64 ust,
+					  CARD64 msc, CARD64 sbc);
+extern _X_EXPORT int DRI2WaitSBC(ClientPtr client, DrawablePtr pDraw,
+				 CARD64 target_sbc, CARD64 *ust, CARD64 *msc,
+				 CARD64 *sbc);
+extern _X_EXPORT Bool DRI2ThrottleClient(ClientPtr client, DrawablePtr pDraw);
+
+extern _X_EXPORT Bool DRI2CanFlip(DrawablePtr pDraw);
+
+extern _X_EXPORT Bool DRI2CanExchange(DrawablePtr pDraw);
+
+extern _X_EXPORT void DRI2BlockClient(ClientPtr client, DrawablePtr pDraw);
+
+extern _X_EXPORT void DRI2SwapComplete(ClientPtr client, DrawablePtr pDraw,
+				       int frame, unsigned int tv_sec,
+				       unsigned int tv_usec, int type,
+				       DRI2SwapEventPtr swap_complete,
+				       void *swap_data);
+extern _X_EXPORT void DRI2WaitMSCComplete(ClientPtr client, DrawablePtr pDraw,
+					  int frame, unsigned int tv_sec,
+					  unsigned int tv_usec);
+
 #endif
diff --git a/hw/xfree86/dri2/dri2ext.c b/hw/xfree86/dri2/dri2ext.c
index 7d6064a..fb8f908 100644
--- a/hw/xfree86/dri2/dri2ext.c
+++ b/hw/xfree86/dri2/dri2ext.c
@@ -259,6 +259,9 @@ ProcDRI2GetBuffers(ClientPtr client)
 		       &pDrawable, &status))
 	return status;
 
+    if (DRI2ThrottleClient(client, pDrawable))
+	return client->noClientException;
+
     attachments = (unsigned int *) &stuff[1];
     buffers = DRI2GetBuffers(pDrawable, &width, &height,
 			     attachments, stuff->count, &count);
@@ -283,6 +286,9 @@ ProcDRI2GetBuffersWithFormat(ClientPtr client)
 		       &pDrawable, &status))
 	return status;
 
+    if (DRI2ThrottleClient(client, pDrawable))
+	return client->noClientException;
+
     attachments = (unsigned int *) &stuff[1];
     buffers = DRI2GetBuffersWithFormat(pDrawable, &width, &height,
 				       attachments, stuff->count, &count);
@@ -329,6 +335,185 @@ ProcDRI2CopyRegion(ClientPtr client)
     return client->noClientException;
 }
 
+static void
+load_swap_reply(xDRI2SwapBuffersReply *rep, CARD64 sbc)
+{
+    rep->swap_hi = sbc >> 32;
+    rep->swap_lo = sbc & 0xffffffff;
+}
+
+static CARD64
+vals_to_card64(CARD32 lo, CARD32 hi)
+{
+    return (CARD64)hi << 32 | lo;
+}
+
+static int
+ProcDRI2SwapBuffers(ClientPtr client)
+{
+    REQUEST(xDRI2SwapBuffersReq);
+    xDRI2SwapBuffersReply rep;
+    DrawablePtr pDrawable;
+    CARD64 target_msc, divisor, remainder, swap_target;
+    int status;
+
+    REQUEST_SIZE_MATCH(xDRI2SwapBuffersReq);
+
+    if (!validDrawable(client, stuff->drawable,
+		       DixReadAccess | DixWriteAccess, &pDrawable, &status))
+	return status;
+
+    target_msc = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi);
+    divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi);
+    remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi);
+
+    status = DRI2SwapBuffers(client, pDrawable, target_msc, divisor, remainder,
+			     &swap_target, NULL, pDrawable);
+    if (status != Success)
+	return BadDrawable;
+
+    rep.type = X_Reply;
+    rep.length = 0;
+    rep.sequenceNumber = client->sequence;
+    load_swap_reply(&rep, swap_target);
+
+    WriteToClient(client, sizeof(xDRI2SwapBuffersReply), &rep);
+
+    return client->noClientException;
+}
+
+static void
+load_msc_reply(xDRI2MSCReply *rep, CARD64 ust, CARD64 msc, CARD64 sbc)
+{
+    rep->ust_hi = ust >> 32;
+    rep->ust_lo = ust & 0xffffffff;
+    rep->msc_hi = msc >> 32;
+    rep->msc_lo = msc & 0xffffffff;
+    rep->sbc_hi = sbc >> 32;
+    rep->sbc_lo = sbc & 0xffffffff;
+}
+
+static int
+ProcDRI2GetMSC(ClientPtr client)
+{
+    REQUEST(xDRI2GetMSCReq);
+    xDRI2MSCReply rep;
+    DrawablePtr pDrawable;
+    CARD64 ust, msc, sbc;
+    int status;
+
+    REQUEST_SIZE_MATCH(xDRI2GetMSCReq);
+
+    if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
+		       &status))
+	return status;
+
+    status = DRI2GetMSC(pDrawable, &ust, &msc, &sbc);
+    if (status != Success)
+	return status;
+
+    rep.type = X_Reply;
+    rep.length = 0;
+    rep.sequenceNumber = client->sequence;
+    load_msc_reply(&rep, ust, msc, sbc);
+
+    WriteToClient(client, sizeof(xDRI2MSCReply), &rep);
+
+    return client->noClientException;
+}
+
+static int
+ProcDRI2WaitMSC(ClientPtr client)
+{
+    REQUEST(xDRI2WaitMSCReq);
+    DrawablePtr pDrawable;
+    CARD64 target, divisor, remainder;
+    int status;
+
+    /* FIXME: in restart case, client may be gone at this point */
+
+    REQUEST_SIZE_MATCH(xDRI2WaitMSCReq);
+
+    if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
+		       &status))
+	return status;
+
+    target = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi);
+    divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi);
+    remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi);
+
+    status = DRI2WaitMSC(client, pDrawable, target, divisor, remainder);
+    if (status != Success)
+	return status;
+
+    return client->noClientException;
+}
+
+int
+ProcDRI2WaitMSCReply(ClientPtr client, CARD64 ust, CARD64 msc, CARD64 sbc)
+{
+    xDRI2MSCReply rep;
+
+    rep.type = X_Reply;
+    rep.length = 0;
+    rep.sequenceNumber = client->sequence;
+    load_msc_reply(&rep, ust, msc, sbc);
+
+    WriteToClient(client, sizeof(xDRI2MSCReply), &rep);
+
+    return client->noClientException;
+}
+
+static int
+ProcDRI2SwapInterval(ClientPtr client)
+{
+    REQUEST(xDRI2SwapIntervalReq);
+    DrawablePtr pDrawable;
+    int status;
+
+    /* FIXME: in restart case, client may be gone at this point */
+
+    REQUEST_SIZE_MATCH(xDRI2SwapIntervalReq);
+
+    if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess,
+		       &pDrawable, &status))
+	return status;
+
+    DRI2SwapInterval(pDrawable, stuff->interval);
+
+    return client->noClientException;
+}
+
+static int
+ProcDRI2WaitSBC(ClientPtr client)
+{
+    REQUEST(xDRI2WaitSBCReq);
+    xDRI2MSCReply rep;
+    DrawablePtr pDrawable;
+    CARD64 target, ust, msc, sbc;
+    int status;
+
+    REQUEST_SIZE_MATCH(xDRI2WaitSBCReq);
+
+    if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
+		       &status))
+	return status;
+
+    target = vals_to_card64(stuff->target_sbc_lo, stuff->target_sbc_hi);
+    status = DRI2WaitSBC(client, pDrawable, target, &ust, &msc, &sbc);
+    if (status != Success)
+	return status;
+
+    rep.type = X_Reply;
+    rep.length = 0;
+    rep.sequenceNumber = client->sequence;
+    load_msc_reply(&rep, ust, msc, sbc);
+
+    WriteToClient(client, sizeof(xDRI2MSCReply), &rep);
+
+    return client->noClientException;
+}
+
 static int
 ProcDRI2Dispatch (ClientPtr client)
 {
@@ -357,6 +542,16 @@ ProcDRI2Dispatch (ClientPtr client)
 	return ProcDRI2CopyRegion(client);
     case X_DRI2GetBuffersWithFormat:
 	return ProcDRI2GetBuffersWithFormat(client);
+    case X_DRI2SwapBuffers:
+	return ProcDRI2SwapBuffers(client);
+    case X_DRI2GetMSC:
+	return ProcDRI2GetMSC(client);
+    case X_DRI2WaitMSC:
+	return ProcDRI2WaitMSC(client);
+    case X_DRI2WaitSBC:
+	return ProcDRI2WaitSBC(client);
+    case X_DRI2SwapInterval:
+	return ProcDRI2SwapInterval(client);
     default:
 	return BadRequest;
     }
diff --git a/include/protocol-versions.h b/include/protocol-versions.h
index d688c66..c74b7fa 100644
--- a/include/protocol-versions.h
+++ b/include/protocol-versions.h
@@ -53,7 +53,7 @@
 
 /* DRI2 */
 #define SERVER_DRI2_MAJOR_VERSION		1
-#define SERVER_DRI2_MINOR_VERSION		1
+#define SERVER_DRI2_MINOR_VERSION		2
 
 /* Generic event extension */
 #define SERVER_GE_MAJOR_VERSION                 1


More information about the xorg-commit mailing list