| // | |
| // Copyright 2018 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_android.cpp: implementation of the Android-specific parts of SystemInfo.h | |
| #include <dlfcn.h> | |
| #include <vulkan/vulkan.h> | |
| #include "gpu_info_util/SystemInfo_internal.h" | |
| #include <cstring> | |
| #include <fstream> | |
| #include "common/angleutils.h" | |
| #include "common/debug.h" | |
| namespace angle | |
| { | |
| class VulkanLibrary final : NonCopyable | |
| { | |
| public: | |
| VulkanLibrary() {} | |
| ~VulkanLibrary() | |
| { | |
| if (mInstance != VK_NULL_HANDLE) | |
| { | |
| PFN_vkDestroyInstance pfnDestroyInstance = | |
| reinterpret_cast<PFN_vkDestroyInstance>(dlsym(mLibVulkan, "vkDestroyInstance")); | |
| if (pfnDestroyInstance) | |
| { | |
| pfnDestroyInstance(mInstance, nullptr); | |
| } | |
| } | |
| if (mLibVulkan) | |
| dlclose(mLibVulkan); | |
| } | |
| VkInstance getVulkanInstance() | |
| { | |
| // Find the system's Vulkan library and open it: | |
| mLibVulkan = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL); | |
| if (!mLibVulkan) | |
| { | |
| // If Vulkan doesn't exist, bail-out early: | |
| return VK_NULL_HANDLE; | |
| } | |
| // Determine the available Vulkan instance version: | |
| uint32_t instanceVersion = VK_API_VERSION_1_0; | |
| #if defined(VK_VERSION_1_1) | |
| PFN_vkEnumerateInstanceVersion pfnEnumerateInstanceVersion = | |
| reinterpret_cast<PFN_vkEnumerateInstanceVersion>( | |
| dlsym(mLibVulkan, "vkEnumerateInstanceVersion")); | |
| if (!pfnEnumerateInstanceVersion || | |
| pfnEnumerateInstanceVersion(&instanceVersion) != VK_SUCCESS) | |
| { | |
| instanceVersion = VK_API_VERSION_1_0; | |
| } | |
| #endif // VK_VERSION_1_1 | |
| // 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; | |
| VkInstanceCreateInfo createInstanceInfo; | |
| createInstanceInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; | |
| createInstanceInfo.pNext = nullptr; | |
| createInstanceInfo.flags = 0; | |
| createInstanceInfo.pApplicationInfo = &appInfo; | |
| createInstanceInfo.enabledLayerCount = 0; | |
| createInstanceInfo.ppEnabledLayerNames = nullptr; | |
| createInstanceInfo.enabledExtensionCount = 0; | |
| createInstanceInfo.ppEnabledExtensionNames = nullptr; | |
| PFN_vkCreateInstance pfnCreateInstance = | |
| reinterpret_cast<PFN_vkCreateInstance>(dlsym(mLibVulkan, "vkCreateInstance")); | |
| if (!pfnCreateInstance || | |
| pfnCreateInstance(&createInstanceInfo, nullptr, &mInstance) != VK_SUCCESS) | |
| { | |
| return VK_NULL_HANDLE; | |
| } | |
| return mInstance; | |
| } | |
| void *gpa(std::string fn) { return dlsym(mLibVulkan, fn.c_str()); } | |
| #define GPA(ob, type, fn) reinterpret_cast<type>(ob.gpa(fn)) | |
| private: | |
| void *mLibVulkan = nullptr; | |
| VkInstance mInstance = VK_NULL_HANDLE; | |
| }; | |
| ANGLE_FORMAT_PRINTF(1, 2) | |
| std::string FormatString(const char *fmt, ...) | |
| { | |
| va_list vararg; | |
| va_start(vararg, fmt); | |
| std::vector<char> buffer(512); | |
| size_t len = FormatStringIntoVector(fmt, vararg, buffer); | |
| va_end(vararg); | |
| return std::string(&buffer[0], len); | |
| } | |
| bool GetSystemInfo(SystemInfo *info) | |
| { | |
| // 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: | |
| PFN_vkEnumeratePhysicalDevices pfnEnumeratePhysicalDevices = | |
| GPA(vkLibrary, PFN_vkEnumeratePhysicalDevices, "vkEnumeratePhysicalDevices"); | |
| PFN_vkGetPhysicalDeviceProperties pfnGetPhysicalDeviceProperties = | |
| GPA(vkLibrary, PFN_vkGetPhysicalDeviceProperties, "vkGetPhysicalDeviceProperties"); | |
| uint32_t physicalDeviceCount = 0; | |
| if (!pfnEnumeratePhysicalDevices || | |
| 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++) | |
| { | |
| VkPhysicalDeviceProperties properties; | |
| pfnGetPhysicalDeviceProperties(physicalDevices[i], &properties); | |
| // 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; | |
| // Need to parse/re-format properties.driverVersion. | |
| // | |
| // TODO(ianelliott): Determine the formatting used for each vendor | |
| // (http://anglebug.com/2677) | |
| switch (properties.vendorID) | |
| { | |
| case kVendorID_AMD: | |
| gpu.driverVendor = "Advanced Micro Devices, Inc"; | |
| gpu.driverVersion = FormatString("0x%x", properties.driverVersion); | |
| gpu.detailedDriverVersion.major = properties.driverVersion; | |
| break; | |
| case kVendorID_ARM: | |
| gpu.driverVendor = "Arm Holdings"; | |
| gpu.driverVersion = FormatString("0x%x", properties.driverVersion); | |
| gpu.detailedDriverVersion.major = properties.driverVersion; | |
| break; | |
| case kVendorID_ImgTec: | |
| gpu.driverVendor = "Imagination Technologies Limited"; | |
| gpu.driverVersion = FormatString("0x%x", properties.driverVersion); | |
| gpu.detailedDriverVersion.major = properties.driverVersion; | |
| break; | |
| case kVendorID_Intel: | |
| gpu.driverVendor = "Intel Corporation"; | |
| gpu.driverVersion = FormatString("0x%x", properties.driverVersion); | |
| gpu.detailedDriverVersion.major = properties.driverVersion; | |
| break; | |
| case kVendorID_Nvidia: | |
| gpu.driverVendor = "NVIDIA Corporation"; | |
| gpu.driverVersion = FormatString("%d.%d.%d.%d", properties.driverVersion >> 22, | |
| (properties.driverVersion >> 14) & 0XFF, | |
| (properties.driverVersion >> 6) & 0XFF, | |
| properties.driverVersion & 0x3F); | |
| gpu.detailedDriverVersion.major = properties.driverVersion >> 22; | |
| gpu.detailedDriverVersion.minor = (properties.driverVersion >> 14) & 0xFF; | |
| gpu.detailedDriverVersion.subMinor = (properties.driverVersion >> 6) & 0xFF; | |
| gpu.detailedDriverVersion.patch = properties.driverVersion & 0x3F; | |
| break; | |
| case kVendorID_Qualcomm: | |
| gpu.driverVendor = "Qualcomm Technologies, Inc"; | |
| if (properties.driverVersion & 0x80000000) | |
| { | |
| gpu.driverVersion = FormatString("%d.%d.%d", properties.driverVersion >> 22, | |
| (properties.driverVersion >> 12) & 0X3FF, | |
| properties.driverVersion & 0xFFF); | |
| gpu.detailedDriverVersion.major = properties.driverVersion >> 22; | |
| gpu.detailedDriverVersion.minor = (properties.driverVersion >> 12) & 0x3FF; | |
| gpu.detailedDriverVersion.subMinor = properties.driverVersion & 0xFFF; | |
| } | |
| else | |
| { | |
| gpu.driverVersion = FormatString("0x%x", properties.driverVersion); | |
| gpu.detailedDriverVersion.major = properties.driverVersion; | |
| } | |
| break; | |
| case kVendorID_Vivante: | |
| gpu.driverVendor = "Vivante"; | |
| gpu.driverVersion = FormatString("0x%x", properties.driverVersion); | |
| gpu.detailedDriverVersion.major = properties.driverVersion; | |
| break; | |
| case kVendorID_VeriSilicon: | |
| gpu.driverVendor = "VeriSilicon"; | |
| gpu.driverVersion = FormatString("0x%x", properties.driverVersion); | |
| gpu.detailedDriverVersion.major = properties.driverVersion; | |
| break; | |
| case kVendorID_Kazan: | |
| gpu.driverVendor = "Kazan Software"; | |
| gpu.driverVersion = FormatString("0x%x", properties.driverVersion); | |
| gpu.detailedDriverVersion.major = properties.driverVersion; | |
| break; | |
| default: | |
| return false; | |
| } | |
| gpu.driverDate = ""; | |
| } | |
| return true; | |
| } | |
| } // namespace angle |