• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * Copyright (c) 2015-2022 The Khronos Group Inc.
4  * Copyright (c) 2015-2022 Valve Corporation
5  * Copyright (c) 2015-2022 LunarG, Inc.
6  * Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
7  * Copyright (c) 2023-2023 RasterGrid Kft.
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *     http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  * Author: Ian Elliot <ian@lunarg.com>
22  * Author: Jon Ashburn <jon@lunarg.com>
23  * Author: Lenny Komow <lenny@lunarg.com>
24  * Author: Charles Giessen <charles@lunarg.com>
25  *
26  */
27 #pragma once
28 
29 #if defined(__FreeBSD__) || defined(__OpenBSD__)
30 #include <sys/types.h>
31 #include <sys/select.h>
32 #endif
33 
34 #include <assert.h>
35 #include <float.h>
36 #include <stdbool.h>
37 #include <stdint.h>
38 #include <stdio.h>
39 #include <string.h>
40 
41 #if defined(__Fuchsia__)
42 #include "dlopen_fuchsia.h"
43 #endif  // defined(__Fuchsia__)
44 
45 // Set of platforms with a common set of functionality which is queried throughout the program
46 #if defined(__linux__) || defined(__APPLE__) || defined(__Fuchsia__) || defined(__QNX__) || defined(__FreeBSD__) || \
47     defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__GNU__)
48 #define COMMON_UNIX_PLATFORMS 1
49 #else
50 #define COMMON_UNIX_PLATFORMS 0
51 #endif
52 
53 #if COMMON_UNIX_PLATFORMS
54 #include <unistd.h>
55 // Note: The following file is for dynamic loading:
56 #include <dlfcn.h>
57 #include <pthread.h>
58 #include <stdlib.h>
59 #include <libgen.h>
60 
61 #elif defined(_WIN32)
62 // WinBase.h defines CreateSemaphore and synchapi.h defines CreateEvent
63 //  undefine them to avoid conflicts with VkLayerDispatchTable struct members.
64 #if defined(CreateSemaphore)
65 #undef CreateSemaphore
66 #endif
67 #if defined(CreateEvent)
68 #undef CreateEvent
69 #endif
70 #include <stdio.h>
71 #include <io.h>
72 #include <shlwapi.h>
73 #include <direct.h>
74 
75 #include "stack_allocation.h"
76 #endif  // defined(_WIN32)
77 
78 #if defined(APPLE_STATIC_LOADER) && !defined(__APPLE__)
79 #error "APPLE_STATIC_LOADER can only be defined on Apple platforms!"
80 #endif
81 
82 #if defined(APPLE_STATIC_LOADER)
83 #define LOADER_EXPORT
84 #elif defined(__GNUC__) && __GNUC__ >= 4
85 #define LOADER_EXPORT __attribute__((visibility("default")))
86 #elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)
87 #define LOADER_EXPORT __attribute__((visibility("default")))
88 #else
89 #define LOADER_EXPORT
90 #endif
91 
92 // For testing purposes, we want to expose some functions not normally callable on the library
93 #if defined(SHOULD_EXPORT_TEST_FUNCTIONS)
94 #if defined(_WIN32)
95 #define TEST_FUNCTION_EXPORT __declspec(dllexport)
96 #else
97 #define TEST_FUNCTION_EXPORT LOADER_EXPORT
98 #endif
99 #else
100 #define TEST_FUNCTION_EXPORT
101 #endif
102 
103 #define MAX_STRING_SIZE 1024
104 
105 // This is defined in vk_layer.h, but if there's problems we need to create the define
106 // here.
107 #if !defined(MAX_NUM_UNKNOWN_EXTS)
108 #define MAX_NUM_UNKNOWN_EXTS 250
109 #endif
110 
111 // Environment Variable information
112 #define VK_ICD_FILENAMES_ENV_VAR "VK_ICD_FILENAMES"  // Deprecated in v1.3.207 loader
113 #define VK_DRIVER_FILES_ENV_VAR "VK_DRIVER_FILES"
114 #define VK_EXPLICIT_LAYER_PATH_ENV_VAR "VK_LAYER_PATH"
115 // Support added in v1.3.207 loader
116 #define VK_ADDITIONAL_DRIVER_FILES_ENV_VAR "VK_ADD_DRIVER_FILES"
117 #define VK_ADDITIONAL_EXPLICIT_LAYER_PATH_ENV_VAR "VK_ADD_LAYER_PATH"
118 // Support added in v1.3.234 loader
119 #define VK_LAYERS_ENABLE_ENV_VAR "VK_LOADER_LAYERS_ENABLE"
120 #define VK_LAYERS_DISABLE_ENV_VAR "VK_LOADER_LAYERS_DISABLE"
121 #define VK_LAYERS_ALLOW_ENV_VAR "VK_LOADER_LAYERS_ALLOW"
122 #define VK_DRIVERS_SELECT_ENV_VAR "VK_LOADER_DRIVERS_SELECT"
123 #define VK_DRIVERS_DISABLE_ENV_VAR "VK_LOADER_DRIVERS_DISABLE"
124 #define VK_LOADER_DISABLE_ALL_LAYERS_VAR_1 "~all~"
125 #define VK_LOADER_DISABLE_ALL_LAYERS_VAR_2 "*"
126 #define VK_LOADER_DISABLE_ALL_LAYERS_VAR_3 "**"
127 #define VK_LOADER_DISABLE_IMPLICIT_LAYERS_VAR "~implicit~"
128 #define VK_LOADER_DISABLE_EXPLICIT_LAYERS_VAR "~explicit~"
129 // Support added in v1.3.295 loader
130 #define VK_IMPLICIT_LAYER_PATH_ENV_VAR "VK_IMPLICIT_LAYER_PATH"
131 #define VK_ADDITIONAL_IMPLICIT_LAYER_PATH_ENV_VAR "VK_ADD_IMPLICIT_LAYER_PATH"
132 
133 // Override layer information
134 #define VK_OVERRIDE_LAYER_NAME "VK_LAYER_LUNARG_override"
135 
136 // Loader Settings filename
137 #define VK_LOADER_SETTINGS_FILENAME "vk_loader_settings.json"
138 
139 #define LAYERS_PATH_ENV "VK_LAYER_PATH"
140 #define ENABLED_LAYERS_ENV "VK_INSTANCE_LAYERS"
141 
142 #if COMMON_UNIX_PLATFORMS
143 /* Linux-specific common code: */
144 
145 // VK Library Filenames, Paths, etc.:
146 #define PATH_SEPARATOR ':'
147 #define DIRECTORY_SYMBOL '/'
148 
149 #define VULKAN_DIR "vulkan/"
150 #define VULKAN_ICDCONF_DIR "icd.d"
151 #define VULKAN_ICD_DIR "icd"
152 #define VULKAN_SETTINGSCONF_DIR "settings.d"
153 #define VULKAN_ELAYERCONF_DIR "explicit_layer.d"
154 #define VULKAN_ILAYERCONF_DIR "implicit_layer.d"
155 #define VULKAN_LAYER_DIR "layer"
156 
157 #define VK_DRIVERS_INFO_RELATIVE_DIR VULKAN_DIR VULKAN_ICDCONF_DIR
158 #define VK_SETTINGS_INFO_RELATIVE_DIR VULKAN_DIR VULKAN_SETTINGSCONF_DIR
159 #define VK_ELAYERS_INFO_RELATIVE_DIR VULKAN_DIR VULKAN_ELAYERCONF_DIR
160 #define VK_ILAYERS_INFO_RELATIVE_DIR VULKAN_DIR VULKAN_ILAYERCONF_DIR
161 
162 #define VK_DRIVERS_INFO_REGISTRY_LOC ""
163 #define VK_ELAYERS_INFO_REGISTRY_LOC ""
164 #define VK_ILAYERS_INFO_REGISTRY_LOC ""
165 #define VK_SETTINGS_INFO_REGISTRY_LOC ""
166 
167 #if defined(__QNX__)
168 #ifndef SYSCONFDIR
169 #define SYSCONFDIR "/etc"
170 #endif
171 #endif
172 
173 // C99:
174 #define PRINTF_SIZE_T_SPECIFIER "%zu"
175 
176 // Dynamic Loading of libraries:
177 typedef void *loader_platform_dl_handle;
178 
179 // Threads:
180 typedef pthread_t loader_platform_thread;
181 
182 // Thread IDs:
183 typedef pthread_t loader_platform_thread_id;
184 
185 // Thread mutex:
186 typedef pthread_mutex_t loader_platform_thread_mutex;
187 
188 typedef pthread_cond_t loader_platform_thread_cond;
189 
190 #elif defined(_WIN32)
191 /* Windows-specific common code: */
192 // VK Library Filenames, Paths, etc.:
193 #define PATH_SEPARATOR ';'
194 #define DIRECTORY_SYMBOL '\\'
195 #define DEFAULT_VK_REGISTRY_HIVE HKEY_LOCAL_MACHINE
196 #define DEFAULT_VK_REGISTRY_HIVE_STR "HKEY_LOCAL_MACHINE"
197 #define SECONDARY_VK_REGISTRY_HIVE HKEY_CURRENT_USER
198 #define SECONDARY_VK_REGISTRY_HIVE_STR "HKEY_CURRENT_USER"
199 
200 #define VK_DRIVERS_INFO_RELATIVE_DIR ""
201 #define VK_SETTINGS_INFO_RELATIVE_DIR ""
202 #define VK_ELAYERS_INFO_RELATIVE_DIR ""
203 #define VK_ILAYERS_INFO_RELATIVE_DIR ""
204 
205 #define VK_VARIANT_REG_STR ""
206 #define VK_VARIANT_REG_STR_W L""
207 
208 #define VK_DRIVERS_INFO_REGISTRY_LOC "SOFTWARE\\Khronos\\Vulkan" VK_VARIANT_REG_STR "\\Drivers"
209 #define VK_ELAYERS_INFO_REGISTRY_LOC "SOFTWARE\\Khronos\\Vulkan" VK_VARIANT_REG_STR "\\ExplicitLayers"
210 #define VK_ILAYERS_INFO_REGISTRY_LOC "SOFTWARE\\Khronos\\Vulkan" VK_VARIANT_REG_STR "\\ImplicitLayers"
211 #define VK_SETTINGS_INFO_REGISTRY_LOC "SOFTWARE\\Khronos\\Vulkan" VK_VARIANT_REG_STR "\\LoaderSettings"
212 
213 #define PRINTF_SIZE_T_SPECIFIER "%Iu"
214 
215 // Dynamic Loading:
216 typedef HMODULE loader_platform_dl_handle;
217 
218 // Threads:
219 typedef HANDLE loader_platform_thread;
220 
221 // Thread IDs:
222 typedef DWORD loader_platform_thread_id;
223 
224 // Thread mutex:
225 typedef CRITICAL_SECTION loader_platform_thread_mutex;
226 
227 typedef CONDITION_VARIABLE loader_platform_thread_cond;
228 
229 #else
230 
231 #warning The "vk_loader_platform.h" file must be modified for this OS.
232 
233 // NOTE: In order to support another OS, an #elif needs to be added (above the
234 // "#else // defined(_WIN32)") for that OS, and OS-specific versions of the
235 // contents of this file must be created, or extend one of the existing OS specific
236 // sections with the necessary changes.
237 
238 #endif
239 
240 // controls whether loader_platform_close_library() closes the libraries or not - controlled by an environment variables
241 extern bool loader_disable_dynamic_library_unloading;
242 
243 // Returns true if the DIRECTORY_SYMBOL is contained within path
loader_platform_is_path(const char * path)244 static inline bool loader_platform_is_path(const char *path) { return strchr(path, DIRECTORY_SYMBOL) != NULL; }
245 
246 // The loader has various initialization tasks which it must do before user code can run. This includes initializing synchronization
247 // objects, determining the log level, writing the version of the loader to the log, and loading dll's (on windows). On linux, the
248 // solution is simply running the initialization code in  __attribute__((constructor)), which MacOS uses when the loader is
249 // dynamically linked. When statically linking on MacOS, the setup code instead uses pthread_once to run the logic a single time
250 // regardless of which API function the application calls first. On Windows, the equivalent way to run code at dll load time is
251 // DllMain which has many limitations placed upon it. Instead, the Windows code follows MacOS and does initialization in the first
252 // API call made, using InitOnceExecuteOnce, except for initialization primitives which must be done in DllMain. This is because
253 // there is no way to clean up the resources allocated by anything allocated by once init.
254 
255 #if defined(APPLE_STATIC_LOADER)
loader_platform_thread_once_fn(pthread_once_t * ctl,void (* func)(void))256 static inline void loader_platform_thread_once_fn(pthread_once_t *ctl, void (*func)(void)) {
257     assert(func != NULL);
258     assert(ctl != NULL);
259     pthread_once(ctl, func);
260 }
261 #define LOADER_PLATFORM_THREAD_ONCE_DECLARATION(var) pthread_once_t var = PTHREAD_ONCE_INIT;
262 #define LOADER_PLATFORM_THREAD_ONCE_EXTERN_DEFINITION(var) extern pthread_once_t var;
263 #define LOADER_PLATFORM_THREAD_ONCE(ctl, func) loader_platform_thread_once_fn(ctl, func);
264 #elif defined(WIN32)
loader_platform_thread_win32_once_fn(INIT_ONCE * ctl,PINIT_ONCE_FN func)265 static inline void loader_platform_thread_win32_once_fn(INIT_ONCE *ctl, PINIT_ONCE_FN func) {
266     InitOnceExecuteOnce(ctl, func, NULL, NULL);
267 }
268 #define LOADER_PLATFORM_THREAD_ONCE_DECLARATION(var) INIT_ONCE var = INIT_ONCE_STATIC_INIT;
269 #define LOADER_PLATFORM_THREAD_ONCE_EXTERN_DEFINITION(var) extern INIT_ONCE var;
270 #define LOADER_PLATFORM_THREAD_ONCE(ctl, func) loader_platform_thread_win32_once_fn(ctl, func);
271 #else
272 #define LOADER_PLATFORM_THREAD_ONCE_DECLARATION(var)
273 #define LOADER_PLATFORM_THREAD_ONCE_EXTERN_DEFINITION(var)
274 #define LOADER_PLATFORM_THREAD_ONCE(ctl, func)
275 
276 #endif
277 
278 #if COMMON_UNIX_PLATFORMS
279 
280 // File IO
loader_platform_file_exists(const char * path)281 static inline bool loader_platform_file_exists(const char *path) {
282     if (access(path, F_OK))
283         return false;
284     else
285         return true;
286 }
287 
288 // Returns true if the given string appears to be a relative or absolute
289 // path, as opposed to a bare filename.
loader_platform_is_path_absolute(const char * path)290 static inline bool loader_platform_is_path_absolute(const char *path) {
291     if (path[0] == '/')
292         return true;
293     else
294         return false;
295 }
296 
loader_platform_dirname(char * path)297 static inline char *loader_platform_dirname(char *path) { return dirname(path); }
298 
299 // loader_platform_executable_path finds application path + name.
300 // Path cannot be longer than 1024, returns NULL if it is greater than that.
301 #if defined(__linux__) || defined(__GNU__)
loader_platform_executable_path(char * buffer,size_t size)302 static inline char *loader_platform_executable_path(char *buffer, size_t size) {
303     ssize_t count = readlink("/proc/self/exe", buffer, size);
304     if (count == -1) return NULL;
305     if (count == 0) return NULL;
306     buffer[count] = '\0';
307     return buffer;
308 }
309 #elif defined(__APPLE__)
310 #include <TargetConditionals.h>
311 // TARGET_OS_IPHONE isn't just iOS it's also iOS/tvOS/watchOS. See TargetConditionals.h documentation.
312 #if TARGET_OS_IPHONE
loader_platform_executable_path(char * buffer,size_t size)313 static inline char *loader_platform_executable_path(char *buffer, size_t size) {
314     (void)size;
315     buffer[0] = '\0';
316     return buffer;
317 }
318 #endif
319 #if TARGET_OS_OSX
320 #include <libproc.h>
loader_platform_executable_path(char * buffer,size_t size)321 static inline char *loader_platform_executable_path(char *buffer, size_t size) {
322     // proc_pidpath takes a uint32_t for the buffer size
323     if (size > UINT32_MAX) {
324         return NULL;
325     }
326     pid_t pid = getpid();
327     int ret = proc_pidpath(pid, buffer, (uint32_t)size);
328     if (ret <= 0) {
329         return NULL;
330     }
331     buffer[ret] = '\0';
332     return buffer;
333 }
334 #endif
335 #elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)
336 #include <sys/sysctl.h>
loader_platform_executable_path(char * buffer,size_t size)337 static inline char *loader_platform_executable_path(char *buffer, size_t size) {
338     int mib[] = {
339         CTL_KERN,
340 #if defined(__NetBSD__)
341         KERN_PROC_ARGS,
342         -1,
343         KERN_PROC_PATHNAME,
344 #else
345         KERN_PROC,
346         KERN_PROC_PATHNAME,
347         -1,
348 #endif
349     };
350     if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buffer, &size, NULL, 0) < 0) {
351         return NULL;
352     }
353 
354     return buffer;
355 }
356 #elif defined(__Fuchsia__) || defined(__OpenBSD__)
loader_platform_executable_path(char * buffer,size_t size)357 static inline char *loader_platform_executable_path(char *buffer, size_t size) { return NULL; }
358 #elif defined(__QNX__)
359 
360 #ifndef SYSCONFDIR
361 #define SYSCONFDIR "/etc"
362 #endif
363 
364 #include <fcntl.h>
365 #include <sys/stat.h>
366 
loader_platform_executable_path(char * buffer,size_t size)367 static inline char *loader_platform_executable_path(char *buffer, size_t size) {
368     int fd = open("/proc/self/exefile", O_RDONLY);
369     size_t rdsize;
370 
371     if (fd == -1) {
372         return NULL;
373     }
374 
375     rdsize = read(fd, buffer, size);
376     if (rdsize == size) {
377         return NULL;
378     }
379     buffer[rdsize] = 0x00;
380     close(fd);
381 
382     return buffer;
383 }
384 #endif  // defined (__QNX__)
385 
386 // Compatibility with compilers that don't support __has_feature
387 #if !defined(__has_feature)
388 #define __has_feature(x) 0
389 #endif
390 
391 #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
392 #define LOADER_ADDRESS_SANITIZER_ACTIVE  // TODO: Add proper build flag for ASAN support
393 #endif
394 
395 // When loading the library, we use RTLD_LAZY so that not all symbols have to be
396 // resolved at this time (which improves performance). Note that if not all symbols
397 // can be resolved, this could cause crashes later. Use the LD_BIND_NOW environment
398 // variable to force all symbols to be resolved here.
399 #define LOADER_DLOPEN_MODE (RTLD_LAZY | RTLD_LOCAL)
400 
401 #if defined(__Fuchsia__)
loader_platform_open_driver(const char * libPath)402 static inline loader_platform_dl_handle loader_platform_open_driver(const char *libPath) {
403     return dlopen_fuchsia(libPath, LOADER_DLOPEN_MODE, true);
404 }
loader_platform_open_library(const char * libPath)405 static inline loader_platform_dl_handle loader_platform_open_library(const char *libPath) {
406     return dlopen_fuchsia(libPath, LOADER_DLOPEN_MODE, false);
407 }
408 #elif defined(VK_USE_PLATFORM_OHOS)
loader_platform_open_library(const char * libPath)409 static inline loader_platform_dl_handle loader_platform_open_library(const char *libPath) {
410     void *handle = NULL;
411     Dl_namespace ns_ps;
412     if (!dlns_get("passthrough", &ns_ps)) {
413         handle = dlopen_ns(&ns_ps, libPath, LOADER_DLOPEN_MODE);
414     }
415     if (!handle) {
416         handle = dlopen(libPath, LOADER_DLOPEN_MODE);
417     }
418     return handle;
419 }
420 #else
loader_platform_open_library(const char * libPath)421 static inline loader_platform_dl_handle loader_platform_open_library(const char *libPath) {
422     return dlopen(libPath, LOADER_DLOPEN_MODE);
423 }
424 #endif
425 
loader_platform_open_library_error(const char * libPath)426 static inline const char *loader_platform_open_library_error(const char *libPath) {
427     (void)libPath;
428 #if defined(__Fuchsia__)
429     return dlerror_fuchsia();
430 #else
431     return dlerror();
432 #endif
433 }
loader_platform_close_library(loader_platform_dl_handle library)434 static inline void loader_platform_close_library(loader_platform_dl_handle library) {
435     if (!loader_disable_dynamic_library_unloading) {
436         dlclose(library);
437     } else {
438         (void)library;
439     }
440 }
loader_platform_get_proc_address(loader_platform_dl_handle library,const char * name)441 static inline void *loader_platform_get_proc_address(loader_platform_dl_handle library, const char *name) {
442     assert(library);
443     assert(name);
444     return dlsym(library, name);
445 }
loader_platform_get_proc_address_error(const char * name)446 static inline const char *loader_platform_get_proc_address_error(const char *name) {
447     (void)name;
448     return dlerror();
449 }
450 
451 // Thread mutex:
loader_platform_thread_create_mutex(loader_platform_thread_mutex * pMutex)452 static inline void loader_platform_thread_create_mutex(loader_platform_thread_mutex *pMutex) { pthread_mutex_init(pMutex, NULL); }
loader_platform_thread_lock_mutex(loader_platform_thread_mutex * pMutex)453 static inline void loader_platform_thread_lock_mutex(loader_platform_thread_mutex *pMutex) { pthread_mutex_lock(pMutex); }
loader_platform_thread_unlock_mutex(loader_platform_thread_mutex * pMutex)454 static inline void loader_platform_thread_unlock_mutex(loader_platform_thread_mutex *pMutex) { pthread_mutex_unlock(pMutex); }
loader_platform_thread_delete_mutex(loader_platform_thread_mutex * pMutex)455 static inline void loader_platform_thread_delete_mutex(loader_platform_thread_mutex *pMutex) { pthread_mutex_destroy(pMutex); }
456 
thread_safe_strtok(char * str,const char * delim,char ** saveptr)457 static inline void *thread_safe_strtok(char *str, const char *delim, char **saveptr) { return strtok_r(str, delim, saveptr); }
458 
loader_fopen(const char * fileName,const char * mode)459 static inline FILE *loader_fopen(const char *fileName, const char *mode) { return fopen(fileName, mode); }
loader_strncat(char * dest,size_t dest_sz,const char * src,size_t count)460 static inline char *loader_strncat(char *dest, size_t dest_sz, const char *src, size_t count) {
461     (void)dest_sz;
462     return strncat(dest, src, count);
463 }
loader_strncpy(char * dest,size_t dest_sz,const char * src,size_t count)464 static inline char *loader_strncpy(char *dest, size_t dest_sz, const char *src, size_t count) {
465     (void)dest_sz;
466     return strncpy(dest, src, count);
467 }
468 
469 #elif defined(_WIN32)
470 
471 // Get the key for the plug n play driver registry
472 // The string returned by this function should NOT be freed
LoaderPnpDriverRegistry()473 static inline const char *LoaderPnpDriverRegistry() {
474     BOOL is_wow;
475     IsWow64Process(GetCurrentProcess(), &is_wow);
476     return is_wow ? "Vulkan" VK_VARIANT_REG_STR "DriverNameWow" : "Vulkan" VK_VARIANT_REG_STR "DriverName";
477 }
LoaderPnpDriverRegistryWide()478 static inline const wchar_t *LoaderPnpDriverRegistryWide() {
479     BOOL is_wow;
480     IsWow64Process(GetCurrentProcess(), &is_wow);
481     return is_wow ? L"Vulkan" VK_VARIANT_REG_STR_W L"DriverNameWow" : L"Vulkan" VK_VARIANT_REG_STR_W L"DriverName";
482 }
483 
484 // Get the key for the plug 'n play explicit layer registry
485 // The string returned by this function should NOT be freed
LoaderPnpELayerRegistry()486 static inline const char *LoaderPnpELayerRegistry() {
487     BOOL is_wow;
488     IsWow64Process(GetCurrentProcess(), &is_wow);
489     return is_wow ? "Vulkan" VK_VARIANT_REG_STR "ExplicitLayersWow" : "Vulkan" VK_VARIANT_REG_STR "ExplicitLayers";
490 }
LoaderPnpELayerRegistryWide()491 static inline const wchar_t *LoaderPnpELayerRegistryWide() {
492     BOOL is_wow;
493     IsWow64Process(GetCurrentProcess(), &is_wow);
494     return is_wow ? L"Vulkan" VK_VARIANT_REG_STR_W L"ExplicitLayersWow" : L"Vulkan" VK_VARIANT_REG_STR_W L"ExplicitLayers";
495 }
496 
497 // Get the key for the plug 'n play implicit layer registry
498 // The string returned by this function should NOT be freed
LoaderPnpILayerRegistry()499 static inline const char *LoaderPnpILayerRegistry() {
500     BOOL is_wow;
501     IsWow64Process(GetCurrentProcess(), &is_wow);
502     return is_wow ? "Vulkan" VK_VARIANT_REG_STR "ImplicitLayersWow" : "Vulkan" VK_VARIANT_REG_STR "ImplicitLayers";
503 }
LoaderPnpILayerRegistryWide()504 static inline const wchar_t *LoaderPnpILayerRegistryWide() {
505     BOOL is_wow;
506     IsWow64Process(GetCurrentProcess(), &is_wow);
507     return is_wow ? L"Vulkan" VK_VARIANT_REG_STR_W L"ImplicitLayersWow" : L"Vulkan" VK_VARIANT_REG_STR_W L"ImplicitLayers";
508 }
509 
510 // File IO
loader_platform_file_exists(const char * path)511 static inline bool loader_platform_file_exists(const char *path) {
512     int path_utf16_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0);
513     if (path_utf16_size <= 0) {
514         return false;
515     }
516     wchar_t *path_utf16 = (wchar_t *)loader_stack_alloc(path_utf16_size * sizeof(wchar_t));
517     if (MultiByteToWideChar(CP_UTF8, 0, path, -1, path_utf16, path_utf16_size) != path_utf16_size) {
518         return false;
519     }
520     if (_waccess(path_utf16, 0) == -1)
521         return false;
522     else
523         return true;
524 }
525 
526 // Returns true if the given string appears to be a relative or absolute
527 // path, as opposed to a bare filename.
loader_platform_is_path_absolute(const char * path)528 static inline bool loader_platform_is_path_absolute(const char *path) {
529     if (!path || !*path) {
530         return false;
531     }
532     if (*path == DIRECTORY_SYMBOL || path[1] == ':') {
533         return true;
534     }
535     return false;
536 }
537 
538 // WIN32 runtime doesn't have dirname().
loader_platform_dirname(char * path)539 static inline char *loader_platform_dirname(char *path) {
540     char *current, *next;
541 
542     // TODO/TBD: Do we need to deal with the Windows's ":" character?
543 
544     for (current = path; *current != '\0'; current = next) {
545         next = strchr(current, DIRECTORY_SYMBOL);
546         if (next == NULL) {
547             if (current != path) *(current - 1) = '\0';
548             return path;
549         } else {
550             // Point one character past the DIRECTORY_SYMBOL:
551             next++;
552         }
553     }
554     return path;
555 }
556 
loader_platform_executable_path(char * buffer,size_t size)557 static inline char *loader_platform_executable_path(char *buffer, size_t size) {
558     wchar_t *buffer_utf16 = (wchar_t *)loader_stack_alloc(size * sizeof(wchar_t));
559     DWORD ret = GetModuleFileNameW(NULL, buffer_utf16, (DWORD)size);
560     if (ret == 0) {
561         return NULL;
562     }
563     if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
564         return NULL;
565     }
566     int buffer_utf8_size = WideCharToMultiByte(CP_UTF8, 0, buffer_utf16, -1, NULL, 0, NULL, NULL);
567     if (buffer_utf8_size <= 0 || (size_t)buffer_utf8_size > size) {
568         return NULL;
569     }
570     if (WideCharToMultiByte(CP_UTF8, 0, buffer_utf16, -1, buffer, buffer_utf8_size, NULL, NULL) != buffer_utf8_size) {
571         return NULL;
572     }
573     return buffer;
574 }
575 
576 // Dynamic Loading:
loader_platform_open_library(const char * lib_path)577 static inline loader_platform_dl_handle loader_platform_open_library(const char *lib_path) {
578     int lib_path_utf16_size = MultiByteToWideChar(CP_UTF8, 0, lib_path, -1, NULL, 0);
579     if (lib_path_utf16_size <= 0) {
580         return NULL;
581     }
582     wchar_t *lib_path_utf16 = (wchar_t *)loader_stack_alloc(lib_path_utf16_size * sizeof(wchar_t));
583     if (MultiByteToWideChar(CP_UTF8, 0, lib_path, -1, lib_path_utf16, lib_path_utf16_size) != lib_path_utf16_size) {
584         return NULL;
585     }
586     // Try loading the library the original way first.
587     loader_platform_dl_handle lib_handle = LoadLibraryW(lib_path_utf16);
588     if (lib_handle == NULL && GetLastError() == ERROR_MOD_NOT_FOUND) {
589         // If that failed, then try loading it with broader search folders.
590         lib_handle = LoadLibraryExW(lib_path_utf16, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
591     }
592     return lib_handle;
593 }
loader_platform_open_library_error(const char * libPath)594 static inline const char *loader_platform_open_library_error(const char *libPath) {
595     static char errorMsg[512];
596     (void)snprintf(errorMsg, 511, "Failed to open dynamic library \"%s\" with error %lu", libPath, GetLastError());
597     return errorMsg;
598 }
loader_platform_close_library(loader_platform_dl_handle library)599 static inline void loader_platform_close_library(loader_platform_dl_handle library) {
600     if (!loader_disable_dynamic_library_unloading) {
601         FreeLibrary(library);
602     } else {
603         (void)library;
604     }
605 }
loader_platform_get_proc_address(loader_platform_dl_handle library,const char * name)606 static inline void *loader_platform_get_proc_address(loader_platform_dl_handle library, const char *name) {
607     assert(library);
608     assert(name);
609     return (void *)GetProcAddress(library, name);
610 }
loader_platform_get_proc_address_error(const char * name)611 static inline const char *loader_platform_get_proc_address_error(const char *name) {
612     static char errorMsg[120];
613     (void)snprintf(errorMsg, 119, "Failed to find function \"%s\" in dynamic library", name);
614     return errorMsg;
615 }
616 
617 // Thread mutex:
loader_platform_thread_create_mutex(loader_platform_thread_mutex * pMutex)618 static inline void loader_platform_thread_create_mutex(loader_platform_thread_mutex *pMutex) { InitializeCriticalSection(pMutex); }
loader_platform_thread_lock_mutex(loader_platform_thread_mutex * pMutex)619 static inline void loader_platform_thread_lock_mutex(loader_platform_thread_mutex *pMutex) { EnterCriticalSection(pMutex); }
loader_platform_thread_unlock_mutex(loader_platform_thread_mutex * pMutex)620 static inline void loader_platform_thread_unlock_mutex(loader_platform_thread_mutex *pMutex) { LeaveCriticalSection(pMutex); }
loader_platform_thread_delete_mutex(loader_platform_thread_mutex * pMutex)621 static inline void loader_platform_thread_delete_mutex(loader_platform_thread_mutex *pMutex) { DeleteCriticalSection(pMutex); }
622 
thread_safe_strtok(char * str,const char * delimiters,char ** context)623 static inline void *thread_safe_strtok(char *str, const char *delimiters, char **context) {
624     return strtok_s(str, delimiters, context);
625 }
626 
loader_fopen(const char * fileName,const char * mode)627 static inline FILE *loader_fopen(const char *fileName, const char *mode) {
628     FILE *file = NULL;
629     errno_t err = fopen_s(&file, fileName, mode);
630     if (err != 0) return NULL;
631     return file;
632 }
633 
loader_strncat(char * dest,size_t dest_sz,const char * src,size_t count)634 static inline char *loader_strncat(char *dest, size_t dest_sz, const char *src, size_t count) {
635     errno_t err = strncat_s(dest, dest_sz, src, count);
636     if (err != 0) return NULL;
637     return dest;
638 }
639 
loader_strncpy(char * dest,size_t dest_sz,const char * src,size_t count)640 static inline char *loader_strncpy(char *dest, size_t dest_sz, const char *src, size_t count) {
641     errno_t err = strncpy_s(dest, dest_sz, src, count);
642     if (err != 0) return NULL;
643     return dest;
644 }
645 
646 #else  // defined(_WIN32)
647 
648 #warning The "vk_loader_platform.h" file must be modified for this OS.
649 
650 // NOTE: In order to support another OS, an #elif needs to be added (above the
651 // "#else // defined(_WIN32)") for that OS, and OS-specific versions of the
652 // contents of this file must be created.
653 
654 // NOTE: Other OS-specific changes are also needed for this OS.  Search for
655 // files with "WIN32" in it, as a quick way to find files that must be changed.
656 
657 #endif  // defined(_WIN32)
658