diff options
| author | Ian Elliott <ian@LunarG.com> | 2015-01-13 17:52:38 -0700 |
|---|---|---|
| committer | Courtney Goeltzenleuchter <courtney@LunarG.com> | 2015-02-04 17:58:11 -0700 |
| commit | 08dd2294cf50d9282134bcf968d9f2eb0e3abd67 (patch) | |
| tree | c663dad2b00a96460a938ab893cde6ec895b0318 /loader | |
| parent | 50aeba51c159d41c3f3ccfbdd7edb7b5e5e0b162 (diff) | |
| download | usermoji-08dd2294cf50d9282134bcf968d9f2eb0e3abd67.tar.xz | |
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).
Diffstat (limited to 'loader')
| -rw-r--r-- | loader/CMakeLists.txt | 7 | ||||
| -rw-r--r-- | loader/dirent_on_windows.c | 148 | ||||
| -rw-r--r-- | loader/dirent_on_windows.h | 50 | ||||
| -rw-r--r-- | loader/loader.c | 227 | ||||
| -rw-r--r-- | loader/loader.h | 4 | ||||
| -rw-r--r-- | loader/loader_platform.h | 238 |
6 files changed, 597 insertions, 77 deletions
diff --git a/loader/CMakeLists.txt b/loader/CMakeLists.txt index b2250ad0..13a4b5b7 100644 --- a/loader/CMakeLists.txt +++ b/loader/CMakeLists.txt @@ -13,6 +13,11 @@ include_directories( 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 00000000..3564a26f --- /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 00000000..a02a0d82 --- /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 0aa29406..c4cdce02 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_instance { }; struct loader_layers { - void *lib_handle; + loader_platform_dl_handle lib_handle; char name[256]; }; @@ -79,7 +80,7 @@ struct loader_msg_callback { }; struct loader_scanned_icds { - void *handle; + loader_platform_dl_handle handle; xglGetProcAddrType GetProcAddr; xglCreateInstanceType CreateInstance; xglDestroyInstanceType DestroyInstance; @@ -105,6 +106,7 @@ static struct { 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_log(XGL_DBG_MSG_TYPE msg_type, int32_t msg_code, 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 struct loader_icd *loader_icd_add(struct loader_instance *ptr_inst, 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 @@ static void loader_scanned_icd_add(const char *filename) 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 @@ static void loader_icd_scan(void) 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 @@ static void loader_icd_scan(void) 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 @@ static void loader_icd_scan(void) } } - 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 @@ static void layer_lib_scan_path(const char * libInPaths) 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 @@ static void layer_lib_scan_path(const char * libInPaths) 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 @@ static void layer_lib_scan_path(const char * libInPaths) 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 @@ static void loader_init_layer_libs(struct loader_icd *icd, uint32_t gpu_index, s 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 void loader_init_layer_libs(struct loader_icd *icd, uint32_t gpu_index, s 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 @@ static bool find_layer_name(struct loader_icd *icd, uint32_t gpu_index, const ch 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 @@ static bool find_layer_name(struct loader_icd *icd, uint32_t gpu_index, const ch } 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 @@ static uint32_t loader_get_layer_env(struct loader_icd *icd, uint32_t gpu_index, 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 @@ static void loader_deactivate_layer(const struct loader_instance *instance) 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 @@ extern uint32_t loader_activate_layers(XGL_PHYSICAL_GPU gpu, const XGL_DEVICE_CR 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 @@ LOADER_EXPORT XGL_RESULT XGLAPI xglCreateInstance( 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 XGL_RESULT XGLAPI xglEnumerateGpus( 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 @@ LOADER_EXPORT XGL_RESULT XGLAPI xglEnumerateLayers(XGL_PHYSICAL_GPU gpu, size_t 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 @@ LOADER_EXPORT XGL_RESULT XGLAPI xglEnumerateLayers(XGL_PHYSICAL_GPU gpu, size_t 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 @@ LOADER_EXPORT XGL_RESULT XGLAPI xglEnumerateLayers(XGL_PHYSICAL_GPU gpu, size_t 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 @@ LOADER_EXPORT XGL_RESULT XGLAPI xglEnumerateLayers(XGL_PHYSICAL_GPU gpu, size_t 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 18c05b73..397c5d3e 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 00000000..a9cd4df1 --- /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 */ |
