xserver: Branch 'master' - 5 commits

Adam Jackson ajax at kemper.freedesktop.org
Wed Feb 14 22:14:59 UTC 2018


 configure.ac                   |    2 
 glx/Makefile.am                |    8 
 glx/createcontext.c            |    2 
 glx/glxcmds.c                  |  283 ++++++----------------
 glx/glxcmdsswap.c              |   98 -------
 glx/glxcontext.h               |   10 
 glx/glxext.c                   |  372 +++++++++++++++++++----------
 glx/glxext.h                   |    5 
 glx/glxscreens.h               |    1 
 glx/glxserver.h                |   15 -
 glx/meson.build                |   21 +
 glx/vnd_dispatch_stubs.c       |  525 +++++++++++++++++++++++++++++++++++++++++
 glx/vndcmds.c                  |  483 +++++++++++++++++++++++++++++++++++++
 glx/vndext.c                   |  306 +++++++++++++++++++++++
 glx/vndserver.h                |  119 +++++++++
 glx/vndservermapping.c         |  196 +++++++++++++++
 glx/vndservervendor.c          |   91 +++++++
 glx/vndservervendor.h          |   68 +++++
 glx/xfont.c                    |    2 
 hw/dmx/dmxinit.c               |    3 
 hw/kdrive/ephyr/ephyr.c        |    2 
 hw/kdrive/ephyr/ephyrinit.c    |   16 -
 hw/kdrive/ephyr/meson.build    |    1 
 hw/kdrive/src/kdrive.c         |    3 
 hw/vfb/InitOutput.c            |   17 -
 hw/vfb/meson.build             |    3 
 hw/xfree86/Makefile.am         |    5 
 hw/xfree86/common/xf86Init.c   |    2 
 hw/xfree86/dixmods/glxmodule.c |    7 
 hw/xfree86/meson.build         |    1 
 hw/xnest/Init.c                |    7 
 hw/xquartz/darwin.c            |    4 
 hw/xquartz/quartz.c            |   21 -
 hw/xwayland/Makefile.am        |    1 
 hw/xwayland/meson.build        |    1 
 hw/xwayland/xwayland.c         |    5 
 hw/xwin/InitOutput.c           |    1 
 include/Makefile.am            |    1 
 include/extinit.h              |    1 
 include/glx_extinit.h          |    8 
 include/glxvndabi.h            |  307 +++++++++++++++++++++++
 include/meson.build            |    1 
 mi/miinitext.c                 |  176 ++++---------
 test/Makefile.am               |    4 
 44 files changed, 2579 insertions(+), 626 deletions(-)

New commits:
commit 133bd4443be6b76a36afadfae0905b832e998165
Author: Adam Jackson <ajax at redhat.com>
Date:   Wed Jan 10 13:05:48 2018 -0500

    glx: Large commands are context state, not client state
    
    There's no reason a multithreaded client shouldn't be allowed to
    interleave other requests (for other contexts) with a RenderLarge. Move
    the check into __glXForceCurrent, and store the state in the context not
    the client.
    
    Signed-off-by: Adam Jackson <ajax at redhat.com>

diff --git a/glx/glxcmds.c b/glx/glxcmds.c
index c5d6324d3..6785e9db3 100644
--- a/glx/glxcmds.c
+++ b/glx/glxcmds.c
@@ -1949,6 +1949,18 @@ __glXDisp_GetDrawableAttributesSGIX(__GLXclientState * cl, GLbyte * pc)
 */
 
 /*
+** Reset state used to keep track of large (multi-request) commands.
+*/
+static void
+ResetLargeCommandStatus(__GLXcontext *cx)
+{
+    cx->largeCmdBytesSoFar = 0;
+    cx->largeCmdBytesTotal = 0;
+    cx->largeCmdRequestsSoFar = 0;
+    cx->largeCmdRequestsTotal = 0;
+}
+
+/*
 ** Execute all the drawing commands in a request.
 */
 int
@@ -2079,8 +2091,6 @@ __glXDisp_RenderLarge(__GLXclientState * cl, GLbyte * pc)
 
     glxc = __glXForceCurrent(cl, req->contextTag, &error);
     if (!glxc) {
-        /* Reset in case this isn't 1st request. */
-        __glXResetLargeCommandStatus(cl);
         return error;
     }
     if (safe_pad(req->dataBytes) < 0)
@@ -2093,12 +2103,12 @@ __glXDisp_RenderLarge(__GLXclientState * cl, GLbyte * pc)
     if ((req->length << 2) != safe_pad(dataBytes) + sz_xGLXRenderLargeReq) {
         client->errorValue = req->length;
         /* Reset in case this isn't 1st request. */
-        __glXResetLargeCommandStatus(cl);
+        ResetLargeCommandStatus(glxc);
         return BadLength;
     }
     pc += sz_xGLXRenderLargeReq;
 
-    if (cl->largeCmdRequestsSoFar == 0) {
+    if (glxc->largeCmdRequestsSoFar == 0) {
         __GLXrenderSizeData entry;
         int extra = 0;
         int left = (req->length << 2) - sz_xGLXRenderLargeReq;
@@ -2157,21 +2167,21 @@ __glXDisp_RenderLarge(__GLXclientState * cl, GLbyte * pc)
         /*
          ** Make enough space in the buffer, then copy the entire request.
          */
-        if (cl->largeCmdBufSize < cmdlen) {
-	    GLbyte *newbuf = cl->largeCmdBuf;
+        if (glxc->largeCmdBufSize < cmdlen) {
+	    GLbyte *newbuf = glxc->largeCmdBuf;
 
 	    if (!(newbuf = realloc(newbuf, cmdlen)))
 		return BadAlloc;
 
-	    cl->largeCmdBuf = newbuf;
-            cl->largeCmdBufSize = cmdlen;
+	    glxc->largeCmdBuf = newbuf;
+            glxc->largeCmdBufSize = cmdlen;
         }
-        memcpy(cl->largeCmdBuf, pc, dataBytes);
+        memcpy(glxc->largeCmdBuf, pc, dataBytes);
 
-        cl->largeCmdBytesSoFar = dataBytes;
-        cl->largeCmdBytesTotal = cmdlen;
-        cl->largeCmdRequestsSoFar = 1;
-        cl->largeCmdRequestsTotal = req->requestTotal;
+        glxc->largeCmdBytesSoFar = dataBytes;
+        glxc->largeCmdBytesTotal = cmdlen;
+        glxc->largeCmdRequestsSoFar = 1;
+        glxc->largeCmdRequestsTotal = req->requestTotal;
         return Success;
 
     }
@@ -2185,37 +2195,37 @@ __glXDisp_RenderLarge(__GLXclientState * cl, GLbyte * pc)
         /*
          ** Check the request number and the total request count.
          */
-        if (req->requestNumber != cl->largeCmdRequestsSoFar + 1) {
+        if (req->requestNumber != glxc->largeCmdRequestsSoFar + 1) {
             client->errorValue = req->requestNumber;
-            __glXResetLargeCommandStatus(cl);
+            ResetLargeCommandStatus(glxc);
             return __glXError(GLXBadLargeRequest);
         }
-        if (req->requestTotal != cl->largeCmdRequestsTotal) {
+        if (req->requestTotal != glxc->largeCmdRequestsTotal) {
             client->errorValue = req->requestTotal;
-            __glXResetLargeCommandStatus(cl);
+            ResetLargeCommandStatus(glxc);
             return __glXError(GLXBadLargeRequest);
         }
 
         /*
          ** Check that we didn't get too much data.
          */
-        if ((bytesSoFar = safe_add(cl->largeCmdBytesSoFar, dataBytes)) < 0) {
+        if ((bytesSoFar = safe_add(glxc->largeCmdBytesSoFar, dataBytes)) < 0) {
             client->errorValue = dataBytes;
-            __glXResetLargeCommandStatus(cl);
+            ResetLargeCommandStatus(glxc);
             return __glXError(GLXBadLargeRequest);
         }
 
-        if (bytesSoFar > cl->largeCmdBytesTotal) {
+        if (bytesSoFar > glxc->largeCmdBytesTotal) {
             client->errorValue = dataBytes;
-            __glXResetLargeCommandStatus(cl);
+            ResetLargeCommandStatus(glxc);
             return __glXError(GLXBadLargeRequest);
         }
 
-        memcpy(cl->largeCmdBuf + cl->largeCmdBytesSoFar, pc, dataBytes);
-        cl->largeCmdBytesSoFar += dataBytes;
-        cl->largeCmdRequestsSoFar++;
+        memcpy(glxc->largeCmdBuf + glxc->largeCmdBytesSoFar, pc, dataBytes);
+        glxc->largeCmdBytesSoFar += dataBytes;
+        glxc->largeCmdRequestsSoFar++;
 
-        if (req->requestNumber == cl->largeCmdRequestsTotal) {
+        if (req->requestNumber == glxc->largeCmdRequestsTotal) {
             __GLXdispatchRenderProcPtr proc;
 
             /*
@@ -2231,12 +2241,12 @@ __glXDisp_RenderLarge(__GLXclientState * cl, GLbyte * pc)
              ** fixes a bug that did not allow large commands of odd sizes to
              ** be accepted by the server.
              */
-            if (safe_pad(cl->largeCmdBytesSoFar) != cl->largeCmdBytesTotal) {
+            if (safe_pad(glxc->largeCmdBytesSoFar) != glxc->largeCmdBytesTotal) {
                 client->errorValue = dataBytes;
-                __glXResetLargeCommandStatus(cl);
+                ResetLargeCommandStatus(glxc);
                 return __glXError(GLXBadLargeRequest);
             }
-            hdr = (__GLXrenderLargeHeader *) cl->largeCmdBuf;
+            hdr = (__GLXrenderLargeHeader *) glxc->largeCmdBuf;
             /*
              ** The opcode and length field in the header had already been
              ** swapped when the first request was received.
@@ -2256,12 +2266,12 @@ __glXDisp_RenderLarge(__GLXclientState * cl, GLbyte * pc)
             /*
              ** Skip over the header and execute the command.
              */
-            (*proc) (cl->largeCmdBuf + __GLX_RENDER_LARGE_HDR_SIZE);
+            (*proc) (glxc->largeCmdBuf + __GLX_RENDER_LARGE_HDR_SIZE);
 
             /*
              ** Reset for the next RenderLarge series.
              */
-            __glXResetLargeCommandStatus(cl);
+            ResetLargeCommandStatus(glxc);
         }
         else {
             /*
diff --git a/glx/glxcontext.h b/glx/glxcontext.h
index 19d347fdb..8f623b4b4 100644
--- a/glx/glxcontext.h
+++ b/glx/glxcontext.h
@@ -113,6 +113,16 @@ struct __GLXcontext {
     GLint selectBufSize;        /* number of elements allocated */
 
     /*
+     ** Keep track of large rendering commands, which span multiple requests.
+     */
+    GLint largeCmdBytesSoFar;   /* bytes received so far        */
+    GLint largeCmdBytesTotal;   /* total bytes expected         */
+    GLint largeCmdRequestsSoFar;        /* requests received so far     */
+    GLint largeCmdRequestsTotal;        /* total requests expected      */
+    GLbyte *largeCmdBuf;
+    GLint largeCmdBufSize;
+
+    /*
      ** The drawable private this context is bound to
      */
     __GLXdrawable *drawPriv;
diff --git a/glx/glxext.c b/glx/glxext.c
index a345c437a..a51c13ff1 100644
--- a/glx/glxext.c
+++ b/glx/glxext.c
@@ -66,18 +66,6 @@ static int __glXDispatch(ClientPtr);
 static GLboolean __glXFreeContext(__GLXcontext * cx);
 
 /*
-** Reset state used to keep track of large (multi-request) commands.
-*/
-void
-__glXResetLargeCommandStatus(__GLXclientState * cl)
-{
-    cl->largeCmdBytesSoFar = 0;
-    cl->largeCmdBytesTotal = 0;
-    cl->largeCmdRequestsSoFar = 0;
-    cl->largeCmdRequestsTotal = 0;
-}
-
-/*
  * This procedure is called when the client who created the context goes away
  * OR when glXDestroyContext is called. If the context is current for a client
  * the dispatch layer will have moved the context struct to a fake resource ID
@@ -188,6 +176,7 @@ __glXFreeContext(__GLXcontext * cx)
 
     free(cx->feedbackBuf);
     free(cx->selectBuf);
+    free(cx->largeCmdBuf);
     if (cx == lastGLContext) {
         lastGLContext = NULL;
     }
@@ -270,7 +259,6 @@ glxClientCallback(CallbackListPtr *list, void *closure, void *data)
     switch (pClient->clientState) {
     case ClientStateGone:
         free(cl->returnBuf);
-        free(cl->largeCmdBuf);
         free(cl->GLClientextensions);
         cl->returnBuf = NULL;
         cl->GLClientextensions = NULL;
@@ -591,6 +579,9 @@ xorgGlxCreateVendor(void)
 __GLXcontext *
 __glXForceCurrent(__GLXclientState * cl, GLXContextTag tag, int *error)
 {
+    ClientPtr client = cl->client;
+    REQUEST(xGLXSingleReq);
+
     __GLXcontext *cx;
 
     /*
@@ -604,6 +595,13 @@ __glXForceCurrent(__GLXclientState * cl, GLXContextTag tag, int *error)
         return 0;
     }
 
+    /* If we're expecting a glXRenderLarge request, this better be one. */
+    if (cx->largeCmdRequestsSoFar != 0 && stuff->glxCode != X_GLXRenderLarge) {
+        client->errorValue = stuff->glxCode;
+        *error = __glXError(GLXBadLargeRequest);
+        return 0;
+    }
+
     if (!cx->isDirect) {
         if (cx->drawPriv == NULL) {
             /*
@@ -710,13 +708,6 @@ __glXDispatch(ClientPtr client)
     opcode = stuff->glxCode;
     cl = glxGetClient(client);
 
-    /*
-     ** If we're expecting a glXRenderLarge request, this better be one.
-     */
-    if ((cl->largeCmdRequestsSoFar != 0) && (opcode != X_GLXRenderLarge)) {
-        client->errorValue = stuff->glxCode;
-        return __glXError(GLXBadLargeRequest);
-    }
 
     if (!cl->client)
         cl->client = client;
diff --git a/glx/glxext.h b/glx/glxext.h
index af59165bf..5ad497e4a 100644
--- a/glx/glxext.h
+++ b/glx/glxext.h
@@ -57,7 +57,6 @@ extern Bool __glXAddContext(__GLXcontext * cx);
 extern void __glXErrorCallBack(GLenum code);
 extern void __glXClearErrorOccured(void);
 extern GLboolean __glXErrorOccured(void);
-extern void __glXResetLargeCommandStatus(__GLXclientState *);
 
 extern const char GLServerVersion[];
 extern int DoGetString(__GLXclientState * cl, GLbyte * pc, GLboolean need_swap);
diff --git a/glx/glxserver.h b/glx/glxserver.h
index 8ffde2342..60bdeb00d 100644
--- a/glx/glxserver.h
+++ b/glx/glxserver.h
@@ -115,16 +115,6 @@ struct __GLXclientStateRec {
     GLbyte *returnBuf;
     GLint returnBufSize;
 
-    /*
-     ** Keep track of large rendering commands, which span multiple requests.
-     */
-    GLint largeCmdBytesSoFar;   /* bytes received so far        */
-    GLint largeCmdBytesTotal;   /* total bytes expected         */
-    GLint largeCmdRequestsSoFar;        /* requests received so far     */
-    GLint largeCmdRequestsTotal;        /* total requests expected      */
-    GLbyte *largeCmdBuf;
-    GLint largeCmdBufSize;
-
     /* Back pointer to X client record */
     ClientPtr client;
 
commit 5d87e4f71355272c8da38c83f493b826623301cc
Author: Adam Jackson <ajax at redhat.com>
Date:   Wed Jan 10 13:05:47 2018 -0500

    miinitext: Remove separate extension toggle list
    
    This was only separate because GLX was loadable. The frontend is now
    linked statically, so we can use the static extension list directly.
    
    Signed-off-by: Adam Jackson <ajax at redhat.com>

diff --git a/mi/miinitext.c b/mi/miinitext.c
index c8162337c..e55073bf3 100644
--- a/mi/miinitext.c
+++ b/mi/miinitext.c
@@ -106,128 +106,6 @@ SOFTWARE.
 #include "micmap.h"
 #include "globals.h"
 
-/* The following is only a small first step towards run-time
- * configurable extensions.
- */
-typedef struct {
-    const char *name;
-    Bool *disablePtr;
-} ExtensionToggle;
-
-static ExtensionToggle ExtensionToggleList[] = {
-    /* sort order is extension name string as shown in xdpyinfo */
-    {"Generic Events", &noGEExtension},
-#ifdef COMPOSITE
-    {"Composite", &noCompositeExtension},
-#endif
-#ifdef DAMAGE
-    {"DAMAGE", &noDamageExtension},
-#endif
-#ifdef DBE
-    {"DOUBLE-BUFFER", &noDbeExtension},
-#endif
-#ifdef DPMSExtension
-    {"DPMS", &noDPMSExtension},
-#endif
-#ifdef GLXEXT
-    {"GLX", &noGlxExtension},
-#endif
-#ifdef SCREENSAVER
-    {"MIT-SCREEN-SAVER", &noScreenSaverExtension},
-#endif
-#ifdef MITSHM
-    {"MIT-SHM", &noMITShmExtension},
-#endif
-#ifdef RANDR
-    {"RANDR", &noRRExtension},
-#endif
-    {"RENDER", &noRenderExtension},
-#ifdef XCSECURITY
-    {"SECURITY", &noSecurityExtension},
-#endif
-#ifdef RES
-    {"X-Resource", &noResExtension},
-#endif
-#ifdef XF86BIGFONT
-    {"XFree86-Bigfont", &noXFree86BigfontExtension},
-#endif
-#ifdef XORGSERVER
-#ifdef XFreeXDGA
-    {"XFree86-DGA", &noXFree86DGAExtension},
-#endif
-#ifdef XF86DRI
-    {"XFree86-DRI", &noXFree86DRIExtension},
-#endif
-#ifdef XF86VIDMODE
-    {"XFree86-VidModeExtension", &noXFree86VidModeExtension},
-#endif
-#endif
-    {"XFIXES", &noXFixesExtension},
-#ifdef PANORAMIX
-    {"XINERAMA", &noPanoramiXExtension},
-#endif
-    {"XInputExtension", NULL},
-    {"XKEYBOARD", NULL},
-#ifdef XSELINUX
-    {"SELinux", &noSELinuxExtension},
-#endif
-    {"XTEST", &noTestExtensions},
-#ifdef XV
-    {"XVideo", &noXvExtension},
-#endif
-};
-
-Bool
-EnableDisableExtension(const char *name, Bool enable)
-{
-    ExtensionToggle *ext;
-    int i;
-
-    for (i = 0; i < ARRAY_SIZE(ExtensionToggleList); i++) {
-        ext = &ExtensionToggleList[i];
-        if (strcmp(name, ext->name) == 0) {
-            if (ext->disablePtr != NULL) {
-                *ext->disablePtr = !enable;
-                return TRUE;
-            }
-            else {
-                /* Extension is always on, impossible to disable */
-                return enable;  /* okay if they wanted to enable,
-                                   fail if they tried to disable */
-            }
-        }
-    }
-
-    return FALSE;
-}
-
-void
-EnableDisableExtensionError(const char *name, Bool enable)
-{
-    ExtensionToggle *ext;
-    int i;
-    Bool found = FALSE;
-
-    for (i = 0; i < ARRAY_SIZE(ExtensionToggleList); i++) {
-        ext = &ExtensionToggleList[i];
-        if ((strcmp(name, ext->name) == 0) && (ext->disablePtr == NULL)) {
-            ErrorF("[mi] Extension \"%s\" can not be disabled\n", name);
-            found = TRUE;
-            break;
-        }
-    }
-    if (found == FALSE)
-        ErrorF("[mi] Extension \"%s\" is not recognized\n", name);
-    ErrorF("[mi] Only the following extensions can be run-time %s:\n",
-           enable ? "enabled" : "disabled");
-    for (i = 0; i < ARRAY_SIZE(ExtensionToggleList); i++) {
-        ext = &ExtensionToggleList[i];
-        if (ext->disablePtr != NULL) {
-            ErrorF("[mi]    %s\n", ext->name);
-        }
-    }
-}
-
 /* List of built-in (statically linked) extensions */
 static const ExtensionModule staticExtensions[] = {
     {GEExtensionInit, "Generic Event Extension", &noGEExtension},
@@ -303,6 +181,57 @@ static const ExtensionModule staticExtensions[] = {
 #endif
 };
 
+Bool
+EnableDisableExtension(const char *name, Bool enable)
+{
+    const ExtensionModule *ext;
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(staticExtensions); i++) {
+        ext = &staticExtensions[i];
+        if (strcmp(name, ext->name) == 0) {
+            if (ext->disablePtr != NULL) {
+                *ext->disablePtr = !enable;
+                return TRUE;
+            }
+            else {
+                /* Extension is always on, impossible to disable */
+                return enable;  /* okay if they wanted to enable,
+                                   fail if they tried to disable */
+            }
+        }
+    }
+
+    return FALSE;
+}
+
+void
+EnableDisableExtensionError(const char *name, Bool enable)
+{
+    const ExtensionModule *ext;
+    int i;
+    Bool found = FALSE;
+
+    for (i = 0; i < ARRAY_SIZE(staticExtensions); i++) {
+        ext = &staticExtensions[i];
+        if ((strcmp(name, ext->name) == 0) && (ext->disablePtr == NULL)) {
+            ErrorF("[mi] Extension \"%s\" can not be disabled\n", name);
+            found = TRUE;
+            break;
+        }
+    }
+    if (found == FALSE)
+        ErrorF("[mi] Extension \"%s\" is not recognized\n", name);
+    ErrorF("[mi] Only the following extensions can be run-time %s:\n",
+           enable ? "enabled" : "disabled");
+    for (i = 0; i < ARRAY_SIZE(staticExtensions); i++) {
+        ext = &staticExtensions[i];
+        if (ext->disablePtr != NULL) {
+            ErrorF("[mi]    %s\n", ext->name);
+        }
+    }
+}
+
 static ExtensionModule *ExtensionModuleList = NULL;
 static int numExtensionModules = 0;
 
commit 67c303fff303f94b62f03a76de97116c6ebcfda9
Author: Adam Jackson <ajax at redhat.com>
Date:   Wed Jan 10 13:05:46 2018 -0500

    miinitext: Load GLX on the mi path
    
    Add a stub for Xnest so it continues to link, but otherwise we support
    GLX on every server so there's no need to make every DDX add it.
    
    Signed-off-by: Adam Jackson <ajax at redhat.com>

diff --git a/hw/dmx/dmxinit.c b/hw/dmx/dmxinit.c
index 8f17f4ddf..07154d648 100644
--- a/hw/dmx/dmxinit.c
+++ b/hw/dmx/dmxinit.c
@@ -536,9 +536,6 @@ static void dmxAddExtensions(void)
 {
     const ExtensionModule dmxExtensions[] = {
         { DMXExtensionInit, DMX_EXTENSION_NAME, NULL },
-#ifdef GLXEXT
-        { GlxExtensionInit, "GLX", &noGlxExtension },
-#endif
     };
 
     LoadExtensionList(dmxExtensions, ARRAY_SIZE(dmxExtensions), TRUE);
diff --git a/hw/kdrive/ephyr/ephyrinit.c b/hw/kdrive/ephyr/ephyrinit.c
index 947a6e8ef..abc35dfca 100644
--- a/hw/kdrive/ephyr/ephyrinit.c
+++ b/hw/kdrive/ephyr/ephyrinit.c
@@ -58,25 +58,9 @@ InitCard(char *name)
     KdCardInfoAdd(&ephyrFuncs, 0);
 }
 
-static const ExtensionModule ephyrExtensions[] = {
-#ifdef GLXEXT
- { GlxExtensionInit, "GLX", &noGlxExtension },
-#endif
-};
-
-static
-void ephyrExtensionInit(void)
-{
-    LoadExtensionList(ephyrExtensions, ARRAY_SIZE(ephyrExtensions), TRUE);
-}
-
-
 void
 InitOutput(ScreenInfo * pScreenInfo, int argc, char **argv)
 {
-    if (serverGeneration == 1)
-        ephyrExtensionInit();
-
     KdInitOutput(pScreenInfo, argc, argv);
 }
 
diff --git a/hw/vfb/InitOutput.c b/hw/vfb/InitOutput.c
index 2b7bca5fa..407f2afcd 100644
--- a/hw/vfb/InitOutput.c
+++ b/hw/vfb/InitOutput.c
@@ -957,27 +957,12 @@ vfbScreenInit(ScreenPtr pScreen, int argc, char **argv)
 
 }                               /* end vfbScreenInit */
 
-static const ExtensionModule vfbExtensions[] = {
-#ifdef GLXEXT
-    { GlxExtensionInit, "GLX", &noGlxExtension },
-#endif
-};
-
-static
-void vfbExtensionInit(void)
-{
-    LoadExtensionList(vfbExtensions, ARRAY_SIZE(vfbExtensions), TRUE);
-}
-
 void
 InitOutput(ScreenInfo * screen_info, int argc, char **argv)
 {
     int i;
     int NumFormats = 0;
 
-    if (serverGeneration == 1)
-        vfbExtensionInit();
-
     /* initialize pixmap formats */
 
     /* must have a pixmap depth to match every screen depth */
diff --git a/hw/xfree86/dixmods/glxmodule.c b/hw/xfree86/dixmods/glxmodule.c
index c3d92fa92..2215c8867 100644
--- a/hw/xfree86/dixmods/glxmodule.c
+++ b/hw/xfree86/dixmods/glxmodule.c
@@ -47,10 +47,6 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 static MODULESETUPPROTO(glxSetup);
 
-static const ExtensionModule GLXExt[] = {
-    { GlxExtensionInit, "GLX", &noGlxExtension },
-};
-
 static XF86ModuleVersionInfo VersRec = {
     "glx",
     MODULEVENDORSTRING,
@@ -85,7 +81,5 @@ glxSetup(void *module, void *opts, int *errmaj, int *errmin)
         GlxPushProvider(provider);
     xorgGlxCreateVendor();
 
-    LoadExtensionList(GLXExt, ARRAY_SIZE(GLXExt), FALSE);
-
     return module;
 }
diff --git a/hw/xnest/Init.c b/hw/xnest/Init.c
index e8a700e88..b45685216 100644
--- a/hw/xnest/Init.c
+++ b/hw/xnest/Init.c
@@ -47,6 +47,13 @@ is" without express or implied warranty.
 
 Bool xnestDoFullGeneration = True;
 
+#ifdef GLXEXT
+void
+GlxExtensionInit(void)
+{
+}
+#endif
+
 void
 InitOutput(ScreenInfo * screen_info, int argc, char *argv[])
 {
diff --git a/hw/xquartz/quartz.c b/hw/xquartz/quartz.c
index c8ea3bf8b..980aa4a36 100644
--- a/hw/xquartz/quartz.c
+++ b/hw/xquartz/quartz.c
@@ -149,25 +149,6 @@ QuartzSetupScreen(int index,
     return TRUE;
 }
 
-static const ExtensionModule quartzExtensions[] = {
-    /* PseudoramiX needs to be done before RandR, so
-     * it is in miinitext.c until it can be reordered.
-     * { PseudoramiXExtensionInit, "PseudoramiX", &noPseudoramiXExtension },
-     */
-#ifdef GLXEXT
-    {GlxExtensionInit, "GLX", &noGlxExtension},
-#endif
-};
-
-/*
- * QuartzExtensionInit
- * Initialises XQuartz-specific extensions.
- */
-static void QuartzExtensionInit(void)
-{
-    LoadExtensionList(quartzExtensions, ARRAY_SIZE(quartzExtensions), TRUE);
-}
-
 /*
  * QuartzInitOutput
  *  Quartz display initialization.
@@ -208,8 +189,6 @@ QuartzInitOutput(int argc,
 
     // Do display mode specific initialization
     quartzProcs->DisplayInit();
-
-    QuartzExtensionInit();
 }
 
 /*
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 7aba7bae2..73bc47a67 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -1067,9 +1067,6 @@ xwl_log_handler(const char *format, va_list args)
 }
 
 static const ExtensionModule xwayland_extensions[] = {
-#ifdef GLXEXT
-    { GlxExtensionInit, "GLX", &noGlxExtension },
-#endif
 #ifdef XF86VIDMODE
     { xwlVidModeExtensionInit, XF86VIDMODENAME, &noXFree86VidModeExtension },
 #endif
diff --git a/hw/xwin/InitOutput.c b/hw/xwin/InitOutput.c
index 95fc68bea..ef19f7941 100644
--- a/hw/xwin/InitOutput.c
+++ b/hw/xwin/InitOutput.c
@@ -113,7 +113,6 @@ static PixmapFormatRec g_PixmapFormats[] = {
 
 static const ExtensionModule xwinExtensions[] = {
 #ifdef GLXEXT
-  { GlxExtensionInit, "GLX", &noGlxExtension },
 #ifdef XWIN_WINDOWS_DRI
   { WindowsDRIExtensionInit, "Windows-DRI", &noDriExtension },
 #endif
diff --git a/include/extinit.h b/include/extinit.h
index 67e300d18..46081ad30 100644
--- a/include/extinit.h
+++ b/include/extinit.h
@@ -78,6 +78,7 @@ extern void GEExtensionInit(void);
 
 #ifdef GLXEXT
 extern _X_EXPORT Bool noGlxExtension;
+extern void GlxExtensionInit(void);
 #endif
 
 #ifdef PANORAMIX
diff --git a/include/glx_extinit.h b/include/glx_extinit.h
index 32b8fcf72..07f3cc855 100644
--- a/include/glx_extinit.h
+++ b/include/glx_extinit.h
@@ -27,9 +27,8 @@
 #define GLX_EXT_INIT_H
 
 /* this is separate due to sdksyms pulling in extinit.h */
+/* XXX this comment no longer makes sense i think */
 #ifdef GLXEXT
-extern void GlxExtensionInit(void);
-
 typedef struct __GLXprovider __GLXprovider;
 typedef struct __GLXscreen __GLXscreen;
 struct __GLXprovider {
diff --git a/mi/miinitext.c b/mi/miinitext.c
index ce9325e29..c8162337c 100644
--- a/mi/miinitext.c
+++ b/mi/miinitext.c
@@ -298,6 +298,9 @@ static const ExtensionModule staticExtensions[] = {
 #ifdef XSELINUX
     {SELinuxExtensionInit, "SELinux", &noSELinuxExtension},
 #endif
+#ifdef GLXEXT
+    {GlxExtensionInit, "GLX", &noGlxExtension},
+#endif
 };
 
 static ExtensionModule *ExtensionModuleList = NULL;
diff --git a/test/Makefile.am b/test/Makefile.am
index 2dbb2df03..12ac327a3 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -153,6 +153,10 @@ if !SPECIAL_DTRACE_OBJECTS
 tests_LDADD += $(top_builddir)/os/libos.la
 endif
 
+if GLX
+tests_LDADD += $(top_builddir)/glx/libglxvnd.la
+endif
+
 BUILT_SOURCES = sdksyms.c
 CLEANFILES += sdksyms.c
 
commit d8ec33fe0542141aed1d9016d2ecaf52da944b4b
Author: Adam Jackson <ajax at redhat.com>
Date:   Wed Jan 10 13:05:45 2018 -0500

    glx: Use vnd layer for dispatch (v4)
    
    The big change here is MakeCurrent and context tag tracking. We now
    delegate context tags entirely to the vnd layer, and simply store a
    pointer to the context state as the tag data. If a context is deleted
    while it's current, we allocate a fake ID for the context and move the
    context state there, so the tag data still points to a real context. As
    a result we can stop trying so hard to detach the client from contexts
    at disconnect time and just let resource destruction handle it.
    
    Since vnd handles all the MakeCurrent protocol now, our request handlers
    for it can just be return BadImplementation. We also remove a bunch of
    LEGAL_NEW_RESOURCE, because now by the time we're called vnd has already
    allocated its tracking resource on that XID.
    
    v2: Update to match v2 of the vnd import, and remove more redundant work
    like request length checks.
    
    v3: Add/remove the XID map from the vendor private thunk, not the
    backend. (Kyle Brenneman)
    
    v4: Fix deletion of ghost contexts (Kyle Brenneman)
    
    Signed-off-by: Adam Jackson <ajax at redhat.com>

diff --git a/configure.ac b/configure.ac
index 9e498e662..c1f389c1e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1295,7 +1295,7 @@ if test "x$GLX" = xyes; then
 	PKG_CHECK_MODULES([GL], $GLPROTO $LIBGL)
 	AC_SUBST(XLIB_CFLAGS)
 	AC_DEFINE(GLXEXT, 1, [Build GLX extension])
-	GLX_LIBS='$(top_builddir)/glx/libglx.la'
+	GLX_LIBS='$(top_builddir)/glx/libglx.la $(top_builddir)/glx/libglxvnd.la'
 	GLX_SYS_LIBS="$GLX_SYS_LIBS $GL_LIBS"
 else
         GLX=no
diff --git a/glx/createcontext.c b/glx/createcontext.c
index 76316db67..00c23fcdd 100644
--- a/glx/createcontext.c
+++ b/glx/createcontext.c
@@ -123,8 +123,6 @@ __glXDisp_CreateContextAttribsARB(__GLXclientState * cl, GLbyte * pc)
     if (req->length != expected_size)
         return BadLength;
 
-    LEGAL_NEW_RESOURCE(req->context, client);
-
     /* The GLX_ARB_create_context spec says:
      *
      *     "* If <config> is not a valid GLXFBConfig, GLXBadFBConfig is
diff --git a/glx/glxcmds.c b/glx/glxcmds.c
index f4820d8e4..c5d6324d3 100644
--- a/glx/glxcmds.c
+++ b/glx/glxcmds.c
@@ -47,6 +47,7 @@
 #include "indirect_table.h"
 #include "indirect_util.h"
 #include "protocol-versions.h"
+#include "glxvndabi.h"
 
 static char GLXServerVendorName[] = "SGI";
 
@@ -135,6 +136,10 @@ _X_HIDDEN int
 validGlxContext(ClientPtr client, XID id, int access_mode,
                 __GLXcontext ** context, int *err)
 {
+    /* no ghost contexts */
+    if (id & SERVER_BIT)
+        return FALSE;
+
     *err = dixLookupResourceByType((void **) context, id,
                                    __glXContextRes, client, access_mode);
     if (*err != Success || (*context)->idExists == GL_FALSE) {
@@ -240,8 +245,6 @@ DoCreateContext(__GLXclientState * cl, GLXContextID gcId,
     __GLXcontext *glxc, *shareglxc;
     int err;
 
-    LEGAL_NEW_RESOURCE(gcId, client);
-
     /*
      ** Find the display list space that we want to share.
      **
@@ -356,14 +359,11 @@ DoCreateContext(__GLXclientState * cl, GLXContextID gcId,
 int
 __glXDisp_CreateContext(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXCreateContextReq *req = (xGLXCreateContextReq *) pc;
     __GLXconfig *config;
     __GLXscreen *pGlxScreen;
     int err;
 
-    REQUEST_SIZE_MATCH(xGLXCreateContextReq);
-
     if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err))
         return err;
     if (!validGlxVisual(cl->client, pGlxScreen, req->visual, &config, &err))
@@ -376,14 +376,11 @@ __glXDisp_CreateContext(__GLXclientState * cl, GLbyte * pc)
 int
 __glXDisp_CreateNewContext(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXCreateNewContextReq *req = (xGLXCreateNewContextReq *) pc;
     __GLXconfig *config;
     __GLXscreen *pGlxScreen;
     int err;
 
-    REQUEST_SIZE_MATCH(xGLXCreateNewContextReq);
-
     if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err))
         return err;
     if (!validGlxFBConfig(cl->client, pGlxScreen, req->fbconfig, &config, &err))
@@ -417,62 +414,33 @@ __glXDisp_CreateContextWithConfigSGIX(__GLXclientState * cl, GLbyte * pc)
 int
 __glXDisp_DestroyContext(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXDestroyContextReq *req = (xGLXDestroyContextReq *) pc;
     __GLXcontext *glxc;
     int err;
 
-    REQUEST_SIZE_MATCH(xGLXDestroyContextReq);
-
     if (!validGlxContext(cl->client, req->context, DixDestroyAccess,
                          &glxc, &err))
         return err;
 
     glxc->idExists = GL_FALSE;
-    if (!glxc->currentClient)
-        FreeResourceByType(req->context, __glXContextRes, FALSE);
+    if (glxc->currentClient) {
+        XID ghost = FakeClientID(glxc->currentClient->index);
+
+        if (!AddResource(ghost, __glXContextRes, glxc))
+            return BadAlloc;
+        ChangeResourceValue(glxc->id, __glXContextRes, NULL);
+        glxc->id = ghost;
+    }
+
+    FreeResourceByType(req->context, __glXContextRes, FALSE);
 
     return Success;
 }
 
-/*
- * This will return "deleted" contexts, ie, where idExists is GL_FALSE.
- * Contrast validGlxContext, which will not.  We're cheating here and
- * using the XID as the context tag, which is fine as long as we defer
- * actually destroying the context until it's no longer referenced, and
- * block clients from trying to MakeCurrent on contexts that are on the
- * way to destruction.  Notice that DoMakeCurrent calls validGlxContext
- * for new contexts but __glXLookupContextByTag for previous contexts.
- */
 __GLXcontext *
 __glXLookupContextByTag(__GLXclientState * cl, GLXContextTag tag)
 {
-    __GLXcontext *ret;
-
-    if (dixLookupResourceByType((void **) &ret, tag, __glXContextRes,
-                                cl->client, DixUseAccess) == Success)
-        return ret;
-
-    return NULL;
-}
-
-/*****************************************************************************/
-
-static void
-StopUsingContext(__GLXcontext * glxc)
-{
-    if (glxc) {
-        glxc->currentClient = NULL;
-        if (!glxc->idExists) {
-            FreeResourceByType(glxc->id, __glXContextRes, FALSE);
-        }
-    }
-}
-
-static void
-StartUsingContext(__GLXclientState * cl, __GLXcontext * glxc)
-{
-    glxc->currentClient = cl->client;
+    return glxServer.getContextTagPrivate(cl->client, tag);
 }
 
 static __GLXconfig *
@@ -583,14 +551,12 @@ __glXGetDrawable(__GLXcontext * glxc, GLXDrawable drawId, ClientPtr client,
 ** Make an OpenGL context and drawable current.
 */
 
-static int
-DoMakeCurrent(__GLXclientState * cl,
-              GLXDrawable drawId, GLXDrawable readId,
-              GLXContextID contextId, GLXContextTag tag)
+int
+xorgGlxMakeCurrent(ClientPtr client, GLXContextTag tag, XID drawId, XID readId,
+                   XID contextId, GLXContextTag newContextTag)
 {
-    ClientPtr client = cl->client;
-    xGLXMakeCurrentReply reply;
-    __GLXcontext *glxc, *prevglxc;
+    __GLXclientState *cl = glxGetClient(client);
+    __GLXcontext *glxc = NULL, *prevglxc = NULL;
     __GLXdrawable *drawPriv = NULL;
     __GLXdrawable *readPriv = NULL;
     int error;
@@ -603,39 +569,28 @@ DoMakeCurrent(__GLXclientState * cl,
     if ((drawId == None) != (readId == None))
         return BadMatch;
 
-    /*
-     ** Lookup old context.  If we have one, it must be in a usable state.
-     */
+    /* Look up old context. If we have one, it must be in a usable state. */
     if (tag != 0) {
-        prevglxc = __glXLookupContextByTag(cl, tag);
-        if (!prevglxc) {
-            /*
-             ** Tag for previous context is invalid.
-             */
+        prevglxc = glxServer.getContextTagPrivate(client, tag);
+        if (!prevglxc)
             return __glXError(GLXBadContextTag);
-        }
+
         if (prevglxc->renderMode != GL_RENDER) {
             /* Oops.  Not in render mode render. */
             client->errorValue = prevglxc->id;
             return __glXError(GLXBadContextState);
         }
     }
-    else {
-        prevglxc = 0;
-    }
 
-    /*
-     ** Lookup new context.  It must not be current for someone else.
-     */
+    /* Look up new context. It must not be current for someone else. */
     if (contextId != None) {
         int status;
 
         if (!validGlxContext(client, contextId, DixUseAccess, &glxc, &error))
             return error;
-        if ((glxc != prevglxc) && glxc->currentClient) {
-            /* Context is current to somebody else */
+
+        if ((glxc != prevglxc) && glxc->currentClient)
             return BadAccess;
-        }
 
         if (drawId) {
             drawPriv = __glXGetDrawable(glxc, drawId, client, &status);
@@ -648,38 +603,25 @@ DoMakeCurrent(__GLXclientState * cl,
             if (readPriv == NULL)
                 return status;
         }
-    } else {
-        /* Switching to no context.  Ignore new drawable. */
-
-        glxc = 0;
-        drawPriv = 0;
-        readPriv = 0;
     }
 
     if (prevglxc) {
-        /*
-         ** Flush the previous context if needed.
-         */
+        /* Flush the previous context if needed. */
         Bool need_flush = !prevglxc->isDirect;
 #ifdef GLX_CONTEXT_RELEASE_BEHAVIOR_ARB
         if (prevglxc->releaseBehavior == GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB)
             need_flush = GL_FALSE;
 #endif
         if (need_flush) {
-            if (__glXForceCurrent(cl, tag, (int *) &error)) {
-                glFlush();
-            }
-            else {
+            if (!__glXForceCurrent(cl, tag, (int *) &error))
                 return error;
-            }
+            glFlush();
         }
 
-        /*
-         ** Make the previous context not current.
-         */
-        if (!(*prevglxc->loseCurrent) (prevglxc)) {
+        /* Make the previous context not current. */
+        if (!(*prevglxc->loseCurrent) (prevglxc))
             return __glXError(GLXBadContext);
-        }
+
         lastGLContext = NULL;
         if (!prevglxc->isDirect) {
             prevglxc->drawPriv = NULL;
@@ -687,8 +629,7 @@ DoMakeCurrent(__GLXclientState * cl,
         }
     }
 
-    if ((glxc != 0) && !glxc->isDirect) {
-
+    if (glxc && !glxc->isDirect) {
         glxc->drawPriv = drawPriv;
         glxc->readPriv = readPriv;
 
@@ -702,66 +643,35 @@ DoMakeCurrent(__GLXclientState * cl,
         }
 
         glxc->currentClient = client;
+        glxServer.setContextTagPrivate(client, newContextTag, glxc);
     }
 
-    StopUsingContext(prevglxc);
-
-    reply = (xGLXMakeCurrentReply) {
-        .type = X_Reply,
-        .sequenceNumber = client->sequence,
-        .length = 0,
-        .contextTag = 0
-    };
-
-    if (glxc) {
-        StartUsingContext(cl, glxc);
-        reply.contextTag = glxc->id;
+    if (prevglxc) {
+        prevglxc->currentClient = NULL;
+        if (!prevglxc->idExists) {
+            FreeResourceByType(prevglxc->id, __glXContextRes, FALSE);
+        }
     }
 
-    if (client->swapped) {
-        __GLX_DECLARE_SWAP_VARIABLES;
-        __GLX_SWAP_SHORT(&reply.sequenceNumber);
-        __GLX_SWAP_INT(&reply.length);
-        __GLX_SWAP_INT(&reply.contextTag);
-    }
-    WriteToClient(client, sz_xGLXMakeCurrentReply, &reply);
     return Success;
 }
 
 int
 __glXDisp_MakeCurrent(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
-    xGLXMakeCurrentReq *req = (xGLXMakeCurrentReq *) pc;
-
-    REQUEST_SIZE_MATCH(xGLXMakeCurrentReq);
-
-    return DoMakeCurrent(cl, req->drawable, req->drawable,
-                         req->context, req->oldContextTag);
+    return BadImplementation;
 }
 
 int
 __glXDisp_MakeContextCurrent(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
-    xGLXMakeContextCurrentReq *req = (xGLXMakeContextCurrentReq *) pc;
-
-    REQUEST_SIZE_MATCH(xGLXMakeContextCurrentReq);
-
-    return DoMakeCurrent(cl, req->drawable, req->readdrawable,
-                         req->context, req->oldContextTag);
+    return BadImplementation;
 }
 
 int
 __glXDisp_MakeCurrentReadSGI(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
-    xGLXMakeCurrentReadSGIReq *req = (xGLXMakeCurrentReadSGIReq *) pc;
-
-    REQUEST_SIZE_MATCH(xGLXMakeCurrentReadSGIReq);
-
-    return DoMakeCurrent(cl, req->drawable, req->readable,
-                         req->context, req->oldContextTag);
+    return BadImplementation;
 }
 
 int
@@ -773,8 +683,6 @@ __glXDisp_IsDirect(__GLXclientState * cl, GLbyte * pc)
     __GLXcontext *glxc;
     int err;
 
-    REQUEST_SIZE_MATCH(xGLXIsDirectReq);
-
     if (!validGlxContext(cl->client, req->context, DixReadAccess, &glxc, &err))
         return err;
 
@@ -838,14 +746,11 @@ __glXDisp_QueryVersion(__GLXclientState * cl, GLbyte * pc)
 int
 __glXDisp_WaitGL(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXWaitGLReq *req = (xGLXWaitGLReq *) pc;
     GLXContextTag tag;
     __GLXcontext *glxc = NULL;
     int error;
 
-    REQUEST_SIZE_MATCH(xGLXWaitGLReq);
-
     tag = req->contextTag;
     if (tag) {
         glxc = __glXLookupContextByTag(cl, tag);
@@ -867,14 +772,11 @@ __glXDisp_WaitGL(__GLXclientState * cl, GLbyte * pc)
 int
 __glXDisp_WaitX(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXWaitXReq *req = (xGLXWaitXReq *) pc;
     GLXContextTag tag;
     __GLXcontext *glxc = NULL;
     int error;
 
-    REQUEST_SIZE_MATCH(xGLXWaitXReq);
-
     tag = req->contextTag;
     if (tag) {
         glxc = __glXLookupContextByTag(cl, tag);
@@ -903,8 +805,6 @@ __glXDisp_CopyContext(__GLXclientState * cl, GLbyte * pc)
     __GLXcontext *src, *dst;
     int error;
 
-    REQUEST_SIZE_MATCH(xGLXCopyContextReq);
-
     source = req->source;
     dest = req->dest;
     tag = req->contextTag;
@@ -992,8 +892,6 @@ __glXDisp_GetVisualConfigs(__GLXclientState * cl, GLbyte * pc)
     __GLX_DECLARE_SWAP_VARIABLES;
     __GLX_DECLARE_SWAP_ARRAY_VARIABLES;
 
-    REQUEST_SIZE_MATCH(xGLXGetVisualConfigsReq);
-
     if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err))
         return err;
 
@@ -1213,10 +1111,8 @@ DoGetFBConfigs(__GLXclientState * cl, unsigned screen)
 int
 __glXDisp_GetFBConfigs(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXGetFBConfigsReq *req = (xGLXGetFBConfigsReq *) pc;
 
-    REQUEST_SIZE_MATCH(xGLXGetFBConfigsReq);
     return DoGetFBConfigs(cl, req->screen);
 }
 
@@ -1287,8 +1183,6 @@ DoCreateGLXPixmap(ClientPtr client, __GLXscreen * pGlxScreen,
     DrawablePtr pDraw;
     int err;
 
-    LEGAL_NEW_RESOURCE(glxDrawableId, client);
-
     err = dixLookupDrawable(&pDraw, drawableId, client, 0, DixAddAccess);
     if (err != Success) {
         client->errorValue = drawableId;
@@ -1354,14 +1248,11 @@ determineTextureTarget(ClientPtr client, XID glxDrawableID,
 int
 __glXDisp_CreateGLXPixmap(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXCreateGLXPixmapReq *req = (xGLXCreateGLXPixmapReq *) pc;
     __GLXconfig *config;
     __GLXscreen *pGlxScreen;
     int err;
 
-    REQUEST_SIZE_MATCH(xGLXCreateGLXPixmapReq);
-
     if (!validGlxScreen(cl->client, req->screen, &pGlxScreen, &err))
         return err;
     if (!validGlxVisual(cl->client, pGlxScreen, req->visual, &config, &err))
@@ -1442,11 +1333,8 @@ DoDestroyDrawable(__GLXclientState * cl, XID glxdrawable, int type)
 int
 __glXDisp_DestroyGLXPixmap(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXDestroyGLXPixmapReq *req = (xGLXDestroyGLXPixmapReq *) pc;
 
-    REQUEST_SIZE_MATCH(xGLXDestroyGLXPixmapReq);
-
     return DoDestroyDrawable(cl, req->glxpixmap, GLX_DRAWABLE_PIXMAP);
 }
 
@@ -1472,8 +1360,6 @@ DoCreatePbuffer(ClientPtr client, int screenNum, XID fbconfigId,
     PixmapPtr pPixmap;
     int err;
 
-    LEGAL_NEW_RESOURCE(glxDrawableId, client);
-
     if (!validGlxScreen(client, screenNum, &pGlxScreen, &err))
         return err;
     if (!validGlxFBConfig(client, pGlxScreen, fbconfigId, &config, &err))
@@ -1658,8 +1544,6 @@ __glXDisp_CreateWindow(__GLXclientState * cl, GLbyte * pc)
     }
     REQUEST_FIXED_SIZE(xGLXCreateWindowReq, req->numAttribs << 3);
 
-    LEGAL_NEW_RESOURCE(req->glxwindow, client);
-
     if (!validGlxScreen(client, req->screen, &pGlxScreen, &err))
         return err;
     if (!validGlxFBConfig(client, pGlxScreen, req->fbconfig, &config, &err))
@@ -1709,8 +1593,6 @@ __glXDisp_SwapBuffers(__GLXclientState * cl, GLbyte * pc)
     __GLXdrawable *pGlxDraw;
     int error;
 
-    REQUEST_SIZE_MATCH(xGLXSwapBuffersReq);
-
     tag = req->contextTag;
     drawId = req->drawable;
     if (tag) {
@@ -1813,11 +1695,8 @@ __glXDisp_QueryContextInfoEXT(__GLXclientState * cl, GLbyte * pc)
 int
 __glXDisp_QueryContext(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXQueryContextReq *req = (xGLXQueryContextReq *) pc;
 
-    REQUEST_SIZE_MATCH(xGLXQueryContextReq);
-
     return DoQueryContext(cl, req->context);
 }
 
@@ -2453,8 +2332,6 @@ __glXDisp_QueryExtensionsString(__GLXclientState * cl, GLbyte * pc)
     char *buf;
     int err;
 
-    REQUEST_SIZE_MATCH(xGLXQueryExtensionsStringReq);
-
     if (!validGlxScreen(client, req->screen, &pGlxScreen, &err))
         return err;
 
@@ -2508,8 +2385,6 @@ __glXDisp_QueryServerString(__GLXclientState * cl, GLbyte * pc)
     __GLXscreen *pGlxScreen;
     int err;
 
-    REQUEST_SIZE_MATCH(xGLXQueryServerStringReq);
-
     if (!validGlxScreen(client, req->screen, &pGlxScreen, &err))
         return err;
 
diff --git a/glx/glxcmdsswap.c b/glx/glxcmdsswap.c
index 10d84062e..7d6674470 100644
--- a/glx/glxcmdsswap.c
+++ b/glx/glxcmdsswap.c
@@ -56,13 +56,10 @@
 int
 __glXDispSwap_CreateContext(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXCreateContextReq *req = (xGLXCreateContextReq *) pc;
 
     __GLX_DECLARE_SWAP_VARIABLES;
 
-    REQUEST_SIZE_MATCH(xGLXCreateContextReq);
-
     __GLX_SWAP_SHORT(&req->length);
     __GLX_SWAP_INT(&req->context);
     __GLX_SWAP_INT(&req->visual);
@@ -75,13 +72,10 @@ __glXDispSwap_CreateContext(__GLXclientState * cl, GLbyte * pc)
 int
 __glXDispSwap_CreateNewContext(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXCreateNewContextReq *req = (xGLXCreateNewContextReq *) pc;
 
     __GLX_DECLARE_SWAP_VARIABLES;
 
-    REQUEST_SIZE_MATCH(xGLXCreateNewContextReq);
-
     __GLX_SWAP_SHORT(&req->length);
     __GLX_SWAP_INT(&req->context);
     __GLX_SWAP_INT(&req->fbconfig);
@@ -115,13 +109,10 @@ __glXDispSwap_CreateContextWithConfigSGIX(__GLXclientState * cl, GLbyte * pc)
 int
 __glXDispSwap_DestroyContext(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXDestroyContextReq *req = (xGLXDestroyContextReq *) pc;
 
     __GLX_DECLARE_SWAP_VARIABLES;
 
-    REQUEST_SIZE_MATCH(xGLXDestroyContextReq);
-
     __GLX_SWAP_SHORT(&req->length);
     __GLX_SWAP_INT(&req->context);
 
@@ -131,69 +122,28 @@ __glXDispSwap_DestroyContext(__GLXclientState * cl, GLbyte * pc)
 int
 __glXDispSwap_MakeCurrent(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
-    xGLXMakeCurrentReq *req = (xGLXMakeCurrentReq *) pc;
-
-    __GLX_DECLARE_SWAP_VARIABLES;
-
-    REQUEST_SIZE_MATCH(xGLXMakeCurrentReq);
-
-    __GLX_SWAP_SHORT(&req->length);
-    __GLX_SWAP_INT(&req->drawable);
-    __GLX_SWAP_INT(&req->context);
-    __GLX_SWAP_INT(&req->oldContextTag);
-
-    return __glXDisp_MakeCurrent(cl, pc);
+    return BadImplementation;
 }
 
 int
 __glXDispSwap_MakeContextCurrent(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
-    xGLXMakeContextCurrentReq *req = (xGLXMakeContextCurrentReq *) pc;
-
-    __GLX_DECLARE_SWAP_VARIABLES;
-
-    REQUEST_SIZE_MATCH(xGLXMakeContextCurrentReq);
-
-    __GLX_SWAP_SHORT(&req->length);
-    __GLX_SWAP_INT(&req->drawable);
-    __GLX_SWAP_INT(&req->readdrawable);
-    __GLX_SWAP_INT(&req->context);
-    __GLX_SWAP_INT(&req->oldContextTag);
-
-    return __glXDisp_MakeContextCurrent(cl, pc);
+    return BadImplementation;
 }
 
 int
 __glXDispSwap_MakeCurrentReadSGI(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
-    xGLXMakeCurrentReadSGIReq *req = (xGLXMakeCurrentReadSGIReq *) pc;
-
-    __GLX_DECLARE_SWAP_VARIABLES;
-
-    REQUEST_SIZE_MATCH(xGLXMakeCurrentReadSGIReq);
-
-    __GLX_SWAP_SHORT(&req->length);
-    __GLX_SWAP_INT(&req->drawable);
-    __GLX_SWAP_INT(&req->readable);
-    __GLX_SWAP_INT(&req->context);
-    __GLX_SWAP_INT(&req->oldContextTag);
-
-    return __glXDisp_MakeCurrentReadSGI(cl, pc);
+    return BadImplementation;
 }
 
 int
 __glXDispSwap_IsDirect(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXIsDirectReq *req = (xGLXIsDirectReq *) pc;
 
     __GLX_DECLARE_SWAP_VARIABLES;
 
-    REQUEST_SIZE_MATCH(xGLXIsDirectReq);
-
     __GLX_SWAP_SHORT(&req->length);
     __GLX_SWAP_INT(&req->context);
 
@@ -203,13 +153,10 @@ __glXDispSwap_IsDirect(__GLXclientState * cl, GLbyte * pc)
 int
 __glXDispSwap_QueryVersion(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXQueryVersionReq *req = (xGLXQueryVersionReq *) pc;
 
     __GLX_DECLARE_SWAP_VARIABLES;
 
-    REQUEST_SIZE_MATCH(xGLXQueryVersionReq);
-
     __GLX_SWAP_SHORT(&req->length);
     __GLX_SWAP_INT(&req->majorVersion);
     __GLX_SWAP_INT(&req->minorVersion);
@@ -220,13 +167,10 @@ __glXDispSwap_QueryVersion(__GLXclientState * cl, GLbyte * pc)
 int
 __glXDispSwap_WaitGL(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXWaitGLReq *req = (xGLXWaitGLReq *) pc;
 
     __GLX_DECLARE_SWAP_VARIABLES;
 
-    REQUEST_SIZE_MATCH(xGLXWaitGLReq);
-
     __GLX_SWAP_SHORT(&req->length);
     __GLX_SWAP_INT(&req->contextTag);
 
@@ -236,13 +180,10 @@ __glXDispSwap_WaitGL(__GLXclientState * cl, GLbyte * pc)
 int
 __glXDispSwap_WaitX(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXWaitXReq *req = (xGLXWaitXReq *) pc;
 
     __GLX_DECLARE_SWAP_VARIABLES;
 
-    REQUEST_SIZE_MATCH(xGLXWaitXReq);
-
     __GLX_SWAP_SHORT(&req->length);
     __GLX_SWAP_INT(&req->contextTag);
 
@@ -252,13 +193,10 @@ __glXDispSwap_WaitX(__GLXclientState * cl, GLbyte * pc)
 int
 __glXDispSwap_CopyContext(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXCopyContextReq *req = (xGLXCopyContextReq *) pc;
 
     __GLX_DECLARE_SWAP_VARIABLES;
 
-    REQUEST_SIZE_MATCH(xGLXCopyContextReq);
-
     __GLX_SWAP_SHORT(&req->length);
     __GLX_SWAP_INT(&req->source);
     __GLX_SWAP_INT(&req->dest);
@@ -270,13 +208,10 @@ __glXDispSwap_CopyContext(__GLXclientState * cl, GLbyte * pc)
 int
 __glXDispSwap_GetVisualConfigs(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXGetVisualConfigsReq *req = (xGLXGetVisualConfigsReq *) pc;
 
     __GLX_DECLARE_SWAP_VARIABLES;
 
-    REQUEST_SIZE_MATCH(xGLXGetVisualConfigsReq);
-
     __GLX_SWAP_INT(&req->screen);
     return __glXDisp_GetVisualConfigs(cl, pc);
 }
@@ -284,13 +219,10 @@ __glXDispSwap_GetVisualConfigs(__GLXclientState * cl, GLbyte * pc)
 int
 __glXDispSwap_GetFBConfigs(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXGetFBConfigsReq *req = (xGLXGetFBConfigsReq *) pc;
 
     __GLX_DECLARE_SWAP_VARIABLES;
 
-    REQUEST_SIZE_MATCH(xGLXGetFBConfigsReq);
-
     __GLX_SWAP_INT(&req->screen);
     return __glXDisp_GetFBConfigs(cl, pc);
 }
@@ -312,13 +244,10 @@ __glXDispSwap_GetFBConfigsSGIX(__GLXclientState * cl, GLbyte * pc)
 int
 __glXDispSwap_CreateGLXPixmap(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXCreateGLXPixmapReq *req = (xGLXCreateGLXPixmapReq *) pc;
 
     __GLX_DECLARE_SWAP_VARIABLES;
 
-    REQUEST_SIZE_MATCH(xGLXCreateGLXPixmapReq);
-
     __GLX_SWAP_SHORT(&req->length);
     __GLX_SWAP_INT(&req->screen);
     __GLX_SWAP_INT(&req->visual);
@@ -380,13 +309,10 @@ __glXDispSwap_CreateGLXPixmapWithConfigSGIX(__GLXclientState * cl, GLbyte * pc)
 int
 __glXDispSwap_DestroyGLXPixmap(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXDestroyGLXPixmapReq *req = (xGLXDestroyGLXPixmapReq *) pc;
 
     __GLX_DECLARE_SWAP_VARIABLES;
 
-    REQUEST_SIZE_MATCH(xGLXDestroyGLXPixmapReq);
-
     __GLX_SWAP_SHORT(&req->length);
     __GLX_SWAP_INT(&req->glxpixmap);
 
@@ -412,13 +338,10 @@ __glXDispSwap_DestroyPixmap(__GLXclientState * cl, GLbyte * pc)
 int
 __glXDispSwap_QueryContext(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXQueryContextReq *req = (xGLXQueryContextReq *) pc;
 
     __GLX_DECLARE_SWAP_VARIABLES;
 
-    REQUEST_SIZE_MATCH(xGLXQueryContextReq);
-
     __GLX_SWAP_INT(&req->context);
 
     return __glXDisp_QueryContext(cl, pc);
@@ -474,13 +397,10 @@ __glXDispSwap_CreateGLXPbufferSGIX(__GLXclientState * cl, GLbyte * pc)
 int
 __glXDispSwap_DestroyPbuffer(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXDestroyPbufferReq *req = (xGLXDestroyPbufferReq *) pc;
 
     __GLX_DECLARE_SWAP_VARIABLES;
 
-    REQUEST_SIZE_MATCH(xGLXDestroyPbufferReq);
-
     __GLX_SWAP_INT(&req->pbuffer);
 
     return __glXDisp_DestroyPbuffer(cl, pc);
@@ -604,13 +524,10 @@ __glXDispSwap_DestroyWindow(__GLXclientState * cl, GLbyte * pc)
 int
 __glXDispSwap_SwapBuffers(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXSwapBuffersReq *req = (xGLXSwapBuffersReq *) pc;
 
     __GLX_DECLARE_SWAP_VARIABLES;
 
-    REQUEST_SIZE_MATCH(xGLXSwapBuffersReq);
-
     __GLX_SWAP_SHORT(&req->length);
     __GLX_SWAP_INT(&req->contextTag);
     __GLX_SWAP_INT(&req->drawable);
@@ -621,13 +538,10 @@ __glXDispSwap_SwapBuffers(__GLXclientState * cl, GLbyte * pc)
 int
 __glXDispSwap_UseXFont(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXUseXFontReq *req = (xGLXUseXFontReq *) pc;
 
     __GLX_DECLARE_SWAP_VARIABLES;
 
-    REQUEST_SIZE_MATCH(xGLXUseXFontReq);
-
     __GLX_SWAP_SHORT(&req->length);
     __GLX_SWAP_INT(&req->contextTag);
     __GLX_SWAP_INT(&req->font);
@@ -641,13 +555,10 @@ __glXDispSwap_UseXFont(__GLXclientState * cl, GLbyte * pc)
 int
 __glXDispSwap_QueryExtensionsString(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXQueryExtensionsStringReq *req = (xGLXQueryExtensionsStringReq *) pc;
 
     __GLX_DECLARE_SWAP_VARIABLES;
 
-    REQUEST_SIZE_MATCH(xGLXQueryExtensionsStringReq);
-
     __GLX_SWAP_SHORT(&req->length);
     __GLX_SWAP_INT(&req->screen);
 
@@ -657,13 +568,10 @@ __glXDispSwap_QueryExtensionsString(__GLXclientState * cl, GLbyte * pc)
 int
 __glXDispSwap_QueryServerString(__GLXclientState * cl, GLbyte * pc)
 {
-    ClientPtr client = cl->client;
     xGLXQueryServerStringReq *req = (xGLXQueryServerStringReq *) pc;
 
     __GLX_DECLARE_SWAP_VARIABLES;
 
-    REQUEST_SIZE_MATCH(xGLXQueryServerStringReq);
-
     __GLX_SWAP_SHORT(&req->length);
     __GLX_SWAP_INT(&req->screen);
     __GLX_SWAP_INT(&req->name);
diff --git a/glx/glxext.c b/glx/glxext.c
index d39fe6d8e..a345c437a 100644
--- a/glx/glxext.c
+++ b/glx/glxext.c
@@ -46,10 +46,12 @@
 #include "glxext.h"
 #include "indirect_table.h"
 #include "indirect_util.h"
+#include "glxvndabi.h"
 
 /*
 ** X resources.
 */
+static int glxGeneration;
 RESTYPE __glXContextRes;
 RESTYPE __glXDrawableRes;
 
@@ -64,15 +66,6 @@ static int __glXDispatch(ClientPtr);
 static GLboolean __glXFreeContext(__GLXcontext * cx);
 
 /*
-** Called when the extension is reset.
-*/
-static void
-ResetExtension(ExtensionEntry * extEntry)
-{
-    lastGLContext = NULL;
-}
-
-/*
 ** Reset state used to keep track of large (multi-request) commands.
 */
 void
@@ -86,16 +79,18 @@ __glXResetLargeCommandStatus(__GLXclientState * cl)
 
 /*
  * This procedure is called when the client who created the context goes away
- * OR when glXDestroyContext is called.  In either case, all we do is flag that
- * the ID is no longer valid, and (maybe) free the context.
+ * OR when glXDestroyContext is called. If the context is current for a client
+ * the dispatch layer will have moved the context struct to a fake resource ID
+ * and cx here will be NULL. Otherwise we really free the context.
  */
 static int
 ContextGone(__GLXcontext * cx, XID id)
 {
-    cx->idExists = GL_FALSE;
-    if (!cx->currentClient) {
+    if (!cx)
+        return TRUE;
+
+    if (!cx->currentClient)
         __glXFreeContext(cx);
-    }
 
     return TRUE;
 }
@@ -271,29 +266,14 @@ glxClientCallback(CallbackListPtr *list, void *closure, void *data)
     NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
     ClientPtr pClient = clientinfo->client;
     __GLXclientState *cl = glxGetClient(pClient);
-    __GLXcontext *c, *next;
 
     switch (pClient->clientState) {
-    case ClientStateRunning:
-        cl->client = pClient;
-        break;
-
     case ClientStateGone:
-        /* detach from all current contexts */
-        for (c = glxAllContexts; c; c = next) {
-            next = c->next;
-            if (c->currentClient == pClient) {
-                c->loseCurrent(c);
-                lastGLContext = NULL;
-                c->currentClient = NULL;
-                FreeResourceByType(c->id, __glXContextRes, FALSE);
-            }
-        }
-
         free(cl->returnBuf);
         free(cl->largeCmdBuf);
         free(cl->GLClientextensions);
-        memset(cl, 0, sizeof(*cl));
+        cl->returnBuf = NULL;
+        cl->GLClientextensions = NULL;
         break;
 
     default:
@@ -303,7 +283,7 @@ glxClientCallback(CallbackListPtr *list, void *closure, void *data)
 
 /************************************************************************/
 
-static __GLXprovider *__glXProviderStack;
+static __GLXprovider *__glXProviderStack = &__glXDRISWRastProvider;
 
 void
 GlxPushProvider(__GLXprovider * provider)
@@ -346,50 +326,236 @@ GetGLXDrawableBytes(void *value, XID id, ResourceSizePtr size)
     }
 }
 
-/*
-** Initialize the GLX extension.
-*/
-void
-GlxExtensionInit(void)
+static void
+xorgGlxCloseExtension(const ExtensionEntry *extEntry)
 {
-    ExtensionEntry *extEntry;
-    ScreenPtr pScreen;
-    int i;
-    __GLXprovider *p, **stack;
-    Bool glx_provided = FALSE;
+    lastGLContext = NULL;
+}
+
+static int
+xorgGlxHandleRequest(ClientPtr client)
+{
+    return __glXDispatch(client);
+}
+
+static ScreenPtr
+screenNumToScreen(int screen)
+{
+    if (screen < 0 || screen >= screenInfo.numScreens)
+        return NULL;
+
+    return screenInfo.screens[screen];
+}
+
+static int
+maybe_swap32(ClientPtr client, int x)
+{
+    return client->swapped ? bswap_32(x) : x;
+}
+
+static GlxServerVendor *
+vendorForScreen(ClientPtr client, int screen)
+{
+    screen = maybe_swap32(client, screen);
+
+    return glxServer.getVendorForScreen(client, screenNumToScreen(screen));
+}
+
+/* this ought to be generated */
+static int
+xorgGlxThunkRequest(ClientPtr client)
+{
+    REQUEST(xGLXVendorPrivateReq);
+    CARD32 vendorCode = maybe_swap32(client, stuff->vendorCode);
+    GlxServerVendor *vendor = NULL;
+    XID resource = 0;
+    int ret;
+
+    switch (vendorCode) {
+    case X_GLXvop_QueryContextInfoEXT: {
+        xGLXQueryContextInfoEXTReq *req = (void *)stuff;
+        REQUEST_AT_LEAST_SIZE(*req);
+        if (!(vendor = glxServer.getXIDMap(maybe_swap32(client, req->context))))
+            return __glXError(GLXBadContext);
+        break;
+        }
+
+    case X_GLXvop_GetFBConfigsSGIX: {
+        xGLXGetFBConfigsSGIXReq *req = (void *)stuff;
+        REQUEST_AT_LEAST_SIZE(*req);
+        if (!(vendor = vendorForScreen(client, req->screen)))
+            return BadValue;
+        break;
+        }
+
+    case X_GLXvop_CreateContextWithConfigSGIX: {
+        xGLXCreateContextWithConfigSGIXReq *req = (void *)stuff;
+        REQUEST_AT_LEAST_SIZE(*req);
+        resource = maybe_swap32(client, req->context);
+        if (!(vendor = vendorForScreen(client, req->screen)))
+            return BadValue;
+        break;
+        }
+
+    case X_GLXvop_CreateGLXPixmapWithConfigSGIX: {
+        xGLXCreateGLXPixmapWithConfigSGIXReq *req = (void *)stuff;
+        REQUEST_AT_LEAST_SIZE(*req);
+        resource = maybe_swap32(client, req->glxpixmap);
+        if (!(vendor = vendorForScreen(client, req->screen)))
+            return BadValue;
+        break;
+        }
+
+    case X_GLXvop_CreateGLXPbufferSGIX: {
+        xGLXCreateGLXPbufferSGIXReq *req = (void *)stuff;
+        REQUEST_AT_LEAST_SIZE(*req);
+        resource = maybe_swap32(client, req->pbuffer);
+        if (!(vendor = vendorForScreen(client, req->screen)))
+            return BadValue;
+        break;
+        }
+
+    /* same offset for the drawable for these three */
+    case X_GLXvop_DestroyGLXPbufferSGIX:
+    case X_GLXvop_ChangeDrawableAttributesSGIX:
+    case X_GLXvop_GetDrawableAttributesSGIX: {
+        xGLXGetDrawableAttributesSGIXReq *req = (void *)stuff;
+        REQUEST_AT_LEAST_SIZE(*req);
+        if (!(vendor = glxServer.getXIDMap(maybe_swap32(client,
+                                                        req->drawable))))
+            return __glXError(GLXBadDrawable);
+        break;
+        }
 
-    if (serverGeneration == 1) {
-        for (stack = &__glXProviderStack; *stack; stack = &(*stack)->next)
-            ;
-        *stack = &__glXDRISWRastProvider;
+    /* most things just use the standard context tag */
+    default: {
+        /* size checked by vnd layer already */
+        GLXContextTag tag = maybe_swap32(client, stuff->contextTag);
+        vendor = glxServer.getContextTag(client, tag);
+        if (!vendor)
+            return __glXError(GLXBadContextTag);
+        break;
+        }
     }
 
-    /* Mesa requires at least one True/DirectColor visual */
-    if (!checkScreenVisuals())
-        return;
+    /* If we're creating a resource, add the map now */
+    if (resource) {
+        LEGAL_NEW_RESOURCE(resource, client);
+        if (!glxServer.addXIDMap(resource, vendor))
+            return BadAlloc;
+    }
 
-    __glXContextRes = CreateNewResourceType((DeleteType) ContextGone,
-                                            "GLXContext");
-    __glXDrawableRes = CreateNewResourceType((DeleteType) DrawableGone,
-                                             "GLXDrawable");
-    if (!__glXContextRes || !__glXDrawableRes)
-        return;
+    ret = glxServer.forwardRequest(vendor, client);
+
+    if (ret == Success && vendorCode == X_GLXvop_DestroyGLXPbufferSGIX) {
+        xGLXDestroyGLXPbufferSGIXReq *req = (void *)stuff;
+        glxServer.removeXIDMap(maybe_swap32(client, req->pbuffer));
+    }
+
+    if (ret != Success)
+        glxServer.removeXIDMap(resource);
+
+    return ret;
+}
+
+static GlxServerDispatchProc
+xorgGlxGetDispatchAddress(CARD8 minorOpcode, CARD32 vendorCode)
+{
+    /* we don't support any other GLX opcodes */
+    if (minorOpcode != X_GLXVendorPrivate &&
+        minorOpcode != X_GLXVendorPrivateWithReply)
+        return NULL;
+
+    /* we only support some vendor private requests */
+    if (!__glXGetProtocolDecodeFunction(&VendorPriv_dispatch_info, vendorCode,
+                                        FALSE))
+        return NULL;
+
+    return xorgGlxThunkRequest;
+}
+
+static Bool
+xorgGlxServerPreInit(const ExtensionEntry *extEntry)
+{
+    if (glxGeneration != serverGeneration) {
+        /* Mesa requires at least one True/DirectColor visual */
+        if (!checkScreenVisuals())
+            return FALSE;
+
+        __glXContextRes = CreateNewResourceType((DeleteType) ContextGone,
+                                                "GLXContext");
+        __glXDrawableRes = CreateNewResourceType((DeleteType) DrawableGone,
+                                                 "GLXDrawable");
+        if (!__glXContextRes || !__glXDrawableRes)
+            return FALSE;
+
+        if (!dixRegisterPrivateKey
+            (&glxClientPrivateKeyRec, PRIVATE_CLIENT, sizeof(__GLXclientState)))
+            return FALSE;
+        if (!AddCallback(&ClientStateCallback, glxClientCallback, 0))
+            return FALSE;
+
+        __glXErrorBase = extEntry->errorBase;
+        __glXEventBase = extEntry->eventBase;
+
+        SetResourceTypeSizeFunc(__glXDrawableRes, GetGLXDrawableBytes);
+#if PRESENT
+        __glXregisterPresentCompleteNotify();
+#endif
+
+        glxGeneration = serverGeneration;
+    }
+
+    return glxGeneration == serverGeneration;
+}
+
+static GlxServerVendor *glvnd_vendor = NULL;
+
+static GlxServerVendor *
+xorgGlxInitGLVNDVendor(void)
+{
+    if (glvnd_vendor == NULL) {
+        GlxServerImports *imports = NULL;
+        imports = glxServer.allocateServerImports();
+
+        if (imports != NULL) {
+            imports->extensionCloseDown = xorgGlxCloseExtension;
+            imports->handleRequest = xorgGlxHandleRequest;
+            imports->getDispatchAddress = xorgGlxGetDispatchAddress;
+            imports->makeCurrent = xorgGlxMakeCurrent;
+            glvnd_vendor = glxServer.createVendor(imports);
+            glxServer.freeServerImports(imports);
+        }
+    }
+    return glvnd_vendor;
+}
 
-    SetResourceTypeSizeFunc(__glXDrawableRes, GetGLXDrawableBytes);
+static void
+xorgGlxServerInit(CallbackListPtr *pcbl, void *param, void *ext)
+{
+    const ExtensionEntry *extEntry = ext;
+    int i;
 
-    if (!dixRegisterPrivateKey
-        (&glxClientPrivateKeyRec, PRIVATE_CLIENT, sizeof(__GLXclientState)))
+    if (!xorgGlxServerPreInit(extEntry)) {
         return;
-    if (!AddCallback(&ClientStateCallback, glxClientCallback, 0))
+    }
+
+    if (!xorgGlxInitGLVNDVendor()) {
         return;
+    }
 
     for (i = 0; i < screenInfo.numScreens; i++) {
-        pScreen = screenInfo.screens[i];
+        ScreenPtr pScreen = screenInfo.screens[i];
+        __GLXprovider *p;
 
-        for (p = __glXProviderStack; p != NULL; p = p->next) {
-            __GLXscreen *glxScreen;
+        if (glxServer.getVendorForScreen(NULL, pScreen) != NULL) {
+            // There's already a vendor registered.
+            LogMessage(X_INFO, "GLX: Another vendor is already registered for screen %d\n", i);
+            continue;
+        }
 
-            glxScreen = p->screenProbe(pScreen);
+        for (p = __glXProviderStack; p != NULL; p = p->next) {
+            __GLXscreen *glxScreen = p->screenProbe(pScreen);
             if (glxScreen != NULL) {
                 LogMessage(X_INFO,
                            "GLX: Initialized %s GL provider for screen %d\n",
@@ -399,33 +565,19 @@ GlxExtensionInit(void)
 
         }
 
-        if (!p)
+        if (p) {
+            glxServer.setScreenVendor(pScreen, glvnd_vendor);
+        } else {
             LogMessage(X_INFO,
                        "GLX: no usable GL providers found for screen %d\n", i);
-        else
-            glx_provided = TRUE;
-    }
-
-    /* don't register extension if GL is not provided on any screen */
-    if (!glx_provided)
-        return;
-
-    /*
-     ** Add extension to server extensions.
-     */
-    extEntry = AddExtension(GLX_EXTENSION_NAME, __GLX_NUMBER_EVENTS,
-                            __GLX_NUMBER_ERRORS, __glXDispatch,
-                            __glXDispatch, ResetExtension, StandardMinorOpcode);
-    if (!extEntry) {
-        FatalError("__glXExtensionInit: AddExtensions failed\n");
-        return;
+        }
     }
+}
 
-    __glXErrorBase = extEntry->errorBase;
-    __glXEventBase = extEntry->eventBase;
-#if PRESENT
-    __glXregisterPresentCompleteNotify();
-#endif
+Bool
+xorgGlxCreateVendor(void)
+{
+    return AddCallback(glxServer.extensionInitCallback, xorgGlxServerInit, NULL);
 }
 
 /************************************************************************/
@@ -500,7 +652,7 @@ glxSuspendClients(void)
     int i;
 
     for (i = 1; i < currentMaxClients; i++) {
-        if (clients[i] && glxGetClient(clients[i])->inUse)
+        if (glxGetClient(clients[i])->client)
             IgnoreClient(clients[i]);
     }
 
@@ -516,7 +668,7 @@ glxResumeClients(void)
     glxBlockClients = FALSE;
 
     for (i = 1; i < currentMaxClients; i++) {
-        if (clients[i] && glxGetClient(clients[i])->inUse)
+        if (glxGetClient(clients[i])->client)
             AttendClient(clients[i]);
     }
 
@@ -553,12 +705,10 @@ __glXDispatch(ClientPtr client)
     CARD8 opcode;
     __GLXdispatchSingleProcPtr proc;
     __GLXclientState *cl;
-    int retval;
+    int retval = BadRequest;
 
     opcode = stuff->glxCode;
     cl = glxGetClient(client);
-    /* Mark it in use so we suspend it on VT switch. */
-    cl->inUse = TRUE;
 
     /*
      ** If we're expecting a glXRenderLarge request, this better be one.
@@ -568,6 +718,9 @@ __glXDispatch(ClientPtr client)
         return __glXError(GLXBadLargeRequest);
     }
 
+    if (!cl->client)
+        cl->client = client;
+
     /* If we're currently blocking GLX clients, just put this guy to
      * sleep, reset the request and return. */
     if (glxBlockClients) {
@@ -582,12 +735,8 @@ __glXDispatch(ClientPtr client)
      */
     proc = __glXGetProtocolDecodeFunction(&Single_dispatch_info, opcode,
                                           client->swapped);
-    if (proc != NULL) {
+    if (proc != NULL)
         retval = (*proc) (cl, (GLbyte *) stuff);
-    }
-    else {
-        retval = BadRequest;
-    }
 
     return retval;
 }
diff --git a/glx/glxext.h b/glx/glxext.h
index cde0e1519..af59165bf 100644
--- a/glx/glxext.h
+++ b/glx/glxext.h
@@ -62,4 +62,8 @@ extern void __glXResetLargeCommandStatus(__GLXclientState *);
 extern const char GLServerVersion[];
 extern int DoGetString(__GLXclientState * cl, GLbyte * pc, GLboolean need_swap);
 
+extern int
+xorgGlxMakeCurrent(ClientPtr client, GLXContextTag tag, XID drawId, XID readId,
+                   XID contextId, GLXContextTag newContextTag);
+
 #endif                          /* _glxext_h_ */
diff --git a/glx/glxscreens.h b/glx/glxscreens.h
index c6a0c5021..40649f88d 100644
--- a/glx/glxscreens.h
+++ b/glx/glxscreens.h
@@ -36,6 +36,7 @@
  */
 
 #include "extension_string.h"
+#include "glxvndabi.h"
 
 typedef struct __GLXconfig __GLXconfig;
 struct __GLXconfig {
diff --git a/glx/glxserver.h b/glx/glxserver.h
index 8a3e6f98b..8ffde2342 100644
--- a/glx/glxserver.h
+++ b/glx/glxserver.h
@@ -110,11 +110,6 @@ __glXregisterPresentCompleteNotify(void);
 */
 struct __GLXclientStateRec {
     /*
-     ** Whether this structure is currently being used to support a client.
-     */
-    Bool inUse;
-
-    /*
      ** Buffer for returned data.
      */
     GLbyte *returnBuf;
diff --git a/glx/xfont.c b/glx/xfont.c
index 83a455d73..bd2fdae52 100644
--- a/glx/xfont.c
+++ b/glx/xfont.c
@@ -152,8 +152,6 @@ __glXDisp_UseXFont(__GLXclientState * cl, GLbyte * pc)
     __GLXcontext *cx;
     int error;
 
-    REQUEST_SIZE_MATCH(xGLXUseXFontReq);
-
     req = (xGLXUseXFontReq *) pc;
     cx = __glXForceCurrent(cl, req->contextTag, &error);
     if (!cx) {
diff --git a/hw/kdrive/ephyr/ephyr.c b/hw/kdrive/ephyr/ephyr.c
index acf389c1d..4f1f19860 100644
--- a/hw/kdrive/ephyr/ephyr.c
+++ b/hw/kdrive/ephyr/ephyr.c
@@ -40,7 +40,7 @@
 #include "glamor.h"
 #endif
 #include "ephyr_glamor_glx.h"
-
+#include "glx_extinit.h"
 #include "xkbsrv.h"
 
 extern Bool ephyr_glamor;
diff --git a/hw/kdrive/ephyr/meson.build b/hw/kdrive/ephyr/meson.build
index 615649865..7b9225f26 100644
--- a/hw/kdrive/ephyr/meson.build
+++ b/hw/kdrive/ephyr/meson.build
@@ -56,6 +56,7 @@ executable(
         libxserver_xkb_stubs,
         libxserver_xi_stubs,
         libxserver_glx,
+        libglxvnd,
     ],
     install: true,
 )
diff --git a/hw/kdrive/src/kdrive.c b/hw/kdrive/src/kdrive.c
index 6dbb90856..6e8168323 100644
--- a/hw/kdrive/src/kdrive.c
+++ b/hw/kdrive/src/kdrive.c
@@ -30,6 +30,7 @@
 #ifdef RANDR
 #include <randrstr.h>
 #endif
+#include "glx_extinit.h"
 
 #ifdef XV
 #include "kxv.h"
@@ -973,6 +974,8 @@ KdInitOutput(ScreenInfo * pScreenInfo, int argc, char **argv)
         for (screen = card->screenList; screen; screen = screen->next)
             KdAddScreen(pScreenInfo, screen, argc, argv);
 
+    xorgGlxCreateVendor();
+
 #if defined(CONFIG_UDEV) || defined(CONFIG_HAL)
     if (SeatId) /* Enable input hot-plugging */
         config_pre_init();
diff --git a/hw/vfb/InitOutput.c b/hw/vfb/InitOutput.c
index 6d386ee2f..2b7bca5fa 100644
--- a/hw/vfb/InitOutput.c
+++ b/hw/vfb/InitOutput.c
@@ -1002,6 +1002,8 @@ InitOutput(ScreenInfo * screen_info, int argc, char **argv)
         vfbPixmapDepths[32] = TRUE;
     }
 
+    xorgGlxCreateVendor();
+
     for (i = 1; i <= 32; i++) {
         if (vfbPixmapDepths[i]) {
             if (NumFormats >= MAXFORMATS)
diff --git a/hw/vfb/meson.build b/hw/vfb/meson.build
index 89acdfacd..a0771c3a6 100644
--- a/hw/vfb/meson.build
+++ b/hw/vfb/meson.build
@@ -15,7 +15,8 @@ xvfb_server = executable(
         libxserver,
         libxserver_xkb_stubs,
         libxserver_xi_stubs,
-        libxserver_glx
+        libxserver_glx,
+        libglxvnd,
     ],
     install: true,
 )
diff --git a/hw/xfree86/Makefile.am b/hw/xfree86/Makefile.am
index 458720052..57c8b8dd4 100644
--- a/hw/xfree86/Makefile.am
+++ b/hw/xfree86/Makefile.am
@@ -14,6 +14,10 @@ DRI3_BUILDDIR = $(top_builddir)/dri3
 DRI3_LIB = $(DRI3_BUILDDIR)/libdri3.la
 endif
 
+if GLX
+GLXVND_LIB = $(top_builddir)/glx/libglxvnd.la
+endif
+
 if GLAMOR_EGL
 GLAMOR_EGL_SUBDIR = glamor_egl
 endif
@@ -70,6 +74,7 @@ LOCAL_LIBS = \
             $(DRI_LIB) \
             $(DRI2_LIB) \
 	    $(DRI3_LIB) \
+	    $(GLXVND_LIB) \
 	    $(top_builddir)/miext/sync/libsync.la \
             $(top_builddir)/mi/libmi.la \
             $(top_builddir)/os/libos.la \
diff --git a/hw/xfree86/common/xf86Init.c b/hw/xfree86/common/xf86Init.c
index f9843c719..cdbf80c61 100644
--- a/hw/xfree86/common/xf86Init.c
+++ b/hw/xfree86/common/xf86Init.c
@@ -78,7 +78,7 @@
 #include "xf86InPriv.h"
 #include "picturestr.h"
 #include "randrstr.h"
-
+#include "glxvndabi.h"
 #include "xf86Bus.h"
 #ifdef XSERVER_LIBPCIACCESS
 #include "xf86VGAarbiter.h"
diff --git a/hw/xfree86/dixmods/glxmodule.c b/hw/xfree86/dixmods/glxmodule.c
index bf7e65911..c3d92fa92 100644
--- a/hw/xfree86/dixmods/glxmodule.c
+++ b/hw/xfree86/dixmods/glxmodule.c
@@ -83,6 +83,7 @@ glxSetup(void *module, void *opts, int *errmaj, int *errmin)
     provider = LoaderSymbol("__glXDRI2Provider");
     if (provider)
         GlxPushProvider(provider);
+    xorgGlxCreateVendor();
 
     LoadExtensionList(GLXExt, ARRAY_SIZE(GLXExt), FALSE);
 
diff --git a/hw/xfree86/meson.build b/hw/xfree86/meson.build
index 629daf977..8fc53e4cf 100644
--- a/hw/xfree86/meson.build
+++ b/hw/xfree86/meson.build
@@ -51,6 +51,7 @@ srcs_xorg = [
 
 xorg_link = [
     libxserver,
+    libglxvnd,
     xorg_common,
     xorg_loader,
     xorg_ddc,
diff --git a/hw/xquartz/darwin.c b/hw/xquartz/darwin.c
index 71a65f3ce..c701eb6ac 100644
--- a/hw/xquartz/darwin.c
+++ b/hw/xquartz/darwin.c
@@ -50,7 +50,7 @@
 #include <X11/extensions/XIproto.h>
 #include "exevents.h"
 #include "extinit.h"
-
+#include "glx_extinit.h"
 #include "xserver-properties.h"
 
 #include <sys/types.h>
@@ -670,6 +670,8 @@ InitOutput(ScreenInfo *pScreenInfo, int argc, char **argv)
         AddScreen(DarwinScreenInit, argc, argv);
     }
 
+    xorgGlxCreateVendor();
+
     DarwinAdjustScreenOrigins(pScreenInfo);
 }
 
diff --git a/hw/xwayland/Makefile.am b/hw/xwayland/Makefile.am
index 7204591e3..173686e31 100644
--- a/hw/xwayland/Makefile.am
+++ b/hw/xwayland/Makefile.am
@@ -24,6 +24,7 @@ Xwayland_SOURCES =				\
 Xwayland_LDADD =				\
 	$(glamor_lib)				\
 	$(XWAYLAND_LIBS)			\
+	$(top_builddir)/glx/libglxvnd.la	\
 	$(XWAYLAND_SYS_LIBS)			\
 	$(top_builddir)/Xext/libXvidmode.la	\
 	$(XSERVER_SYS_LIBS)
diff --git a/hw/xwayland/meson.build b/hw/xwayland/meson.build
index 24203c63e..f6f75001c 100644
--- a/hw/xwayland/meson.build
+++ b/hw/xwayland/meson.build
@@ -70,6 +70,7 @@ executable(
         libxserver_xkb_stubs,
         libxserver_xi_stubs,
         libxserver_glx,
+        libglxvnd,
     ],
     install: true,
 )
diff --git a/hw/xwayland/xwayland.c b/hw/xwayland/xwayland.c
index 9b1d85674..7aba7bae2 100644
--- a/hw/xwayland/xwayland.c
+++ b/hw/xwayland/xwayland.c
@@ -1107,5 +1107,7 @@ InitOutput(ScreenInfo * screen_info, int argc, char **argv)
         FatalError("Couldn't add screen\n");
     }
 
+    xorgGlxCreateVendor();
+
     LocalAccessScopeUser();
 }
diff --git a/include/glx_extinit.h b/include/glx_extinit.h
index 710ca6e3e..32b8fcf72 100644
--- a/include/glx_extinit.h
+++ b/include/glx_extinit.h
@@ -40,7 +40,10 @@ struct __GLXprovider {
 extern __GLXprovider __glXDRISWRastProvider;
 
 void GlxPushProvider(__GLXprovider * provider);
-
+Bool xorgGlxCreateVendor(void);
+#else
+static inline Bool xorgGlxCreateVendor(void) { return TRUE; }
 #endif
 
+
 #endif
commit 8753218beae641e5c5ac2c2ba598cfb99a893cf4
Author: Kyle Brenneman <kbrenneman at nvidia.com>
Date:   Wed Jan 10 13:05:44 2018 -0500

    glx: Import glxvnd server module (v2)
    
    This is based on an out-of-tree module written by Kyle:
    
    https://github.com/kbrenneman/libglvnd/tree/server-libglx
    
    I (ajax) did a bunch of cosmetic fixes, ported it off xfree86 API,
    added request length checks, and fixed a minor bug or two.
    
    v2: Use separate functions to set/get a context tag's private data, and
    call the backend's MakeCurrent when a client disconnects to unbind the
    context. (Kyle Brenneman)
    
    Signed-off-by: Adam Jackson <ajax at redhat.com>

diff --git a/glx/Makefile.am b/glx/Makefile.am
index 699de63b8..cb71a3763 100644
--- a/glx/Makefile.am
+++ b/glx/Makefile.am
@@ -2,7 +2,7 @@ if DRI2
 GLXDRI_LIBRARY = libglxdri.la
 endif
 
-noinst_LTLIBRARIES = libglx.la $(GLXDRI_LIBRARY)
+noinst_LTLIBRARIES = libglx.la $(GLXDRI_LIBRARY) libglxvnd.la
 
 AM_CFLAGS = \
 	@DIX_CFLAGS@ \
@@ -83,3 +83,9 @@ libglx_la_SOURCES = \
         xfont.c
 
 libglx_la_LIBADD = $(DLOPEN_LIBS)
+
+libglxvnd_la_SOURCES = \
+	vndcmds.c \
+	vndext.c \
+	vndservermapping.c \
+	vndservervendor.c
diff --git a/glx/meson.build b/glx/meson.build
index f13f8f24b..5f93a75a5 100644
--- a/glx/meson.build
+++ b/glx/meson.build
@@ -53,3 +53,24 @@ srcs_glxdri2 = []
 if build_dri2 or build_dri3
     srcs_glxdri2 = files('glxdri2.c')
 endif
+
+srcs_vnd = [
+    'vndcmds.c',
+    'vndext.c',
+    'vndservermapping.c',
+    'vndservervendor.c',
+]
+
+libglxvnd = ''
+if build_glx
+    libglxvnd = static_library('libglxvnd',
+	srcs_vnd,
+	include_directories: inc,
+        dependencies: [
+            common_dep,
+            dl_dep,
+            dependency('glproto', version: '>= 1.4.17'),
+            dependency('gl', version: '>= 9.2.0'),
+        ],
+    )
+endif
diff --git a/glx/vnd_dispatch_stubs.c b/glx/vnd_dispatch_stubs.c
new file mode 100644
index 000000000..629160fe7
--- /dev/null
+++ b/glx/vnd_dispatch_stubs.c
@@ -0,0 +1,525 @@
+
+#include <dix-config.h>
+#include <dix.h>
+#include "vndserver.h"
+
+// HACK: The opcode in old glxproto.h has a typo in it.
+#if !defined(X_GLXCreateContextAttribsARB)
+#define X_GLXCreateContextAttribsARB X_GLXCreateContextAtrribsARB
+#endif
+
+static int dispatch_Render(ClientPtr client)
+{
+    REQUEST(xGLXRenderReq);
+    CARD32 contextTag;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_AT_LEAST_SIZE(*stuff);
+    contextTag = GlxCheckSwap(client, stuff->contextTag);
+    vendor = glxServer.getContextTag(client, contextTag);
+    if (vendor != NULL) {
+        int ret;
+        ret = glxServer.forwardRequest(vendor, client);
+        return ret;
+    } else {
+        client->errorValue = contextTag;
+        return GlxErrorBase + GLXBadContextTag;
+    }
+}
+static int dispatch_RenderLarge(ClientPtr client)
+{
+    REQUEST(xGLXRenderLargeReq);
+    CARD32 contextTag;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_AT_LEAST_SIZE(*stuff);
+    contextTag = GlxCheckSwap(client, stuff->contextTag);
+    vendor = glxServer.getContextTag(client, contextTag);
+    if (vendor != NULL) {
+        int ret;
+        ret = glxServer.forwardRequest(vendor, client);
+        return ret;
+    } else {
+        client->errorValue = contextTag;
+        return GlxErrorBase + GLXBadContextTag;
+    }
+}
+static int dispatch_CreateContext(ClientPtr client)
+{
+    REQUEST(xGLXCreateContextReq);
+    CARD32 screen, context;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_SIZE_MATCH(*stuff);
+    screen = GlxCheckSwap(client, stuff->screen);
+    context = GlxCheckSwap(client, stuff->context);
+    LEGAL_NEW_RESOURCE(context, client);
+    if (screen < screenInfo.numScreens) {
+        vendor = glxServer.getVendorForScreen(client, screenInfo.screens[screen]);
+    }
+    if (vendor != NULL) {
+        int ret;
+        if (!glxServer.addXIDMap(context, vendor)) {
+            return BadAlloc;
+        }
+        ret = glxServer.forwardRequest(vendor, client);
+        if (ret != Success) {
+            glxServer.removeXIDMap(context);
+        }
+        return ret;
+    } else {
+        client->errorValue = screen;
+        return BadMatch;
+    }
+}
+static int dispatch_DestroyContext(ClientPtr client)
+{
+    REQUEST(xGLXDestroyContextReq);
+    CARD32 context;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_SIZE_MATCH(*stuff);
+    context = GlxCheckSwap(client, stuff->context);
+    vendor = glxServer.getXIDMap(context);
+    if (vendor != NULL) {
+        int ret;
+        ret = glxServer.forwardRequest(vendor, client);
+        if (ret == Success) {
+            glxServer.removeXIDMap(context);
+        }
+        return ret;
+    } else {
+        client->errorValue = context;
+        return GlxErrorBase + GLXBadContext;
+    }
+}
+static int dispatch_WaitGL(ClientPtr client)
+{
+    REQUEST(xGLXWaitGLReq);
+    CARD32 contextTag;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_SIZE_MATCH(*stuff);
+    contextTag = GlxCheckSwap(client, stuff->contextTag);
+    vendor = glxServer.getContextTag(client, contextTag);
+    if (vendor != NULL) {
+        int ret;
+        ret = glxServer.forwardRequest(vendor, client);
+        return ret;
+    } else {
+        client->errorValue = contextTag;
+        return GlxErrorBase + GLXBadContextTag;
+    }
+}
+static int dispatch_WaitX(ClientPtr client)
+{
+    REQUEST(xGLXWaitXReq);
+    CARD32 contextTag;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_SIZE_MATCH(*stuff);
+    contextTag = GlxCheckSwap(client, stuff->contextTag);
+    vendor = glxServer.getContextTag(client, contextTag);
+    if (vendor != NULL) {
+        int ret;
+        ret = glxServer.forwardRequest(vendor, client);
+        return ret;
+    } else {
+        client->errorValue = contextTag;
+        return GlxErrorBase + GLXBadContextTag;
+    }
+}
+static int dispatch_UseXFont(ClientPtr client)
+{
+    REQUEST(xGLXUseXFontReq);
+    CARD32 contextTag;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_SIZE_MATCH(*stuff);
+    contextTag = GlxCheckSwap(client, stuff->contextTag);
+    vendor = glxServer.getContextTag(client, contextTag);
+    if (vendor != NULL) {
+        int ret;
+        ret = glxServer.forwardRequest(vendor, client);
+        return ret;
+    } else {
+        client->errorValue = contextTag;
+        return GlxErrorBase + GLXBadContextTag;
+    }
+}
+static int dispatch_CreateGLXPixmap(ClientPtr client)
+{
+    REQUEST(xGLXCreateGLXPixmapReq);
+    CARD32 screen, glxpixmap;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_SIZE_MATCH(*stuff);
+    screen = GlxCheckSwap(client, stuff->screen);
+    glxpixmap = GlxCheckSwap(client, stuff->glxpixmap);
+    LEGAL_NEW_RESOURCE(glxpixmap, client);
+    if (screen < screenInfo.numScreens) {
+        vendor = glxServer.getVendorForScreen(client, screenInfo.screens[screen]);
+    }
+    if (vendor != NULL) {
+        int ret;
+        if (!glxServer.addXIDMap(glxpixmap, vendor)) {
+            return BadAlloc;
+        }
+        ret = glxServer.forwardRequest(vendor, client);
+        if (ret != Success) {
+            glxServer.removeXIDMap(glxpixmap);
+        }
+        return ret;
+    } else {
+        client->errorValue = screen;
+        return BadMatch;
+    }
+}
+static int dispatch_GetVisualConfigs(ClientPtr client)
+{
+    REQUEST(xGLXGetVisualConfigsReq);
+    CARD32 screen;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_SIZE_MATCH(*stuff);
+    screen = GlxCheckSwap(client, stuff->screen);
+    if (screen < screenInfo.numScreens) {
+        vendor = glxServer.getVendorForScreen(client, screenInfo.screens[screen]);
+    }
+    if (vendor != NULL) {
+        int ret;
+        ret = glxServer.forwardRequest(vendor, client);
+        return ret;
+    } else {
+        client->errorValue = screen;
+        return BadMatch;
+    }
+}
+static int dispatch_DestroyGLXPixmap(ClientPtr client)
+{
+    REQUEST(xGLXDestroyGLXPixmapReq);
+    CARD32 glxpixmap;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_SIZE_MATCH(*stuff);
+    glxpixmap = GlxCheckSwap(client, stuff->glxpixmap);
+    vendor = glxServer.getXIDMap(glxpixmap);
+    if (vendor != NULL) {
+        int ret;
+        ret = glxServer.forwardRequest(vendor, client);
+        return ret;
+    } else {
+        client->errorValue = glxpixmap;
+        return GlxErrorBase + GLXBadPixmap;
+    }
+}
+static int dispatch_QueryExtensionsString(ClientPtr client)
+{
+    REQUEST(xGLXQueryExtensionsStringReq);
+    CARD32 screen;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_SIZE_MATCH(*stuff);
+    screen = GlxCheckSwap(client, stuff->screen);
+    if (screen < screenInfo.numScreens) {
+        vendor = glxServer.getVendorForScreen(client, screenInfo.screens[screen]);
+    }
+    if (vendor != NULL) {
+        int ret;
+        ret = glxServer.forwardRequest(vendor, client);
+        return ret;
+    } else {
+        client->errorValue = screen;
+        return BadMatch;
+    }
+}
+static int dispatch_QueryServerString(ClientPtr client)
+{
+    REQUEST(xGLXQueryServerStringReq);
+    CARD32 screen;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_SIZE_MATCH(*stuff);
+    screen = GlxCheckSwap(client, stuff->screen);
+    if (screen < screenInfo.numScreens) {
+        vendor = glxServer.getVendorForScreen(client, screenInfo.screens[screen]);
+    }
+    if (vendor != NULL) {
+        int ret;
+        ret = glxServer.forwardRequest(vendor, client);
+        return ret;
+    } else {
+        client->errorValue = screen;
+        return BadMatch;
+    }
+}
+static int dispatch_ChangeDrawableAttributes(ClientPtr client)
+{
+    REQUEST(xGLXChangeDrawableAttributesReq);
+    CARD32 drawable;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_AT_LEAST_SIZE(*stuff);
+    drawable = GlxCheckSwap(client, stuff->drawable);
+    vendor = glxServer.getXIDMap(drawable);
+    if (vendor != NULL) {
+        int ret;
+        ret = glxServer.forwardRequest(vendor, client);
+        return ret;
+    } else {
+        client->errorValue = drawable;
+        return BadDrawable;
+    }
+}
+static int dispatch_CreateNewContext(ClientPtr client)
+{
+    REQUEST(xGLXCreateNewContextReq);
+    CARD32 screen, context;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_SIZE_MATCH(*stuff);
+    screen = GlxCheckSwap(client, stuff->screen);
+    context = GlxCheckSwap(client, stuff->context);
+    LEGAL_NEW_RESOURCE(context, client);
+    if (screen < screenInfo.numScreens) {
+        vendor = glxServer.getVendorForScreen(client, screenInfo.screens[screen]);
+    }
+    if (vendor != NULL) {
+        int ret;
+        if (!glxServer.addXIDMap(context, vendor)) {
+            return BadAlloc;
+        }
+        ret = glxServer.forwardRequest(vendor, client);
+        if (ret != Success) {
+            glxServer.removeXIDMap(context);
+        }
+        return ret;
+    } else {
+        client->errorValue = screen;
+        return BadMatch;
+    }
+}
+static int dispatch_CreatePbuffer(ClientPtr client)
+{
+    REQUEST(xGLXCreatePbufferReq);
+    CARD32 screen, pbuffer;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_AT_LEAST_SIZE(*stuff);
+    screen = GlxCheckSwap(client, stuff->screen);
+    pbuffer = GlxCheckSwap(client, stuff->pbuffer);
+    LEGAL_NEW_RESOURCE(pbuffer, client);
+    if (screen < screenInfo.numScreens) {
+        vendor = glxServer.getVendorForScreen(client, screenInfo.screens[screen]);
+    }
+    if (vendor != NULL) {
+        int ret;
+        if (!glxServer.addXIDMap(pbuffer, vendor)) {
+            return BadAlloc;
+        }
+        ret = glxServer.forwardRequest(vendor, client);
+        if (ret != Success) {
+            glxServer.removeXIDMap(pbuffer);
+        }
+        return ret;
+    } else {
+        client->errorValue = screen;
+        return BadMatch;
+    }
+}
+static int dispatch_CreatePixmap(ClientPtr client)
+{
+    REQUEST(xGLXCreatePixmapReq);
+    CARD32 screen, glxpixmap;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_AT_LEAST_SIZE(*stuff);
+    screen = GlxCheckSwap(client, stuff->screen);
+    glxpixmap = GlxCheckSwap(client, stuff->glxpixmap);
+    LEGAL_NEW_RESOURCE(glxpixmap, client);
+    if (screen < screenInfo.numScreens) {
+        vendor = glxServer.getVendorForScreen(client, screenInfo.screens[screen]);
+    }
+    if (vendor != NULL) {
+        int ret;
+        if (!glxServer.addXIDMap(glxpixmap, vendor)) {
+            return BadAlloc;
+        }
+        ret = glxServer.forwardRequest(vendor, client);
+        if (ret != Success) {
+            glxServer.removeXIDMap(glxpixmap);
+        }
+        return ret;
+    } else {
+        client->errorValue = screen;
+        return BadMatch;
+    }
+}
+static int dispatch_CreateWindow(ClientPtr client)
+{
+    REQUEST(xGLXCreateWindowReq);
+    CARD32 screen, glxwindow;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_AT_LEAST_SIZE(*stuff);
+    screen = GlxCheckSwap(client, stuff->screen);
+    glxwindow = GlxCheckSwap(client, stuff->glxwindow);
+    LEGAL_NEW_RESOURCE(glxwindow, client);
+    if (screen < screenInfo.numScreens) {
+        vendor = glxServer.getVendorForScreen(client, screenInfo.screens[screen]);
+    }
+    if (vendor != NULL) {
+        int ret;
+        if (!glxServer.addXIDMap(glxwindow, vendor)) {
+            return BadAlloc;
+        }
+        ret = glxServer.forwardRequest(vendor, client);
+        if (ret != Success) {
+            glxServer.removeXIDMap(glxwindow);
+        }
+        return ret;
+    } else {
+        client->errorValue = screen;
+        return BadMatch;
+    }
+}
+static int dispatch_CreateContextAttribsARB(ClientPtr client)
+{
+    REQUEST(xGLXCreateContextAttribsARBReq);
+    CARD32 screen, context;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_AT_LEAST_SIZE(*stuff);
+    screen = GlxCheckSwap(client, stuff->screen);
+    context = GlxCheckSwap(client, stuff->context);
+    LEGAL_NEW_RESOURCE(context, client);
+    if (screen < screenInfo.numScreens) {
+        vendor = glxServer.getVendorForScreen(client, screenInfo.screens[screen]);
+    }
+    if (vendor != NULL) {
+        int ret;
+        if (!glxServer.addXIDMap(context, vendor)) {
+            return BadAlloc;
+        }
+        ret = glxServer.forwardRequest(vendor, client);
+        if (ret != Success) {
+            glxServer.removeXIDMap(context);
+        }
+        return ret;
+    } else {
+        client->errorValue = screen;
+        return BadMatch;
+    }
+}
+static int dispatch_DestroyPbuffer(ClientPtr client)
+{
+    REQUEST(xGLXDestroyPbufferReq);
+    CARD32 pbuffer;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_SIZE_MATCH(*stuff);
+    pbuffer = GlxCheckSwap(client, stuff->pbuffer);
+    vendor = glxServer.getXIDMap(pbuffer);
+    if (vendor != NULL) {
+        int ret;
+        ret = glxServer.forwardRequest(vendor, client);
+        if (ret == Success) {
+            glxServer.removeXIDMap(pbuffer);
+        }
+        return ret;
+    } else {
+        client->errorValue = pbuffer;
+        return GlxErrorBase + GLXBadPbuffer;
+    }
+}
+static int dispatch_DestroyPixmap(ClientPtr client)
+{
+    REQUEST(xGLXDestroyPixmapReq);
+    CARD32 glxpixmap;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_SIZE_MATCH(*stuff);
+    glxpixmap = GlxCheckSwap(client, stuff->glxpixmap);
+    vendor = glxServer.getXIDMap(glxpixmap);
+    if (vendor != NULL) {
+        int ret;
+        ret = glxServer.forwardRequest(vendor, client);
+        if (ret == Success) {
+            glxServer.removeXIDMap(glxpixmap);
+        }
+        return ret;
+    } else {
+        client->errorValue = glxpixmap;
+        return GlxErrorBase + GLXBadPixmap;
+    }
+}
+static int dispatch_DestroyWindow(ClientPtr client)
+{
+    REQUEST(xGLXDestroyWindowReq);
+    CARD32 glxwindow;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_SIZE_MATCH(*stuff);
+    glxwindow = GlxCheckSwap(client, stuff->glxwindow);
+    vendor = glxServer.getXIDMap(glxwindow);
+    if (vendor != NULL) {
+        int ret;
+        ret = glxServer.forwardRequest(vendor, client);
+        if (ret == Success) {
+            glxServer.removeXIDMap(glxwindow);
+        }
+        return ret;
+    } else {
+        client->errorValue = glxwindow;
+        return GlxErrorBase + GLXBadWindow;
+    }
+}
+static int dispatch_GetDrawableAttributes(ClientPtr client)
+{
+    REQUEST(xGLXGetDrawableAttributesReq);
+    CARD32 drawable;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_SIZE_MATCH(*stuff);
+    drawable = GlxCheckSwap(client, stuff->drawable);
+    vendor = glxServer.getXIDMap(drawable);
+    if (vendor != NULL) {
+        int ret;
+        ret = glxServer.forwardRequest(vendor, client);
+        return ret;
+    } else {
+        client->errorValue = drawable;
+        return BadDrawable;
+    }
+}
+static int dispatch_GetFBConfigs(ClientPtr client)
+{
+    REQUEST(xGLXGetFBConfigsReq);
+    CARD32 screen;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_SIZE_MATCH(*stuff);
+    screen = GlxCheckSwap(client, stuff->screen);
+    if (screen < screenInfo.numScreens) {
+        vendor = glxServer.getVendorForScreen(client, screenInfo.screens[screen]);
+    }
+    if (vendor != NULL) {
+        int ret;
+        ret = glxServer.forwardRequest(vendor, client);
+        return ret;
+    } else {
+        client->errorValue = screen;
+        return BadMatch;
+    }
+}
+static int dispatch_QueryContext(ClientPtr client)
+{
+    REQUEST(xGLXQueryContextReq);
+    CARD32 context;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_SIZE_MATCH(*stuff);
+    context = GlxCheckSwap(client, stuff->context);
+    vendor = glxServer.getXIDMap(context);
+    if (vendor != NULL) {
+        int ret;
+        ret = glxServer.forwardRequest(vendor, client);
+        return ret;
+    } else {
+        client->errorValue = context;
+        return GlxErrorBase + GLXBadContext;
+    }
+}
+static int dispatch_IsDirect(ClientPtr client)
+{
+    REQUEST(xGLXIsDirectReq);
+    CARD32 context;
+    GlxServerVendor *vendor = NULL;
+    REQUEST_SIZE_MATCH(*stuff);
+    context = GlxCheckSwap(client, stuff->context);
+    vendor = glxServer.getXIDMap(context);
+    if (vendor != NULL) {
+        int ret;
+        ret = glxServer.forwardRequest(vendor, client);
+        return ret;
+    } else {
+        client->errorValue = context;
+        return GlxErrorBase + GLXBadContext;
+    }
+}
diff --git a/glx/vndcmds.c b/glx/vndcmds.c
new file mode 100644
index 000000000..200176d4c
--- /dev/null
+++ b/glx/vndcmds.c
@@ -0,0 +1,483 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * unaltered in all copies or substantial portions of the Materials.
+ * Any additions, deletions, or changes to the original source files
+ * must be clearly indicated in accompanying documentation.
+ *
+ * If only executable code is distributed, then the accompanying
+ * documentation must state that "this software is based in part on the
+ * work of the Khronos Group."
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ */
+
+#include <dix-config.h>
+
+#include "hashtable.h"
+#include "vndserver.h"
+#include "vndservervendor.h"
+
+/**
+ * The length of the dispatchFuncs array. Every opcode above this is a
+ * X_GLsop_* code, which all can use the same handler.
+ */
+#define OPCODE_ARRAY_LEN 100
+
+// This hashtable is used to keep track of the dispatch stubs for
+// GLXVendorPrivate and GLXVendorPrivateWithReply.
+typedef struct GlxVendorPrivDispatchRec {
+    CARD32 vendorCode;
+    GlxServerDispatchProc proc;
+    HashTable hh;
+} GlxVendorPrivDispatch;
+
+static GlxServerDispatchProc dispatchFuncs[OPCODE_ARRAY_LEN] = {};
+static HashTable vendorPrivHash = NULL;
+static HtGenericHashSetupRec vendorPrivSetup = {
+    .keySize = sizeof(void*)
+};
+
+static int DispatchBadRequest(ClientPtr client)
+{
+    return BadRequest;
+}
+
+static GlxVendorPrivDispatch *LookupVendorPrivDispatch(CARD32 vendorCode, Bool create)
+{
+    GlxVendorPrivDispatch *disp = NULL;
+
+    disp = ht_find(vendorPrivHash, &vendorCode);
+    if (disp == NULL && create) {
+        if ((disp = ht_add(vendorPrivHash, &vendorCode))) {
+            disp->vendorCode = vendorCode;
+            disp->proc = NULL;
+        }
+    }
+
+    return disp;
+}
+
+static GlxServerDispatchProc GetVendorDispatchFunc(CARD8 opcode, CARD32 vendorCode)
+{
+    GlxServerVendor *vendor;
+
+    xorg_list_for_each_entry(vendor, &GlxVendorList, entry) {
+        GlxServerDispatchProc proc = vendor->glxvc.getDispatchAddress(opcode, vendorCode);
+        if (proc != NULL) {
+            return proc;
+        }
+    }
+
+    return DispatchBadRequest;
+}
+
+static void SetReplyHeader(ClientPtr client, void *replyPtr)
+{
+    xGenericReply *rep = (xGenericReply *) replyPtr;
+    rep->type = X_Reply;
+    rep->sequenceNumber = client->sequence;
+    rep->length = 0;
+}
+
+/* Include the trivial dispatch handlers */
+#include "vnd_dispatch_stubs.c"
+
+static int dispatch_GLXQueryVersion(ClientPtr client)
+{
+    xGLXQueryVersionReply reply;
+    REQUEST_SIZE_MATCH(xGLXQueryVersionReq);
+
+    SetReplyHeader(client, &reply);
+    reply.majorVersion = GlxCheckSwap(client, 1);
+    reply.minorVersion = GlxCheckSwap(client, 4);
+
+    WriteToClient(client, sz_xGLXQueryVersionReply, &reply);
+    return Success;
+}
+
+/* broken header workaround */
+#ifndef X_GLXSetClientInfo2ARB
+#define X_GLXSetClientInfo2ARB X_GLXSetConfigInfo2ARB
+#endif
+
+/**
+ * This function is used for X_GLXClientInfo, X_GLXSetClientInfoARB, and
+ * X_GLXSetClientInfo2ARB.
+ */
+static int dispatch_GLXClientInfo(ClientPtr client)
+{
+    GlxServerVendor *vendor;
+    void *requestCopy = NULL;
+    size_t requestSize = client->req_len * 4;
+
+    if (client->minorOp == X_GLXClientInfo) {
+        REQUEST_AT_LEAST_SIZE(xGLXClientInfoReq);
+    } else if (client->minorOp == X_GLXSetClientInfoARB) {
+        REQUEST_AT_LEAST_SIZE(xGLXSetClientInfoARBReq);
+    } else if (client->minorOp == X_GLXSetClientInfo2ARB) {
+        REQUEST_AT_LEAST_SIZE(xGLXSetClientInfo2ARBReq);
+    } else {
+        return BadImplementation;
+    }
+
+    // We'll forward this request to each vendor library. Since a vendor might
+    // modify the request data in place (e.g., for byte swapping), make a copy
+    // of the request first.
+    requestCopy = malloc(requestSize);
+    if (requestCopy == NULL) {
+        return BadAlloc;
+    }
+    memcpy(requestCopy, client->requestBuffer, requestSize);
+
+    xorg_list_for_each_entry(vendor, &GlxVendorList, entry) {
+        vendor->glxvc.handleRequest(client);
+        // Revert the request buffer back to our copy.
+        memcpy(client->requestBuffer, requestCopy, requestSize);
+    }
+    free(requestCopy);
+    return Success;
+}
+
+static int CommonLoseCurrent(ClientPtr client, GlxContextTagInfo *tagInfo)
+{
+    int ret;
+
+    ret = tagInfo->vendor->glxvc.makeCurrent(client,
+            tagInfo->tag, // No old context tag,
+            None, None, None, 0);
+
+    if (ret == Success) {
+        GlxFreeContextTag(tagInfo);
+    }
+    return ret;
+}
+
+static int CommonMakeNewCurrent(ClientPtr client,
+        GlxServerVendor *vendor,
+        GLXDrawable drawable,
+        GLXDrawable readdrawable,
+        GLXContextID context,
+        GLXContextTag *newContextTag)
+{
+    int ret = BadAlloc;
+    GlxContextTagInfo *tagInfo;
+
+    tagInfo = GlxAllocContextTag(client, vendor);
+
+    if (tagInfo) {
+        ret = vendor->glxvc.makeCurrent(client,
+                0, // No old context tag,
+                drawable, readdrawable, context,
+                tagInfo->tag);
+
+        if (ret == Success) {
+            tagInfo->drawable = drawable;
+            tagInfo->readdrawable = readdrawable;
+            tagInfo->context = context;
+            *newContextTag = tagInfo->tag;
+        } else {
+            GlxFreeContextTag(tagInfo);
+        }
+    }
+
+    return ret;
+}
+
+static int CommonMakeCurrent(ClientPtr client,
+        GLXContextTag oldContextTag,
+        GLXDrawable drawable,
+        GLXDrawable readdrawable,
+        GLXContextID context)
+{
+    xGLXMakeCurrentReply reply = {};
+    GlxContextTagInfo *oldTag = NULL;
+    GlxServerVendor *newVendor = NULL;
+
+    oldContextTag = GlxCheckSwap(client, oldContextTag);
+    drawable = GlxCheckSwap(client, drawable);
+    readdrawable = GlxCheckSwap(client, readdrawable);
+    context = GlxCheckSwap(client, context);
+
+    SetReplyHeader(client, &reply);
+
+    if (oldContextTag != 0) {
+        oldTag = GlxLookupContextTag(client, oldContextTag);
+        if (oldTag == NULL) {
+            return GlxErrorBase + GLXBadContextTag;
+        }
+    }
+    if (context != 0) {
+        newVendor = GlxGetXIDMap(context);
+        if (newVendor == NULL) {
+            return GlxErrorBase + GLXBadContext;
+        }
+    }
+
+    if (oldTag == NULL && newVendor == NULL) {
+        // Nothing to do here. Just send a successful reply.
+        reply.contextTag = 0;
+    } else if (oldTag != NULL && newVendor != NULL
+            && oldTag->context == context
+            && oldTag->drawable == drawable
+            && oldTag->readdrawable == readdrawable)
+    {
+        // The old and new values are all the same, so send a successful reply.
+        reply.contextTag = oldTag->tag;
+    } else {
+        // TODO: For switching contexts in a single vendor, just make one
+        // makeCurrent call?
+
+        // TODO: When changing vendors, would it be better to do the
+        // MakeCurrent(new) first, then the LoseCurrent(old)?
+        // If the MakeCurrent(new) fails, then the old context will still be current.
+        // If the LoseCurrent(old) fails, then we can (probably) undo the MakeCurrent(new) with
+        // a LoseCurrent(old).
+        // But, if the recovery LoseCurrent(old) fails, then we're really in a bad state.
+
+        // Clear the old context first.
+        if (oldTag != NULL) {
+            int ret = CommonLoseCurrent(client, oldTag);
+            if (ret != Success) {
+                return ret;
+            }
+            oldTag = NULL;
+        }
+
+        if (newVendor != NULL) {
+            int ret = CommonMakeNewCurrent(client, newVendor, drawable, readdrawable, context, &reply.contextTag);
+            if (ret != Success) {
+                return ret;
+            }
+        } else {
+            reply.contextTag = 0;
+        }
+    }
+
+    reply.contextTag = GlxCheckSwap(client, reply.contextTag);
+    WriteToClient(client, sz_xGLXMakeCurrentReply, &reply);
+    return Success;
+}
+
+static int dispatch_GLXMakeCurrent(ClientPtr client)
+{
+    REQUEST(xGLXMakeCurrentReq);
+    REQUEST_SIZE_MATCH(*stuff);
+
+    return CommonMakeCurrent(client, stuff->oldContextTag,
+            stuff->drawable, stuff->drawable, stuff->context);
+}
+
+static int dispatch_GLXMakeContextCurrent(ClientPtr client)
+{
+    REQUEST(xGLXMakeContextCurrentReq);
+    REQUEST_SIZE_MATCH(*stuff);
+
+    return CommonMakeCurrent(client, stuff->oldContextTag,
+            stuff->drawable, stuff->readdrawable, stuff->context);
+}
+
+static int dispatch_GLXMakeCurrentReadSGI(ClientPtr client)
+{
+    REQUEST(xGLXMakeCurrentReadSGIReq);
+    REQUEST_SIZE_MATCH(*stuff);
+
+    return CommonMakeCurrent(client, stuff->oldContextTag,
+            stuff->drawable, stuff->readable, stuff->context);
+}
+
+static int dispatch_GLXCopyContext(ClientPtr client)
+{
+    REQUEST(xGLXCopyContextReq);
+    GlxServerVendor *vendor;
+    REQUEST_SIZE_MATCH(*stuff);
+
+    // If we've got a context tag, then we'll use it to select a vendor. If we
+    // don't have a tag, then we'll look up one of the contexts. In either
+    // case, it's up to the vendor library to make sure that the context ID's
+    // are valid.
+    if (stuff->contextTag != 0) {
+        GlxContextTagInfo *tagInfo = GlxLookupContextTag(client, GlxCheckSwap(client, stuff->contextTag));
+        if (tagInfo == NULL) {
+            return GlxErrorBase + GLXBadContextTag;
+        }
+        vendor = tagInfo->vendor;
+    } else {
+        vendor = GlxGetXIDMap(GlxCheckSwap(client, stuff->source));
+        if (vendor == NULL) {
+            return GlxErrorBase + GLXBadContext;
+        }
+    }
+    return vendor->glxvc.handleRequest(client);
+}
+
+static int dispatch_GLXSwapBuffers(ClientPtr client)
+{
+    GlxServerVendor *vendor = NULL;
+    REQUEST(xGLXSwapBuffersReq);
+    REQUEST_SIZE_MATCH(*stuff);
+
+    if (stuff->contextTag != 0) {
+        // If the request has a context tag, then look up a vendor from that.
+        // The vendor library is then responsible for validating the drawable.
+        GlxContextTagInfo *tagInfo = GlxLookupContextTag(client, GlxCheckSwap(client, stuff->contextTag));
+        if (tagInfo == NULL) {
+            return GlxErrorBase + GLXBadContextTag;
+        }
+        vendor = tagInfo->vendor;
+    } else {
+        // We don't have a context tag, so look up the vendor from the
+        // drawable.
+        vendor = GlxGetXIDMap(GlxCheckSwap(client, stuff->drawable));
+        if (vendor == NULL) {
+            return GlxErrorBase + GLXBadDrawable;
+        }
+    }
+
+    return vendor->glxvc.handleRequest(client);
+}
+
+/**
+ * This is a generic handler for all of the X_GLXsop* requests.
+ */
+static int dispatch_GLXSingle(ClientPtr client)
+{
+    REQUEST(xGLXSingleReq);
+    GlxContextTagInfo *tagInfo;
+    REQUEST_AT_LEAST_SIZE(*stuff);
+
+    tagInfo = GlxLookupContextTag(client, GlxCheckSwap(client, stuff->contextTag));
+    if (tagInfo != NULL) {
+        return tagInfo->vendor->glxvc.handleRequest(client);
+    } else {
+        return GlxErrorBase + GLXBadContextTag;
+    }
+}
+
+static int dispatch_GLXVendorPriv(ClientPtr client)
+{
+    GlxVendorPrivDispatch *disp;
+    REQUEST(xGLXVendorPrivateReq);
+    REQUEST_AT_LEAST_SIZE(*stuff);
+
+    disp = LookupVendorPrivDispatch(GlxCheckSwap(client, stuff->vendorCode), TRUE);
+    if (disp == NULL) {
+        return BadAlloc;
+    }
+
+    if (disp->proc == NULL) {
+        // We don't have a dispatch function for this request yet. Check with
+        // each vendor library to find one.
+        // Note that even if none of the vendors provides a dispatch stub,
+        // we'll still add an entry to the dispatch table, so that we don't
+        // have to look it up again later.
+        disp = (GlxVendorPrivDispatch *) malloc(sizeof(GlxVendorPrivDispatch));
+        disp->proc = GetVendorDispatchFunc(stuff->glxCode,
+                                           GlxCheckSwap(client,
+                                                        stuff->vendorCode));
+        if (disp->proc == NULL) {
+            disp->proc = DispatchBadRequest;
+        }
+    }
+    return disp->proc(client);
+}
+
+Bool GlxDispatchInit(void)
+{
+    GlxVendorPrivDispatch *disp;
+
+    vendorPrivHash = ht_create(sizeof(CARD32), sizeof(GlxVendorPrivDispatch),
+                               ht_generic_hash, ht_generic_compare,
+                               (void *) &vendorPrivSetup);
+    if (!vendorPrivHash) {
+        return FALSE;
+    }
+
+    // Assign a custom dispatch stub GLXMakeCurrentReadSGI. This is the only
+    // vendor private request that we need to deal with in libglvnd itself.
+    disp = LookupVendorPrivDispatch(X_GLXvop_MakeCurrentReadSGI, TRUE);
+    if (disp == NULL) {
+        return FALSE;
+    }
+    disp->proc = dispatch_GLXMakeCurrentReadSGI;
+
+    // Assign the dispatch stubs for requests that need special handling.
+    dispatchFuncs[X_GLXQueryVersion] = dispatch_GLXQueryVersion;
+    dispatchFuncs[X_GLXMakeCurrent] = dispatch_GLXMakeCurrent;
+    dispatchFuncs[X_GLXMakeContextCurrent] = dispatch_GLXMakeContextCurrent;
+    dispatchFuncs[X_GLXCopyContext] = dispatch_GLXCopyContext;
+    dispatchFuncs[X_GLXSwapBuffers] = dispatch_GLXSwapBuffers;
+
+    dispatchFuncs[X_GLXClientInfo] = dispatch_GLXClientInfo;
+    dispatchFuncs[X_GLXSetClientInfoARB] = dispatch_GLXClientInfo;
+    dispatchFuncs[X_GLXSetClientInfo2ARB] = dispatch_GLXClientInfo;
+
+    dispatchFuncs[X_GLXVendorPrivate] = dispatch_GLXVendorPriv;
+    dispatchFuncs[X_GLXVendorPrivateWithReply] = dispatch_GLXVendorPriv;
+
+    // Assign the trivial stubs
+    dispatchFuncs[X_GLXRender] = dispatch_Render;
+    dispatchFuncs[X_GLXRenderLarge] = dispatch_RenderLarge;
+    dispatchFuncs[X_GLXCreateContext] = dispatch_CreateContext;
+    dispatchFuncs[X_GLXDestroyContext] = dispatch_DestroyContext;
+    dispatchFuncs[X_GLXWaitGL] = dispatch_WaitGL;
+    dispatchFuncs[X_GLXWaitX] = dispatch_WaitX;
+    dispatchFuncs[X_GLXUseXFont] = dispatch_UseXFont;
+    dispatchFuncs[X_GLXCreateGLXPixmap] = dispatch_CreateGLXPixmap;
+    dispatchFuncs[X_GLXGetVisualConfigs] = dispatch_GetVisualConfigs;
+    dispatchFuncs[X_GLXDestroyGLXPixmap] = dispatch_DestroyGLXPixmap;
+    dispatchFuncs[X_GLXQueryExtensionsString] = dispatch_QueryExtensionsString;
+    dispatchFuncs[X_GLXQueryServerString] = dispatch_QueryServerString;
+    dispatchFuncs[X_GLXChangeDrawableAttributes] = dispatch_ChangeDrawableAttributes;
+    dispatchFuncs[X_GLXCreateNewContext] = dispatch_CreateNewContext;
+    dispatchFuncs[X_GLXCreatePbuffer] = dispatch_CreatePbuffer;
+    dispatchFuncs[X_GLXCreatePixmap] = dispatch_CreatePixmap;
+    dispatchFuncs[X_GLXCreateWindow] = dispatch_CreateWindow;
+    dispatchFuncs[X_GLXCreateContextAttribsARB] = dispatch_CreateContextAttribsARB;
+    dispatchFuncs[X_GLXDestroyPbuffer] = dispatch_DestroyPbuffer;
+    dispatchFuncs[X_GLXDestroyPixmap] = dispatch_DestroyPixmap;
+    dispatchFuncs[X_GLXDestroyWindow] = dispatch_DestroyWindow;
+    dispatchFuncs[X_GLXGetDrawableAttributes] = dispatch_GetDrawableAttributes;
+    dispatchFuncs[X_GLXGetFBConfigs] = dispatch_GetFBConfigs;
+    dispatchFuncs[X_GLXQueryContext] = dispatch_QueryContext;
+    dispatchFuncs[X_GLXIsDirect] = dispatch_IsDirect;
+
+    return TRUE;
+}
+
+void GlxDispatchReset(void)
+{
+    memset(dispatchFuncs, 0, sizeof(dispatchFuncs));
+
+    ht_destroy(vendorPrivHash);
+    vendorPrivHash = NULL;
+}
+
+int GlxDispatchRequest(ClientPtr client)
+{
+    REQUEST(xReq);
+    if (stuff->data < OPCODE_ARRAY_LEN) {
+        if (dispatchFuncs[stuff->data] == NULL) {
+            // Try to find a dispatch stub.
+            dispatchFuncs[stuff->data] = GetVendorDispatchFunc(stuff->data, 0);
+        }
+        return dispatchFuncs[stuff->data](client);
+    } else {
+        return dispatch_GLXSingle(client);
+    }
+}
diff --git a/glx/vndext.c b/glx/vndext.c
new file mode 100644
index 000000000..f593c499a
--- /dev/null
+++ b/glx/vndext.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * unaltered in all copies or substantial portions of the Materials.
+ * Any additions, deletions, or changes to the original source files
+ * must be clearly indicated in accompanying documentation.
+ *
+ * If only executable code is distributed, then the accompanying
+ * documentation must state that "this software is based in part on the
+ * work of the Khronos Group."
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ */
+
+#include "vndserver.h"
+
+#include <string.h>
+#include <scrnintstr.h>
+#include <windowstr.h>
+#include <dixstruct.h>
+#include <extnsionst.h>
+#include <glx_extinit.h>
+
+#include <GL/glxproto.h>
+#include "vndservervendor.h"
+
+int GlxErrorBase = 0;
+static CallbackListPtr vndInitCallbackList;
+static DevPrivateKeyRec glvXGLVScreenPrivKey;
+static DevPrivateKeyRec glvXGLVClientPrivKey;
+
+// The resource type used to keep track of the vendor library for XID's.
+RESTYPE idResource;
+
+static int
+idResourceDeleteCallback(void *value, XID id)
+{
+    return 0;
+}
+
+static GlxScreenPriv *
+xglvGetScreenPrivate(ScreenPtr pScreen)
+{
+    return dixLookupPrivate(&pScreen->devPrivates, &glvXGLVScreenPrivKey);
+}
+
+static void
+xglvSetScreenPrivate(ScreenPtr pScreen, void *priv)
+{
+    dixSetPrivate(&pScreen->devPrivates, &glvXGLVScreenPrivKey, priv);
+}
+
+GlxScreenPriv *
+GlxGetScreen(ScreenPtr pScreen)
+{
+    if (pScreen != NULL) {
+        GlxScreenPriv *priv = xglvGetScreenPrivate(pScreen);
+        if (priv == NULL) {
+            priv = calloc(1, sizeof(GlxScreenPriv));
+            if (priv == NULL) {
+                return NULL;
+            }
+
+            xglvSetScreenPrivate(pScreen, priv);
+        }
+        return priv;
+    } else {
+        return NULL;
+    }
+}
+
+static void
+GlxMappingReset(void)
+{
+    int i;
+
+    for (i=0; i<screenInfo.numScreens; i++) {
+        GlxScreenPriv *priv = xglvGetScreenPrivate(screenInfo.screens[i]);
+        if (priv != NULL) {
+            xglvSetScreenPrivate(screenInfo.screens[i], NULL);
+            free(priv);
+        }
+    }
+}
+
+static Bool
+GlxMappingInit(void)
+{
+    int i;
+
+    for (i=0; i<screenInfo.numScreens; i++) {
+        if (GlxGetScreen(screenInfo.screens[i]) == NULL) {
+            GlxMappingReset();
+            return FALSE;
+        }
+    }
+
+    idResource = CreateNewResourceType(idResourceDeleteCallback,
+                                       "GLXServerIDRes");
+    if (idResource == RT_NONE)
+    {
+        GlxMappingReset();
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static GlxClientPriv *
+xglvGetClientPrivate(ClientPtr pClient)
+{
+    return dixLookupPrivate(&pClient->devPrivates, &glvXGLVClientPrivKey);
+}
+
+static void
+xglvSetClientPrivate(ClientPtr pClient, void *priv)
+{
+    dixSetPrivate(&pClient->devPrivates, &glvXGLVClientPrivKey, priv);
+}
+
+GlxClientPriv *
+GlxGetClientData(ClientPtr client)
+{
+    GlxClientPriv *cl = xglvGetClientPrivate(client);
+    if (cl == NULL) {
+        cl = calloc(1, sizeof(GlxClientPriv));
+        if (cl != NULL) {
+            xglvSetClientPrivate(client, cl);
+        }
+    }
+    return cl;
+}
+
+void
+GlxFreeClientData(ClientPtr client)
+{
+    GlxClientPriv *cl = xglvGetClientPrivate(client);
+    if (cl != NULL) {
+        unsigned int i;
+        for (i = 0; i < cl->contextTagCount; i++) {
+            GlxContextTagInfo *tag = &cl->contextTags[i];
+            if (tag->vendor != NULL) {
+                tag->vendor->glxvc.makeCurrent(client, tag->tag,
+                                               None, None, None, 0);
+            }
+        }
+        xglvSetClientPrivate(client, NULL);
+        free(cl->contextTags);
+        free(cl);
+    }
+}
+
+static void
+GLXClientCallback(CallbackListPtr *list, void *closure, void *data)
+{
+    NewClientInfoRec *clientinfo = (NewClientInfoRec *) data;
+    ClientPtr client = clientinfo->client;
+
+    switch (client->clientState)
+    {
+        case ClientStateRetained:
+        case ClientStateGone:
+            GlxFreeClientData(client);
+            break;
+    }
+}
+
+static void
+GLXReset(ExtensionEntry *extEntry)
+{
+    // xf86Msg(X_INFO, "GLX: GLXReset\n");
+
+    GlxVendorExtensionReset(extEntry);
+    GlxDispatchReset();
+    GlxMappingReset();
+}
+
+void
+GlxExtensionInit(void)
+{
+    ExtensionEntry *extEntry;
+
+    // Init private keys, per-screen data
+    if (!dixRegisterPrivateKey(&glvXGLVScreenPrivKey, PRIVATE_SCREEN, 0))
+        return;
+    if (!dixRegisterPrivateKey(&glvXGLVClientPrivKey, PRIVATE_CLIENT, 0))
+        return;
+
+    if (!GlxMappingInit()) {
+        return;
+    }
+
+    if (!GlxDispatchInit()) {
+        return;
+    }
+
+    if (!AddCallback(&ClientStateCallback, GLXClientCallback, NULL)) {
+        return;
+    }
+
+    extEntry = AddExtension(GLX_EXTENSION_NAME, __GLX_NUMBER_EVENTS,
+                            __GLX_NUMBER_ERRORS, GlxDispatchRequest,
+                            GlxDispatchRequest, GLXReset, StandardMinorOpcode);
+    if (!extEntry) {
+        return;
+    }
+
+    GlxErrorBase = extEntry->errorBase;
+    CallCallbacks(&vndInitCallbackList, extEntry);
+}
+
+static int
+GlxForwardRequest(GlxServerVendor *vendor, ClientPtr client)
+{
+    return vendor->glxvc.handleRequest(client);
+}
+
+static GlxServerVendor *
+GlxGetContextTag(ClientPtr client, GLXContextTag tag)
+{
+    GlxContextTagInfo *tagInfo = GlxLookupContextTag(client, tag);
+
+    if (tagInfo != NULL) {
+        return tagInfo->vendor;
+    } else {
+        return NULL;
+    }
+}
+
+static Bool
+GlxSetContextTagPrivate(ClientPtr client, GLXContextTag tag, void *data)
+{
+    GlxContextTagInfo *tagInfo = GlxLookupContextTag(client, tag);
+    if (tagInfo != NULL) {
+        tagInfo->data = data;
+        return TRUE;
+    } else {
+        return FALSE;
+    }
+}
+
+static void *
+GlxGetContextTagPrivate(ClientPtr client, GLXContextTag tag)
+{
+    GlxContextTagInfo *tagInfo = GlxLookupContextTag(client, tag);
+    if (tagInfo != NULL) {
+        return tagInfo->data;
+    } else {
+        return NULL;
+    }
+}
+
+static GlxServerImports *
+GlxAllocateServerImports(void)
+{
+    return calloc(1, sizeof(GlxServerImports));
+}
+
+static void
+GlxFreeServerImports(GlxServerImports *imports)
+{
+    free(imports);
+}
+
+_X_EXPORT const GlxServerExports glxServer = {
+    GLXSERVER_VENDOR_ABI_MAJOR_VERSION, // majorVersion
+    GLXSERVER_VENDOR_ABI_MINOR_VERSION, // minorVersion
+
+    &vndInitCallbackList,
+
+    GlxAllocateServerImports, // allocateServerImports
+    GlxFreeServerImports, // freeServerImports
+
+    GlxCreateVendor, // createVendor
+    GlxDestroyVendor, // destroyVendor
+    GlxSetScreenVendor, // setScreenVendor
+
+    GlxAddXIDMap, // addXIDMap
+    GlxGetXIDMap, // getXIDMap
+    GlxRemoveXIDMap, // removeXIDMap
+    GlxGetContextTag, // getContextTag
+    GlxSetContextTagPrivate, // setContextTagPrivate
+    GlxGetContextTagPrivate, // getContextTagPrivate
+    GlxGetVendorForScreen, // getVendorForScreen
+    GlxForwardRequest, // forwardRequest
+};
+
+const GlxServerExports *
+glvndGetExports(void)
+{
+    return &glxServer;
+}
diff --git a/glx/vndserver.h b/glx/vndserver.h
new file mode 100644
index 000000000..12297349c
--- /dev/null
+++ b/glx/vndserver.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * unaltered in all copies or substantial portions of the Materials.
+ * Any additions, deletions, or changes to the original source files
+ * must be clearly indicated in accompanying documentation.
+ *
+ * If only executable code is distributed, then the accompanying
+ * documentation must state that "this software is based in part on the
+ * work of the Khronos Group."
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ */
+
+#ifndef VNDSERVER_H
+#define VNDSERVER_H
+
+#include <dix-config.h>
+#include "glxvndabi.h"
+
+#define GLXContextID CARD32
+#define GLXDrawable CARD32
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+typedef struct GlxScreenPrivRec {
+    GlxServerVendor *vendor;
+} GlxScreenPriv;
+
+typedef struct GlxContextTagInfoRec {
+    GLXContextTag tag;
+    ClientPtr client;
+    GlxServerVendor *vendor;
+    void *data;
+    GLXContextID context;
+    GLXDrawable drawable;
+    GLXDrawable readdrawable;
+} GlxContextTagInfo;
+
+typedef struct GlxClientPrivRec {
+    GlxContextTagInfo *contextTags;
+    unsigned int contextTagCount;
+} GlxClientPriv;
+
+extern int GlxErrorBase;
+extern RESTYPE idResource;
+
+// Defined in glxext.c.
+const ExtensionEntry *GlxGetExtensionEntry(void);
+
+Bool GlxDispatchInit(void);
+void GlxDispatchReset(void);
+
+/**
+ * Handles a request from the client.
+ *
+ * This function will look up the correct handler function and forward the
+ * request to it.
+ */
+int GlxDispatchRequest(ClientPtr client);
+
+/**
+ * Looks up the GlxClientPriv struct for a client. If we don't have a
+ * GlxClientPriv struct yet, then allocate one.
+ */
+GlxClientPriv *GlxGetClientData(ClientPtr client);
+
+/**
+ * Frees any data that's specific to a client. This should be called when a
+ * client disconnects.
+ */
+void GlxFreeClientData(ClientPtr client);
+
+Bool GlxAddXIDMap(XID id, GlxServerVendor *vendor);
+GlxServerVendor * GlxGetXIDMap(XID id);
+void GlxRemoveXIDMap(XID id);
+
+GlxContextTagInfo *GlxAllocContextTag(ClientPtr client, GlxServerVendor *vendor);
+GlxContextTagInfo *GlxLookupContextTag(ClientPtr client, GLXContextTag tag);
+void GlxFreeContextTag(GlxContextTagInfo *tagInfo);
+
+Bool GlxSetScreenVendor(ScreenPtr screen, GlxServerVendor *vendor);
+GlxScreenPriv *GlxGetScreen(ScreenPtr pScreen);
+GlxServerVendor *GlxGetVendorForScreen(ClientPtr client, ScreenPtr screen);
+
+static inline CARD32 GlxCheckSwap(ClientPtr client, CARD32 value)
+{
+    if (client->swapped)
+    {
+        value = ((value & 0XFF000000) >> 24) | ((value & 0X00FF0000) >>  8)
+            | ((value & 0X0000FF00) <<  8) | ((value & 0X000000FF) << 24);
+    }
+    return value;
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+_X_EXPORT const GlxServerExports *glvndGetExports(void);
+
+#endif // VNDSERVER_H
diff --git a/glx/vndservermapping.c b/glx/vndservermapping.c
new file mode 100644
index 000000000..fd3be92d9
--- /dev/null
+++ b/glx/vndservermapping.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * unaltered in all copies or substantial portions of the Materials.
+ * Any additions, deletions, or changes to the original source files
+ * must be clearly indicated in accompanying documentation.
+ *
+ * If only executable code is distributed, then the accompanying
+ * documentation must state that "this software is based in part on the
+ * work of the Khronos Group."
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ */
+
+#include "vndserver.h"
+
+#include <pixmapstr.h>
+
+#include "vndservervendor.h"
+
+static GlxServerVendor *LookupXIDMapResource(XID id)
+{
+    void *ptr = NULL;
+    int rv;
+
+    rv = dixLookupResourceByType(&ptr, id, idResource, NULL, DixReadAccess);
+    if (rv == Success) {
+        return (GlxServerVendor *) ptr;
+    } else {
+        return NULL;
+    }
+}
+
+GlxServerVendor *GlxGetXIDMap(XID id)
+{
+    GlxServerVendor *vendor = LookupXIDMapResource(id);
+
+    if (vendor == NULL) {
+        // If we haven't seen this XID before, then it may be a drawable that
+        // wasn't created through GLX, like a regular X window or pixmap. Try
+        // to look up a matching drawable to find a screen number for it.
+        void *ptr = NULL;
+        int rv = dixLookupResourceByClass(&ptr, id, RC_DRAWABLE, NULL,
+                                         DixGetAttrAccess);
+        if (rv == Success && ptr != NULL) {
+            DrawablePtr draw = (DrawablePtr) ptr;
+            GlxScreenPriv *screenPriv = GlxGetScreen(draw->pScreen);
+            if (screenPriv != NULL) {
+                vendor = screenPriv->vendor;
+            }
+        }
+    }
+    return vendor;
+}
+
+Bool GlxAddXIDMap(XID id, GlxServerVendor *vendor)
+{
+    if (id == 0 || vendor == NULL) {
+        return FALSE;
+    }
+    if (LookupXIDMapResource(id) != NULL) {
+        return FALSE;
+    }
+    return AddResource(id, idResource, vendor);
+}
+
+void GlxRemoveXIDMap(XID id)
+{
+    FreeResourceByType(id, idResource, FALSE);
+}
+
+GlxContextTagInfo *GlxAllocContextTag(ClientPtr client, GlxServerVendor *vendor)
+{
+    GlxClientPriv *cl;
+    unsigned int index;
+
+    if (vendor == NULL) {
+        return NULL;
+    }
+
+    cl = GlxGetClientData(client);
+    if (cl == NULL) {
+        return NULL;
+    }
+
+    // Look for a free tag index.
+    for (index=0; index<cl->contextTagCount; index++) {
+        if (cl->contextTags[index].vendor == NULL) {
+            break;
+        }
+    }
+    if (index >= cl->contextTagCount) {
+        // We didn't find a free entry, so grow the array.
+        GlxContextTagInfo *newTags;
+        unsigned int newSize = cl->contextTagCount * 2;
+        if (newSize == 0) {
+            // TODO: What's a good starting size for this?
+            newSize = 16;
+        }
+
+        newTags = (GlxContextTagInfo *)
+            realloc(cl->contextTags, newSize * sizeof(GlxContextTagInfo));
+        if (newTags == NULL) {
+            return NULL;
+        }
+
+        memset(&newTags[cl->contextTagCount], 0,
+                (newSize - cl->contextTagCount) * sizeof(GlxContextTagInfo));
+
+        index = cl->contextTagCount;
+        cl->contextTags = newTags;
+        cl->contextTagCount = newSize;
+    }
+
+    assert(index >= 0);
+    assert(index < cl->contextTagCount);
+    memset(&cl->contextTags[index], 0, sizeof(GlxContextTagInfo));
+    cl->contextTags[index].tag = (GLXContextTag) (index + 1);
+    cl->contextTags[index].client = client;
+    cl->contextTags[index].vendor = vendor;
+    return &cl->contextTags[index];
+}
+
+GlxContextTagInfo *GlxLookupContextTag(ClientPtr client, GLXContextTag tag)
+{
+    GlxClientPriv *cl = GlxGetClientData(client);
+    if (cl == NULL) {
+        return NULL;
+    }
+
+    if (tag > 0 && (tag - 1) < cl->contextTagCount) {
+        if (cl->contextTags[tag - 1].vendor != NULL) {
+            assert(cl->contextTags[tag - 1].client == client);
+            return &cl->contextTags[tag - 1];
+        }
+    }
+    return NULL;
+}
+
+void GlxFreeContextTag(GlxContextTagInfo *tagInfo)
+{
+    if (tagInfo != NULL) {
+        tagInfo->vendor = NULL;
+        tagInfo->vendor = NULL;
+        tagInfo->data = NULL;
+        tagInfo->context = None;
+        tagInfo->drawable = None;
+        tagInfo->readdrawable = None;
+    }
+}
+
+Bool GlxSetScreenVendor(ScreenPtr screen, GlxServerVendor *vendor)
+{
+    GlxScreenPriv *priv;
+
+    if (vendor == NULL) {
+        return FALSE;
+    }
+
+    priv = GlxGetScreen(screen);
+    if (priv == NULL) {
+        return FALSE;
+    }
+
+    if (priv->vendor != NULL) {
+        return FALSE;
+    }
+
+    priv->vendor = vendor;
+    return TRUE;
+}
+
+GlxServerVendor *GlxGetVendorForScreen(ClientPtr client, ScreenPtr screen)
+{
+    GlxScreenPriv *priv = GlxGetScreen(screen);
+    if (priv != NULL) {
+        return priv->vendor;
+    } else {
+        return NULL;
+    }
+}
diff --git a/glx/vndservervendor.c b/glx/vndservervendor.c
new file mode 100644
index 000000000..bd86c67f7
--- /dev/null
+++ b/glx/vndservervendor.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * unaltered in all copies or substantial portions of the Materials.
+ * Any additions, deletions, or changes to the original source files
+ * must be clearly indicated in accompanying documentation.
+ *
+ * If only executable code is distributed, then the accompanying
+ * documentation must state that "this software is based in part on the
+ * work of the Khronos Group."
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ */
+
+#include "vndservervendor.h"
+
+struct xorg_list GlxVendorList = { &GlxVendorList, &GlxVendorList };
+
+GlxServerVendor *GlxCreateVendor(const GlxServerImports *imports)
+{
+    GlxServerVendor *vendor = NULL;
+
+    if (imports == NULL) {
+        ErrorF("GLX: Vendor library did not provide an imports table\n");
+        return NULL;
+    }
+
+    if (imports->extensionCloseDown == NULL
+            || imports->handleRequest == NULL
+            || imports->getDispatchAddress == NULL
+            || imports->makeCurrent == NULL) {
+        ErrorF("GLX: Vendor library is missing required callback functions.\n");
+        return NULL;
+    }
+
+    vendor = (GlxServerVendor *) calloc(1, sizeof(GlxServerVendor));
+    if (vendor == NULL) {
+        ErrorF("GLX: Can't allocate vendor library.\n");
+        return NULL;
+    }
+    memcpy(&vendor->glxvc, imports, sizeof(GlxServerImports));
+
+    xorg_list_append(&vendor->entry, &GlxVendorList);
+    return vendor;
+}
+
+void GlxDestroyVendor(GlxServerVendor *vendor)
+{
+    if (vendor != NULL) {
+        xorg_list_del(&vendor->entry);
+        free(vendor);
+    }
+}
+
+void GlxVendorExtensionReset(const ExtensionEntry *extEntry)
+{
+    GlxServerVendor *vendor, *tempVendor;
+
+    // TODO: Do we allow the driver to destroy a vendor library handle from
+    // here?
+    xorg_list_for_each_entry_safe(vendor, tempVendor, &GlxVendorList, entry) {
+        if (vendor->glxvc.extensionCloseDown != NULL) {
+            vendor->glxvc.extensionCloseDown(extEntry);
+        }
+    }
+
+    // If the server is exiting instead of starting a new generation, then
+    // free the remaining GlxServerVendor structs.
+    //
+    // XXX this used to be conditional on xf86ServerIsExiting, but it's
+    // cleaner to just always create the vendor struct on every generation,
+    // if nothing else so all ddxes get the same behavior.
+    xorg_list_for_each_entry_safe(vendor, tempVendor, &GlxVendorList, entry) {
+        GlxDestroyVendor(vendor);
+    }
+}
diff --git a/glx/vndservervendor.h b/glx/vndservervendor.h
new file mode 100644
index 000000000..77cb983a6
--- /dev/null
+++ b/glx/vndservervendor.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * unaltered in all copies or substantial portions of the Materials.
+ * Any additions, deletions, or changes to the original source files
+ * must be clearly indicated in accompanying documentation.
+ *
+ * If only executable code is distributed, then the accompanying
+ * documentation must state that "this software is based in part on the
+ * work of the Khronos Group."
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ */
+
+#ifndef VND_SERVER_VENDOR_H
+#define VND_SERVER_VENDOR_H
+
+#include <dix-config.h>
+
+#include "glxvndabi.h"
+#include "list.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/**
+ * Info related to a single vendor library.
+ */
+struct GlxServerVendorRec {
+    GlxServerImports glxvc;
+
+    struct xorg_list entry;
+};
+
+/**
+ * A linked list of vendor libraries.
+ *
+ * Note that this list only includes vendor libraries that were successfully
+ * initialized.
+ */
+extern struct xorg_list GlxVendorList;
+
+GlxServerVendor *GlxCreateVendor(const GlxServerImports *imports);
+void GlxDestroyVendor(GlxServerVendor *vendor);
+
+void GlxVendorExtensionReset(const ExtensionEntry *extEntry);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // VND_SERVER_VENDOR_H
diff --git a/include/Makefile.am b/include/Makefile.am
index cbc4a7c58..afd6db2cf 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -27,6 +27,7 @@ sdk_HEADERS =		\
 	gcstruct.h	\
 	globals.h	\
 	glx_extinit.h	\
+	glxvndabi.h	\
 	input.h		\
 	inputstr.h	\
 	list.h		\
diff --git a/include/glxvndabi.h b/include/glxvndabi.h
new file mode 100644
index 000000000..b78306d23
--- /dev/null
+++ b/include/glxvndabi.h
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2016, NVIDIA CORPORATION.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and/or associated documentation files (the
+ * "Materials"), to deal in the Materials without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Materials, and to
+ * permit persons to whom the Materials are furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * unaltered in all copies or substantial portions of the Materials.
+ * Any additions, deletions, or changes to the original source files
+ * must be clearly indicated in accompanying documentation.
+ *
+ * If only executable code is distributed, then the accompanying
+ * documentation must state that "this software is based in part on the
+ * work of the Khronos Group."
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ */
+
+/**
+ * \file
+ *
+ * Defines the interface between the libglvnd server module and a vendor
+ * library.
+ *
+ * Each screen may have one vendor library assigned to it. The GLVND module
+ * will examine each GLX request to determine which screen it goes to, and then
+ * it will forward that request to whichever vendor is assigned to that screen.
+ *
+ * Each vendor library is represented by an opaque __GLXServerVendor handle.
+ * Display drivers are responsible for creating handles for its GLX
+ * implementations, and assigning those handles to each screen.
+ *
+ * The GLVND module keeps a list of callbacks, which are called from
+ * InitExtensions. Drivers should use that callback to assign a vendor
+ * handle to whichever screens they support.
+ *
+ * Additional notes about dispatching:
+ * - If a request has one or more GLXContextTag values, then the dispatch stub
+ *   must ensure that all of the tags belong to the vendor that it forwards the
+ *   request to. Otherwise, if a vendor library tries to look up the private
+ *   data for the tag, it could get the data from another vendor and crash.
+ * - Following from the last point, if a request takes a GLXContextTag value,
+ *   then the dispatch stub should use the tag to select a vendor. If the
+ *   request takes two or more tags, then the vendor must ensure that they all
+ *   map to the same vendor.
+ */
+
+#ifndef GLXVENDORABI_H
+#define GLXVENDORABI_H
+
+#include <scrnintstr.h>
+#include <extnsionst.h>
+#include <GL/glxproto.h>
+
+/*!
+ * Current version of the ABI.
+ *
+ * This version number contains a major number in the high-order 16 bits, and
+ * a minor version number in the low-order 16 bits.
+ *
+ * The major version number is incremented when an interface change will break
+ * backwards compatibility with existing vendor libraries. The minor version
+ * number is incremented when there's a change but existing vendor libraries
+ * will still work.
+ */
+#define GLXSERVER_VENDOR_ABI_MAJOR_VERSION 0
+#define GLXSERVER_VENDOR_ABI_MINOR_VERSION 0
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/**
+ * An opaque pointer representing a vendor library.
+ */
+typedef struct GlxServerVendorRec GlxServerVendor;
+
+typedef int (* GlxServerDispatchProc) (ClientPtr client);
+
+typedef struct GlxServerImportsRec GlxServerImports;
+
+/**
+ * Functions exported by libglvnd to the vendor library.
+ */
+typedef struct GlxServerExportsRec {
+    int majorVersion;
+    int minorVersion;
+
+    /**
+     * This callback is called during each server generation when the GLX
+     * extension is initialized.
+     *
+     * Drivers may create a __GLXServerVendor handle at any time, but may only
+     * assign a vendor to a screen from this callback.
+     *
+     * The callback is called with the ExtensionEntry pointer for the GLX
+     * extension.
+     */
+    CallbackListPtr *extensionInitCallback;
+
+    /**
+     * Allocates and zeroes a __GLXserverImports structure.
+     *
+     * Future versions of the GLVND interface may add optional members to the
+     * end of the __GLXserverImports struct. Letting the GLVND layer allocate
+     * the __GLXserverImports struct allows backward compatibility with
+     * existing drivers.
+     */
+    GlxServerImports * (* allocateServerImports) (void);
+
+    /**
+     * Frees a __GLXserverImports structure that was allocated with
+     * \c allocateServerImports.
+     */
+    void (* freeServerImports) (GlxServerImports *imports);
+
+    /**
+     * Creates a new vendor library handle.
+     */
+    GlxServerVendor * (* createVendor) (const GlxServerImports *imports);
+
+    /**
+     * Destroys a vendor library handle.
+     *
+     * This function may not be called while the vendor handle is assigned to a
+     * screen, but it may be called from the __GLXserverImports::extensionCloseDown
+     * callback.
+     */
+    void (* destroyVendor) (GlxServerVendor *vendor);
+
+    /**
+     * Sets the vendor library to use for a screen.
+     *
+     * This function should be called from the screen's CreateScreenResources
+     * callback.
+     */
+    Bool (* setScreenVendor) (ScreenPtr screen, GlxServerVendor *vendor);
+
+
+    /**
+     * Adds an entry to the XID map.
+     *
+     * This mapping is used to dispatch requests based on an XID.
+     *
+     * Client-generated XID's (contexts, drawables, etc) must be added to the
+     * map by the dispatch stub.
+     *
+     * XID's that are generated in the server should be added by the vendor
+     * library.
+     *
+     * Vendor libraries are responsible for keeping track of any additional
+     * data they need for the XID's.
+     *
+     * Note that adding GLXFBConfig ID's appears to be unnecessary -- every GLX
+     * request I can find that takes a GLXFBConfig also takes a screen number.
+     *
+     * \param id The XID to add to the map. The XID must not already be in the
+     *      map.
+     * \param vendor The vendor library to associate with \p id.
+     * \return True on success, or False on failure.
+     */
+    Bool (* addXIDMap) (XID id, GlxServerVendor *vendor);
+
+    /**
+     * Returns the vendor and data for an XID, as added with \c addXIDMap.
+     *
+     * If \p id wasn't added with \c addXIDMap (for example, if it's a regular
+     * X window), then libglvnd will try to look it up as a drawable and return
+     * the vendor for whatever screen it's on.
+     *
+     * \param id The XID to look up.
+     * \return The vendor that owns the XID, or \c NULL if no matching vendor
+     * was found.
+     */
+    GlxServerVendor * (* getXIDMap) (XID id);
+
+    /**
+     * Removes an entry from the XID map.
+     */
+    void (* removeXIDMap) (XID id);
+
+    /**
+     * Looks up a context tag.
+     *
+     * Context tags are created and managed by libglvnd to ensure that they're
+     * unique between vendors.
+     *
+     * \param client The client connection.
+     * \param tag The context tag.
+     * \return The vendor that owns the context tag, or \c NULL if the context
+     * tag is invalid.
+     */
+    GlxServerVendor * (* getContextTag)(ClientPtr client, GLXContextTag tag);
+
+    /**
+     * Assigns a pointer to vendor-private data for a context tag.
+     *
+     * Since the tag values are assigned by GLVND, vendors can use this
+     * function to store any private data they need for a context tag.
+     *
+     * \param client The client connection.
+     * \param tag The context tag.
+     * \param data An arbitrary pointer value.
+     */
+    Bool (* setContextTagPrivate)(ClientPtr client, GLXContextTag tag, void *data);
+
+    /**
+     * Returns the private data pointer that was assigned from
+     * setContextTagPrivate.
+     *
+     * This function is safe to use in __GLXserverImports::makeCurrent to look
+     * up the old context private pointer.
+     *
+     * However, this function is not safe to use from a ClientStateCallback,
+     * because GLVND may have alraedy deleted the tag by that point.
+     */
+    void * (* getContextTagPrivate)(ClientPtr client, GLXContextTag tag);
+
+    GlxServerVendor * (* getVendorForScreen) (ClientPtr client, ScreenPtr screen);
+
+    /**
+     * Forwards a request to a vendor library.
+     *
+     * \param vendor The vendor to send the request to.
+     * \param client The client.
+     */
+    int (* forwardRequest) (GlxServerVendor *vendor, ClientPtr client);
+} GlxServerExports;
+
+extern _X_EXPORT const GlxServerExports glxServer;
+
+/**
+ * Functions exported by the vendor library to libglvnd.
+ */
+struct GlxServerImportsRec {
+    /**
+     * Called on a server reset.
+     *
+     * This is called from the extension's CloseDown callback.
+     *
+     * Note that this is called after freeing all of GLVND's per-screen data,
+     * so the callback may destroy any vendor handles.
+     *
+     * If the server is exiting, then GLVND will free any remaining vendor
+     * handles after calling the extensionCloseDown callbacks.
+     */
+    void (* extensionCloseDown) (const ExtensionEntry *extEntry);
+
+    /**
+     * Handles a GLX request.
+     */
+    int (* handleRequest) (ClientPtr client);
+
+    /**
+     * Returns a dispatch function for a request.
+     *
+     * \param minorOpcode The minor opcode of the request.
+     * \param vendorCode The vendor opcode, if \p minorOpcode
+     *      is \c X_GLXVendorPrivate or \c X_GLXVendorPrivateWithReply.
+     * \return A dispatch function, or NULL if the vendor doesn't support this
+     *      request.
+     */
+    GlxServerDispatchProc (* getDispatchAddress) (CARD8 minorOpcode, CARD32 vendorCode);
+
+    /**
+     * Handles a MakeCurrent request.
+     *
+     * This function is called to handle any MakeCurrent request. The vendor
+     * library should deal with changing the current context. After the vendor
+     * returns GLVND will send the reply.
+     *
+     * In addition, GLVND will call this function with any current contexts
+     * when a client disconnects.
+     *
+     * To ensure that context tags are unique, libglvnd will select a context
+     * tag and pass it to the vendor library.
+     *
+     * The vendor can use \c __GLXserverExports::getContextTagPrivate to look
+     * up the private data pointer for \p oldContextTag.
+     *
+     * Likewise, the vendor can use \c __GLXserverExports::setContextTagPrivate
+     * to assign a private data pointer to \p newContextTag.
+     */
+    int (* makeCurrent) (ClientPtr client,
+        GLXContextTag oldContextTag,
+        XID drawable,
+        XID readdrawable,
+        XID context,
+        GLXContextTag newContextTag);
+};
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // GLXVENDORABI_H
diff --git a/include/meson.build b/include/meson.build
index 72892becd..ee5a6fb29 100644
--- a/include/meson.build
+++ b/include/meson.build
@@ -323,6 +323,7 @@ if build_xorg
             'gcstruct.h',
             'globals.h',
             'glx_extinit.h',
+            'glxvndabi.h',
             'input.h',
             'inputstr.h',
             'list.h',


More information about the xorg-commit mailing list