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 * 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@lunarg.com>
20 * Author: Jon Ashburn <jon@lunarg.com>
21 *
22 */
23 #pragma once
24
25 #if defined(_WIN32)
26 // WinSock2.h must be included *BEFORE* windows.h
27 #include <WinSock2.h>
28 #endif // _WIN32
29
30 #include "vulkan/vk_platform.h"
31 #include "vulkan/vk_sdk_platform.h"
32
33 #if defined(__linux__)
34 /* Linux-specific common code: */
35
36 // Headers:
37 //#define _GNU_SOURCE 1
38 // TBD: Are the contents of the following file used?
39 #include <unistd.h>
40 // Note: The following file is for dynamic loading:
41 #include <dlfcn.h>
42 #include <pthread.h>
43 #include <assert.h>
44 #include <string.h>
45 #include <stdbool.h>
46 #include <stdlib.h>
47 #include <libgen.h>
48
49 // VK Library Filenames, Paths, etc.:
50 #define PATH_SEPERATOR ':'
51 #define DIRECTORY_SYMBOL '/'
52
53 #define VULKAN_DIR "/vulkan/"
54 #define VULKAN_ICDCONF_DIR "icd.d"
55 #define VULKAN_ICD_DIR "icd"
56 #define VULKAN_ELAYERCONF_DIR "explicit_layer.d"
57 #define VULKAN_ILAYERCONF_DIR "implicit_layer.d"
58 #define VULKAN_LAYER_DIR "layer"
59
60 #if defined(LOCALPREFIX)
61 #define LOCAL_DRIVERS_INFO \
62 LOCALPREFIX "/" SYSCONFDIR VULKAN_DIR VULKAN_ICDCONF_DIR ":" \
63 LOCALPREFIX "/" DATADIR VULKAN_DIR VULKAN_ICDCONF_DIR ":"
64 #define LOCAL_ELAYERS_INFO \
65 LOCALPREFIX "/" SYSCONFDIR VULKAN_DIR VULKAN_ELAYERCONF_DIR ":" \
66 LOCALPREFIX "/" DATADIR VULKAN_DIR VULKAN_ELAYERCONF_DIR ":"
67 #define LOCAL_ILAYERS_INFO \
68 LOCALPREFIX "/" SYSCONFDIR VULKAN_DIR VULKAN_ILAYERCONF_DIR ":" \
69 LOCALPREFIX "/" DATADIR VULKAN_DIR VULKAN_ILAYERCONF_DIR ":"
70 #else
71 #define LOCAL_DRIVERS_INFO
72 #define LOCAL_ELAYERS_INFO
73 #define LOCAL_ILAYERS_INFO
74 #endif
75
76 #define DEFAULT_VK_DRIVERS_INFO \
77 LOCAL_DRIVERS_INFO \
78 "/" SYSCONFDIR VULKAN_DIR VULKAN_ICDCONF_DIR ":" \
79 "/usr/" DATADIR VULKAN_DIR VULKAN_ICDCONF_DIR
80 #define DEFAULT_VK_DRIVERS_PATH ""
81 #define DEFAULT_VK_ELAYERS_INFO \
82 LOCAL_ELAYERS_INFO \
83 "/" SYSCONFDIR VULKAN_DIR VULKAN_ELAYERCONF_DIR ":" \
84 "/usr/" DATADIR VULKAN_DIR VULKAN_ELAYERCONF_DIR
85 #define DEFAULT_VK_ILAYERS_INFO \
86 LOCAL_ILAYERS_INFO \
87 "/" SYSCONFDIR VULKAN_DIR VULKAN_ILAYERCONF_DIR ":" \
88 "/usr/" DATADIR VULKAN_DIR VULKAN_ILAYERCONF_DIR
89 #define DEFAULT_VK_LAYERS_PATH ""
90 #if !defined(LAYERS_SOURCE_PATH)
91 #define LAYERS_SOURCE_PATH NULL
92 #endif
93 #define LAYERS_PATH_ENV "VK_LAYER_PATH"
94 #define HOME_VK_DRIVERS_INFO VULKAN_DIR VULKAN_ICDCONF_DIR
95 #define HOME_VK_ELAYERS_INFO VULKAN_DIR VULKAN_ELAYERCONF_DIR
96 #define HOME_VK_ILAYERS_INFO VULKAN_DIR VULKAN_ILAYERCONF_DIR
97
98 // C99:
99 #define PRINTF_SIZE_T_SPECIFIER "%zu"
100
101 // File IO
loader_platform_file_exists(const char * path)102 static inline bool loader_platform_file_exists(const char *path) {
103 if (access(path, F_OK))
104 return false;
105 else
106 return true;
107 }
108
loader_platform_is_path_absolute(const char * path)109 static inline bool loader_platform_is_path_absolute(const char *path) {
110 if (path[0] == '/')
111 return true;
112 else
113 return false;
114 }
115
loader_platform_dirname(char * path)116 static inline char *loader_platform_dirname(char *path) {
117 return dirname(path);
118 }
119
120 // Dynamic Loading of libraries:
121 typedef void *loader_platform_dl_handle;
122 static inline loader_platform_dl_handle
loader_platform_open_library(const char * libPath)123 loader_platform_open_library(const char *libPath) {
124 return dlopen(libPath, RTLD_LAZY | RTLD_LOCAL);
125 }
126 static inline const char *
loader_platform_open_library_error(const char * libPath)127 loader_platform_open_library_error(const char *libPath) {
128 return dlerror();
129 }
130 static inline void
loader_platform_close_library(loader_platform_dl_handle library)131 loader_platform_close_library(loader_platform_dl_handle library) {
132 dlclose(library);
133 }
134 static inline void *
loader_platform_get_proc_address(loader_platform_dl_handle library,const char * name)135 loader_platform_get_proc_address(loader_platform_dl_handle library,
136 const char *name) {
137 assert(library);
138 assert(name);
139 return dlsym(library, name);
140 }
141 static inline const char *
loader_platform_get_proc_address_error(const char * name)142 loader_platform_get_proc_address_error(const char *name) {
143 return dlerror();
144 }
145
146 // Threads:
147 typedef pthread_t loader_platform_thread;
148 #define THREAD_LOCAL_DECL __thread
149 #define LOADER_PLATFORM_THREAD_ONCE_DECLARATION(var) \
150 pthread_once_t var = PTHREAD_ONCE_INIT;
151 #define LOADER_PLATFORM_THREAD_ONCE_DEFINITION(var) pthread_once_t var;
loader_platform_thread_once(pthread_once_t * ctl,void (* func)(void))152 static inline void loader_platform_thread_once(pthread_once_t *ctl,
153 void (*func)(void)) {
154 assert(func != NULL);
155 assert(ctl != NULL);
156 pthread_once(ctl, func);
157 }
158
159 // Thread IDs:
160 typedef pthread_t loader_platform_thread_id;
loader_platform_get_thread_id()161 static inline loader_platform_thread_id loader_platform_get_thread_id() {
162 return pthread_self();
163 }
164
165 // Thread mutex:
166 typedef pthread_mutex_t loader_platform_thread_mutex;
167 static inline void
loader_platform_thread_create_mutex(loader_platform_thread_mutex * pMutex)168 loader_platform_thread_create_mutex(loader_platform_thread_mutex *pMutex) {
169 pthread_mutex_init(pMutex, NULL);
170 }
171 static inline void
loader_platform_thread_lock_mutex(loader_platform_thread_mutex * pMutex)172 loader_platform_thread_lock_mutex(loader_platform_thread_mutex *pMutex) {
173 pthread_mutex_lock(pMutex);
174 }
175 static inline void
loader_platform_thread_unlock_mutex(loader_platform_thread_mutex * pMutex)176 loader_platform_thread_unlock_mutex(loader_platform_thread_mutex *pMutex) {
177 pthread_mutex_unlock(pMutex);
178 }
179 static inline void
loader_platform_thread_delete_mutex(loader_platform_thread_mutex * pMutex)180 loader_platform_thread_delete_mutex(loader_platform_thread_mutex *pMutex) {
181 pthread_mutex_destroy(pMutex);
182 }
183 typedef pthread_cond_t loader_platform_thread_cond;
184 static inline void
loader_platform_thread_init_cond(loader_platform_thread_cond * pCond)185 loader_platform_thread_init_cond(loader_platform_thread_cond *pCond) {
186 pthread_cond_init(pCond, NULL);
187 }
188 static inline void
loader_platform_thread_cond_wait(loader_platform_thread_cond * pCond,loader_platform_thread_mutex * pMutex)189 loader_platform_thread_cond_wait(loader_platform_thread_cond *pCond,
190 loader_platform_thread_mutex *pMutex) {
191 pthread_cond_wait(pCond, pMutex);
192 }
193 static inline void
loader_platform_thread_cond_broadcast(loader_platform_thread_cond * pCond)194 loader_platform_thread_cond_broadcast(loader_platform_thread_cond *pCond) {
195 pthread_cond_broadcast(pCond);
196 }
197
198 #define loader_stack_alloc(size) alloca(size)
199
200 #elif defined(_WIN32) // defined(__linux__)
201 /* Windows-specific common code: */
202 // WinBase.h defines CreateSemaphore and synchapi.h defines CreateEvent
203 // undefine them to avoid conflicts with VkLayerDispatchTable struct members.
204 #ifdef CreateSemaphore
205 #undef CreateSemaphore
206 #endif
207 #ifdef CreateEvent
208 #undef CreateEvent
209 #endif
210 #include <assert.h>
211 #include <stdio.h>
212 #include <string.h>
213 #include <io.h>
214 #include <stdbool.h>
215 #include <shlwapi.h>
216 #ifdef __cplusplus
217 #include <iostream>
218 #include <string>
219 using namespace std;
220 #endif // __cplusplus
221
222 // VK Library Filenames, Paths, etc.:
223 #define PATH_SEPERATOR ';'
224 #define DIRECTORY_SYMBOL '\\'
225 #define DEFAULT_VK_REGISTRY_HIVE HKEY_LOCAL_MACHINE
226 #define DEFAULT_VK_DRIVERS_INFO "SOFTWARE\\Khronos\\Vulkan\\Drivers"
227 // TODO: Are these the correct paths
228 #define DEFAULT_VK_DRIVERS_PATH ""
229 #define DEFAULT_VK_ELAYERS_INFO "SOFTWARE\\Khronos\\Vulkan\\ExplicitLayers"
230 #define DEFAULT_VK_ILAYERS_INFO "SOFTWARE\\Khronos\\Vulkan\\ImplicitLayers"
231 #if !defined(DEFAULT_VK_LAYERS_PATH)
232 #define DEFAULT_VK_LAYERS_PATH ""
233 #endif
234 #if !defined(LAYERS_SOURCE_PATH)
235 #define LAYERS_SOURCE_PATH NULL
236 #endif
237 #define LAYERS_PATH_ENV "VK_LAYER_PATH"
238 #define HOME_VK_DRIVERS_INFO ""
239 #define HOME_VK_ELAYERS_INFO ""
240 #define HOME_VK_ILAYERS_INFO ""
241 #define PRINTF_SIZE_T_SPECIFIER "%Iu"
242
243 // File IO
loader_platform_file_exists(const char * path)244 static bool loader_platform_file_exists(const char *path) {
245 if ((_access(path, 0)) == -1)
246 return false;
247 else
248 return true;
249 }
250
loader_platform_is_path_absolute(const char * path)251 static bool loader_platform_is_path_absolute(const char *path) {
252 return !PathIsRelative(path);
253 }
254
255 // WIN32 runtime doesn't have dirname().
loader_platform_dirname(char * path)256 static inline char *loader_platform_dirname(char *path) {
257 char *current, *next;
258
259 // TODO/TBD: Do we need to deal with the Windows's ":" character?
260
261 for (current = path; *current != '\0'; current = next) {
262 next = strchr(current, DIRECTORY_SYMBOL);
263 if (next == NULL) {
264 if (current != path)
265 *(current - 1) = '\0';
266 return path;
267 } else {
268 // Point one character past the DIRECTORY_SYMBOL:
269 next++;
270 }
271 }
272 return path;
273 }
274
275 // WIN32 runtime doesn't have basename().
276 // Microsoft also doesn't have basename(). Paths are different on Windows, and
277 // so this is just a temporary solution in order to get us compiling, so that we
278 // can test some scenarios, and develop the correct solution for Windows.
279 // TODO: Develop a better, permanent solution for Windows, to replace this
280 // temporary code:
loader_platform_basename(char * pathname)281 static char *loader_platform_basename(char *pathname) {
282 char *current, *next;
283
284 // TODO/TBD: Do we need to deal with the Windows's ":" character?
285
286 for (current = pathname; *current != '\0'; current = next) {
287 next = strchr(current, DIRECTORY_SYMBOL);
288 if (next == NULL) {
289 // No more DIRECTORY_SYMBOL's so return p:
290 return current;
291 } else {
292 // Point one character past the DIRECTORY_SYMBOL:
293 next++;
294 }
295 }
296 // We shouldn't get to here, but this makes the compiler happy:
297 return current;
298 }
299
300 // Dynamic Loading:
301 typedef HMODULE loader_platform_dl_handle;
302 static loader_platform_dl_handle
loader_platform_open_library(const char * libPath)303 loader_platform_open_library(const char *libPath) {
304 return LoadLibrary(libPath);
305 }
loader_platform_open_library_error(const char * libPath)306 static char *loader_platform_open_library_error(const char *libPath) {
307 static char errorMsg[164];
308 snprintf(errorMsg, 163, "Failed to open dynamic library \"%s\"", libPath);
309 return errorMsg;
310 }
loader_platform_close_library(loader_platform_dl_handle library)311 static void loader_platform_close_library(loader_platform_dl_handle library) {
312 FreeLibrary(library);
313 }
loader_platform_get_proc_address(loader_platform_dl_handle library,const char * name)314 static void *loader_platform_get_proc_address(loader_platform_dl_handle library,
315 const char *name) {
316 assert(library);
317 assert(name);
318 return GetProcAddress(library, name);
319 }
loader_platform_get_proc_address_error(const char * name)320 static char *loader_platform_get_proc_address_error(const char *name) {
321 static char errorMsg[120];
322 snprintf(errorMsg, 119, "Failed to find function \"%s\" in dynamic library",
323 name);
324 return errorMsg;
325 }
326
327 // Threads:
328 typedef HANDLE loader_platform_thread;
329 #define THREAD_LOCAL_DECL __declspec(thread)
330 #define LOADER_PLATFORM_THREAD_ONCE_DECLARATION(var) \
331 INIT_ONCE var = INIT_ONCE_STATIC_INIT;
332 #define LOADER_PLATFORM_THREAD_ONCE_DEFINITION(var) INIT_ONCE var;
333 static BOOL CALLBACK
InitFuncWrapper(PINIT_ONCE InitOnce,PVOID Parameter,PVOID * Context)334 InitFuncWrapper(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context) {
335 void (*func)(void) = (void (*)(void))Parameter;
336 func();
337 return TRUE;
338 }
339
loader_platform_thread_once(void * ctl,void (* func)(void))340 static void loader_platform_thread_once(void *ctl, void (*func)(void)) {
341 assert(func != NULL);
342 assert(ctl != NULL);
343 InitOnceExecuteOnce((PINIT_ONCE)ctl, InitFuncWrapper, func, NULL);
344 }
345
346 // Thread IDs:
347 typedef DWORD loader_platform_thread_id;
loader_platform_get_thread_id()348 static loader_platform_thread_id loader_platform_get_thread_id() {
349 return GetCurrentThreadId();
350 }
351
352 // Thread mutex:
353 typedef CRITICAL_SECTION loader_platform_thread_mutex;
354 static void
loader_platform_thread_create_mutex(loader_platform_thread_mutex * pMutex)355 loader_platform_thread_create_mutex(loader_platform_thread_mutex *pMutex) {
356 InitializeCriticalSection(pMutex);
357 }
358 static void
loader_platform_thread_lock_mutex(loader_platform_thread_mutex * pMutex)359 loader_platform_thread_lock_mutex(loader_platform_thread_mutex *pMutex) {
360 EnterCriticalSection(pMutex);
361 }
362 static void
loader_platform_thread_unlock_mutex(loader_platform_thread_mutex * pMutex)363 loader_platform_thread_unlock_mutex(loader_platform_thread_mutex *pMutex) {
364 LeaveCriticalSection(pMutex);
365 }
366 static void
loader_platform_thread_delete_mutex(loader_platform_thread_mutex * pMutex)367 loader_platform_thread_delete_mutex(loader_platform_thread_mutex *pMutex) {
368 DeleteCriticalSection(pMutex);
369 }
370 typedef CONDITION_VARIABLE loader_platform_thread_cond;
371 static void
loader_platform_thread_init_cond(loader_platform_thread_cond * pCond)372 loader_platform_thread_init_cond(loader_platform_thread_cond *pCond) {
373 InitializeConditionVariable(pCond);
374 }
375 static void
loader_platform_thread_cond_wait(loader_platform_thread_cond * pCond,loader_platform_thread_mutex * pMutex)376 loader_platform_thread_cond_wait(loader_platform_thread_cond *pCond,
377 loader_platform_thread_mutex *pMutex) {
378 SleepConditionVariableCS(pCond, pMutex, INFINITE);
379 }
380 static void
loader_platform_thread_cond_broadcast(loader_platform_thread_cond * pCond)381 loader_platform_thread_cond_broadcast(loader_platform_thread_cond *pCond) {
382 WakeAllConditionVariable(pCond);
383 }
384
385 // Windows Registry:
386 char *loader_get_registry_string(const HKEY hive, const LPCTSTR sub_key,
387 const char *value);
388
389 #define loader_stack_alloc(size) _alloca(size)
390 #else // defined(_WIN32)
391
392 #error The "loader_platform.h" file must be modified for this OS.
393
394 // NOTE: In order to support another OS, an #elif needs to be added (above the
395 // "#else // defined(_WIN32)") for that OS, and OS-specific versions of the
396 // contents of this file must be created.
397
398 // NOTE: Other OS-specific changes are also needed for this OS. Search for
399 // files with "WIN32" in it, as a quick way to find files that must be changed.
400
401 #endif // defined(_WIN32)
402
403 // returns true if the given string appears to be a relative or absolute
404 // path, as opposed to a bare filename.
loader_platform_is_path(const char * path)405 static inline bool loader_platform_is_path(const char *path) {
406 return strchr(path, DIRECTORY_SYMBOL) != NULL;
407 }
408