vkinfo.cpp revision 4da3bd68ab085b1e07304e64d3deada3dac994e0
1/*
2 * Copyright 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <algorithm>
18#include <array>
19#include <inttypes.h>
20#include <stdlib.h>
21#include <sstream>
22#include <vector>
23
24#define VK_PROTOTYPES
25#include <vulkan/vulkan.h>
26#include <vulkan/vk_ext_debug_report.h>
27
28#define LOG_TAG "vkinfo"
29#include <log/log.h>
30
31namespace {
32
33struct GpuInfo {
34    VkPhysicalDeviceProperties properties;
35    VkPhysicalDeviceMemoryProperties memory;
36    std::vector<VkQueueFamilyProperties> queue_families;
37    std::vector<VkExtensionProperties> extensions;
38    std::vector<VkLayerProperties> layers;
39    std::vector<std::vector<VkExtensionProperties>> layer_extensions;
40};
41struct VulkanInfo {
42    std::vector<VkExtensionProperties> extensions;
43    std::vector<VkLayerProperties> layers;
44    std::vector<std::vector<VkExtensionProperties>> layer_extensions;
45    std::vector<GpuInfo> gpus;
46};
47
48// ----------------------------------------------------------------------------
49
50[[noreturn]] void die(const char* proc, VkResult result) {
51    const char* result_str;
52    switch (result) {
53        // clang-format off
54        case VK_SUCCESS: result_str = "VK_SUCCESS"; break;
55        case VK_NOT_READY: result_str = "VK_NOT_READY"; break;
56        case VK_TIMEOUT: result_str = "VK_TIMEOUT"; break;
57        case VK_EVENT_SET: result_str = "VK_EVENT_SET"; break;
58        case VK_EVENT_RESET: result_str = "VK_EVENT_RESET"; break;
59        case VK_INCOMPLETE: result_str = "VK_INCOMPLETE"; break;
60        case VK_ERROR_OUT_OF_HOST_MEMORY: result_str = "VK_ERROR_OUT_OF_HOST_MEMORY"; break;
61        case VK_ERROR_OUT_OF_DEVICE_MEMORY: result_str = "VK_ERROR_OUT_OF_DEVICE_MEMORY"; break;
62        case VK_ERROR_INITIALIZATION_FAILED: result_str = "VK_ERROR_INITIALIZATION_FAILED"; break;
63        case VK_ERROR_DEVICE_LOST: result_str = "VK_ERROR_DEVICE_LOST"; break;
64        case VK_ERROR_MEMORY_MAP_FAILED: result_str = "VK_ERROR_MEMORY_MAP_FAILED"; break;
65        case VK_ERROR_LAYER_NOT_PRESENT: result_str = "VK_ERROR_LAYER_NOT_PRESENT"; break;
66        case VK_ERROR_EXTENSION_NOT_PRESENT: result_str = "VK_ERROR_EXTENSION_NOT_PRESENT"; break;
67        case VK_ERROR_INCOMPATIBLE_DRIVER: result_str = "VK_ERROR_INCOMPATIBLE_DRIVER"; break;
68        default: result_str = "<unknown VkResult>"; break;
69            // clang-format on
70    }
71    fprintf(stderr, "%s failed: %s (%d)\n", proc, result_str, result);
72    exit(1);
73}
74
75bool HasExtension(const std::vector<VkExtensionProperties>& extensions,
76                  const char* name) {
77    return std::find_if(extensions.cbegin(), extensions.cend(),
78                        [=](const VkExtensionProperties& prop) {
79                            return strcmp(prop.extensionName, name) == 0;
80                        }) != extensions.end();
81}
82
83void EnumerateInstanceExtensions(
84    const char* layer_name,
85    std::vector<VkExtensionProperties>* extensions) {
86    VkResult result;
87    uint32_t count;
88    result =
89        vkEnumerateInstanceExtensionProperties(layer_name, &count, nullptr);
90    if (result != VK_SUCCESS)
91        die("vkEnumerateInstanceExtensionProperties (count)", result);
92    do {
93        extensions->resize(count);
94        result = vkEnumerateInstanceExtensionProperties(layer_name, &count,
95                                                        extensions->data());
96    } while (result == VK_INCOMPLETE);
97    if (result != VK_SUCCESS)
98        die("vkEnumerateInstanceExtensionProperties (data)", result);
99}
100
101void EnumerateDeviceExtensions(VkPhysicalDevice gpu,
102                               const char* layer_name,
103                               std::vector<VkExtensionProperties>* extensions) {
104    VkResult result;
105    uint32_t count;
106    result =
107        vkEnumerateDeviceExtensionProperties(gpu, layer_name, &count, nullptr);
108    if (result != VK_SUCCESS)
109        die("vkEnumerateDeviceExtensionProperties (count)", result);
110    do {
111        extensions->resize(count);
112        result = vkEnumerateDeviceExtensionProperties(gpu, layer_name, &count,
113                                                      extensions->data());
114    } while (result == VK_INCOMPLETE);
115    if (result != VK_SUCCESS)
116        die("vkEnumerateDeviceExtensionProperties (data)", result);
117}
118
119void GatherInfo(VulkanInfo* info) {
120    VkResult result;
121    uint32_t count;
122
123    result = vkEnumerateInstanceLayerProperties(&count, nullptr);
124    if (result != VK_SUCCESS)
125        die("vkEnumerateInstanceLayerProperties (count)", result);
126    do {
127        info->layers.resize(count);
128        result =
129            vkEnumerateInstanceLayerProperties(&count, info->layers.data());
130    } while (result == VK_INCOMPLETE);
131    if (result != VK_SUCCESS)
132        die("vkEnumerateInstanceLayerProperties (data)", result);
133    info->layer_extensions.resize(info->layers.size());
134
135    EnumerateInstanceExtensions(nullptr, &info->extensions);
136    for (size_t i = 0; i < info->layers.size(); i++) {
137        EnumerateInstanceExtensions(info->layers[i].layerName,
138                                    &info->layer_extensions[i]);
139    }
140
141    const std::array<const char*, 1> kDesiredExtensions = {
142        {VK_EXT_DEBUG_REPORT_EXTENSION_NAME},
143    };
144    const char* extensions[kDesiredExtensions.size()];
145    uint32_t num_extensions = 0;
146    for (const auto& desired_ext : kDesiredExtensions) {
147        bool available = HasExtension(info->extensions, desired_ext);
148        for (size_t i = 0; !available && i < info->layer_extensions.size(); i++)
149            available = HasExtension(info->layer_extensions[i], desired_ext);
150        if (available)
151            extensions[num_extensions++] = desired_ext;
152    }
153
154    const VkInstanceCreateInfo create_info = {
155        .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
156        .enabledExtensionCount = num_extensions,
157        .ppEnabledExtensionNames = extensions,
158    };
159    VkInstance instance;
160    result = vkCreateInstance(&create_info, nullptr, &instance);
161    if (result != VK_SUCCESS)
162        die("vkCreateInstance", result);
163
164    uint32_t num_gpus;
165    result = vkEnumeratePhysicalDevices(instance, &num_gpus, nullptr);
166    if (result != VK_SUCCESS)
167        die("vkEnumeratePhysicalDevices (count)", result);
168    std::vector<VkPhysicalDevice> gpus(num_gpus, VK_NULL_HANDLE);
169    do {
170        gpus.resize(num_gpus, VK_NULL_HANDLE);
171        result = vkEnumeratePhysicalDevices(instance, &num_gpus, gpus.data());
172    } while (result == VK_INCOMPLETE);
173    if (result != VK_SUCCESS)
174        die("vkEnumeratePhysicalDevices (data)", result);
175
176    info->gpus.resize(num_gpus);
177    for (size_t gpu_idx = 0; gpu_idx < gpus.size(); gpu_idx++) {
178        VkPhysicalDevice gpu = gpus[gpu_idx];
179        GpuInfo& gpu_info = info->gpus.at(gpu_idx);
180
181        vkGetPhysicalDeviceProperties(gpu, &gpu_info.properties);
182        vkGetPhysicalDeviceMemoryProperties(gpu, &gpu_info.memory);
183
184        vkGetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr);
185        gpu_info.queue_families.resize(count);
186        vkGetPhysicalDeviceQueueFamilyProperties(
187            gpu, &count, gpu_info.queue_families.data());
188
189        result = vkEnumerateDeviceLayerProperties(gpu, &count, nullptr);
190        if (result != VK_SUCCESS)
191            die("vkEnumerateDeviceLayerProperties (count)", result);
192        do {
193            gpu_info.layers.resize(count);
194            result = vkEnumerateDeviceLayerProperties(gpu, &count,
195                                                      gpu_info.layers.data());
196        } while (result == VK_INCOMPLETE);
197        if (result != VK_SUCCESS)
198            die("vkEnumerateDeviceLayerProperties (data)", result);
199        gpu_info.layer_extensions.resize(gpu_info.layers.size());
200
201        EnumerateDeviceExtensions(gpu, nullptr, &gpu_info.extensions);
202        for (size_t i = 0; i < gpu_info.layers.size(); i++) {
203            EnumerateDeviceExtensions(gpu, gpu_info.layers[i].layerName,
204                                      &gpu_info.layer_extensions[i]);
205        }
206    }
207
208    vkDestroyInstance(instance, nullptr);
209}
210
211// ----------------------------------------------------------------------------
212
213uint32_t ExtractMajorVersion(uint32_t version) {
214    return (version >> 22) & 0x3FF;
215}
216uint32_t ExtractMinorVersion(uint32_t version) {
217    return (version >> 12) & 0x3FF;
218}
219uint32_t ExtractPatchVersion(uint32_t version) {
220    return (version >> 0) & 0xFFF;
221}
222
223const char* VkPhysicalDeviceTypeStr(VkPhysicalDeviceType type) {
224    switch (type) {
225        case VK_PHYSICAL_DEVICE_TYPE_OTHER:
226            return "OTHER";
227        case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
228            return "INTEGRATED_GPU";
229        case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
230            return "DISCRETE_GPU";
231        case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
232            return "VIRTUAL_GPU";
233        case VK_PHYSICAL_DEVICE_TYPE_CPU:
234            return "CPU";
235        default:
236            return "<UNKNOWN>";
237    }
238}
239
240const char* VkQueueFlagBitStr(VkQueueFlagBits bit) {
241    switch (bit) {
242        case VK_QUEUE_GRAPHICS_BIT:
243            return "GRAPHICS";
244        case VK_QUEUE_COMPUTE_BIT:
245            return "COMPUTE";
246        case VK_QUEUE_TRANSFER_BIT:
247            return "TRANSFER";
248        case VK_QUEUE_SPARSE_BINDING_BIT:
249            return "SPARSE";
250    }
251}
252
253void PrintExtensions(const std::vector<VkExtensionProperties>& extensions,
254                     const char* prefix) {
255    for (const auto& e : extensions)
256        printf("%s%s (v%u)\n", prefix, e.extensionName, e.specVersion);
257}
258
259void PrintGpuInfo(const GpuInfo& info) {
260    VkResult result;
261    std::ostringstream strbuf;
262
263    printf("  \"%s\" (%s) %u.%u.%u/%#x [%04x:%04x]\n",
264           info.properties.deviceName,
265           VkPhysicalDeviceTypeStr(info.properties.deviceType),
266           ExtractMajorVersion(info.properties.apiVersion),
267           ExtractMinorVersion(info.properties.apiVersion),
268           ExtractPatchVersion(info.properties.apiVersion),
269           info.properties.driverVersion, info.properties.vendorID,
270           info.properties.deviceID);
271
272    for (uint32_t heap = 0; heap < info.memory.memoryHeapCount; heap++) {
273        if ((info.memory.memoryHeaps[heap].flags &
274             VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0)
275            strbuf << "DEVICE_LOCAL";
276        printf("    Heap %u: %" PRIu64 " MiB (0x%" PRIx64 " B) %s\n", heap,
277               info.memory.memoryHeaps[heap].size / 0x1000000,
278               info.memory.memoryHeaps[heap].size, strbuf.str().c_str());
279        strbuf.str(std::string());
280
281        for (uint32_t type = 0; type < info.memory.memoryTypeCount; type++) {
282            if (info.memory.memoryTypes[type].heapIndex != heap)
283                continue;
284            VkMemoryPropertyFlags flags =
285                info.memory.memoryTypes[type].propertyFlags;
286            if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0)
287                strbuf << " DEVICE_LOCAL";
288            if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
289                strbuf << " HOST_VISIBLE";
290            if ((flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0)
291                strbuf << " COHERENT";
292            if ((flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) != 0)
293                strbuf << " CACHED";
294            if ((flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) != 0)
295                strbuf << " LAZILY_ALLOCATED";
296            printf("      Type %u:%s\n", type, strbuf.str().c_str());
297            strbuf.str(std::string());
298        }
299    }
300
301    for (uint32_t family = 0; family < info.queue_families.size(); family++) {
302        const VkQueueFamilyProperties& qprops = info.queue_families[family];
303        VkQueueFlags flags = qprops.queueFlags;
304        char flags_str[5];
305        flags_str[0] = (flags & VK_QUEUE_GRAPHICS_BIT) ? 'G' : '_';
306        flags_str[1] = (flags & VK_QUEUE_COMPUTE_BIT) ? 'C' : '_';
307        flags_str[2] = (flags & VK_QUEUE_TRANSFER_BIT) ? 'T' : '_';
308        flags_str[3] = (flags & VK_QUEUE_SPARSE_BINDING_BIT) ? 'S' : '_';
309        flags_str[4] = '\0';
310        printf(
311            "    Queue Family %u: %ux %s\n"
312            "      timestampValidBits: %ub\n"
313            "      minImageTransferGranularity: (%u,%u,%u)\n",
314            family, qprops.queueCount, flags_str, qprops.timestampValidBits,
315            qprops.minImageTransferGranularity.width,
316            qprops.minImageTransferGranularity.height,
317            qprops.minImageTransferGranularity.depth);
318
319        if (!info.extensions.empty()) {
320            printf("    Extensions [%zu]:\n", info.extensions.size());
321            PrintExtensions(info.extensions, "    ");
322        }
323        if (!info.layers.empty()) {
324            printf("    Layers [%zu]:\n", info.layers.size());
325            for (size_t i = 0; i < info.layers.size(); i++) {
326                const auto& layer = info.layers[i];
327                printf("    - %s %u.%u.%u/%u \"%s\"\n", layer.layerName,
328                       ExtractMajorVersion(layer.specVersion),
329                       ExtractMinorVersion(layer.specVersion),
330                       ExtractPatchVersion(layer.specVersion),
331                       layer.implementationVersion, layer.description);
332                if (!info.layer_extensions[i].empty()) {
333                    printf("       Extensions [%zu]:\n",
334                           info.layer_extensions.size());
335                    PrintExtensions(info.layer_extensions[i], "       ");
336                }
337            }
338        }
339    }
340}
341
342void PrintInfo(const VulkanInfo& info) {
343    std::ostringstream strbuf;
344
345    printf("Instance Extensions [%zu]:\n", info.extensions.size());
346    PrintExtensions(info.extensions, "  ");
347    if (!info.layers.empty()) {
348        printf("Instance Layers [%zu]:\n", info.layers.size());
349        for (size_t i = 0; i < info.layers.size(); i++) {
350            const auto& layer = info.layers[i];
351            printf("  %s %u.%u.%u/%u \"%s\"\n", layer.layerName,
352                   ExtractMajorVersion(layer.specVersion),
353                   ExtractMinorVersion(layer.specVersion),
354                   ExtractPatchVersion(layer.specVersion),
355                   layer.implementationVersion, layer.description);
356            if (!info.layer_extensions[i].empty()) {
357                PrintExtensions(info.layer_extensions[i], "    ");
358            }
359        }
360    }
361
362    printf("PhysicalDevices [%zu]:\n", info.gpus.size());
363    for (const auto& gpu : info.gpus)
364        PrintGpuInfo(gpu);
365}
366
367}  // namespace
368
369// ----------------------------------------------------------------------------
370
371int main(int /*argc*/, char const* /*argv*/ []) {
372    VulkanInfo info;
373    GatherInfo(&info);
374    PrintInfo(info);
375    return 0;
376}
377