summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKyle Brenneman <kbrenneman@nvidia.com>2018-01-10 13:05:44 -0500
committerAdam Jackson <ajax@redhat.com>2018-02-14 17:04:35 -0500
commit8753218beae641e5c5ac2c2ba598cfb99a893cf4 (patch)
tree86dea0de50f26d27e1bd280035e2f727e9b63219
parentd1fdddeb76328ab84d9a181a5c72b90013f0f0a6 (diff)
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@redhat.com>
-rw-r--r--glx/Makefile.am8
-rw-r--r--glx/meson.build21
-rw-r--r--glx/vnd_dispatch_stubs.c525
-rw-r--r--glx/vndcmds.c483
-rw-r--r--glx/vndext.c306
-rw-r--r--glx/vndserver.h119
-rw-r--r--glx/vndservermapping.c196
-rw-r--r--glx/vndservervendor.c91
-rw-r--r--glx/vndservervendor.h68
-rw-r--r--include/Makefile.am1
-rw-r--r--include/glxvndabi.h307
-rw-r--r--include/meson.build1
12 files changed, 2125 insertions, 1 deletions
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',