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.
This commit is contained in:
Kyle Brenneman 2016-03-10 16:36:45 -07:00
parent da7ae346e3
commit 3a84276f63
7 changed files with 175 additions and 123 deletions

View file

@ -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

View file

@ -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.
*/
__GLdispatchPatchCallbacks *patchCallbacks;
/*!
* (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.
*/
void (*patchThreadAttach)(void);
} __GLXapiImports;

View file

@ -866,7 +866,7 @@ static Bool InternalMakeCurrentDispatch(
&apiState->glas,
vendor->glDispatch,
vendor->vendorID,
vendor->glxvc->patchCallbacks
vendor->patchCallbacks
);
if (ret) {

View file

@ -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);

View file

@ -50,6 +50,7 @@ struct __GLXvendorInfoRec {
__GLdispatchTable *glDispatch; //< GL dispatch table
const __GLXapiImports *glxvc;
const __GLdispatchPatchCallbacks *patchCallbacks;
__GLXdispatchTableStatic staticDispatch; //< static GLX dispatch table
};

View file

@ -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.

View file

@ -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;