1 /* 2 * 3 * Copyright (c) 2015-2016 The Khronos Group Inc. 4 * Copyright (c) 2015-2016 Valve Corporation 5 * Copyright (c) 2015-2016 LunarG, Inc. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a copy 8 * of this software and/or associated documentation files (the "Materials"), to 9 * deal in the Materials without restriction, including without limitation the 10 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 11 * sell copies of the Materials, and to permit persons to whom the Materials are 12 * furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice(s) and this permission notice shall be included in 15 * all copies or substantial portions of the Materials. 16 * 17 * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 * 21 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 22 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 23 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE 24 * USE OR OTHER DEALINGS IN THE MATERIALS. 25 * 26 * Author: Ian Elliot <ian (at) lunarg.com> 27 * Author: Jon Ashburn <jon (at) lunarg.com> 28 * 29 */ 30 #pragma once 31 32 #if defined(_WIN32) 33 // WinSock2.h must be included *BEFORE* windows.h 34 #include <WinSock2.h> 35 #endif // _WIN32 36 37 #include "vulkan/vk_platform.h" 38 #include "vulkan/vk_sdk_platform.h" 39 40 #if defined(__linux__) 41 /* Linux-specific common code: */ 42 43 // Headers: 44 //#define _GNU_SOURCE 1 45 // TBD: Are the contents of the following file used? 46 #include <unistd.h> 47 // Note: The following file is for dynamic loading: 48 #include <dlfcn.h> 49 #include <pthread.h> 50 #include <assert.h> 51 #include <string.h> 52 #include <stdbool.h> 53 #include <stdlib.h> 54 #include <libgen.h> 55 56 // VK Library Filenames, Paths, etc.: 57 #define PATH_SEPERATOR ':' 58 #define DIRECTORY_SYMBOL '/' 59 60 #define VULKAN_ICDCONF_DIR \ 61 "/" \ 62 "vulkan" \ 63 "/" \ 64 "icd.d" 65 #define VULKAN_ICD_DIR \ 66 "/" \ 67 "vulkan" \ 68 "/" \ 69 "icd" 70 #define VULKAN_ELAYERCONF_DIR \ 71 "/" \ 72 "vulkan" \ 73 "/" \ 74 "explicit_layer.d" 75 #define VULKAN_ILAYERCONF_DIR \ 76 "/" \ 77 "vulkan" \ 78 "/" \ 79 "implicit_layer.d" 80 #define VULKAN_LAYER_DIR \ 81 "/" \ 82 "vulkan" \ 83 "/" \ 84 "layer" 85 86 #if defined(LOCALPREFIX) 87 #define LOCAL_DRIVERS_INFO \ 88 LOCALPREFIX "/" SYSCONFDIR VULKAN_ICDCONF_DIR ":" LOCALPREFIX \ 89 "/" DATADIR VULKAN_ICDCONF_DIR ":" 90 #define LOCAL_ELAYERS_INFO \ 91 LOCALPREFIX "/" SYSCONFDIR VULKAN_ELAYERCONF_DIR ":" LOCALPREFIX \ 92 "/" DATADIR VULKAN_ELAYERCONF_DIR ":" 93 #define LOCAL_ILAYERS_INFO \ 94 LOCALPREFIX "/" SYSCONFDIR VULKAN_ILAYERCONF_DIR ":" LOCALPREFIX \ 95 "/" DATADIR VULKAN_ILAYERCONF_DIR ":" 96 #else 97 #define LOCAL_DRIVERS_INFO 98 #define LOCAL_ELAYERS_INFO 99 #define LOCAL_ILAYERS_INFO 100 #endif 101 102 #define DEFAULT_VK_DRIVERS_INFO \ 103 LOCAL_DRIVERS_INFO \ 104 "/" SYSCONFDIR VULKAN_ICDCONF_DIR ":" \ 105 "/usr/" DATADIR VULKAN_ICDCONF_DIR 106 #define DEFAULT_VK_DRIVERS_PATH "" 107 #define DEFAULT_VK_ELAYERS_INFO \ 108 LOCAL_ELAYERS_INFO \ 109 "/" SYSCONFDIR VULKAN_ELAYERCONF_DIR ":" \ 110 "/usr/" DATADIR VULKAN_ELAYERCONF_DIR 111 #define DEFAULT_VK_ILAYERS_INFO \ 112 LOCAL_ILAYERS_INFO \ 113 "/" SYSCONFDIR VULKAN_ILAYERCONF_DIR ":" \ 114 "/usr/" DATADIR VULKAN_ILAYERCONF_DIR 115 #define DEFAULT_VK_LAYERS_PATH "" 116 #define LAYERS_PATH_ENV "VK_LAYER_PATH" 117 #define HOME_VK_DRIVERS_INFO "/.local/share" VULKAN_ICDCONF_DIR 118 #define HOME_VK_ELAYERS_INFO "/.local/share" VULKAN_ELAYERCONF_DIR 119 #define HOME_VK_ILAYERS_INFO "/.local/share" VULKAN_ILAYERCONF_DIR 120 121 // C99: 122 #define PRINTF_SIZE_T_SPECIFIER "%zu" 123 124 // File IO 125 static inline bool loader_platform_file_exists(const char *path) { 126 if (access(path, F_OK)) 127 return false; 128 else 129 return true; 130 } 131 132 static inline bool loader_platform_is_path_absolute(const char *path) { 133 if (path[0] == '/') 134 return true; 135 else 136 return false; 137 } 138 139 static inline char *loader_platform_dirname(char *path) { 140 return dirname(path); 141 } 142 143 // Environment variables 144 145 static inline char *loader_getenv(const char *name) { return getenv(name); } 146 147 static inline void loader_free_getenv(const char *val) {} 148 149 // Dynamic Loading of libraries: 150 typedef void *loader_platform_dl_handle; 151 static inline loader_platform_dl_handle 152 loader_platform_open_library(const char *libPath) { 153 return dlopen(libPath, RTLD_LAZY | RTLD_LOCAL); 154 } 155 static inline const char * 156 loader_platform_open_library_error(const char *libPath) { 157 return dlerror(); 158 } 159 static inline void 160 loader_platform_close_library(loader_platform_dl_handle library) { 161 dlclose(library); 162 } 163 static inline void * 164 loader_platform_get_proc_address(loader_platform_dl_handle library, 165 const char *name) { 166 assert(library); 167 assert(name); 168 return dlsym(library, name); 169 } 170 static inline const char * 171 loader_platform_get_proc_address_error(const char *name) { 172 return dlerror(); 173 } 174 175 // Threads: 176 typedef pthread_t loader_platform_thread; 177 #define THREAD_LOCAL_DECL __thread 178 #define LOADER_PLATFORM_THREAD_ONCE_DECLARATION(var) \ 179 pthread_once_t var = PTHREAD_ONCE_INIT; 180 #define LOADER_PLATFORM_THREAD_ONCE_DEFINITION(var) pthread_once_t var; 181 static inline void loader_platform_thread_once(pthread_once_t *ctl, 182 void (*func)(void)) { 183 assert(func != NULL); 184 assert(ctl != NULL); 185 pthread_once(ctl, func); 186 } 187 188 // Thread IDs: 189 typedef pthread_t loader_platform_thread_id; 190 static inline loader_platform_thread_id loader_platform_get_thread_id() { 191 return pthread_self(); 192 } 193 194 // Thread mutex: 195 typedef pthread_mutex_t loader_platform_thread_mutex; 196 static inline void 197 loader_platform_thread_create_mutex(loader_platform_thread_mutex *pMutex) { 198 pthread_mutex_init(pMutex, NULL); 199 } 200 static inline void 201 loader_platform_thread_lock_mutex(loader_platform_thread_mutex *pMutex) { 202 pthread_mutex_lock(pMutex); 203 } 204 static inline void 205 loader_platform_thread_unlock_mutex(loader_platform_thread_mutex *pMutex) { 206 pthread_mutex_unlock(pMutex); 207 } 208 static inline void 209 loader_platform_thread_delete_mutex(loader_platform_thread_mutex *pMutex) { 210 pthread_mutex_destroy(pMutex); 211 } 212 typedef pthread_cond_t loader_platform_thread_cond; 213 static inline void 214 loader_platform_thread_init_cond(loader_platform_thread_cond *pCond) { 215 pthread_cond_init(pCond, NULL); 216 } 217 static inline void 218 loader_platform_thread_cond_wait(loader_platform_thread_cond *pCond, 219 loader_platform_thread_mutex *pMutex) { 220 pthread_cond_wait(pCond, pMutex); 221 } 222 static inline void 223 loader_platform_thread_cond_broadcast(loader_platform_thread_cond *pCond) { 224 pthread_cond_broadcast(pCond); 225 } 226 227 #define loader_stack_alloc(size) alloca(size) 228 229 #elif defined(_WIN32) // defined(__linux__) 230 /* Windows-specific common code: */ 231 // WinBase.h defines CreateSemaphore and synchapi.h defines CreateEvent 232 // undefine them to avoid conflicts with VkLayerDispatchTable struct members. 233 #ifdef CreateSemaphore 234 #undef CreateSemaphore 235 #endif 236 #ifdef CreateEvent 237 #undef CreateEvent 238 #endif 239 #include <assert.h> 240 #include <stdio.h> 241 #include <string.h> 242 #include <io.h> 243 #include <stdbool.h> 244 #include <shlwapi.h> 245 #ifdef __cplusplus 246 #include <iostream> 247 #include <string> 248 using namespace std; 249 #endif // __cplusplus 250 251 // VK Library Filenames, Paths, etc.: 252 #define PATH_SEPERATOR ';' 253 #define DIRECTORY_SYMBOL '\\' 254 #define DEFAULT_VK_REGISTRY_HIVE HKEY_LOCAL_MACHINE 255 #define DEFAULT_VK_DRIVERS_INFO "SOFTWARE\\Khronos\\Vulkan\\Drivers" 256 // TODO: Are these the correct paths 257 #define DEFAULT_VK_DRIVERS_PATH "C:\\Windows\\System32;C:\\Windows\\SysWow64" 258 #define DEFAULT_VK_ELAYERS_INFO "SOFTWARE\\Khronos\\Vulkan\\ExplicitLayers" 259 #define DEFAULT_VK_ILAYERS_INFO "SOFTWARE\\Khronos\\Vulkan\\ImplicitLayers" 260 #define DEFAULT_VK_LAYERS_PATH "C:\\Windows\\System32;C:\\Windows\\SysWow64" 261 #define LAYERS_PATH_ENV "VK_LAYER_PATH" 262 #define HOME_VK_DRIVERS_INFO "" 263 #define HOME_VK_ELAYERS_INFO "" 264 #define HOME_VK_ILAYERS_INFO "" 265 #define PRINTF_SIZE_T_SPECIFIER "%Iu" 266 267 // File IO 268 static bool loader_platform_file_exists(const char *path) { 269 if ((_access(path, 0)) == -1) 270 return false; 271 else 272 return true; 273 } 274 275 static bool loader_platform_is_path_absolute(const char *path) { 276 return !PathIsRelative(path); 277 } 278 279 // WIN32 runtime doesn't have dirname(). 280 static inline char *loader_platform_dirname(char *path) { 281 char *current, *next; 282 283 // TODO/TBD: Do we need to deal with the Windows's ":" character? 284 285 for (current = path; *current != '\0'; current = next) { 286 next = strchr(current, DIRECTORY_SYMBOL); 287 if (next == NULL) { 288 if (current != path) 289 *(current - 1) = '\0'; 290 return path; 291 } else { 292 // Point one character past the DIRECTORY_SYMBOL: 293 next++; 294 } 295 } 296 return path; 297 } 298 299 // WIN32 runtime doesn't have basename(). 300 // Microsoft also doesn't have basename(). Paths are different on Windows, and 301 // so this is just a temporary solution in order to get us compiling, so that we 302 // can test some scenarios, and develop the correct solution for Windows. 303 // TODO: Develop a better, permanent solution for Windows, to replace this 304 // temporary code: 305 static char *loader_platform_basename(char *pathname) { 306 char *current, *next; 307 308 // TODO/TBD: Do we need to deal with the Windows's ":" character? 309 310 for (current = pathname; *current != '\0'; current = next) { 311 next = strchr(current, DIRECTORY_SYMBOL); 312 if (next == NULL) { 313 // No more DIRECTORY_SYMBOL's so return p: 314 return current; 315 } else { 316 // Point one character past the DIRECTORY_SYMBOL: 317 next++; 318 } 319 } 320 // We shouldn't get to here, but this makes the compiler happy: 321 return current; 322 } 323 324 // Environment variables 325 326 static inline char *loader_getenv(const char *name) { 327 char *retVal; 328 DWORD valSize; 329 330 valSize = GetEnvironmentVariableA(name, NULL, 0); 331 332 // valSize DOES include the null terminator, so for any set variable 333 // will always be at least 1. If it's 0, the variable wasn't set. 334 if (valSize == 0) 335 return NULL; 336 337 // TODO; FIXME This should be using any app defined memory allocation 338 retVal = (char *)malloc(valSize); 339 340 GetEnvironmentVariableA(name, retVal, valSize); 341 342 return retVal; 343 } 344 345 static inline void loader_free_getenv(const char *val) { free((void *)val); } 346 347 // Dynamic Loading: 348 typedef HMODULE loader_platform_dl_handle; 349 static loader_platform_dl_handle 350 loader_platform_open_library(const char *libPath) { 351 return LoadLibrary(libPath); 352 } 353 static char *loader_platform_open_library_error(const char *libPath) { 354 static char errorMsg[120]; 355 snprintf(errorMsg, 119, "Failed to open dynamic library \"%s\"", libPath); 356 return errorMsg; 357 } 358 static void loader_platform_close_library(loader_platform_dl_handle library) { 359 FreeLibrary(library); 360 } 361 static void *loader_platform_get_proc_address(loader_platform_dl_handle library, 362 const char *name) { 363 assert(library); 364 assert(name); 365 return GetProcAddress(library, name); 366 } 367 static char *loader_platform_get_proc_address_error(const char *name) { 368 static char errorMsg[120]; 369 snprintf(errorMsg, 119, "Failed to find function \"%s\" in dynamic library", 370 name); 371 return errorMsg; 372 } 373 374 // Threads: 375 typedef HANDLE loader_platform_thread; 376 #define THREAD_LOCAL_DECL __declspec(thread) 377 #define LOADER_PLATFORM_THREAD_ONCE_DECLARATION(var) \ 378 INIT_ONCE var = INIT_ONCE_STATIC_INIT; 379 #define LOADER_PLATFORM_THREAD_ONCE_DEFINITION(var) INIT_ONCE var; 380 static BOOL CALLBACK 381 InitFuncWrapper(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context) { 382 void (*func)(void) = (void (*)(void))Parameter; 383 func(); 384 return TRUE; 385 } 386 387 static void loader_platform_thread_once(void *ctl, void (*func)(void)) { 388 assert(func != NULL); 389 assert(ctl != NULL); 390 InitOnceExecuteOnce((PINIT_ONCE)ctl, InitFuncWrapper, func, NULL); 391 } 392 393 // Thread IDs: 394 typedef DWORD loader_platform_thread_id; 395 static loader_platform_thread_id loader_platform_get_thread_id() { 396 return GetCurrentThreadId(); 397 } 398 399 // Thread mutex: 400 typedef CRITICAL_SECTION loader_platform_thread_mutex; 401 static void 402 loader_platform_thread_create_mutex(loader_platform_thread_mutex *pMutex) { 403 InitializeCriticalSection(pMutex); 404 } 405 static void 406 loader_platform_thread_lock_mutex(loader_platform_thread_mutex *pMutex) { 407 EnterCriticalSection(pMutex); 408 } 409 static void 410 loader_platform_thread_unlock_mutex(loader_platform_thread_mutex *pMutex) { 411 LeaveCriticalSection(pMutex); 412 } 413 static void 414 loader_platform_thread_delete_mutex(loader_platform_thread_mutex *pMutex) { 415 DeleteCriticalSection(pMutex); 416 } 417 typedef CONDITION_VARIABLE loader_platform_thread_cond; 418 static void 419 loader_platform_thread_init_cond(loader_platform_thread_cond *pCond) { 420 InitializeConditionVariable(pCond); 421 } 422 static void 423 loader_platform_thread_cond_wait(loader_platform_thread_cond *pCond, 424 loader_platform_thread_mutex *pMutex) { 425 SleepConditionVariableCS(pCond, pMutex, INFINITE); 426 } 427 static void 428 loader_platform_thread_cond_broadcast(loader_platform_thread_cond *pCond) { 429 WakeAllConditionVariable(pCond); 430 } 431 432 // Windows Registry: 433 char *loader_get_registry_string(const HKEY hive, const LPCTSTR sub_key, 434 const char *value); 435 436 #define loader_stack_alloc(size) _alloca(size) 437 #else // defined(_WIN32) 438 439 #error The "loader_platform.h" file must be modified for this OS. 440 441 // NOTE: In order to support another OS, an #elif needs to be added (above the 442 // "#else // defined(_WIN32)") for that OS, and OS-specific versions of the 443 // contents of this file must be created. 444 445 // NOTE: Other OS-specific changes are also needed for this OS. Search for 446 // files with "WIN32" in it, as a quick way to find files that must be changed. 447 448 #endif // defined(_WIN32) 449 450 // returns true if the given string appears to be a relative or absolute 451 // path, as opposed to a bare filename. 452 static inline bool loader_platform_is_path(const char *path) { 453 return strchr(path, DIRECTORY_SYMBOL) != NULL; 454 } 455