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