GLX: Change __glx_Main to use the libGLX-allocated __GLXapiImports table.

__glx_Main now takes a pointer to the __GLXapiImports struct and fills it in.

The __GLXapiImports struct is now allocated and zeroed by libGLX. This makes it
possible to add an optional element to the end of the struct without breaking
backward compatibility.
This commit is contained in:
Kyle Brenneman 2016-03-03 14:29:13 -07:00
parent 3887b8e90e
commit da7ae346e3
5 changed files with 88 additions and 63 deletions

View file

@ -158,8 +158,8 @@ typedef struct __GLdispatchPatchCallbacksRec {
DispatchPatchLookupStubOffset lookupStubOffset);
/*!
* Called by libglvnd to notify the current vendor that it no longer owns
* the top-level entrypoints.
* (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.

View file

@ -300,25 +300,30 @@ typedef struct __GLXapiImportsRec {
/*!
* (OPTIONAL) Callbacks by which the vendor library may 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.
*
* 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.
*/
const __GLdispatchPatchCallbacks *patchCallbacks;
__GLdispatchPatchCallbacks *patchCallbacks;
} __GLXapiImports;
/*****************************************************************************/
#define __GLX_MAIN_PROTO_NAME "__glx_Main"
#define __GLX_MAIN_PROTO(version, exports, vendorName) \
const __GLXapiImports *__glx_Main(uint32_t version, \
#define __GLX_MAIN_PROTO(version, exports, vendor, imports) \
__GLXapiImports *__glx_Main(uint32_t version, \
const __GLXapiExports *exports, \
__GLXvendorInfo *vendor)
__GLXvendorInfo *vendor, \
__GLXapiImports *imports)
typedef const __GLXapiImports *(*__PFNGLXMAINPROC)
(uint32_t version, const __GLXapiExports *exports, __GLXvendorInfo *vendor);
typedef Bool (*__PFNGLXMAINPROC)
(uint32_t version, const __GLXapiExports *exports, __GLXvendorInfo *vendor, __GLXapiImports *imports);
/*!
* Vendor libraries must export a function called __glx_Main() with the
@ -328,23 +333,27 @@ typedef const __GLXapiImports *(*__PFNGLXMAINPROC)
* Vendor libraries can optionally use the version number to support older
* versions of the ABI.
*
* \param version The ABI version. The upper 16 bits contains the major version
* \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 exports The table of functions provided by libGLX. This pointer will
* \param[in] exports The table of functions provided by libGLX. This pointer will
* remain valid for as long as the vendor is loaded.
*
* \param vendor The opaque pointer used to identify this vendor library. This
* \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.
*
* \return A pointer to a __GLXapiImports struct, which must remain valid for
* as long as the vendor is loaded. If the vendor library does not support the
* requested ABI version, or if some other error occurrs, then it should return
* \c NULL.
* \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.
*/
const __GLXapiImports *__glx_Main(uint32_t version,
Bool __glx_Main(uint32_t version,
const __GLXapiExports *exports,
__GLXvendorInfo *vendor);
__GLXvendorInfo *vendor,
__GLXapiImports *imports);
/*!
* @}

View file

@ -447,6 +447,37 @@ 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;
@ -481,7 +512,7 @@ __GLXvendorInfo *__glXLookupVendorByName(const char *vendorName)
__GLXvendorInfo *vendor;
__PFNGLXMAINPROC glxMainProc;
char *filename;
const __GLXapiImports *imports;
Bool success;
// Previously unseen vendor. dlopen() the new vendor and add it to the
// hash table.
@ -522,30 +553,23 @@ __GLXvendorInfo *__glXLookupVendorByName(const char *vendorName)
// Plug in the vendor imports table.
pEntry->imports.patchCallbacks = &pEntry->patchCallbacks;
vendor->glxvc = &pEntry->imports;
/* Initialize the dynamic dispatch table */
LKDHASH_INIT(vendor->dynDispatchHash);
imports = (*glxMainProc)(GLX_VENDOR_ABI_VERSION,
success = (*glxMainProc)(GLX_VENDOR_ABI_VERSION,
&glxExportsTable,
vendor);
if (!imports) {
vendor, &pEntry->imports);
if (!success) {
goto fail;
}
// Copy the imports table from the vendor library.
memcpy(&pEntry->imports, imports, sizeof(__GLXapiImports));
if (imports->patchCallbacks != NULL) {
memcpy(&pEntry->patchCallbacks, imports->patchCallbacks, sizeof(__GLdispatchPatchCallbacks));
}
// Set the patchCallbacks table.
if (pEntry->patchCallbacks.isPatchSupported != NULL
&& pEntry->patchCallbacks.initiatePatch != NULL) {
pEntry->imports.patchCallbacks = &pEntry->patchCallbacks;
} else {
pEntry->imports.patchCallbacks = NULL;
// Check to see whether this vendor library can support entrypoint
// patching.
if (!CheckVendorImportsTable(pEntry)) {
goto fail;
}
vendor->glxvc = &pEntry->imports;
if (!LookupVendorEntrypoints(vendor)) {
goto fail;

View file

@ -563,7 +563,9 @@ 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) {

View file

@ -664,37 +664,27 @@ static GLboolean dummyInitiatePatch(int type,
return GL_TRUE;
}
static void dummyReleasePatch(void)
{
}
static const __GLdispatchPatchCallbacks dummyPatchCallbacks =
{
.isPatchSupported = dummyCheckPatchSupported,
.initiatePatch = dummyInitiatePatch,
.releasePatch = dummyReleasePatch,
};
#endif // defined(PATCH_ENTRYPOINTS)
static const __GLXapiImports dummyImports =
{
.isScreenSupported = dummyCheckSupportsScreen,
.getProcAddress = dummyGetProcAddress,
.getDispatchAddress = dummyGetDispatchAddress,
.setDispatchIndex = dummySetDispatchIndex,
#if defined(PATCH_ENTRYPOINTS)
.patchCallbacks = &dummyPatchCallbacks,
#else
.patchCallbacks = NULL,
#endif
};
PUBLIC __GLX_MAIN_PROTO(version, exports, vendor)
PUBLIC Bool __glx_Main(uint32_t version,
const __GLXapiExports *exports,
__GLXvendorInfo *vendor,
__GLXapiImports *imports)
{
if (version <= GLX_VENDOR_ABI_VERSION) {
memcpy(&apiExports, exports, sizeof(*exports));
return &dummyImports;
imports->isScreenSupported = dummyCheckSupportsScreen;
imports->getProcAddress = dummyGetProcAddress;
imports->getDispatchAddress = dummyGetDispatchAddress;
imports->setDispatchIndex = dummySetDispatchIndex;
#if defined(PATCH_ENTRYPOINTS)
imports->patchCallbacks->isPatchSupported = dummyCheckPatchSupported;
imports->patchCallbacks->initiatePatch = dummyInitiatePatch;
#endif
return True;
} else {
return NULL;
return False;
}
}