From 225188f4c4d96832f1669f7dc958f8a6f2bdccc0 Mon Sep 17 00:00:00 2001 From: Ian Elliott Date: Tue, 17 Feb 2015 10:33:47 -0700 Subject: [PATCH] loader: Windows now uses registry + env's (diff names) The loader on Windows now looks in the Windows Registry + in environment variables for the following (Note the new names--"LIB" was dropped): - XGL_DRIVERS_PATH - XGL_LAYERS_PATH - XGL_LAYER_NAMES Linux still retains the "LIB" at the start of the environment variable names. If both are used, they are concatenated into a semi-colon-delimited list. A generic loader_get_registry_and_env() func is used to perform this (only for Windows, since Linux doesn't have a registry). --- BUILD.md | 36 ++++++--- loader/loader.c | 189 +++++++++++++++++++++++++++++++++++------------ loader/loader_platform.h | 9 +++ 3 files changed, 175 insertions(+), 59 deletions(-) diff --git a/BUILD.md b/BUILD.md index 143cf9c..eb16234 100644 --- a/BUILD.md +++ b/BUILD.md @@ -152,28 +152,40 @@ At this point, you can use Windows Explorer to launch Visual Studio by double-cl XGL programs must be able to find and use the XGL.dll libary. Make sure it is either installed in the C:\Windows\System32 folder, or the PATH enviroment variable includes the folder that it is located in. -To run XGL programs you must have an appropriate icd (installable client driver) that is either installed in the C:\Windows\System32 folder, or pointed to by the -environment variable LIBXGL_DRIVERS_PATH. This environment variable cannot be set with Cygwin, but must be set via Windows, and may require a system restart in order for it to take effect. Here is how to set this environment variable on a Windows 7 system: +To run XGL programs you must have an appropriate icd (installable client driver) that is either installed in the C:\Windows\System32 folder, or pointed to by the registry and/or an environment variable: + +- Registry: + - Root Key: HKEY_LOCAL_MACHINE + - Key: "System\XGL" + - Value: "XGL_DRIVERS_PATH" (semi-colon-delimited set of folders to look for ICDs) +- Environment Variable: "XGL_DRIVERS_PATH" (semi-colon-delimited set of folders to look for ICDs) + +Note: If both the registry value and environment variable are used, they are concatenated into a new semi-colon-delimited list of folders. + +Note: Environment variables on Windows cannot be set with Cygwin, but must be set via the Windows Control Panel, and generally require a system restart in order to take effect. Here is how to set this environment variable on a Windows 7 system: - Launch Control Panel (e.g. Start->Control Panel) - Within the search box, type "environment variable" and click on "Edit the system environment variables" (or navigate there via "System and Security->System->Advanced system settings"). - This will launch a window with several tabs, one of which is "Advanced". Click on the "Environment Variables..." button. - For either "User variables" or "System variables" click "New...". -- Enter "LIBXGL_DRIVERS_PATH" as the variable name, and an appropriate Windows path to where your driver DLL is (e.g. C:\Users\username\GL-Next\_out64\icd\drivername\Debug). +- Enter "XGL_DRIVERS_PATH" as the variable name, and an appropriate Windows path to where your driver DLL is (e.g. C:\Users\username\GL-Next\_out64\icd\drivername\Debug). It is possible to specify multiple icd folders. Simply use a semi-colon (i.e. ";") to separate folders in the environment variable. The icd loader searches in all of the folders for files that are named "XGL_*.dll" (e.g. "XGL_foo.dll"). It attempts to dynamically load these files, and look for appropriate functions. To enable debug and validation layers with your XGL programs you must tell the icd loader -where to find the layer libraries, and which ones you desire to use. The default folder for layers is C:\Windows\System32. However, you can use the following environment variables to specify alternate locations, and to specify which layers to use: - -- LIBXGL_LAYERS_PATH (semi-colon-delimited set of folders to look for layers) -- LIBXGL_LAYER_NAMES (color-delimited list of layer names) - -For example, to enable the APIDump and DrawState layers, set: - -- "LIBXGL_LAYERS_PATH" to "C:\Users\username\GL-Next\_out64\layers\Debug" -- "LIBXGL_LAYER_NAMES to "APIDump:DrawState" +where to find the layer libraries, and which ones you desire to use. The default folder for layers is C:\Windows\System32. Again, this can be pointed to by the registry and/or an environment variable: + +- Registry: + - Root Key: HKEY_LOCAL_MACHINE + - Key: "System\XGL" + - Value: "XGL_LAYERS_PATH" (semi-colon-delimited set of folders to look for layers) + - Value: "XGL_LAYER_NAMES" (semi-colon-delimited list of layer names) +- Environment Variables: + - "XGL_LAYERS_PATH" (semi-colon-delimited set of folders to look for layers) + - "XGL_LAYER_NAMES" (semi-colon-delimited list of layer names) + +Note: If both the registry value and environment variable are used, they are concatenated into a new semi-colon-delimited list. The icd loader searches in all of the folders for files that are named "XGLLayer*.dll" (e.g. "XGLLayerParamChecker.dll"). It attempts to dynamically load these files, and look for appropriate functions. diff --git a/loader/loader.c b/loader/loader.c index 9a5312f..3db03e6 100644 --- a/loader/loader.c +++ b/loader/loader.c @@ -111,6 +111,70 @@ static struct { } loader; +#if defined(WIN32) +// For ICD developers, look in the registry, and look for an environment +// variable for a path(s) where to find the ICD(s): +static char *loader_get_registry_and_env(const char *env_var, + const char *registry_value) +{ + char *env_str = getenv(env_var); + size_t env_len = (env_str == NULL) ? 0 : strlen(env_str); +#define INITIAL_STR_LEN 1024 + char *registry_str = malloc(INITIAL_STR_LEN); + DWORD registry_len = INITIAL_STR_LEN; + DWORD registry_value_type; + LONG registry_return_value; + char *rtn_str = NULL; + size_t rtn_len; + + registry_return_value = RegGetValue(HKEY_LOCAL_MACHINE, "Software\\XGL", + registry_value, + (RRF_RT_REG_SZ | RRF_ZEROONFAILURE), + ®istry_value_type, + (PVOID) registry_str, + ®istry_len); + + if (registry_return_value == ERROR_MORE_DATA) { + registry_str = realloc(registry_str, registry_len); + registry_return_value = RegGetValue(HKEY_LOCAL_MACHINE, "Software\\XGL", + registry_value, + (RRF_RT_REG_SZ | RRF_ZEROONFAILURE), + ®istry_value_type, + (PVOID) registry_str, + ®istry_len); + } + + rtn_len = env_len + registry_len + 1; + if (rtn_len <= 2) { + // We found neither the desired registry value, nor the environment + // variable; return NULL: + return NULL; + } else { + // We found something, and so we need to allocate memory for the string + // to return: + rtn_str = malloc(rtn_len); + } + + if (registry_return_value != ERROR_SUCCESS) { + // We didn't find the desired registry value, and so we must have found + // only the environment variable: + _snprintf(rtn_str, rtn_len, "%s", env_str); + } else if (env_str != NULL) { + // We found both the desired registry value and the environment + // variable, so concatenate them both: + _snprintf(rtn_str, rtn_len, "%s;%s", registry_str, env_str); + } else { + // We must have only found the desired registry value: + _snprintf(rtn_str, rtn_len, "%s", registry_str); + } + + free(registry_str); + + return(rtn_str); +} +#endif // WIN32 + + static XGL_RESULT loader_msg_callback_add(XGL_DBG_MSG_CALLBACK_FUNCTION func, void *data) { @@ -355,24 +419,32 @@ static void loader_scanned_icd_add(const char *filename) */ static void loader_icd_scan(void) { - const char *libPaths, *p, *next; + const char *p, *next; + char *libPaths = NULL; DIR *sysdir; struct dirent *dent; char icd_library[1024]; char path[1024]; uint32_t len; - - libPaths = NULL; -#if !defined(WIN32) +#if defined(WIN32) + bool must_free_libPaths; + libPaths = loader_get_registry_and_env(DRIVER_PATH_ENV, + DRIVER_PATH_REGISTRY_VALUE); + if (libPaths != NULL) { + must_free_libPaths = true; + } else { + must_free_libPaths = false; + libPaths = DEFAULT_XGL_DRIVERS_PATH; + } +#else // WIN32 if (geteuid() == getuid()) { - /* Don't allow setuid apps to use LIBXGL_DRIVERS_PATH */ -#endif // WIN32 - libPaths = getenv("LIBXGL_DRIVERS_PATH"); -#if !defined(WIN32) + /* Don't allow setuid apps to use the DRIVER_PATH_ENV env var: */ + libPaths = getenv(DRIVER_PATH_ENV); + } + if (libPaths == NULL) { + libPaths = DEFAULT_XGL_DRIVERS_PATH; } #endif // WIN32 - if (libPaths == NULL) - libPaths = DEFAULT_XGL_DRIVERS_PATH; for (p = libPaths; *p; p = next) { next = strchr(p, PATH_SEPERATOR); @@ -416,52 +488,67 @@ static void loader_icd_scan(void) } } +#if defined(WIN32) + // Free any allocated memory: + if (must_free_libPaths) { + free(libPaths); + } +#endif // WIN32 + + // Note that we've scanned for ICDs: loader.icds_scanned = true; } -static void layer_lib_scan_path(const char * libInPaths) +static void layer_lib_scan(void) { const char *p, *next; - char *libPaths; + char *libPaths = NULL; DIR *curdir; struct dirent *dent; - uint32_t len, i; + size_t len, i; char temp_str[1024]; - len = 0; - loader.layer_dirs = NULL; - if (libInPaths){ - len = (uint32_t) strlen(libInPaths); - p = libInPaths; +#if defined(WIN32) + bool must_free_libPaths; + libPaths = loader_get_registry_and_env(LAYERS_PATH_ENV, + LAYERS_PATH_REGISTRY_VALUE); + if (libPaths != NULL) { + must_free_libPaths = true; + } else { + must_free_libPaths = false; + libPaths = DEFAULT_XGL_LAYERS_PATH; } - else { -#if !defined(WIN32) - if (geteuid() == getuid()) { -#endif // WIN32 - p = getenv("LIBXGL_LAYERS_PATH"); - if (p != NULL) - len = (uint32_t) strlen(p); -#if !defined(WIN32) - } -#endif // WIN32 +#else // WIN32 + if (geteuid() == getuid()) { + /* Don't allow setuid apps to use the DRIVER_PATH_ENV env var: */ + libPaths = getenv(DRIVER_PATH_ENV); } - - if (len == 0) { - len = (uint32_t) strlen(DEFAULT_XGL_LAYERS_PATH); - p = DEFAULT_XGL_LAYERS_PATH; + if (libPaths == NULL) { + libPaths = DEFAULT_XGL_LAYERS_PATH; } +#endif // WIN32 - if (len == 0) { - // Have no paths to search + if (libPaths == NULL) { + // Have no paths to search: return; } + len = strlen(libPaths); loader.layer_dirs = malloc(len+1); - if (loader.layer_dirs == NULL) + if (loader.layer_dirs == NULL) { + free(libPaths); return; - - // Alloc passed, so we know there is enough space to hold the string, don't need strncpy - strcpy(loader.layer_dirs, p); + } + // Alloc passed, so we know there is enough space to hold the string, don't + // need strncpy + strcpy(loader.layer_dirs, libPaths); +#if defined(WIN32) + // Free any allocated memory: + if (must_free_libPaths) { + free(libPaths); + must_free_libPaths = false; + } +#endif // WIN32 libPaths = loader.layer_dirs; /* cleanup any previously scanned libraries */ @@ -530,11 +617,6 @@ static void layer_lib_scan_path(const char * libInPaths) loader.layer_scanned = true; } -static void layer_lib_scan(void) -{ - layer_lib_scan_path(NULL); -} - static void loader_init_dispatch_table(XGL_LAYER_DISPATCH_TABLE *tab, xglGetProcAddrType fpGPA, XGL_PHYSICAL_GPU gpu) { loader_initialize_dispatch_table(tab, fpGPA, gpu); @@ -648,17 +730,30 @@ static bool find_layer_name(struct loader_icd *icd, uint32_t gpu_index, const ch static uint32_t loader_get_layer_env(struct loader_icd *icd, uint32_t gpu_index, struct layer_name_pair *pLayerNames) { - const char *layerEnv; + char *layerEnv; uint32_t len, count = 0; char *p, *pOrig, *next, *name; - layerEnv = getenv("LIBXGL_LAYER_NAMES"); - if (!layerEnv) +#if defined(WIN32) + layerEnv = loader_get_registry_and_env(LAYER_NAMES_ENV, + LAYER_NAMES_REGISTRY_VALUE); +#else // WIN32 + layerEnv = getenv(LAYER_NAMES_ENV); +#endif // WIN32 + if (layerEnv == NULL) { return 0; + } p = malloc(strlen(layerEnv) + 1); - if (!p) + if (p == NULL) { +#if defined(WIN32) + free(layerEnv); +#endif // WIN32 return 0; + } strcpy(p, layerEnv); +#if defined(WIN32) + free(layerEnv); +#endif // WIN32 pOrig = p; while (p && *p && count < MAX_LAYER_LIBRARIES) { diff --git a/loader/loader_platform.h b/loader/loader_platform.h index dc0fa5c..9686b65 100644 --- a/loader/loader_platform.h +++ b/loader/loader_platform.h @@ -45,6 +45,9 @@ // XGL Library Filenames, Paths, etc.: #define PATH_SEPERATOR ':' #define DIRECTORY_SYMBOL "/" +#define DRIVER_PATH_ENV "LIBXGL_DRIVERS_PATH" +#define LAYERS_PATH_ENV "LIBXGL_LAYERS_PATH" +#define LAYER_NAMES_ENV "LIBXGL_LAYER_NAMES" #ifndef DEFAULT_XGL_DRIVERS_PATH // TODO: Is this a good default location? // Need to search for both 32bit and 64bit ICDs @@ -146,6 +149,12 @@ using namespace std; // XGL Library Filenames, Paths, etc.: #define PATH_SEPERATOR ';' #define DIRECTORY_SYMBOL "\\" +#define DRIVER_PATH_REGISTRY_VALUE "XGL_DRIVERS_PATH" +#define LAYERS_PATH_REGISTRY_VALUE "XGL_LAYERS_PATH" +#define LAYER_NAMES_REGISTRY_VALUE "XGL_LAYER_NAMES" +#define DRIVER_PATH_ENV "XGL_DRIVERS_PATH" +#define LAYERS_PATH_ENV "XGL_LAYERS_PATH" +#define LAYER_NAMES_ENV "XGL_LAYER_NAMES" #ifndef DEFAULT_XGL_DRIVERS_PATH // TODO: Is this a good default location? // Need to search for both 32bit and 64bit ICDs -- 2.7.4