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@lunarg.com>
27  * Author: Jon Ashburn <jon@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
loader_platform_file_exists(const char * path)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 
loader_platform_is_path_absolute(const char * path)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 
loader_platform_dirname(char * path)139 static inline char *loader_platform_dirname(char *path) {
140     return dirname(path);
141 }
142 
143 // Environment variables
144 
loader_getenv(const char * name)145 static inline char *loader_getenv(const char *name) { return getenv(name); }
146 
loader_free_getenv(const char * val)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
loader_platform_open_library(const char * libPath)152 loader_platform_open_library(const char *libPath) {
153     return dlopen(libPath, RTLD_LAZY | RTLD_LOCAL);
154 }
155 static inline const char *
loader_platform_open_library_error(const char * libPath)156 loader_platform_open_library_error(const char *libPath) {
157     return dlerror();
158 }
159 static inline void
loader_platform_close_library(loader_platform_dl_handle library)160 loader_platform_close_library(loader_platform_dl_handle library) {
161     dlclose(library);
162 }
163 static inline void *
loader_platform_get_proc_address(loader_platform_dl_handle library,const char * name)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 *
loader_platform_get_proc_address_error(const char * name)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;
loader_platform_thread_once(pthread_once_t * ctl,void (* func)(void))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;
loader_platform_get_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
loader_platform_thread_create_mutex(loader_platform_thread_mutex * pMutex)197 loader_platform_thread_create_mutex(loader_platform_thread_mutex *pMutex) {
198     pthread_mutex_init(pMutex, NULL);
199 }
200 static inline void
loader_platform_thread_lock_mutex(loader_platform_thread_mutex * pMutex)201 loader_platform_thread_lock_mutex(loader_platform_thread_mutex *pMutex) {
202     pthread_mutex_lock(pMutex);
203 }
204 static inline void
loader_platform_thread_unlock_mutex(loader_platform_thread_mutex * pMutex)205 loader_platform_thread_unlock_mutex(loader_platform_thread_mutex *pMutex) {
206     pthread_mutex_unlock(pMutex);
207 }
208 static inline void
loader_platform_thread_delete_mutex(loader_platform_thread_mutex * pMutex)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
loader_platform_thread_init_cond(loader_platform_thread_cond * pCond)214 loader_platform_thread_init_cond(loader_platform_thread_cond *pCond) {
215     pthread_cond_init(pCond, NULL);
216 }
217 static inline void
loader_platform_thread_cond_wait(loader_platform_thread_cond * pCond,loader_platform_thread_mutex * pMutex)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
loader_platform_thread_cond_broadcast(loader_platform_thread_cond * pCond)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
loader_platform_file_exists(const char * path)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 
loader_platform_is_path_absolute(const char * path)275 static bool loader_platform_is_path_absolute(const char *path) {
276     return !PathIsRelative(path);
277 }
278 
279 // WIN32 runtime doesn't have dirname().
loader_platform_dirname(char * path)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:
loader_platform_basename(char * pathname)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 
loader_getenv(const char * name)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 
loader_free_getenv(const char * val)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
loader_platform_open_library(const char * libPath)350 loader_platform_open_library(const char *libPath) {
351     return LoadLibrary(libPath);
352 }
loader_platform_open_library_error(const char * libPath)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 }
loader_platform_close_library(loader_platform_dl_handle library)358 static void loader_platform_close_library(loader_platform_dl_handle library) {
359     FreeLibrary(library);
360 }
loader_platform_get_proc_address(loader_platform_dl_handle library,const char * name)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 }
loader_platform_get_proc_address_error(const char * name)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
InitFuncWrapper(PINIT_ONCE InitOnce,PVOID Parameter,PVOID * Context)381 InitFuncWrapper(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context) {
382     void (*func)(void) = (void (*)(void))Parameter;
383     func();
384     return TRUE;
385 }
386 
loader_platform_thread_once(void * ctl,void (* func)(void))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;
loader_platform_get_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
loader_platform_thread_create_mutex(loader_platform_thread_mutex * pMutex)402 loader_platform_thread_create_mutex(loader_platform_thread_mutex *pMutex) {
403     InitializeCriticalSection(pMutex);
404 }
405 static void
loader_platform_thread_lock_mutex(loader_platform_thread_mutex * pMutex)406 loader_platform_thread_lock_mutex(loader_platform_thread_mutex *pMutex) {
407     EnterCriticalSection(pMutex);
408 }
409 static void
loader_platform_thread_unlock_mutex(loader_platform_thread_mutex * pMutex)410 loader_platform_thread_unlock_mutex(loader_platform_thread_mutex *pMutex) {
411     LeaveCriticalSection(pMutex);
412 }
413 static void
loader_platform_thread_delete_mutex(loader_platform_thread_mutex * pMutex)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
loader_platform_thread_init_cond(loader_platform_thread_cond * pCond)419 loader_platform_thread_init_cond(loader_platform_thread_cond *pCond) {
420     InitializeConditionVariable(pCond);
421 }
422 static void
loader_platform_thread_cond_wait(loader_platform_thread_cond * pCond,loader_platform_thread_mutex * pMutex)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
loader_platform_thread_cond_broadcast(loader_platform_thread_cond * pCond)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.
loader_platform_is_path(const char * path)452 static inline bool loader_platform_is_path(const char *path) {
453     return strchr(path, DIRECTORY_SYMBOL) != NULL;
454 }
455