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