Home | History | Annotate | Download | only in demos
      1 /*
      2  * Copyright (c) 2015-2016 The Khronos Group Inc.
      3  * Copyright (c) 2015-2016 Valve Corporation
      4  * Copyright (c) 2015-2016 LunarG, Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and/or associated documentation files (the "Materials"), to
      8  * deal in the Materials without restriction, including without limitation the
      9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
     10  * sell copies of the Materials, and to permit persons to whom the Materials are
     11  * furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice(s) and this permission notice shall be included in
     14  * all copies or substantial portions of the Materials.
     15  *
     16  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     19  *
     20  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
     21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
     23  * USE OR OTHER DEALINGS IN THE MATERIALS.
     24  *
     25  * Author: Courtney Goeltzenleuchter <courtney (at) LunarG.com>
     26  * Author: David Pinedo <david (at) lunarg.com>
     27  * Author: Mark Lobodzinski <mark (at) lunarg.com>
     28  */
     29 #include <stdlib.h>
     30 #include <stdio.h>
     31 #include <stdbool.h>
     32 #include <string.h>
     33 #include <assert.h>
     34 #include <inttypes.h>
     35 
     36 #ifdef _WIN32
     37 #include <fcntl.h>
     38 #include <io.h>
     39 #endif // _WIN32
     40 
     41 #include <vulkan/vulkan.h>
     42 
     43 #define ERR(err)                                                               \
     44     printf("%s:%d: failed with %s\n", __FILE__, __LINE__,                      \
     45            vk_result_string(err));
     46 
     47 #ifdef _WIN32
     48 
     49 #define snprintf _snprintf
     50 
     51 // Returns nonzero if the console is used only for this process. Will return
     52 // zero if another process (such as cmd.exe) is also attached.
     53 static int ConsoleIsExclusive(void) {
     54     DWORD pids[2];
     55     DWORD num_pids = GetConsoleProcessList(pids, ARRAYSIZE(pids));
     56     return num_pids <= 1;
     57 }
     58 
     59 #define WAIT_FOR_CONSOLE_DESTROY                                               \
     60     do {                                                                       \
     61         if (ConsoleIsExclusive())                                                    \
     62             Sleep(INFINITE);                                                   \
     63     } while (0)
     64 #else
     65 #define WAIT_FOR_CONSOLE_DESTROY
     66 #endif
     67 
     68 #define ERR_EXIT(err)                                                          \
     69     do {                                                                       \
     70         ERR(err);                                                              \
     71         fflush(stdout);                                                        \
     72         WAIT_FOR_CONSOLE_DESTROY;                                              \
     73         exit(-1);                                                              \
     74     } while (0)
     75 
     76 #if defined(NDEBUG) && defined(__GNUC__)
     77 #define U_ASSERT_ONLY __attribute__((unused))
     78 #else
     79 #define U_ASSERT_ONLY
     80 #endif
     81 
     82 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
     83 
     84 #define MAX_GPUS 8
     85 
     86 #define MAX_QUEUE_TYPES 5
     87 #define APP_SHORT_NAME "vulkaninfo"
     88 
     89 struct app_gpu;
     90 
     91 struct app_dev {
     92     struct app_gpu *gpu; /* point back to the GPU */
     93 
     94     VkDevice obj;
     95 
     96     VkFormatProperties format_props[VK_FORMAT_RANGE_SIZE];
     97 };
     98 
     99 struct layer_extension_list {
    100     VkLayerProperties layer_properties;
    101     uint32_t extension_count;
    102     VkExtensionProperties *extension_properties;
    103 };
    104 
    105 struct app_instance {
    106     VkInstance instance;
    107     uint32_t global_layer_count;
    108     struct layer_extension_list *global_layers;
    109     uint32_t global_extension_count;
    110     VkExtensionProperties *global_extensions;
    111 };
    112 
    113 struct app_gpu {
    114     uint32_t id;
    115     VkPhysicalDevice obj;
    116 
    117     VkPhysicalDeviceProperties props;
    118 
    119     uint32_t queue_count;
    120     VkQueueFamilyProperties *queue_props;
    121     VkDeviceQueueCreateInfo *queue_reqs;
    122 
    123     VkPhysicalDeviceMemoryProperties memory_props;
    124     VkPhysicalDeviceFeatures features;
    125     VkPhysicalDevice limits;
    126 
    127     uint32_t device_layer_count;
    128     struct layer_extension_list *device_layers;
    129 
    130     uint32_t device_extension_count;
    131     VkExtensionProperties *device_extensions;
    132 
    133     struct app_dev dev;
    134 };
    135 
    136 static VKAPI_ATTR VkBool32 VKAPI_CALL
    137 dbg_callback(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType,
    138              uint64_t srcObject, size_t location, int32_t msgCode,
    139              const char *pLayerPrefix, const char *pMsg, void *pUserData) {
    140     char *message = (char *)malloc(strlen(pMsg) + 100);
    141 
    142     assert(message);
    143 
    144     if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
    145         sprintf(message, "ERROR: [%s] Code %d : %s", pLayerPrefix, msgCode,
    146                 pMsg);
    147     } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
    148         sprintf(message, "WARNING: [%s] Code %d : %s", pLayerPrefix, msgCode,
    149                 pMsg);
    150     } else if (msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
    151         sprintf(message, "INFO: [%s] Code %d : %s", pLayerPrefix, msgCode,
    152                 pMsg);
    153     } else if (msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
    154         sprintf(message, "DEBUG: [%s] Code %d : %s", pLayerPrefix, msgCode,
    155                 pMsg);
    156     }
    157 
    158     printf("%s\n", message);
    159     fflush(stdout);
    160     free(message);
    161 
    162     /*
    163      * false indicates that layer should not bail-out of an
    164      * API call that had validation failures. This may mean that the
    165      * app dies inside the driver due to invalid parameter(s).
    166      * That's what would happen without validation layers, so we'll
    167      * keep that behavior here.
    168      */
    169     return false;
    170 }
    171 
    172 static const char *vk_result_string(VkResult err) {
    173     switch (err) {
    174 #define STR(r)                                                                 \
    175     case r:                                                                    \
    176         return #r
    177         STR(VK_SUCCESS);
    178         STR(VK_NOT_READY);
    179         STR(VK_TIMEOUT);
    180         STR(VK_EVENT_SET);
    181         STR(VK_EVENT_RESET);
    182         STR(VK_ERROR_INITIALIZATION_FAILED);
    183         STR(VK_ERROR_OUT_OF_HOST_MEMORY);
    184         STR(VK_ERROR_OUT_OF_DEVICE_MEMORY);
    185         STR(VK_ERROR_DEVICE_LOST);
    186         STR(VK_ERROR_LAYER_NOT_PRESENT);
    187         STR(VK_ERROR_EXTENSION_NOT_PRESENT);
    188         STR(VK_ERROR_MEMORY_MAP_FAILED);
    189         STR(VK_ERROR_INCOMPATIBLE_DRIVER);
    190 #undef STR
    191     default:
    192         return "UNKNOWN_RESULT";
    193     }
    194 }
    195 
    196 static const char *vk_physical_device_type_string(VkPhysicalDeviceType type) {
    197     switch (type) {
    198 #define STR(r)                                                                 \
    199     case VK_PHYSICAL_DEVICE_TYPE_##r:                                          \
    200         return #r
    201         STR(OTHER);
    202         STR(INTEGRATED_GPU);
    203         STR(DISCRETE_GPU);
    204         STR(VIRTUAL_GPU);
    205 #undef STR
    206     default:
    207         return "UNKNOWN_DEVICE";
    208     }
    209 }
    210 
    211 static const char *vk_format_string(VkFormat fmt) {
    212     switch (fmt) {
    213 #define STR(r)                                                                 \
    214     case VK_FORMAT_##r:                                                        \
    215         return #r
    216         STR(UNDEFINED);
    217         STR(R4G4_UNORM_PACK8);
    218         STR(R4G4B4A4_UNORM_PACK16);
    219         STR(B4G4R4A4_UNORM_PACK16);
    220         STR(R5G6B5_UNORM_PACK16);
    221         STR(B5G6R5_UNORM_PACK16);
    222         STR(R5G5B5A1_UNORM_PACK16);
    223         STR(B5G5R5A1_UNORM_PACK16);
    224         STR(A1R5G5B5_UNORM_PACK16);
    225         STR(R8_UNORM);
    226         STR(R8_SNORM);
    227         STR(R8_USCALED);
    228         STR(R8_SSCALED);
    229         STR(R8_UINT);
    230         STR(R8_SINT);
    231         STR(R8_SRGB);
    232         STR(R8G8_UNORM);
    233         STR(R8G8_SNORM);
    234         STR(R8G8_USCALED);
    235         STR(R8G8_SSCALED);
    236         STR(R8G8_UINT);
    237         STR(R8G8_SINT);
    238         STR(R8G8_SRGB);
    239         STR(R8G8B8_UNORM);
    240         STR(R8G8B8_SNORM);
    241         STR(R8G8B8_USCALED);
    242         STR(R8G8B8_SSCALED);
    243         STR(R8G8B8_UINT);
    244         STR(R8G8B8_SINT);
    245         STR(R8G8B8_SRGB);
    246         STR(B8G8R8_UNORM);
    247         STR(B8G8R8_SNORM);
    248         STR(B8G8R8_USCALED);
    249         STR(B8G8R8_SSCALED);
    250         STR(B8G8R8_UINT);
    251         STR(B8G8R8_SINT);
    252         STR(B8G8R8_SRGB);
    253         STR(R8G8B8A8_UNORM);
    254         STR(R8G8B8A8_SNORM);
    255         STR(R8G8B8A8_USCALED);
    256         STR(R8G8B8A8_SSCALED);
    257         STR(R8G8B8A8_UINT);
    258         STR(R8G8B8A8_SINT);
    259         STR(R8G8B8A8_SRGB);
    260         STR(B8G8R8A8_UNORM);
    261         STR(B8G8R8A8_SNORM);
    262         STR(B8G8R8A8_USCALED);
    263         STR(B8G8R8A8_SSCALED);
    264         STR(B8G8R8A8_UINT);
    265         STR(B8G8R8A8_SINT);
    266         STR(B8G8R8A8_SRGB);
    267         STR(A8B8G8R8_UNORM_PACK32);
    268         STR(A8B8G8R8_SNORM_PACK32);
    269         STR(A8B8G8R8_USCALED_PACK32);
    270         STR(A8B8G8R8_SSCALED_PACK32);
    271         STR(A8B8G8R8_UINT_PACK32);
    272         STR(A8B8G8R8_SINT_PACK32);
    273         STR(A8B8G8R8_SRGB_PACK32);
    274         STR(A2R10G10B10_UNORM_PACK32);
    275         STR(A2R10G10B10_SNORM_PACK32);
    276         STR(A2R10G10B10_USCALED_PACK32);
    277         STR(A2R10G10B10_SSCALED_PACK32);
    278         STR(A2R10G10B10_UINT_PACK32);
    279         STR(A2R10G10B10_SINT_PACK32);
    280         STR(A2B10G10R10_UNORM_PACK32);
    281         STR(A2B10G10R10_SNORM_PACK32);
    282         STR(A2B10G10R10_USCALED_PACK32);
    283         STR(A2B10G10R10_SSCALED_PACK32);
    284         STR(A2B10G10R10_UINT_PACK32);
    285         STR(A2B10G10R10_SINT_PACK32);
    286         STR(R16_UNORM);
    287         STR(R16_SNORM);
    288         STR(R16_USCALED);
    289         STR(R16_SSCALED);
    290         STR(R16_UINT);
    291         STR(R16_SINT);
    292         STR(R16_SFLOAT);
    293         STR(R16G16_UNORM);
    294         STR(R16G16_SNORM);
    295         STR(R16G16_USCALED);
    296         STR(R16G16_SSCALED);
    297         STR(R16G16_UINT);
    298         STR(R16G16_SINT);
    299         STR(R16G16_SFLOAT);
    300         STR(R16G16B16_UNORM);
    301         STR(R16G16B16_SNORM);
    302         STR(R16G16B16_USCALED);
    303         STR(R16G16B16_SSCALED);
    304         STR(R16G16B16_UINT);
    305         STR(R16G16B16_SINT);
    306         STR(R16G16B16_SFLOAT);
    307         STR(R16G16B16A16_UNORM);
    308         STR(R16G16B16A16_SNORM);
    309         STR(R16G16B16A16_USCALED);
    310         STR(R16G16B16A16_SSCALED);
    311         STR(R16G16B16A16_UINT);
    312         STR(R16G16B16A16_SINT);
    313         STR(R16G16B16A16_SFLOAT);
    314         STR(R32_UINT);
    315         STR(R32_SINT);
    316         STR(R32_SFLOAT);
    317         STR(R32G32_UINT);
    318         STR(R32G32_SINT);
    319         STR(R32G32_SFLOAT);
    320         STR(R32G32B32_UINT);
    321         STR(R32G32B32_SINT);
    322         STR(R32G32B32_SFLOAT);
    323         STR(R32G32B32A32_UINT);
    324         STR(R32G32B32A32_SINT);
    325         STR(R32G32B32A32_SFLOAT);
    326         STR(R64_UINT);
    327         STR(R64_SINT);
    328         STR(R64_SFLOAT);
    329         STR(R64G64_UINT);
    330         STR(R64G64_SINT);
    331         STR(R64G64_SFLOAT);
    332         STR(R64G64B64_UINT);
    333         STR(R64G64B64_SINT);
    334         STR(R64G64B64_SFLOAT);
    335         STR(R64G64B64A64_UINT);
    336         STR(R64G64B64A64_SINT);
    337         STR(R64G64B64A64_SFLOAT);
    338         STR(B10G11R11_UFLOAT_PACK32);
    339         STR(E5B9G9R9_UFLOAT_PACK32);
    340         STR(D16_UNORM);
    341         STR(X8_D24_UNORM_PACK32);
    342         STR(D32_SFLOAT);
    343         STR(S8_UINT);
    344         STR(D16_UNORM_S8_UINT);
    345         STR(D24_UNORM_S8_UINT);
    346         STR(D32_SFLOAT_S8_UINT);
    347         STR(BC1_RGB_UNORM_BLOCK);
    348         STR(BC1_RGB_SRGB_BLOCK);
    349         STR(BC2_UNORM_BLOCK);
    350         STR(BC2_SRGB_BLOCK);
    351         STR(BC3_UNORM_BLOCK);
    352         STR(BC3_SRGB_BLOCK);
    353         STR(BC4_UNORM_BLOCK);
    354         STR(BC4_SNORM_BLOCK);
    355         STR(BC5_UNORM_BLOCK);
    356         STR(BC5_SNORM_BLOCK);
    357         STR(BC6H_UFLOAT_BLOCK);
    358         STR(BC6H_SFLOAT_BLOCK);
    359         STR(BC7_UNORM_BLOCK);
    360         STR(BC7_SRGB_BLOCK);
    361         STR(ETC2_R8G8B8_UNORM_BLOCK);
    362         STR(ETC2_R8G8B8A1_UNORM_BLOCK);
    363         STR(ETC2_R8G8B8A8_UNORM_BLOCK);
    364         STR(EAC_R11_UNORM_BLOCK);
    365         STR(EAC_R11_SNORM_BLOCK);
    366         STR(EAC_R11G11_UNORM_BLOCK);
    367         STR(EAC_R11G11_SNORM_BLOCK);
    368         STR(ASTC_4x4_UNORM_BLOCK);
    369         STR(ASTC_4x4_SRGB_BLOCK);
    370         STR(ASTC_5x4_UNORM_BLOCK);
    371         STR(ASTC_5x4_SRGB_BLOCK);
    372         STR(ASTC_5x5_UNORM_BLOCK);
    373         STR(ASTC_5x5_SRGB_BLOCK);
    374         STR(ASTC_6x5_UNORM_BLOCK);
    375         STR(ASTC_6x5_SRGB_BLOCK);
    376         STR(ASTC_6x6_UNORM_BLOCK);
    377         STR(ASTC_6x6_SRGB_BLOCK);
    378         STR(ASTC_8x5_UNORM_BLOCK);
    379         STR(ASTC_8x5_SRGB_BLOCK);
    380         STR(ASTC_8x6_UNORM_BLOCK);
    381         STR(ASTC_8x6_SRGB_BLOCK);
    382         STR(ASTC_8x8_UNORM_BLOCK);
    383         STR(ASTC_8x8_SRGB_BLOCK);
    384         STR(ASTC_10x5_UNORM_BLOCK);
    385         STR(ASTC_10x5_SRGB_BLOCK);
    386         STR(ASTC_10x6_UNORM_BLOCK);
    387         STR(ASTC_10x6_SRGB_BLOCK);
    388         STR(ASTC_10x8_UNORM_BLOCK);
    389         STR(ASTC_10x8_SRGB_BLOCK);
    390         STR(ASTC_10x10_UNORM_BLOCK);
    391         STR(ASTC_10x10_SRGB_BLOCK);
    392         STR(ASTC_12x10_UNORM_BLOCK);
    393         STR(ASTC_12x10_SRGB_BLOCK);
    394         STR(ASTC_12x12_UNORM_BLOCK);
    395         STR(ASTC_12x12_SRGB_BLOCK);
    396 #undef STR
    397     default:
    398         return "UNKNOWN_FORMAT";
    399     }
    400 }
    401 
    402 static void app_dev_init_formats(struct app_dev *dev) {
    403     VkFormat f;
    404 
    405     for (f = 0; f < VK_FORMAT_RANGE_SIZE; f++) {
    406         const VkFormat fmt = f;
    407 
    408         vkGetPhysicalDeviceFormatProperties(dev->gpu->obj, fmt,
    409                                             &dev->format_props[f]);
    410     }
    411 }
    412 
    413 static void extract_version(uint32_t version, uint32_t *major, uint32_t *minor,
    414                             uint32_t *patch) {
    415     *major = version >> 22;
    416     *minor = (version >> 12) & 0x3ff;
    417     *patch = version & 0xfff;
    418 }
    419 
    420 static void app_get_physical_device_layer_extensions(
    421     struct app_gpu *gpu, char *layer_name, uint32_t *extension_count,
    422     VkExtensionProperties **extension_properties) {
    423     VkResult err;
    424     uint32_t ext_count = 0;
    425     VkExtensionProperties *ext_ptr = NULL;
    426 
    427     /* repeat get until VK_INCOMPLETE goes away */
    428     do {
    429         err = vkEnumerateDeviceExtensionProperties(gpu->obj, layer_name,
    430                                                    &ext_count, NULL);
    431         assert(!err);
    432 
    433         if (ext_ptr) {
    434             free(ext_ptr);
    435         }
    436         ext_ptr = malloc(ext_count * sizeof(VkExtensionProperties));
    437         err = vkEnumerateDeviceExtensionProperties(gpu->obj, layer_name,
    438                                                    &ext_count, ext_ptr);
    439     } while (err == VK_INCOMPLETE);
    440     assert(!err);
    441 
    442     *extension_count = ext_count;
    443     *extension_properties = ext_ptr;
    444 }
    445 
    446 static void app_dev_init(struct app_dev *dev, struct app_gpu *gpu) {
    447     VkDeviceCreateInfo info = {
    448         .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
    449         .pNext = NULL,
    450         .queueCreateInfoCount = 0,
    451         .pQueueCreateInfos = NULL,
    452         .enabledLayerCount = 0,
    453         .ppEnabledLayerNames = NULL,
    454         .enabledExtensionCount = 0,
    455         .ppEnabledExtensionNames = NULL,
    456     };
    457     VkResult U_ASSERT_ONLY err;
    458     // Extensions to enable
    459     static const char *known_extensions[] = {
    460         VK_KHR_SWAPCHAIN_EXTENSION_NAME,
    461     };
    462 
    463     uint32_t count = 0;
    464 
    465     /* Scan layers */
    466     VkLayerProperties *device_layer_properties = NULL;
    467     struct layer_extension_list *device_layers = NULL;
    468 
    469     do {
    470         err = vkEnumerateDeviceLayerProperties(gpu->obj, &count, NULL);
    471         assert(!err);
    472 
    473         if (device_layer_properties) {
    474             free(device_layer_properties);
    475         }
    476         device_layer_properties = malloc(sizeof(VkLayerProperties) * count);
    477         assert(device_layer_properties);
    478 
    479         if (device_layers) {
    480             free(device_layers);
    481         }
    482         device_layers = malloc(sizeof(struct layer_extension_list) * count);
    483         assert(device_layers);
    484 
    485         err = vkEnumerateDeviceLayerProperties(gpu->obj, &count,
    486                                                device_layer_properties);
    487     } while (err == VK_INCOMPLETE);
    488     assert(!err);
    489 
    490     gpu->device_layer_count = count;
    491     gpu->device_layers = device_layers;
    492 
    493     for (uint32_t i = 0; i < gpu->device_layer_count; i++) {
    494         VkLayerProperties *src_info = &device_layer_properties[i];
    495         struct layer_extension_list *dst_info = &gpu->device_layers[i];
    496         memcpy(&dst_info->layer_properties, src_info,
    497                sizeof(VkLayerProperties));
    498 
    499         /* Save away layer extension info for report */
    500         app_get_physical_device_layer_extensions(
    501             gpu, src_info->layerName, &dst_info->extension_count,
    502             &dst_info->extension_properties);
    503     }
    504     free(device_layer_properties);
    505 
    506     app_get_physical_device_layer_extensions(
    507         gpu, NULL, &gpu->device_extension_count, &gpu->device_extensions);
    508 
    509     fflush(stdout);
    510 
    511     uint32_t enabled_extension_count = 0;
    512     uint32_t known_extension_count = ARRAY_SIZE(known_extensions);
    513 
    514     for (uint32_t i = 0; i < known_extension_count; i++) {
    515         VkBool32 extension_found = 0;
    516         for (uint32_t j = 0; j < gpu->device_extension_count; j++) {
    517             VkExtensionProperties *ext_prop = &gpu->device_extensions[j];
    518             if (!strcmp(known_extensions[i], ext_prop->extensionName)) {
    519 
    520                 extension_found = 1;
    521                 enabled_extension_count++;
    522             }
    523         }
    524         if (!extension_found) {
    525             printf("Cannot find extension: %s\n", known_extensions[i]);
    526             ERR_EXIT(VK_ERROR_EXTENSION_NOT_PRESENT);
    527         }
    528     }
    529 
    530     /* request all queues */
    531     info.queueCreateInfoCount = gpu->queue_count;
    532     info.pQueueCreateInfos = gpu->queue_reqs;
    533 
    534     info.enabledLayerCount = 0;
    535     info.ppEnabledLayerNames = NULL;
    536     info.enabledExtensionCount = enabled_extension_count;
    537     info.ppEnabledExtensionNames = (const char *const *)known_extensions;
    538     dev->gpu = gpu;
    539     err = vkCreateDevice(gpu->obj, &info, NULL, &dev->obj);
    540     if (err)
    541         ERR_EXIT(err);
    542 }
    543 
    544 static void app_dev_destroy(struct app_dev *dev) {
    545     vkDestroyDevice(dev->obj, NULL);
    546 }
    547 
    548 static void
    549 app_get_global_layer_extensions(char *layer_name, uint32_t *extension_count,
    550                                 VkExtensionProperties **extension_properties) {
    551     VkResult err;
    552     uint32_t ext_count = 0;
    553     VkExtensionProperties *ext_ptr = NULL;
    554 
    555     /* repeat get until VK_INCOMPLETE goes away */
    556     do {
    557         err = vkEnumerateInstanceExtensionProperties(layer_name, &ext_count,
    558                                                      NULL);
    559         assert(!err);
    560 
    561         if (ext_ptr) {
    562             free(ext_ptr);
    563         }
    564         ext_ptr = malloc(ext_count * sizeof(VkExtensionProperties));
    565         err = vkEnumerateInstanceExtensionProperties(layer_name, &ext_count,
    566                                                      ext_ptr);
    567     } while (err == VK_INCOMPLETE);
    568     assert(!err);
    569 
    570     *extension_count = ext_count;
    571     *extension_properties = ext_ptr;
    572 }
    573 
    574 static void app_create_instance(struct app_instance *inst) {
    575     const VkApplicationInfo app_info = {
    576         .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
    577         .pNext = NULL,
    578         .pApplicationName = APP_SHORT_NAME,
    579         .applicationVersion = 1,
    580         .pEngineName = APP_SHORT_NAME,
    581         .engineVersion = 1,
    582         .apiVersion = VK_API_VERSION_1_0,
    583     };
    584     VkInstanceCreateInfo inst_info = {
    585         .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
    586         .pNext = NULL,
    587         .pApplicationInfo = &app_info,
    588         .enabledLayerCount = 0,
    589         .ppEnabledLayerNames = NULL,
    590         .enabledExtensionCount = 0,
    591         .ppEnabledExtensionNames = NULL,
    592     };
    593     VkResult U_ASSERT_ONLY err;
    594     // Global Extensions to enable
    595     static char *known_extensions[] = {
    596         VK_KHR_SURFACE_EXTENSION_NAME,
    597 #ifdef VK_USE_PLATFORM_ANDROID_KHR
    598         VK_KHR_ANDROID_SURFACE_EXTENSION_NAME,
    599 #endif
    600 #ifdef VK_USE_PLATFORM_MIR_KHR
    601         VK_KHR_MIR_SURFACE_EXTENSION_NAME,
    602 #endif
    603 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
    604         VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME,
    605 #endif
    606 #ifdef VK_USE_PLATFORM_WIN32_KHR
    607         VK_KHR_WIN32_SURFACE_EXTENSION_NAME,
    608 #endif
    609 #ifdef VK_USE_PLATFORM_XCB_KHR
    610         VK_KHR_XCB_SURFACE_EXTENSION_NAME,
    611 #endif
    612 #ifdef VK_USE_PLATFORM_XLIB_KHR
    613         VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
    614 #endif
    615     };
    616 
    617     uint32_t global_extension_count = 0;
    618     uint32_t count = 0;
    619 
    620     /* Scan layers */
    621     VkLayerProperties *global_layer_properties = NULL;
    622     struct layer_extension_list *global_layers = NULL;
    623 
    624     do {
    625         err = vkEnumerateInstanceLayerProperties(&count, NULL);
    626         assert(!err);
    627 
    628         if (global_layer_properties) {
    629             free(global_layer_properties);
    630         }
    631         global_layer_properties = malloc(sizeof(VkLayerProperties) * count);
    632         assert(global_layer_properties);
    633 
    634         if (global_layers) {
    635             free(global_layers);
    636         }
    637         global_layers = malloc(sizeof(struct layer_extension_list) * count);
    638         assert(global_layers);
    639 
    640         err =
    641             vkEnumerateInstanceLayerProperties(&count, global_layer_properties);
    642     } while (err == VK_INCOMPLETE);
    643     assert(!err);
    644 
    645     inst->global_layer_count = count;
    646     inst->global_layers = global_layers;
    647 
    648     for (uint32_t i = 0; i < inst->global_layer_count; i++) {
    649         VkLayerProperties *src_info = &global_layer_properties[i];
    650         struct layer_extension_list *dst_info = &inst->global_layers[i];
    651         memcpy(&dst_info->layer_properties, src_info,
    652                sizeof(VkLayerProperties));
    653 
    654         /* Save away layer extension info for report */
    655         app_get_global_layer_extensions(src_info->layerName,
    656                                         &dst_info->extension_count,
    657                                         &dst_info->extension_properties);
    658     }
    659     free(global_layer_properties);
    660 
    661     /* Collect global extensions */
    662     inst->global_extension_count = 0;
    663     app_get_global_layer_extensions(NULL, &inst->global_extension_count,
    664                                     &inst->global_extensions);
    665 
    666     for (uint32_t i = 0; i < ARRAY_SIZE(known_extensions); i++) {
    667         VkBool32 extension_found = 0;
    668         for (uint32_t j = 0; j < inst->global_extension_count; j++) {
    669             VkExtensionProperties *extension_prop = &inst->global_extensions[j];
    670             if (!strcmp(known_extensions[i], extension_prop->extensionName)) {
    671 
    672                 extension_found = 1;
    673                 global_extension_count++;
    674             }
    675         }
    676         if (!extension_found) {
    677             printf("Cannot find extension: %s\n", known_extensions[i]);
    678             ERR_EXIT(VK_ERROR_EXTENSION_NOT_PRESENT);
    679         }
    680     }
    681 
    682     inst_info.enabledExtensionCount = global_extension_count;
    683     inst_info.ppEnabledExtensionNames = (const char *const *)known_extensions;
    684 
    685     VkDebugReportCallbackCreateInfoEXT dbg_info;
    686     memset(&dbg_info, 0, sizeof(dbg_info));
    687     dbg_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
    688     dbg_info.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT |
    689                      VK_DEBUG_REPORT_WARNING_BIT_EXT |
    690                      VK_DEBUG_REPORT_INFORMATION_BIT_EXT;
    691     dbg_info.pfnCallback = dbg_callback;
    692     inst_info.pNext = &dbg_info;
    693 
    694     err = vkCreateInstance(&inst_info, NULL, &inst->instance);
    695     if (err == VK_ERROR_INCOMPATIBLE_DRIVER) {
    696         printf("Cannot create Vulkan instance.\n");
    697         ERR_EXIT(err);
    698     } else if (err) {
    699         ERR_EXIT(err);
    700     }
    701 }
    702 
    703 static void app_destroy_instance(struct app_instance *inst) {
    704     free(inst->global_extensions);
    705     vkDestroyInstance(inst->instance, NULL);
    706 }
    707 
    708 static void app_gpu_init(struct app_gpu *gpu, uint32_t id,
    709                          VkPhysicalDevice obj) {
    710     uint32_t i;
    711 
    712     memset(gpu, 0, sizeof(*gpu));
    713 
    714     gpu->id = id;
    715     gpu->obj = obj;
    716 
    717     vkGetPhysicalDeviceProperties(gpu->obj, &gpu->props);
    718 
    719     /* get queue count */
    720     vkGetPhysicalDeviceQueueFamilyProperties(gpu->obj, &gpu->queue_count, NULL);
    721 
    722     gpu->queue_props = malloc(sizeof(gpu->queue_props[0]) * gpu->queue_count);
    723 
    724     if (!gpu->queue_props)
    725         ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
    726     vkGetPhysicalDeviceQueueFamilyProperties(gpu->obj, &gpu->queue_count,
    727                                              gpu->queue_props);
    728 
    729     /* set up queue requests */
    730     gpu->queue_reqs = malloc(sizeof(*gpu->queue_reqs) * gpu->queue_count);
    731     if (!gpu->queue_reqs)
    732         ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
    733     for (i = 0; i < gpu->queue_count; i++) {
    734         float *queue_priorities =
    735             malloc(gpu->queue_props[i].queueCount * sizeof(float));
    736         memset(queue_priorities, 0,
    737                gpu->queue_props[i].queueCount * sizeof(float));
    738         gpu->queue_reqs[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
    739         gpu->queue_reqs[i].pNext = NULL;
    740         gpu->queue_reqs[i].queueFamilyIndex = i;
    741         gpu->queue_reqs[i].queueCount = gpu->queue_props[i].queueCount;
    742         gpu->queue_reqs[i].pQueuePriorities = queue_priorities;
    743     }
    744 
    745     vkGetPhysicalDeviceMemoryProperties(gpu->obj, &gpu->memory_props);
    746 
    747     vkGetPhysicalDeviceFeatures(gpu->obj, &gpu->features);
    748 
    749     app_dev_init(&gpu->dev, gpu);
    750     app_dev_init_formats(&gpu->dev);
    751 }
    752 
    753 static void app_gpu_destroy(struct app_gpu *gpu) {
    754     app_dev_destroy(&gpu->dev);
    755     free(gpu->device_extensions);
    756 
    757     for (uint32_t i = 0; i < gpu->queue_count; i++) {
    758         free((void *)gpu->queue_reqs[i].pQueuePriorities);
    759     }
    760     free(gpu->queue_reqs);
    761     free(gpu->queue_props);
    762 }
    763 
    764 // clang-format off
    765 static void app_dev_dump_format_props(const struct app_dev *dev, VkFormat fmt)
    766 {
    767     const VkFormatProperties *props = &dev->format_props[fmt];
    768     struct {
    769         const char *name;
    770         VkFlags flags;
    771     } features[3];
    772     uint32_t i;
    773 
    774     features[0].name  = "linearTiling   FormatFeatureFlags";
    775     features[0].flags = props->linearTilingFeatures;
    776     features[1].name  = "optimalTiling  FormatFeatureFlags";
    777     features[1].flags = props->optimalTilingFeatures;
    778     features[2].name  = "bufferFeatures FormatFeatureFlags";
    779     features[2].flags = props->bufferFeatures;
    780 
    781     printf("\nFORMAT_%s:", vk_format_string(fmt));
    782     for (i = 0; i < ARRAY_SIZE(features); i++) {
    783         printf("\n\t%s:", features[i].name);
    784         if (features[i].flags == 0) {
    785             printf("\n\t\tNone");
    786         } else {
    787             printf("%s%s%s%s%s%s%s%s%s%s%s%s%s",
    788                ((features[i].flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)               ? "\n\t\tVK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT"               : ""),
    789                ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)               ? "\n\t\tVK_FORMAT_FEATURE_STORAGE_IMAGE_BIT"               : ""),
    790                ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT)        ? "\n\t\tVK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT"        : ""),
    791                ((features[i].flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)            ? "\n\t\tVK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT"            : ""),
    792                ((features[i].flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT)      ? "\n\t\tVK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT"      : ""),
    793                ((features[i].flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)    ? "\n\t\tVK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT"    : ""),
    794                ((features[i].flags & VK_FORMAT_FEATURE_BLIT_SRC_BIT)                    ? "\n\t\tVK_FORMAT_FEATURE_BLIT_SRC_BIT"                    : ""),
    795                ((features[i].flags & VK_FORMAT_FEATURE_BLIT_DST_BIT)                    ? "\n\t\tVK_FORMAT_FEATURE_BLIT_DST_BIT"                    : ""),
    796                ((features[i].flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT) ? "\n\t\tVK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT" : ""),
    797                ((features[i].flags & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT)        ? "\n\t\tVK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT"        : ""),
    798                ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT)        ? "\n\t\tVK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT"        : ""),
    799                ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT) ? "\n\t\tVK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT" : ""),
    800                ((features[i].flags & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT)               ? "\n\t\tVK_FORMAT_FEATURE_VERTEX_BUFFER_BIT"               : ""));
    801         }
    802     }
    803     printf("\n");
    804 }
    805 
    806 
    807 static void
    808 app_dev_dump(const struct app_dev *dev)
    809 {
    810     VkFormat fmt;
    811 
    812     for (fmt = 0; fmt < VK_FORMAT_RANGE_SIZE; fmt++) {
    813         app_dev_dump_format_props(dev, fmt);
    814     }
    815 }
    816 
    817 #ifdef _WIN32
    818 #define PRINTF_SIZE_T_SPECIFIER    "%Iu"
    819 #else
    820 #define PRINTF_SIZE_T_SPECIFIER    "%zu"
    821 #endif
    822 
    823 static void app_gpu_dump_features(const struct app_gpu *gpu)
    824 {
    825     const VkPhysicalDeviceFeatures *features = &gpu->features;
    826 
    827     printf("VkPhysicalDeviceFeatures:\n");
    828     printf("=========================\n");
    829 
    830     printf("\trobustBufferAccess                      = %u\n", features->robustBufferAccess                     );
    831     printf("\tfullDrawIndexUint32                     = %u\n", features->fullDrawIndexUint32                    );
    832     printf("\timageCubeArray                          = %u\n", features->imageCubeArray                         );
    833     printf("\tindependentBlend                        = %u\n", features->independentBlend                       );
    834     printf("\tgeometryShader                          = %u\n", features->geometryShader                         );
    835     printf("\ttessellationShader                      = %u\n", features->tessellationShader                     );
    836     printf("\tsampleRateShading                       = %u\n", features->sampleRateShading                      );
    837     printf("\tdualSrcBlend                            = %u\n", features->dualSrcBlend                           );
    838     printf("\tlogicOp                                 = %u\n", features->logicOp                                );
    839     printf("\tmultiDrawIndirect                       = %u\n", features->multiDrawIndirect                      );
    840     printf("\tdrawIndirectFirstInstance               = %u\n", features->drawIndirectFirstInstance              );
    841     printf("\tdepthClamp                              = %u\n", features->depthClamp                             );
    842     printf("\tdepthBiasClamp                          = %u\n", features->depthBiasClamp                         );
    843     printf("\tfillModeNonSolid                        = %u\n", features->fillModeNonSolid                       );
    844     printf("\tdepthBounds                             = %u\n", features->depthBounds                            );
    845     printf("\twideLines                               = %u\n", features->wideLines                              );
    846     printf("\tlargePoints                             = %u\n", features->largePoints                            );
    847     printf("\ttextureCompressionETC2                  = %u\n", features->textureCompressionETC2                 );
    848     printf("\ttextureCompressionASTC_LDR              = %u\n", features->textureCompressionASTC_LDR             );
    849     printf("\ttextureCompressionBC                    = %u\n", features->textureCompressionBC                   );
    850     printf("\tocclusionQueryPrecise                   = %u\n", features->occlusionQueryPrecise                  );
    851     printf("\tpipelineStatisticsQuery                 = %u\n", features->pipelineStatisticsQuery                );
    852     printf("\tvertexSideEffects                       = %u\n", features->vertexPipelineStoresAndAtomics         );
    853     printf("\ttessellationSideEffects                 = %u\n", features->fragmentStoresAndAtomics               );
    854     printf("\tgeometrySideEffects                     = %u\n", features->shaderTessellationAndGeometryPointSize );
    855     printf("\tshaderImageGatherExtended               = %u\n", features->shaderImageGatherExtended              );
    856     printf("\tshaderStorageImageExtendedFormats       = %u\n", features->shaderStorageImageExtendedFormats      );
    857     printf("\tshaderStorageImageMultisample           = %u\n", features->shaderStorageImageMultisample          );
    858     printf("\tshaderStorageImageReadWithoutFormat     = %u\n", features->shaderStorageImageReadWithoutFormat    );
    859     printf("\tshaderStorageImageWriteWithoutFormat    = %u\n", features->shaderStorageImageWriteWithoutFormat   );
    860     printf("\tshaderUniformBufferArrayDynamicIndexing = %u\n", features->shaderUniformBufferArrayDynamicIndexing);
    861     printf("\tshaderSampledImageArrayDynamicIndexing  = %u\n", features->shaderSampledImageArrayDynamicIndexing );
    862     printf("\tshaderStorageBufferArrayDynamicIndexing = %u\n", features->shaderStorageBufferArrayDynamicIndexing);
    863     printf("\tshaderStorageImageArrayDynamicIndexing  = %u\n", features->shaderStorageImageArrayDynamicIndexing );
    864     printf("\tshaderClipDistance                      = %u\n", features->shaderClipDistance                     );
    865     printf("\tshaderCullDistance                      = %u\n", features->shaderCullDistance                     );
    866     printf("\tshaderFloat64                           = %u\n", features->shaderFloat64                          );
    867     printf("\tshaderInt64                             = %u\n", features->shaderInt64                            );
    868     printf("\tshaderInt16                             = %u\n", features->shaderInt16                            );
    869     printf("\tshaderResourceResidency                 = %u\n", features->shaderResourceResidency                );
    870     printf("\tshaderResourceMinLod                    = %u\n", features->shaderResourceMinLod                   );
    871     printf("\talphaToOne                              = %u\n", features->alphaToOne                             );
    872     printf("\tsparseBinding                           = %u\n", features->sparseBinding                          );
    873     printf("\tsparseResidencyBuffer                   = %u\n", features->sparseResidencyBuffer                  );
    874     printf("\tsparseResidencyImage2D                  = %u\n", features->sparseResidencyImage2D                 );
    875     printf("\tsparseResidencyImage3D                  = %u\n", features->sparseResidencyImage3D                 );
    876     printf("\tsparseResidency2Samples                 = %u\n", features->sparseResidency2Samples                );
    877     printf("\tsparseResidency4Samples                 = %u\n", features->sparseResidency4Samples                );
    878     printf("\tsparseResidency8Samples                 = %u\n", features->sparseResidency8Samples                );
    879     printf("\tsparseResidency16Samples                = %u\n", features->sparseResidency16Samples               );
    880     printf("\tsparseResidencyAliased                  = %u\n", features->sparseResidencyAliased                 );
    881     printf("\tvariableMultisampleRate                 = %u\n", features->variableMultisampleRate                );
    882     printf("\tiheritedQueries                         = %u\n", features->inheritedQueries                       );
    883 }
    884 
    885 static void app_dump_sparse_props(const VkPhysicalDeviceSparseProperties *sparseProps)
    886 {
    887 
    888     printf("\tVkPhysicalDeviceSparseProperties:\n");
    889     printf("\t---------------------------------\n");
    890 
    891     printf("\t\tresidencyStandard2DBlockShape            = %u\n", sparseProps->residencyStandard2DBlockShape           );
    892     printf("\t\tresidencyStandard2DMultisampleBlockShape = %u\n", sparseProps->residencyStandard2DMultisampleBlockShape);
    893     printf("\t\tresidencyStandard3DBlockShape            = %u\n", sparseProps->residencyStandard3DBlockShape           );
    894     printf("\t\tresidencyAlignedMipSize                  = %u\n", sparseProps->residencyAlignedMipSize                 );
    895     printf("\t\tresidencyNonResidentStrict               = %u\n", sparseProps->residencyNonResidentStrict              );
    896 }
    897 
    898 static void app_dump_limits(const VkPhysicalDeviceLimits *limits)
    899 {
    900     printf("\tVkPhysicalDeviceLimits:\n");
    901     printf("\t-----------------------\n");
    902 
    903     printf("\t\tmaxImageDimension1D                     = 0x%" PRIxLEAST32 "\n", limits->maxImageDimension1D                    );
    904     printf("\t\tmaxImageDimension2D                     = 0x%" PRIxLEAST32 "\n", limits->maxImageDimension2D                    );
    905     printf("\t\tmaxImageDimension3D                     = 0x%" PRIxLEAST32 "\n", limits->maxImageDimension3D                    );
    906     printf("\t\tmaxImageDimensionCube                   = 0x%" PRIxLEAST32 "\n", limits->maxImageDimensionCube                  );
    907     printf("\t\tmaxImageArrayLayers                     = 0x%" PRIxLEAST32 "\n", limits->maxImageArrayLayers                    );
    908     printf("\t\tmaxTexelBufferElements                  = 0x%" PRIxLEAST32 "\n", limits->maxTexelBufferElements                 );
    909     printf("\t\tmaxUniformBufferRange                   = 0x%" PRIxLEAST32 "\n", limits->maxUniformBufferRange                  );
    910     printf("\t\tmaxStorageBufferRange                   = 0x%" PRIxLEAST32 "\n", limits->maxStorageBufferRange                  );
    911     printf("\t\tmaxPushConstantsSize                    = 0x%" PRIxLEAST32 "\n", limits->maxPushConstantsSize                   );
    912     printf("\t\tmaxMemoryAllocationCount                = 0x%" PRIxLEAST32 "\n", limits->maxMemoryAllocationCount               );
    913     printf("\t\tmaxSamplerAllocationCount               = 0x%" PRIxLEAST32 "\n", limits->maxSamplerAllocationCount              );
    914     printf("\t\tbufferImageGranularity                  = 0x%" PRIxLEAST64 "\n", limits->bufferImageGranularity                 );
    915     printf("\t\tsparseAddressSpaceSize                  = 0x%" PRIxLEAST64 "\n", limits->sparseAddressSpaceSize                 );
    916     printf("\t\tmaxBoundDescriptorSets                  = 0x%" PRIxLEAST32 "\n", limits->maxBoundDescriptorSets                 );
    917     printf("\t\tmaxPerStageDescriptorSamplers           = 0x%" PRIxLEAST32 "\n", limits->maxPerStageDescriptorSamplers          );
    918     printf("\t\tmaxPerStageDescriptorUniformBuffers     = 0x%" PRIxLEAST32 "\n", limits->maxPerStageDescriptorUniformBuffers    );
    919     printf("\t\tmaxPerStageDescriptorStorageBuffers     = 0x%" PRIxLEAST32 "\n", limits->maxPerStageDescriptorStorageBuffers    );
    920     printf("\t\tmaxPerStageDescriptorSampledImages      = 0x%" PRIxLEAST32 "\n", limits->maxPerStageDescriptorSampledImages     );
    921     printf("\t\tmaxPerStageDescriptorStorageImages      = 0x%" PRIxLEAST32 "\n", limits->maxPerStageDescriptorStorageImages     );
    922     printf("\t\tmaxPerStageDescriptorInputAttachments   = 0x%" PRIxLEAST32 "\n", limits->maxPerStageDescriptorInputAttachments  );
    923     printf("\t\tmaxPerStageResources                    = 0x%" PRIxLEAST32 "\n", limits->maxPerStageResources                   );
    924     printf("\t\tmaxDescriptorSetSamplers                = 0x%" PRIxLEAST32 "\n", limits->maxDescriptorSetSamplers               );
    925     printf("\t\tmaxDescriptorSetUniformBuffers          = 0x%" PRIxLEAST32 "\n", limits->maxDescriptorSetUniformBuffers         );
    926     printf("\t\tmaxDescriptorSetUniformBuffersDynamic   = 0x%" PRIxLEAST32 "\n", limits->maxDescriptorSetUniformBuffersDynamic  );
    927     printf("\t\tmaxDescriptorSetStorageBuffers          = 0x%" PRIxLEAST32 "\n", limits->maxDescriptorSetStorageBuffers         );
    928     printf("\t\tmaxDescriptorSetStorageBuffersDynamic   = 0x%" PRIxLEAST32 "\n", limits->maxDescriptorSetStorageBuffersDynamic  );
    929     printf("\t\tmaxDescriptorSetSampledImages           = 0x%" PRIxLEAST32 "\n", limits->maxDescriptorSetSampledImages          );
    930     printf("\t\tmaxDescriptorSetStorageImages           = 0x%" PRIxLEAST32 "\n", limits->maxDescriptorSetStorageImages          );
    931     printf("\t\tmaxDescriptorSetInputAttachments        = 0x%" PRIxLEAST32 "\n", limits->maxDescriptorSetInputAttachments       );
    932     printf("\t\tmaxVertexInputAttributes                = 0x%" PRIxLEAST32 "\n", limits->maxVertexInputAttributes               );
    933     printf("\t\tmaxVertexInputBindings                  = 0x%" PRIxLEAST32 "\n", limits->maxVertexInputBindings                 );
    934     printf("\t\tmaxVertexInputAttributeOffset           = 0x%" PRIxLEAST32 "\n", limits->maxVertexInputAttributeOffset          );
    935     printf("\t\tmaxVertexInputBindingStride             = 0x%" PRIxLEAST32 "\n", limits->maxVertexInputBindingStride            );
    936     printf("\t\tmaxVertexOutputComponents               = 0x%" PRIxLEAST32 "\n", limits->maxVertexOutputComponents              );
    937     printf("\t\tmaxTessellationGenerationLevel          = 0x%" PRIxLEAST32 "\n", limits->maxTessellationGenerationLevel         );
    938     printf("\t\tmaxTessellationPatchSize                        = 0x%" PRIxLEAST32 "\n", limits->maxTessellationPatchSize                       );
    939     printf("\t\tmaxTessellationControlPerVertexInputComponents  = 0x%" PRIxLEAST32 "\n", limits->maxTessellationControlPerVertexInputComponents );
    940     printf("\t\tmaxTessellationControlPerVertexOutputComponents = 0x%" PRIxLEAST32 "\n", limits->maxTessellationControlPerVertexOutputComponents);
    941     printf("\t\tmaxTessellationControlPerPatchOutputComponents  = 0x%" PRIxLEAST32 "\n", limits->maxTessellationControlPerPatchOutputComponents );
    942     printf("\t\tmaxTessellationControlTotalOutputComponents     = 0x%" PRIxLEAST32 "\n", limits->maxTessellationControlTotalOutputComponents    );
    943     printf("\t\tmaxTessellationEvaluationInputComponents        = 0x%" PRIxLEAST32 "\n", limits->maxTessellationEvaluationInputComponents       );
    944     printf("\t\tmaxTessellationEvaluationOutputComponents       = 0x%" PRIxLEAST32 "\n", limits->maxTessellationEvaluationOutputComponents      );
    945     printf("\t\tmaxGeometryShaderInvocations            = 0x%" PRIxLEAST32 "\n", limits->maxGeometryShaderInvocations           );
    946     printf("\t\tmaxGeometryInputComponents              = 0x%" PRIxLEAST32 "\n", limits->maxGeometryInputComponents             );
    947     printf("\t\tmaxGeometryOutputComponents             = 0x%" PRIxLEAST32 "\n", limits->maxGeometryOutputComponents            );
    948     printf("\t\tmaxGeometryOutputVertices               = 0x%" PRIxLEAST32 "\n", limits->maxGeometryOutputVertices              );
    949     printf("\t\tmaxGeometryTotalOutputComponents        = 0x%" PRIxLEAST32 "\n", limits->maxGeometryTotalOutputComponents       );
    950     printf("\t\tmaxFragmentInputComponents              = 0x%" PRIxLEAST32 "\n", limits->maxFragmentInputComponents             );
    951     printf("\t\tmaxFragmentOutputAttachments            = 0x%" PRIxLEAST32 "\n", limits->maxFragmentOutputAttachments           );
    952     printf("\t\tmaxFragmentDualSrcAttachments           = 0x%" PRIxLEAST32 "\n", limits->maxFragmentDualSrcAttachments          );
    953     printf("\t\tmaxFragmentCombinedOutputResources      = 0x%" PRIxLEAST32 "\n", limits->maxFragmentCombinedOutputResources     );
    954     printf("\t\tmaxComputeSharedMemorySize              = 0x%" PRIxLEAST32 "\n", limits->maxComputeSharedMemorySize             );
    955     printf("\t\tmaxComputeWorkGroupCount[0]             = 0x%" PRIxLEAST32 "\n", limits->maxComputeWorkGroupCount[0]            );
    956     printf("\t\tmaxComputeWorkGroupCount[1]             = 0x%" PRIxLEAST32 "\n", limits->maxComputeWorkGroupCount[1]            );
    957     printf("\t\tmaxComputeWorkGroupCount[2]             = 0x%" PRIxLEAST32 "\n", limits->maxComputeWorkGroupCount[2]            );
    958     printf("\t\tmaxComputeWorkGroupInvocations          = 0x%" PRIxLEAST32 "\n", limits->maxComputeWorkGroupInvocations         );
    959     printf("\t\tmaxComputeWorkGroupSize[0]              = 0x%" PRIxLEAST32 "\n", limits->maxComputeWorkGroupSize[0]             );
    960     printf("\t\tmaxComputeWorkGroupSize[1]              = 0x%" PRIxLEAST32 "\n", limits->maxComputeWorkGroupSize[1]             );
    961     printf("\t\tmaxComputeWorkGroupSize[2]              = 0x%" PRIxLEAST32 "\n", limits->maxComputeWorkGroupSize[2]             );
    962     printf("\t\tsubPixelPrecisionBits                   = 0x%" PRIxLEAST32 "\n", limits->subPixelPrecisionBits                  );
    963     printf("\t\tsubTexelPrecisionBits                   = 0x%" PRIxLEAST32 "\n", limits->subTexelPrecisionBits                  );
    964     printf("\t\tmipmapPrecisionBits                     = 0x%" PRIxLEAST32 "\n", limits->mipmapPrecisionBits                    );
    965     printf("\t\tmaxDrawIndexedIndexValue                = 0x%" PRIxLEAST32 "\n", limits->maxDrawIndexedIndexValue               );
    966     printf("\t\tmaxDrawIndirectCount                    = 0x%" PRIxLEAST32 "\n", limits->maxDrawIndirectCount                   );
    967     printf("\t\tmaxSamplerLodBias                       = %f\n",                 limits->maxSamplerLodBias                      );
    968     printf("\t\tmaxSamplerAnisotropy                    = %f\n",                 limits->maxSamplerAnisotropy                   );
    969     printf("\t\tmaxViewports                            = 0x%" PRIxLEAST32 "\n", limits->maxViewports                           );
    970     printf("\t\tmaxViewportDimensions[0]                = 0x%" PRIxLEAST32 "\n", limits->maxViewportDimensions[0]               );
    971     printf("\t\tmaxViewportDimensions[1]                = 0x%" PRIxLEAST32 "\n", limits->maxViewportDimensions[1]               );
    972     printf("\t\tviewportBoundsRange[0]                  = %f\n",                 limits->viewportBoundsRange[0]                 );
    973     printf("\t\tviewportBoundsRange[1]                  = %f\n",                 limits->viewportBoundsRange[1]                 );
    974     printf("\t\tviewportSubPixelBits                    = 0x%" PRIxLEAST32 "\n", limits->viewportSubPixelBits                   );
    975     printf("\t\tminMemoryMapAlignment                   = " PRINTF_SIZE_T_SPECIFIER "\n", limits->minMemoryMapAlignment         );
    976     printf("\t\tminTexelBufferOffsetAlignment           = 0x%" PRIxLEAST64 "\n", limits->minTexelBufferOffsetAlignment          );
    977     printf("\t\tminUniformBufferOffsetAlignment         = 0x%" PRIxLEAST64 "\n", limits->minUniformBufferOffsetAlignment        );
    978     printf("\t\tminStorageBufferOffsetAlignment         = 0x%" PRIxLEAST64 "\n", limits->minStorageBufferOffsetAlignment        );
    979     printf("\t\tminTexelOffset                          = 0x%" PRIxLEAST32 "\n", limits->minTexelOffset                         );
    980     printf("\t\tmaxTexelOffset                          = 0x%" PRIxLEAST32 "\n", limits->maxTexelOffset                         );
    981     printf("\t\tminTexelGatherOffset                    = 0x%" PRIxLEAST32 "\n", limits->minTexelGatherOffset                   );
    982     printf("\t\tmaxTexelGatherOffset                    = 0x%" PRIxLEAST32 "\n", limits->maxTexelGatherOffset                   );
    983     printf("\t\tminInterpolationOffset                  = %f\n",                 limits->minInterpolationOffset                 );
    984     printf("\t\tmaxInterpolationOffset                  = %f\n",                 limits->maxInterpolationOffset                 );
    985     printf("\t\tsubPixelInterpolationOffsetBits         = 0x%" PRIxLEAST32 "\n", limits->subPixelInterpolationOffsetBits        );
    986     printf("\t\tmaxFramebufferWidth                     = 0x%" PRIxLEAST32 "\n", limits->maxFramebufferWidth                    );
    987     printf("\t\tmaxFramebufferHeight                    = 0x%" PRIxLEAST32 "\n", limits->maxFramebufferHeight                   );
    988     printf("\t\tmaxFramebufferLayers                    = 0x%" PRIxLEAST32 "\n", limits->maxFramebufferLayers                   );
    989     printf("\t\tframebufferColorSampleCounts            = 0x%" PRIxLEAST32 "\n", limits->framebufferColorSampleCounts           );
    990     printf("\t\tframebufferDepthSampleCounts            = 0x%" PRIxLEAST32 "\n", limits->framebufferDepthSampleCounts           );
    991     printf("\t\tframebufferStencilSampleCounts          = 0x%" PRIxLEAST32 "\n", limits->framebufferStencilSampleCounts         );
    992     printf("\t\tmaxColorAttachments                     = 0x%" PRIxLEAST32 "\n", limits->maxColorAttachments                    );
    993     printf("\t\tsampledImageColorSampleCounts           = 0x%" PRIxLEAST32 "\n", limits->sampledImageColorSampleCounts          );
    994     printf("\t\tsampledImageDepthSampleCounts           = 0x%" PRIxLEAST32 "\n", limits->sampledImageDepthSampleCounts          );
    995     printf("\t\tsampledImageStencilSampleCounts         = 0x%" PRIxLEAST32 "\n", limits->sampledImageStencilSampleCounts        );
    996     printf("\t\tsampledImageIntegerSampleCounts         = 0x%" PRIxLEAST32 "\n", limits->sampledImageIntegerSampleCounts        );
    997     printf("\t\tstorageImageSampleCounts                = 0x%" PRIxLEAST32 "\n", limits->storageImageSampleCounts               );
    998     printf("\t\tmaxSampleMaskWords                      = 0x%" PRIxLEAST32 "\n", limits->maxSampleMaskWords                     );
    999     printf("\t\ttimestampComputeAndGraphics             = %u\n",                 limits->timestampComputeAndGraphics            );
   1000     printf("\t\ttimestampPeriod                         = 0x%f\n",               limits->timestampPeriod                        );
   1001     printf("\t\tmaxClipDistances                        = 0x%" PRIxLEAST32 "\n", limits->maxClipDistances                       );
   1002     printf("\t\tmaxCullDistances                        = 0x%" PRIxLEAST32 "\n", limits->maxCullDistances                       );
   1003     printf("\t\tmaxCombinedClipAndCullDistances         = 0x%" PRIxLEAST32 "\n", limits->maxCombinedClipAndCullDistances        );
   1004     printf("\t\tpointSizeRange[0]                       = %f\n",                 limits->pointSizeRange[0]                      );
   1005     printf("\t\tpointSizeRange[1]                       = %f\n",                 limits->pointSizeRange[1]                      );
   1006     printf("\t\tlineWidthRange[0]                       = %f\n",                 limits->lineWidthRange[0]                      );
   1007     printf("\t\tlineWidthRange[1]                       = %f\n",                 limits->lineWidthRange[1]                      );
   1008     printf("\t\tpointSizeGranularity                    = %f\n",                 limits->pointSizeGranularity                   );
   1009     printf("\t\tlineWidthGranularity                    = %f\n",                 limits->lineWidthGranularity                   );
   1010     printf("\t\tstrictLines                             = %u\n",                 limits->strictLines                            );
   1011     printf("\t\tstandardSampleLocations                 = %u\n",                 limits->standardSampleLocations                );
   1012     printf("\t\toptimalBufferCopyOffsetAlignment        = 0x%" PRIxLEAST64 "\n", limits->optimalBufferCopyOffsetAlignment       );
   1013     printf("\t\toptimalBufferCopyRowPitchAlignment      = 0x%" PRIxLEAST64 "\n", limits->optimalBufferCopyRowPitchAlignment     );
   1014     printf("\t\tnonCoherentAtomSize                     = 0x%" PRIxLEAST64 "\n", limits->nonCoherentAtomSize                    );
   1015 }
   1016 
   1017 static void app_gpu_dump_props(const struct app_gpu *gpu)
   1018 {
   1019     const VkPhysicalDeviceProperties *props = &gpu->props;
   1020 
   1021     printf("VkPhysicalDeviceProperties:\n");
   1022     printf("===========================\n");
   1023     printf("\tapiVersion     = %u\n",                props->apiVersion);
   1024     printf("\tdriverVersion  = %u\n",                props->driverVersion);
   1025     printf("\tvendorID       = 0x%04x\n",            props->vendorID);
   1026     printf("\tdeviceID       = 0x%04x\n",            props->deviceID);
   1027     printf("\tdeviceType     = %s\n",                vk_physical_device_type_string(props->deviceType));
   1028     printf("\tdeviceName     = %s\n",                props->deviceName);
   1029 
   1030     app_dump_limits(&gpu->props.limits);
   1031     app_dump_sparse_props(&gpu->props.sparseProperties);
   1032 
   1033     fflush(stdout);
   1034 }
   1035 // clang-format on
   1036 
   1037 static void
   1038 app_dump_extensions(const char *indent, const char *layer_name,
   1039                     const uint32_t extension_count,
   1040                     const VkExtensionProperties *extension_properties) {
   1041     uint32_t i;
   1042     if (layer_name && (strlen(layer_name) > 0)) {
   1043         printf("%s%s Extensions", indent, layer_name);
   1044     } else {
   1045         printf("Extensions");
   1046     }
   1047     printf("\tcount = %d\n", extension_count);
   1048     for (i = 0; i < extension_count; i++) {
   1049         VkExtensionProperties const *ext_prop = &extension_properties[i];
   1050 
   1051         printf("%s\t", indent);
   1052         printf("%-32s: extension revision %2d\n", ext_prop->extensionName,
   1053                ext_prop->specVersion);
   1054     }
   1055     printf("\n");
   1056     fflush(stdout);
   1057 }
   1058 
   1059 static void app_gpu_dump_queue_props(const struct app_gpu *gpu, uint32_t id) {
   1060     const VkQueueFamilyProperties *props = &gpu->queue_props[id];
   1061 
   1062     printf("VkQueueFamilyProperties[%d]:\n", id);
   1063     printf("============================\n");
   1064     printf("\tqueueFlags         = %c%c%c\n",
   1065            (props->queueFlags & VK_QUEUE_GRAPHICS_BIT) ? 'G' : '.',
   1066            (props->queueFlags & VK_QUEUE_COMPUTE_BIT) ? 'C' : '.',
   1067            (props->queueFlags & VK_QUEUE_TRANSFER_BIT) ? 'D' : '.');
   1068     printf("\tqueueCount         = %u\n", props->queueCount);
   1069     printf("\ttimestampValidBits = %u\n", props->timestampValidBits);
   1070     printf("\tminImageTransferGranularity = (%d, %d, %d)\n",
   1071            props->minImageTransferGranularity.width,
   1072            props->minImageTransferGranularity.height,
   1073            props->minImageTransferGranularity.depth);
   1074     fflush(stdout);
   1075 }
   1076 
   1077 static void app_gpu_dump_memory_props(const struct app_gpu *gpu) {
   1078     const VkPhysicalDeviceMemoryProperties *props = &gpu->memory_props;
   1079 
   1080     printf("VkPhysicalDeviceMemoryProperties:\n");
   1081     printf("=================================\n");
   1082     printf("\tmemoryTypeCount       = %u\n", props->memoryTypeCount);
   1083     for (uint32_t i = 0; i < props->memoryTypeCount; i++) {
   1084         printf("\tmemoryTypes[%u] : \n", i);
   1085         printf("\t\tpropertyFlags = %u\n", props->memoryTypes[i].propertyFlags);
   1086         printf("\t\theapIndex     = %u\n", props->memoryTypes[i].heapIndex);
   1087     }
   1088     printf("\tmemoryHeapCount       = %u\n", props->memoryHeapCount);
   1089     for (uint32_t i = 0; i < props->memoryHeapCount; i++) {
   1090         printf("\tmemoryHeaps[%u] : \n", i);
   1091         printf("\t\tsize          = " PRINTF_SIZE_T_SPECIFIER "\n",
   1092                (size_t)props->memoryHeaps[i].size);
   1093     }
   1094     fflush(stdout);
   1095 }
   1096 
   1097 static void app_gpu_dump(const struct app_gpu *gpu) {
   1098     uint32_t i;
   1099 
   1100     printf("Device Extensions and layers:\n");
   1101     printf("=============================\n");
   1102     printf("GPU%u\n", gpu->id);
   1103     app_gpu_dump_props(gpu);
   1104     printf("\n");
   1105     app_dump_extensions("", "Device", gpu->device_extension_count,
   1106                         gpu->device_extensions);
   1107     printf("\n");
   1108     printf("Layers\tcount = %d\n", gpu->device_layer_count);
   1109     for (uint32_t i = 0; i < gpu->device_layer_count; i++) {
   1110         uint32_t major, minor, patch;
   1111         char spec_version[64], layer_version[64];
   1112         struct layer_extension_list const *layer_info = &gpu->device_layers[i];
   1113 
   1114         extract_version(layer_info->layer_properties.specVersion, &major,
   1115                         &minor, &patch);
   1116         snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", major, minor,
   1117                  patch);
   1118         snprintf(layer_version, sizeof(layer_version), "%d",
   1119                  layer_info->layer_properties.implementationVersion);
   1120         printf("\t%s (%s) Vulkan version %s, layer version %s\n",
   1121                layer_info->layer_properties.layerName,
   1122                (char *)layer_info->layer_properties.description, spec_version,
   1123                layer_version);
   1124 
   1125         app_dump_extensions("\t", layer_info->layer_properties.layerName,
   1126                             layer_info->extension_count,
   1127                             layer_info->extension_properties);
   1128         fflush(stdout);
   1129     }
   1130     printf("\n");
   1131     for (i = 0; i < gpu->queue_count; i++) {
   1132         app_gpu_dump_queue_props(gpu, i);
   1133         printf("\n");
   1134     }
   1135     app_gpu_dump_memory_props(gpu);
   1136     printf("\n");
   1137     app_gpu_dump_features(gpu);
   1138     printf("\n");
   1139     app_dev_dump(&gpu->dev);
   1140 }
   1141 
   1142 #ifdef _WIN32
   1143 // Enlarges the console window to have a large scrollback size.
   1144 static void ConsoleEnlarge() {
   1145     HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);
   1146 
   1147     // make the console window bigger
   1148     CONSOLE_SCREEN_BUFFER_INFO csbi;
   1149     COORD bufferSize;
   1150     if (GetConsoleScreenBufferInfo(consoleHandle, &csbi))
   1151     {
   1152         bufferSize.X = csbi.dwSize.X + 30;
   1153         bufferSize.Y = 20000;
   1154         SetConsoleScreenBufferSize(consoleHandle, bufferSize);
   1155     }
   1156 
   1157     SMALL_RECT r;
   1158     r.Left = r.Top = 0;
   1159     r.Right = csbi.dwSize.X - 1 + 30;
   1160     r.Bottom = 50;
   1161     SetConsoleWindowInfo(consoleHandle, true, &r);
   1162 
   1163     // change the console window title
   1164     SetConsoleTitle(TEXT(APP_SHORT_NAME));
   1165 }
   1166 #endif
   1167 
   1168 int main(int argc, char **argv) {
   1169     unsigned int major, minor, patch;
   1170     struct app_gpu gpus[MAX_GPUS];
   1171     VkPhysicalDevice objs[MAX_GPUS];
   1172     uint32_t gpu_count, i;
   1173     VkResult err;
   1174     struct app_instance inst;
   1175 
   1176 #ifdef _WIN32
   1177     if (ConsoleIsExclusive())
   1178         ConsoleEnlarge();
   1179 #endif
   1180 
   1181     major = VK_API_VERSION_1_0 >> 22;
   1182     minor = (VK_API_VERSION_1_0 >> 12) & 0x3ff;
   1183     patch = VK_HEADER_VERSION & 0xfff;
   1184     printf("===========\n");
   1185     printf("VULKAN INFO\n");
   1186     printf("===========\n\n");
   1187     printf("Vulkan API Version: %d.%d.%d\n\n", major, minor, patch);
   1188 
   1189     app_create_instance(&inst);
   1190 
   1191     printf("Instance Extensions and layers:\n");
   1192     printf("===============================\n");
   1193     app_dump_extensions("", "Instance", inst.global_extension_count,
   1194                         inst.global_extensions);
   1195 
   1196     printf("Instance Layers\tcount = %d\n", inst.global_layer_count);
   1197     for (uint32_t i = 0; i < inst.global_layer_count; i++) {
   1198         uint32_t major, minor, patch;
   1199         char spec_version[64], layer_version[64];
   1200         VkLayerProperties const *layer_prop =
   1201             &inst.global_layers[i].layer_properties;
   1202 
   1203         extract_version(layer_prop->specVersion, &major, &minor, &patch);
   1204         snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", major, minor,
   1205                  patch);
   1206         snprintf(layer_version, sizeof(layer_version), "%d",
   1207                  layer_prop->implementationVersion);
   1208         printf("\t%s (%s) Vulkan version %s, layer version %s\n",
   1209                layer_prop->layerName, (char *)layer_prop->description,
   1210                spec_version, layer_version);
   1211 
   1212         app_dump_extensions("\t",
   1213                             inst.global_layers[i].layer_properties.layerName,
   1214                             inst.global_layers[i].extension_count,
   1215                             inst.global_layers[i].extension_properties);
   1216     }
   1217 
   1218     err = vkEnumeratePhysicalDevices(inst.instance, &gpu_count, NULL);
   1219     if (err)
   1220         ERR_EXIT(err);
   1221     if (gpu_count > MAX_GPUS) {
   1222         printf("Too many GPUS found \n");
   1223         ERR_EXIT(-1);
   1224     }
   1225     err = vkEnumeratePhysicalDevices(inst.instance, &gpu_count, objs);
   1226     if (err)
   1227         ERR_EXIT(err);
   1228 
   1229     for (i = 0; i < gpu_count; i++) {
   1230         app_gpu_init(&gpus[i], i, objs[i]);
   1231         app_gpu_dump(&gpus[i]);
   1232         printf("\n\n");
   1233     }
   1234 
   1235     for (i = 0; i < gpu_count; i++)
   1236         app_gpu_destroy(&gpus[i]);
   1237 
   1238     app_destroy_instance(&inst);
   1239 
   1240     fflush(stdout);
   1241 #ifdef _WIN32
   1242     if (ConsoleIsExclusive())
   1243         Sleep(INFINITE);
   1244 #endif
   1245 
   1246     return 0;
   1247 }
   1248