diff options
author | Kyle Brenneman <kbrenneman@nvidia.com> | 2016-03-28 17:40:51 -0600 |
---|---|---|
committer | Kyle Brenneman <kbrenneman@nvidia.com> | 2016-03-28 17:40:51 -0600 |
commit | 95a5bfcdfbc3c38e201e81d6497efe6c7b97f72b (patch) | |
tree | 84d622feb712ea43d432a2c8b0ca9cd65e8ae20d | |
parent | 5c8e63290620d78763503f9ba4de28530ae1961e (diff) | |
parent | 86585e3bb0781ad1ef925e6fd81888190c12b1a5 (diff) |
Merge pull request #74 from kbrenneman/libglx-abi-version-1.
Updates to libGLX vendor library interface.
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | include/glvnd/GLdispatchABI.h | 101 | ||||
-rw-r--r-- | include/glvnd/libglxabi.h | 195 | ||||
-rw-r--r-- | src/GLX/libglx.c | 90 | ||||
-rw-r--r-- | src/GLX/libglxmapping.c | 132 | ||||
-rw-r--r-- | src/GLX/libglxmapping.h | 17 | ||||
-rw-r--r-- | src/GLdispatch/GLdispatch.c | 10 | ||||
-rw-r--r-- | src/GLdispatch/GLdispatch.h | 75 | ||||
-rw-r--r-- | src/GLdispatch/GLdispatchPrivate.h | 19 | ||||
-rw-r--r-- | src/GLdispatch/vnd-glapi/mapi/entry.h | 10 | ||||
-rw-r--r-- | src/GLdispatch/vnd-glapi/mapi/entry_armv7_tsd.c | 3 | ||||
-rw-r--r-- | src/GLdispatch/vnd-glapi/mapi/entry_pure_c.c | 3 | ||||
-rw-r--r-- | src/GLdispatch/vnd-glapi/mapi/entry_x86_64_tls.c | 3 | ||||
-rw-r--r-- | src/GLdispatch/vnd-glapi/mapi/entry_x86_64_tsd.c | 3 | ||||
-rw-r--r-- | src/GLdispatch/vnd-glapi/mapi/entry_x86_tsd.c | 3 | ||||
-rw-r--r-- | tests/GLX_dummy/GLX_dummy.c | 97 |
16 files changed, 475 insertions, 288 deletions
diff --git a/configure.ac b/configure.ac index b2ba9f8..8d00683 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ dnl configure.ac dnl Process this file with autoconf to produce a configure script. AC_PREREQ([2.63]) -AC_INIT([libglvnd], [0.0.0], [kbrenneman@nvidia.com]) +AC_INIT([libglvnd], [0.1.0], [kbrenneman@nvidia.com]) AC_CONFIG_SRCDIR([config.h.in]) AC_CONFIG_HEADERS([config.h]) diff --git a/include/glvnd/GLdispatchABI.h b/include/glvnd/GLdispatchABI.h index d16de2d..25d593a 100644 --- a/include/glvnd/GLdispatchABI.h +++ b/include/glvnd/GLdispatchABI.h @@ -44,18 +44,45 @@ extern "C" { * these client ABIs. */ -/* - * Thread-local implementation used by libglvnd. This is passed into - * the patch function callback via the type parameter. +/*! + * Thread-local implementation used by libglvnd. This is passed into the patch + * function callback via the type parameter. + * + * For most architectures, the vendor library can ignore this parameter, since + * it will always be the same value. It's used for systems like ARM, where the + * stubs might be use the ARM or Thumb instruction sets. + * + * The stub type does not make any distinction between TLS and TSD stubs. The + * entire purpose of entrypoint rewriting is to skip the dispatch table in + * libGLdispatch.so, so it doesn't matter how that dispatch table is stored. */ enum { - __GLDISPATCH_STUB_X86_TLS, - __GLDISPATCH_STUB_X86_64_TLS, - __GLDISPATCH_STUB_X86_TSD, - __GLDISPATCH_STUB_PURE_C, - __GLDISPATCH_STUB_X86_64_TSD, - __GLDISPATCH_STUB_ARMV7_THUMB_TSD, - __GLDISPATCH_STUB_NUM_TYPES + /*! + * Indicates that the stubs aren't defined in assembly. For example, if the + * dispatch stubs are written in C. Vendor libraries generally won't see + * this value. + */ + __GLDISPATCH_STUB_UNKNOWN, + + /*! + * Used for stubs on x86 systems. + */ + __GLDISPATCH_STUB_X86, + + /*! + * Used for stubs on x86-64 systems. + */ + __GLDISPATCH_STUB_X86_64, + + /*! + * Used for stubs on ARMv7, using the Thumb instruction set. + */ + __GLDISPATCH_STUB_ARMV7_THUMB, + + /*! + * Used for stubs on ARMv7, using the normal ARM instruction set. + */ + __GLDISPATCH_STUB_ARMV7_ARM }; /*! @@ -86,60 +113,6 @@ enum { typedef GLboolean (*DispatchPatchLookupStubOffset)(const char *funcName, void **writePtr, const void **execPtr); -typedef struct __GLdispatchPatchCallbacksRec { - /*! - * Checks to see if the vendor library supports patching the given stub - * type and size. - * - * \param type The type of entrypoints. This will be a one of the - * __GLDISPATCH_STUB_* values. - * \param stubSize The maximum size of the stub that the vendor library can - * write, in bytes. - * \param lookupStubOffset A callback into libglvnd to look up the address - * of each entrypoint. - */ - GLboolean (* checkPatchSupported)(int type, int stubSize); - - /*! - * Called by libglvnd to request that a vendor library patch its top-level - * entrypoints. - * - * The vendor library should use the \p lookupStubOffset callback to find - * the addresses of each entrypoint. - * - * This function may be called more than once to patch multiple sets of - * entrypoints. For example, depending on how they're built, libOpenGL.so - * or libGL.so may have their own entrypoints that are separate functions - * from the ones in libGLdispatch. - * - * Note that during this call is the only time that the entrypoints can be - * modified. After the call to \c initiatePatch returns, the vendor library - * should treat the entrypoints as read-only. - * - * \param type The type of entrypoints. This will be a one of the - * __GLDISPATCH_STUB_* values. - * \param stubSize The maximum size of the stub that the vendor library can - * write, in bytes. - * \param lookupStubOffset A callback into libglvnd to look up the address - * of each entrypoint. - * - * \return GL_TRUE if the vendor library supports patching with this type - * and size. - */ - GLboolean (*initiatePatch)(int type, - int stubSize, - DispatchPatchLookupStubOffset lookupStubOffset); - - /*! - * Called by libglvnd to notify the current vendor that it no longer owns - * the top-level entrypoints. - * - * Libglvnd will take care of the restoring the entrypoints back to their - * original state. The vendor library must not try to modify them. - */ - void (*releasePatch)(void); -} __GLdispatchPatchCallbacks; - #if defined(__cplusplus) } #endif diff --git a/include/glvnd/libglxabi.h b/include/glvnd/libglxabi.h index 3a59691..b664e76 100644 --- a/include/glvnd/libglxabi.h +++ b/include/glvnd/libglxabi.h @@ -90,8 +90,18 @@ extern "C" { /*! * 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 GLX_VENDOR_ABI_VERSION 0 +#define GLX_VENDOR_ABI_VERSION ((1 << 16) | 0) +#define GLX_VENDOR_ABI_GET_MAJOR_VERSION(version) ((version) & 0xFFFF) +#define GLX_VENDOR_ABI_GET_MINOR_VERSION(version) ((version) >> 16) /*! @@ -151,15 +161,19 @@ typedef struct __GLXapiExportsRec { /************************************************************************ * These routines are used by vendor dispatch functions to look up - * and add mappings between various objects and screens. + * and add mappings between various objects and vendors. ************************************************************************/ /*! - * Records the screen number and vendor for a context. The screen and - * vendor must be the ones returned for the XVisualInfo or GLXFBConfig that - * the context is created from. + * Records the vendor for a context. The vendor must be the one returned + * for the XVisualInfo or GLXFBConfig that the context is created from. + * + * \param dpy The display pointer. + * \param context The context handle. + * \param vendor The vendor that created the context. + * \return Zero on success, non-zero on error. */ - void (*addVendorContextMapping)(Display *dpy, GLXContext context, __GLXvendorInfo *vendor); + int (*addVendorContextMapping)(Display *dpy, GLXContext context, __GLXvendorInfo *vendor); /*! * Removes a mapping from context to vendor. The context must have been @@ -168,33 +182,27 @@ typedef struct __GLXapiExportsRec { void (*removeVendorContextMapping)(Display *dpy, GLXContext context); /*! - * Looks up the screen and vendor for a context. + * Looks up the vendor for a context. * - * If no mapping is found, then \p retScreen will be set to -1, and - * \p retVendor and \p retDisplay will be set to NULL. - * - * \p retScreen, \p retVendor, and \p retDisplay may be NULL if the screen, - * vendor, or display are not required. + * If no mapping is found, then this function will return \c NULL. No + * errors are raised, so the dispatch function must raise any appropriate X + * errors. * * Note that this function does not take a display connection, since * there are cases (e.g., glXGetContextIDEXT) that take a GLXContext but * not a display. * * \param context The context to look up. - * \param[out] retVendor Returns the vendor. - * \return Zero if a match was found, or non-zero if it was not. + * \return The vendor for the context, or NULL if no matching context was + * found. */ - int (*vendorFromContext)(GLXContext context, __GLXvendorInfo **retVendor); + __GLXvendorInfo * (*vendorFromContext)(GLXContext context); - void (*addVendorFBConfigMapping)(Display *dpy, GLXFBConfig config, __GLXvendorInfo *vendor); + int (*addVendorFBConfigMapping)(Display *dpy, GLXFBConfig config, __GLXvendorInfo *vendor); void (*removeVendorFBConfigMapping)(Display *dpy, GLXFBConfig config); - int (*vendorFromFBConfig)(Display *dpy, GLXFBConfig config, __GLXvendorInfo **retVendor); - - void (*addScreenVisualMapping)(Display *dpy, const XVisualInfo *visual, __GLXvendorInfo *vendor); - void (*removeScreenVisualMapping)(Display *dpy, const XVisualInfo *visual); - int (*vendorFromVisual)(Display *dpy, const XVisualInfo *visual, __GLXvendorInfo **retVendor); + __GLXvendorInfo * (*vendorFromFBConfig)(Display *dpy, GLXFBConfig config); - void (*addVendorDrawableMapping)(Display *dpy, GLXDrawable drawable, __GLXvendorInfo *vendor); + int (*addVendorDrawableMapping)(Display *dpy, GLXDrawable drawable, __GLXvendorInfo *vendor); void (*removeVendorDrawableMapping)(Display *dpy, GLXDrawable drawable); /*! @@ -210,7 +218,7 @@ typedef struct __GLXapiExportsRec { * All of this should be opaque to a dispatch function, since the only * thing that matters is finding out which vendor to dispatch to. */ - int (*vendorFromDrawable)(Display *dpy, GLXDrawable drawable, __GLXvendorInfo **retVendor); + __GLXvendorInfo * (*vendorFromDrawable)(Display *dpy, GLXDrawable drawable); } __GLXapiExports; @@ -231,7 +239,7 @@ typedef struct __GLXapiImportsRec { * \param screen The screen number. * \return True if the vendor library can support this screen. */ - Bool (* checkSupportsScreen) (Display *dpy, int screen); + Bool (* isScreenSupported) (Display *dpy, int screen); /*! * This retrieves the pointer to the real GLX or core GL function. @@ -289,39 +297,134 @@ typedef struct __GLXapiImportsRec { XID resid, unsigned char opcode, Bool coreX11error); - /*! - * (OPTIONAL) Callbacks by which the vendor library may re-write libglvnd's + /* + * The vendor library may use the isPatchSupported, initiatePatch, + * releasePatch, and patchThreadAttach callbacks to re-write libglvnd's * entrypoints at make current time, provided no other contexts are current - * and the TLS model supports this functionality. This is a performance + * and the TLS model supports this functionality. This is a performance * optimization that may not be available at runtime; the vendor library - * must not depend on this functionality for correctness. This should - * point to a statically-allocated structure, or NULL if unimplemented. + * must not depend on this functionality for correctness. + * + * To use this optimization, the vendor library must provide at least the + * isPatchSupported and initiatePatch entrypoints. + */ + + /*! + * (OPTIONAL) Checks to see if the vendor library supports patching the + * given stub type and size. + * + * \param type The type of entrypoints. This will be a one of the + * __GLDISPATCH_STUB_* values. + * \param stubSize The maximum size of the stub that the vendor library can + * write, in bytes. + * \param lookupStubOffset A callback into libglvnd to look up the address + * of each entrypoint. + */ + GLboolean (* isPatchSupported)(int type, int stubSize); + + /*! + * (OPTIONAL) Called by libglvnd to request that a vendor library patch its + * top-level entrypoints. + * + * The vendor library should use the \p lookupStubOffset callback to find + * the addresses of each entrypoint. + * + * This function may be called more than once to patch multiple sets of + * entrypoints. For example, depending on how they're built, libOpenGL.so + * or libGL.so may have their own entrypoints that are separate functions + * from the ones in libGLdispatch. + * + * Note that during this call is the only time that the entrypoints can be + * modified. After the call to \c initiatePatch returns, the vendor library + * should treat the entrypoints as read-only. + * + * \param type The type of entrypoints. This will be a one of the + * __GLDISPATCH_STUB_* values. + * \param stubSize The maximum size of the stub that the vendor library can + * write, in bytes. + * \param lookupStubOffset A callback into libglvnd to look up the address + * of each entrypoint. + * + * \return GL_TRUE if the vendor library supports patching with this type + * and size. + */ + GLboolean (*initiatePatch)(int type, + int stubSize, + DispatchPatchLookupStubOffset lookupStubOffset); + + /*! + * (OPTIONAL) Called by libglvnd to notify the current vendor that it no + * longer owns the top-level entrypoints. + * + * Libglvnd will take care of the restoring the entrypoints back to their + * original state. The vendor library must not try to modify them. + */ + void (*releasePatch)(void); + + /*! + * (OPTIONAL) Called at the start of window-system functions (GLX and EGL). + * This callback allows vendor libraries to perform any per-thread + * initialization. + * + * This is basically a workaround for broken applications. A lot of apps + * will make one or more invalid GLX/EGL calls on a thread (often including + * a MakeCurrent with invalid parameters), and then will try to call an + * OpenGL function. + * + * A non-libglvnd-based driver would be able to initialize any thread state + * even on a bogus GLX call, but with libglvnd, those calls wouldn't get + * past libGLX. + * + * This function is optional. If it's \c NULL, then libGLdispatch will + * simply ignore it. + * + * \note This function may be called concurrently from multiple threads. */ - const __GLdispatchPatchCallbacks *patchCallbacks; + void (*patchThreadAttach)(void); } __GLXapiImports; /*****************************************************************************/ +#define __GLX_MAIN_PROTO_NAME "__glx_Main" +#define __GLX_MAIN_PROTO(version, exports, vendor, imports) \ + Bool __glx_Main(uint32_t version, \ + const __GLXapiExports *exports, \ + __GLXvendorInfo *vendor, \ + __GLXapiImports *imports) + +typedef Bool (*__PFNGLXMAINPROC) + (uint32_t version, const __GLXapiExports *exports, __GLXvendorInfo *vendor, __GLXapiImports *imports); + /*! * Vendor libraries must export a function called __glx_Main() with the - * following prototype. This function also performs a handshake based on the ABI - * version number. This function receives a pointer to an exports table whose - * lifetime is only guaranteed to be at a minimum that of the call to - * __glx_Main(), in addition to the version number and a string identifying the - * vendor. If there is an ABI version mismatch or some other error occurs, this - * function returns NULL; otherwise this returns a pointer to a filled-in - * dispatch table. + * following prototype. + * + * This function also performs a handshake based on the ABI version number. + * Vendor libraries can optionally use the version number to support older + * versions of the ABI. + * + * \param[in] version The ABI version. The upper 16 bits contains the major version + * number, and the lower 16 bits contains the minor version number. + * + * \param[in] exports The table of functions provided by libGLX. This pointer will + * remain valid for as long as the vendor is loaded. + * + * \param[in] vendor The opaque pointer used to identify this vendor library. This + * may be used in future versions to provide additional per-vendor information. + * + * \param[out] imports The function table that the vendor library should fill + * in. The vendor library must assign every non-optional function in the + * struct. + * + * \return True on success. If the vendor library does not support the + * requested ABI version or if some other error occurs, then it should return + * False. */ -#define __GLX_MAIN_PROTO_NAME "__glx_Main" -#define __GLX_MAIN_PROTO(version, exports, vendorName) \ - const __GLXapiImports *__glx_Main(uint32_t version, \ - const __GLXapiExports *exports, \ - const char *vendorName, \ - int vendorID) - -typedef const __GLXapiImports *(*__PFNGLXMAINPROC) - (uint32_t, const __GLXapiExports *, const char *, int); +Bool __glx_Main(uint32_t version, + const __GLXapiExports *exports, + __GLXvendorInfo *vendor, + __GLXapiImports *imports); /*! * @} diff --git a/src/GLX/libglx.c b/src/GLX/libglx.c index df3f4d2..f3a408a 100644 --- a/src/GLX/libglx.c +++ b/src/GLX/libglx.c @@ -163,7 +163,7 @@ static __GLXvendorInfo *CommonDispatchDrawable(Display *dpy, GLXDrawable draw, if (draw != None) { __glXThreadInitialize(); - __glXVendorFromDrawable(dpy, draw, &vendor); + vendor = __glXVendorFromDrawable(dpy, draw); } if (vendor == NULL) { __glXSendError(dpy, errorCode, draw, minorCode, coreX11error); @@ -178,7 +178,7 @@ static __GLXvendorInfo *CommonDispatchContext(Display *dpy, GLXContext context, if (context != NULL) { __glXThreadInitialize(); - __glXVendorFromContext(context, &vendor); + vendor = __glXVendorFromContext(context); } if (vendor == NULL) { __glXSendError(dpy, GLXBadContext, 0, minorCode, False); @@ -193,7 +193,7 @@ static __GLXvendorInfo *CommonDispatchFBConfig(Display *dpy, GLXFBConfig config, if (config != NULL) { __glXThreadInitialize(); - __glXVendorFromFBConfig(dpy, config, &vendor); + vendor = __glXVendorFromFBConfig(dpy, config); } if (vendor == NULL) { __glXSendError(dpy, GLXBadFBConfig, 0, minorCode, False); @@ -238,7 +238,10 @@ PUBLIC GLXContext glXCreateContext(Display *dpy, XVisualInfo *vis, vendor = __glXLookupVendorByScreen(dpy, vis->screen); if (vendor != NULL) { GLXContext context = vendor->staticDispatch.createContext(dpy, vis, share_list, direct); - __glXAddVendorContextMapping(dpy, context, vendor); + if (__glXAddVendorContextMapping(dpy, context, vendor) != 0) { + vendor->staticDispatch.destroyContext(dpy, context); + context = NULL; + } return context; } else { return NULL; @@ -255,7 +258,10 @@ PUBLIC GLXContext glXCreateNewContext(Display *dpy, GLXFBConfig config, if (vendor != NULL) { context = vendor->staticDispatch.createNewContext(dpy, config, render_type, share_list, direct); - __glXAddVendorContextMapping(dpy, context, vendor); + if (__glXAddVendorContextMapping(dpy, context, vendor) != 0) { + vendor->staticDispatch.destroyContext(dpy, context); + context = NULL; + } } return context; } @@ -407,9 +413,13 @@ static GLXContext glXImportContextEXT(Display *dpy, GLXContextID contextID) } vendor = __glXLookupVendorByScreen(dpy, screen); - if (vendor != NULL && vendor->staticDispatch.importContextEXT != NULL) { + if (vendor != NULL && vendor->staticDispatch.importContextEXT != NULL + && vendor->staticDispatch.freeContextEXT) { GLXContext context = vendor->staticDispatch.importContextEXT(dpy, contextID); - __glXAddVendorContextMapping(dpy, context, vendor); + if (__glXAddVendorContextMapping(dpy, context, vendor) != 0) { + vendor->staticDispatch.freeContextEXT(dpy, context); + context = NULL; + } return context; } else { return NULL; @@ -422,7 +432,7 @@ static void glXFreeContextEXT(Display *dpy, GLXContext context) __glXThreadInitialize(); - __glXVendorFromContext(context, &vendor); + vendor = __glXVendorFromContext(context); if (vendor != NULL && vendor->staticDispatch.freeContextEXT != NULL) { __glXRemoveVendorContextMapping(dpy, context); vendor->staticDispatch.freeContextEXT(dpy, context); @@ -439,7 +449,10 @@ PUBLIC GLXPixmap glXCreateGLXPixmap(Display *dpy, XVisualInfo *vis, Pixmap pixma vendor = __glXLookupVendorByScreen(dpy, vis->screen); if (vendor != NULL) { GLXPixmap pmap = vendor->staticDispatch.createGLXPixmap(dpy, vis, pixmap); - __glXAddVendorDrawableMapping(dpy, pmap, vendor); + if (__glXAddVendorDrawableMapping(dpy, pmap, vendor) != 0) { + vendor->staticDispatch.destroyGLXPixmap(dpy, pmap); + pmap = None; + } return pmap; } else { return None; @@ -635,7 +648,7 @@ void __glXRemoveVendorContextMapping(Display *dpy, GLXContext context) __glvndPthreadFuncs.mutex_unlock(&glxContextHashLock); } -void __glXAddVendorContextMapping(Display *dpy, GLXContext context, __GLXvendorInfo *vendor) +int __glXAddVendorContextMapping(Display *dpy, GLXContext context, __GLXvendorInfo *vendor) { __GLXcontextInfo *ctxInfo; @@ -644,19 +657,27 @@ void __glXAddVendorContextMapping(Display *dpy, GLXContext context, __GLXvendorI HASH_FIND_PTR(glxContextHash, &context, ctxInfo); if (ctxInfo == NULL) { ctxInfo = (__GLXcontextInfo *) malloc(sizeof(__GLXcontextInfo)); + if (ctxInfo == NULL) { + __glvndPthreadFuncs.mutex_unlock(&glxContextHashLock); + return -1; + } ctxInfo->context = context; ctxInfo->vendor = vendor; ctxInfo->currentCount = 0; ctxInfo->deleted = False; HASH_ADD_PTR(glxContextHash, context, ctxInfo); } else { - assert(ctxInfo->vendor == vendor); + if (ctxInfo->vendor != vendor) { + __glvndPthreadFuncs.mutex_unlock(&glxContextHashLock); + return -1; + } } __glvndPthreadFuncs.mutex_unlock(&glxContextHashLock); + return 0; } -int __glXVendorFromContext(GLXContext context, __GLXvendorInfo **retVendor) +__GLXvendorInfo *__glXVendorFromContext(GLXContext context) { __GLXcontextInfo *ctxInfo; __GLXvendorInfo *vendor = NULL; @@ -668,10 +689,7 @@ int __glXVendorFromContext(GLXContext context, __GLXvendorInfo **retVendor) } __glvndPthreadFuncs.mutex_unlock(&glxContextHashLock); - if (retVendor != NULL) { - *retVendor = vendor; - } - return (vendor != NULL ? 0 : -1); + return vendor; } static void FreeContextInfo(__GLXcontextInfo *ctx) @@ -848,7 +866,7 @@ static Bool InternalMakeCurrentDispatch( &threadState->glas, vendor->glDispatch, vendor->vendorID, - vendor->glxvc->patchCallbacks + vendor->patchCallbacks ); if (ret) { @@ -1425,7 +1443,6 @@ PUBLIC const char *glXQueryExtensionsString(Display *dpy, int screen) return pDispatch->queryExtensionsString(dpy, screen); } - PUBLIC GLXFBConfig *glXChooseFBConfig(Display *dpy, int screen, const int *attrib_list, int *nelements) { @@ -1440,8 +1457,17 @@ PUBLIC GLXFBConfig *glXChooseFBConfig(Display *dpy, int screen, if (fbconfigs != NULL) { int i; + Bool success = True; for (i = 0; i < *nelements; i++) { - __glXAddVendorFBConfigMapping(dpy, fbconfigs[i], vendor); + if (__glXAddVendorFBConfigMapping(dpy, fbconfigs[i], vendor) != 0) { + success = False; + break; + } + } + if (!success) { + XFree(fbconfigs); + fbconfigs = NULL; + *nelements = 0; } } return fbconfigs; @@ -1458,7 +1484,10 @@ PUBLIC GLXPbuffer glXCreatePbuffer(Display *dpy, GLXFBConfig config, __GLXvendorInfo *vendor = CommonDispatchFBConfig(dpy, config, X_GLXCreatePbuffer); if (vendor != NULL) { pbuffer = vendor->staticDispatch.createPbuffer(dpy, config, attrib_list); - __glXAddVendorDrawableMapping(dpy, pbuffer, vendor); + if (__glXAddVendorDrawableMapping(dpy, pbuffer, vendor) != 0) { + vendor->staticDispatch.destroyPbuffer(dpy, pbuffer); + pbuffer = None; + } } return pbuffer; } @@ -1471,7 +1500,10 @@ PUBLIC GLXPixmap glXCreatePixmap(Display *dpy, GLXFBConfig config, __GLXvendorInfo *vendor = CommonDispatchFBConfig(dpy, config, X_GLXCreatePixmap); if (vendor != NULL) { glxPixmap = vendor->staticDispatch.createPixmap(dpy, config, pixmap, attrib_list); - __glXAddVendorDrawableMapping(dpy, glxPixmap, vendor); + if (__glXAddVendorDrawableMapping(dpy, glxPixmap, vendor) != 0) { + vendor->staticDispatch.destroyGLXPixmap(dpy, glxPixmap); + glxPixmap = None; + } } return glxPixmap; } @@ -1484,7 +1516,10 @@ PUBLIC GLXWindow glXCreateWindow(Display *dpy, GLXFBConfig config, __GLXvendorInfo *vendor = CommonDispatchFBConfig(dpy, config, X_GLXCreateWindow); if (vendor != NULL) { glxWindow = vendor->staticDispatch.createWindow(dpy, config, win, attrib_list); - __glXAddVendorDrawableMapping(dpy, glxWindow, vendor); + if (__glXAddVendorDrawableMapping(dpy, glxWindow, vendor) != 0) { + vendor->staticDispatch.destroyWindow(dpy, glxWindow); + glxWindow = None; + } } return glxWindow; } @@ -1545,8 +1580,17 @@ PUBLIC GLXFBConfig *glXGetFBConfigs(Display *dpy, int screen, int *nelements) GLXFBConfig *fbconfigs = vendor->staticDispatch.getFBConfigs(dpy, screen, nelements); if (fbconfigs != NULL) { int i; + Bool success = True; for (i = 0; i < *nelements; i++) { - __glXAddVendorFBConfigMapping(dpy, fbconfigs[i], vendor); + if (__glXAddVendorFBConfigMapping(dpy, fbconfigs[i], vendor) != 0) { + success = False; + break; + } + } + if (!success) { + XFree(fbconfigs); + fbconfigs = NULL; + *nelements = 0; } } return fbconfigs; diff --git a/src/GLX/libglxmapping.c b/src/GLX/libglxmapping.c index 67d5d7d..506cb06 100644 --- a/src/GLX/libglxmapping.c +++ b/src/GLX/libglxmapping.c @@ -104,6 +104,15 @@ typedef struct __GLXdispatchFuncHashRec { */ typedef struct __GLXvendorNameHashRec { __GLXvendorInfo vendor; + + /** + * The imports table for this vendor. This is allocated and zeroed by + * libGLX.so, so that we can add functions to the end without breaking + * backward compatibility. + */ + __GLXapiImports imports; + __GLdispatchPatchCallbacks patchCallbacks; + UT_hash_handle hh; } __GLXvendorNameHash; @@ -143,10 +152,6 @@ static const __GLXapiExports glxExportsTable = { .removeVendorFBConfigMapping = __glXRemoveVendorFBConfigMapping, .vendorFromFBConfig = __glXVendorFromFBConfig, - .addScreenVisualMapping = __glXAddScreenVisualMapping, - .removeScreenVisualMapping = __glXRemoveScreenVisualMapping, - .vendorFromVisual = __glXVendorFromVisual, - .addVendorDrawableMapping = __glXAddVendorDrawableMapping, .removeVendorDrawableMapping = __glXRemoveVendorDrawableMapping, .vendorFromDrawable = __glXVendorFromDrawable, @@ -476,6 +481,7 @@ __GLXvendorInfo *__glXLookupVendorByName(const char *vendorName) __GLXvendorInfo *vendor; __PFNGLXMAINPROC glxMainProc; char *filename; + Bool success; // Previously unseen vendor. dlopen() the new vendor and add it to the // hash table. @@ -485,6 +491,7 @@ __GLXvendorInfo *__glXLookupVendorByName(const char *vendorName) } vendor = &pEntry->vendor; + vendor->glxvc = &pEntry->imports; vendor->name = (char *) (pEntry + 1); memcpy(vendor->name, vendorName, vendorNameLen + 1); @@ -505,18 +512,6 @@ __GLXvendorInfo *__glXLookupVendorByName(const char *vendorName) vendor->vendorID = __glDispatchNewVendorID(); assert(vendor->vendorID >= 0); - vendor->glxvc = (*glxMainProc)(GLX_VENDOR_ABI_VERSION, - &glxExportsTable, - vendor->name, - vendor->vendorID); - if (!vendor->glxvc) { - goto fail; - } - - if (!LookupVendorEntrypoints(vendor)) { - goto fail; - } - vendor->glDispatch = (__GLdispatchTable *) __glDispatchCreateTable( VendorGetProcAddressCallback, @@ -529,6 +524,37 @@ __GLXvendorInfo *__glXLookupVendorByName(const char *vendorName) /* Initialize the dynamic dispatch table */ LKDHASH_INIT(vendor->dynDispatchHash); + success = (*glxMainProc)(GLX_VENDOR_ABI_VERSION, + &glxExportsTable, + vendor, &pEntry->imports); + if (!success) { + goto fail; + } + + // Make sure all the required functions are there. + if (pEntry->imports.isScreenSupported == NULL + || pEntry->imports.getProcAddress == NULL + || pEntry->imports.getDispatchAddress == NULL + || pEntry->imports.setDispatchIndex == NULL) + { + goto fail; + } + + if (!LookupVendorEntrypoints(vendor)) { + goto fail; + } + + // Check to see whether this vendor library can support entrypoint + // patching. + if (pEntry->imports.isPatchSupported != NULL + && pEntry->imports.initiatePatch != NULL) { + pEntry->patchCallbacks.isPatchSupported = pEntry->imports.isPatchSupported; + pEntry->patchCallbacks.initiatePatch = pEntry->imports.initiatePatch; + pEntry->patchCallbacks.releasePatch = pEntry->imports.releasePatch; + pEntry->patchCallbacks.threadAttach = pEntry->imports.patchThreadAttach; + pEntry->vendor.patchCallbacks = &pEntry->patchCallbacks; + } + HASH_ADD_KEYPTR(hh, _LH(__glXVendorNameHash), vendor->name, strlen(vendor->name), pEntry); LKDHASH_UNLOCK(__glXVendorNameHash); @@ -604,7 +630,7 @@ __GLXvendorInfo *__glXLookupVendorByScreen(Display *dpy, const int screen) // Make sure that the vendor library can support this screen. // If it can't, then we'll fall back to the indirect rendering // library. - if (vendor != NULL && !vendor->glxvc->checkSupportsScreen(dpy, screen)) { + if (vendor != NULL && !vendor->glxvc->isScreenSupported(dpy, screen)) { vendor = NULL; } } @@ -794,16 +820,16 @@ typedef struct { static DEFINE_LKDHASH(__GLXvendorConfigMappingHash, fbconfigHashtable); -void __glXAddVendorFBConfigMapping(Display *dpy, GLXFBConfig config, __GLXvendorInfo *vendor) +int __glXAddVendorFBConfigMapping(Display *dpy, GLXFBConfig config, __GLXvendorInfo *vendor) { __GLXvendorConfigMappingHash *pEntry; if (config == NULL) { - return; + return 0; } if (vendor == NULL) { - return; + return -1; } LKDHASH_WRLOCK(fbconfigHashtable); @@ -812,6 +838,10 @@ void __glXAddVendorFBConfigMapping(Display *dpy, GLXFBConfig config, __GLXvendor if (pEntry == NULL) { pEntry = malloc(sizeof(*pEntry)); + if (pEntry == NULL) { + LKDHASH_UNLOCK(fbconfigHashtable); + return -1; + } pEntry->config = config; pEntry->vendor = vendor; HASH_ADD_PTR(_LH(fbconfigHashtable), config, pEntry); @@ -819,10 +849,14 @@ void __glXAddVendorFBConfigMapping(Display *dpy, GLXFBConfig config, __GLXvendor // Any GLXContext or GLXFBConfig handles must be unique to a single // vendor at a time. If we get two different vendors, then there's // either a bug in libGLX or in at least one of the vendor libraries. - assert(pEntry->vendor == vendor); + if (pEntry->vendor != vendor) { + LKDHASH_UNLOCK(fbconfigHashtable); + return -1; + } } LKDHASH_UNLOCK(fbconfigHashtable); + return 0; } void __glXRemoveVendorFBConfigMapping(Display *dpy, GLXFBConfig config) @@ -845,7 +879,7 @@ void __glXRemoveVendorFBConfigMapping(Display *dpy, GLXFBConfig config) LKDHASH_UNLOCK(fbconfigHashtable); } -int __glXVendorFromFBConfig(Display *dpy, GLXFBConfig config, __GLXvendorInfo **retVendor) +__GLXvendorInfo *__glXVendorFromFBConfig(Display *dpy, GLXFBConfig config) { __GLXvendorConfigMappingHash *pEntry; __GLXvendorInfo *vendor = NULL; @@ -862,28 +896,7 @@ int __glXVendorFromFBConfig(Display *dpy, GLXFBConfig config, __GLXvendorInfo ** LKDHASH_UNLOCK(fbconfigHashtable); - if (retVendor != NULL) { - *retVendor = vendor; - } - return (vendor != NULL ? 0 : -1); -} - -// Internally, we use the screen number to look up a vendor, so we don't need -// to record anything else for an XVisualInfo. -void __glXAddScreenVisualMapping(Display *dpy, const XVisualInfo *visual, __GLXvendorInfo *vendor) -{ -} -void __glXRemoveScreenVisualMapping(Display *dpy, const XVisualInfo *visual) -{ -} -int __glXVendorFromVisual(Display *dpy, const XVisualInfo *visual, __GLXvendorInfo **retVendor) -{ - __glXThreadInitialize(); - - if (retVendor != NULL) { - *retVendor = __glXLookupVendorByScreen(dpy, visual->screen); - } - return 0; + return vendor; } @@ -894,16 +907,16 @@ int __glXVendorFromVisual(Display *dpy, const XVisualInfo *visual, __GLXvendorIn */ -static void AddVendorXIDMapping(Display *dpy, __GLXdisplayInfo *dpyInfo, XID xid, __GLXvendorInfo *vendor) +static int AddVendorXIDMapping(Display *dpy, __GLXdisplayInfo *dpyInfo, XID xid, __GLXvendorInfo *vendor) { __GLXvendorXIDMappingHash *pEntry = NULL; if (xid == None) { - return; + return 0; } if (vendor == NULL) { - return; + return -1; } LKDHASH_WRLOCK(dpyInfo->xidVendorHash); @@ -912,16 +925,24 @@ static void AddVendorXIDMapping(Display *dpy, __GLXdisplayInfo *dpyInfo, XID xid if (pEntry == NULL) { pEntry = malloc(sizeof(*pEntry)); + if (pEntry == NULL) { + LKDHASH_UNLOCK(dpyInfo->xidVendorHash); + return -1; + } pEntry->xid = xid; pEntry->vendor = vendor; HASH_ADD(hh, _LH(dpyInfo->xidVendorHash), xid, sizeof(xid), pEntry); } else { // Like GLXContext and GLXFBConfig handles, any GLXDrawables must map // to a single vendor library. - assert(pEntry->vendor == vendor); + if (pEntry->vendor != vendor) { + LKDHASH_UNLOCK(dpyInfo->xidVendorHash); + return -1; + } } LKDHASH_UNLOCK(dpyInfo->xidVendorHash); + return 0; } @@ -967,6 +988,8 @@ static void VendorFromXID(Display *dpy, __GLXdisplayInfo *dpyInfo, XID xid, if (screen >= 0 && screen < ScreenCount(dpy)) { vendor = __glXLookupVendorByScreen(dpy, screen); if (vendor != NULL) { + // Note that if this fails, it's not necessarily a problem. + // We can just query it again next time. AddVendorXIDMapping(dpy, dpyInfo, xid, vendor); } } @@ -979,11 +1002,13 @@ static void VendorFromXID(Display *dpy, __GLXdisplayInfo *dpyInfo, XID xid, } -void __glXAddVendorDrawableMapping(Display *dpy, GLXDrawable drawable, __GLXvendorInfo *vendor) +int __glXAddVendorDrawableMapping(Display *dpy, GLXDrawable drawable, __GLXvendorInfo *vendor) { __GLXdisplayInfo *dpyInfo = __glXLookupDisplay(dpy); if (dpyInfo != NULL) { - AddVendorXIDMapping(dpy, dpyInfo, drawable, vendor); + return AddVendorXIDMapping(dpy, dpyInfo, drawable, vendor); + } else { + return -1; } } @@ -997,7 +1022,7 @@ void __glXRemoveVendorDrawableMapping(Display *dpy, GLXDrawable drawable) } -int __glXVendorFromDrawable(Display *dpy, GLXDrawable drawable, __GLXvendorInfo **retVendor) +__GLXvendorInfo *__glXVendorFromDrawable(Display *dpy, GLXDrawable drawable) { __glXThreadInitialize(); @@ -1012,10 +1037,7 @@ int __glXVendorFromDrawable(Display *dpy, GLXDrawable drawable, __GLXvendorInfo } } - if (retVendor != NULL) { - *retVendor = vendor; - } - return (vendor != NULL ? 0 : -1); + return vendor; } /*! diff --git a/src/GLX/libglxmapping.h b/src/GLX/libglxmapping.h index 984b374..2c377e7 100644 --- a/src/GLX/libglxmapping.h +++ b/src/GLX/libglxmapping.h @@ -50,6 +50,7 @@ struct __GLXvendorInfoRec { __GLdispatchTable *glDispatch; //< GL dispatch table const __GLXapiImports *glxvc; + const __GLdispatchPatchCallbacks *patchCallbacks; __GLXdispatchTableStatic staticDispatch; //< static GLX dispatch table }; @@ -98,21 +99,17 @@ __GLdispatchTable *__glXGetGLDispatch(Display *dpy, const int screen); * Various functions to manage mappings used to determine the screen * of a particular GLX call. */ -void __glXAddVendorContextMapping(Display *dpy, GLXContext context, __GLXvendorInfo *vendor); +int __glXAddVendorContextMapping(Display *dpy, GLXContext context, __GLXvendorInfo *vendor); void __glXRemoveVendorContextMapping(Display *dpy, GLXContext context); -int __glXVendorFromContext(GLXContext context, __GLXvendorInfo **retVendor); +__GLXvendorInfo *__glXVendorFromContext(GLXContext context); -void __glXAddVendorFBConfigMapping(Display *dpy, GLXFBConfig config, __GLXvendorInfo *vendor); +int __glXAddVendorFBConfigMapping(Display *dpy, GLXFBConfig config, __GLXvendorInfo *vendor); void __glXRemoveVendorFBConfigMapping(Display *dpy, GLXFBConfig config); -int __glXVendorFromFBConfig(Display *dpy, GLXFBConfig config, __GLXvendorInfo **retVendor); +__GLXvendorInfo *__glXVendorFromFBConfig(Display *dpy, GLXFBConfig config); -void __glXAddScreenVisualMapping(Display *dpy, const XVisualInfo *visual, __GLXvendorInfo *vendor); -void __glXRemoveScreenVisualMapping(Display *dpy, const XVisualInfo *visual); -int __glXVendorFromVisual(Display *dpy, const XVisualInfo *visual, __GLXvendorInfo **retVendor); - -void __glXAddVendorDrawableMapping(Display *dpy, GLXDrawable drawable, __GLXvendorInfo *vendor); +int __glXAddVendorDrawableMapping(Display *dpy, GLXDrawable drawable, __GLXvendorInfo *vendor); void __glXRemoveVendorDrawableMapping(Display *dpy, GLXDrawable drawable); -int __glXVendorFromDrawable(Display *dpy, GLXDrawable drawable, __GLXvendorInfo **retVendor); +__GLXvendorInfo *__glXVendorFromDrawable(Display *dpy, GLXDrawable drawable); __GLXextFuncPtr __glXGetGLXDispatchAddress(const GLubyte *procName); __GLXextFuncPtr __glXGenerateGLXEntrypoint(const GLubyte *procName); diff --git a/src/GLdispatch/GLdispatch.c b/src/GLdispatch/GLdispatch.c index 9c22498..aa0b64d 100644 --- a/src/GLdispatch/GLdispatch.c +++ b/src/GLdispatch/GLdispatch.c @@ -563,14 +563,16 @@ static int PatchEntrypoints( if (stubCurrentPatchCb) { // Notify the previous vendor that it no longer owns these // entrypoints. - stubCurrentPatchCb->releasePatch(); + if (stubCurrentPatchCb->releasePatch != NULL) { + stubCurrentPatchCb->releasePatch(); + } } if (patchCb) { GLboolean anySuccess = GL_FALSE; glvnd_list_for_each_entry(stub, &dispatchStubList, entry) { - if (patchCb->checkPatchSupported(stub->callbacks.getStubType(), + if (patchCb->isPatchSupported(stub->callbacks.getStubType(), stub->callbacks.getStubSize())) { if (stub->callbacks.startPatch()) { @@ -826,6 +828,10 @@ void __glDispatchCheckMultithreaded(void) } } UnlockDispatch(); + + if (stubCurrentPatchCb != NULL && stubCurrentPatchCb->threadAttach != NULL) { + stubCurrentPatchCb->threadAttach(); + } } } diff --git a/src/GLdispatch/GLdispatch.h b/src/GLdispatch/GLdispatch.h index 5dd700a..3d83215 100644 --- a/src/GLdispatch/GLdispatch.h +++ b/src/GLdispatch/GLdispatch.h @@ -137,6 +137,81 @@ typedef struct __GLdispatchThreadStateRec { struct __GLdispatchThreadStatePrivateRec *priv; } __GLdispatchThreadState; +typedef struct __GLdispatchPatchCallbacksRec { + /*! + * Checks to see if the vendor library supports patching the given stub + * type and size. + * + * \param type The type of entrypoints. This will be a one of the + * __GLDISPATCH_STUB_* values. + * \param stubSize The maximum size of the stub that the vendor library can + * write, in bytes. + * \param lookupStubOffset A callback into libglvnd to look up the address + * of each entrypoint. + */ + GLboolean (* isPatchSupported)(int type, int stubSize); + + /*! + * Called by libglvnd to request that a vendor library patch its top-level + * entrypoints. + * + * The vendor library should use the \p lookupStubOffset callback to find + * the addresses of each entrypoint. + * + * This function may be called more than once to patch multiple sets of + * entrypoints. For example, depending on how they're built, libOpenGL.so + * or libGL.so may have their own entrypoints that are separate functions + * from the ones in libGLdispatch. + * + * Note that during this call is the only time that the entrypoints can be + * modified. After the call to \c initiatePatch returns, the vendor library + * should treat the entrypoints as read-only. + * + * \param type The type of entrypoints. This will be a one of the + * __GLDISPATCH_STUB_* values. + * \param stubSize The maximum size of the stub that the vendor library can + * write, in bytes. + * \param lookupStubOffset A callback into libglvnd to look up the address + * of each entrypoint. + * + * \return GL_TRUE if the vendor library supports patching with this type + * and size. + */ + GLboolean (*initiatePatch)(int type, + int stubSize, + DispatchPatchLookupStubOffset lookupStubOffset); + + /*! + * (OPTIONAL) Called by libglvnd to notify the current vendor that it no + * longer owns the top-level entrypoints. + * + * Libglvnd will take care of the restoring the entrypoints back to their + * original state. The vendor library must not try to modify them. + */ + void (*releasePatch)(void); + + /*! + * (OPTIONAL) Called at the start of window-system functions (GLX and EGL). + * This callback allows vendor libraries to perform any per-thread + * initialization. + * + * This is basically a workaround for broken applications. A lot of apps + * will make one or more invalid GLX/EGL calls on a thread (often including + * a MakeCurrent with invalid parameters), and then will try to call an + * OpenGL function. + * + * A non-libglvnd-based driver would be able to initialize any thread state + * even on a bogus GLX call, but with libglvnd, those calls wouldn't get + * past libGLX. + * + * This function is optional. If it's \c NULL, then libGLdispatch will + * simply ignore it. + * + * \note This function may be called concurrently from multiple threads. + */ + void (*threadAttach)(void); +} __GLdispatchPatchCallbacks; + /*! * Gets the version number for the ABI between libGLdispatch and the * window-system libraries. diff --git a/src/GLdispatch/GLdispatchPrivate.h b/src/GLdispatch/GLdispatchPrivate.h index b025483..aca8de7 100644 --- a/src/GLdispatch/GLdispatchPrivate.h +++ b/src/GLdispatch/GLdispatchPrivate.h @@ -37,25 +37,6 @@ #include "utils_misc.h" /*! - * XXX: Any changes to the internal mapi enum should be accompanied by an ABI - * update, and vice versa. - */ -#define TLS_TYPE_CHECK(x) STATIC_ASSERT((int)__GLDISPATCH_STUB_ ## x == (int)ENTRY_ ## x) - -static inline void UNUSED __unused_tls_type_check(void) -{ - TLS_TYPE_CHECK(X86_TLS); - TLS_TYPE_CHECK(X86_64_TLS); - TLS_TYPE_CHECK(X86_TSD); - TLS_TYPE_CHECK(PURE_C); - TLS_TYPE_CHECK(X86_64_TSD); - TLS_TYPE_CHECK(ARMV7_THUMB_TSD); - TLS_TYPE_CHECK(NUM_TYPES); -} - -#undef TLS_TYPE_CHECK - -/*! * Private dispatch table structure. This is used by GLdispatch for tracking * and updating dispatch tables. */ diff --git a/src/GLdispatch/vnd-glapi/mapi/entry.h b/src/GLdispatch/vnd-glapi/mapi/entry.h index 35758a2..bea812d 100644 --- a/src/GLdispatch/vnd-glapi/mapi/entry.h +++ b/src/GLdispatch/vnd-glapi/mapi/entry.h @@ -32,16 +32,6 @@ typedef void (*mapi_func)(void); -enum { - ENTRY_X86_TLS, - ENTRY_X86_64_TLS, - ENTRY_X86_TSD, - ENTRY_PURE_C, - ENTRY_X86_64_TSD, - ENTRY_ARMV7_THUMB_TSD, - ENTRY_NUM_TYPES -}; - extern const int entry_type; extern const int entry_stub_size; diff --git a/src/GLdispatch/vnd-glapi/mapi/entry_armv7_tsd.c b/src/GLdispatch/vnd-glapi/mapi/entry_armv7_tsd.c index be394c9..7bd9da0 100644 --- a/src/GLdispatch/vnd-glapi/mapi/entry_armv7_tsd.c +++ b/src/GLdispatch/vnd-glapi/mapi/entry_armv7_tsd.c @@ -39,6 +39,7 @@ #include "u_macros.h" #include "u_current.h" #include "utils_misc.h" +#include "glvnd/GLdispatchABI.h" /* * See: https://sourceware.org/binutils/docs/as/ARM-Directives.html @@ -157,7 +158,7 @@ __asm__(".balign 4096\n" __asm__(".arm\n\t"); #endif -const int entry_type = ENTRY_ARMV7_THUMB_TSD; +const int entry_type = __GLDISPATCH_STUB_ARMV7_THUMB; const int entry_stub_size = ARMV7_ENTRY_SIZE; static const int TEMPLATE_OFFSET_CURRENT_TABLE = ARMV7_BYTECODE_SIZE - 3*4; diff --git a/src/GLdispatch/vnd-glapi/mapi/entry_pure_c.c b/src/GLdispatch/vnd-glapi/mapi/entry_pure_c.c index 7b9ea82..134143e 100644 --- a/src/GLdispatch/vnd-glapi/mapi/entry_pure_c.c +++ b/src/GLdispatch/vnd-glapi/mapi/entry_pure_c.c @@ -30,6 +30,7 @@ #include <stdlib.h> #include "glapi/glapi.h" +#include "glvnd/GLdispatchABI.h" static INLINE const struct _glapi_table * entry_current_get(void) @@ -48,7 +49,7 @@ entry_current_get(void) #define MAPI_TMP_PUBLIC_ENTRIES #include "mapi_tmp.h" -const int entry_type = ENTRY_PURE_C; +const int entry_type = __GLDISPATCH_STUB_UNKNOWN; const int entry_stub_size = 0; void diff --git a/src/GLdispatch/vnd-glapi/mapi/entry_x86_64_tls.c b/src/GLdispatch/vnd-glapi/mapi/entry_x86_64_tls.c index 7ac068c..d99c8a4 100644 --- a/src/GLdispatch/vnd-glapi/mapi/entry_x86_64_tls.c +++ b/src/GLdispatch/vnd-glapi/mapi/entry_x86_64_tls.c @@ -36,6 +36,7 @@ #include "utils_misc.h" #include "u_macros.h" #include "glapi/glapi.h" +#include "glvnd/GLdispatchABI.h" #define ENTRY_STUB_ALIGN 32 #define ENTRY_STUB_SIZE ENTRY_STUB_ALIGN @@ -74,7 +75,7 @@ __asm__("x86_64_current_tls:\n\t" extern unsigned long x86_64_current_tls(); -const int entry_type = ENTRY_X86_64_TLS; +const int entry_type = __GLDISPATCH_STUB_X86_64; const int entry_stub_size = ENTRY_STUB_SIZE; void entry_generate_default_code(char *entry, int slot) diff --git a/src/GLdispatch/vnd-glapi/mapi/entry_x86_64_tsd.c b/src/GLdispatch/vnd-glapi/mapi/entry_x86_64_tsd.c index e2199a0..008d5ea 100644 --- a/src/GLdispatch/vnd-glapi/mapi/entry_x86_64_tsd.c +++ b/src/GLdispatch/vnd-glapi/mapi/entry_x86_64_tsd.c @@ -38,6 +38,7 @@ #include "u_macros.h" #include "glapi/glapi.h" +#include "glvnd/GLdispatchABI.h" #define X86_64_ENTRY_SIZE 64 @@ -90,7 +91,7 @@ __asm__(".balign 4096\n" "public_entry_end:"); __asm__(".text\n"); -const int entry_type = ENTRY_X86_64_TSD; +const int entry_type = __GLDISPATCH_STUB_X86_64; const int entry_stub_size = X86_64_ENTRY_SIZE; static const unsigned char ENTRY_TEMPLATE[] = diff --git a/src/GLdispatch/vnd-glapi/mapi/entry_x86_tsd.c b/src/GLdispatch/vnd-glapi/mapi/entry_x86_tsd.c index 1f58642..4c23239 100644 --- a/src/GLdispatch/vnd-glapi/mapi/entry_x86_tsd.c +++ b/src/GLdispatch/vnd-glapi/mapi/entry_x86_tsd.c @@ -36,6 +36,7 @@ #include "u_macros.h" #include "glapi/glapi.h" +#include "glvnd/GLdispatchABI.h" #define X86_ENTRY_SIZE 32 @@ -68,7 +69,7 @@ __asm__(".balign 4096\n" "public_entry_end:"); __asm__(".text\n"); -const int entry_type = ENTRY_X86_TSD; +const int entry_type = __GLDISPATCH_STUB_X86; const int entry_stub_size = X86_ENTRY_SIZE; static const unsigned char ENTRY_TEMPLATE[] = diff --git a/tests/GLX_dummy/GLX_dummy.c b/tests/GLX_dummy/GLX_dummy.c index 2e15db8..29465c9 100644 --- a/tests/GLX_dummy/GLX_dummy.c +++ b/tests/GLX_dummy/GLX_dummy.c @@ -42,8 +42,7 @@ #include "compiler.h" -static char *thisVendorName; -static __GLXapiExports apiExports; +static const __GLXapiExports *apiExports = NULL; /* * Dummy context structure. @@ -330,7 +329,7 @@ static void dummySelectEvent (Display *dpy, */ static void dummy_glBegin (void) { - GLXContext ctx = apiExports.getCurrentContext(); + GLXContext ctx = apiExports->getCurrentContext(); assert(ctx); ctx->beginHit++; @@ -338,7 +337,7 @@ static void dummy_glBegin (void) static void dummy_glVertex3fv(GLfloat *v) { - GLXContext ctx = apiExports.getCurrentContext(); + GLXContext ctx = apiExports->getCurrentContext(); assert(ctx); ctx->vertex3fvHit++; @@ -346,7 +345,7 @@ static void dummy_glVertex3fv(GLfloat *v) static void dummy_glEnd (void) { - GLXContext ctx = apiExports.getCurrentContext(); + GLXContext ctx = apiExports->getCurrentContext(); assert(ctx); ctx->endHit++; @@ -356,7 +355,7 @@ static void dummy_glMakeCurrentTestResults(GLint req, GLboolean *saw, void **ret) { - GLXContext ctx = apiExports.getCurrentContext(); + GLXContext ctx = apiExports->getCurrentContext(); assert(ctx); *saw = GL_TRUE; @@ -372,7 +371,11 @@ static void dummy_glMakeCurrentTestResults(GLint req, break; case GL_MC_VENDOR_STRING: { - *ret = thisVendorName ? strdup(thisVendorName) : NULL; + // FIXME: This is used from testglxnscreens to check that the + // correct vendor library is loaded from each display. Originally, + // it used the vendor name passed to __glx_Main, but libGLX doesn't + // provide the vendor name anymore. + *ret = NULL; } break; case GL_MC_LAST_REQ: @@ -402,13 +405,13 @@ static void dispatch_glXExampleExtensionFunction(Display *dpy, ExampleExtensionFunctionPtr func; const int index = dummyExampleExtensionFunctionIndex; - dynDispatch = apiExports.getDynDispatch(dpy, screen); + dynDispatch = apiExports->getDynDispatch(dpy, screen); if (!dynDispatch) { return; } func = (ExampleExtensionFunctionPtr) - apiExports.fetchDispatchEntry(dynDispatch, index); + apiExports->fetchDispatchEntry(dynDispatch, index); if (func) { func(dpy, screen, retval); } @@ -503,7 +506,7 @@ static void dummySetDispatchIndex (const GLubyte *procName, int ind #if defined(PATCH_ENTRYPOINTS) PUBLIC int __glXSawVertex3fv; -static void patch_x86_64_tls(char *writeEntry, +static void patch_x86_64(char *writeEntry, const char *execEntry, int stubSize) { @@ -535,7 +538,7 @@ static void patch_x86_64_tls(char *writeEntry, #endif } -static void patch_x86_tls(char *writeEntry, +static void patch_x86(char *writeEntry, const char *execEntry, int stubSize) { @@ -575,7 +578,7 @@ static void patch_x86_tls(char *writeEntry, #endif } -static void patch_armv7_thumb_tsd(char *writeEntry, +static void patch_armv7_thumb(char *writeEntry, const char *execEntry, int stubSize) { @@ -621,11 +624,9 @@ static void patch_armv7_thumb_tsd(char *writeEntry, static GLboolean dummyCheckPatchSupported(int type, int stubSize) { switch (type) { - case __GLDISPATCH_STUB_X86_64_TLS: - case __GLDISPATCH_STUB_X86_TLS: - case __GLDISPATCH_STUB_X86_TSD: - case __GLDISPATCH_STUB_X86_64_TSD: - case __GLDISPATCH_STUB_ARMV7_THUMB_TSD: + case __GLDISPATCH_STUB_X86_64: + case __GLDISPATCH_STUB_X86: + case __GLDISPATCH_STUB_ARMV7_THUMB: return GL_TRUE; default: return GL_FALSE; @@ -646,16 +647,14 @@ static GLboolean dummyInitiatePatch(int type, if (lookupStubOffset("Vertex3fv", &writeAddr, &execAddr)) { switch (type) { - case __GLDISPATCH_STUB_X86_64_TLS: - case __GLDISPATCH_STUB_X86_64_TSD: - patch_x86_64_tls(writeAddr, execAddr, stubSize); + case __GLDISPATCH_STUB_X86_64: + patch_x86_64(writeAddr, execAddr, stubSize); break; - case __GLDISPATCH_STUB_X86_TLS: - case __GLDISPATCH_STUB_X86_TSD: - patch_x86_tls(writeAddr, execAddr, stubSize); + case __GLDISPATCH_STUB_X86: + patch_x86(writeAddr, execAddr, stubSize); break; - case __GLDISPATCH_STUB_ARMV7_THUMB_TSD: - patch_armv7_thumb_tsd(writeAddr, execAddr, stubSize); + case __GLDISPATCH_STUB_ARMV7_THUMB: + patch_armv7_thumb(writeAddr, execAddr, stubSize); break; default: assert(0); @@ -665,38 +664,30 @@ static GLboolean dummyInitiatePatch(int type, return GL_TRUE; } -static void dummyReleasePatch(void) -{ -} - -static const __GLdispatchPatchCallbacks dummyPatchCallbacks = -{ - .checkPatchSupported = dummyCheckPatchSupported, - .initiatePatch = dummyInitiatePatch, - .releasePatch = dummyReleasePatch, -}; #endif // defined(PATCH_ENTRYPOINTS) -static const __GLXapiImports dummyImports = -{ - .checkSupportsScreen = dummyCheckSupportsScreen, - .getProcAddress = dummyGetProcAddress, - .getDispatchAddress = dummyGetDispatchAddress, - .setDispatchIndex = dummySetDispatchIndex, +PUBLIC Bool __glx_Main(uint32_t version, + const __GLXapiExports *exports, + __GLXvendorInfo *vendor, + __GLXapiImports *imports) +{ + if (GLX_VENDOR_ABI_GET_MAJOR_VERSION(version) + == GLX_VENDOR_ABI_GET_MAJOR_VERSION(GLX_VENDOR_ABI_VERSION)) { + if (GLX_VENDOR_ABI_GET_MINOR_VERSION(version) + >= GLX_VENDOR_ABI_GET_MINOR_VERSION(GLX_VENDOR_ABI_VERSION)) { + apiExports = exports; + + imports->isScreenSupported = dummyCheckSupportsScreen; + imports->getProcAddress = dummyGetProcAddress; + imports->getDispatchAddress = dummyGetDispatchAddress; + imports->setDispatchIndex = dummySetDispatchIndex; #if defined(PATCH_ENTRYPOINTS) - .patchCallbacks = &dummyPatchCallbacks, -#else - .patchCallbacks = NULL, + imports->isPatchSupported = dummyCheckPatchSupported; + imports->initiatePatch = dummyInitiatePatch; #endif -}; -PUBLIC __GLX_MAIN_PROTO(version, exports, vendorName) -{ - thisVendorName = strdup(vendorName); - if (version <= GLX_VENDOR_ABI_VERSION) { - memcpy(&apiExports, exports, sizeof(*exports)); - return &dummyImports; - } else { - return NULL; + return True; + } } + return False; } |