Vulkan Support Check and Dynamic Loader C++ code sample
很多时候不想静态依赖VulkanSDK所提供的静态库,因为会遇到一些过早的电脑不支持vulkan,
那么就需要使用动态加载vulkan-1.dll(for Windows)或libMoltenVK.dylib(for MacOS)的方式进行判断了。
VulkanSDK提供了相关头文件实现可以做到相关功能,仅需要include一下头文件 `vulkan/vulkan.hpp`,不需要再额外链接它的vulkan-1.lib文件
本段代码包含三个部分:
1. 判断是否支持vulkan(简单判断)
2. 从系统动态链接库(显卡厂商提供的dll)动态加载Vulkan,然后初始化。
3. 实际使用导出的函数,去遍历此电脑所有支持vulkan的设备。
那么直接贴代码:
1 #include "vulkan/vulkan.hpp" 2 3 struct GpuInfo 4 { 5 uint32_t api_version = 0; 6 uint32_t driver_version = 0; 7 uint32_t vendor_id = 0; 8 uint32_t device_id = 0; 9 char device_name[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE] = {0}; 10 // 0 = discrete gpu 11 // 1 = integrated gpu 12 // 2 = virtual gpu 13 // 3 = cpu 14 int type = 0; 15 }; 16 17 std::vector<GpuInfo> gpuInfos; 18 19 bool isSupportVulkan = false; 20 std::unique_ptr<vk::DynamicLoader> vulkanDynamicLoader; 21 std::unique_ptr<vk::DispatchLoaderDynamic> vulkanDispatchLoaderDynamic; 22 23 try 24 { 25 #ifdef WIN32 26 std::string vulkanLibraryFilePath = "vulkan-1.dll"; 27 #else //APPLE 28 std::string vulkanLibraryFilePath = diropt::CurrentPath() + "/Contents/Frameworks/libMoltenVK.dylib"; 29 #endif 30 vulkanDynamicLoader = std::make_unique<vk::DynamicLoader>(vulkanLibraryFilePath); 31 } 32 catch(std::runtime_error& ex) 33 { 34 isSupportVulkan = false; 35 return -1; 36 } 37 if(!vulkanDynamicLoader) 38 { 39 isSupportVulkan = false; 40 return -1; 41 } 42 isSupportVulkan = vulkanDynamicLoader->success(); 43 if(!isSupportVulkan) 44 { 45 isSupportVulkan = false; 46 return -1; 47 } 48 PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = vulkanDynamicLoader->getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr"); 49 if(!vkGetInstanceProcAddr) 50 { 51 isSupportVulkan = false; 52 return -1; 53 } 54 55 // 用vkGetInstanceProcAddr指针去创建默认的分发器对象并初始化 56 vulkanDispatchLoaderDynamic = std::make_unique<vk::DispatchLoaderDynamic>(vkGetInstanceProcAddr); 57 58 VkResult ret; 59 VkInstance g_instance; 60 uint32_t instance_api_version = VK_MAKE_VERSION(1, 0, 0); 61 typedef VkResult(VKAPI_PTR * PFN_vkEnumerateInstanceVersion)(uint32_t * pApiVersion); 62 PFN_vkEnumerateInstanceVersion vkEnumerateInstanceVersion = 63 (PFN_vkEnumerateInstanceVersion)vulkanDispatchLoaderDynamic->vkGetInstanceProcAddr(0, "vkEnumerateInstanceVersion"); 64 if (vkEnumerateInstanceVersion) 65 { 66 //列举vulkan实例的版本 67 ret = vkEnumerateInstanceVersion(&instance_api_version); 68 if (ret != VK_SUCCESS) 69 { 70 return -1; 71 } 72 } 73 74 VkApplicationInfo applicationInfo; 75 applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; 76 applicationInfo.pNext = 0; 77 applicationInfo.pApplicationName = "vulkan-check"; 78 applicationInfo.applicationVersion = 0; 79 applicationInfo.pEngineName = "vulkan-check"; 80 applicationInfo.engineVersion = 20230447; 81 applicationInfo.apiVersion = instance_api_version; 82 83 VkInstanceCreateInfo instanceCreateInfo; 84 instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; 85 instanceCreateInfo.pNext = 0; 86 instanceCreateInfo.flags = 0; 87 instanceCreateInfo.pApplicationInfo = &applicationInfo; 88 instanceCreateInfo.enabledLayerCount = 0; 89 instanceCreateInfo.ppEnabledLayerNames = 0; 90 instanceCreateInfo.enabledExtensionCount = 0; 91 instanceCreateInfo.ppEnabledExtensionNames = 0; 92 93 VkInstance instance = 0; 94 //创建Vulkan实例 95 ret = vulkanDispatchLoaderDynamic->vkCreateInstance(&instanceCreateInfo, 0, &instance); 96 if (ret != VK_SUCCESS) 97 { 98 return -1; 99 } 100 g_instance = instance; 101 102 //再用已经创建好的Vulkan实例去进一步初始化vulkanDispatchLoaderDynamic 103 vulkanDispatchLoaderDynamic->init(instance, vkGetInstanceProcAddr); 104 105 //获取所有支持vulkan的设备列表 106 uint32_t physicalDeviceCount = 0; 107 ret = vulkanDispatchLoaderDynamic->vkEnumeratePhysicalDevices(g_instance, &physicalDeviceCount, 0); 108 if (ret != VK_SUCCESS) 109 { 110 return -1; 111 } 112 #define NCNN_MAX_GPU_COUNT 8 113 if (physicalDeviceCount > NCNN_MAX_GPU_COUNT) 114 physicalDeviceCount = NCNN_MAX_GPU_COUNT; 115 116 std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount); 117 //列举所有支持Vulkan的物理设备 118 ret = vulkanDispatchLoaderDynamic->vkEnumeratePhysicalDevices(g_instance, &physicalDeviceCount, physicalDevices.data()); 119 if (ret != VK_SUCCESS) 120 { 121 return -1; 122 } 123 124 int gpu_info_index = 0; 125 for (uint32_t i = 0; i < physicalDeviceCount; i++) 126 { 127 const VkPhysicalDevice& physicalDevice = physicalDevices[i]; 128 129 // device type 130 VkPhysicalDeviceProperties physicalDeviceProperties; 131 vulkanDispatchLoaderDynamic->vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties); 132 133 // info 134 GpuInfo gpu_info; 135 gpu_info.api_version = physicalDeviceProperties.apiVersion; 136 gpu_info.driver_version = physicalDeviceProperties.driverVersion; 137 gpu_info.vendor_id = physicalDeviceProperties.vendorID; 138 gpu_info.device_id = physicalDeviceProperties.deviceID; 139 memset(gpu_info.device_name, 0, VK_MAX_PHYSICAL_DEVICE_NAME_SIZE); 140 memcpy(gpu_info.device_name, physicalDeviceProperties.deviceName, strlen(physicalDeviceProperties.deviceName)); 141 142 if (physicalDeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_OTHER) 143 gpu_info.type = 0; 144 else if (physicalDeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) 145 gpu_info.type = 1; 146 else if (physicalDeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) 147 gpu_info.type = 2; 148 else if (physicalDeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU) 149 gpu_info.type = 3; 150 else if (physicalDeviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) 151 gpu_info.type = 4; 152 else 153 gpu_info.type = -1; 154 155 gpu_info_index++; 156 gpuInfos.emplace_back(gpu_info); 157 }