loader: Windows now uses registry + env's (diff names)
authorIan Elliott <ian@LunarG.com>
Tue, 17 Feb 2015 17:33:47 +0000 (10:33 -0700)
committerIan Elliott <ian@LunarG.com>
Wed, 18 Feb 2015 22:46:37 +0000 (15:46 -0700)
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
loader/loader.c
loader/loader_platform.h

index 143cf9c..eb16234 100644 (file)
--- 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.
index 9a5312f..3db03e6 100644 (file)
@@ -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),
+                                        &registry_value_type,
+                                        (PVOID) registry_str,
+                                        &registry_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),
+                                            &registry_value_type,
+                                            (PVOID) registry_str,
+                                            &registry_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) {
index dc0fa5c..9686b65 100644 (file)
@@ -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