From 3a84276f63242f8f231b4772448d025c1ae41cc1 Mon Sep 17 00:00:00 2001 From: Kyle Brenneman Date: Thu, 10 Mar 2016 16:36:45 -0700 Subject: GLX: Add the patch callbacks directly to __GLXapiImports. Added the function pointers for entrypoint rewriting as members of __GLXapiImports, instead of using a separate __GLdispatchPatchCallbacks pointer. Moved the __GLdispatchPatchCallbacks struct to GLdispatch.h. --- include/glvnd/GLdispatchABI.h | 75 -------------------------------------- include/glvnd/libglxabi.h | 85 +++++++++++++++++++++++++++++++++++++++---- src/GLX/libglx.c | 2 +- src/GLX/libglxmapping.c | 56 +++++++++------------------- src/GLX/libglxmapping.h | 1 + src/GLdispatch/GLdispatch.h | 75 ++++++++++++++++++++++++++++++++++++++ tests/GLX_dummy/GLX_dummy.c | 4 +- 7 files changed, 175 insertions(+), 123 deletions(-) diff --git a/include/glvnd/GLdispatchABI.h b/include/glvnd/GLdispatchABI.h index 16afb3d..25d593a 100644 --- a/include/glvnd/GLdispatchABI.h +++ b/include/glvnd/GLdispatchABI.h @@ -113,81 +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 (* 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; - #if defined(__cplusplus) } #endif diff --git a/include/glvnd/libglxabi.h b/include/glvnd/libglxabi.h index 52ff3b9..13189b9 100644 --- a/include/glvnd/libglxabi.h +++ b/include/glvnd/libglxabi.h @@ -297,19 +297,90 @@ 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 * optimization that may not be available at runtime; the vendor library * must not depend on this functionality for correctness. * - * Like the __GLXapiImports struct itself, this struct is allocated and - * zeroed by libGLX. The vendor library should assign function pointers - * to the members of this struct, but should not change the - * \c patchCallbacks pointer itself. + * 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. */ - __GLdispatchPatchCallbacks *patchCallbacks; + void (*patchThreadAttach)(void); } __GLXapiImports; diff --git a/src/GLX/libglx.c b/src/GLX/libglx.c index 01ea9a7..c61c17a 100644 --- a/src/GLX/libglx.c +++ b/src/GLX/libglx.c @@ -866,7 +866,7 @@ static Bool InternalMakeCurrentDispatch( &apiState->glas, vendor->glDispatch, vendor->vendorID, - vendor->glxvc->patchCallbacks + vendor->patchCallbacks ); if (ret) { diff --git a/src/GLX/libglxmapping.c b/src/GLX/libglxmapping.c index 40f36bc..506cb06 100644 --- a/src/GLX/libglxmapping.c +++ b/src/GLX/libglxmapping.c @@ -447,37 +447,6 @@ static GLboolean LookupVendorEntrypoints(__GLXvendorInfo *vendor) return GL_TRUE; } -static Bool CheckVendorImportsTable(__GLXvendorNameHash *pEntry) -{ - // 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) - { - return False; - } - - // Check to see whether this vendor library can support entrypoint - // patching. - if (pEntry->imports.patchCallbacks != NULL) { - if (pEntry->imports.patchCallbacks != &pEntry->patchCallbacks) { - // The vendor library shouldn't replace the patchCallbacks - // pointer. If it does, then just ignore it. - pEntry->imports.patchCallbacks = NULL; - } else { - if (pEntry->patchCallbacks.isPatchSupported == NULL - || pEntry->patchCallbacks.initiatePatch == NULL) { - // If we don't have at least the isPatchSupported and - // initiatePatch callbacks, then patching isn't - // supported. - pEntry->imports.patchCallbacks = NULL; - } - } - } - return True; -} - static void *VendorGetProcAddressCallback(const char *procName, void *param) { __GLXvendorInfo *vendor = (__GLXvendorInfo *) param; @@ -522,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); @@ -551,9 +521,6 @@ __GLXvendorInfo *__glXLookupVendorByName(const char *vendorName) goto fail; } - // Plug in the vendor imports table. - pEntry->imports.patchCallbacks = &pEntry->patchCallbacks; - /* Initialize the dynamic dispatch table */ LKDHASH_INIT(vendor->dynDispatchHash); @@ -564,17 +531,30 @@ __GLXvendorInfo *__glXLookupVendorByName(const char *vendorName) goto fail; } - // Check to see whether this vendor library can support entrypoint - // patching. - if (!CheckVendorImportsTable(pEntry)) { + // 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; } - vendor->glxvc = &pEntry->imports; 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); diff --git a/src/GLX/libglxmapping.h b/src/GLX/libglxmapping.h index 525ea27..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 }; diff --git a/src/GLdispatch/GLdispatch.h b/src/GLdispatch/GLdispatch.h index 5532403..0573bba 100644 --- a/src/GLdispatch/GLdispatch.h +++ b/src/GLdispatch/GLdispatch.h @@ -123,6 +123,81 @@ typedef struct __GLdispatchAPIStateRec { struct __GLdispatchAPIStatePrivateRec *priv; } __GLdispatchAPIState; +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/tests/GLX_dummy/GLX_dummy.c b/tests/GLX_dummy/GLX_dummy.c index f8b6347..cb493eb 100644 --- a/tests/GLX_dummy/GLX_dummy.c +++ b/tests/GLX_dummy/GLX_dummy.c @@ -679,8 +679,8 @@ PUBLIC Bool __glx_Main(uint32_t version, imports->getDispatchAddress = dummyGetDispatchAddress; imports->setDispatchIndex = dummySetDispatchIndex; #if defined(PATCH_ENTRYPOINTS) - imports->patchCallbacks->isPatchSupported = dummyCheckPatchSupported; - imports->patchCallbacks->initiatePatch = dummyInitiatePatch; + imports->isPatchSupported = dummyCheckPatchSupported; + imports->initiatePatch = dummyInitiatePatch; #endif return True; -- cgit v1.2.3