Home | History | Annotate | Download | only in loader
      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