2013-08-23 01:06:53 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2013, NVIDIA CORPORATION.
|
2013-08-23 01:21:31 +02:00
|
|
|
*
|
|
|
|
* 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.
|
2013-08-23 01:06:53 +02:00
|
|
|
*/
|
|
|
|
|
2013-08-23 01:21:31 +02:00
|
|
|
#include <X11/Xlibint.h>
|
|
|
|
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <dlfcn.h>
|
2015-07-17 15:26:52 +02:00
|
|
|
#include <string.h>
|
2013-08-23 01:21:31 +02:00
|
|
|
|
|
|
|
#if defined(HASH_DEBUG)
|
|
|
|
# include <stdio.h>
|
|
|
|
#endif
|
|
|
|
|
2013-11-26 00:21:41 +01:00
|
|
|
#include "libglxcurrent.h"
|
2013-08-23 01:06:53 +02:00
|
|
|
#include "libglxmapping.h"
|
|
|
|
#include "libglxnoop.h"
|
2013-08-23 01:21:31 +02:00
|
|
|
#include "libglxthread.h"
|
2015-04-13 21:38:35 +02:00
|
|
|
#include "libglxstring.h"
|
2015-05-28 18:53:48 +02:00
|
|
|
#include "utils_misc.h"
|
2015-05-27 17:11:19 +02:00
|
|
|
#include "glvnd_genentry.h"
|
2013-08-23 01:21:31 +02:00
|
|
|
#include "trace.h"
|
2013-08-23 01:06:53 +02:00
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
#include "lkdhash.h"
|
2013-08-12 22:12:09 +02:00
|
|
|
#include "x11glvnd.h"
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2013-08-23 01:21:31 +02:00
|
|
|
#define _GNU_SOURCE 1
|
2013-08-23 01:06:53 +02:00
|
|
|
|
2015-04-24 00:46:52 +02:00
|
|
|
#if !defined(FALLBACK_VENDOR_NAME)
|
|
|
|
/*!
|
|
|
|
* This is the vendor name that we'll use as a fallback if we can't otherwise
|
2015-06-29 21:38:27 +02:00
|
|
|
* find one.
|
|
|
|
*
|
|
|
|
* The only place where this should happen is if the display connection is to a
|
|
|
|
* remote X server, which might not support the x11glvnd extension, or might
|
|
|
|
* specify a vendor library that's not available to the client. In that case,
|
|
|
|
* only indirect rendering will be possible.
|
|
|
|
*
|
|
|
|
* Eventually, libglvnd should have a dedicated vendor library for indirect
|
|
|
|
* rendering, independent of any hardware vendor. Until then, this will
|
|
|
|
* typically be a symlink to an existing vendor library.
|
2015-04-24 00:46:52 +02:00
|
|
|
*/
|
2015-06-29 21:38:27 +02:00
|
|
|
#define FALLBACK_VENDOR_NAME "indirect"
|
2015-04-24 00:46:52 +02:00
|
|
|
#endif
|
|
|
|
|
2015-09-28 23:55:57 +02:00
|
|
|
#define GLX_EXTENSION_NAME "GLX"
|
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
/*
|
|
|
|
* Hash table containing a mapping from dispatch table index entries to
|
|
|
|
* entry point names. This is used in __glXFetchDispatchEntry() to query
|
|
|
|
* the appropriate vendor in the case where the entry hasn't been seen before
|
|
|
|
* by this vendor.
|
|
|
|
*/
|
|
|
|
typedef struct __GLXdispatchIndexHashRec {
|
|
|
|
int index;
|
|
|
|
GLubyte *procName;
|
|
|
|
UT_hash_handle hh;
|
|
|
|
} __GLXdispatchIndexHash;
|
|
|
|
|
|
|
|
static DEFINE_INITIALIZED_LKDHASH(__GLXdispatchIndexHash, __glXDispatchIndexHash);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Monotonically-increasing number describing both the virtual "size" of the
|
|
|
|
* dynamic dispatch table and the next unused index. Must be accessed holding
|
|
|
|
* the __glXDispatchIndexHash lock.
|
|
|
|
*/
|
|
|
|
static int __glXNextUnusedHashIndex;
|
|
|
|
|
|
|
|
typedef struct __GLXdispatchFuncHashRec {
|
|
|
|
int index;
|
|
|
|
__GLXextFuncPtr addr;
|
|
|
|
UT_hash_handle hh;
|
|
|
|
} __GLXdispatchFuncHash;
|
|
|
|
|
|
|
|
/****************************************************************************/
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
/*
|
|
|
|
* __glXVendorNameHash is a hash table mapping a vendor name to vendor info.
|
|
|
|
*/
|
|
|
|
typedef struct __GLXvendorNameHashRec {
|
2016-02-17 23:27:12 +01:00
|
|
|
__GLXvendorInfo vendor;
|
2016-03-03 21:50:24 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
UT_hash_handle hh;
|
|
|
|
} __GLXvendorNameHash;
|
|
|
|
|
|
|
|
static DEFINE_INITIALIZED_LKDHASH(__GLXvendorNameHash, __glXVendorNameHash);
|
|
|
|
|
2015-04-14 19:58:43 +02:00
|
|
|
typedef struct __GLXdisplayInfoHashRec {
|
|
|
|
Display *dpy;
|
|
|
|
__GLXdisplayInfo info;
|
|
|
|
UT_hash_handle hh;
|
|
|
|
} __GLXdisplayInfoHash;
|
|
|
|
|
|
|
|
static DEFINE_INITIALIZED_LKDHASH(__GLXdisplayInfoHash, __glXDisplayInfoHash);
|
|
|
|
|
2016-01-04 23:12:23 +01:00
|
|
|
struct __GLXvendorXIDMappingHashRec {
|
2015-04-23 20:30:34 +02:00
|
|
|
XID xid;
|
2016-01-04 20:11:47 +01:00
|
|
|
__GLXvendorInfo *vendor;
|
2015-04-23 20:30:34 +02:00
|
|
|
UT_hash_handle hh;
|
|
|
|
};
|
|
|
|
|
2015-05-27 17:11:19 +02:00
|
|
|
static glvnd_mutex_t glxGenEntrypointMutex = GLVND_MUTEX_INITIALIZER;
|
|
|
|
|
2016-02-17 23:27:12 +01:00
|
|
|
static __GLXextFuncPtr __glXFetchDispatchEntry(__GLXvendorInfo *vendor, int index);
|
|
|
|
|
|
|
|
static const __GLXapiExports glxExportsTable = {
|
|
|
|
.getDynDispatch = __glXGetDynDispatch,
|
|
|
|
.getCurrentDynDispatch = __glXGetCurrentDynDispatch,
|
|
|
|
.fetchDispatchEntry = __glXFetchDispatchEntry,
|
|
|
|
|
|
|
|
/* We use the real function since __glXGetCurrentContext is inline */
|
|
|
|
.getCurrentContext = glXGetCurrentContext,
|
|
|
|
|
|
|
|
.addVendorContextMapping = __glXAddVendorContextMapping,
|
|
|
|
.removeVendorContextMapping = __glXRemoveVendorContextMapping,
|
|
|
|
.vendorFromContext = __glXVendorFromContext,
|
|
|
|
|
|
|
|
.addVendorFBConfigMapping = __glXAddVendorFBConfigMapping,
|
|
|
|
.removeVendorFBConfigMapping = __glXRemoveVendorFBConfigMapping,
|
|
|
|
.vendorFromFBConfig = __glXVendorFromFBConfig,
|
|
|
|
|
|
|
|
.addVendorDrawableMapping = __glXAddVendorDrawableMapping,
|
|
|
|
.removeVendorDrawableMapping = __glXRemoveVendorDrawableMapping,
|
|
|
|
.vendorFromDrawable = __glXVendorFromDrawable,
|
|
|
|
};
|
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
static GLboolean AllocDispatchIndex(__GLXvendorInfo *vendor,
|
|
|
|
const GLubyte *procName)
|
|
|
|
{
|
|
|
|
__GLXdispatchIndexHash *pEntry = malloc(sizeof(*pEntry));
|
|
|
|
if (!pEntry) {
|
|
|
|
return GL_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
pEntry->procName = (GLubyte *)strdup((const char *)procName);
|
2013-09-04 06:57:16 +02:00
|
|
|
if (!pEntry->procName) {
|
|
|
|
free(pEntry);
|
|
|
|
return GL_FALSE;
|
|
|
|
}
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_WRLOCK(__glXDispatchIndexHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
pEntry->index = __glXNextUnusedHashIndex++;
|
|
|
|
|
|
|
|
// Notify the vendor this is the index which should be used
|
2015-08-29 00:50:42 +02:00
|
|
|
vendor->glxvc->setDispatchIndex(procName, pEntry->index);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
HASH_ADD_INT(_LH(__glXDispatchIndexHash),
|
|
|
|
index, pEntry);
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_UNLOCK(__glXDispatchIndexHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
return GL_TRUE;
|
|
|
|
}
|
|
|
|
|
2015-05-27 17:11:19 +02:00
|
|
|
/**
|
|
|
|
* Looks up a dispatch function from a vendor library.
|
|
|
|
*
|
|
|
|
* If the vendor library provides a dispatch function, then it will allocate a
|
|
|
|
* dispatch index for it.
|
|
|
|
*
|
|
|
|
* If the vendor library exports it as a normal OpenGL function, then it will
|
|
|
|
* return a dispatch function from libGLdispatch.
|
|
|
|
*
|
|
|
|
* This function is used from __glXGetGLXDispatchAddress and as the callback to
|
|
|
|
* glvndUpdateEntrypoints.
|
|
|
|
*/
|
|
|
|
static GLVNDentrypointStub __glXFindVendorDispatchAddress(const char *procName, __GLXvendorInfo *vendor)
|
|
|
|
{
|
|
|
|
__GLXextFuncPtr addr = NULL;
|
|
|
|
|
2015-08-29 00:50:42 +02:00
|
|
|
addr = vendor->glxvc->getDispatchAddress((const GLubyte *) procName);
|
2015-05-27 17:11:19 +02:00
|
|
|
if (addr != NULL) {
|
|
|
|
// Allocate the new dispatch index.
|
|
|
|
if (!AllocDispatchIndex(vendor, (const GLubyte *) procName)) {
|
|
|
|
addr = NULL;
|
|
|
|
}
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we didn't find a GLX dispatch function, then check for a normal
|
|
|
|
// OpenGL function. This should handle any case where a GL extension
|
|
|
|
// function starts with "glX".
|
2015-08-29 00:50:42 +02:00
|
|
|
addr = vendor->glxvc->getProcAddress((const GLubyte *) procName);
|
2015-05-27 17:11:19 +02:00
|
|
|
if (addr != NULL) {
|
|
|
|
addr = __glDispatchGetProcAddress(procName);
|
|
|
|
}
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
2014-10-03 01:17:59 +02:00
|
|
|
/*!
|
|
|
|
* Callback function used when freeing the dispatch index hash table.
|
|
|
|
*/
|
|
|
|
static void CleanupDispatchIndexEntry(void *unused, __GLXdispatchIndexHash *pEntry)
|
|
|
|
{
|
|
|
|
assert(pEntry);
|
|
|
|
free(pEntry->procName);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2013-08-23 01:21:31 +02:00
|
|
|
* This function queries each loaded vendor to determine if there is
|
|
|
|
* a vendor-implemented dispatch function. The dispatch function
|
|
|
|
* uses the vendor <-> API library ABI to determine the screen given
|
|
|
|
* the parameters of the function and dispatch to the correct vendor's
|
|
|
|
* implementation.
|
2013-08-23 01:06:53 +02:00
|
|
|
*/
|
2013-08-23 01:21:31 +02:00
|
|
|
__GLXextFuncPtr __glXGetGLXDispatchAddress(const GLubyte *procName)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2013-08-12 22:12:09 +02:00
|
|
|
__GLXextFuncPtr addr = NULL;
|
|
|
|
__GLXvendorNameHash *pEntry, *tmp;
|
|
|
|
|
|
|
|
/*
|
2015-05-27 17:11:19 +02:00
|
|
|
* Note that if a GLX extension function doesn't depend on calling any
|
|
|
|
* other GLX functions first, then the app could call it before loading any
|
|
|
|
* vendor libraries. If that happens, then the entrypoint would go to a
|
|
|
|
* no-op stub instead of the correct dispatch stub.
|
|
|
|
*
|
|
|
|
* Running into that case would be an application bug, since it means that
|
|
|
|
* the application is calling an extension function without checking the
|
|
|
|
* extension string -- calling glXGetClientString would have loaded the
|
|
|
|
* vendor libraries for every screen.
|
2013-11-26 00:21:41 +01:00
|
|
|
*
|
2015-05-27 17:11:19 +02:00
|
|
|
* In order to work with a buggy app like that, we might have to find and
|
|
|
|
* load all available vendor libraries until we find one that supports the
|
|
|
|
* function. Lacking that, a user could work around the issue by setting
|
|
|
|
* __GLX_VENDOR_LIBRARY_NAME.
|
2013-08-12 22:12:09 +02:00
|
|
|
*/
|
2015-05-27 17:11:19 +02:00
|
|
|
|
|
|
|
// Look through the vendors that we've already loaded, and see if any of
|
|
|
|
// them support the function.
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_RDLOCK(__glXVendorNameHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
HASH_ITER(hh, _LH(__glXVendorNameHash), pEntry, tmp) {
|
2016-02-17 23:27:12 +01:00
|
|
|
addr = __glXFindVendorDispatchAddress((const char *)procName, &pEntry->vendor);
|
2013-08-12 22:12:09 +02:00
|
|
|
if (addr) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_UNLOCK(__glXVendorNameHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
2015-05-27 17:11:19 +02:00
|
|
|
/*!
|
|
|
|
* Generates an entrypoint for a GLX function. The resulting function will
|
|
|
|
* jump to a dispatch function, which we can plug in when we load the vendor
|
|
|
|
* library later on.
|
|
|
|
*
|
|
|
|
* Note that this should still work even if the function turns out to be an
|
|
|
|
* OpenGL function, not GLX. In that case, we'll plug in the dispatch function
|
|
|
|
* from libGLdispatch instead.
|
|
|
|
*/
|
|
|
|
__GLXextFuncPtr __glXGenerateGLXEntrypoint(const GLubyte *procName)
|
|
|
|
{
|
|
|
|
__GLXextFuncPtr addr = NULL;
|
2015-07-14 01:16:16 +02:00
|
|
|
/*
|
|
|
|
* For GLX functions, try to generate an entrypoint. We'll plug in
|
|
|
|
* a dispatch function for it if and when we load a vendor library
|
|
|
|
* that supports it.
|
|
|
|
*/
|
|
|
|
if (procName[0] == 'g' && procName[1] == 'l' && procName[2] == 'X') {
|
2016-02-23 00:16:59 +01:00
|
|
|
__glvndPthreadFuncs.mutex_lock(&glxGenEntrypointMutex);
|
2015-07-14 01:16:16 +02:00
|
|
|
addr = (__GLXextFuncPtr) glvndGenerateEntrypoint((const char *) procName);
|
2016-02-23 00:16:59 +01:00
|
|
|
__glvndPthreadFuncs.mutex_unlock(&glxGenEntrypointMutex);
|
2015-07-14 01:16:16 +02:00
|
|
|
} else {
|
|
|
|
/* For GL functions, request a dispatch stub from libGLdispatch. */
|
|
|
|
addr = __glDispatchGetProcAddress((const char *)procName);
|
2015-05-27 17:11:19 +02:00
|
|
|
}
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
2015-04-19 18:30:21 +02:00
|
|
|
__GLXextFuncPtr __glXFetchDispatchEntry(__GLXvendorInfo *vendor,
|
2013-08-12 22:12:09 +02:00
|
|
|
int index)
|
|
|
|
{
|
|
|
|
__GLXextFuncPtr addr = NULL;
|
|
|
|
__GLXdispatchFuncHash *pEntry;
|
|
|
|
GLubyte *procName = NULL;
|
|
|
|
|
2016-02-17 23:48:55 +01:00
|
|
|
LKDHASH_RDLOCK(vendor->dynDispatchHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-02-17 23:48:55 +01:00
|
|
|
HASH_FIND_INT(_LH(vendor->dynDispatchHash), &index, pEntry);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
if (pEntry) {
|
|
|
|
// This can be NULL, which indicates the vendor does not implement this
|
|
|
|
// entry. Vendor library provided dispatch functions are expected to
|
|
|
|
// default to a no-op in case dispatching fails.
|
|
|
|
addr = pEntry->addr;
|
|
|
|
}
|
|
|
|
|
2016-02-17 23:48:55 +01:00
|
|
|
LKDHASH_UNLOCK(vendor->dynDispatchHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
if (!pEntry) {
|
|
|
|
// Not seen before by this vendor: query the vendor for the right
|
|
|
|
// address to use.
|
|
|
|
|
|
|
|
__GLXdispatchIndexHash *pdiEntry;
|
|
|
|
|
|
|
|
// First retrieve the procname of this index
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_RDLOCK(__glXDispatchIndexHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
HASH_FIND_INT(_LH(__glXDispatchIndexHash), &index, pdiEntry);
|
|
|
|
procName = pdiEntry->procName;
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_UNLOCK(__glXDispatchIndexHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
// This should have a valid entry point associated with it.
|
|
|
|
assert(procName);
|
|
|
|
|
|
|
|
if (procName) {
|
|
|
|
// Get the real address
|
2016-02-17 23:48:55 +01:00
|
|
|
addr = vendor->glxvc->getProcAddress(procName);
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
|
|
|
|
2016-02-17 23:48:55 +01:00
|
|
|
LKDHASH_WRLOCK(vendor->dynDispatchHash);
|
|
|
|
HASH_FIND_INT(_LH(vendor->dynDispatchHash), &index, pEntry);
|
2013-08-12 22:12:09 +02:00
|
|
|
if (!pEntry) {
|
|
|
|
pEntry = malloc(sizeof(*pEntry));
|
|
|
|
if (!pEntry) {
|
|
|
|
// Uh-oh!
|
|
|
|
assert(pEntry);
|
2016-02-17 23:48:55 +01:00
|
|
|
LKDHASH_UNLOCK(vendor->dynDispatchHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
pEntry->index = index;
|
|
|
|
pEntry->addr = addr;
|
|
|
|
|
2016-02-17 23:48:55 +01:00
|
|
|
HASH_ADD_INT(_LH(vendor->dynDispatchHash), index, pEntry);
|
2013-08-12 22:12:09 +02:00
|
|
|
} else {
|
|
|
|
addr = pEntry->addr;
|
|
|
|
}
|
2016-02-17 23:48:55 +01:00
|
|
|
LKDHASH_UNLOCK(vendor->dynDispatchHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
static char *ConstructVendorLibraryFilename(const char *vendorName)
|
|
|
|
{
|
|
|
|
char *filename;
|
|
|
|
int ret;
|
|
|
|
|
2015-03-27 18:38:58 +01:00
|
|
|
ret = glvnd_asprintf(&filename, "libGLX_%s.so.0", vendorName);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
if (ret < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return filename;
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
2016-02-17 23:27:12 +01:00
|
|
|
static void CleanupVendorNameEntry(void *unused,
|
|
|
|
__GLXvendorNameHash *pEntry)
|
2014-10-03 01:17:59 +02:00
|
|
|
{
|
2016-02-17 23:27:12 +01:00
|
|
|
__GLXvendorInfo *vendor = &pEntry->vendor;
|
|
|
|
if (vendor->glDispatch != NULL) {
|
2014-10-03 01:17:59 +02:00
|
|
|
__glDispatchDestroyTable(vendor->glDispatch);
|
2016-02-17 23:27:12 +01:00
|
|
|
vendor->glDispatch = NULL;
|
2014-10-03 01:17:59 +02:00
|
|
|
}
|
|
|
|
|
2016-02-17 23:48:55 +01:00
|
|
|
/* Clean up the dynamic dispatch table */
|
|
|
|
LKDHASH_TEARDOWN(__GLXdispatchFuncHash,
|
|
|
|
vendor->dynDispatchHash, NULL, NULL, True);
|
2014-10-03 01:17:59 +02:00
|
|
|
|
2016-02-17 23:27:12 +01:00
|
|
|
if (vendor->dlhandle != NULL) {
|
2014-10-03 01:17:59 +02:00
|
|
|
dlclose(vendor->dlhandle);
|
2016-02-17 23:27:12 +01:00
|
|
|
vendor->dlhandle = NULL;
|
2014-10-03 01:17:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-29 00:50:42 +02:00
|
|
|
static GLboolean LookupVendorEntrypoints(__GLXvendorInfo *vendor)
|
|
|
|
{
|
|
|
|
#define LOADENTRYPOINT(ptr, name) do { \
|
|
|
|
vendor->staticDispatch.ptr = vendor->glxvc->getProcAddress((const GLubyte *) name); \
|
|
|
|
if (vendor->staticDispatch.ptr == NULL) { return GL_FALSE; } \
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
LOADENTRYPOINT(chooseVisual, "glXChooseVisual" );
|
|
|
|
LOADENTRYPOINT(copyContext, "glXCopyContext" );
|
|
|
|
LOADENTRYPOINT(createContext, "glXCreateContext" );
|
|
|
|
LOADENTRYPOINT(createGLXPixmap, "glXCreateGLXPixmap" );
|
|
|
|
LOADENTRYPOINT(destroyContext, "glXDestroyContext" );
|
|
|
|
LOADENTRYPOINT(destroyGLXPixmap, "glXDestroyGLXPixmap" );
|
|
|
|
LOADENTRYPOINT(getConfig, "glXGetConfig" );
|
|
|
|
LOADENTRYPOINT(isDirect, "glXIsDirect" );
|
|
|
|
LOADENTRYPOINT(makeCurrent, "glXMakeCurrent" );
|
|
|
|
LOADENTRYPOINT(swapBuffers, "glXSwapBuffers" );
|
|
|
|
LOADENTRYPOINT(useXFont, "glXUseXFont" );
|
|
|
|
LOADENTRYPOINT(waitGL, "glXWaitGL" );
|
|
|
|
LOADENTRYPOINT(waitX, "glXWaitX" );
|
|
|
|
LOADENTRYPOINT(queryServerString, "glXQueryServerString" );
|
|
|
|
LOADENTRYPOINT(getClientString, "glXGetClientString" );
|
|
|
|
LOADENTRYPOINT(queryExtensionsString, "glXQueryExtensionsString");
|
|
|
|
LOADENTRYPOINT(chooseFBConfig, "glXChooseFBConfig" );
|
|
|
|
LOADENTRYPOINT(createNewContext, "glXCreateNewContext" );
|
|
|
|
LOADENTRYPOINT(createPbuffer, "glXCreatePbuffer" );
|
|
|
|
LOADENTRYPOINT(createPixmap, "glXCreatePixmap" );
|
|
|
|
LOADENTRYPOINT(createWindow, "glXCreateWindow" );
|
|
|
|
LOADENTRYPOINT(destroyPbuffer, "glXDestroyPbuffer" );
|
|
|
|
LOADENTRYPOINT(destroyPixmap, "glXDestroyPixmap" );
|
|
|
|
LOADENTRYPOINT(destroyWindow, "glXDestroyWindow" );
|
|
|
|
LOADENTRYPOINT(getFBConfigAttrib, "glXGetFBConfigAttrib" );
|
|
|
|
LOADENTRYPOINT(getFBConfigs, "glXGetFBConfigs" );
|
|
|
|
LOADENTRYPOINT(getSelectedEvent, "glXGetSelectedEvent" );
|
|
|
|
LOADENTRYPOINT(getVisualFromFBConfig, "glXGetVisualFromFBConfig");
|
|
|
|
LOADENTRYPOINT(makeContextCurrent, "glXMakeContextCurrent" );
|
|
|
|
LOADENTRYPOINT(queryContext, "glXQueryContext" );
|
|
|
|
LOADENTRYPOINT(queryDrawable, "glXQueryDrawable" );
|
|
|
|
LOADENTRYPOINT(selectEvent, "glXSelectEvent" );
|
|
|
|
#undef LOADENTRYPOINT
|
|
|
|
|
2015-10-15 00:57:17 +02:00
|
|
|
// These functions are optional.
|
|
|
|
#define LOADENTRYPOINT(ptr, name) do { \
|
|
|
|
vendor->staticDispatch.ptr = vendor->glxvc->getProcAddress((const GLubyte *) name); \
|
|
|
|
} while(0)
|
|
|
|
LOADENTRYPOINT(importContextEXT, "glXImportContextEXT" );
|
|
|
|
LOADENTRYPOINT(freeContextEXT, "glXFreeContextEXT" );
|
|
|
|
#undef LOADENTRYPOINT
|
|
|
|
|
2015-08-29 00:50:42 +02:00
|
|
|
return GL_TRUE;
|
|
|
|
}
|
|
|
|
|
2015-10-01 23:24:18 +02:00
|
|
|
static void *VendorGetProcAddressCallback(const char *procName, void *param)
|
|
|
|
{
|
|
|
|
__GLXvendorInfo *vendor = (__GLXvendorInfo *) param;
|
|
|
|
return vendor->glxvc->getProcAddress((const GLubyte *) procName);
|
|
|
|
}
|
|
|
|
|
2013-08-23 01:21:31 +02:00
|
|
|
__GLXvendorInfo *__glXLookupVendorByName(const char *vendorName)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2013-08-12 22:12:09 +02:00
|
|
|
__GLXvendorNameHash *pEntry = NULL;
|
|
|
|
Bool locked = False;
|
2016-02-17 23:27:12 +01:00
|
|
|
size_t vendorNameLen;
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2015-07-17 15:26:52 +02:00
|
|
|
// We'll use the vendor name to construct a DSO name, so make sure it
|
|
|
|
// doesn't contain any '/' characters.
|
|
|
|
if (strchr(vendorName, '/') != NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-02-17 23:27:12 +01:00
|
|
|
vendorNameLen = strlen(vendorName);
|
|
|
|
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_RDLOCK(__glXVendorNameHash);
|
2016-02-17 23:27:12 +01:00
|
|
|
HASH_FIND(hh, _LH(__glXVendorNameHash), vendorName, vendorNameLen, pEntry);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_UNLOCK(__glXVendorNameHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
if (!pEntry) {
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_WRLOCK(__glXVendorNameHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
locked = True;
|
|
|
|
// Do another lookup to check uniqueness
|
2016-02-17 23:27:12 +01:00
|
|
|
HASH_FIND(hh, _LH(__glXVendorNameHash), vendorName, vendorNameLen, pEntry);
|
2013-08-12 22:12:09 +02:00
|
|
|
if (!pEntry) {
|
2016-02-17 23:27:12 +01:00
|
|
|
__GLXvendorInfo *vendor;
|
|
|
|
__PFNGLXMAINPROC glxMainProc;
|
2014-10-03 01:17:05 +02:00
|
|
|
char *filename;
|
2016-03-03 21:50:24 +01:00
|
|
|
const __GLXapiImports *imports;
|
2014-10-03 01:17:05 +02:00
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
// Previously unseen vendor. dlopen() the new vendor and add it to the
|
|
|
|
// hash table.
|
2016-02-17 23:27:12 +01:00
|
|
|
pEntry = calloc(1, sizeof(*pEntry) + vendorNameLen + 1);
|
2013-08-12 22:12:09 +02:00
|
|
|
if (!pEntry) {
|
|
|
|
goto fail;
|
|
|
|
}
|
2016-02-17 23:27:12 +01:00
|
|
|
vendor = &pEntry->vendor;
|
|
|
|
|
|
|
|
vendor->name = (char *) (pEntry + 1);
|
|
|
|
memcpy(vendor->name, vendorName, vendorNameLen + 1);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
filename = ConstructVendorLibraryFilename(vendorName);
|
2014-10-03 01:17:05 +02:00
|
|
|
if (filename) {
|
2016-02-17 23:27:12 +01:00
|
|
|
vendor->dlhandle = dlopen(filename, RTLD_LAZY);
|
2014-10-03 01:17:05 +02:00
|
|
|
}
|
2013-08-12 22:12:09 +02:00
|
|
|
free(filename);
|
2016-02-17 23:27:12 +01:00
|
|
|
if (vendor->dlhandle == NULL) {
|
2013-08-12 22:12:09 +02:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2016-02-17 23:27:12 +01:00
|
|
|
glxMainProc = dlsym(vendor->dlhandle, __GLX_MAIN_PROTO_NAME);
|
2013-08-12 22:12:09 +02:00
|
|
|
if (!glxMainProc) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2016-02-17 23:27:12 +01:00
|
|
|
vendor->vendorID = __glDispatchNewVendorID();
|
|
|
|
assert(vendor->vendorID >= 0);
|
2014-01-24 04:51:49 +01:00
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
vendor->glDispatch = (__GLdispatchTable *)
|
2013-11-26 00:21:41 +01:00
|
|
|
__glDispatchCreateTable(
|
2015-10-01 23:24:18 +02:00
|
|
|
VendorGetProcAddressCallback,
|
|
|
|
vendor
|
2013-11-26 00:21:41 +01:00
|
|
|
);
|
2013-08-12 22:12:09 +02:00
|
|
|
if (!vendor->glDispatch) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2016-03-03 21:50:24 +01:00
|
|
|
// Plug in the vendor imports table.
|
|
|
|
pEntry->imports.patchCallbacks = &pEntry->patchCallbacks;
|
|
|
|
vendor->glxvc = &pEntry->imports;
|
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
/* Initialize the dynamic dispatch table */
|
2016-02-17 23:48:55 +01:00
|
|
|
LKDHASH_INIT(vendor->dynDispatchHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-03-03 21:50:24 +01:00
|
|
|
imports = (*glxMainProc)(GLX_VENDOR_ABI_VERSION,
|
2016-03-03 19:11:11 +01:00
|
|
|
&glxExportsTable,
|
|
|
|
vendor);
|
2016-03-03 21:50:24 +01:00
|
|
|
if (!imports) {
|
2016-03-03 19:11:11 +01:00
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2016-03-03 21:50:24 +01:00
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2016-03-03 19:11:11 +01:00
|
|
|
if (!LookupVendorEntrypoints(vendor)) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2014-01-24 05:10:55 +01:00
|
|
|
HASH_ADD_KEYPTR(hh, _LH(__glXVendorNameHash), vendor->name,
|
|
|
|
strlen(vendor->name), pEntry);
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_UNLOCK(__glXVendorNameHash);
|
2015-05-27 17:11:19 +02:00
|
|
|
|
|
|
|
// Look up the dispatch functions for any GLX extensions that we
|
|
|
|
// generated entrypoints for.
|
2016-02-23 00:16:59 +01:00
|
|
|
__glvndPthreadFuncs.mutex_lock(&glxGenEntrypointMutex);
|
2015-05-27 17:11:19 +02:00
|
|
|
glvndUpdateEntrypoints(
|
|
|
|
(GLVNDentrypointUpdateCallback) __glXFindVendorDispatchAddress,
|
|
|
|
vendor);
|
2016-02-23 00:16:59 +01:00
|
|
|
__glvndPthreadFuncs.mutex_unlock(&glxGenEntrypointMutex);
|
2013-08-12 22:12:09 +02:00
|
|
|
} else {
|
|
|
|
/* Some other thread added a vendor */
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_UNLOCK(__glXVendorNameHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-17 23:27:12 +01:00
|
|
|
return &pEntry->vendor;
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
fail:
|
|
|
|
if (locked) {
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_UNLOCK(__glXVendorNameHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
2016-02-17 23:27:12 +01:00
|
|
|
if (pEntry != NULL) {
|
|
|
|
CleanupVendorNameEntry(NULL, pEntry);
|
|
|
|
free(pEntry);
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
2013-08-23 01:21:31 +02:00
|
|
|
return NULL;
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
2013-08-23 01:21:31 +02:00
|
|
|
__GLXvendorInfo *__glXLookupVendorByScreen(Display *dpy, const int screen)
|
|
|
|
{
|
2013-08-12 22:12:09 +02:00
|
|
|
__GLXvendorInfo *vendor = NULL;
|
2015-04-24 01:00:52 +02:00
|
|
|
__GLXdisplayInfo *dpyInfo;
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2015-05-05 18:04:45 +02:00
|
|
|
if (screen < 0 || screen >= ScreenCount(dpy)) {
|
2013-08-12 22:12:09 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-04-24 01:00:52 +02:00
|
|
|
dpyInfo = __glXLookupDisplay(dpy);
|
|
|
|
if (dpyInfo == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-02-23 00:16:59 +01:00
|
|
|
__glvndPthreadFuncs.rwlock_rdlock(&dpyInfo->vendorLock);
|
2015-05-05 18:04:45 +02:00
|
|
|
vendor = dpyInfo->vendors[screen];
|
2016-02-23 00:16:59 +01:00
|
|
|
__glvndPthreadFuncs.rwlock_unlock(&dpyInfo->vendorLock);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2015-05-05 18:04:45 +02:00
|
|
|
if (vendor != NULL) {
|
|
|
|
return vendor;
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
|
|
|
|
2016-02-23 00:16:59 +01:00
|
|
|
__glvndPthreadFuncs.rwlock_wrlock(&dpyInfo->vendorLock);
|
2015-05-05 18:04:45 +02:00
|
|
|
vendor = dpyInfo->vendors[screen];
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2015-05-05 18:04:45 +02:00
|
|
|
if (!vendor) {
|
2013-08-12 22:12:09 +02:00
|
|
|
/*
|
|
|
|
* If we have specified a vendor library, use that. Otherwise,
|
|
|
|
* try to lookup the vendor based on the current screen.
|
|
|
|
*/
|
|
|
|
const char *preloadedVendorName = getenv("__GLX_VENDOR_LIBRARY_NAME");
|
|
|
|
|
|
|
|
if (preloadedVendorName) {
|
|
|
|
vendor = __glXLookupVendorByName(preloadedVendorName);
|
|
|
|
}
|
|
|
|
|
2015-04-24 01:00:52 +02:00
|
|
|
if (!vendor) {
|
|
|
|
if (dpyInfo->x11glvndSupported) {
|
|
|
|
char *queriedVendorName = XGLVQueryScreenVendorMapping(dpy, screen);
|
|
|
|
vendor = __glXLookupVendorByName(queriedVendorName);
|
|
|
|
Xfree(queriedVendorName);
|
2015-07-29 18:58:49 +02:00
|
|
|
|
|
|
|
// Make sure that the vendor library can support this screen.
|
|
|
|
// If it can't, then we'll fall back to the indirect rendering
|
|
|
|
// library.
|
2016-02-29 19:11:26 +01:00
|
|
|
if (vendor != NULL && !vendor->glxvc->isScreenSupported(dpy, screen)) {
|
2015-07-29 18:58:49 +02:00
|
|
|
vendor = NULL;
|
|
|
|
}
|
2015-04-24 01:00:52 +02:00
|
|
|
}
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
|
|
|
|
2015-04-24 00:46:52 +02:00
|
|
|
if (!vendor) {
|
|
|
|
vendor = __glXLookupVendorByName(FALLBACK_VENDOR_NAME);
|
|
|
|
}
|
|
|
|
|
2015-05-05 18:04:45 +02:00
|
|
|
dpyInfo->vendors[screen] = vendor;
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
2016-02-23 00:16:59 +01:00
|
|
|
__glvndPthreadFuncs.rwlock_unlock(&dpyInfo->vendorLock);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
DBG_PRINTF(10, "Found vendor \"%s\" for screen %d\n",
|
2015-05-05 18:04:45 +02:00
|
|
|
(vendor != NULL ? vendor->name : "NULL"), screen);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
return vendor;
|
2013-08-23 01:21:31 +02:00
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
|
2013-08-23 01:21:31 +02:00
|
|
|
const __GLXdispatchTableStatic *__glXGetStaticDispatch(Display *dpy, const int screen)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2013-08-23 01:21:31 +02:00
|
|
|
__GLXvendorInfo *vendor = __glXLookupVendorByScreen(dpy, screen);
|
2013-08-23 01:06:53 +02:00
|
|
|
|
2013-08-23 01:21:31 +02:00
|
|
|
if (vendor) {
|
2015-08-29 00:50:42 +02:00
|
|
|
return &vendor->staticDispatch;
|
2013-08-23 01:21:31 +02:00
|
|
|
} else {
|
2013-08-23 01:06:53 +02:00
|
|
|
return __glXDispatchNoopPtr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
__GLdispatchTable *__glXGetGLDispatch(Display *dpy, const int screen)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2013-08-23 01:21:31 +02:00
|
|
|
__GLXvendorInfo *vendor = __glXLookupVendorByScreen(dpy, screen);
|
2013-08-23 01:06:53 +02:00
|
|
|
|
2013-08-23 01:21:31 +02:00
|
|
|
if (vendor) {
|
|
|
|
assert(vendor->glDispatch);
|
|
|
|
return vendor->glDispatch;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
2013-08-23 01:21:31 +02:00
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
|
2015-04-19 18:30:21 +02:00
|
|
|
__GLXvendorInfo *__glXGetDynDispatch(Display *dpy, const int screen)
|
2013-08-23 01:21:31 +02:00
|
|
|
{
|
2014-10-03 01:17:59 +02:00
|
|
|
__glXThreadInitialize();
|
|
|
|
|
2013-08-23 01:21:31 +02:00
|
|
|
__GLXvendorInfo *vendor = __glXLookupVendorByScreen(dpy, screen);
|
2015-04-19 18:30:21 +02:00
|
|
|
return vendor;
|
2013-08-23 01:21:31 +02:00
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
|
2015-04-23 19:33:52 +02:00
|
|
|
/**
|
|
|
|
* Allocates and initializes a __GLXdisplayInfoHash structure.
|
|
|
|
*
|
|
|
|
* The caller is responsible for adding the structure to the hashtable.
|
|
|
|
*
|
|
|
|
* \param dpy The display connection.
|
|
|
|
* \return A newly-allocated __GLXdisplayInfoHash structure, or NULL on error.
|
|
|
|
*/
|
|
|
|
static __GLXdisplayInfoHash *InitDisplayInfoEntry(Display *dpy)
|
|
|
|
{
|
2015-04-24 01:00:52 +02:00
|
|
|
__GLXdisplayInfoHash *pEntry;
|
2015-05-05 18:04:45 +02:00
|
|
|
size_t size;
|
2015-04-24 01:00:52 +02:00
|
|
|
int eventBase, errorBase;
|
|
|
|
|
2015-05-05 18:04:45 +02:00
|
|
|
size = sizeof(*pEntry) + ScreenCount(dpy) * sizeof(__GLXvendorInfo *);
|
|
|
|
pEntry = (__GLXdisplayInfoHash *) malloc(size);
|
2015-04-23 19:33:52 +02:00
|
|
|
if (pEntry == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-05-05 18:04:45 +02:00
|
|
|
memset(pEntry, 0, size);
|
2015-04-23 19:33:52 +02:00
|
|
|
pEntry->dpy = dpy;
|
2015-05-05 18:04:45 +02:00
|
|
|
pEntry->info.vendors = (__GLXvendorInfo **) (pEntry + 1);
|
2015-04-24 01:00:52 +02:00
|
|
|
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_INIT(pEntry->info.xidVendorHash);
|
2016-02-23 00:16:59 +01:00
|
|
|
__glvndPthreadFuncs.rwlock_init(&pEntry->info.vendorLock, NULL);
|
2015-04-24 01:00:52 +02:00
|
|
|
|
2015-09-28 23:55:57 +02:00
|
|
|
// Check whether the server supports the GLX extension, and record the
|
|
|
|
// major opcode if it does.
|
|
|
|
pEntry->info.glxSupported = XQueryExtension(dpy, GLX_EXTENSION_NAME,
|
|
|
|
&pEntry->info.glxMajorOpcode, &eventBase,
|
|
|
|
&pEntry->info.glxFirstError);
|
|
|
|
|
|
|
|
// Check whether the server supports the x11glvnd extension.
|
2015-04-24 01:00:52 +02:00
|
|
|
if (XGLVQueryExtension(dpy, &eventBase, &errorBase)) {
|
2015-09-28 23:55:57 +02:00
|
|
|
pEntry->info.x11glvndSupported = True;
|
2015-04-24 01:00:52 +02:00
|
|
|
XGLVQueryVersion(dpy, &pEntry->info.x11glvndMajor,
|
|
|
|
&pEntry->info.x11glvndMinor);
|
|
|
|
}
|
|
|
|
|
2015-04-23 19:33:52 +02:00
|
|
|
return pEntry;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Frees a __GLXdisplayInfoHash structure.
|
|
|
|
*
|
|
|
|
* The caller is responsible for removing the structure from the hashtable.
|
|
|
|
*
|
|
|
|
* \param unused Ingored. Needed for the uthash teardown function.
|
|
|
|
* \param pEntry The structure to free.
|
|
|
|
*/
|
|
|
|
static void CleanupDisplayInfoEntry(void *unused, __GLXdisplayInfoHash *pEntry)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (pEntry == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i=0; i<GLX_CLIENT_STRING_LAST_ATTRIB; i++) {
|
2015-04-30 01:18:01 +02:00
|
|
|
free(pEntry->info.clientStrings[i]);
|
2015-04-23 19:33:52 +02:00
|
|
|
}
|
2015-04-23 20:30:34 +02:00
|
|
|
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_TEARDOWN(__GLXvendorXIDMappingHash,
|
2016-01-04 23:12:23 +01:00
|
|
|
pEntry->info.xidVendorHash, NULL, NULL, False);
|
2015-04-23 19:33:52 +02:00
|
|
|
}
|
|
|
|
|
2015-04-14 19:58:43 +02:00
|
|
|
__GLXdisplayInfo *__glXLookupDisplay(Display *dpy)
|
|
|
|
{
|
|
|
|
__GLXdisplayInfoHash *pEntry = NULL;
|
2015-12-09 23:56:36 +01:00
|
|
|
__GLXdisplayInfoHash *foundEntry = NULL;
|
2015-04-14 19:58:43 +02:00
|
|
|
|
2015-04-19 18:30:21 +02:00
|
|
|
if (dpy == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_RDLOCK(__glXDisplayInfoHash);
|
2015-04-14 19:58:43 +02:00
|
|
|
HASH_FIND_PTR(_LH(__glXDisplayInfoHash), &dpy, pEntry);
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_UNLOCK(__glXDisplayInfoHash);
|
2015-04-14 19:58:43 +02:00
|
|
|
|
|
|
|
if (pEntry != NULL) {
|
|
|
|
return &pEntry->info;
|
|
|
|
}
|
|
|
|
|
2015-12-09 23:56:36 +01:00
|
|
|
// Create the new __GLXdisplayInfoHash structure without holding the lock.
|
|
|
|
// If we run into an X error, we may wind up in __glXMappingTeardown before
|
|
|
|
// we can unlock it again, which would deadlock.
|
|
|
|
pEntry = InitDisplayInfoEntry(dpy);
|
2015-04-14 19:58:43 +02:00
|
|
|
if (pEntry == NULL) {
|
2015-12-09 23:56:36 +01:00
|
|
|
return NULL;
|
2015-04-14 19:58:43 +02:00
|
|
|
}
|
|
|
|
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_WRLOCK(__glXDisplayInfoHash);
|
2015-12-09 23:56:36 +01:00
|
|
|
HASH_FIND_PTR(_LH(__glXDisplayInfoHash), &dpy, foundEntry);
|
|
|
|
if (foundEntry == NULL) {
|
|
|
|
HASH_ADD_PTR(_LH(__glXDisplayInfoHash), dpy, pEntry);
|
2015-04-14 19:58:43 +02:00
|
|
|
} else {
|
2015-12-09 23:56:36 +01:00
|
|
|
// Another thread already created the hashtable entry.
|
|
|
|
free(pEntry);
|
|
|
|
pEntry = foundEntry;
|
2015-04-14 19:58:43 +02:00
|
|
|
}
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_UNLOCK(__glXDisplayInfoHash);
|
2015-12-09 23:56:36 +01:00
|
|
|
|
|
|
|
return &pEntry->info;
|
2015-04-14 19:58:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void __glXFreeDisplay(Display *dpy)
|
|
|
|
{
|
|
|
|
__GLXdisplayInfoHash *pEntry = NULL;
|
|
|
|
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_WRLOCK(__glXDisplayInfoHash);
|
2015-04-14 19:58:43 +02:00
|
|
|
HASH_FIND_PTR(_LH(__glXDisplayInfoHash), &dpy, pEntry);
|
|
|
|
if (pEntry != NULL) {
|
|
|
|
HASH_DEL(_LH(__glXDisplayInfoHash), pEntry);
|
|
|
|
}
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_UNLOCK(__glXDisplayInfoHash);
|
2015-04-14 19:58:43 +02:00
|
|
|
|
|
|
|
if (pEntry != NULL) {
|
2015-04-23 19:33:52 +02:00
|
|
|
CleanupDisplayInfoEntry(NULL, pEntry);
|
2015-04-14 19:58:43 +02:00
|
|
|
free(pEntry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
/****************************************************************************/
|
|
|
|
/*
|
2016-01-04 22:44:22 +01:00
|
|
|
* Define two hashtables to store the mappings for GLXFBConfig and GLXContext
|
|
|
|
* handles to vendor libraries.
|
|
|
|
*
|
|
|
|
* The same functions are used to access both tables.
|
2013-08-12 22:12:09 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
typedef struct {
|
2016-02-10 00:50:37 +01:00
|
|
|
GLXFBConfig config;
|
2016-01-04 20:52:14 +01:00
|
|
|
__GLXvendorInfo *vendor;
|
2013-08-12 22:12:09 +02:00
|
|
|
UT_hash_handle hh;
|
2016-02-10 00:50:37 +01:00
|
|
|
} __GLXvendorConfigMappingHash;
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
static DEFINE_LKDHASH(__GLXvendorConfigMappingHash, fbconfigHashtable);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-02-26 22:05:38 +01:00
|
|
|
int __glXAddVendorFBConfigMapping(Display *dpy, GLXFBConfig config, __GLXvendorInfo *vendor)
|
2013-08-23 01:21:31 +02:00
|
|
|
{
|
2016-02-10 00:50:37 +01:00
|
|
|
__GLXvendorConfigMappingHash *pEntry;
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
if (config == NULL) {
|
2016-02-26 22:05:38 +01:00
|
|
|
return 0;
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
|
|
|
|
2016-01-04 20:52:14 +01:00
|
|
|
if (vendor == NULL) {
|
2016-02-26 22:05:38 +01:00
|
|
|
return -1;
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
LKDHASH_WRLOCK(fbconfigHashtable);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
HASH_FIND_PTR(_LH(fbconfigHashtable), &config, pEntry);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
if (pEntry == NULL) {
|
|
|
|
pEntry = malloc(sizeof(*pEntry));
|
2016-02-26 22:05:38 +01:00
|
|
|
if (pEntry == NULL) {
|
|
|
|
LKDHASH_UNLOCK(fbconfigHashtable);
|
|
|
|
return -1;
|
|
|
|
}
|
2016-02-10 00:50:37 +01:00
|
|
|
pEntry->config = config;
|
2016-01-04 20:52:14 +01:00
|
|
|
pEntry->vendor = vendor;
|
2016-02-10 00:50:37 +01:00
|
|
|
HASH_ADD_PTR(_LH(fbconfigHashtable), config, pEntry);
|
2013-08-12 22:12:09 +02:00
|
|
|
} else {
|
2016-01-06 18:23:32 +01:00
|
|
|
// 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.
|
2016-02-26 22:05:38 +01:00
|
|
|
if (pEntry->vendor != vendor) {
|
|
|
|
LKDHASH_UNLOCK(fbconfigHashtable);
|
|
|
|
return -1;
|
|
|
|
}
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
LKDHASH_UNLOCK(fbconfigHashtable);
|
2016-02-26 22:05:38 +01:00
|
|
|
return 0;
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
void __glXRemoveVendorFBConfigMapping(Display *dpy, GLXFBConfig config)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2016-02-10 00:50:37 +01:00
|
|
|
__GLXvendorConfigMappingHash *pEntry;
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
if (config == NULL) {
|
2013-08-12 22:12:09 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
LKDHASH_WRLOCK(fbconfigHashtable);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
HASH_FIND_PTR(_LH(fbconfigHashtable), &config, pEntry);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
if (pEntry != NULL) {
|
2016-02-10 00:50:37 +01:00
|
|
|
HASH_DELETE(hh, _LH(fbconfigHashtable), pEntry);
|
2013-08-12 22:12:09 +02:00
|
|
|
free(pEntry);
|
|
|
|
}
|
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
LKDHASH_UNLOCK(fbconfigHashtable);
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
2016-02-26 22:41:30 +01:00
|
|
|
__GLXvendorInfo *__glXVendorFromFBConfig(Display *dpy, GLXFBConfig config)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2016-02-10 00:50:37 +01:00
|
|
|
__GLXvendorConfigMappingHash *pEntry;
|
2016-01-04 20:52:14 +01:00
|
|
|
__GLXvendorInfo *vendor = NULL;
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-01-21 23:08:26 +01:00
|
|
|
__glXThreadInitialize();
|
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
LKDHASH_RDLOCK(fbconfigHashtable);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
HASH_FIND_PTR(_LH(fbconfigHashtable), &config, pEntry);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
if (pEntry != NULL) {
|
2016-01-04 20:52:14 +01:00
|
|
|
vendor = pEntry->vendor;
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
LKDHASH_UNLOCK(fbconfigHashtable);
|
2013-08-23 01:06:53 +02:00
|
|
|
|
2016-02-26 22:41:30 +01:00
|
|
|
return vendor;
|
2015-04-19 18:30:21 +02:00
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************/
|
2013-08-12 22:12:09 +02:00
|
|
|
/*
|
2016-01-04 23:12:23 +01:00
|
|
|
* __GLXvendorXIDMappingHash is a hash table which maps XIDs to vendors.
|
2013-08-12 22:12:09 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
2016-02-26 22:05:38 +01:00
|
|
|
static int AddVendorXIDMapping(Display *dpy, __GLXdisplayInfo *dpyInfo, XID xid, __GLXvendorInfo *vendor)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2016-01-04 23:12:23 +01:00
|
|
|
__GLXvendorXIDMappingHash *pEntry = NULL;
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
if (xid == None) {
|
2016-02-26 22:05:38 +01:00
|
|
|
return 0;
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
|
|
|
|
2016-01-04 20:11:47 +01:00
|
|
|
if (vendor == NULL) {
|
2016-02-26 22:05:38 +01:00
|
|
|
return -1;
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
|
|
|
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_WRLOCK(dpyInfo->xidVendorHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-01-04 23:12:23 +01:00
|
|
|
HASH_FIND(hh, _LH(dpyInfo->xidVendorHash), &xid, sizeof(xid), pEntry);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
if (pEntry == NULL) {
|
|
|
|
pEntry = malloc(sizeof(*pEntry));
|
2016-02-26 22:05:38 +01:00
|
|
|
if (pEntry == NULL) {
|
|
|
|
LKDHASH_UNLOCK(dpyInfo->xidVendorHash);
|
|
|
|
return -1;
|
|
|
|
}
|
2013-08-12 22:12:09 +02:00
|
|
|
pEntry->xid = xid;
|
2016-01-04 20:11:47 +01:00
|
|
|
pEntry->vendor = vendor;
|
2016-01-04 23:12:23 +01:00
|
|
|
HASH_ADD(hh, _LH(dpyInfo->xidVendorHash), xid, sizeof(xid), pEntry);
|
2013-08-12 22:12:09 +02:00
|
|
|
} else {
|
2016-01-06 18:23:32 +01:00
|
|
|
// Like GLXContext and GLXFBConfig handles, any GLXDrawables must map
|
|
|
|
// to a single vendor library.
|
2016-02-26 22:05:38 +01:00
|
|
|
if (pEntry->vendor != vendor) {
|
|
|
|
LKDHASH_UNLOCK(dpyInfo->xidVendorHash);
|
|
|
|
return -1;
|
|
|
|
}
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
|
|
|
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_UNLOCK(dpyInfo->xidVendorHash);
|
2016-02-26 22:05:38 +01:00
|
|
|
return 0;
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-01-04 23:12:23 +01:00
|
|
|
static void RemoveVendorXIDMapping(Display *dpy, __GLXdisplayInfo *dpyInfo, XID xid)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2016-01-04 23:12:23 +01:00
|
|
|
__GLXvendorXIDMappingHash *pEntry;
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
if (xid == None) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_WRLOCK(dpyInfo->xidVendorHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-01-04 23:12:23 +01:00
|
|
|
HASH_FIND(hh, _LH(dpyInfo->xidVendorHash), &xid, sizeof(xid), pEntry);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
if (pEntry != NULL) {
|
2016-01-04 23:12:23 +01:00
|
|
|
HASH_DELETE(hh, _LH(dpyInfo->xidVendorHash), pEntry);
|
2013-08-12 22:12:09 +02:00
|
|
|
free(pEntry);
|
|
|
|
}
|
|
|
|
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_UNLOCK(dpyInfo->xidVendorHash);
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-01-04 23:12:23 +01:00
|
|
|
static void VendorFromXID(Display *dpy, __GLXdisplayInfo *dpyInfo, XID xid,
|
2016-01-04 20:23:29 +01:00
|
|
|
__GLXvendorInfo **retVendor)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2016-01-04 23:12:23 +01:00
|
|
|
__GLXvendorXIDMappingHash *pEntry;
|
2016-01-04 20:11:47 +01:00
|
|
|
__GLXvendorInfo *vendor = NULL;
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_RDLOCK(dpyInfo->xidVendorHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2016-01-04 23:12:23 +01:00
|
|
|
HASH_FIND(hh, _LH(dpyInfo->xidVendorHash), &xid, sizeof(xid), pEntry);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
if (pEntry) {
|
2016-01-04 20:11:47 +01:00
|
|
|
vendor = pEntry->vendor;
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_UNLOCK(dpyInfo->xidVendorHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
} else {
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_UNLOCK(dpyInfo->xidVendorHash);
|
2015-04-24 01:00:52 +02:00
|
|
|
|
|
|
|
if (dpyInfo->x11glvndSupported) {
|
2016-01-04 20:23:29 +01:00
|
|
|
int screen = XGLVQueryXIDScreenMapping(dpy, xid);
|
2016-01-04 20:11:47 +01:00
|
|
|
if (screen >= 0 && screen < ScreenCount(dpy)) {
|
|
|
|
vendor = __glXLookupVendorByScreen(dpy, screen);
|
|
|
|
if (vendor != NULL) {
|
2016-02-26 22:05:38 +01:00
|
|
|
// Note that if this fails, it's not necessarily a problem.
|
|
|
|
// We can just query it again next time.
|
2016-01-04 23:12:23 +01:00
|
|
|
AddVendorXIDMapping(dpy, dpyInfo, xid, vendor);
|
2016-01-04 20:11:47 +01:00
|
|
|
}
|
|
|
|
}
|
2015-04-24 01:00:52 +02:00
|
|
|
}
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
|
|
|
|
2016-01-04 20:11:47 +01:00
|
|
|
if (retVendor != NULL) {
|
|
|
|
*retVendor = vendor;
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-26 22:05:38 +01:00
|
|
|
int __glXAddVendorDrawableMapping(Display *dpy, GLXDrawable drawable, __GLXvendorInfo *vendor)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2015-04-23 20:30:34 +02:00
|
|
|
__GLXdisplayInfo *dpyInfo = __glXLookupDisplay(dpy);
|
|
|
|
if (dpyInfo != NULL) {
|
2016-02-26 22:05:38 +01:00
|
|
|
return AddVendorXIDMapping(dpy, dpyInfo, drawable, vendor);
|
|
|
|
} else {
|
|
|
|
return -1;
|
2015-04-23 20:30:34 +02:00
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-01-04 20:37:08 +01:00
|
|
|
void __glXRemoveVendorDrawableMapping(Display *dpy, GLXDrawable drawable)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2015-04-23 20:30:34 +02:00
|
|
|
__GLXdisplayInfo *dpyInfo = __glXLookupDisplay(dpy);
|
|
|
|
if (dpyInfo != NULL) {
|
2016-01-04 23:12:23 +01:00
|
|
|
RemoveVendorXIDMapping(dpy, dpyInfo, drawable);
|
2015-04-23 20:30:34 +02:00
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-02-26 22:41:30 +01:00
|
|
|
__GLXvendorInfo *__glXVendorFromDrawable(Display *dpy, GLXDrawable drawable)
|
2015-04-19 18:30:21 +02:00
|
|
|
{
|
2016-01-21 23:08:26 +01:00
|
|
|
__glXThreadInitialize();
|
|
|
|
|
2015-04-23 20:30:34 +02:00
|
|
|
__GLXdisplayInfo *dpyInfo = __glXLookupDisplay(dpy);
|
2015-04-24 01:00:52 +02:00
|
|
|
__GLXvendorInfo *vendor = NULL;
|
2015-04-23 20:30:34 +02:00
|
|
|
if (dpyInfo != NULL) {
|
2015-04-24 01:00:52 +02:00
|
|
|
if (dpyInfo->x11glvndSupported) {
|
2016-01-04 23:12:23 +01:00
|
|
|
VendorFromXID(dpy, dpyInfo, drawable, &vendor);
|
2015-04-24 01:00:52 +02:00
|
|
|
} else {
|
|
|
|
// We'll use the same vendor for every screen in this case.
|
|
|
|
vendor = __glXLookupVendorByScreen(dpy, 0);
|
|
|
|
}
|
2015-04-23 20:30:34 +02:00
|
|
|
}
|
2015-04-24 01:00:52 +02:00
|
|
|
|
2016-02-26 22:41:30 +01:00
|
|
|
return vendor;
|
2015-04-19 18:30:21 +02:00
|
|
|
}
|
|
|
|
|
2014-10-03 01:17:59 +02:00
|
|
|
/*!
|
|
|
|
* This handles freeing all mapping state during library teardown
|
2014-10-29 22:20:13 +01:00
|
|
|
* or resetting locks on fork recovery.
|
2014-10-03 01:17:59 +02:00
|
|
|
*/
|
|
|
|
void __glXMappingTeardown(Bool doReset)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (doReset) {
|
2015-04-23 20:30:34 +02:00
|
|
|
__GLXdisplayInfoHash *dpyInfoEntry, *dpyInfoTmp;
|
|
|
|
|
2014-10-03 01:17:59 +02:00
|
|
|
/*
|
|
|
|
* If we're just doing fork recovery, we don't actually want to unload
|
2014-10-29 22:20:13 +01:00
|
|
|
* any currently loaded vendors _or_ remove any mappings (they should
|
|
|
|
* still be valid in the new process, and may be needed if the child
|
|
|
|
* tries using pointers/XIDs that were created in the parent). Just
|
|
|
|
* reset the corresponding locks.
|
2014-10-03 01:17:59 +02:00
|
|
|
*/
|
2016-02-23 00:16:59 +01:00
|
|
|
__glvndPthreadFuncs.rwlock_init(&__glXDispatchIndexHash.lock, NULL);
|
|
|
|
__glvndPthreadFuncs.rwlock_init(&fbconfigHashtable.lock, NULL);
|
|
|
|
__glvndPthreadFuncs.rwlock_init(&__glXVendorNameHash.lock, NULL);
|
|
|
|
__glvndPthreadFuncs.rwlock_init(&__glXDisplayInfoHash.lock, NULL);
|
2015-04-23 20:30:34 +02:00
|
|
|
|
|
|
|
HASH_ITER(hh, _LH(__glXDisplayInfoHash), dpyInfoEntry, dpyInfoTmp) {
|
2016-02-23 00:16:59 +01:00
|
|
|
__glvndPthreadFuncs.rwlock_init(&dpyInfoEntry->info.xidVendorHash.lock, NULL);
|
|
|
|
__glvndPthreadFuncs.rwlock_init(&dpyInfoEntry->info.vendorLock, NULL);
|
2015-04-23 20:30:34 +02:00
|
|
|
}
|
2014-10-03 01:17:59 +02:00
|
|
|
} else {
|
2014-10-29 22:20:13 +01:00
|
|
|
/* Tear down all hashtables used in this file */
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_TEARDOWN(__GLXdispatchIndexHash,
|
2014-10-29 22:20:13 +01:00
|
|
|
__glXDispatchIndexHash, CleanupDispatchIndexEntry,
|
|
|
|
NULL, False);
|
|
|
|
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_WRLOCK(__glXDispatchIndexHash);
|
2014-10-29 22:20:13 +01:00
|
|
|
__glXNextUnusedHashIndex = 0;
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_UNLOCK(__glXDispatchIndexHash);
|
2014-10-29 22:20:13 +01:00
|
|
|
|
2016-02-10 00:50:37 +01:00
|
|
|
LKDHASH_TEARDOWN(__GLXvendorConfigMappingHash,
|
2016-01-04 22:44:22 +01:00
|
|
|
fbconfigHashtable, NULL, NULL, False);
|
2014-10-29 22:20:13 +01:00
|
|
|
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_TEARDOWN(__GLXdisplayInfoHash,
|
2015-04-23 19:33:52 +02:00
|
|
|
__glXDisplayInfoHash, CleanupDisplayInfoEntry,
|
|
|
|
NULL, False);
|
2014-10-03 01:17:59 +02:00
|
|
|
/*
|
|
|
|
* This implicitly unloads vendor libraries that were loaded when
|
|
|
|
* they were added to this hashtable.
|
|
|
|
*/
|
2016-02-23 01:26:54 +01:00
|
|
|
LKDHASH_TEARDOWN(__GLXvendorNameHash,
|
2014-10-03 01:17:59 +02:00
|
|
|
__glXVendorNameHash, CleanupVendorNameEntry,
|
|
|
|
NULL, False);
|
2015-05-27 17:11:19 +02:00
|
|
|
|
|
|
|
/* Free any generated entrypoints */
|
|
|
|
glvndFreeEntrypoints();
|
2014-10-03 01:17:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|