diff options
author | Kyle Brenneman <kbrenneman@nvidia.com> | 2018-01-10 13:05:44 -0500 |
---|---|---|
committer | Adam Jackson <ajax@redhat.com> | 2018-02-14 17:04:35 -0500 |
commit | 8753218beae641e5c5ac2c2ba598cfb99a893cf4 (patch) | |
tree | 86dea0de50f26d27e1bd280035e2f727e9b63219 | |
parent | d1fdddeb76328ab84d9a181a5c72b90013f0f0a6 (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.am | 8 | ||||
-rw-r--r-- | glx/meson.build | 21 | ||||
-rw-r--r-- | glx/vnd_dispatch_stubs.c | 525 | ||||
-rw-r--r-- | glx/vndcmds.c | 483 | ||||
-rw-r--r-- | glx/vndext.c | 306 | ||||
-rw-r--r-- | glx/vndserver.h | 119 | ||||
-rw-r--r-- | glx/vndservermapping.c | 196 | ||||
-rw-r--r-- | glx/vndservervendor.c | 91 | ||||
-rw-r--r-- | glx/vndservervendor.h | 68 | ||||
-rw-r--r-- | include/Makefile.am | 1 | ||||
-rw-r--r-- | include/glxvndabi.h | 307 | ||||
-rw-r--r-- | include/meson.build | 1 |
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', |