Can compile "loader" and "layers" on Windows and Linux ...
These directories build and are partially turned-on on Windows, using the "tri"
demo (follow-on commit) and a "NULL driver" that was created out of the
sample/Intel driver. The GetProcAddress() is not yet finding symbols in the
NULL driver.
For now:
- "C:\Windows\System32" is the default XGL driver directory. The getenv()
isn't yet working. I suggest creating your own #define in order to point to
where a driver is.
- In order to recognize a Windows driver, we must look at both its prefix and
suffix (i.e. it is named "XGL_*.dll", e.g. "XGL_i965.dll).
- We autogenerate Windows ".def" files for the layers. Additional info is:
- This is necessary in order for a DLL to export symbols that can be queried
using GetProcAddress(). We can't use the normal Windows approach of
declaring these functions using "__declspec(dllexport)", because these
functions are declared in "xgl.h".
- This involves adding and running the new "xgl-win-def-file-generate.py"
file.
- NOTE: Layers don't have the xglInitAndEnumerateGpus() entrypoint, just the
xglGetProcAddr() entrypoint (and now the xglEnumerateLayers() entrypoint).
Generating them is pretty simple.
NOTE: In order to build on a 64-bit Windows 7/8 system, I did the following:
- Install VisualStudio 2013 Professional
- Install CMake from: http://www.cmake.org/cmake/resources/software.html
- I let it add itself to the system PATH environment variable.
- Install Python 3 from: https://www.python.org/downloads
- I let it add itself to the system PATH environment variable.
- Obtain the Git repository, checkout the "ian-150127-WinBuild" branch.
- Using a Cygwin shell: I did the following:
- "cd" to the top-level directory (i.e. the one that contains the ".git"
directory).
- "mkdir _out64"
- "cd _out64"
- "cmake -G "Visual Studio 12 Win64" .."
- At this point, I used WindowsExplorer to open the "XGL.sln" file. I can
build. CMake causes the build shortcut to be "Ctrl-Shift-B" instead of the
normal "F7". I had to right-click the "ALL_BUILD" project, go to
Properties->Debugging and change the debug Command and Working Directory to
point to "tri.exe" and where the executable are. At this point, I can debug
(using the normal "F5" shortcut).
diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt
index b2250ad..13a4b5b 100644
--- a/loader/CMakeLists.txt
+++ b/loader/CMakeLists.txt
@@ -13,6 +13,11 @@
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DXGL_PROTOTYPES")
-add_library(XGL SHARED loader.c dispatch.c table_ops.h)
+if (WIN32)
+ add_library(XGL SHARED loader.c dirent_on_windows.c dispatch.c table_ops.h)
+endif()
+if (NOT WIN32)
+ add_library(XGL SHARED loader.c dispatch.c table_ops.h)
+endif()
set_target_properties(XGL PROPERTIES SOVERSION 0)
target_link_libraries(XGL -ldl -lpthread)
diff --git a/loader/dirent_on_windows.c b/loader/dirent_on_windows.c
new file mode 100644
index 0000000..3564a26
--- /dev/null
+++ b/loader/dirent_on_windows.c
@@ -0,0 +1,148 @@
+/*
+
+ Implementation of POSIX directory browsing functions and types for Win32.
+
+ Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com)
+ History: Created March 1997. Updated June 2003 and July 2012.
+ Rights: See end of file.
+
+*/
+
+#include <dirent_on_windows.h>
+#include <errno.h>
+#include <io.h> /* _findfirst and _findnext set errno iff they return -1 */
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef ptrdiff_t handle_type; /* C99's intptr_t not sufficiently portable */
+
+struct DIR
+{
+ handle_type handle; /* -1 for failed rewind */
+ struct _finddata_t info;
+ struct dirent result; /* d_name null iff first time */
+ char *name; /* null-terminated char string */
+};
+
+DIR *opendir(const char *name)
+{
+ DIR *dir = 0;
+
+ if(name && name[0])
+ {
+ size_t base_length = strlen(name);
+ const char *all = /* search pattern must end with suitable wildcard */
+ strchr("/\\", name[base_length - 1]) ? "*" : "/*";
+
+ if((dir = (DIR *) malloc(sizeof *dir)) != 0 &&
+ (dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0)
+ {
+ strcat(strcpy(dir->name, name), all);
+
+ if((dir->handle =
+ (handle_type) _findfirst(dir->name, &dir->info)) != -1)
+ {
+ dir->result.d_name = 0;
+ }
+ else /* rollback */
+ {
+ free(dir->name);
+ free(dir);
+ dir = 0;
+ }
+ }
+ else /* rollback */
+ {
+ free(dir);
+ dir = 0;
+ errno = ENOMEM;
+ }
+ }
+ else
+ {
+ errno = EINVAL;
+ }
+
+ return dir;
+}
+
+int closedir(DIR *dir)
+{
+ int result = -1;
+
+ if(dir)
+ {
+ if(dir->handle != -1)
+ {
+ result = _findclose(dir->handle);
+ }
+
+ free(dir->name);
+ free(dir);
+ }
+
+ if(result == -1) /* map all errors to EBADF */
+ {
+ errno = EBADF;
+ }
+
+ return result;
+}
+
+struct dirent *readdir(DIR *dir)
+{
+ struct dirent *result = 0;
+
+ if(dir && dir->handle != -1)
+ {
+ if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1)
+ {
+ result = &dir->result;
+ result->d_name = dir->info.name;
+ }
+ }
+ else
+ {
+ errno = EBADF;
+ }
+
+ return result;
+}
+
+void rewinddir(DIR *dir)
+{
+ if(dir && dir->handle != -1)
+ {
+ _findclose(dir->handle);
+ dir->handle = (handle_type) _findfirst(dir->name, &dir->info);
+ dir->result.d_name = 0;
+ }
+ else
+ {
+ errno = EBADF;
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+/*
+
+ Copyright Kevlin Henney, 1997, 2003, 2012. All rights reserved.
+
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose is hereby granted without fee, provided
+ that this copyright and permissions notice appear in all copies and
+ derivatives.
+
+ This software is supplied "as is" without express or implied warranty.
+
+ But that said, if there are any problems please get in touch.
+
+*/
diff --git a/loader/dirent_on_windows.h b/loader/dirent_on_windows.h
new file mode 100644
index 0000000..a02a0d8
--- /dev/null
+++ b/loader/dirent_on_windows.h
@@ -0,0 +1,50 @@
+#ifndef DIRENT_INCLUDED
+#define DIRENT_INCLUDED
+
+/*
+
+ Declaration of POSIX directory browsing functions and types for Win32.
+
+ Author: Kevlin Henney (kevlin@acm.org, kevlin@curbralan.com)
+ History: Created March 1997. Updated June 2003.
+ Rights: See end of file.
+
+*/
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+typedef struct DIR DIR;
+
+struct dirent
+{
+ char *d_name;
+};
+
+DIR *opendir(const char *);
+int closedir(DIR *);
+struct dirent *readdir(DIR *);
+void rewinddir(DIR *);
+
+/*
+
+ Copyright Kevlin Henney, 1997, 2003. All rights reserved.
+
+ Permission to use, copy, modify, and distribute this software and its
+ documentation for any purpose is hereby granted without fee, provided
+ that this copyright and permissions notice appear in all copies and
+ derivatives.
+
+ This software is supplied "as is" without express or implied warranty.
+
+ But that said, if there are any problems please get in touch.
+
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/loader/loader.c b/loader/loader.c
index 0aa2940..c4cdce0 100644
--- a/loader/loader.c
+++ b/loader/loader.c
@@ -34,11 +34,12 @@
#include <string.h>
#include <sys/types.h>
+#if defined(WIN32)
+#include "dirent_on_windows.h"
+#else // WIN32
#include <dirent.h>
-#include <unistd.h>
-#include <dlfcn.h>
-#include <pthread.h>
-#include <assert.h>
+#endif // WIN32
+#include "loader_platform.h"
#include "table_ops.h"
#include "loader.h"
@@ -48,7 +49,7 @@
};
struct loader_layers {
- void *lib_handle;
+ loader_platform_dl_handle lib_handle;
char name[256];
};
@@ -79,7 +80,7 @@
};
struct loader_scanned_icds {
- void *handle;
+ loader_platform_dl_handle handle;
xglGetProcAddrType GetProcAddr;
xglCreateInstanceType CreateInstance;
xglDestroyInstanceType DestroyInstance;
@@ -105,6 +106,7 @@
bool break_on_warning;
} loader;
+
static XGL_RESULT loader_msg_callback_add(XGL_DBG_MSG_CALLBACK_FUNCTION func,
void *data)
{
@@ -206,7 +208,7 @@
static void
loader_icd_destroy(struct loader_icd *icd)
{
- dlclose(icd->scanned_icds->handle);
+ loader_platform_close_library(icd->scanned_icds->handle);
free(icd);
}
@@ -296,20 +298,21 @@
static void loader_scanned_icd_add(const char *filename)
{
- void *handle;
+ loader_platform_dl_handle handle;
void *fp_gpa, *fp_enumerate, *fp_create_inst, *fp_destroy_inst;
struct loader_scanned_icds *new_node;
- handle = dlopen(filename, RTLD_LAZY);
+ // Used to call: dlopen(filename, RTLD_LAZY);
+ handle = loader_platform_open_library(filename);
if (!handle) {
- loader_log(XGL_DBG_MSG_WARNING, 0, dlerror());
+ loader_log(XGL_DBG_MSG_WARNING, 0, loader_platform_open_library_error(filename));
return;
}
#define LOOKUP(func_ptr, func) do { \
- func_ptr = (xgl ##func## Type) dlsym(handle, "xgl" #func); \
+ func_ptr = (xgl ##func## Type) loader_platform_get_proc_address(handle, "xgl" #func); \
if (!func_ptr) { \
- loader_log(XGL_DBG_MSG_WARNING, 0, dlerror()); \
+ loader_log(XGL_DBG_MSG_WARNING, 0, loader_platform_get_proc_address_error("xgl" #func)); \
return; \
} \
} while (0)
@@ -335,12 +338,50 @@
loader.scanned_icd_list = new_node;
}
+#if defined(WIN32)
+
+#define PATH_SEPERATOR ';'
+#define DIRECTORY_SYMBOL "\\"
+#ifndef DEFAULT_XGL_DRIVERS_PATH
+// TODO: Is this a good default location?
+// Need to search for both 32bit and 64bit ICDs
+#define DEFAULT_XGL_DRIVERS_PATH "C:\\Windows\\System32"
+// TODO/TBD: Is this an appropriate prefix for Windows?
+#define XGL_DRIVER_LIBRARY_PREFIX "XGL_"
+#define XGL_DRIVER_LIBRARY_PREFIX_LEN 4
+// TODO/TBD: Is this an appropriate suffix for Windows?
+#define XGL_LAYER_LIBRARY_PREFIX "XGLLayer"
+#define XGL_LAYER_LIBRARY_PREFIX_LEN 8
+#define XGL_LIBRARY_SUFFIX ".dll"
+#define XGL_LIBRARY_SUFFIX_LEN 4
+#endif // DEFAULT_XGL_DRIVERS_PATH
+#ifndef DEFAULT_XGL_LAYERS_PATH
+// TODO: Is this a good default location?
+#define DEFAULT_XGL_LAYERS_PATH "C:\\Windows\\System32"
+#endif // DEFAULT_XGL_LAYERS_PATH
+
+#else // WIN32
+
+#define PATH_SEPERATOR ':'
+#define DIRECTORY_SYMBOL "/"
#ifndef DEFAULT_XGL_DRIVERS_PATH
// TODO: Is this a good default location?
// Need to search for both 32bit and 64bit ICDs
#define DEFAULT_XGL_DRIVERS_PATH "/usr/lib/i386-linux-gnu/xgl:/usr/lib/x86_64-linux-gnu/xgl"
+#define XGL_DRIVER_LIBRARY_PREFIX "libXGL_"
+#define XGL_DRIVER_LIBRARY_PREFIX_LEN 7
+#define XGL_LAYER_LIBRARY_PREFIX "libXGLLayer"
+#define XGL_LAYER_LIBRARY_PREFIX_LEN 11
+#define XGL_LIBRARY_SUFFIX ".so"
+#define XGL_LIBRARY_SUFFIX_LEN 3
+#endif // DEFAULT_XGL_DRIVERS_PATH
+#ifndef DEFAULT_XGL_LAYERS_PATH
+// TODO: Are these good default locations?
+#define DEFAULT_XGL_LAYERS_PATH ".:/usr/lib/i386-linux-gnu/xgl:/usr/lib/x86_64-linux-gnu/xgl"
#endif
+#endif // WIN32
+
/**
* Try to \c loader_icd_scan XGL driver(s).
*
@@ -361,15 +402,19 @@
int len;
libPaths = NULL;
+#if !defined(WIN32)
if (geteuid() == getuid()) {
- /* don't allow setuid apps to use LIBXGL_DRIVERS_PATH */
+ /* Don't allow setuid apps to use LIBXGL_DRIVERS_PATH */
+#endif // WIN32
libPaths = getenv("LIBXGL_DRIVERS_PATH");
+#if !defined(WIN32)
}
+#endif // WIN32
if (libPaths == NULL)
libPaths = DEFAULT_XGL_DRIVERS_PATH;
for (p = libPaths; *p; p = next) {
- next = strchr(p, ':');
+ next = strchr(p, PATH_SEPERATOR);
if (next == NULL) {
len = strlen(p);
next = p + len;
@@ -381,16 +426,28 @@
next++;
}
+ // TODO/TBD: Do we want to do this on Windows, or just let Windows take
+ // care of its own search path (which it apparently has)?
sysdir = opendir(p);
if (sysdir) {
dent = readdir(sysdir);
while (dent) {
- /* look for ICDs starting with "libXGL_" */
- if (!strncmp(dent->d_name, "libXGL_", 7)) {
- snprintf(icd_library, 1024, "%s/%s",p,dent->d_name);
-
- loader_scanned_icd_add(icd_library);
- }
+ /* Look for ICDs starting with XGL_DRIVER_LIBRARY_PREFIX and
+ * ending with XGL_LIBRARY_SUFFIX
+ */
+ if (!strncmp(dent->d_name,
+ XGL_DRIVER_LIBRARY_PREFIX,
+ XGL_DRIVER_LIBRARY_PREFIX_LEN)) {
+ int nlen = strlen(dent->d_name);
+ const char *suf = dent->d_name + nlen - XGL_LIBRARY_SUFFIX_LEN;
+ if ((nlen > XGL_LIBRARY_SUFFIX_LEN) &&
+ !strncmp(suf,
+ XGL_LIBRARY_SUFFIX,
+ XGL_LIBRARY_SUFFIX_LEN)) {
+ snprintf(icd_library, 1024, "%s" DIRECTORY_SYMBOL "%s", p,dent->d_name);
+ loader_scanned_icd_add(icd_library);
+ }
+ }
dent = readdir(sysdir);
}
@@ -398,14 +455,9 @@
}
}
-
loader.icds_scanned = true;
}
-#ifndef DEFAULT_XGL_LAYERS_PATH
-// TODO: Are these good default locations?
-#define DEFAULT_XGL_LAYERS_PATH ".:/usr/lib/i386-linux-gnu/xgl:/usr/lib/x86_64-linux-gnu/xgl"
-#endif
static void layer_lib_scan_path(const char * libInPaths)
{
@@ -423,11 +475,15 @@
p = libInPaths;
}
else {
+#if !defined(WIN32)
if (geteuid() == getuid()) {
+#endif // WIN32
p = getenv("LIBXGL_LAYERS_PATH");
if (p != NULL)
len = strlen(p);
+#if !defined(WIN32)
}
+#endif // WIN32
}
if (len == 0) {
@@ -456,7 +512,7 @@
loader.scanned_layer_count = 0;
for (p = libPaths; *p; p = next) {
- next = strchr(p, ':');
+ next = strchr(p, PATH_SEPERATOR);
if (next == NULL) {
len = strlen(p);
next = p + len;
@@ -471,25 +527,37 @@
if (curdir) {
dent = readdir(curdir);
while (dent) {
- /* look for wrappers starting with "libXGLlayer" */
- if (!strncmp(dent->d_name, "libXGLLayer", strlen("libXGLLayer"))) {
- void * handle;
- snprintf(temp_str, sizeof(temp_str), "%s/%s",p,dent->d_name);
- if ((handle = dlopen(temp_str, RTLD_LAZY)) == NULL) {
- dent = readdir(curdir);
- continue;
- }
- if (loader.scanned_layer_count == MAX_LAYER_LIBRARIES) {
- loader_log(XGL_DBG_MSG_ERROR, 0, "%s ignored: max layer libraries exceed", temp_str);
- break;
- }
- if ((loader.scanned_layer_names[loader.scanned_layer_count] = malloc(strlen(temp_str) + 1)) == NULL) {
- loader_log(XGL_DBG_MSG_ERROR, 0, "%s ignored: out of memory", temp_str);
- break;
- }
- strcpy(loader.scanned_layer_names[loader.scanned_layer_count], temp_str);
- loader.scanned_layer_count++;
- dlclose(handle);
+ /* Look for layers starting with XGL_LAYER_LIBRARY_PREFIX and
+ * ending with XGL_LIBRARY_SUFFIX
+ */
+ if (!strncmp(dent->d_name,
+ XGL_LAYER_LIBRARY_PREFIX,
+ XGL_LAYER_LIBRARY_PREFIX_LEN)) {
+ int nlen = strlen(dent->d_name);
+ const char *suf = dent->d_name + nlen - XGL_LIBRARY_SUFFIX_LEN;
+ if ((nlen > XGL_LIBRARY_SUFFIX_LEN) &&
+ !strncmp(suf,
+ XGL_LIBRARY_SUFFIX,
+ XGL_LIBRARY_SUFFIX_LEN)) {
+ loader_platform_dl_handle handle;
+ snprintf(temp_str, sizeof(temp_str), "%s" DIRECTORY_SYMBOL "%s",p,dent->d_name);
+ // Used to call: dlopen(temp_str, RTLD_LAZY)
+ if ((handle = loader_platform_open_library(temp_str)) == NULL) {
+ dent = readdir(curdir);
+ continue;
+ }
+ if (loader.scanned_layer_count == MAX_LAYER_LIBRARIES) {
+ loader_log(XGL_DBG_MSG_ERROR, 0, "%s ignored: max layer libraries exceed", temp_str);
+ break;
+ }
+ if ((loader.scanned_layer_names[loader.scanned_layer_count] = malloc(strlen(temp_str) + 1)) == NULL) {
+ loader_log(XGL_DBG_MSG_ERROR, 0, "%s ignored: out of memory", temp_str);
+ break;
+ }
+ strcpy(loader.scanned_layer_names[loader.scanned_layer_count], temp_str);
+ loader.scanned_layer_count++;
+ loader_platform_close_library(handle);
+ }
}
dent = readdir(curdir);
@@ -556,8 +624,9 @@
obj = &(icd->layer_libs[gpu_index][i]);
strncpy(obj->name, (char *) pLayerNames[i].layer_name, sizeof(obj->name) - 1);
obj->name[sizeof(obj->name) - 1] = '\0';
- if ((obj->lib_handle = dlopen(pLayerNames[i].lib_name, RTLD_LAZY | RTLD_DEEPBIND)) == NULL) {
- loader_log(XGL_DBG_MSG_ERROR, 0, "Failed to open layer library %s got error %d", pLayerNames[i].lib_name, dlerror());
+ // Used to call: dlopen(pLayerNames[i].lib_name, RTLD_LAZY | RTLD_DEEPBIND)
+ if ((obj->lib_handle = loader_platform_open_library(pLayerNames[i].lib_name)) == NULL) {
+ loader_log(XGL_DBG_MSG_ERROR, 0, loader_platform_open_library_error(pLayerNames[i].lib_name));
continue;
} else {
loader_log(XGL_DBG_MSG_UNKNOWN, 0, "Inserting layer %s from library %s", pLayerNames[i].layer_name, pLayerNames[i].lib_name);
@@ -570,7 +639,7 @@
static bool find_layer_name(struct loader_icd *icd, uint32_t gpu_index, const char * layer_name, const char **lib_name)
{
- void *handle;
+ loader_platform_dl_handle handle;
xglEnumerateLayersType fpEnumerateLayers;
char layer_buf[16][256];
char * layers[16];
@@ -580,14 +649,17 @@
for (unsigned int j = 0; j < loader.scanned_layer_count; j++) {
*lib_name = loader.scanned_layer_names[j];
- if ((handle = dlopen(*lib_name, RTLD_LAZY)) == NULL)
+ // Used to call: dlopen(*lib_name, RTLD_LAZY)
+ if ((handle = loader_platform_open_library(*lib_name)) == NULL)
continue;
- if ((fpEnumerateLayers = dlsym(handle, "xglEnumerateLayers")) == NULL) {
- //use default layer name based on library name libXGLLayer<name>.so
+ if ((fpEnumerateLayers = (xglEnumerateLayersType) loader_platform_get_proc_address(handle, "xglEnumerateLayers")) == NULL) {
char * lib_str = malloc(strlen(*lib_name) + 1 + strlen(layer_name));
- snprintf(lib_str, strlen(*lib_name) + strlen(layer_name), "libXGLLayer%s.so", layer_name);
- dlclose(handle);
- if (!strcmp(basename(*lib_name), lib_str)) {
+ //use default layer name
+ snprintf(lib_str, strlen(*lib_name) + strlen(layer_name),
+ XGL_DRIVER_LIBRARY_PREFIX "%s" XGL_LIBRARY_SUFFIX,
+ layer_name);
+ loader_platform_close_library(handle);
+ if (!strcmp(*lib_name, lib_str)) {
free(lib_str);
return true;
}
@@ -598,16 +670,16 @@
}
else {
size_t cnt;
- fpEnumerateLayers(NULL, 16, 256, &cnt, layers, (void *) icd->gpus + gpu_index);
+ fpEnumerateLayers(NULL, 16, 256, &cnt, layers, (char *) icd->gpus + gpu_index);
for (unsigned int i = 0; i < cnt; i++) {
if (!strcmp((char *) layers[i], layer_name)) {
- dlclose(handle);
+ loader_platform_close_library(handle);
return true;
}
}
}
- dlclose(handle);
+ loader_platform_close_library(handle);
}
return false;
@@ -630,7 +702,7 @@
while (p && *p && count < MAX_LAYER_LIBRARIES) {
const char *lib_name = NULL;
- next = strchr(p, ':');
+ next = strchr(p, PATH_SEPERATOR);
if (next == NULL) {
len = strlen(p);
next = p + len;
@@ -717,7 +789,7 @@
for (uint32_t i = 0; i < icd->layer_count[j]; i++) {
libs = &(icd->layer_libs[j][i]);
if (libs->lib_handle)
- dlclose(libs->lib_handle);
+ loader_platform_close_library(libs->lib_handle);
libs->lib_handle = NULL;
}
if (icd->wrappedGpus[j])
@@ -763,8 +835,8 @@
char funcStr[256];
snprintf(funcStr, 256, "%sGetProcAddr",icd->layer_libs[gpu_index][i].name);
- if ((nextGPA = dlsym(icd->layer_libs[gpu_index][i].lib_handle, funcStr)) == NULL)
- nextGPA = dlsym(icd->layer_libs[gpu_index][i].lib_handle, "xglGetProcAddr");
+ if ((nextGPA = (xglGetProcAddrType) loader_platform_get_proc_address(icd->layer_libs[gpu_index][i].lib_handle, funcStr)) == NULL)
+ nextGPA = (xglGetProcAddrType) loader_platform_get_proc_address(icd->layer_libs[gpu_index][i].lib_handle, "xglGetProcAddr");
if (!nextGPA) {
loader_log(XGL_DBG_MSG_ERROR, 0, "Failed to find xglGetProcAddr in layer %s", icd->layer_libs[gpu_index][i].name);
continue;
@@ -803,17 +875,18 @@
const XGL_ALLOC_CALLBACKS* pAllocCb,
XGL_INSTANCE* pInstance)
{
- static pthread_once_t once_icd = PTHREAD_ONCE_INIT;
- static pthread_once_t once_layer = PTHREAD_ONCE_INIT;
+ static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_icd);
+ static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(once_layer);
struct loader_instance *ptr_instance = NULL;
struct loader_scanned_icds *scanned_icds;
struct loader_icd *icd;
XGL_RESULT res;
- pthread_once(&once_icd, loader_icd_scan);
+ /* Scan/discover all ICD libraries in a single-threaded manner */
+ loader_platform_thread_once(&once_icd, loader_icd_scan);
- /* get layer libraries */
- pthread_once(&once_layer, layer_lib_scan);
+ /* get layer libraries in a single-threaded manner */
+ loader_platform_thread_once(&once_layer, layer_lib_scan);
ptr_instance = (struct loader_instance*) malloc(sizeof(struct loader_instance));
if (ptr_instance == NULL) {
@@ -967,8 +1040,9 @@
LOADER_EXPORT void * XGLAPI xglGetProcAddr(XGL_PHYSICAL_GPU gpu, const char * pName)
{
- if (gpu == NULL)
+ if (gpu == NULL) {
return NULL;
+ }
XGL_BASE_LAYER_OBJECT* gpuw = (XGL_BASE_LAYER_OBJECT *) gpu;
XGL_LAYER_DISPATCH_TABLE * disp_table = * (XGL_LAYER_DISPATCH_TABLE **) gpuw->baseObject;
void *addr;
@@ -992,7 +1066,7 @@
uint32_t count = 0;
char *lib_name;
struct loader_icd *icd = loader_get_icd((const XGL_BASE_LAYER_OBJECT *) gpu, &gpu_index);
- void *handle;
+ loader_platform_dl_handle handle;
xglEnumerateLayersType fpEnumerateLayers;
char layer_buf[16][256];
char * layers[16];
@@ -1008,16 +1082,17 @@
for (unsigned int j = 0; j < loader.scanned_layer_count && count < maxLayerCount; j++) {
lib_name = loader.scanned_layer_names[j];
- if ((handle = dlopen(lib_name, RTLD_LAZY)) == NULL)
+ // Used to call: dlopen(*lib_name, RTLD_LAZY)
+ if ((handle = loader_platform_open_library(lib_name)) == NULL)
continue;
- if ((fpEnumerateLayers = dlsym(handle, "xglEnumerateLayers")) == NULL) {
- //use default layer name based on library name libXGLLayer<name>.so
+ if ((fpEnumerateLayers = loader_platform_get_proc_address(handle, "xglEnumerateLayers")) == NULL) {
+ //use default layer name based on library name XGL_LAYER_LIBRARY_PREFIX<name>.XGL_LIBRARY_SUFFIX
char *pEnd, *cpyStr;
int siz;
- dlclose(handle);
+ loader_platform_close_library(handle);
lib_name = basename(lib_name);
pEnd = strrchr(lib_name, '.');
- siz = pEnd - lib_name - strlen("libXGLLayer") + 1;
+ siz = pEnd - lib_name - strlen(XGL_LAYER_LIBRARY_PREFIX) + 1;
if (pEnd == NULL || siz <= 0)
continue;
cpyStr = malloc(siz);
@@ -1025,7 +1100,7 @@
free(cpyStr);
continue;
}
- strncpy(cpyStr, lib_name + strlen("libXGLLayer"), siz);
+ strncpy(cpyStr, lib_name + strlen(XGL_LAYER_LIBRARY_PREFIX), siz);
cpyStr[siz - 1] = '\0';
if (siz > maxStringSize)
siz = maxStringSize;
@@ -1039,8 +1114,8 @@
uint32_t n;
XGL_RESULT res;
n = (maxStringSize < 256) ? maxStringSize : 256;
- res = fpEnumerateLayers(NULL, 16, n, &cnt, layers, (void *) icd->gpus + gpu_index);
- dlclose(handle);
+ res = fpEnumerateLayers(NULL, 16, n, &cnt, layers, (char *) icd->gpus + gpu_index);
+ loader_platform_close_library(handle);
if (res != XGL_SUCCESS)
continue;
if (cnt + count > maxLayerCount)
diff --git a/loader/loader.h b/loader/loader.h
index 18c05b7..397c5d3 100644
--- a/loader/loader.h
+++ b/loader/loader.h
@@ -30,7 +30,11 @@
#include <xgl.h>
#include <xglDbg.h>
+#if defined(WIN32)
+// FIXME: NEED WINDOWS EQUIVALENT
+#else // WIN32
#include <xglWsiX11Ext.h>
+#endif // WIN32
#include <xglLayer.h>
#if defined(__GNUC__) && __GNUC__ >= 4
# define LOADER_EXPORT __attribute__((visibility("default")))
diff --git a/loader/loader_platform.h b/loader/loader_platform.h
new file mode 100644
index 0000000..a9cd4df
--- /dev/null
+++ b/loader/loader_platform.h
@@ -0,0 +1,238 @@
+/*
+ * XGL
+ *
+ * Copyright (C) 2015 LunarG, Inc.
+ * Copyright 2014 Valve Software
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Ian Elliott <ian@lunarg.com>
+ */
+
+#ifndef LOADER_PLATFORM_H
+#define LOADER_PLATFORM_H
+
+#if defined(__linux__)
+/* Linux-specific common code: */
+
+// Headers:
+//#define _GNU_SOURCE 1
+// TBD: Are the contents of the following file used?
+#include <unistd.h>
+// Note: The following file is for dynamic loading:
+#include <dlfcn.h>
+#include <pthread.h>
+#include <assert.h>
+
+// C99:
+#define STATIC_INLINE static inline
+
+// Dynamic Loading:
+typedef void * loader_platform_dl_handle;
+static inline loader_platform_dl_handle loader_platform_open_library(const char* libPath)
+{
+ // NOTE: The prior (Linux only) loader code always used RTLD_LAZY. In one
+ // place, it used RTLD_DEEPBIND. It probably doesn't hurt to always use
+ // RTLD_DEEPBIND, and so that is what is being done.
+ return dlopen(libPath, RTLD_LAZY | RTLD_DEEPBIND | RTLD_LOCAL);
+}
+static inline char * loader_platform_open_library_error(const char* libPath)
+{
+ return dlerror();
+}
+static inline void loader_platform_close_library(loader_platform_dl_handle library)
+{
+ dlclose(library);
+}
+static inline void * loader_platform_get_proc_address(loader_platform_dl_handle library,
+ const char *name)
+{
+ assert(library);
+ assert(name);
+ return dlsym(library, name);
+}
+static inline char * loader_platform_get_proc_address_error(const char *name)
+{
+ return dlerror();
+}
+
+// Threads:
+typedef pthread_t loader_platform_thread;
+#define LOADER_PLATFORM_THREAD_ONCE_DECLARATION(var) \
+ pthread_once_t var = PTHREAD_ONCE_INIT;
+static inline void loader_platform_thread_once(void *ctl, void (* func) (void))
+{
+ assert(func != NULL);
+ assert(ctl != NULL);
+ pthread_once((pthread_once_t *) ctl, func);
+}
+
+// Thread IDs:
+typedef pthread_t loader_platform_thread_id;
+static inline loader_platform_thread_id loader_platform_get_thread_id()
+{
+ return pthread_self();
+}
+
+// Thread mutex:
+typedef pthread_mutex_t loader_platform_thread_mutex;
+static inline void loader_platform_thread_create_mutex(loader_platform_thread_mutex* pMutex)
+{
+ pthread_mutex_init(pMutex, NULL);
+}
+static inline void loader_platform_thread_lock_mutex(loader_platform_thread_mutex* pMutex)
+{
+ pthread_mutex_lock(pMutex);
+}
+static inline void loader_platform_thread_unlock_mutex(loader_platform_thread_mutex* pMutex)
+{
+ pthread_mutex_unlock(pMutex);
+}
+static inline void loader_platform_thread_delete_mutex(loader_platform_thread_mutex* pMutex)
+{
+ pthread_mutex_destroy(pMutex);
+}
+
+
+#elif defined(_WIN32) // defined(__linux__)
+/* Windows-specific common code: */
+
+// Headers:
+#include <windows.h>
+#include <assert.h>
+#ifdef __cplusplus
+#include <iostream>
+#include <string>
+using namespace std;
+#endif // __cplusplus
+
+// C99:
+// Microsoft didn't implement C99 in Visual Studio; but started adding it with
+// VS2013. However, VS2013 still didn't have snprintf(). The following is a
+// work-around.
+#define snprintf _snprintf
+#define STATIC_INLINE static
+// Microsoft also doesn't have basename(). Paths are different on Windows, and
+// so this is just a temporary solution in order to get us compiling, so that we
+// can test some scenarios, and develop the correct solution for Windows.
+ // TODO: Develop a better, permanent solution for Windows, to replace this
+ // temporary code:
+static char *basename(char *pathname)
+{
+ char *current, *next;
+
+#define DIRECTORY_SYMBOL '\\'
+
+// TODO/TBD: Do we need to deal with the Windows's ":" character?
+
+ for (current = pathname; *current != '\0'; current = next) {
+ next = strchr(current, DIRECTORY_SYMBOL);
+ if (next == NULL) {
+ // No more DIRECTORY_SYMBOL's so return p:
+ return current;
+ } else {
+ // Point one character past the DIRECTORY_SYMBOL:
+ next++;
+ }
+ }
+}
+
+// Dynamic Loading:
+typedef HMODULE loader_platform_dl_handle;
+static loader_platform_dl_handle loader_platform_open_library(const char* libPath)
+{
+ return LoadLibrary(libPath);
+}
+static char * loader_platform_open_library_error(const char* libPath)
+{
+ static char errorMsg[120];
+ snprintf(errorMsg, 119, "Failed to open dynamic library \"%s\"", libPath);
+ return errorMsg;
+}
+static void loader_platform_close_library(loader_platform_dl_handle library)
+{
+ FreeLibrary(library);
+}
+static void * loader_platform_get_proc_address(loader_platform_dl_handle library,
+ const char *name)
+{
+ assert(library);
+ assert(name);
+ return GetProcAddress(library, name);
+}
+static char * loader_platform_get_proc_address_error(const char *name)
+{
+ static char errorMsg[120];
+ snprintf(errorMsg, 119, "Failed to find function \"%s\" in dynamic library", name);
+ return errorMsg;
+}
+
+// Threads:
+typedef HANDLE loader_platform_thread;
+#define LOADER_PLATFORM_THREAD_ONCE_DECLARATION(var) \
+ INIT_ONCE var = INIT_ONCE_STATIC_INIT;
+static void loader_platform_thread_once(void *ctl, void (* func) (void))
+{
+ assert(func != NULL);
+ assert(ctl != NULL);
+ InitOnceExecuteOnce((PINIT_ONCE) ctl, (PINIT_ONCE_FN) func, NULL, NULL);
+}
+
+// Thread IDs:
+typedef DWORD loader_platform_thread_id;
+static loader_platform_thread_id loader_platform_get_thread_id()
+{
+ return GetCurrentThreadId();
+}
+
+// Thread mutex:
+typedef CRITICAL_SECTION loader_platform_thread_mutex;
+static void loader_platform_thread_create_mutex(loader_platform_thread_mutex* pMutex)
+{
+ InitializeCriticalSection(pMutex);
+}
+static void loader_platform_thread_lock_mutex(loader_platform_thread_mutex* pMutex)
+{
+ EnterCriticalSection(pMutex);
+}
+static void loader_platform_thread_unlock_mutex(loader_platform_thread_mutex* pMutex)
+{
+ LeaveCriticalSection(pMutex);
+}
+static void loader_platform_thread_delete_mutex(loader_platform_thread_mutex* pMutex)
+{
+ DeleteCriticalSection(pMutex);
+}
+
+#else // defined(_WIN32)
+
+#error The "loader_platform.h" file must be modified for this OS.
+
+// NOTE: In order to support another OS, an #elif needs to be added (above the
+// "#else // defined(_WIN32)") for that OS, and OS-specific versions of the
+// contents of this file must be created.
+
+// NOTE: Other OS-specific changes are also needed for this OS. Search for
+// files with "WIN32" in it, as a quick way to find files that must be changed.
+
+#endif // defined(_WIN32)
+
+#endif /* LOADER_PLATFORM_H */