1 /** 2 * Dlang vulkan lib loader retrieving vkGetInstanceProcAddr for windows, macos and posix systems 3 * 4 * Copyright: Copyright 2015-2016 The Khronos Group Inc.; Copyright 2016 Alex Parrill, Peter Particle. 5 * License: $(https://opensource.org/licenses/MIT, MIT License). 6 * Authors: Copyright 2016 Alex Parrill, Peter Particle 7 */ 8 module erupted.vulkan_lib_loader; 9 10 import erupted.functions; 11 import core.stdc.stdio : fprintf, stderr, FILE; 12 13 nothrow @nogc: 14 15 16 /// private helper functions for windows platform 17 version( Windows ) { 18 private: 19 import core.sys.windows.windows; 20 HMODULE vulkan_lib = null; 21 auto loadLib() { return LoadLibrary( "vulkan-1.dll" ); } 22 bool freeLib() { return FreeLibrary( vulkan_lib ) != 0; } 23 auto loadSym() { return cast( PFN_vkGetInstanceProcAddr )GetProcAddress( vulkan_lib, "vkGetInstanceProcAddr" ); } 24 void logLibError( FILE* log_stream, const( char )* message ) { 25 fprintf( log_stream, "%svulkan-1.dll! Error code: 0x%x\n", message, GetLastError()); 26 } 27 } 28 29 30 /// private helper functions for android platform 31 else version( Android ) { 32 private: 33 import core.sys.posix.dlfcn : dlerror, dlopen, dlclose, dlsym, RTLD_NOW, RTLD_LOCAL; 34 void* vulkan_lib = null; 35 auto loadLib() { return dlopen( "libvulkan.so", RTLD_NOW | RTLD_LOCAL ); } 36 bool freeLib() { return dlclose( vulkan_lib ) == 0; } 37 auto loadSym() { return cast( PFN_vkGetInstanceProcAddr )dlsym( vulkan_lib, "vkGetInstanceProcAddr" ); } 38 void logLibError( FILE* log_stream, const( char )* message ) { 39 fprintf( log_stream, "%slibvulkan.so.1! Error: %s\n", message, dlerror ); 40 } 41 } 42 43 44 /// private helper functions for macos platforms 45 else version( OSX ) { 46 private: 47 import core.sys.posix.dlfcn : dlerror, dlopen, dlclose, dlsym, RTLD_LAZY, RTLD_LOCAL; 48 void* vulkan_lib = null; 49 auto loadLib() { return dlopen( "libvulkan.1.dylib", RTLD_LAZY | RTLD_LOCAL ); } 50 bool freeLib() { return dlclose( vulkan_lib ) == 0; } 51 auto loadSym() { return cast( PFN_vkGetInstanceProcAddr )dlsym( vulkan_lib, "vkGetInstanceProcAddr" ); } 52 void logLibError( FILE* log_stream, const( char )* message ) { 53 fprintf( log_stream, "%slibvulkan.1.dylib! Error: %s\n", message, dlerror ); 54 } 55 } 56 57 58 /// private helper functions for posix platforms 59 else version( Posix ) { 60 private: 61 import core.sys.posix.dlfcn : dlerror, dlopen, dlclose, dlsym, RTLD_LAZY, RTLD_LOCAL; 62 void* vulkan_lib = null; 63 auto loadLib() { return dlopen( "libvulkan.so.1", RTLD_LAZY | RTLD_LOCAL ); } 64 bool freeLib() { return dlclose( vulkan_lib ) == 0; } 65 auto loadSym() { return cast( PFN_vkGetInstanceProcAddr )dlsym( vulkan_lib, "vkGetInstanceProcAddr" ); } 66 void logLibError( FILE* log_stream, const( char )* message ) { 67 fprintf( log_stream, "%slibvulkan.so.1! Error: %s\n", message, dlerror ); 68 } 69 } 70 71 72 /// tries to load the platform vulkan dynamic link library 73 /// the library handle / pointer is stored privately in this module 74 /// errors are reported to a specifiable stream which is standard error by default 75 /// Params: 76 /// log_stream = file stream to receive error messages, default stderr 77 /// Returns: true if the vulkan lib could be loaded, false otherwise 78 bool loadVulkanLib( FILE* log_stream = stderr ) { 79 vulkan_lib = loadLib; 80 if( !vulkan_lib ) { 81 logLibError( log_stream, "Could not load " ); 82 return false; 83 } else { 84 return true; 85 } 86 } 87 88 89 /// tries to load the vkGetInstanceProcAddr function from the module private lib handle / pointer 90 /// if the lib was not loaded so far loadVulkanLib is called 91 /// errors are reported to a specifiable stream which is standard error by default 92 /// Params: 93 /// log_stream = file stream to receive error messages, default stderr 94 /// Returns: vkGetInstanceProcAddr if it could be loaded from the lib, null otherwise 95 PFN_vkGetInstanceProcAddr loadGetInstanceProcAddr( FILE* log_stream = stderr ) { 96 if( !vulkan_lib && !loadVulkanLib( log_stream )) { 97 fprintf( log_stream, "Cannot not retrieve vkGetInstanceProcAddr as vulkan lib is not loaded!" ); 98 return null; 99 } 100 auto getInstanceProcAddr = loadSym; 101 if( !getInstanceProcAddr ) 102 logLibError( log_stream, "Could not retrieve vkGetInstanceProcAddr from " ); 103 return getInstanceProcAddr; 104 } 105 106 107 /// tries to free / unload the previously loaded platform vulkan lib 108 /// errors are reported to a specifiable stream which is standard error by default 109 /// Params: 110 /// log_stream = file stream to receive error messages, default stderr 111 /// Returns: true if the vulkan lib could be freed, false otherwise 112 bool freeVulkanLib( FILE* log_stream = stderr ) { 113 if( !vulkan_lib ) { 114 fprintf( log_stream, "Cannot free vulkan lib as it is not loaded!" ); 115 return false; 116 } else if( !freeLib() ) { 117 logLibError( log_stream, "Could not unload " ); 118 return false; 119 } else { 120 return true; 121 } 122 } 123 124 125 /// Combines loadVulkanLib, loadGetInstanceProcAddr and loadGlobalLevelFunctions( PFN_vkGetInstanceProcAddr ) 126 /// from module erupted.functions. If this function succeeds the function vkGetInstanceProcAddr 127 /// from module erupted.functions can be used freely. Moreover the required functions to initialize a 128 /// vulkan instance a vkEnumerateInstanceExtensionProperties, vkEnumerateInstanceLayerProperties and vkCreateInstance 129 /// are available as well. To get all the other functions an vulkan instance must be created and with it 130 /// loadInstanceLevelFunctions be called from either erupted.functions or through a custom tailored module 131 /// with mixed in extensions through the erupted.platform.mixin_extensions mechanism. 132 /// Additional device based functions can then be loaded with loadDeviceLevelFunctions passing in the instance or 133 /// with creating a vulkan device beforehand and calling the same function with it. 134 /// 135 /// Note: as this function indirectly calls loadVulkanLib loading the vulkan lib, freeVulkanLib should be called 136 /// at some point in the process to cleanly free / unload the lib 137 /// all errors during vulkan lib loading and vkGetInstanceProcAddr retrieving are reported to log_stream, default stderr 138 /// log_stream = file stream to receive error messages, default stderr 139 /// Returns: true if the vulkan lib could be freed, false otherwise 140 bool loadGlobalLevelFunctions( FILE* log_stream = stderr ) { 141 auto getInstanceProcAddr = loadGetInstanceProcAddr( log_stream ); 142 if( !getInstanceProcAddr ) return false; 143 erupted.functions.loadGlobalLevelFunctions( getInstanceProcAddr ); 144 return true; 145 } 146 147