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>
|
|
|
|
|
|
|
|
#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"
|
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
|
|
|
|
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-11-26 00:21:41 +01:00
|
|
|
struct __GLXdispatchTableDynamicRec {
|
2013-08-12 22:12:09 +02:00
|
|
|
/*
|
|
|
|
* Hash table containing the dynamic dispatch funcs. This is used instead of
|
|
|
|
* a flat array to avoid sparse array usage. XXX might be more performant to
|
|
|
|
* use an array, though?
|
|
|
|
*/
|
|
|
|
DEFINE_LKDHASH(__GLXdispatchFuncHash, hash);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Pointer to the vendor library info, used by __glXFetchDispatchEntry()
|
|
|
|
*/
|
|
|
|
__GLXvendorInfo *vendor;
|
2013-11-26 00:21:41 +01:00
|
|
|
};
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
/****************************************************************************/
|
2013-08-12 22:12:09 +02:00
|
|
|
/*
|
|
|
|
* __glXVendorScreenHash is a hash table which maps a Display+screen to a vendor.
|
|
|
|
* Look up this mapping from the X server once, the first time a unique
|
|
|
|
* Display+screen pair is seen.
|
|
|
|
*/
|
|
|
|
typedef struct {
|
|
|
|
Display *dpy;
|
|
|
|
int screen;
|
|
|
|
} __GLXvendorScreenHashKey;
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct __GLXvendorScreenHashRec {
|
|
|
|
__GLXvendorScreenHashKey key;
|
|
|
|
__GLXvendorInfo *vendor;
|
|
|
|
// XXX for performance reasons we may want to stash the dispatch tables here
|
|
|
|
// as well
|
|
|
|
UT_hash_handle hh;
|
|
|
|
} __GLXvendorScreenHash;
|
|
|
|
|
|
|
|
static DEFINE_INITIALIZED_LKDHASH(__GLXvendorScreenHash, __glXVendorScreenHash);
|
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
/*
|
|
|
|
* __glXVendorNameHash is a hash table mapping a vendor name to vendor info.
|
|
|
|
*/
|
|
|
|
typedef struct __GLXvendorNameHashRec {
|
|
|
|
const char *name;
|
|
|
|
__GLXvendorInfo *vendor;
|
|
|
|
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);
|
|
|
|
|
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
|
|
|
|
|
|
|
LKDHASH_WRLOCK(__glXPthreadFuncs, __glXDispatchIndexHash);
|
|
|
|
pEntry->index = __glXNextUnusedHashIndex++;
|
|
|
|
|
|
|
|
// Notify the vendor this is the index which should be used
|
|
|
|
vendor->staticDispatch->
|
|
|
|
glxvc.setDispatchIndex(procName, pEntry->index);
|
|
|
|
|
|
|
|
HASH_ADD_INT(_LH(__glXDispatchIndexHash),
|
|
|
|
index, pEntry);
|
|
|
|
LKDHASH_UNLOCK(__glXPthreadFuncs, __glXDispatchIndexHash);
|
|
|
|
|
|
|
|
return GL_TRUE;
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX for full correctness, we should probably load vendors
|
|
|
|
* on all screens up-front before doing this. However, that
|
|
|
|
* might be bad for performance?
|
2013-11-26 00:21:41 +01:00
|
|
|
*
|
|
|
|
* A better way to solve this issue might be to tweak the ABI slightly
|
|
|
|
* to allow vendors to provide a standalone DSO which only
|
|
|
|
* exports vendor-neutral dispatch functions, and nothing else.
|
2013-08-12 22:12:09 +02:00
|
|
|
*/
|
|
|
|
LKDHASH_RDLOCK(__glXPthreadFuncs, __glXVendorNameHash);
|
|
|
|
HASH_ITER(hh, _LH(__glXVendorNameHash), pEntry, tmp) {
|
|
|
|
// See if the current vendor supports this GLX entry point
|
|
|
|
addr = pEntry->vendor->staticDispatch->
|
|
|
|
glxvc.getDispatchAddress(procName);
|
|
|
|
if (addr) {
|
2013-08-12 22:12:09 +02:00
|
|
|
// Allocate the new dispatch index.
|
|
|
|
if (!AllocDispatchIndex(pEntry->vendor, procName)) {
|
|
|
|
addr = NULL;
|
|
|
|
}
|
2013-08-12 22:12:09 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
LKDHASH_UNLOCK(__glXPthreadFuncs, __glXVendorNameHash);
|
|
|
|
|
|
|
|
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;
|
2015-04-19 18:30:21 +02:00
|
|
|
__GLXdispatchTableDynamic *dynDispatch = vendor->dynDispatch;
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
LKDHASH_RDLOCK(__glXPthreadFuncs, dynDispatch->hash);
|
|
|
|
|
|
|
|
HASH_FIND_INT(_LH(dynDispatch->hash), &index, pEntry);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
LKDHASH_UNLOCK(__glXPthreadFuncs, dynDispatch->hash);
|
|
|
|
|
|
|
|
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
|
|
|
|
LKDHASH_RDLOCK(__glXPthreadFuncs, __glXDispatchIndexHash);
|
|
|
|
HASH_FIND_INT(_LH(__glXDispatchIndexHash), &index, pdiEntry);
|
|
|
|
procName = pdiEntry->procName;
|
|
|
|
LKDHASH_UNLOCK(__glXPthreadFuncs, __glXDispatchIndexHash);
|
|
|
|
|
|
|
|
// This should have a valid entry point associated with it.
|
|
|
|
assert(procName);
|
|
|
|
|
|
|
|
if (procName) {
|
|
|
|
// Get the real address
|
|
|
|
addr = dynDispatch->vendor->staticDispatch->
|
2013-11-26 00:21:41 +01:00
|
|
|
glxvc.getProcAddress(procName, GL_FALSE);
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
LKDHASH_WRLOCK(__glXPthreadFuncs, dynDispatch->hash);
|
|
|
|
HASH_FIND_INT(_LH(dynDispatch->hash), &index, pEntry);
|
|
|
|
if (!pEntry) {
|
|
|
|
pEntry = malloc(sizeof(*pEntry));
|
|
|
|
if (!pEntry) {
|
|
|
|
// Uh-oh!
|
|
|
|
assert(pEntry);
|
2013-09-04 06:55:54 +02:00
|
|
|
LKDHASH_UNLOCK(__glXPthreadFuncs, dynDispatch->hash);
|
2013-08-12 22:12:09 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
pEntry->index = index;
|
|
|
|
pEntry->addr = addr;
|
|
|
|
|
|
|
|
HASH_ADD_INT(_LH(dynDispatch->hash), index, pEntry);
|
|
|
|
} else {
|
|
|
|
addr = pEntry->addr;
|
|
|
|
}
|
|
|
|
LKDHASH_UNLOCK(__glXPthreadFuncs, dynDispatch->hash);
|
|
|
|
}
|
|
|
|
|
|
|
|
return addr;
|
|
|
|
}
|
|
|
|
|
2013-11-26 00:21:41 +01:00
|
|
|
static __GLXapiExports glxExportsTable;
|
|
|
|
static glvnd_once_t glxExportsTableOnceControl = GLVND_ONCE_INIT;
|
|
|
|
|
|
|
|
static void InitExportsTable(void)
|
|
|
|
{
|
|
|
|
glxExportsTable.getDynDispatch = __glXGetDynDispatch;
|
|
|
|
glxExportsTable.getCurrentDynDispatch = __glXGetCurrentDynDispatch;
|
|
|
|
glxExportsTable.fetchDispatchEntry = __glXFetchDispatchEntry;
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
/* We use the real function since __glXGetCurrentContext is inline */
|
2013-11-26 00:21:41 +01:00
|
|
|
glxExportsTable.getCurrentContext = glXGetCurrentContext;
|
|
|
|
|
|
|
|
glxExportsTable.addScreenContextMapping = __glXAddScreenContextMapping;
|
|
|
|
glxExportsTable.removeScreenContextMapping = __glXRemoveScreenContextMapping;
|
2015-04-19 18:30:21 +02:00
|
|
|
glxExportsTable.vendorFromContext = __glXVendorFromContext;
|
2013-11-26 00:21:41 +01:00
|
|
|
|
|
|
|
glxExportsTable.addScreenFBConfigMapping = __glXAddScreenFBConfigMapping;
|
|
|
|
glxExportsTable.removeScreenFBConfigMapping = __glXRemoveScreenFBConfigMapping;
|
2015-04-19 18:30:21 +02:00
|
|
|
glxExportsTable.vendorFromFBConfig = __glXVendorFromFBConfig;
|
2013-11-26 00:21:41 +01:00
|
|
|
|
2015-04-20 22:29:07 +02:00
|
|
|
glxExportsTable.addScreenVisualMapping = __glXAddScreenVisualMapping;
|
|
|
|
glxExportsTable.removeScreenVisualMapping = __glXRemoveScreenVisualMapping;
|
|
|
|
glxExportsTable.vendorFromVisual = __glXVendorFromVisual;
|
|
|
|
|
2013-11-26 00:21:41 +01:00
|
|
|
glxExportsTable.addScreenDrawableMapping = __glXAddScreenDrawableMapping;
|
|
|
|
glxExportsTable.removeScreenDrawableMapping = __glXRemoveScreenDrawableMapping;
|
2015-04-19 18:30:21 +02:00
|
|
|
glxExportsTable.vendorFromDrawable = __glXVendorFromDrawable;
|
2013-11-26 00:21:41 +01:00
|
|
|
|
|
|
|
}
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2015-03-27 18:38:58 +01:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2014-10-03 01:17:59 +02:00
|
|
|
void TeardownVendor(__GLXvendorInfo *vendor, Bool doLibraryUnload)
|
|
|
|
{
|
|
|
|
free(vendor->name);
|
|
|
|
if (vendor->glDispatch) {
|
|
|
|
__glDispatchDestroyTable(vendor->glDispatch);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clean up the dynamic dispatch table */
|
|
|
|
LKDHASH_TEARDOWN(__glXPthreadFuncs, __GLXdispatchFuncHash,
|
|
|
|
vendor->dynDispatch->hash, NULL, NULL, True);
|
|
|
|
|
|
|
|
free(vendor->dynDispatch);
|
|
|
|
|
|
|
|
if (doLibraryUnload) {
|
|
|
|
dlclose(vendor->dlhandle);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(vendor);
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
void *dlhandle = NULL;
|
|
|
|
__PFNGLXMAINPROC glxMainProc;
|
|
|
|
const __GLXdispatchTableStatic *dispatch;
|
2013-08-12 22:12:09 +02:00
|
|
|
__GLXdispatchTableDynamic *dynDispatch;
|
2013-08-12 22:12:09 +02:00
|
|
|
__GLXvendorInfo *vendor = NULL;
|
|
|
|
Bool locked = False;
|
2014-01-24 04:51:49 +01:00
|
|
|
int vendorID = -1;
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
LKDHASH_RDLOCK(__glXPthreadFuncs, __glXVendorNameHash);
|
|
|
|
HASH_FIND(hh, _LH(__glXVendorNameHash), vendorName, strlen(vendorName), pEntry);
|
|
|
|
|
|
|
|
if (pEntry) {
|
|
|
|
vendor = pEntry->vendor;
|
|
|
|
}
|
|
|
|
LKDHASH_UNLOCK(__glXPthreadFuncs, __glXVendorNameHash);
|
|
|
|
|
|
|
|
if (!pEntry) {
|
|
|
|
LKDHASH_WRLOCK(__glXPthreadFuncs, __glXVendorNameHash);
|
|
|
|
locked = True;
|
|
|
|
// Do another lookup to check uniqueness
|
|
|
|
HASH_FIND(hh, _LH(__glXVendorNameHash), vendorName, strlen(vendorName), pEntry);
|
|
|
|
if (!pEntry) {
|
2014-10-03 01:17:05 +02:00
|
|
|
char *filename;
|
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
// Previously unseen vendor. dlopen() the new vendor and add it to the
|
|
|
|
// hash table.
|
|
|
|
pEntry = calloc(1, sizeof(*pEntry));
|
|
|
|
if (!pEntry) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
filename = ConstructVendorLibraryFilename(vendorName);
|
2014-10-03 01:17:05 +02:00
|
|
|
if (filename) {
|
|
|
|
dlhandle = dlopen(filename, RTLD_LAZY);
|
|
|
|
}
|
2013-08-12 22:12:09 +02:00
|
|
|
free(filename);
|
|
|
|
if (!dlhandle) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
glxMainProc = dlsym(dlhandle, __GLX_MAIN_PROTO_NAME);
|
|
|
|
if (!glxMainProc) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2013-11-26 00:21:41 +01:00
|
|
|
/* Initialize the glxExportsTable if we haven't already */
|
|
|
|
__glXPthreadFuncs.once(&glxExportsTableOnceControl,
|
|
|
|
InitExportsTable);
|
|
|
|
|
2014-01-24 04:51:49 +01:00
|
|
|
vendorID = __glDispatchNewVendorID();
|
|
|
|
assert(vendorID >= 0);
|
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
dispatch = (*glxMainProc)(GLX_VENDOR_ABI_VERSION,
|
|
|
|
&glxExportsTable,
|
2014-01-24 04:51:49 +01:00
|
|
|
vendorName,
|
|
|
|
vendorID);
|
2013-08-12 22:12:09 +02:00
|
|
|
if (!dispatch) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
vendor = pEntry->vendor
|
|
|
|
= calloc(1, sizeof(__GLXvendorInfo));
|
|
|
|
if (!vendor) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
pEntry->name = vendor->name = strdup(vendorName);
|
2014-01-24 04:51:49 +01:00
|
|
|
vendor->vendorID = vendorID;
|
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
if (!vendor->name) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
vendor->dlhandle = dlhandle;
|
|
|
|
vendor->staticDispatch = dispatch;
|
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
vendor->glDispatch = (__GLdispatchTable *)
|
2013-11-26 00:21:41 +01:00
|
|
|
__glDispatchCreateTable(
|
|
|
|
dispatch->glxvc.getProcAddress
|
|
|
|
);
|
2013-08-12 22:12:09 +02:00
|
|
|
if (!vendor->glDispatch) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
dynDispatch = vendor->dynDispatch
|
|
|
|
= malloc(sizeof(__GLXdispatchTableDynamic));
|
|
|
|
if (!dynDispatch) {
|
|
|
|
goto fail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Initialize the dynamic dispatch table */
|
|
|
|
LKDHASH_INIT(__glXPthreadFuncs, dynDispatch->hash);
|
|
|
|
dynDispatch->vendor = vendor;
|
2013-08-12 22:12:09 +02:00
|
|
|
|
2014-01-24 05:10:55 +01:00
|
|
|
HASH_ADD_KEYPTR(hh, _LH(__glXVendorNameHash), vendor->name,
|
|
|
|
strlen(vendor->name), pEntry);
|
2013-08-12 22:12:09 +02:00
|
|
|
} else {
|
|
|
|
/* Some other thread added a vendor */
|
|
|
|
vendor = pEntry->vendor;
|
|
|
|
}
|
|
|
|
LKDHASH_UNLOCK(__glXPthreadFuncs, __glXVendorNameHash);
|
|
|
|
}
|
|
|
|
|
|
|
|
return vendor;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
if (locked) {
|
|
|
|
LKDHASH_UNLOCK(__glXPthreadFuncs, __glXVendorNameHash);
|
|
|
|
}
|
|
|
|
if (dlhandle) {
|
|
|
|
dlclose(dlhandle);
|
|
|
|
}
|
|
|
|
if (vendor) {
|
2014-10-03 01:17:59 +02:00
|
|
|
TeardownVendor(vendor, False/* doLibraryUnload */);
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
|
|
|
free(pEntry);
|
2013-08-23 01:21:31 +02:00
|
|
|
return NULL;
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
2014-10-03 01:17:59 +02:00
|
|
|
static void CleanupVendorNameEntry(void *unused,
|
|
|
|
__GLXvendorNameHash *pEntry)
|
|
|
|
{
|
|
|
|
TeardownVendor(pEntry->vendor, True/* doLibraryUnload */);
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
__GLXvendorScreenHash *pEntry = NULL;
|
|
|
|
__GLXvendorScreenHashKey key;
|
|
|
|
|
|
|
|
if (screen < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&key, 0, sizeof(key));
|
|
|
|
|
|
|
|
key.dpy = dpy;
|
|
|
|
key.screen = screen;
|
|
|
|
|
|
|
|
LKDHASH_RDLOCK(__glXPthreadFuncs, __glXVendorScreenHash);
|
|
|
|
|
|
|
|
HASH_FIND(hh, _LH(__glXVendorScreenHash), &key,
|
|
|
|
sizeof(key), pEntry);
|
|
|
|
if (pEntry) {
|
|
|
|
vendor = pEntry->vendor;
|
|
|
|
}
|
|
|
|
|
|
|
|
LKDHASH_UNLOCK(__glXPthreadFuncs, __glXVendorScreenHash);
|
|
|
|
|
|
|
|
if (!pEntry) {
|
|
|
|
/*
|
|
|
|
* 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");
|
|
|
|
char *queriedVendorName;
|
|
|
|
|
|
|
|
assert(!vendor);
|
|
|
|
|
|
|
|
if (preloadedVendorName) {
|
|
|
|
vendor = __glXLookupVendorByName(preloadedVendorName);
|
|
|
|
}
|
|
|
|
|
2013-11-18 22:54:01 +01:00
|
|
|
if (!vendor && (dpy != NULL)) {
|
2013-08-12 22:12:09 +02:00
|
|
|
queriedVendorName = XGLVQueryScreenVendorMapping(dpy, screen);
|
2013-08-12 22:12:09 +02:00
|
|
|
vendor = __glXLookupVendorByName(queriedVendorName);
|
|
|
|
Xfree(queriedVendorName);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!vendor) {
|
2013-11-18 22:54:01 +01:00
|
|
|
/* No vendor available */
|
|
|
|
return NULL;
|
2013-08-12 22:12:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
LKDHASH_WRLOCK(__glXPthreadFuncs, __glXVendorScreenHash);
|
|
|
|
|
|
|
|
HASH_FIND(hh, _LH(__glXVendorScreenHash), &key, sizeof(key), pEntry);
|
|
|
|
|
|
|
|
if (!pEntry) {
|
|
|
|
pEntry = malloc(sizeof(*pEntry));
|
|
|
|
if (!pEntry) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pEntry->key.dpy = dpy;
|
|
|
|
pEntry->key.screen = screen;
|
|
|
|
pEntry->vendor = vendor;
|
|
|
|
HASH_ADD(hh, _LH(__glXVendorScreenHash), key,
|
|
|
|
sizeof(__GLXvendorScreenHashKey), pEntry);
|
|
|
|
} else {
|
|
|
|
/* Some other thread already added a vendor */
|
|
|
|
vendor = pEntry->vendor;
|
|
|
|
}
|
|
|
|
|
|
|
|
LKDHASH_UNLOCK(__glXPthreadFuncs, __glXVendorScreenHash);
|
|
|
|
}
|
|
|
|
|
|
|
|
DBG_PRINTF(10, "Found vendor \"%s\" for screen %d\n",
|
|
|
|
vendor->name, screen);
|
|
|
|
|
|
|
|
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) {
|
|
|
|
assert(vendor->staticDispatch);
|
|
|
|
return vendor->staticDispatch;
|
|
|
|
} else {
|
2013-08-23 01:06:53 +02:00
|
|
|
return __glXDispatchNoopPtr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-19 18:30:21 +02:00
|
|
|
const __GLXdispatchTableStatic * __glXGetDrawableStaticDispatch(Display *dpy,
|
|
|
|
GLXDrawable drawable)
|
|
|
|
{
|
|
|
|
int screen = __glXScreenFromDrawable(dpy, drawable);
|
|
|
|
return __glXGetStaticDispatch(dpy, screen);
|
|
|
|
}
|
|
|
|
|
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-14 19:58:43 +02:00
|
|
|
__GLXdisplayInfo *__glXLookupDisplay(Display *dpy)
|
|
|
|
{
|
|
|
|
__GLXdisplayInfoHash *pEntry = NULL;
|
|
|
|
|
2015-04-19 18:30:21 +02:00
|
|
|
if (dpy == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-04-14 19:58:43 +02:00
|
|
|
LKDHASH_RDLOCK(__glXPthreadFuncs, __glXDisplayInfoHash);
|
|
|
|
HASH_FIND_PTR(_LH(__glXDisplayInfoHash), &dpy, pEntry);
|
|
|
|
LKDHASH_UNLOCK(__glXPthreadFuncs, __glXDisplayInfoHash);
|
|
|
|
|
|
|
|
if (pEntry != NULL) {
|
|
|
|
return &pEntry->info;
|
|
|
|
}
|
|
|
|
|
|
|
|
LKDHASH_WRLOCK(__glXPthreadFuncs, __glXDisplayInfoHash);
|
|
|
|
HASH_FIND_PTR(_LH(__glXDisplayInfoHash), &dpy, pEntry);
|
|
|
|
if (pEntry == NULL) {
|
|
|
|
pEntry = (__GLXdisplayInfoHash *) malloc(sizeof(*pEntry));
|
|
|
|
if (pEntry != NULL) {
|
|
|
|
memset(pEntry, 0, sizeof(*pEntry));
|
|
|
|
pEntry->dpy = dpy;
|
|
|
|
HASH_ADD_PTR(_LH(__glXDisplayInfoHash), dpy, pEntry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
LKDHASH_UNLOCK(__glXPthreadFuncs, __glXDisplayInfoHash);
|
|
|
|
if (pEntry != NULL) {
|
|
|
|
return &pEntry->info;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void __glXFreeDisplay(Display *dpy)
|
|
|
|
{
|
|
|
|
__GLXdisplayInfoHash *pEntry = NULL;
|
|
|
|
|
|
|
|
LKDHASH_WRLOCK(__glXPthreadFuncs, __glXDisplayInfoHash);
|
|
|
|
HASH_FIND_PTR(_LH(__glXDisplayInfoHash), &dpy, pEntry);
|
|
|
|
if (pEntry != NULL) {
|
|
|
|
HASH_DEL(_LH(__glXDisplayInfoHash), pEntry);
|
|
|
|
}
|
|
|
|
LKDHASH_UNLOCK(__glXPthreadFuncs, __glXDisplayInfoHash);
|
|
|
|
|
|
|
|
if (pEntry != NULL) {
|
|
|
|
int i;
|
|
|
|
for (i=0; i<GLX_CLIENT_STRING_LAST_ATTRIB; i++) {
|
|
|
|
if (pEntry->info.clientStrings[i] != NULL) {
|
|
|
|
free(pEntry->info.clientStrings[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(pEntry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-12 22:12:09 +02:00
|
|
|
/****************************************************************************/
|
|
|
|
/*
|
|
|
|
* __glXScreenPointerMappingHash is a hash table that maps a void*
|
|
|
|
* (either GLXContext or GLXFBConfig) to a screen index. Note this
|
|
|
|
* stores both GLXContext and GLXFBConfig in this table.
|
|
|
|
*/
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
void *ptr;
|
|
|
|
int screen;
|
|
|
|
UT_hash_handle hh;
|
|
|
|
} __GLXscreenPointerMappingHash;
|
|
|
|
|
|
|
|
|
|
|
|
static DEFINE_INITIALIZED_LKDHASH(__GLXscreenPointerMappingHash, __glXScreenPointerMappingHash);
|
|
|
|
|
2013-08-23 01:21:31 +02:00
|
|
|
static void AddScreenPointerMapping(void *ptr, int screen)
|
|
|
|
{
|
2013-08-12 22:12:09 +02:00
|
|
|
__GLXscreenPointerMappingHash *pEntry;
|
|
|
|
|
|
|
|
if (ptr == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (screen < 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
LKDHASH_WRLOCK(__glXPthreadFuncs, __glXScreenPointerMappingHash);
|
|
|
|
|
|
|
|
HASH_FIND_PTR(_LH(__glXScreenPointerMappingHash), &ptr, pEntry);
|
|
|
|
|
|
|
|
if (pEntry == NULL) {
|
|
|
|
pEntry = malloc(sizeof(*pEntry));
|
|
|
|
pEntry->ptr = ptr;
|
|
|
|
pEntry->screen = screen;
|
|
|
|
HASH_ADD_PTR(_LH(__glXScreenPointerMappingHash), ptr, pEntry);
|
|
|
|
} else {
|
|
|
|
pEntry->screen = screen;
|
|
|
|
}
|
|
|
|
|
|
|
|
LKDHASH_UNLOCK(__glXPthreadFuncs, __glXScreenPointerMappingHash);
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-26 00:21:41 +01:00
|
|
|
static void RemoveScreenPointerMapping(void *ptr)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2013-08-12 22:12:09 +02:00
|
|
|
__GLXscreenPointerMappingHash *pEntry;
|
|
|
|
|
|
|
|
if (ptr == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
LKDHASH_WRLOCK(__glXPthreadFuncs, __glXScreenPointerMappingHash);
|
|
|
|
|
2013-09-27 02:27:09 +02:00
|
|
|
HASH_FIND_PTR(_LH(__glXScreenPointerMappingHash), &ptr, pEntry);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
if (pEntry != NULL) {
|
|
|
|
HASH_DELETE(hh, _LH(__glXScreenPointerMappingHash), pEntry);
|
|
|
|
free(pEntry);
|
|
|
|
}
|
|
|
|
|
|
|
|
LKDHASH_UNLOCK(__glXPthreadFuncs, __glXScreenPointerMappingHash);
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int ScreenFromPointer(void *ptr)
|
|
|
|
{
|
2013-08-12 22:12:09 +02:00
|
|
|
__GLXscreenPointerMappingHash *pEntry;
|
|
|
|
int screen = -1;
|
|
|
|
|
|
|
|
LKDHASH_RDLOCK(__glXPthreadFuncs, __glXScreenPointerMappingHash);
|
|
|
|
|
2013-09-27 02:27:09 +02:00
|
|
|
HASH_FIND_PTR(_LH(__glXScreenPointerMappingHash), &ptr, pEntry);
|
2013-08-12 22:12:09 +02:00
|
|
|
|
|
|
|
if (pEntry != NULL) {
|
|
|
|
screen = pEntry->screen;
|
|
|
|
}
|
|
|
|
|
|
|
|
LKDHASH_UNLOCK(__glXPthreadFuncs, __glXScreenPointerMappingHash);
|
|
|
|
|
|
|
|
return screen;
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
2015-04-19 18:30:21 +02:00
|
|
|
/**
|
|
|
|
* Common function for the various __glXVendorFrom* functions.
|
|
|
|
*/
|
|
|
|
static int CommonVendorFromScreen(Display *dpy, int screen, int *retScreen, __GLXvendorInfo **retVendor)
|
|
|
|
{
|
|
|
|
if (retScreen != NULL) {
|
|
|
|
*retScreen = screen;
|
|
|
|
}
|
|
|
|
if (retVendor != NULL) {
|
|
|
|
if (screen >= 0) {
|
|
|
|
*retVendor = __glXLookupVendorByScreen(dpy, screen);
|
|
|
|
} else {
|
|
|
|
*retVendor = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (screen >= 0 ? 0 : -1);
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
|
2015-04-19 18:30:21 +02:00
|
|
|
void __glXAddScreenContextMapping(Display *dpy, GLXContext context, int screen, __GLXvendorInfo *vendor)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
|
|
|
AddScreenPointerMapping(context, screen);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-04-19 18:30:21 +02:00
|
|
|
void __glXRemoveScreenContextMapping(Display *dpy, GLXContext context)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2013-11-26 00:21:41 +01:00
|
|
|
RemoveScreenPointerMapping(context);
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int __glXScreenFromContext(GLXContext context)
|
|
|
|
{
|
|
|
|
return ScreenFromPointer(context);
|
|
|
|
}
|
|
|
|
|
2015-04-19 18:30:21 +02:00
|
|
|
int __glXVendorFromContext(Display *dpy, GLXContext context, int *retScreen, __GLXvendorInfo **retVendor)
|
|
|
|
{
|
|
|
|
int screen = ScreenFromPointer(context);
|
|
|
|
return CommonVendorFromScreen(dpy, screen, retScreen, retVendor);
|
|
|
|
}
|
|
|
|
|
2013-08-23 01:06:53 +02:00
|
|
|
|
2015-04-19 18:30:21 +02:00
|
|
|
void __glXAddScreenFBConfigMapping(Display *dpy, GLXFBConfig config, int screen, __GLXvendorInfo *vendor)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
|
|
|
AddScreenPointerMapping(config, screen);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-04-19 18:30:21 +02:00
|
|
|
void __glXRemoveScreenFBConfigMapping(Display *dpy, GLXFBConfig config)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2013-11-26 00:21:41 +01:00
|
|
|
RemoveScreenPointerMapping(config);
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int __glXScreenFromFBConfig(GLXFBConfig config)
|
|
|
|
{
|
|
|
|
return ScreenFromPointer(config);
|
|
|
|
}
|
|
|
|
|
2015-04-19 18:30:21 +02:00
|
|
|
int __glXVendorFromFBConfig(Display *dpy, GLXFBConfig config, int *retScreen, __GLXvendorInfo **retVendor)
|
|
|
|
{
|
|
|
|
int screen = ScreenFromPointer(config);
|
|
|
|
return CommonVendorFromScreen(dpy, screen, retScreen, retVendor);
|
|
|
|
}
|
|
|
|
|
2015-04-20 22:29:07 +02:00
|
|
|
// 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)
|
|
|
|
{
|
|
|
|
if (retVendor != NULL) {
|
|
|
|
*retVendor = __glXLookupVendorByScreen(dpy, visual->screen);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2013-08-23 01:06:53 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************/
|
2013-08-12 22:12:09 +02:00
|
|
|
/*
|
|
|
|
* __glXScreenXIDMappingHash is a hash table which maps XIDs to screens.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
XID xid;
|
|
|
|
int screen;
|
|
|
|
UT_hash_handle hh;
|
|
|
|
} __GLXscreenXIDMappingHash;
|
|
|
|
|
|
|
|
|
|
|
|
static DEFINE_INITIALIZED_LKDHASH(__GLXscreenXIDMappingHash, __glXScreenXIDMappingHash);
|
|
|
|
|
2013-08-23 01:06:53 +02:00
|
|
|
static void AddScreenXIDMapping(XID xid, int screen)
|
|
|
|
{
|
2013-08-12 22:12:09 +02:00
|
|
|
__GLXscreenXIDMappingHash *pEntry = NULL;
|
|
|
|
|
|
|
|
if (xid == None) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (screen < 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
LKDHASH_WRLOCK(__glXPthreadFuncs, __glXScreenXIDMappingHash);
|
|
|
|
|
|
|
|
HASH_FIND(hh, _LH(__glXScreenXIDMappingHash), &xid, sizeof(xid), pEntry);
|
|
|
|
|
|
|
|
if (pEntry == NULL) {
|
|
|
|
pEntry = malloc(sizeof(*pEntry));
|
|
|
|
pEntry->xid = xid;
|
|
|
|
pEntry->screen = screen;
|
|
|
|
HASH_ADD(hh, _LH(__glXScreenXIDMappingHash), xid, sizeof(xid), pEntry);
|
|
|
|
} else {
|
|
|
|
pEntry->screen = screen;
|
|
|
|
}
|
|
|
|
|
|
|
|
LKDHASH_UNLOCK(__glXPthreadFuncs, __glXScreenXIDMappingHash);
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-26 00:21:41 +01:00
|
|
|
static void RemoveScreenXIDMapping(XID xid)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2013-08-12 22:12:09 +02:00
|
|
|
__GLXscreenXIDMappingHash *pEntry;
|
|
|
|
|
|
|
|
if (xid == None) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
LKDHASH_WRLOCK(__glXPthreadFuncs, __glXScreenXIDMappingHash);
|
|
|
|
|
|
|
|
HASH_FIND(hh, _LH(__glXScreenXIDMappingHash), &xid, sizeof(xid), pEntry);
|
|
|
|
|
|
|
|
if (pEntry != NULL) {
|
|
|
|
HASH_DELETE(hh, _LH(__glXScreenXIDMappingHash), pEntry);
|
|
|
|
free(pEntry);
|
|
|
|
}
|
|
|
|
|
|
|
|
LKDHASH_UNLOCK(__glXPthreadFuncs, __glXScreenXIDMappingHash);
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:21:31 +02:00
|
|
|
static int ScreenFromXID(Display *dpy, XID xid)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2013-08-12 22:12:09 +02:00
|
|
|
__GLXscreenXIDMappingHash *pEntry;
|
|
|
|
int screen = -1;
|
|
|
|
|
|
|
|
LKDHASH_RDLOCK(__glXPthreadFuncs, __glXScreenXIDMappingHash);
|
|
|
|
|
|
|
|
HASH_FIND(hh, _LH(__glXScreenXIDMappingHash), &xid, sizeof(xid), pEntry);
|
|
|
|
|
|
|
|
if (pEntry) {
|
|
|
|
screen = pEntry->screen;
|
2013-11-18 23:47:42 +01:00
|
|
|
LKDHASH_UNLOCK(__glXPthreadFuncs, __glXScreenXIDMappingHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
} else {
|
2013-08-12 22:12:09 +02:00
|
|
|
screen = XGLVQueryXIDScreenMapping(dpy, xid);
|
2013-11-18 23:47:42 +01:00
|
|
|
LKDHASH_UNLOCK(__glXPthreadFuncs, __glXScreenXIDMappingHash);
|
2013-08-12 22:12:09 +02:00
|
|
|
AddScreenXIDMapping(xid, screen);
|
|
|
|
}
|
|
|
|
|
|
|
|
return screen;
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-04-19 18:30:21 +02:00
|
|
|
void __glXAddScreenDrawableMapping(Display *dpy, GLXDrawable drawable, int screen, __GLXvendorInfo *vendor)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
|
|
|
AddScreenXIDMapping(drawable, screen);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-04-19 18:30:21 +02:00
|
|
|
void __glXRemoveScreenDrawableMapping(Display *dpy, GLXDrawable drawable)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2013-11-26 00:21:41 +01:00
|
|
|
RemoveScreenXIDMapping(drawable);
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-23 01:21:31 +02:00
|
|
|
int __glXScreenFromDrawable(Display *dpy, GLXDrawable drawable)
|
2013-08-23 01:06:53 +02:00
|
|
|
{
|
2013-08-23 01:21:31 +02:00
|
|
|
return ScreenFromXID(dpy, drawable);
|
2013-08-23 01:06:53 +02:00
|
|
|
}
|
2014-10-03 01:17:59 +02:00
|
|
|
|
2015-04-19 18:30:21 +02:00
|
|
|
int __glXVendorFromDrawable(Display *dpy, GLXDrawable drawable, int *retScreen, __GLXvendorInfo **retVendor)
|
|
|
|
{
|
|
|
|
int screen = ScreenFromXID(dpy, drawable);
|
|
|
|
return CommonVendorFromScreen(dpy, screen, retScreen, retVendor);
|
|
|
|
}
|
|
|
|
|
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) {
|
|
|
|
/*
|
|
|
|
* 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
|
|
|
*/
|
2014-10-29 22:20:13 +01:00
|
|
|
__glXPthreadFuncs.rwlock_init(&__glXDispatchIndexHash.lock, NULL);
|
|
|
|
__glXPthreadFuncs.rwlock_init(&__glXVendorScreenHash.lock, NULL);
|
|
|
|
__glXPthreadFuncs.rwlock_init(&__glXScreenPointerMappingHash.lock, NULL);
|
|
|
|
__glXPthreadFuncs.rwlock_init(&__glXScreenXIDMappingHash.lock, NULL);
|
2014-10-03 01:17:59 +02:00
|
|
|
__glXPthreadFuncs.rwlock_init(&__glXVendorNameHash.lock, NULL);
|
2015-04-14 19:58:43 +02:00
|
|
|
__glXPthreadFuncs.rwlock_init(&__glXDisplayInfoHash.lock, NULL);
|
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 */
|
|
|
|
LKDHASH_TEARDOWN(__glXPthreadFuncs, __GLXdispatchIndexHash,
|
|
|
|
__glXDispatchIndexHash, CleanupDispatchIndexEntry,
|
|
|
|
NULL, False);
|
|
|
|
|
|
|
|
LKDHASH_WRLOCK(__glXPthreadFuncs, __glXDispatchIndexHash);
|
|
|
|
__glXNextUnusedHashIndex = 0;
|
|
|
|
LKDHASH_UNLOCK(__glXPthreadFuncs, __glXDispatchIndexHash);
|
|
|
|
|
|
|
|
LKDHASH_TEARDOWN(__glXPthreadFuncs, __GLXvendorScreenHash,
|
|
|
|
__glXVendorScreenHash, NULL, NULL, False);
|
2015-04-14 19:58:43 +02:00
|
|
|
LKDHASH_TEARDOWN(__glXPthreadFuncs, __GLXdisplayInfoHash,
|
|
|
|
__glXDisplayInfoHash, NULL, NULL, False);
|
2014-10-29 22:20:13 +01:00
|
|
|
|
|
|
|
LKDHASH_TEARDOWN(__glXPthreadFuncs, __GLXscreenPointerMappingHash,
|
|
|
|
__glXScreenPointerMappingHash, NULL, NULL, False);
|
|
|
|
|
|
|
|
LKDHASH_TEARDOWN(__glXPthreadFuncs, __GLXscreenXIDMappingHash,
|
|
|
|
__glXScreenXIDMappingHash, NULL, 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.
|
|
|
|
*/
|
|
|
|
LKDHASH_TEARDOWN(__glXPthreadFuncs, __GLXvendorNameHash,
|
|
|
|
__glXVendorNameHash, CleanupVendorNameEntry,
|
|
|
|
NULL, False);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|