Home | History | Annotate | Download | only in loader
      1 /*
      2  *
      3  * Copyright (c) 2015-2018 The Khronos Group Inc.
      4  * Copyright (c) 2015-2018 Valve Corporation
      5  * Copyright (c) 2015-2018 LunarG, Inc.
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *     http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  *
     19  * Author: Ian Elliot <ian (at) lunarg.com>
     20  * Author: Jon Ashburn <jon (at) lunarg.com>
     21  * Author: Lenny Komow <lenny (at) lunarg.com>
     22  *
     23  */
     24 #pragma once
     25 
     26 #if defined(_WIN32)
     27 // WinSock2.h must be included *BEFORE* windows.h
     28 #include <WinSock2.h>
     29 #endif  // _WIN32
     30 
     31 #include "vulkan/vk_platform.h"
     32 #include "vulkan/vk_sdk_platform.h"
     33 
     34 #if defined(__linux__)
     35 /* Linux-specific common code: */
     36 
     37 // Headers:
     38 //#define _GNU_SOURCE 1
     39 // TBD: Are the contents of the following file used?
     40 #include <unistd.h>
     41 // Note: The following file is for dynamic loading:
     42 #include <dlfcn.h>
     43 #include <pthread.h>
     44 #include <assert.h>
     45 #include <string.h>
     46 #include <stdbool.h>
     47 #include <stdlib.h>
     48 #include <libgen.h>
     49 
     50 // VK Library Filenames, Paths, etc.:
     51 #define PATH_SEPARATOR ':'
     52 #define DIRECTORY_SYMBOL '/'
     53 
     54 #define VULKAN_DIR "/vulkan/"
     55 #define VULKAN_ICDCONF_DIR "icd.d"
     56 #define VULKAN_ICD_DIR "icd"
     57 #define VULKAN_ELAYERCONF_DIR "explicit_layer.d"
     58 #define VULKAN_ILAYERCONF_DIR "implicit_layer.d"
     59 #define VULKAN_LAYER_DIR "layer"
     60 
     61 #define DEFAULT_VK_DRIVERS_INFO ""
     62 #define DEFAULT_VK_ELAYERS_INFO ""
     63 #define DEFAULT_VK_ILAYERS_INFO ""
     64 
     65 #define DEFAULT_VK_DRIVERS_PATH ""
     66 #if !defined(DEFAULT_VK_LAYERS_PATH)
     67 #define DEFAULT_VK_LAYERS_PATH ""
     68 #endif
     69 
     70 #if !defined(LAYERS_SOURCE_PATH)
     71 #define LAYERS_SOURCE_PATH NULL
     72 #endif
     73 #define LAYERS_PATH_ENV "VK_LAYER_PATH"
     74 #define ENABLED_LAYERS_ENV "VK_INSTANCE_LAYERS"
     75 
     76 #define RELATIVE_VK_DRIVERS_INFO VULKAN_DIR VULKAN_ICDCONF_DIR
     77 #define RELATIVE_VK_ELAYERS_INFO VULKAN_DIR VULKAN_ELAYERCONF_DIR
     78 #define RELATIVE_VK_ILAYERS_INFO VULKAN_DIR VULKAN_ILAYERCONF_DIR
     79 
     80 // C99:
     81 #define PRINTF_SIZE_T_SPECIFIER "%zu"
     82 
     83 // File IO
     84 static inline bool loader_platform_file_exists(const char *path) {
     85     if (access(path, F_OK))
     86         return false;
     87     else
     88         return true;
     89 }
     90 
     91 static inline bool loader_platform_is_path_absolute(const char *path) {
     92     if (path[0] == '/')
     93         return true;
     94     else
     95         return false;
     96 }
     97 
     98 static inline char *loader_platform_dirname(char *path) { return dirname(path); }
     99 
    100 // Dynamic Loading of libraries:
    101 typedef void *loader_platform_dl_handle;
    102 static inline loader_platform_dl_handle loader_platform_open_library(const char *libPath) {
    103     // When loading the library, we use RTLD_LAZY so that not all symbols have to be
    104     // resolved at this time (which improves performance). Note that if not all symbols
    105     // can be resolved, this could cause crashes later. Use the LD_BIND_NOW environment
    106     // variable to force all symbols to be resolved here.
    107     return dlopen(libPath, RTLD_LAZY | RTLD_LOCAL);
    108 }
    109 static inline const char *loader_platform_open_library_error(const char *libPath) { return dlerror(); }
    110 static inline void loader_platform_close_library(loader_platform_dl_handle library) { dlclose(library); }
    111 static inline void *loader_platform_get_proc_address(loader_platform_dl_handle library, const char *name) {
    112     assert(library);
    113     assert(name);
    114     return dlsym(library, name);
    115 }
    116 static inline const char *loader_platform_get_proc_address_error(const char *name) { return dlerror(); }
    117 
    118 // Threads:
    119 typedef pthread_t loader_platform_thread;
    120 #define THREAD_LOCAL_DECL __thread
    121 
    122 // The once init functionality is not used on Linux
    123 #define LOADER_PLATFORM_THREAD_ONCE_DECLARATION(var)
    124 #define LOADER_PLATFORM_THREAD_ONCE_DEFINITION(var)
    125 #define LOADER_PLATFORM_THREAD_ONCE(ctl, func)
    126 
    127 // Thread IDs:
    128 typedef pthread_t loader_platform_thread_id;
    129 static inline loader_platform_thread_id loader_platform_get_thread_id() { return pthread_self(); }
    130 
    131 // Thread mutex:
    132 typedef pthread_mutex_t loader_platform_thread_mutex;
    133 static inline void loader_platform_thread_create_mutex(loader_platform_thread_mutex *pMutex) { pthread_mutex_init(pMutex, NULL); }
    134 static inline void loader_platform_thread_lock_mutex(loader_platform_thread_mutex *pMutex) { pthread_mutex_lock(pMutex); }
    135 static inline void loader_platform_thread_unlock_mutex(loader_platform_thread_mutex *pMutex) { pthread_mutex_unlock(pMutex); }
    136 static inline void loader_platform_thread_delete_mutex(loader_platform_thread_mutex *pMutex) { pthread_mutex_destroy(pMutex); }
    137 typedef pthread_cond_t loader_platform_thread_cond;
    138 static inline void loader_platform_thread_init_cond(loader_platform_thread_cond *pCond) { pthread_cond_init(pCond, NULL); }
    139 static inline void loader_platform_thread_cond_wait(loader_platform_thread_cond *pCond, loader_platform_thread_mutex *pMutex) {
    140     pthread_cond_wait(pCond, pMutex);
    141 }
    142 static inline void loader_platform_thread_cond_broadcast(loader_platform_thread_cond *pCond) { pthread_cond_broadcast(pCond); }
    143 
    144 #define loader_stack_alloc(size) alloca(size)
    145 
    146 #elif defined(_WIN32)  // defined(__linux__)
    147 /* Windows-specific common code: */
    148 // WinBase.h defines CreateSemaphore and synchapi.h defines CreateEvent
    149 //  undefine them to avoid conflicts with VkLayerDispatchTable struct members.
    150 #ifdef CreateSemaphore
    151 #undef CreateSemaphore
    152 #endif
    153 #ifdef CreateEvent
    154 #undef CreateEvent
    155 #endif
    156 #include <assert.h>
    157 #include <stdio.h>
    158 #include <string.h>
    159 #include <io.h>
    160 #include <stdbool.h>
    161 #include <shlwapi.h>
    162 #ifdef __cplusplus
    163 #include <iostream>
    164 #include <string>
    165 #endif  // __cplusplus
    166 
    167 // VK Library Filenames, Paths, etc.:
    168 #define PATH_SEPARATOR ';'
    169 #define DIRECTORY_SYMBOL '\\'
    170 #define DEFAULT_VK_REGISTRY_HIVE HKEY_LOCAL_MACHINE
    171 #define DEFAULT_VK_REGISTRY_HIVE_STR "HKEY_LOCAL_MACHINE"
    172 #define SECONDARY_VK_REGISTRY_HIVE HKEY_CURRENT_USER
    173 #define SECONDARY_VK_REGISTRY_HIVE_STR "HKEY_CURRENT_USER"
    174 #define DEFAULT_VK_DRIVERS_INFO "SOFTWARE\\Khronos\\" API_NAME "\\Drivers"
    175 #define DEFAULT_VK_DRIVERS_PATH ""
    176 #define DEFAULT_VK_ELAYERS_INFO "SOFTWARE\\Khronos\\" API_NAME "\\ExplicitLayers"
    177 #define DEFAULT_VK_ILAYERS_INFO "SOFTWARE\\Khronos\\" API_NAME "\\ImplicitLayers"
    178 #if !defined(DEFAULT_VK_LAYERS_PATH)
    179 #define DEFAULT_VK_LAYERS_PATH ""
    180 #endif
    181 #if !defined(LAYERS_SOURCE_PATH)
    182 #define LAYERS_SOURCE_PATH NULL
    183 #endif
    184 #define LAYERS_PATH_ENV "VK_LAYER_PATH"
    185 #define ENABLED_LAYERS_ENV "VK_INSTANCE_LAYERS"
    186 #define RELATIVE_VK_DRIVERS_INFO ""
    187 #define RELATIVE_VK_ELAYERS_INFO ""
    188 #define RELATIVE_VK_ILAYERS_INFO ""
    189 #define PRINTF_SIZE_T_SPECIFIER "%Iu"
    190 
    191 #if defined(_WIN32)
    192 // Get the key for the plug n play driver registry
    193 // The string returned by this function should NOT be freed
    194 static inline const char *LoaderPnpDriverRegistry() {
    195     BOOL is_wow;
    196     IsWow64Process(GetCurrentProcess(), &is_wow);
    197     return is_wow ? (API_NAME "DriverNameWow") : (API_NAME "DriverName");
    198 }
    199 
    200 // Get the key for the plug 'n play explicit layer registry
    201 // The string returned by this function should NOT be freed
    202 static inline const char *LoaderPnpELayerRegistry() {
    203     BOOL is_wow;
    204     IsWow64Process(GetCurrentProcess(), &is_wow);
    205     return is_wow ? (API_NAME "ExplicitLayersWow") : (API_NAME "ExplicitLayers");
    206 }
    207 // Get the key for the plug 'n play implicit layer registry
    208 // The string returned by this function should NOT be freed
    209 
    210 static inline const char *LoaderPnpILayerRegistry() {
    211     BOOL is_wow;
    212     IsWow64Process(GetCurrentProcess(), &is_wow);
    213     return is_wow ? (API_NAME "ImplicitLayersWow") : (API_NAME "ImplicitLayers");
    214 }
    215 #endif
    216 
    217 // File IO
    218 static bool loader_platform_file_exists(const char *path) {
    219     if ((_access(path, 0)) == -1)
    220         return false;
    221     else
    222         return true;
    223 }
    224 
    225 static bool loader_platform_is_path_absolute(const char *path) {
    226     if (!path || !*path) {
    227         return false;
    228     }
    229     if (*path == DIRECTORY_SYMBOL || path[1] == ':') {
    230         return true;
    231     }
    232     return false;
    233 }
    234 
    235 // WIN32 runtime doesn't have dirname().
    236 static inline char *loader_platform_dirname(char *path) {
    237     char *current, *next;
    238 
    239     // TODO/TBD: Do we need to deal with the Windows's ":" character?
    240 
    241     for (current = path; *current != '\0'; current = next) {
    242         next = strchr(current, DIRECTORY_SYMBOL);
    243         if (next == NULL) {
    244             if (current != path) *(current - 1) = '\0';
    245             return path;
    246         } else {
    247             // Point one character past the DIRECTORY_SYMBOL:
    248             next++;
    249         }
    250     }
    251     return path;
    252 }
    253 
    254 // WIN32 runtime doesn't have basename().
    255 // Microsoft also doesn't have basename().  Paths are different on Windows, and
    256 // so this is just a temporary solution in order to get us compiling, so that we
    257 // can test some scenarios, and develop the correct solution for Windows.
    258 // TODO: Develop a better, permanent solution for Windows, to replace this
    259 // temporary code:
    260 static char *loader_platform_basename(char *pathname) {
    261     char *current, *next;
    262 
    263     // TODO/TBD: Do we need to deal with the Windows's ":" character?
    264 
    265     for (current = pathname; *current != '\0'; current = next) {
    266         next = strchr(current, DIRECTORY_SYMBOL);
    267         if (next == NULL) {
    268             // No more DIRECTORY_SYMBOL's so return p:
    269             return current;
    270         } else {
    271             // Point one character past the DIRECTORY_SYMBOL:
    272             next++;
    273         }
    274     }
    275     // We shouldn't get to here, but this makes the compiler happy:
    276     return current;
    277 }
    278 
    279 // Dynamic Loading:
    280 typedef HMODULE loader_platform_dl_handle;
    281 static loader_platform_dl_handle loader_platform_open_library(const char *lib_path) {
    282     // Try loading the library the original way first.
    283     loader_platform_dl_handle lib_handle = LoadLibrary(lib_path);
    284     if (lib_handle == NULL && GetLastError() == ERROR_MOD_NOT_FOUND) {
    285         // If that failed, then try loading it with broader search folders.
    286         lib_handle = LoadLibraryEx(lib_path, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
    287     }
    288     return lib_handle;
    289 }
    290 static char *loader_platform_open_library_error(const char *libPath) {
    291     static char errorMsg[164];
    292     (void)snprintf(errorMsg, 163, "Failed to open dynamic library \"%s\" with error %lu", libPath, GetLastError());
    293     return errorMsg;
    294 }
    295 static void loader_platform_close_library(loader_platform_dl_handle library) { FreeLibrary(library); }
    296 static void *loader_platform_get_proc_address(loader_platform_dl_handle library, const char *name) {
    297     assert(library);
    298     assert(name);
    299     return GetProcAddress(library, name);
    300 }
    301 static char *loader_platform_get_proc_address_error(const char *name) {
    302     static char errorMsg[120];
    303     (void)snprintf(errorMsg, 119, "Failed to find function \"%s\" in dynamic library", name);
    304     return errorMsg;
    305 }
    306 
    307 // Threads:
    308 typedef HANDLE loader_platform_thread;
    309 #define THREAD_LOCAL_DECL __declspec(thread)
    310 
    311 // The once init functionality is not used when building a DLL on Windows. This is because there is no way to clean up the
    312 // resources allocated by anything allocated by once init. This isn't a problem for static libraries, but it is for dynamic
    313 // ones. When building a DLL, we use DllMain() instead to allow properly cleaning up resources.
    314 #if defined(LOADER_DYNAMIC_LIB)
    315 #define LOADER_PLATFORM_THREAD_ONCE_DECLARATION(var)
    316 #define LOADER_PLATFORM_THREAD_ONCE_DEFINITION(var)
    317 #define LOADER_PLATFORM_THREAD_ONCE(ctl, func)
    318 #else
    319 #define LOADER_PLATFORM_THREAD_ONCE_DECLARATION(var) INIT_ONCE var = INIT_ONCE_STATIC_INIT;
    320 #define LOADER_PLATFORM_THREAD_ONCE_DEFINITION(var) INIT_ONCE var;
    321 #define LOADER_PLATFORM_THREAD_ONCE(ctl, func) loader_platform_thread_once_fn(ctl, func)
    322 static BOOL CALLBACK InitFuncWrapper(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context) {
    323     void (*func)(void) = (void (*)(void))Parameter;
    324     func();
    325     return TRUE;
    326 }
    327 static void loader_platform_thread_once_fn(void *ctl, void (*func)(void)) {
    328     assert(func != NULL);
    329     assert(ctl != NULL);
    330     InitOnceExecuteOnce((PINIT_ONCE)ctl, InitFuncWrapper, func, NULL);
    331 }
    332 #endif
    333 
    334 // Thread IDs:
    335 typedef DWORD loader_platform_thread_id;
    336 static loader_platform_thread_id loader_platform_get_thread_id() { return GetCurrentThreadId(); }
    337 
    338 // Thread mutex:
    339 typedef CRITICAL_SECTION loader_platform_thread_mutex;
    340 static void loader_platform_thread_create_mutex(loader_platform_thread_mutex *pMutex) { InitializeCriticalSection(pMutex); }
    341 static void loader_platform_thread_lock_mutex(loader_platform_thread_mutex *pMutex) { EnterCriticalSection(pMutex); }
    342 static void loader_platform_thread_unlock_mutex(loader_platform_thread_mutex *pMutex) { LeaveCriticalSection(pMutex); }
    343 static void loader_platform_thread_delete_mutex(loader_platform_thread_mutex *pMutex) { DeleteCriticalSection(pMutex); }
    344 typedef CONDITION_VARIABLE loader_platform_thread_cond;
    345 static void loader_platform_thread_init_cond(loader_platform_thread_cond *pCond) { InitializeConditionVariable(pCond); }
    346 static void loader_platform_thread_cond_wait(loader_platform_thread_cond *pCond, loader_platform_thread_mutex *pMutex) {
    347     SleepConditionVariableCS(pCond, pMutex, INFINITE);
    348 }
    349 static void loader_platform_thread_cond_broadcast(loader_platform_thread_cond *pCond) { WakeAllConditionVariable(pCond); }
    350 
    351 #define loader_stack_alloc(size) _alloca(size)
    352 #else  // defined(_WIN32)
    353 
    354 #error The "loader_platform.h" file must be modified for this OS.
    355 
    356 // NOTE: In order to support another OS, an #elif needs to be added (above the
    357 // "#else // defined(_WIN32)") for that OS, and OS-specific versions of the
    358 // contents of this file must be created.
    359 
    360 // NOTE: Other OS-specific changes are also needed for this OS.  Search for
    361 // files with "WIN32" in it, as a quick way to find files that must be changed.
    362 
    363 #endif  // defined(_WIN32)
    364 
    365 // returns true if the given string appears to be a relative or absolute
    366 // path, as opposed to a bare filename.
    367 static inline bool loader_platform_is_path(const char *path) { return strchr(path, DIRECTORY_SYMBOL) != NULL; }
    368