| // |
| // Copyright 2020 The ANGLE Project Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| // |
| |
| // SystemInfo_vulkan.cpp: Generic vulkan implementation of SystemInfo.h |
| // TODO: Use VK_KHR_driver_properties. http://anglebug.com/42263671 |
| |
| #include "gpu_info_util/SystemInfo_vulkan.h" |
| |
| #include <vulkan/vulkan.h> |
| #include "gpu_info_util/SystemInfo_internal.h" |
| |
| #include <algorithm> |
| #include <cstring> |
| #include <fstream> |
| #include <string> |
| #include <vector> |
| |
| #include "common/angleutils.h" |
| #include "common/debug.h" |
| #include "common/platform_helpers.h" |
| #include "common/system_utils.h" |
| #include "common/vulkan/libvulkan_loader.h" |
| |
| namespace angle |
| { |
| namespace |
| { |
| // Note: most drivers use VK_MAKE_API_VERSION to create the version. |
| VersionInfo ParseGenericDriverVersion(uint32_t driverVersion) |
| { |
| VersionInfo version = {}; |
| |
| version.major = VK_API_VERSION_MAJOR(driverVersion); |
| version.minor = VK_API_VERSION_MINOR(driverVersion); |
| version.subMinor = VK_API_VERSION_PATCH(driverVersion); |
| |
| return version; |
| } |
| } // namespace |
| |
| VersionInfo ParseAMDVulkanDriverVersion(uint32_t driverVersion) |
| { |
| return ParseGenericDriverVersion(driverVersion); |
| } |
| |
| VersionInfo ParseArmVulkanDriverVersion(uint32_t driverVersion) |
| { |
| return ParseGenericDriverVersion(driverVersion); |
| } |
| |
| VersionInfo ParseBroadcomVulkanDriverVersion(uint32_t driverVersion) |
| { |
| return ParseGenericDriverVersion(driverVersion); |
| } |
| |
| VersionInfo ParseSwiftShaderVulkanDriverVersion(uint32_t driverVersion) |
| { |
| return ParseGenericDriverVersion(driverVersion); |
| } |
| |
| VersionInfo ParseImaginationVulkanDriverVersion(uint32_t driverVersion) |
| { |
| return ParseGenericDriverVersion(driverVersion); |
| } |
| |
| VersionInfo ParseIntelWindowsVulkanDriverVersion(uint32_t driverVersion) |
| { |
| VersionInfo version = {}; |
| |
| // Windows Intel driver versions are built in the following format: |
| // |
| // Major (18 bits) | Minor (14 bits) |
| // |
| version.major = driverVersion >> 14; |
| version.minor = driverVersion & 0x3FFF; |
| |
| return version; |
| } |
| |
| VersionInfo ParseKazanVulkanDriverVersion(uint32_t driverVersion) |
| { |
| return ParseGenericDriverVersion(driverVersion); |
| } |
| |
| VersionInfo ParseNvidiaVulkanDriverVersion(uint32_t driverVersion) |
| { |
| VersionInfo version = {}; |
| |
| version.major = driverVersion >> 22; |
| version.minor = driverVersion >> 14 & 0xFF; |
| version.subMinor = driverVersion >> 6 & 0xFF; |
| version.patch = driverVersion & 0x3F; |
| |
| return version; |
| } |
| |
| VersionInfo ParseQualcommVulkanDriverVersion(uint32_t driverVersion) |
| { |
| if ((driverVersion & 0x80000000) != 0) |
| { |
| return ParseGenericDriverVersion(driverVersion); |
| } |
| |
| // Older drivers with an unknown format, consider them version 0. |
| VersionInfo version = {}; |
| version.minor = driverVersion; |
| return version; |
| } |
| |
| VersionInfo ParseSamsungVulkanDriverVersion(uint32_t driverVersion) |
| { |
| return ParseGenericDriverVersion(driverVersion); |
| } |
| |
| VersionInfo ParseVeriSiliconVulkanDriverVersion(uint32_t driverVersion) |
| { |
| return ParseGenericDriverVersion(driverVersion); |
| } |
| |
| VersionInfo ParseVivanteVulkanDriverVersion(uint32_t driverVersion) |
| { |
| return ParseGenericDriverVersion(driverVersion); |
| } |
| |
| VersionInfo ParseMesaVulkanDriverVersion(uint32_t driverVersion) |
| { |
| return ParseGenericDriverVersion(driverVersion); |
| } |
| |
| VersionInfo ParseMoltenVulkanDriverVersion(uint32_t driverVersion) |
| { |
| // Note: MoltenVK formulates its version number as a decimal number like so: |
| // (major * 10000) + (minor * 100) + patch |
| VersionInfo version = {}; |
| |
| version.major = driverVersion / 10000; |
| version.minor = (driverVersion / 100) % 100; |
| version.patch = driverVersion % 100; |
| |
| return version; |
| } |
| |
| VKAPI_ATTR VkBool32 VKAPI_CALL |
| VVLDebugUtilsMessenger(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, |
| VkDebugUtilsMessageTypeFlagsEXT messageTypes, |
| const VkDebugUtilsMessengerCallbackDataEXT *callbackData, |
| void *userData) |
| { |
| // VUID-VkDebugUtilsMessengerCallbackDataEXT-pMessage-parameter |
| // pMessage must be a null-terminated UTF-8 string |
| ASSERT(callbackData->pMessage != nullptr); |
| |
| // Log the validation error message |
| std::ostringstream log; |
| if (callbackData->pMessageIdName != nullptr) |
| { |
| log << "[ " << callbackData->pMessageIdName << " ] "; |
| } |
| log << callbackData->pMessage << std::endl; |
| std::string msg = log.str(); |
| WARN() << msg; |
| |
| bool triggerAssert = (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) != 0; |
| if (triggerAssert) |
| { |
| // Trigger assert when there is validation error, so we can catch it on bots. |
| ASSERT(false); |
| } |
| |
| return VK_FALSE; |
| } |
| |
| constexpr const char *kVkKhronosValidationLayerName[] = {"VK_LAYER_KHRONOS_validation"}; |
| |
| bool HasKhronosValidationLayer(const std::vector<VkLayerProperties> &layerProps) |
| { |
| for (const auto &layerProp : layerProps) |
| { |
| std::string layerPropLayerName = std::string(layerProp.layerName); |
| if (layerPropLayerName == kVkKhronosValidationLayerName[0]) |
| { |
| return true; |
| } |
| } |
| |
| WARN() << "Vulkan validation layers are missing"; |
| |
| return false; |
| } |
| |
| class VulkanLibrary final : NonCopyable |
| { |
| public: |
| VulkanLibrary() = default; |
| |
| ~VulkanLibrary() |
| { |
| if (mDebugUtilsMessenger) |
| { |
| mPfnDestroyDebugUtilsMessengerEXT(mInstance, mDebugUtilsMessenger, nullptr); |
| } |
| if (mInstance != VK_NULL_HANDLE) |
| { |
| mPfnDestroyInstance(mInstance, nullptr); |
| } |
| |
| CloseSystemLibrary(mLibVulkan); |
| } |
| |
| std::vector<std::string> GetInstanceExtensionNames() const |
| { |
| std::vector<std::string> extensionNames; |
| |
| if (!mPfnEnumerateInstanceExtensionProperties) |
| { |
| return extensionNames; |
| } |
| |
| uint32_t extensionCount = 0; |
| if (mPfnEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr) != |
| VK_SUCCESS) |
| { |
| return extensionNames; |
| } |
| |
| std::vector<VkExtensionProperties> extensions(extensionCount); |
| if (mPfnEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data()) != |
| VK_SUCCESS) |
| { |
| return extensionNames; |
| } |
| |
| for (const auto &extension : extensions) |
| { |
| extensionNames.emplace_back(extension.extensionName); |
| } |
| |
| std::sort(extensionNames.begin(), extensionNames.end()); |
| |
| return extensionNames; |
| } |
| |
| bool ExtensionFound(std::string const &needle, const std::vector<std::string> &haystack) |
| { |
| // NOTE: The list must be sorted. |
| return std::binary_search(haystack.begin(), haystack.end(), needle); |
| } |
| |
| VkInstance getVulkanInstance() |
| { |
| mLibVulkan = vk::OpenLibVulkan(); |
| if (!mLibVulkan) |
| { |
| // If Vulkan doesn't exist, bail-out early: |
| return VK_NULL_HANDLE; |
| } |
| |
| mPfnGetInstanceProcAddr = |
| getProcWithDLSym<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr"); |
| if (!mPfnGetInstanceProcAddr) |
| { |
| return VK_NULL_HANDLE; |
| } |
| |
| mPfnCreateInstance = getProc<PFN_vkCreateInstance>(NULL, "vkCreateInstance"); |
| if (!mPfnCreateInstance) |
| { |
| return VK_NULL_HANDLE; |
| } |
| |
| mPfnEnumerateInstanceLayerProperties = getProc<PFN_vkEnumerateInstanceLayerProperties>( |
| NULL, "vkEnumerateInstanceLayerProperties"); |
| if (!mPfnEnumerateInstanceLayerProperties) |
| { |
| return VK_NULL_HANDLE; |
| } |
| |
| mPfnEnumerateInstanceExtensionProperties = |
| getProc<PFN_vkEnumerateInstanceExtensionProperties>( |
| NULL, "vkEnumerateInstanceExtensionProperties"); |
| if (!mPfnEnumerateInstanceExtensionProperties) |
| { |
| return VK_NULL_HANDLE; |
| } |
| |
| mPfnEnumerateInstanceVersion = |
| getProc<PFN_vkEnumerateInstanceVersion>(NULL, "vkEnumerateInstanceVersion"); |
| |
| // Determine the available Vulkan instance version: |
| uint32_t instanceVersion = VK_API_VERSION_1_0; |
| #if defined(VK_VERSION_1_1) |
| if (!mPfnEnumerateInstanceVersion || |
| mPfnEnumerateInstanceVersion(&instanceVersion) != VK_SUCCESS) |
| { |
| instanceVersion = VK_API_VERSION_1_0; |
| } |
| #endif // VK_VERSION_1_1 |
| |
| std::vector<std::string> availableInstanceExtensions = GetInstanceExtensionNames(); |
| std::vector<const char *> enabledInstanceExtensions; |
| |
| bool hasPortabilityEnumeration = false; |
| |
| if (IsApple() && ExtensionFound(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME, |
| availableInstanceExtensions)) |
| { |
| // On iOS/macOS, there is no native Vulkan driver, so we need to |
| // enable the portability enumeration extension to allow use of |
| // MoltenVK. |
| enabledInstanceExtensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); |
| hasPortabilityEnumeration = true; |
| } |
| |
| // Enable vulkan validation layer |
| bool enableValidationLayer = false; |
| // Only enable validation layer when asserts are enabled |
| #if !defined(NDEBUG) || defined(ANGLE_ASSERT_ALWAYS_ON) |
| uint32_t instanceLayerCount = 0; |
| { |
| mPfnEnumerateInstanceLayerProperties(&instanceLayerCount, nullptr); |
| } |
| std::vector<VkLayerProperties> instanceLayerProps(instanceLayerCount); |
| if (instanceLayerCount > 0) |
| { |
| mPfnEnumerateInstanceLayerProperties(&instanceLayerCount, instanceLayerProps.data()); |
| } |
| enableValidationLayer = HasKhronosValidationLayer(instanceLayerProps); |
| #endif |
| bool hasDebugMessengerExtension = false; |
| if (enableValidationLayer && |
| ExtensionFound(VK_EXT_DEBUG_UTILS_EXTENSION_NAME, availableInstanceExtensions)) |
| { |
| enabledInstanceExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); |
| hasDebugMessengerExtension = true; |
| } |
| |
| // Create a Vulkan instance: |
| VkApplicationInfo appInfo; |
| appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; |
| appInfo.pNext = nullptr; |
| appInfo.pApplicationName = ""; |
| appInfo.applicationVersion = 1; |
| appInfo.pEngineName = ""; |
| appInfo.engineVersion = 1; |
| appInfo.apiVersion = instanceVersion; |
| VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{}; |
| VkInstanceCreateInfo createInstanceInfo{}; |
| createInstanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; |
| if (enableValidationLayer) |
| { |
| createInstanceInfo.enabledLayerCount = 1; |
| createInstanceInfo.ppEnabledLayerNames = kVkKhronosValidationLayerName; |
| |
| if (hasDebugMessengerExtension) |
| { |
| constexpr VkDebugUtilsMessageSeverityFlagsEXT kSeveritiesToLog = |
| VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT | |
| VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT; |
| |
| constexpr VkDebugUtilsMessageTypeFlagsEXT kMessagesToLog = |
| VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; |
| |
| debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; |
| debugCreateInfo.messageSeverity = kSeveritiesToLog; |
| debugCreateInfo.messageType = kMessagesToLog; |
| debugCreateInfo.pfnUserCallback = &VVLDebugUtilsMessenger; |
| debugCreateInfo.pUserData = nullptr; |
| createInstanceInfo.pNext = &debugCreateInfo; |
| } |
| } |
| createInstanceInfo.pApplicationInfo = &appInfo; |
| createInstanceInfo.enabledExtensionCount = |
| static_cast<uint32_t>(enabledInstanceExtensions.size()); |
| createInstanceInfo.ppEnabledExtensionNames = |
| enabledInstanceExtensions.empty() ? nullptr : enabledInstanceExtensions.data(); |
| |
| if (hasPortabilityEnumeration) |
| { |
| createInstanceInfo.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; |
| } |
| |
| if (mPfnCreateInstance(&createInstanceInfo, nullptr, &mInstance) != VK_SUCCESS) |
| { |
| return VK_NULL_HANDLE; |
| } |
| |
| mPfnDestroyInstance = getProc<PFN_vkDestroyInstance>(mInstance, "vkDestroyInstance"); |
| if (!mPfnDestroyInstance) |
| { |
| return VK_NULL_HANDLE; |
| } |
| |
| mPfnEnumeratePhysicalDevices = |
| getProc<PFN_vkEnumeratePhysicalDevices>(mInstance, "vkEnumeratePhysicalDevices"); |
| if (!mPfnEnumeratePhysicalDevices) |
| { |
| return VK_NULL_HANDLE; |
| } |
| mPfnGetPhysicalDeviceProperties = |
| getProc<PFN_vkGetPhysicalDeviceProperties>(mInstance, "vkGetPhysicalDeviceProperties"); |
| if (!mPfnGetPhysicalDeviceProperties) |
| { |
| return VK_NULL_HANDLE; |
| } |
| if (instanceVersion >= VK_VERSION_1_1) |
| { |
| mPfnGetPhysicalDeviceProperties2 = getProc<PFN_vkGetPhysicalDeviceProperties2>( |
| mInstance, "vkGetPhysicalDeviceProperties2"); |
| if (!mPfnGetPhysicalDeviceProperties2) |
| { |
| return VK_NULL_HANDLE; |
| } |
| } |
| |
| mPfnCreateDebugUtilsMessengerEXT = getProc<PFN_vkCreateDebugUtilsMessengerEXT>( |
| mInstance, "vkCreateDebugUtilsMessengerEXT"); |
| |
| mPfnDestroyDebugUtilsMessengerEXT = getProc<PFN_vkDestroyDebugUtilsMessengerEXT>( |
| mInstance, "vkDestroyDebugUtilsMessengerEXT"); |
| |
| // Set up vulkan validation layer debug messenger to relay the VVL error to the callback |
| // function VVLDebugUtilsMessenger. |
| hasDebugMessengerExtension = hasDebugMessengerExtension && |
| mPfnCreateDebugUtilsMessengerEXT && |
| mPfnDestroyDebugUtilsMessengerEXT; |
| if (hasDebugMessengerExtension) |
| { |
| ASSERT(debugCreateInfo.sType == |
| VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT); |
| mPfnCreateDebugUtilsMessengerEXT(mInstance, &debugCreateInfo, nullptr, |
| &mDebugUtilsMessenger); |
| } |
| return mInstance; |
| } |
| |
| template <typename Func> |
| Func getProcWithDLSym(const char *fn) const |
| { |
| return reinterpret_cast<Func>(angle::GetLibrarySymbol(mLibVulkan, fn)); |
| } |
| |
| template <typename Func> |
| Func getProc(const VkInstance instance, const char *fn) const |
| { |
| return (Func)mPfnGetInstanceProcAddr(instance, fn); |
| } |
| |
| PFN_vkEnumeratePhysicalDevices getEnumeratePhysicalDevicesFunc() |
| { |
| return mPfnEnumeratePhysicalDevices; |
| } |
| |
| PFN_vkGetPhysicalDeviceProperties getPhysicalDevicePropertiesFunc() |
| { |
| return mPfnGetPhysicalDeviceProperties; |
| } |
| |
| PFN_vkGetPhysicalDeviceProperties2 getPhysicalDeviceProperties2Func() |
| { |
| return mPfnGetPhysicalDeviceProperties2; |
| } |
| |
| private: |
| void *mLibVulkan = nullptr; |
| VkInstance mInstance = VK_NULL_HANDLE; |
| VkDebugUtilsMessengerEXT mDebugUtilsMessenger = VK_NULL_HANDLE; |
| PFN_vkGetInstanceProcAddr mPfnGetInstanceProcAddr; |
| PFN_vkCreateInstance mPfnCreateInstance; |
| PFN_vkDestroyInstance mPfnDestroyInstance; |
| PFN_vkEnumerateInstanceVersion mPfnEnumerateInstanceVersion; |
| PFN_vkEnumerateInstanceLayerProperties mPfnEnumerateInstanceLayerProperties; |
| PFN_vkEnumerateInstanceExtensionProperties mPfnEnumerateInstanceExtensionProperties; |
| PFN_vkEnumeratePhysicalDevices mPfnEnumeratePhysicalDevices; |
| PFN_vkGetPhysicalDeviceProperties mPfnGetPhysicalDeviceProperties; |
| PFN_vkGetPhysicalDeviceProperties2 mPfnGetPhysicalDeviceProperties2; |
| PFN_vkCreateDebugUtilsMessengerEXT mPfnCreateDebugUtilsMessengerEXT; |
| PFN_vkDestroyDebugUtilsMessengerEXT mPfnDestroyDebugUtilsMessengerEXT; |
| }; |
| |
| ANGLE_FORMAT_PRINTF(1, 2) |
| std::string FormatString(const char *fmt, ...) |
| { |
| va_list vararg; |
| va_start(vararg, fmt); |
| |
| std::vector<char> buffer; |
| size_t len = FormatStringIntoVector(fmt, vararg, buffer); |
| va_end(vararg); |
| |
| return std::string(&buffer[0], len); |
| } |
| |
| bool GetSystemInfoVulkan(SystemInfo *info) |
| { |
| return GetSystemInfoVulkanWithICD(info, vk::ICD::Default); |
| } |
| |
| bool GetSystemInfoVulkanWithICD(SystemInfo *info, vk::ICD preferredICD) |
| { |
| const bool enableValidationLayers = false; |
| vk::ScopedVkLoaderEnvironment scopedEnvironment(enableValidationLayers, preferredICD); |
| |
| static_assert(sizeof(GPUDeviceInfo::deviceUUID) == VK_UUID_SIZE); |
| |
| // This implementation builds on top of the Vulkan API, but cannot assume the existence of the |
| // Vulkan library. ANGLE can be installed on versions of Android as old as Ice Cream Sandwich. |
| // Therefore, we need to use dlopen()/dlsym() in order to see if Vulkan is installed on the |
| // system, and if so, to use it: |
| VulkanLibrary vkLibrary; |
| VkInstance instance = vkLibrary.getVulkanInstance(); |
| if (instance == VK_NULL_HANDLE) |
| { |
| // If Vulkan doesn't exist, bail-out early: |
| return false; |
| } |
| |
| // Enumerate the Vulkan physical devices, which are ANGLE gpus: |
| auto pfnEnumeratePhysicalDevices = vkLibrary.getEnumeratePhysicalDevicesFunc(); |
| auto pfnGetPhysicalDeviceProperties = vkLibrary.getPhysicalDevicePropertiesFunc(); |
| auto pfnGetPhysicalDeviceProperties2 = vkLibrary.getPhysicalDeviceProperties2Func(); |
| uint32_t physicalDeviceCount = 0; |
| if (pfnEnumeratePhysicalDevices(instance, &physicalDeviceCount, nullptr) != VK_SUCCESS) |
| { |
| return false; |
| } |
| std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount); |
| if (pfnEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices.data()) != |
| VK_SUCCESS) |
| { |
| return false; |
| } |
| |
| // If we get to here, we will likely provide a valid answer (unless an unknown vendorID): |
| info->gpus.resize(physicalDeviceCount); |
| |
| for (uint32_t i = 0; i < physicalDeviceCount; i++) |
| { |
| VkPhysicalDeviceDriverProperties driverProperties = {}; |
| driverProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; |
| |
| VkPhysicalDeviceIDProperties deviceIDProperties = {}; |
| deviceIDProperties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES; |
| deviceIDProperties.pNext = &driverProperties; |
| |
| VkPhysicalDeviceProperties2 properties2 = {}; |
| properties2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; |
| properties2.pNext = &deviceIDProperties; |
| |
| VkPhysicalDeviceProperties &properties = properties2.properties; |
| pfnGetPhysicalDeviceProperties(physicalDevices[i], &properties); |
| |
| // vkGetPhysicalDeviceProperties2() is supported since 1.1 |
| // Use vkGetPhysicalDeviceProperties2() to get driver information. |
| if (properties.apiVersion >= VK_API_VERSION_1_1) |
| { |
| pfnGetPhysicalDeviceProperties2(physicalDevices[i], &properties2); |
| } |
| |
| // Fill in data for a given physical device (a.k.a. gpu): |
| GPUDeviceInfo &gpu = info->gpus[i]; |
| gpu.vendorId = properties.vendorID; |
| gpu.deviceId = properties.deviceID; |
| gpu.deviceName = properties.deviceName; |
| memcpy(gpu.deviceUUID, deviceIDProperties.deviceUUID, VK_UUID_SIZE); |
| memcpy(gpu.driverUUID, deviceIDProperties.driverUUID, VK_UUID_SIZE); |
| |
| // TODO(http://anglebug.com/42266143): Use driverID instead of the hardware vendorID to |
| // detect driveVendor, etc. |
| switch (properties.vendorID) |
| { |
| case kVendorID_AMD: |
| gpu.driverVendor = "Advanced Micro Devices, Inc"; |
| gpu.detailedDriverVersion = ParseAMDVulkanDriverVersion(properties.driverVersion); |
| break; |
| case kVendorID_ARM: |
| gpu.driverVendor = "Arm Holdings"; |
| gpu.detailedDriverVersion = ParseArmVulkanDriverVersion(properties.driverVersion); |
| break; |
| case kVendorID_Broadcom: |
| gpu.driverVendor = "Broadcom"; |
| gpu.detailedDriverVersion = |
| ParseBroadcomVulkanDriverVersion(properties.driverVersion); |
| break; |
| case kVendorID_GOOGLE: |
| gpu.driverVendor = "Google"; |
| gpu.detailedDriverVersion = |
| ParseSwiftShaderVulkanDriverVersion(properties.driverVersion); |
| break; |
| case kVendorID_ImgTec: |
| gpu.driverVendor = "Imagination Technologies Limited"; |
| gpu.detailedDriverVersion = |
| ParseImaginationVulkanDriverVersion(properties.driverVersion); |
| break; |
| case kVendorID_Intel: |
| gpu.driverVendor = "Intel Corporation"; |
| if (IsWindows()) |
| { |
| gpu.detailedDriverVersion = |
| ParseIntelWindowsVulkanDriverVersion(properties.driverVersion); |
| } |
| else |
| { |
| gpu.detailedDriverVersion = |
| ParseMesaVulkanDriverVersion(properties.driverVersion); |
| } |
| break; |
| case kVendorID_Kazan: |
| gpu.driverVendor = "Kazan Software"; |
| gpu.detailedDriverVersion = ParseKazanVulkanDriverVersion(properties.driverVersion); |
| break; |
| case kVendorID_NVIDIA: |
| gpu.driverVendor = "NVIDIA Corporation"; |
| gpu.detailedDriverVersion = |
| ParseNvidiaVulkanDriverVersion(properties.driverVersion); |
| break; |
| case kVendorID_Qualcomm: |
| case kVendorID_Qualcomm_DXGI: |
| gpu.driverVendor = "Qualcomm Technologies, Inc"; |
| gpu.detailedDriverVersion = |
| ParseQualcommVulkanDriverVersion(properties.driverVersion); |
| break; |
| case kVendorID_Samsung: |
| gpu.driverVendor = "Samsung"; |
| gpu.detailedDriverVersion = |
| ParseSamsungVulkanDriverVersion(properties.driverVersion); |
| break; |
| case kVendorID_VeriSilicon: |
| gpu.driverVendor = "VeriSilicon"; |
| gpu.detailedDriverVersion = |
| ParseVeriSiliconVulkanDriverVersion(properties.driverVersion); |
| break; |
| case kVendorID_Vivante: |
| gpu.driverVendor = "Vivante"; |
| gpu.detailedDriverVersion = |
| ParseVivanteVulkanDriverVersion(properties.driverVersion); |
| break; |
| case kVendorID_Mesa: |
| gpu.driverVendor = "Mesa"; |
| gpu.detailedDriverVersion = ParseMesaVulkanDriverVersion(properties.driverVersion); |
| break; |
| case kVendorID_Apple: |
| // Note: This is MoltenVk |
| gpu.driverVendor = "Apple"; |
| gpu.detailedDriverVersion = |
| ParseMoltenVulkanDriverVersion(properties.driverVersion); |
| break; |
| default: |
| return false; |
| } |
| gpu.driverVersion = |
| FormatString("%d.%d.%d", gpu.detailedDriverVersion.major, |
| gpu.detailedDriverVersion.minor, gpu.detailedDriverVersion.subMinor); |
| gpu.driverId = static_cast<DriverID>(driverProperties.driverID); |
| gpu.driverApiVersion = properties.apiVersion; |
| gpu.driverDate = ""; |
| } |
| |
| return true; |
| } |
| |
| } // namespace angle |