vk_loader_platform.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  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 <[email protected]>
  20. * Author: Jon Ashburn <[email protected]>
  21. * Author: Lenny Komow <[email protected]>
  22. *
  23. */
  24. #pragma once
  25. #if defined(_WIN32)
  26. // WinSock2.h must be included *BEFORE* windows.h
  27. #include <winsock2.h>
  28. #endif // _WIN32
  29. #if defined(__Fuchsia__)
  30. #include "dlopen_fuchsia.h"
  31. #endif // defined(__Fuchsia__)
  32. #include "vulkan/vk_platform.h"
  33. #include "vulkan/vk_sdk_platform.h"
  34. #if defined(__linux__) || defined(__APPLE__) || defined(__Fuchsia__)
  35. /* Linux-specific common code: */
  36. // Headers:
  37. //#ifndef _GNU_SOURCE
  38. //#define _GNU_SOURCE 1
  39. //#endif
  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. // VK Library Filenames, Paths, etc.:
  50. #define PATH_SEPARATOR ':'
  51. #define DIRECTORY_SYMBOL '/'
  52. #define VULKAN_DIR "vulkan/"
  53. #define VULKAN_ICDCONF_DIR "icd.d"
  54. #define VULKAN_ICD_DIR "icd"
  55. #define VULKAN_SETTINGSCONF_DIR "settings.d"
  56. #define VULKAN_ELAYERCONF_DIR "explicit_layer.d"
  57. #define VULKAN_ILAYERCONF_DIR "implicit_layer.d"
  58. #define VULKAN_LAYER_DIR "layer"
  59. #define VK_DRIVERS_INFO_RELATIVE_DIR VULKAN_DIR VULKAN_ICDCONF_DIR
  60. #define VK_SETTINGS_INFO_RELATIVE_DIR VULKAN_DIR VULKAN_SETTINGSCONF_DIR
  61. #define VK_ELAYERS_INFO_RELATIVE_DIR VULKAN_DIR VULKAN_ELAYERCONF_DIR
  62. #define VK_ILAYERS_INFO_RELATIVE_DIR VULKAN_DIR VULKAN_ILAYERCONF_DIR
  63. #define VK_DRIVERS_INFO_REGISTRY_LOC ""
  64. #define VK_SETTINGS_INFO_REGISTRY_LOC ""
  65. #define VK_ELAYERS_INFO_REGISTRY_LOC ""
  66. #define VK_ILAYERS_INFO_REGISTRY_LOC ""
  67. #if !defined(DEFAULT_VK_LAYERS_PATH)
  68. #define DEFAULT_VK_LAYERS_PATH ""
  69. #endif
  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. // C99:
  76. #define PRINTF_SIZE_T_SPECIFIER "%zu"
  77. // File IO
  78. static inline bool loader_platform_file_exists(const char *path) {
  79. if (access(path, F_OK))
  80. return false;
  81. else
  82. return true;
  83. }
  84. static inline bool loader_platform_is_path_absolute(const char *path) {
  85. if (path[0] == '/')
  86. return true;
  87. else
  88. return false;
  89. }
  90. static inline char *loader_platform_dirname(char *path) { return dirname(path); }
  91. #if defined(__linux__)
  92. // find application path + name. Path cannot be longer than 1024, returns NULL if it is greater than that.
  93. static inline char *loader_platform_executable_path(char *buffer, size_t size) {
  94. ssize_t count = readlink("/proc/self/exe", buffer, size);
  95. if (count == -1) return NULL;
  96. if (count == 0) return NULL;
  97. buffer[count] = '\0';
  98. return buffer;
  99. }
  100. #elif defined(__APPLE__) // defined(__linux__)
  101. #include <libproc.h>
  102. static inline char *loader_platform_executable_path(char *buffer, size_t size) {
  103. pid_t pid = getpid();
  104. int ret = proc_pidpath(pid, buffer, size);
  105. if (ret <= 0) return NULL;
  106. buffer[ret] = '\0';
  107. return buffer;
  108. }
  109. #elif defined(__Fuchsia__)
  110. static inline char *loader_platform_executable_path(char *buffer, size_t size) { return NULL; }
  111. #endif // defined (__APPLE__)
  112. // Compatability with compilers that don't support __has_feature
  113. #ifndef __has_feature
  114. #define __has_feature(x) 0
  115. #endif
  116. #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
  117. #define LOADER_ADDRESS_SANITIZER
  118. #endif
  119. // Dynamic Loading of libraries:
  120. typedef void *loader_platform_dl_handle;
  121. // When loading the library, we use RTLD_LAZY so that not all symbols have to be
  122. // resolved at this time (which improves performance). Note that if not all symbols
  123. // can be resolved, this could cause crashes later. Use the LD_BIND_NOW environment
  124. // variable to force all symbols to be resolved here.
  125. #define LOADER_DLOPEN_MODE (RTLD_LAZY | RTLD_LOCAL)
  126. #if defined(__Fuchsia__)
  127. static inline loader_platform_dl_handle loader_platform_open_driver(const char *libPath) {
  128. return dlopen_fuchsia(libPath, LOADER_DLOPEN_MODE, true);
  129. }
  130. static inline loader_platform_dl_handle loader_platform_open_library(const char *libPath) {
  131. return dlopen_fuchsia(libPath, LOADER_DLOPEN_MODE, false);
  132. }
  133. #else
  134. static inline loader_platform_dl_handle loader_platform_open_library(const char *libPath) {
  135. return dlopen(libPath, LOADER_DLOPEN_MODE);
  136. }
  137. #endif
  138. static inline const char *loader_platform_open_library_error(const char *libPath) {
  139. #ifdef __Fuchsia__
  140. return dlerror_fuchsia();
  141. #else
  142. return dlerror();
  143. #endif
  144. }
  145. static inline void loader_platform_close_library(loader_platform_dl_handle library) { dlclose(library); }
  146. static inline void *loader_platform_get_proc_address(loader_platform_dl_handle library, const char *name) {
  147. assert(library);
  148. assert(name);
  149. return dlsym(library, name);
  150. }
  151. static inline const char *loader_platform_get_proc_address_error(const char *name) { return dlerror(); }
  152. // Threads:
  153. typedef pthread_t loader_platform_thread;
  154. #define THREAD_LOCAL_DECL __thread
  155. // The once init functionality is not used on Linux
  156. #define LOADER_PLATFORM_THREAD_ONCE_DECLARATION(var)
  157. #define LOADER_PLATFORM_THREAD_ONCE_DEFINITION(var)
  158. #define LOADER_PLATFORM_THREAD_ONCE(ctl, func)
  159. // Thread IDs:
  160. typedef pthread_t loader_platform_thread_id;
  161. static inline loader_platform_thread_id loader_platform_get_thread_id() { return pthread_self(); }
  162. // Thread mutex:
  163. typedef pthread_mutex_t loader_platform_thread_mutex;
  164. static inline void loader_platform_thread_create_mutex(loader_platform_thread_mutex *pMutex) { pthread_mutex_init(pMutex, NULL); }
  165. static inline void loader_platform_thread_lock_mutex(loader_platform_thread_mutex *pMutex) { pthread_mutex_lock(pMutex); }
  166. static inline void loader_platform_thread_unlock_mutex(loader_platform_thread_mutex *pMutex) { pthread_mutex_unlock(pMutex); }
  167. static inline void loader_platform_thread_delete_mutex(loader_platform_thread_mutex *pMutex) { pthread_mutex_destroy(pMutex); }
  168. typedef pthread_cond_t loader_platform_thread_cond;
  169. static inline void loader_platform_thread_init_cond(loader_platform_thread_cond *pCond) { pthread_cond_init(pCond, NULL); }
  170. static inline void loader_platform_thread_cond_wait(loader_platform_thread_cond *pCond, loader_platform_thread_mutex *pMutex) {
  171. pthread_cond_wait(pCond, pMutex);
  172. }
  173. static inline void loader_platform_thread_cond_broadcast(loader_platform_thread_cond *pCond) { pthread_cond_broadcast(pCond); }
  174. #define loader_stack_alloc(size) alloca(size)
  175. #elif defined(_WIN32) // defined(__linux__)
  176. /* Windows-specific common code: */
  177. // WinBase.h defines CreateSemaphore and synchapi.h defines CreateEvent
  178. // undefine them to avoid conflicts with VkLayerDispatchTable struct members.
  179. #ifdef CreateSemaphore
  180. #undef CreateSemaphore
  181. #endif
  182. #ifdef CreateEvent
  183. #undef CreateEvent
  184. #endif
  185. #include <assert.h>
  186. #include <stdio.h>
  187. #include <string.h>
  188. #include <io.h>
  189. #include <stdbool.h>
  190. #include <shlwapi.h>
  191. #include <direct.h>
  192. #ifdef __cplusplus
  193. #include <iostream>
  194. #include <string>
  195. #endif // __cplusplus
  196. // VK Library Filenames, Paths, etc.:
  197. #define PATH_SEPARATOR ';'
  198. #define DIRECTORY_SYMBOL '\\'
  199. #define DEFAULT_VK_REGISTRY_HIVE HKEY_LOCAL_MACHINE
  200. #define DEFAULT_VK_REGISTRY_HIVE_STR "HKEY_LOCAL_MACHINE"
  201. #define SECONDARY_VK_REGISTRY_HIVE HKEY_CURRENT_USER
  202. #define SECONDARY_VK_REGISTRY_HIVE_STR "HKEY_CURRENT_USER"
  203. #define VK_DRIVERS_INFO_RELATIVE_DIR ""
  204. #define VK_SETTINGS_INFO_RELATIVE_DIR ""
  205. #define VK_ELAYERS_INFO_RELATIVE_DIR ""
  206. #define VK_ILAYERS_INFO_RELATIVE_DIR ""
  207. #ifdef _WIN64
  208. #define HKR_VK_DRIVER_NAME API_NAME "DriverName"
  209. #else
  210. #define HKR_VK_DRIVER_NAME API_NAME "DriverNameWow"
  211. #endif
  212. #define VK_DRIVERS_INFO_REGISTRY_LOC "SOFTWARE\\Khronos\\" API_NAME "\\Drivers"
  213. #define VK_SETTINGS_INFO_REGISTRY_LOC "SOFTWARE\\Khronos\\" API_NAME "\\Settings"
  214. #define VK_ELAYERS_INFO_REGISTRY_LOC "SOFTWARE\\Khronos\\" API_NAME "\\ExplicitLayers"
  215. #define VK_ILAYERS_INFO_REGISTRY_LOC "SOFTWARE\\Khronos\\" API_NAME "\\ImplicitLayers"
  216. #if !defined(DEFAULT_VK_LAYERS_PATH)
  217. #define DEFAULT_VK_LAYERS_PATH ""
  218. #endif
  219. #if !defined(LAYERS_SOURCE_PATH)
  220. #define LAYERS_SOURCE_PATH NULL
  221. #endif
  222. #define LAYERS_PATH_ENV "VK_LAYER_PATH"
  223. #define ENABLED_LAYERS_ENV "VK_INSTANCE_LAYERS"
  224. #define PRINTF_SIZE_T_SPECIFIER "%Iu"
  225. #if defined(_WIN32)
  226. // Get the key for the plug n play driver registry
  227. // The string returned by this function should NOT be freed
  228. static inline const char *LoaderPnpDriverRegistry() {
  229. BOOL is_wow;
  230. IsWow64Process(GetCurrentProcess(), &is_wow);
  231. return is_wow ? "VulkanDriverNameWow" : "VulkanDriverName";
  232. }
  233. static inline const wchar_t *LoaderPnpDriverRegistryWide() {
  234. BOOL is_wow;
  235. IsWow64Process(GetCurrentProcess(), &is_wow);
  236. return is_wow ? L"VulkanDriverNameWow" : L"VulkanDriverName";
  237. }
  238. // Get the key for the plug 'n play explicit layer registry
  239. // The string returned by this function should NOT be freed
  240. static inline const char *LoaderPnpELayerRegistry() {
  241. BOOL is_wow;
  242. IsWow64Process(GetCurrentProcess(), &is_wow);
  243. return is_wow ? "VulkanExplicitLayersWow" : "VulkanExplicitLayers";
  244. }
  245. static inline const wchar_t *LoaderPnpELayerRegistryWide() {
  246. BOOL is_wow;
  247. IsWow64Process(GetCurrentProcess(), &is_wow);
  248. return is_wow ? L"VulkanExplicitLayersWow" : L"VulkanExplicitLayers";
  249. }
  250. // Get the key for the plug 'n play implicit layer registry
  251. // The string returned by this function should NOT be freed
  252. static inline const char *LoaderPnpILayerRegistry() {
  253. BOOL is_wow;
  254. IsWow64Process(GetCurrentProcess(), &is_wow);
  255. return is_wow ? "VulkanImplicitLayersWow" : "VulkanImplicitLayers";
  256. }
  257. static inline const wchar_t *LoaderPnpILayerRegistryWide() {
  258. BOOL is_wow;
  259. IsWow64Process(GetCurrentProcess(), &is_wow);
  260. return is_wow ? L"VulkanImplicitLayersWow" : L"VulkanImplicitLayers";
  261. }
  262. #endif
  263. // File IO
  264. static bool loader_platform_file_exists(const char *path) {
  265. if ((_access(path, 0)) == -1)
  266. return false;
  267. else
  268. return true;
  269. }
  270. static bool loader_platform_is_path_absolute(const char *path) {
  271. if (!path || !*path) {
  272. return false;
  273. }
  274. if (*path == DIRECTORY_SYMBOL || path[1] == ':') {
  275. return true;
  276. }
  277. return false;
  278. }
  279. // WIN32 runtime doesn't have dirname().
  280. static inline char *loader_platform_dirname(char *path) {
  281. char *current, *next;
  282. // TODO/TBD: Do we need to deal with the Windows's ":" character?
  283. for (current = path; *current != '\0'; current = next) {
  284. next = strchr(current, DIRECTORY_SYMBOL);
  285. if (next == NULL) {
  286. if (current != path) *(current - 1) = '\0';
  287. return path;
  288. } else {
  289. // Point one character past the DIRECTORY_SYMBOL:
  290. next++;
  291. }
  292. }
  293. return path;
  294. }
  295. static inline char *loader_platform_executable_path(char *buffer, size_t size) {
  296. DWORD ret = GetModuleFileName(NULL, buffer, (DWORD)size);
  297. if (ret == 0) return NULL;
  298. if (ret > size) return NULL;
  299. buffer[ret] = '\0';
  300. return buffer;
  301. }
  302. // Dynamic Loading:
  303. typedef HMODULE loader_platform_dl_handle;
  304. static loader_platform_dl_handle loader_platform_open_library(const char *lib_path) {
  305. // Try loading the library the original way first.
  306. loader_platform_dl_handle lib_handle = LoadLibrary(lib_path);
  307. if (lib_handle == NULL && GetLastError() == ERROR_MOD_NOT_FOUND) {
  308. // If that failed, then try loading it with broader search folders.
  309. lib_handle = LoadLibraryEx(lib_path, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
  310. }
  311. return lib_handle;
  312. }
  313. static char *loader_platform_open_library_error(const char *libPath) {
  314. static char errorMsg[164];
  315. (void)snprintf(errorMsg, 163, "Failed to open dynamic library \"%s\" with error %lu", libPath, GetLastError());
  316. return errorMsg;
  317. }
  318. static void loader_platform_close_library(loader_platform_dl_handle library) { FreeLibrary(library); }
  319. static void *loader_platform_get_proc_address(loader_platform_dl_handle library, const char *name) {
  320. assert(library);
  321. assert(name);
  322. return (void *)GetProcAddress(library, name);
  323. }
  324. static char *loader_platform_get_proc_address_error(const char *name) {
  325. static char errorMsg[120];
  326. (void)snprintf(errorMsg, 119, "Failed to find function \"%s\" in dynamic library", name);
  327. return errorMsg;
  328. }
  329. // Threads:
  330. typedef HANDLE loader_platform_thread;
  331. // __declspec(thread) is not supported by MinGW compiler (ignored with warning or
  332. // cause error depending on compiler switches)
  333. //
  334. // __thread should be used instead
  335. //
  336. // __MINGW32__ defined for both 32 and 64 bit MinGW compilers, so it is enough to
  337. // detect any (32 or 64) flavor of MinGW compiler.
  338. //
  339. // @note __GNUC__ could be used as a more generic way to detect _any_
  340. // GCC[-compatible] compiler on Windows, but this fix was tested
  341. // only with MinGW, so keep it explicit at the moment.
  342. #if defined(__MINGW32__)
  343. #define THREAD_LOCAL_DECL __thread
  344. #else
  345. #define THREAD_LOCAL_DECL __declspec(thread)
  346. #endif
  347. // The once init functionality is not used when building a DLL on Windows. This is because there is no way to clean up the
  348. // resources allocated by anything allocated by once init. This isn't a problem for static libraries, but it is for dynamic
  349. // ones. When building a DLL, we use DllMain() instead to allow properly cleaning up resources.
  350. #if defined(LOADER_DYNAMIC_LIB)
  351. #define LOADER_PLATFORM_THREAD_ONCE_DECLARATION(var)
  352. #define LOADER_PLATFORM_THREAD_ONCE_DEFINITION(var)
  353. #define LOADER_PLATFORM_THREAD_ONCE(ctl, func)
  354. #else
  355. #define LOADER_PLATFORM_THREAD_ONCE_DECLARATION(var) INIT_ONCE var = INIT_ONCE_STATIC_INIT;
  356. #define LOADER_PLATFORM_THREAD_ONCE_DEFINITION(var) INIT_ONCE var;
  357. #define LOADER_PLATFORM_THREAD_ONCE(ctl, func) loader_platform_thread_once_fn(ctl, func)
  358. static BOOL CALLBACK InitFuncWrapper(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context) {
  359. void (*func)(void) = (void (*)(void))Parameter;
  360. func();
  361. return TRUE;
  362. }
  363. static void loader_platform_thread_once_fn(void *ctl, void (*func)(void)) {
  364. assert(func != NULL);
  365. assert(ctl != NULL);
  366. InitOnceExecuteOnce((PINIT_ONCE)ctl, InitFuncWrapper, (void *)func, NULL);
  367. }
  368. #endif
  369. // Thread IDs:
  370. typedef DWORD loader_platform_thread_id;
  371. static loader_platform_thread_id loader_platform_get_thread_id() { return GetCurrentThreadId(); }
  372. // Thread mutex:
  373. typedef CRITICAL_SECTION loader_platform_thread_mutex;
  374. static void loader_platform_thread_create_mutex(loader_platform_thread_mutex *pMutex) { InitializeCriticalSection(pMutex); }
  375. static void loader_platform_thread_lock_mutex(loader_platform_thread_mutex *pMutex) { EnterCriticalSection(pMutex); }
  376. static void loader_platform_thread_unlock_mutex(loader_platform_thread_mutex *pMutex) { LeaveCriticalSection(pMutex); }
  377. static void loader_platform_thread_delete_mutex(loader_platform_thread_mutex *pMutex) { DeleteCriticalSection(pMutex); }
  378. typedef CONDITION_VARIABLE loader_platform_thread_cond;
  379. static void loader_platform_thread_init_cond(loader_platform_thread_cond *pCond) { InitializeConditionVariable(pCond); }
  380. static void loader_platform_thread_cond_wait(loader_platform_thread_cond *pCond, loader_platform_thread_mutex *pMutex) {
  381. SleepConditionVariableCS(pCond, pMutex, INFINITE);
  382. }
  383. static void loader_platform_thread_cond_broadcast(loader_platform_thread_cond *pCond) { WakeAllConditionVariable(pCond); }
  384. #define loader_stack_alloc(size) _alloca(size)
  385. #else // defined(_WIN32)
  386. #error The "loader_platform.h" file must be modified for this OS.
  387. // NOTE: In order to support another OS, an #elif needs to be added (above the
  388. // "#else // defined(_WIN32)") for that OS, and OS-specific versions of the
  389. // contents of this file must be created.
  390. // NOTE: Other OS-specific changes are also needed for this OS. Search for
  391. // files with "WIN32" in it, as a quick way to find files that must be changed.
  392. #endif // defined(_WIN32)
  393. // returns true if the given string appears to be a relative or absolute
  394. // path, as opposed to a bare filename.
  395. static inline bool loader_platform_is_path(const char *path) { return strchr(path, DIRECTORY_SYMBOL) != NULL; }