Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/GLX/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ libGLX_la_LIBADD += $(UTIL_DIR)/libglvnd_pthread.la
libGLX_la_LIBADD += $(UTIL_DIR)/libutils_misc.la
libGLX_la_LIBADD += $(UTIL_DIR)/libapp_error_check.la
libGLX_la_LIBADD += $(UTIL_DIR)/libwinsys_dispatch.la
libGLX_la_LIBADD += $(UTIL_DIR)/libcJSON.la

libGLX_la_LDFLAGS = -shared -Wl,-Bsymbolic -version-info 0 $(LINKER_FLAG_NO_UNDEFINED)

Expand Down
12 changes: 11 additions & 1 deletion src/GLX/libglx.c
Original file line number Diff line number Diff line change
Expand Up @@ -2102,10 +2102,20 @@ void _init(void)
* Check if we need to pre-load any vendors specified via environment
* variable.
*/
const char *preloadedVendor = getenv("__GLX_VENDOR_LIBRARY_NAME");

const char *preloadedVendor = getenv("__GLX_VENDOR_LIBRARY_NAME");
if (preloadedVendor) {
__glXLookupVendorByName(preloadedVendor);
} else {
const char *preloadedVendorFilenames = getenv("__GLX_VENDOR_LIBRARY_FILENAMES");
char **tokens;
tokens = SplitString(preloadedVendorFilenames, NULL, ":");
if (tokens != NULL) {
for (int i = 0; tokens[i] != NULL; ++i) {
__glXLookupVendorFromConfigFile(tokens[i]);
}
free(tokens);
}
}
}

Expand Down
276 changes: 276 additions & 0 deletions src/GLX/libglxmapping.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
#include <dlfcn.h>
#include <string.h>

#include <stdbool.h>
#include <sys/stat.h>

#if defined(HASH_DEBUG)
# include <stdio.h>
#endif
Expand All @@ -44,6 +47,11 @@

#include "lkdhash.h"

#include "cJSON.h"

#define FILE_FORMAT_VERSION_MAJOR 1
#define FILE_FORMAT_VERSION_MINOR 0

#define _GNU_SOURCE 1

#if !defined(FALLBACK_VENDOR_NAME)
Expand Down Expand Up @@ -380,6 +388,261 @@ static void *VendorGetProcAddressCallback(const char *procName, void *param)
return vendor->glxvc->getProcAddress((const GLubyte *) procName);
}

static bool CheckFormatVersion(const char *versionStr)
{
int major, minor, rev;
int len;

major = minor = rev = -1;
len = sscanf(versionStr, "%d.%d.%d", &major, &minor, &rev);
if (len < 1) {
return false;
}
if (len < 2) {
minor = 0;
}
if (len < 3) {
rev = 0;
}
if (major != FILE_FORMAT_VERSION_MAJOR) {
return false;
}

if (minor > FILE_FORMAT_VERSION_MINOR) {
return false;
}
return true;
}

static cJSON *ReadJSONFile(const char *filename)
{
FILE *in = NULL;
char *buf = NULL;
cJSON *root = NULL;
struct stat st;

in = fopen(filename, "r");
if (in == NULL) {
goto done;
}

if (fstat(fileno(in), &st) != 0) {
goto done;
}

buf = (char *) malloc(st.st_size + 1);
if (buf == NULL) {
goto done;
}

if (fread(buf, st.st_size, 1, in) != 1) {
goto done;
}
buf[st.st_size] = '\0';

root = cJSON_Parse(buf);

done:
if (in != NULL) {
fclose(in);
}
if (buf != NULL) {
free(buf);
}
return root;
}

static char* constructVendorName(const char* libraryPath)
{
int start = strrchr(libraryPath, '/') - libraryPath + strlen("libGLX_") + 1;
int vendorNameLen = strlen(strstr(libraryPath + start, ".so"));
char *vendorName = malloc(vendorNameLen);
strncpy(vendorName, libraryPath + start, vendorNameLen);
vendorName[vendorNameLen] = '\0';

return vendorName;
}

__GLXvendorInfo* __glXLookupVendorFromConfigFile(const char *filename)
{
__GLXvendorInfo *vendor = NULL;
cJSON *root;
cJSON *node;
cJSON *icdNode;
const char *libraryPath;

root = ReadJSONFile(filename);
if (root == NULL) {
goto done;
}

node = cJSON_GetObjectItem(root, "file_format_version");
if (node == NULL || node->type != cJSON_String) {
goto done;
}
if (!CheckFormatVersion(node->valuestring)) {
goto done;
}

icdNode = cJSON_GetObjectItem(root, "ICD");
if (icdNode == NULL || icdNode->type != cJSON_Object) {
goto done;
}

node = cJSON_GetObjectItem(icdNode, "library_path");
if (node == NULL || node->type != cJSON_String) {
goto done;
}
libraryPath = node->valuestring;

char* vendorName = constructVendorName(libraryPath);

vendor = __glXLookupVendorByLibraryPath(libraryPath, vendorName);

free(vendorName);

done:
if (root != NULL) {
cJSON_Delete(root);
}
return vendor;
}


__GLXvendorInfo *__glXLookupVendorByLibraryPath(const char *libraryPath, const char *vendorName)
{
__GLXvendorNameHash *pEntry = NULL;
Bool locked = False;
size_t vendorNameLen;

// 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;
}

vendorNameLen = strlen(vendorName);

LKDHASH_RDLOCK(__glXVendorNameHash);
HASH_FIND(hh, _LH(__glXVendorNameHash), vendorName, vendorNameLen, pEntry);

LKDHASH_UNLOCK(__glXVendorNameHash);

if (!pEntry) {
LKDHASH_WRLOCK(__glXVendorNameHash);
locked = True;
// Do another lookup to check uniqueness
HASH_FIND(hh, _LH(__glXVendorNameHash), vendorName, vendorNameLen, pEntry);
if (!pEntry) {
__GLXvendorInfo *vendor;
__PFNGLXMAINPROC glxMainProc;
int i, count;
Bool success;

// Previously unseen vendor. dlopen() the new vendor and add it to the
// hash table.
pEntry = calloc(1, sizeof(*pEntry) + vendorNameLen + 1);
if (!pEntry) {
goto fail;
}
vendor = &pEntry->vendor;

vendor->glxvc = &pEntry->imports;
vendor->name = (char *) (pEntry + 1);
memcpy(vendor->name, vendorName, vendorNameLen + 1);

if (libraryPath) {
vendor->dlhandle = dlopen(libraryPath, RTLD_LAZY);
}

if (vendor->dlhandle == NULL) {
goto fail;
}

glxMainProc = dlsym(vendor->dlhandle, __GLX_MAIN_PROTO_NAME);
if (!glxMainProc) {
goto fail;
}

vendor->vendorID = __glDispatchNewVendorID();
assert(vendor->vendorID >= 0);

vendor->glDispatch = (__GLdispatchTable *)
__glDispatchCreateTable(
VendorGetProcAddressCallback,
vendor
);
if (!vendor->glDispatch) {
goto fail;
}

/* Initialize the dynamic dispatch table */
vendor->dynDispatch = __glvndWinsysVendorDispatchCreate();
if (vendor->dynDispatch == NULL) {
goto fail;
}

success = (*glxMainProc)(GLX_VENDOR_ABI_VERSION,
&glxExportsTable,
vendor, &pEntry->imports);
if (!success) {
goto fail;
}

// Make sure all the required functions are there.
if (pEntry->imports.isScreenSupported == NULL
|| pEntry->imports.getProcAddress == NULL
|| pEntry->imports.getDispatchAddress == NULL
|| pEntry->imports.setDispatchIndex == NULL)
{
goto fail;
}

if (!LookupVendorEntrypoints(vendor)) {
goto fail;
}

// Check to see whether this vendor library can support entrypoint
// patching.
if (pEntry->imports.isPatchSupported != NULL
&& pEntry->imports.initiatePatch != NULL) {
pEntry->patchCallbacks.isPatchSupported = pEntry->imports.isPatchSupported;
pEntry->patchCallbacks.initiatePatch = pEntry->imports.initiatePatch;
pEntry->patchCallbacks.releasePatch = pEntry->imports.releasePatch;
pEntry->patchCallbacks.threadAttach = pEntry->imports.patchThreadAttach;
pEntry->vendor.patchCallbacks = &pEntry->patchCallbacks;
}

HASH_ADD_KEYPTR(hh, _LH(__glXVendorNameHash), vendor->name,
strlen(vendor->name), pEntry);

// Look up the dispatch functions for any GLX extensions that we
// generated entrypoints for.
glvndUpdateEntrypoints(GLXEntrypointUpdateCallback, vendor);

// Tell the vendor the index of all of the GLX dispatch stubs.
count = __glvndWinsysDispatchGetCount();
for (i=0; i<count; i++) {
const char *procName = __glvndWinsysDispatchGetName(i);
vendor->glxvc->setDispatchIndex((const GLubyte *) procName, i);
}
}
LKDHASH_UNLOCK(__glXVendorNameHash);
}

return &pEntry->vendor;

fail:
if (locked) {
LKDHASH_UNLOCK(__glXVendorNameHash);
}
if (pEntry != NULL) {
CleanupVendorNameEntry(NULL, pEntry);
free(pEntry);
}
return NULL;
}

__GLXvendorInfo *__glXLookupVendorByName(const char *vendorName)
{
__GLXvendorNameHash *pEntry = NULL;
Expand Down Expand Up @@ -558,6 +821,19 @@ __GLXvendorInfo *__glXLookupVendorByScreen(Display *dpy, const int screen)

if (specifiedVendorName) {
vendor = __glXLookupVendorByName(specifiedVendorName);
} else {
specifiedVendorName = getenv("__GLX_VENDOR_LIBRARY_FILENAMES");

if (specifiedVendorName) {
char **tokens;
tokens = SplitString(specifiedVendorName, NULL, ":");
if (tokens != NULL) {
for (int i = 0; tokens[i] != NULL; ++i) {
vendor = __glXLookupVendorFromConfigFile(tokens[i]);
}
free(tokens);
}
}
}

if (!vendor) {
Expand Down
8 changes: 8 additions & 0 deletions src/GLX/libglxmapping.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,14 @@ __GLXextFuncPtr __glXGetGLXDispatchAddress(const GLubyte *procName);
__GLXvendorInfo *__glXLookupVendorByName(const char *vendorName);
__GLXvendorInfo *__glXLookupVendorByScreen(Display *dpy, const int screen);

/*!
* Looks up the vendor by configuration file. This has the side effect of
* loading the vendor library if it has not been previously loaded.
* The functionality is similar to __EGL_VENDOR_LIBRARY_FILENAMES.
*/
__GLXvendorInfo *__glXLookupVendorFromConfigFile(const char *filename);
__GLXvendorInfo *__glXLookupVendorByLibraryPath(const char *libraryPath, const char *vendorName);

/*!
* Looks up the __GLXdisplayInfo structure for a display, creating it if
* necessary.
Expand Down
1 change: 1 addition & 0 deletions src/GLX/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ libGLX = shared_library(
include_directories : [inc_include],
link_args : '-Wl,-Bsymbolic',
dependencies : [
idep_cjson,
dep_dl, dep_x11, dep_xext, dep_glproto,
idep_gldispatch, idep_trace,
idep_glvnd_pthread, idep_utils_misc,
Expand Down