vkinfo.cpp revision ae3b70dea59236780aa909338de1ba5201603439
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#include <vulkan/vulkan.h>
25#include <vulkan/vk_ext_debug_report.h>
26
27#define LOG_TAG "vkinfo"
28#include <log/log.h>
29
30namespace {
31
32struct GpuInfo {
33    VkPhysicalDeviceProperties properties;
34    VkPhysicalDeviceMemoryProperties memory;
35    VkPhysicalDeviceFeatures features;
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 GatherGpuInfo(VkPhysicalDevice gpu, GpuInfo& info) {
120    VkResult result;
121    uint32_t count;
122
123    vkGetPhysicalDeviceProperties(gpu, &info.properties);
124    vkGetPhysicalDeviceMemoryProperties(gpu, &info.memory);
125    vkGetPhysicalDeviceFeatures(gpu, &info.features);
126
127    vkGetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr);
128    info.queue_families.resize(count);
129    vkGetPhysicalDeviceQueueFamilyProperties(gpu, &count,
130                                             info.queue_families.data());
131
132    result = vkEnumerateDeviceLayerProperties(gpu, &count, nullptr);
133    if (result != VK_SUCCESS)
134        die("vkEnumerateDeviceLayerProperties (count)", result);
135    do {
136        info.layers.resize(count);
137        result =
138            vkEnumerateDeviceLayerProperties(gpu, &count, info.layers.data());
139    } while (result == VK_INCOMPLETE);
140    if (result != VK_SUCCESS)
141        die("vkEnumerateDeviceLayerProperties (data)", result);
142    info.layer_extensions.resize(info.layers.size());
143
144    EnumerateDeviceExtensions(gpu, nullptr, &info.extensions);
145    for (size_t i = 0; i < info.layers.size(); i++) {
146        EnumerateDeviceExtensions(gpu, info.layers[i].layerName,
147                                  &info.layer_extensions[i]);
148    }
149
150    const std::array<const char*, 1> kDesiredExtensions = {
151        {VK_KHR_SWAPCHAIN_EXTENSION_NAME},
152    };
153    const char* extensions[kDesiredExtensions.size()];
154    uint32_t num_extensions = 0;
155    for (const auto& desired_ext : kDesiredExtensions) {
156        bool available = HasExtension(info.extensions, desired_ext);
157        for (size_t i = 0; !available && i < info.layer_extensions.size(); i++)
158            available = HasExtension(info.layer_extensions[i], desired_ext);
159        if (available)
160            extensions[num_extensions++] = desired_ext;
161    }
162
163    VkDevice device;
164    const VkDeviceQueueCreateInfo queue_create_info = {
165        .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
166        .queueFamilyIndex = 0,
167        .queueCount = 1,
168    };
169    const VkDeviceCreateInfo create_info = {
170        .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
171        .queueCreateInfoCount = 1,
172        .pQueueCreateInfos = &queue_create_info,
173        .enabledExtensionCount = num_extensions,
174        .ppEnabledExtensionNames = extensions,
175        .pEnabledFeatures = &info.features,
176    };
177    result = vkCreateDevice(gpu, &create_info, nullptr, &device);
178    if (result != VK_SUCCESS)
179        die("vkCreateDevice", result);
180    vkDestroyDevice(device, nullptr);
181}
182
183void GatherInfo(VulkanInfo* info) {
184    VkResult result;
185    uint32_t count;
186
187    result = vkEnumerateInstanceLayerProperties(&count, nullptr);
188    if (result != VK_SUCCESS)
189        die("vkEnumerateInstanceLayerProperties (count)", result);
190    do {
191        info->layers.resize(count);
192        result =
193            vkEnumerateInstanceLayerProperties(&count, info->layers.data());
194    } while (result == VK_INCOMPLETE);
195    if (result != VK_SUCCESS)
196        die("vkEnumerateInstanceLayerProperties (data)", result);
197    info->layer_extensions.resize(info->layers.size());
198
199    EnumerateInstanceExtensions(nullptr, &info->extensions);
200    for (size_t i = 0; i < info->layers.size(); i++) {
201        EnumerateInstanceExtensions(info->layers[i].layerName,
202                                    &info->layer_extensions[i]);
203    }
204
205    const char* kDesiredExtensions[] = {
206        VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
207    };
208    const char*
209        extensions[sizeof(kDesiredExtensions) / sizeof(kDesiredExtensions[0])];
210    uint32_t num_extensions = 0;
211    for (const auto& desired_ext : kDesiredExtensions) {
212        bool available = HasExtension(info->extensions, desired_ext);
213        for (size_t i = 0; !available && i < info->layer_extensions.size(); i++)
214            available = HasExtension(info->layer_extensions[i], desired_ext);
215        if (available)
216            extensions[num_extensions++] = desired_ext;
217    }
218
219    const VkInstanceCreateInfo create_info = {
220        .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
221        .enabledExtensionCount = num_extensions,
222        .ppEnabledExtensionNames = extensions,
223    };
224    VkInstance instance;
225    result = vkCreateInstance(&create_info, nullptr, &instance);
226    if (result != VK_SUCCESS)
227        die("vkCreateInstance", result);
228
229    uint32_t num_gpus;
230    result = vkEnumeratePhysicalDevices(instance, &num_gpus, nullptr);
231    if (result != VK_SUCCESS)
232        die("vkEnumeratePhysicalDevices (count)", result);
233    std::vector<VkPhysicalDevice> gpus(num_gpus, VK_NULL_HANDLE);
234    do {
235        gpus.resize(num_gpus, VK_NULL_HANDLE);
236        result = vkEnumeratePhysicalDevices(instance, &num_gpus, gpus.data());
237    } while (result == VK_INCOMPLETE);
238    if (result != VK_SUCCESS)
239        die("vkEnumeratePhysicalDevices (data)", result);
240
241    info->gpus.resize(num_gpus);
242    for (size_t i = 0; i < gpus.size(); i++)
243        GatherGpuInfo(gpus[i], info->gpus.at(i));
244
245    vkDestroyInstance(instance, nullptr);
246}
247
248// ----------------------------------------------------------------------------
249
250uint32_t ExtractMajorVersion(uint32_t version) {
251    return (version >> 22) & 0x3FF;
252}
253uint32_t ExtractMinorVersion(uint32_t version) {
254    return (version >> 12) & 0x3FF;
255}
256uint32_t ExtractPatchVersion(uint32_t version) {
257    return (version >> 0) & 0xFFF;
258}
259
260const char* VkPhysicalDeviceTypeStr(VkPhysicalDeviceType type) {
261    switch (type) {
262        case VK_PHYSICAL_DEVICE_TYPE_OTHER:
263            return "OTHER";
264        case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
265            return "INTEGRATED_GPU";
266        case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
267            return "DISCRETE_GPU";
268        case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
269            return "VIRTUAL_GPU";
270        case VK_PHYSICAL_DEVICE_TYPE_CPU:
271            return "CPU";
272        default:
273            return "<UNKNOWN>";
274    }
275}
276
277const char* VkQueueFlagBitStr(VkQueueFlagBits bit) {
278    switch (bit) {
279        case VK_QUEUE_GRAPHICS_BIT:
280            return "GRAPHICS";
281        case VK_QUEUE_COMPUTE_BIT:
282            return "COMPUTE";
283        case VK_QUEUE_TRANSFER_BIT:
284            return "TRANSFER";
285        case VK_QUEUE_SPARSE_BINDING_BIT:
286            return "SPARSE";
287    }
288}
289
290void PrintExtensions(const std::vector<VkExtensionProperties>& extensions,
291                     const char* prefix) {
292    for (const auto& e : extensions)
293        printf("%s%s (v%u)\n", prefix, e.extensionName, e.specVersion);
294}
295
296void PrintLayers(
297    const std::vector<VkLayerProperties>& layers,
298    const std::vector<std::vector<VkExtensionProperties>> extensions,
299    const char* prefix) {
300    std::string ext_prefix(prefix);
301    ext_prefix.append("    ");
302    for (size_t i = 0; i < layers.size(); i++) {
303        printf(
304            "%s%s %u.%u.%u/%u\n"
305            "%s  %s\n",
306            prefix, layers[i].layerName,
307            ExtractMajorVersion(layers[i].specVersion),
308            ExtractMinorVersion(layers[i].specVersion),
309            ExtractPatchVersion(layers[i].specVersion),
310            layers[i].implementationVersion, prefix, layers[i].description);
311        if (!extensions[i].empty())
312            printf("%s  Extensions [%zu]:\n", prefix, extensions[i].size());
313        PrintExtensions(extensions[i], ext_prefix.c_str());
314    }
315}
316
317void PrintGpuInfo(const GpuInfo& info) {
318    VkResult result;
319    std::ostringstream strbuf;
320
321    printf("  \"%s\" (%s) %u.%u.%u/%#x [%04x:%04x]\n",
322           info.properties.deviceName,
323           VkPhysicalDeviceTypeStr(info.properties.deviceType),
324           ExtractMajorVersion(info.properties.apiVersion),
325           ExtractMinorVersion(info.properties.apiVersion),
326           ExtractPatchVersion(info.properties.apiVersion),
327           info.properties.driverVersion, info.properties.vendorID,
328           info.properties.deviceID);
329
330    for (uint32_t heap = 0; heap < info.memory.memoryHeapCount; heap++) {
331        if ((info.memory.memoryHeaps[heap].flags &
332             VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0)
333            strbuf << "DEVICE_LOCAL";
334        printf("    Heap %u: %" PRIu64 " MiB (0x%" PRIx64 " B) %s\n", heap,
335               info.memory.memoryHeaps[heap].size / 0x1000000,
336               info.memory.memoryHeaps[heap].size, strbuf.str().c_str());
337        strbuf.str(std::string());
338
339        for (uint32_t type = 0; type < info.memory.memoryTypeCount; type++) {
340            if (info.memory.memoryTypes[type].heapIndex != heap)
341                continue;
342            VkMemoryPropertyFlags flags =
343                info.memory.memoryTypes[type].propertyFlags;
344            if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0)
345                strbuf << " DEVICE_LOCAL";
346            if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
347                strbuf << " HOST_VISIBLE";
348            if ((flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0)
349                strbuf << " COHERENT";
350            if ((flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) != 0)
351                strbuf << " CACHED";
352            if ((flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) != 0)
353                strbuf << " LAZILY_ALLOCATED";
354            printf("      Type %u:%s\n", type, strbuf.str().c_str());
355            strbuf.str(std::string());
356        }
357    }
358
359    for (uint32_t family = 0; family < info.queue_families.size(); family++) {
360        const VkQueueFamilyProperties& qprops = info.queue_families[family];
361        VkQueueFlags flags = qprops.queueFlags;
362        char flags_str[5];
363        flags_str[0] = (flags & VK_QUEUE_GRAPHICS_BIT) ? 'G' : '_';
364        flags_str[1] = (flags & VK_QUEUE_COMPUTE_BIT) ? 'C' : '_';
365        flags_str[2] = (flags & VK_QUEUE_TRANSFER_BIT) ? 'T' : '_';
366        flags_str[3] = (flags & VK_QUEUE_SPARSE_BINDING_BIT) ? 'S' : '_';
367        flags_str[4] = '\0';
368        printf(
369            "    Queue Family %u: %ux %s\n"
370            "      timestampValidBits: %ub\n"
371            "      minImageTransferGranularity: (%u,%u,%u)\n",
372            family, qprops.queueCount, flags_str, qprops.timestampValidBits,
373            qprops.minImageTransferGranularity.width,
374            qprops.minImageTransferGranularity.height,
375            qprops.minImageTransferGranularity.depth);
376    }
377
378    if (!info.extensions.empty()) {
379        printf("    Extensions [%zu]:\n", info.extensions.size());
380        PrintExtensions(info.extensions, "      ");
381    }
382    if (!info.layers.empty()) {
383        printf("    Layers [%zu]:\n", info.layers.size());
384        PrintLayers(info.layers, info.layer_extensions, "      ");
385    }
386}
387
388void PrintInfo(const VulkanInfo& info) {
389    std::ostringstream strbuf;
390
391    printf("Instance Extensions [%zu]:\n", info.extensions.size());
392    PrintExtensions(info.extensions, "  ");
393    if (!info.layers.empty()) {
394        printf("Instance Layers [%zu]:\n", info.layers.size());
395        PrintLayers(info.layers, info.layer_extensions, "  ");
396    }
397
398    printf("PhysicalDevices [%zu]:\n", info.gpus.size());
399    for (const auto& gpu : info.gpus)
400        PrintGpuInfo(gpu);
401}
402
403}  // namespace
404
405// ----------------------------------------------------------------------------
406
407int main(int /*argc*/, char const* /*argv*/ []) {
408    VulkanInfo info;
409    GatherInfo(&info);
410    PrintInfo(info);
411    return 0;
412}
413