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  * Licensed under the Apache License, Version 2.0 (the "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *     http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  *
     18  * Author: Courtney Goeltzenleuchter <courtney (at) LunarG.com>
     19  * Author: David Pinedo <david (at) lunarg.com>
     20  * Author: Mark Lobodzinski <mark (at) lunarg.com>
     21  * Author: Rene Lindsay <rene (at) lunarg.com>
     22  * Author: Jeremy Kniager <jeremyk (at) lunarg.com>
     23  * Author: Shannon McPherson <shannon (at) lunarg.com>
     24  */
     25 
     26 #ifdef __GNUC__
     27 #ifndef _POSIX_C_SOURCE
     28 #define _POSIX_C_SOURCE 200809L
     29 #endif
     30 #else
     31 #define strndup(p, n) strdup(p)
     32 #endif
     33 
     34 #include <assert.h>
     35 #include <inttypes.h>
     36 #include <stdbool.h>
     37 #include <stdio.h>
     38 #include <stdlib.h>
     39 #include <string.h>
     40 
     41 #ifdef _WIN32
     42 #include <fcntl.h>
     43 #include <io.h>
     44 #endif  // _WIN32
     45 
     46 #if defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_XCB_KHR)
     47 #include <X11/Xutil.h>
     48 #endif
     49 
     50 #if defined(VK_USE_PLATFORM_MIR_KHR)
     51 #warning "Vulkaninfo does not have code for Mir at this time"
     52 #endif
     53 
     54 #include <vulkan/vulkan.h>
     55 
     56 #define ERR(err) printf("%s:%d: failed with %s\n", __FILE__, __LINE__, VkResultString(err));
     57 
     58 #ifdef _WIN32
     59 
     60 #define snprintf _snprintf
     61 #define strdup _strdup
     62 
     63 // Returns nonzero if the console is used only for this process. Will return
     64 // zero if another process (such as cmd.exe) is also attached.
     65 static int ConsoleIsExclusive(void) {
     66     DWORD pids[2];
     67     DWORD num_pids = GetConsoleProcessList(pids, ARRAYSIZE(pids));
     68     return num_pids <= 1;
     69 }
     70 
     71 #define WAIT_FOR_CONSOLE_DESTROY                   \
     72     do {                                           \
     73         if (ConsoleIsExclusive()) Sleep(INFINITE); \
     74     } while (0)
     75 #else
     76 #define WAIT_FOR_CONSOLE_DESTROY
     77 #endif
     78 
     79 #define ERR_EXIT(err)             \
     80     do {                          \
     81         ERR(err);                 \
     82         fflush(stdout);           \
     83         WAIT_FOR_CONSOLE_DESTROY; \
     84         exit(-1);                 \
     85     } while (0)
     86 
     87 #if defined(NDEBUG) && defined(__GNUC__)
     88 #define U_ASSERT_ONLY __attribute__((unused))
     89 #else
     90 #define U_ASSERT_ONLY
     91 #endif
     92 
     93 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
     94 
     95 #define MAX_QUEUE_TYPES 5
     96 #define APP_SHORT_NAME "vulkaninfo"
     97 
     98 static bool html_output;
     99 
    100 struct VkStructureHeader {
    101     VkStructureType sType;
    102     void *pNext;
    103 };
    104 
    105 struct AppGpu;
    106 
    107 struct AppDev {
    108     struct AppGpu *gpu; /* point back to the GPU */
    109 
    110     VkDevice obj;
    111 
    112     VkFormatProperties format_props[VK_FORMAT_RANGE_SIZE];
    113     VkFormatProperties2KHR format_props2[VK_FORMAT_RANGE_SIZE];
    114 };
    115 
    116 struct LayerExtensionList {
    117     VkLayerProperties layer_properties;
    118     uint32_t extension_count;
    119     VkExtensionProperties *extension_properties;
    120 };
    121 
    122 struct AppInstance {
    123     VkInstance instance;
    124     uint32_t global_layer_count;
    125     struct LayerExtensionList *global_layers;
    126     uint32_t global_extension_count;
    127     VkExtensionProperties *global_extensions;  // Instance Extensions
    128 
    129     const char **inst_extensions;
    130     uint32_t inst_extensions_count;
    131 
    132     PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR;
    133     PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
    134     PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR;
    135     PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR;
    136     PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR;
    137     PFN_vkGetPhysicalDeviceFormatProperties2KHR vkGetPhysicalDeviceFormatProperties2KHR;
    138     PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR vkGetPhysicalDeviceQueueFamilyProperties2KHR;
    139     PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR;
    140     PFN_vkGetPhysicalDeviceMemoryProperties2KHR vkGetPhysicalDeviceMemoryProperties2KHR;
    141     PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR;
    142     PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT vkGetPhysicalDeviceSurfaceCapabilities2EXT;
    143 
    144     VkSurfaceCapabilitiesKHR surface_capabilities;
    145     VkSurfaceCapabilities2KHR surface_capabilities2;
    146     VkSharedPresentSurfaceCapabilitiesKHR shared_surface_capabilities;
    147     VkSurfaceCapabilities2EXT surface_capabilities2_ext;
    148 
    149     VkSurfaceKHR surface;
    150     int width, height;
    151 
    152 #ifdef VK_USE_PLATFORM_WIN32_KHR
    153     HINSTANCE h_instance;  // Windows Instance
    154     HWND h_wnd;            // window handle
    155 #elif VK_USE_PLATFORM_XCB_KHR
    156     xcb_connection_t *xcb_connection;
    157     xcb_screen_t *xcb_screen;
    158     xcb_window_t xcb_window;
    159 #elif VK_USE_PLATFORM_XLIB_KHR
    160     Display *xlib_display;
    161     Window xlib_window;
    162 #elif VK_USE_PLATFORM_ANDROID_KHR  // TODO
    163     ANativeWindow *window;
    164 #endif
    165 };
    166 
    167 struct AppGpu {
    168     uint32_t id;
    169     VkPhysicalDevice obj;
    170 
    171     VkPhysicalDeviceProperties props;
    172     VkPhysicalDeviceProperties2KHR props2;
    173 
    174     uint32_t queue_count;
    175     VkQueueFamilyProperties *queue_props;
    176     VkQueueFamilyProperties2KHR *queue_props2;
    177     VkDeviceQueueCreateInfo *queue_reqs;
    178 
    179     struct AppInstance *inst;
    180 
    181     VkPhysicalDeviceMemoryProperties memory_props;
    182     VkPhysicalDeviceMemoryProperties2KHR memory_props2;
    183 
    184     VkPhysicalDeviceFeatures features;
    185     VkPhysicalDeviceFeatures2KHR features2;
    186     VkPhysicalDevice limits;
    187 
    188     uint32_t device_extension_count;
    189     VkExtensionProperties *device_extensions;
    190 
    191     struct AppDev dev;
    192 };
    193 
    194 static VKAPI_ATTR VkBool32 VKAPI_CALL DbgCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject,
    195                                                   size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg,
    196                                                   void *pUserData) {
    197     char *message = (char *)malloc(strlen(pMsg) + 100);
    198 
    199     assert(message);
    200 
    201     if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
    202         sprintf(message, "ERROR: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
    203     } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
    204         sprintf(message, "WARNING: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
    205     } else if (msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
    206         sprintf(message, "INFO: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
    207     } else if (msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
    208         sprintf(message, "DEBUG: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
    209     }
    210 
    211     printf("%s\n", message);
    212     fflush(stdout);
    213     free(message);
    214 
    215     /*
    216      * false indicates that layer should not bail-out of an
    217      * API call that had validation failures. This may mean that the
    218      * app dies inside the driver due to invalid parameter(s).
    219      * That's what would happen without validation layers, so we'll
    220      * keep that behavior here.
    221      */
    222     return false;
    223 }
    224 
    225 static const char *VkResultString(VkResult err) {
    226     switch (err) {
    227 #define STR(r) \
    228     case r:    \
    229         return #r
    230         STR(VK_SUCCESS);
    231         STR(VK_NOT_READY);
    232         STR(VK_TIMEOUT);
    233         STR(VK_EVENT_SET);
    234         STR(VK_EVENT_RESET);
    235         STR(VK_ERROR_INITIALIZATION_FAILED);
    236         STR(VK_ERROR_OUT_OF_HOST_MEMORY);
    237         STR(VK_ERROR_OUT_OF_DEVICE_MEMORY);
    238         STR(VK_ERROR_DEVICE_LOST);
    239         STR(VK_ERROR_LAYER_NOT_PRESENT);
    240         STR(VK_ERROR_EXTENSION_NOT_PRESENT);
    241         STR(VK_ERROR_MEMORY_MAP_FAILED);
    242         STR(VK_ERROR_INCOMPATIBLE_DRIVER);
    243 #undef STR
    244         default:
    245             return "UNKNOWN_RESULT";
    246     }
    247 }
    248 
    249 static const char *VkPhysicalDeviceTypeString(VkPhysicalDeviceType type) {
    250     switch (type) {
    251 #define STR(r)                        \
    252     case VK_PHYSICAL_DEVICE_TYPE_##r: \
    253         return #r
    254         STR(OTHER);
    255         STR(INTEGRATED_GPU);
    256         STR(DISCRETE_GPU);
    257         STR(VIRTUAL_GPU);
    258         STR(CPU);
    259 #undef STR
    260         default:
    261             return "UNKNOWN_DEVICE";
    262     }
    263 }
    264 
    265 static const char *VkFormatString(VkFormat fmt) {
    266     switch (fmt) {
    267 #define STR(r)          \
    268     case VK_FORMAT_##r: \
    269         return #r
    270         STR(UNDEFINED);
    271         STR(R4G4_UNORM_PACK8);
    272         STR(R4G4B4A4_UNORM_PACK16);
    273         STR(B4G4R4A4_UNORM_PACK16);
    274         STR(R5G6B5_UNORM_PACK16);
    275         STR(B5G6R5_UNORM_PACK16);
    276         STR(R5G5B5A1_UNORM_PACK16);
    277         STR(B5G5R5A1_UNORM_PACK16);
    278         STR(A1R5G5B5_UNORM_PACK16);
    279         STR(R8_UNORM);
    280         STR(R8_SNORM);
    281         STR(R8_USCALED);
    282         STR(R8_SSCALED);
    283         STR(R8_UINT);
    284         STR(R8_SINT);
    285         STR(R8_SRGB);
    286         STR(R8G8_UNORM);
    287         STR(R8G8_SNORM);
    288         STR(R8G8_USCALED);
    289         STR(R8G8_SSCALED);
    290         STR(R8G8_UINT);
    291         STR(R8G8_SINT);
    292         STR(R8G8_SRGB);
    293         STR(R8G8B8_UNORM);
    294         STR(R8G8B8_SNORM);
    295         STR(R8G8B8_USCALED);
    296         STR(R8G8B8_SSCALED);
    297         STR(R8G8B8_UINT);
    298         STR(R8G8B8_SINT);
    299         STR(R8G8B8_SRGB);
    300         STR(B8G8R8_UNORM);
    301         STR(B8G8R8_SNORM);
    302         STR(B8G8R8_USCALED);
    303         STR(B8G8R8_SSCALED);
    304         STR(B8G8R8_UINT);
    305         STR(B8G8R8_SINT);
    306         STR(B8G8R8_SRGB);
    307         STR(R8G8B8A8_UNORM);
    308         STR(R8G8B8A8_SNORM);
    309         STR(R8G8B8A8_USCALED);
    310         STR(R8G8B8A8_SSCALED);
    311         STR(R8G8B8A8_UINT);
    312         STR(R8G8B8A8_SINT);
    313         STR(R8G8B8A8_SRGB);
    314         STR(B8G8R8A8_UNORM);
    315         STR(B8G8R8A8_SNORM);
    316         STR(B8G8R8A8_USCALED);
    317         STR(B8G8R8A8_SSCALED);
    318         STR(B8G8R8A8_UINT);
    319         STR(B8G8R8A8_SINT);
    320         STR(B8G8R8A8_SRGB);
    321         STR(A8B8G8R8_UNORM_PACK32);
    322         STR(A8B8G8R8_SNORM_PACK32);
    323         STR(A8B8G8R8_USCALED_PACK32);
    324         STR(A8B8G8R8_SSCALED_PACK32);
    325         STR(A8B8G8R8_UINT_PACK32);
    326         STR(A8B8G8R8_SINT_PACK32);
    327         STR(A8B8G8R8_SRGB_PACK32);
    328         STR(A2R10G10B10_UNORM_PACK32);
    329         STR(A2R10G10B10_SNORM_PACK32);
    330         STR(A2R10G10B10_USCALED_PACK32);
    331         STR(A2R10G10B10_SSCALED_PACK32);
    332         STR(A2R10G10B10_UINT_PACK32);
    333         STR(A2R10G10B10_SINT_PACK32);
    334         STR(A2B10G10R10_UNORM_PACK32);
    335         STR(A2B10G10R10_SNORM_PACK32);
    336         STR(A2B10G10R10_USCALED_PACK32);
    337         STR(A2B10G10R10_SSCALED_PACK32);
    338         STR(A2B10G10R10_UINT_PACK32);
    339         STR(A2B10G10R10_SINT_PACK32);
    340         STR(R16_UNORM);
    341         STR(R16_SNORM);
    342         STR(R16_USCALED);
    343         STR(R16_SSCALED);
    344         STR(R16_UINT);
    345         STR(R16_SINT);
    346         STR(R16_SFLOAT);
    347         STR(R16G16_UNORM);
    348         STR(R16G16_SNORM);
    349         STR(R16G16_USCALED);
    350         STR(R16G16_SSCALED);
    351         STR(R16G16_UINT);
    352         STR(R16G16_SINT);
    353         STR(R16G16_SFLOAT);
    354         STR(R16G16B16_UNORM);
    355         STR(R16G16B16_SNORM);
    356         STR(R16G16B16_USCALED);
    357         STR(R16G16B16_SSCALED);
    358         STR(R16G16B16_UINT);
    359         STR(R16G16B16_SINT);
    360         STR(R16G16B16_SFLOAT);
    361         STR(R16G16B16A16_UNORM);
    362         STR(R16G16B16A16_SNORM);
    363         STR(R16G16B16A16_USCALED);
    364         STR(R16G16B16A16_SSCALED);
    365         STR(R16G16B16A16_UINT);
    366         STR(R16G16B16A16_SINT);
    367         STR(R16G16B16A16_SFLOAT);
    368         STR(R32_UINT);
    369         STR(R32_SINT);
    370         STR(R32_SFLOAT);
    371         STR(R32G32_UINT);
    372         STR(R32G32_SINT);
    373         STR(R32G32_SFLOAT);
    374         STR(R32G32B32_UINT);
    375         STR(R32G32B32_SINT);
    376         STR(R32G32B32_SFLOAT);
    377         STR(R32G32B32A32_UINT);
    378         STR(R32G32B32A32_SINT);
    379         STR(R32G32B32A32_SFLOAT);
    380         STR(R64_UINT);
    381         STR(R64_SINT);
    382         STR(R64_SFLOAT);
    383         STR(R64G64_UINT);
    384         STR(R64G64_SINT);
    385         STR(R64G64_SFLOAT);
    386         STR(R64G64B64_UINT);
    387         STR(R64G64B64_SINT);
    388         STR(R64G64B64_SFLOAT);
    389         STR(R64G64B64A64_UINT);
    390         STR(R64G64B64A64_SINT);
    391         STR(R64G64B64A64_SFLOAT);
    392         STR(B10G11R11_UFLOAT_PACK32);
    393         STR(E5B9G9R9_UFLOAT_PACK32);
    394         STR(D16_UNORM);
    395         STR(X8_D24_UNORM_PACK32);
    396         STR(D32_SFLOAT);
    397         STR(S8_UINT);
    398         STR(D16_UNORM_S8_UINT);
    399         STR(D24_UNORM_S8_UINT);
    400         STR(D32_SFLOAT_S8_UINT);
    401         STR(BC1_RGB_UNORM_BLOCK);
    402         STR(BC1_RGB_SRGB_BLOCK);
    403         STR(BC1_RGBA_UNORM_BLOCK);
    404         STR(BC1_RGBA_SRGB_BLOCK);
    405         STR(BC2_UNORM_BLOCK);
    406         STR(BC2_SRGB_BLOCK);
    407         STR(BC3_UNORM_BLOCK);
    408         STR(BC3_SRGB_BLOCK);
    409         STR(BC4_UNORM_BLOCK);
    410         STR(BC4_SNORM_BLOCK);
    411         STR(BC5_UNORM_BLOCK);
    412         STR(BC5_SNORM_BLOCK);
    413         STR(BC6H_UFLOAT_BLOCK);
    414         STR(BC6H_SFLOAT_BLOCK);
    415         STR(BC7_UNORM_BLOCK);
    416         STR(BC7_SRGB_BLOCK);
    417         STR(ETC2_R8G8B8_UNORM_BLOCK);
    418         STR(ETC2_R8G8B8_SRGB_BLOCK);
    419         STR(ETC2_R8G8B8A1_UNORM_BLOCK);
    420         STR(ETC2_R8G8B8A1_SRGB_BLOCK);
    421         STR(ETC2_R8G8B8A8_UNORM_BLOCK);
    422         STR(ETC2_R8G8B8A8_SRGB_BLOCK);
    423         STR(EAC_R11_UNORM_BLOCK);
    424         STR(EAC_R11_SNORM_BLOCK);
    425         STR(EAC_R11G11_UNORM_BLOCK);
    426         STR(EAC_R11G11_SNORM_BLOCK);
    427         STR(ASTC_4x4_UNORM_BLOCK);
    428         STR(ASTC_4x4_SRGB_BLOCK);
    429         STR(ASTC_5x4_UNORM_BLOCK);
    430         STR(ASTC_5x4_SRGB_BLOCK);
    431         STR(ASTC_5x5_UNORM_BLOCK);
    432         STR(ASTC_5x5_SRGB_BLOCK);
    433         STR(ASTC_6x5_UNORM_BLOCK);
    434         STR(ASTC_6x5_SRGB_BLOCK);
    435         STR(ASTC_6x6_UNORM_BLOCK);
    436         STR(ASTC_6x6_SRGB_BLOCK);
    437         STR(ASTC_8x5_UNORM_BLOCK);
    438         STR(ASTC_8x5_SRGB_BLOCK);
    439         STR(ASTC_8x6_UNORM_BLOCK);
    440         STR(ASTC_8x6_SRGB_BLOCK);
    441         STR(ASTC_8x8_UNORM_BLOCK);
    442         STR(ASTC_8x8_SRGB_BLOCK);
    443         STR(ASTC_10x5_UNORM_BLOCK);
    444         STR(ASTC_10x5_SRGB_BLOCK);
    445         STR(ASTC_10x6_UNORM_BLOCK);
    446         STR(ASTC_10x6_SRGB_BLOCK);
    447         STR(ASTC_10x8_UNORM_BLOCK);
    448         STR(ASTC_10x8_SRGB_BLOCK);
    449         STR(ASTC_10x10_UNORM_BLOCK);
    450         STR(ASTC_10x10_SRGB_BLOCK);
    451         STR(ASTC_12x10_UNORM_BLOCK);
    452         STR(ASTC_12x10_SRGB_BLOCK);
    453         STR(ASTC_12x12_UNORM_BLOCK);
    454         STR(ASTC_12x12_SRGB_BLOCK);
    455 #undef STR
    456         default:
    457             return "UNKNOWN_FORMAT";
    458     }
    459 }
    460 #if defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR)
    461 static const char *VkPresentModeString(VkPresentModeKHR mode) {
    462     switch (mode) {
    463 #define STR(r)                \
    464     case VK_PRESENT_MODE_##r: \
    465         return #r
    466         STR(IMMEDIATE_KHR);
    467         STR(MAILBOX_KHR);
    468         STR(FIFO_KHR);
    469         STR(FIFO_RELAXED_KHR);
    470 #undef STR
    471         default:
    472             return "UNKNOWN_FORMAT";
    473     }
    474 }
    475 #endif
    476 
    477 static bool CheckExtensionEnabled(const char *extension_to_check, const char **extension_list, uint32_t extension_count) {
    478     for (uint32_t i = 0; i < extension_count; i++) {
    479         if (!strcmp(extension_to_check, extension_list[i])) return true;
    480     }
    481     return false;
    482 }
    483 
    484 static void AppDevInitFormats(struct AppDev *dev) {
    485     VkFormat f;
    486     for (f = 0; f < VK_FORMAT_RANGE_SIZE; f++) {
    487         const VkFormat fmt = f;
    488         vkGetPhysicalDeviceFormatProperties(dev->gpu->obj, fmt, &dev->format_props[f]);
    489 
    490         if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, dev->gpu->inst->inst_extensions,
    491                                   dev->gpu->inst->inst_extensions_count)) {
    492             dev->format_props2[f].sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR;
    493             dev->format_props2[f].pNext = NULL;
    494             dev->gpu->inst->vkGetPhysicalDeviceFormatProperties2KHR(dev->gpu->obj, fmt, &dev->format_props2[f]);
    495         }
    496     }
    497 }
    498 
    499 static void ExtractVersion(uint32_t version, uint32_t *major, uint32_t *minor, uint32_t *patch) {
    500     *major = version >> 22;
    501     *minor = (version >> 12) & 0x3ff;
    502     *patch = version & 0xfff;
    503 }
    504 
    505 static void AppGetPhysicalDeviceLayerExtensions(struct AppGpu *gpu, char *layer_name, uint32_t *extension_count,
    506                                                 VkExtensionProperties **extension_properties) {
    507     VkResult err;
    508     uint32_t ext_count = 0;
    509     VkExtensionProperties *ext_ptr = NULL;
    510 
    511     /* repeat get until VK_INCOMPLETE goes away */
    512     do {
    513         err = vkEnumerateDeviceExtensionProperties(gpu->obj, layer_name, &ext_count, NULL);
    514         assert(!err);
    515 
    516         if (ext_ptr) {
    517             free(ext_ptr);
    518         }
    519         ext_ptr = malloc(ext_count * sizeof(VkExtensionProperties));
    520         err = vkEnumerateDeviceExtensionProperties(gpu->obj, layer_name, &ext_count, ext_ptr);
    521     } while (err == VK_INCOMPLETE);
    522     assert(!err);
    523 
    524     *extension_count = ext_count;
    525     *extension_properties = ext_ptr;
    526 }
    527 
    528 static void AppDevInit(struct AppDev *dev, struct AppGpu *gpu) {
    529     VkDeviceCreateInfo info = {
    530         .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
    531         .pNext = NULL,
    532         .flags = 0,
    533         .queueCreateInfoCount = 0,
    534         .pQueueCreateInfos = NULL,
    535         .enabledLayerCount = 0,
    536         .ppEnabledLayerNames = NULL,
    537         .enabledExtensionCount = 0,
    538         .ppEnabledExtensionNames = NULL,
    539     };
    540     VkResult U_ASSERT_ONLY err;
    541 
    542     // Device extensions
    543     AppGetPhysicalDeviceLayerExtensions(gpu, NULL, &gpu->device_extension_count, &gpu->device_extensions);
    544 
    545     fflush(stdout);
    546 
    547     /* request all queues */
    548     info.queueCreateInfoCount = gpu->queue_count;
    549     info.pQueueCreateInfos = gpu->queue_reqs;
    550 
    551     info.enabledLayerCount = 0;
    552     info.ppEnabledLayerNames = NULL;
    553     info.enabledExtensionCount = 0;
    554     info.ppEnabledExtensionNames = NULL;
    555     dev->gpu = gpu;
    556     err = vkCreateDevice(gpu->obj, &info, NULL, &dev->obj);
    557     if (err) ERR_EXIT(err);
    558 }
    559 
    560 static void AppDevDestroy(struct AppDev *dev) {
    561     vkDeviceWaitIdle(dev->obj);
    562     vkDestroyDevice(dev->obj, NULL);
    563 }
    564 
    565 static void AppGetGlobalLayerExtensions(char *layer_name, uint32_t *extension_count, VkExtensionProperties **extension_properties) {
    566     VkResult err;
    567     uint32_t ext_count = 0;
    568     VkExtensionProperties *ext_ptr = NULL;
    569 
    570     /* repeat get until VK_INCOMPLETE goes away */
    571     do {
    572         // gets the extension count if the last parameter is NULL
    573         err = vkEnumerateInstanceExtensionProperties(layer_name, &ext_count, NULL);
    574         assert(!err);
    575 
    576         if (ext_ptr) {
    577             free(ext_ptr);
    578         }
    579         ext_ptr = malloc(ext_count * sizeof(VkExtensionProperties));
    580         // gets the extension properties if the last parameter is not NULL
    581         err = vkEnumerateInstanceExtensionProperties(layer_name, &ext_count, ext_ptr);
    582     } while (err == VK_INCOMPLETE);
    583     assert(!err);
    584     *extension_count = ext_count;
    585     *extension_properties = ext_ptr;
    586 }
    587 
    588 /* Gets a list of layer and instance extensions */
    589 static void AppGetInstanceExtensions(struct AppInstance *inst) {
    590     VkResult U_ASSERT_ONLY err;
    591 
    592     uint32_t count = 0;
    593 
    594     /* Scan layers */
    595     VkLayerProperties *global_layer_properties = NULL;
    596     struct LayerExtensionList *global_layers = NULL;
    597 
    598     do {
    599         err = vkEnumerateInstanceLayerProperties(&count, NULL);
    600         assert(!err);
    601 
    602         if (global_layer_properties) {
    603             free(global_layer_properties);
    604         }
    605         global_layer_properties = malloc(sizeof(VkLayerProperties) * count);
    606         assert(global_layer_properties);
    607 
    608         if (global_layers) {
    609             free(global_layers);
    610         }
    611         global_layers = malloc(sizeof(struct LayerExtensionList) * count);
    612         assert(global_layers);
    613 
    614         err = vkEnumerateInstanceLayerProperties(&count, global_layer_properties);
    615     } while (err == VK_INCOMPLETE);
    616     assert(!err);
    617 
    618     inst->global_layer_count = count;
    619     inst->global_layers = global_layers;
    620 
    621     for (uint32_t i = 0; i < inst->global_layer_count; i++) {
    622         VkLayerProperties *src_info = &global_layer_properties[i];
    623         struct LayerExtensionList *dst_info = &inst->global_layers[i];
    624         memcpy(&dst_info->layer_properties, src_info, sizeof(VkLayerProperties));
    625 
    626         // Save away layer extension info for report
    627         // Gets layer extensions, if first parameter is not NULL
    628         AppGetGlobalLayerExtensions(src_info->layerName, &dst_info->extension_count, &dst_info->extension_properties);
    629     }
    630     free(global_layer_properties);
    631 
    632     // Collect global extensions
    633     inst->global_extension_count = 0;
    634     // Gets instance extensions, if no layer was specified in the first
    635     // paramteter
    636     AppGetGlobalLayerExtensions(NULL, &inst->global_extension_count, &inst->global_extensions);
    637 }
    638 
    639 // Prints opening CSS and HTML code for html output file
    640 // Defines various div text styles
    641 void PrintHtmlHeader(FILE *out) {
    642     fprintf(out, "<!doctype html>\n");
    643     fprintf(out, "<html>\n");
    644     fprintf(out, "\t<head>\n");
    645     fprintf(out, "\t\t<title>Vulkan Info</title>\n");
    646     fprintf(out, "\t\t<style type='text/css'>\n");
    647     fprintf(out, "\t\thtml {\n");
    648     fprintf(out, "\t\t\tbackground-color: #0b1e48;\n");
    649     fprintf(out, "\t\t\tbackground-image: url(\"https://vulkan.lunarg.com/img/bg-starfield.jpg\");\n");
    650     fprintf(out, "\t\t\tbackground-position: center;\n");
    651     fprintf(out, "\t\t\t-webkit-background-size: cover;\n");
    652     fprintf(out, "\t\t\t-moz-background-size: cover;\n");
    653     fprintf(out, "\t\t\t-o-background-size: cover;\n");
    654     fprintf(out, "\t\t\tbackground-size: cover;\n");
    655     fprintf(out, "\t\t\tbackground-attachment: fixed;\n");
    656     fprintf(out, "\t\t\tbackground-repeat: no-repeat;\n");
    657     fprintf(out, "\t\t\theight: 100%%;\n");
    658     fprintf(out, "\t\t}\n");
    659     fprintf(out, "\t\t#header {\n");
    660     fprintf(out, "\t\t\tz-index: -1;\n");
    661     fprintf(out, "\t\t}\n");
    662     fprintf(out, "\t\t#header>img {\n");
    663     fprintf(out, "\t\t\tposition: absolute;\n");
    664     fprintf(out, "\t\t\twidth: 160px;\n");
    665     fprintf(out, "\t\t\tmargin-left: -280px;\n");
    666     fprintf(out, "\t\t\ttop: -10px;\n");
    667     fprintf(out, "\t\t\tleft: 50%%;\n");
    668     fprintf(out, "\t\t}\n");
    669     fprintf(out, "\t\t#header>h1 {\n");
    670     fprintf(out, "\t\t\tfont-family: Arial, \"Helvetica Neue\", Helvetica, sans-serif;\n");
    671     fprintf(out, "\t\t\tfont-size: 44px;\n");
    672     fprintf(out, "\t\t\tfont-weight: 200;\n");
    673     fprintf(out, "\t\t\ttext-shadow: 4px 4px 5px #000;\n");
    674     fprintf(out, "\t\t\tcolor: #eee;\n");
    675     fprintf(out, "\t\t\tposition: absolute;\n");
    676     fprintf(out, "\t\t\twidth: 400px;\n");
    677     fprintf(out, "\t\t\tmargin-left: -80px;\n");
    678     fprintf(out, "\t\t\ttop: 8px;\n");
    679     fprintf(out, "\t\t\tleft: 50%%;\n");
    680     fprintf(out, "\t\t}\n");
    681     fprintf(out, "\t\tbody {\n");
    682     fprintf(out, "\t\t\tfont-family: Consolas, monaco, monospace;\n");
    683     fprintf(out, "\t\t\tfont-size: 14px;\n");
    684     fprintf(out, "\t\t\tline-height: 20px;\n");
    685     fprintf(out, "\t\t\tcolor: #eee;\n");
    686     fprintf(out, "\t\t\theight: 100%%;\n");
    687     fprintf(out, "\t\t\tmargin: 0;\n");
    688     fprintf(out, "\t\t\toverflow: hidden;\n");
    689     fprintf(out, "\t\t}\n");
    690     fprintf(out, "\t\t#wrapper {\n");
    691     fprintf(out, "\t\t\tbackground-color: rgba(0, 0, 0, 0.7);\n");
    692     fprintf(out, "\t\t\tborder: 1px solid #446;\n");
    693     fprintf(out, "\t\t\tbox-shadow: 0px 0px 10px #000;\n");
    694     fprintf(out, "\t\t\tpadding: 8px 12px;\n\n");
    695     fprintf(out, "\t\t\tdisplay: inline-block;\n");
    696     fprintf(out, "\t\t\tposition: absolute;\n");
    697     fprintf(out, "\t\t\ttop: 80px;\n");
    698     fprintf(out, "\t\t\tbottom: 25px;\n");
    699     fprintf(out, "\t\t\tleft: 50px;\n");
    700     fprintf(out, "\t\t\tright: 50px;\n");
    701     fprintf(out, "\t\t\toverflow: auto;\n");
    702     fprintf(out, "\t\t}\n");
    703     fprintf(out, "\t\tdetails>details {\n");
    704     fprintf(out, "\t\t\tmargin-left: 22px;\n");
    705     fprintf(out, "\t\t}\n");
    706     fprintf(out, "\t\tdetails>summary:only-child::-webkit-details-marker {\n");
    707     fprintf(out, "\t\t\tdisplay: none;\n");
    708     fprintf(out, "\t\t}\n");
    709     fprintf(out, "\t\t.var, .type, .val {\n");
    710     fprintf(out, "\t\t\tdisplay: inline;\n");
    711     fprintf(out, "\t\t}\n");
    712     fprintf(out, "\t\t.var {\n");
    713     fprintf(out, "\t\t}\n");
    714     fprintf(out, "\t\t.type {\n");
    715     fprintf(out, "\t\t\tcolor: #acf;\n");
    716     fprintf(out, "\t\t\tmargin: 0 12px;\n");
    717     fprintf(out, "\t\t}\n");
    718     fprintf(out, "\t\t.val {\n");
    719     fprintf(out, "\t\t\tcolor: #afa;\n");
    720     fprintf(out, "\t\t\tbackground: #222;\n");
    721     fprintf(out, "\t\t\ttext-align: right;\n");
    722     fprintf(out, "\t\t}\n");
    723     fprintf(out, "\t\t</style>\n");
    724     fprintf(out, "\t</head>\n");
    725     fprintf(out, "\t<body>\n");
    726     fprintf(out, "\t\t<div id='header'>\n");
    727     fprintf(out, "\t\t\t<img src='C:/Git/VulkanTools/layersvt/images/lunarg.png' />\n");
    728     fprintf(out, "\t\t\t<h1>Vulkan Info</h1>\n");
    729     fprintf(out, "\t\t</div>\n");
    730     fprintf(out, "\t\t<div id='wrapper'>\n");
    731 }
    732 
    733 // Prints closing HTML code for html output file
    734 void PrintHtmlFooter(FILE *out) {
    735     fprintf(out, "\t\t</div>\n");
    736     fprintf(out, "\t</body>\n");
    737     fprintf(out, "</html>");
    738 }
    739 
    740 // static void AppCreateInstance(struct AppInstance *inst, int argc, ...) {
    741 static void AppCreateInstance(struct AppInstance *inst) {
    742     AppGetInstanceExtensions(inst);
    743 
    744     //---Build a list of extensions to load---
    745 
    746     const char *info_instance_extensions[] = {VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
    747                                               VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME,
    748                                               VK_KHR_SURFACE_EXTENSION_NAME,
    749                                               VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME,
    750                                               VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME,
    751 #ifdef VK_USE_PLATFORM_WIN32_KHR
    752                                               VK_KHR_WIN32_SURFACE_EXTENSION_NAME
    753 #elif VK_USE_PLATFORM_XCB_KHR
    754                                               VK_KHR_XCB_SURFACE_EXTENSION_NAME
    755 #elif VK_USE_PLATFORM_XLIB_KHR
    756                                               VK_KHR_XLIB_SURFACE_EXTENSION_NAME
    757 #elif VK_USE_PLATFORM_WAYLAND_KHR
    758                                               VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
    759 #elif VK_USE_PLATFORM_ANDROID_KHR
    760                                               VK_KHR_ANDROID_SURFACE_EXTENSION_NAME
    761 #endif
    762     };
    763     uint32_t info_instance_extensions_count = ARRAY_SIZE(info_instance_extensions);
    764     inst->inst_extensions = malloc(sizeof(char *) * ARRAY_SIZE(info_instance_extensions));
    765     inst->inst_extensions_count = 0;
    766 
    767     for (uint32_t k = 0; (k < info_instance_extensions_count); k++) {
    768         for (uint32_t j = 0; (j < inst->global_extension_count); j++) {
    769             const char *found_name = inst->global_extensions[j].extensionName;
    770             if (!strcmp(info_instance_extensions[k], found_name)) {
    771                 inst->inst_extensions[inst->inst_extensions_count++] = info_instance_extensions[k];
    772                 break;
    773             }
    774         }
    775     }
    776 
    777     //----------------------------------------
    778 
    779     const VkApplicationInfo app_info = {
    780         .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
    781         .pNext = NULL,
    782         .pApplicationName = APP_SHORT_NAME,
    783         .applicationVersion = 1,
    784         .pEngineName = APP_SHORT_NAME,
    785         .engineVersion = 1,
    786         .apiVersion = VK_API_VERSION_1_0,
    787     };
    788 
    789     VkInstanceCreateInfo inst_info = {.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
    790                                       .pNext = NULL,
    791                                       .pApplicationInfo = &app_info,
    792                                       .enabledLayerCount = 0,
    793                                       .ppEnabledLayerNames = NULL,
    794                                       .enabledExtensionCount = inst->inst_extensions_count,
    795                                       .ppEnabledExtensionNames = inst->inst_extensions};
    796 
    797     VkDebugReportCallbackCreateInfoEXT dbg_info;
    798     memset(&dbg_info, 0, sizeof(dbg_info));
    799     dbg_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
    800     dbg_info.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
    801     dbg_info.pfnCallback = DbgCallback;
    802     inst_info.pNext = &dbg_info;
    803 
    804     VkResult U_ASSERT_ONLY err;
    805     err = vkCreateInstance(&inst_info, NULL, &inst->instance);
    806     if (err == VK_ERROR_INCOMPATIBLE_DRIVER) {
    807         printf("Cannot create Vulkan instance.\n");
    808         ERR_EXIT(err);
    809     } else if (err) {
    810         ERR_EXIT(err);
    811     }
    812 
    813     inst->vkGetPhysicalDeviceSurfaceSupportKHR =
    814             (PFN_vkGetPhysicalDeviceSurfaceSupportKHR)vkGetInstanceProcAddr(inst->instance, "vkGetPhysicalDeviceSurfaceSupportKHR");
    815     inst->vkGetPhysicalDeviceSurfaceCapabilitiesKHR = (PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)vkGetInstanceProcAddr(
    816             inst->instance, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
    817     inst->vkGetPhysicalDeviceSurfaceFormatsKHR =
    818             (PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)vkGetInstanceProcAddr(inst->instance, "vkGetPhysicalDeviceSurfaceFormatsKHR");
    819     inst->vkGetPhysicalDeviceSurfacePresentModesKHR = (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)vkGetInstanceProcAddr(
    820             inst->instance, "vkGetPhysicalDeviceSurfacePresentModesKHR");
    821     inst->vkGetPhysicalDeviceProperties2KHR =
    822             (PFN_vkGetPhysicalDeviceProperties2KHR)vkGetInstanceProcAddr(inst->instance, "vkGetPhysicalDeviceProperties2KHR");
    823     inst->vkGetPhysicalDeviceFormatProperties2KHR = (PFN_vkGetPhysicalDeviceFormatProperties2KHR)vkGetInstanceProcAddr(
    824             inst->instance, "vkGetPhysicalDeviceFormatProperties2KHR");
    825     inst->vkGetPhysicalDeviceQueueFamilyProperties2KHR = (PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)vkGetInstanceProcAddr(
    826             inst->instance, "vkGetPhysicalDeviceQueueFamilyProperties2KHR");
    827     inst->vkGetPhysicalDeviceFeatures2KHR =
    828             (PFN_vkGetPhysicalDeviceFeatures2KHR)vkGetInstanceProcAddr(inst->instance, "vkGetPhysicalDeviceFeatures2KHR");
    829     inst->vkGetPhysicalDeviceMemoryProperties2KHR = (PFN_vkGetPhysicalDeviceMemoryProperties2KHR)vkGetInstanceProcAddr(
    830             inst->instance, "vkGetPhysicalDeviceMemoryProperties2KHR");
    831     inst->vkGetPhysicalDeviceSurfaceCapabilities2KHR = (PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR)vkGetInstanceProcAddr(
    832             inst->instance, "vkGetPhysicalDeviceSurfaceCapabilities2KHR");
    833     inst->vkGetPhysicalDeviceSurfaceCapabilities2EXT = (PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT)vkGetInstanceProcAddr(
    834             inst->instance, "vkGetPhysicalDeviceSurfaceCapabilities2EXT");
    835 }
    836 
    837 //-----------------------------------------------------------
    838 
    839 static void AppDestroyInstance(struct AppInstance *inst) {
    840     free(inst->global_extensions);
    841     for (uint32_t i = 0; i < inst->global_layer_count; i++) {
    842         free(inst->global_layers[i].extension_properties);
    843     }
    844     free(inst->global_layers);
    845     free((char **)inst->inst_extensions);
    846     vkDestroyInstance(inst->instance, NULL);
    847 }
    848 
    849 static void AppGpuInit(struct AppGpu *gpu, struct AppInstance *inst, uint32_t id, VkPhysicalDevice obj) {
    850     uint32_t i;
    851 
    852     memset(gpu, 0, sizeof(*gpu));
    853 
    854     gpu->id = id;
    855     gpu->obj = obj;
    856     gpu->inst = inst;
    857 
    858     vkGetPhysicalDeviceProperties(gpu->obj, &gpu->props);
    859 
    860     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
    861                               gpu->inst->inst_extensions_count)) {
    862         gpu->props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR;
    863         gpu->props2.pNext = NULL;
    864 
    865         inst->vkGetPhysicalDeviceProperties2KHR(gpu->obj, &gpu->props2);
    866     }
    867 
    868     /* get queue count */
    869     vkGetPhysicalDeviceQueueFamilyProperties(gpu->obj, &gpu->queue_count, NULL);
    870 
    871     gpu->queue_props = malloc(sizeof(gpu->queue_props[0]) * gpu->queue_count);
    872 
    873     if (!gpu->queue_props) ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
    874     vkGetPhysicalDeviceQueueFamilyProperties(gpu->obj, &gpu->queue_count, gpu->queue_props);
    875 
    876     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
    877                               gpu->inst->inst_extensions_count)) {
    878         gpu->queue_props2 = malloc(sizeof(gpu->queue_props2[0]) * gpu->queue_count);
    879 
    880         if (!gpu->queue_props2) ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
    881 
    882         for (i = 0; i < gpu->queue_count; i++) {
    883             gpu->queue_props2[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR;
    884             gpu->queue_props2[i].pNext = NULL;
    885         }
    886 
    887         inst->vkGetPhysicalDeviceQueueFamilyProperties2KHR(gpu->obj, &gpu->queue_count, gpu->queue_props2);
    888     }
    889 
    890     /* set up queue requests */
    891     gpu->queue_reqs = malloc(sizeof(*gpu->queue_reqs) * gpu->queue_count);
    892     if (!gpu->queue_reqs) ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
    893     for (i = 0; i < gpu->queue_count; i++) {
    894         float *queue_priorities = malloc(gpu->queue_props[i].queueCount * sizeof(float));
    895         if (!queue_priorities) ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
    896         memset(queue_priorities, 0, gpu->queue_props[i].queueCount * sizeof(float));
    897 
    898         gpu->queue_reqs[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
    899         gpu->queue_reqs[i].pNext = NULL;
    900         gpu->queue_reqs[i].flags = 0;
    901         gpu->queue_reqs[i].queueFamilyIndex = i;
    902         gpu->queue_reqs[i].queueCount = gpu->queue_props[i].queueCount;
    903         gpu->queue_reqs[i].pQueuePriorities = queue_priorities;
    904     }
    905 
    906     vkGetPhysicalDeviceMemoryProperties(gpu->obj, &gpu->memory_props);
    907 
    908     vkGetPhysicalDeviceFeatures(gpu->obj, &gpu->features);
    909 
    910     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
    911                               gpu->inst->inst_extensions_count)) {
    912         gpu->memory_props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR;
    913         gpu->memory_props2.pNext = NULL;
    914 
    915         inst->vkGetPhysicalDeviceMemoryProperties2KHR(gpu->obj, &gpu->memory_props2);
    916 
    917         gpu->features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
    918         gpu->features2.pNext = NULL;
    919 
    920         inst->vkGetPhysicalDeviceFeatures2KHR(gpu->obj, &gpu->features2);
    921     }
    922 
    923     AppDevInit(&gpu->dev, gpu);
    924     AppDevInitFormats(&gpu->dev);
    925 }
    926 
    927 static void AppGpuDestroy(struct AppGpu *gpu) {
    928     AppDevDestroy(&gpu->dev);
    929     free(gpu->device_extensions);
    930 
    931     for (uint32_t i = 0; i < gpu->queue_count; i++) {
    932         free((void *)gpu->queue_reqs[i].pQueuePriorities);
    933     }
    934     free(gpu->queue_reqs);
    935 
    936     free(gpu->queue_props);
    937     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
    938                               gpu->inst->inst_extensions_count)) {
    939         free(gpu->queue_props2);
    940     }
    941 }
    942 
    943 // clang-format off
    944 
    945 //-----------------------------------------------------------
    946 
    947 //---------------------------Win32---------------------------
    948 #ifdef VK_USE_PLATFORM_WIN32_KHR
    949 
    950 // MS-Windows event handling function:
    951 LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    952     return (DefWindowProc(hWnd, uMsg, wParam, lParam));
    953 }
    954 
    955 static void AppCreateWin32Window(struct AppInstance *inst) {
    956     inst->h_instance = GetModuleHandle(NULL);
    957 
    958     WNDCLASSEX win_class;
    959 
    960     // Initialize the window class structure:
    961     win_class.cbSize = sizeof(WNDCLASSEX);
    962     win_class.style = CS_HREDRAW | CS_VREDRAW;
    963     win_class.lpfnWndProc = WndProc;
    964     win_class.cbClsExtra = 0;
    965     win_class.cbWndExtra = 0;
    966     win_class.hInstance = inst->h_instance;
    967     win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    968     win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
    969     win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    970     win_class.lpszMenuName = NULL;
    971     win_class.lpszClassName = APP_SHORT_NAME;
    972     win_class.hInstance = inst->h_instance;
    973     win_class.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
    974     // Register window class:
    975     if (!RegisterClassEx(&win_class)) {
    976         // It didn't work, so try to give a useful error:
    977         printf("Failed to register the window class!\n");
    978         fflush(stdout);
    979         exit(1);
    980     }
    981     // Create window with the registered class:
    982     RECT wr = { 0, 0, inst->width, inst->height };
    983     AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
    984     inst->h_wnd = CreateWindowEx(0,
    985         APP_SHORT_NAME,       // class name
    986         APP_SHORT_NAME,       // app name
    987         //WS_VISIBLE | WS_SYSMENU |
    988         WS_OVERLAPPEDWINDOW,  // window style
    989         100, 100,             // x/y coords
    990         wr.right - wr.left,   // width
    991         wr.bottom - wr.top,   // height
    992         NULL,                 // handle to parent
    993         NULL,                 // handle to menu
    994         inst->h_instance,      // hInstance
    995         NULL);                // no extra parameters
    996     if (!inst->h_wnd) {
    997         // It didn't work, so try to give a useful error:
    998         printf("Failed to create a window!\n");
    999         fflush(stdout);
   1000         exit(1);
   1001     }
   1002 }
   1003 
   1004 static void AppCreateWin32Surface(struct AppInstance *inst) {
   1005     VkResult U_ASSERT_ONLY err;
   1006     VkWin32SurfaceCreateInfoKHR createInfo;
   1007     createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
   1008     createInfo.pNext = NULL;
   1009     createInfo.flags = 0;
   1010     createInfo.hinstance = inst->h_instance;
   1011     createInfo.hwnd = inst->h_wnd;
   1012     err = vkCreateWin32SurfaceKHR(inst->instance, &createInfo, NULL, &inst->surface);
   1013     assert(!err);
   1014 }
   1015 
   1016 static void AppDestroyWin32Window(struct AppInstance *inst) {
   1017     DestroyWindow(inst->h_wnd);
   1018 }
   1019 #endif //VK_USE_PLATFORM_WIN32_KHR
   1020 //-----------------------------------------------------------
   1021 
   1022 #if defined(VK_USE_PLATFORM_XCB_KHR)     || \
   1023     defined(VK_USE_PLATFORM_XLIB_KHR)    || \
   1024     defined(VK_USE_PLATFORM_WIN32_KHR)
   1025 static void AppDestroySurface(struct AppInstance *inst) { //same for all platforms
   1026     vkDestroySurfaceKHR(inst->instance, inst->surface, NULL);
   1027 }
   1028 #endif
   1029 
   1030 //----------------------------XCB----------------------------
   1031 
   1032 #ifdef VK_USE_PLATFORM_XCB_KHR
   1033 static void AppCreateXcbWindow(struct AppInstance *inst) {
   1034     //--Init Connection--
   1035     const xcb_setup_t *setup;
   1036     xcb_screen_iterator_t iter;
   1037     int scr;
   1038 
   1039     // API guarantees non-null xcb_connection
   1040     inst->xcb_connection = xcb_connect(NULL, &scr);
   1041     int conn_error = xcb_connection_has_error(inst->xcb_connection);
   1042     if (conn_error) {
   1043         fprintf(stderr, "XCB failed to connect to the X server due to error:%d.\n", conn_error);
   1044         fflush(stderr);
   1045         inst->xcb_connection = NULL;
   1046     }
   1047 
   1048     setup = xcb_get_setup(inst->xcb_connection);
   1049     iter = xcb_setup_roots_iterator(setup);
   1050     while (scr-- > 0) {
   1051         xcb_screen_next(&iter);
   1052     }
   1053 
   1054     inst->xcb_screen = iter.data;
   1055     //-------------------
   1056 
   1057     inst->xcb_window = xcb_generate_id(inst->xcb_connection);
   1058     xcb_create_window(inst->xcb_connection, XCB_COPY_FROM_PARENT, inst->xcb_window,
   1059                       inst->xcb_screen->root, 0, 0, inst->width, inst->height, 0,
   1060                       XCB_WINDOW_CLASS_INPUT_OUTPUT, inst->xcb_screen->root_visual,
   1061                       0, NULL);
   1062 
   1063     xcb_intern_atom_cookie_t cookie = xcb_intern_atom(inst->xcb_connection, 1, 12, "WM_PROTOCOLS");
   1064     xcb_intern_atom_reply_t *reply =  xcb_intern_atom_reply(inst->xcb_connection, cookie, 0);
   1065     free(reply);
   1066 }
   1067 
   1068 static void AppCreateXcbSurface(struct AppInstance *inst) {
   1069     if (!inst->xcb_connection) {
   1070         return;
   1071     }
   1072 
   1073     VkResult U_ASSERT_ONLY err;
   1074     VkXcbSurfaceCreateInfoKHR xcb_createInfo;
   1075     xcb_createInfo.sType      = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
   1076     xcb_createInfo.pNext      = NULL;
   1077     xcb_createInfo.flags      = 0;
   1078     xcb_createInfo.connection = inst->xcb_connection;
   1079     xcb_createInfo.window     = inst->xcb_window;
   1080     err = vkCreateXcbSurfaceKHR(inst->instance, &xcb_createInfo, NULL, &inst->surface);
   1081     assert(!err);
   1082 }
   1083 
   1084 static void AppDestroyXcbWindow(struct AppInstance *inst) {
   1085     if (!inst->xcb_connection) {
   1086         return; // Nothing to destroy
   1087     }
   1088 
   1089     xcb_destroy_window(inst->xcb_connection, inst->xcb_window);
   1090     xcb_disconnect(inst->xcb_connection);
   1091 }
   1092 //VK_USE_PLATFORM_XCB_KHR
   1093 //-----------------------------------------------------------
   1094 
   1095 //----------------------------XLib---------------------------
   1096 #elif VK_USE_PLATFORM_XLIB_KHR
   1097 static void AppCreateXlibWindow(struct AppInstance *inst) {
   1098     long visualMask = VisualScreenMask;
   1099     int numberOfVisuals;
   1100 
   1101     inst->xlib_display = XOpenDisplay(NULL);
   1102     if (inst->xlib_display == NULL) {
   1103         printf("XLib failed to connect to the X server.\nExiting ...\n");
   1104         fflush(stdout);
   1105         exit(1);
   1106     }
   1107 
   1108     XVisualInfo vInfoTemplate={};
   1109     vInfoTemplate.screen = DefaultScreen(inst->xlib_display);
   1110     XVisualInfo *visualInfo = XGetVisualInfo(inst->xlib_display, visualMask,
   1111                                              &vInfoTemplate, &numberOfVisuals);
   1112     inst->xlib_window = XCreateWindow(
   1113                 inst->xlib_display, RootWindow(inst->xlib_display, vInfoTemplate.screen), 0, 0,
   1114                 inst->width, inst->height, 0, visualInfo->depth, InputOutput,
   1115                 visualInfo->visual, 0, NULL);
   1116 
   1117     XSync(inst->xlib_display,false);
   1118 }
   1119 
   1120 static void AppCreateXlibSurface(struct AppInstance *inst) {
   1121     VkResult U_ASSERT_ONLY err;
   1122     VkXlibSurfaceCreateInfoKHR createInfo;
   1123     createInfo.sType  = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
   1124     createInfo.pNext  = NULL;
   1125     createInfo.flags  = 0;
   1126     createInfo.dpy    = inst->xlib_display;
   1127     createInfo.window = inst->xlib_window;
   1128     err = vkCreateXlibSurfaceKHR(inst->instance, &createInfo, NULL, &inst->surface);
   1129     assert(!err);
   1130 }
   1131 
   1132 static void AppDestroyXlibWindow(struct AppInstance *inst) {
   1133     XDestroyWindow(inst->xlib_display, inst->xlib_window);
   1134     XCloseDisplay(inst->xlib_display);
   1135 }
   1136 #endif //VK_USE_PLATFORM_XLIB_KHR
   1137 //-----------------------------------------------------------
   1138 
   1139 #if defined(VK_USE_PLATFORM_XCB_KHR)     || \
   1140     defined(VK_USE_PLATFORM_XLIB_KHR)    || \
   1141     defined(VK_USE_PLATFORM_WIN32_KHR)
   1142 static int AppDumpSurfaceFormats(struct AppInstance *inst, struct AppGpu *gpu, FILE *out){
   1143     // Get the list of VkFormat's that are supported:
   1144     VkResult U_ASSERT_ONLY err;
   1145     uint32_t format_count = 0;
   1146     err = inst->vkGetPhysicalDeviceSurfaceFormatsKHR(gpu->obj, inst->surface, &format_count, NULL);
   1147     assert(!err);
   1148 
   1149     VkSurfaceFormatKHR *surf_formats = (VkSurfaceFormatKHR *)malloc(format_count * sizeof(VkSurfaceFormatKHR));
   1150     if (!surf_formats)
   1151         ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
   1152     err = inst->vkGetPhysicalDeviceSurfaceFormatsKHR(gpu->obj, inst->surface, &format_count, surf_formats);
   1153     assert(!err);
   1154 
   1155     if (html_output) {
   1156         fprintf(out, "\t\t\t\t<details><summary>Formats: count = <div class='val'>%d</div></summary>", format_count);
   1157         if (format_count > 0) {
   1158             fprintf(out, "\n");
   1159         } else {
   1160             fprintf(out, "</details>\n");
   1161         }
   1162     } else {
   1163         printf("Formats:\t\tcount = %d\n", format_count);
   1164     }
   1165 
   1166     for (uint32_t i = 0; i < format_count; i++) {
   1167         if (html_output) {
   1168             fprintf(out, "\t\t\t\t\t<details><summary><div class='type'>%s</div></summary></details>\n",
   1169                     VkFormatString(surf_formats[i].format));
   1170         } else {
   1171             printf("\t%s\n", VkFormatString(surf_formats[i].format));
   1172         }
   1173     }
   1174     if (html_output && format_count > 0) fprintf(out, "\t\t\t\t</details>\n");
   1175 
   1176     fflush(out);
   1177     free(surf_formats);
   1178     return format_count;
   1179 }
   1180 
   1181 static int AppDumpSurfacePresentModes(struct AppInstance *inst, struct AppGpu *gpu, FILE *out) {
   1182     // Get the list of VkPresentMode's that are supported:
   1183     VkResult U_ASSERT_ONLY err;
   1184     uint32_t present_mode_count = 0;
   1185     err = inst->vkGetPhysicalDeviceSurfacePresentModesKHR(gpu->obj, inst->surface, &present_mode_count, NULL);
   1186     assert(!err);
   1187 
   1188     VkPresentModeKHR *surf_present_modes = (VkPresentModeKHR *)malloc(present_mode_count * sizeof(VkPresentInfoKHR));
   1189     if (!surf_present_modes)
   1190         ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
   1191     err = inst->vkGetPhysicalDeviceSurfacePresentModesKHR(gpu->obj, inst->surface, &present_mode_count, surf_present_modes);
   1192     assert(!err);
   1193 
   1194     if (html_output) {
   1195         fprintf(out, "\t\t\t\t<details><summary>Present Modes: count = <div class='val'>%d</div></summary>", present_mode_count);
   1196         if (present_mode_count > 0) {
   1197             fprintf(out, "\n");
   1198         } else {
   1199             fprintf(out, "</details>");
   1200         }
   1201     } else {
   1202         printf("Present Modes:\t\tcount = %d\n", present_mode_count);
   1203     }
   1204 
   1205     for (uint32_t i = 0; i < present_mode_count; i++) {
   1206         if (html_output) {
   1207             fprintf(out, "\t\t\t\t\t<details><summary><div class='type'>%s</div></summary></details>\n",
   1208                     VkPresentModeString(surf_present_modes[i]));
   1209         } else {
   1210             printf("\t%s\n", VkPresentModeString(surf_present_modes[i]));
   1211         }
   1212     }
   1213     if (html_output && present_mode_count > 0) fprintf(out, "\t\t\t\t</details>\n");
   1214 
   1215     fflush(out);
   1216     free(surf_present_modes);
   1217     return present_mode_count;
   1218 }
   1219 
   1220 static void AppDumpSurfaceCapabilities(struct AppInstance *inst, struct AppGpu *gpu, FILE *out) {
   1221     if (CheckExtensionEnabled(VK_KHR_SURFACE_EXTENSION_NAME, gpu->inst->inst_extensions, gpu->inst->inst_extensions_count)) {
   1222         inst->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(gpu->obj, inst->surface, &inst->surface_capabilities);
   1223 
   1224         if (html_output) {
   1225             fprintf(out, "\t\t\t\t<details><summary>VkSurfaceCapabilitiesKHR</summary>\n");
   1226             fprintf(out, "\t\t\t\t\t<details><summary>minImageCount = <div class='val'>%u</div></summary></details>\n", inst->surface_capabilities.minImageCount);
   1227             fprintf(out, "\t\t\t\t\t<details><summary>maxImageCount = <div class='val'>%u</div></summary></details>\n", inst->surface_capabilities.maxImageCount);
   1228             fprintf(out, "\t\t\t\t\t<details><summary>currentExtent</summary>\n");
   1229             fprintf(out, "\t\t\t\t\t\t<details><summary>width = <div class='val'>%u</div></summary></details>\n", inst->surface_capabilities.currentExtent.width);
   1230             fprintf(out, "\t\t\t\t\t\t<details><summary>height = <div class='val'>%u</div></summary></details>\n", inst->surface_capabilities.currentExtent.height);
   1231             fprintf(out, "\t\t\t\t\t</details>\n");
   1232             fprintf(out, "\t\t\t\t\t<details><summary>minImageExtent</summary>\n");
   1233             fprintf(out, "\t\t\t\t\t\t<details><summary>width = <div class='val'>%u</div></summary></details>\n", inst->surface_capabilities.minImageExtent.width);
   1234             fprintf(out, "\t\t\t\t\t\t<details><summary>height = <div class='val'>%u</div></summary></details>\n", inst->surface_capabilities.minImageExtent.height);
   1235             fprintf(out, "\t\t\t\t\t</details>\n");
   1236             fprintf(out, "\t\t\t\t\t<details><summary>maxImageExtent</summary>\n");
   1237             fprintf(out, "\t\t\t\t\t\t<details><summary>width = <div class='val'>%u</div></summary></details>\n", inst->surface_capabilities.maxImageExtent.width);
   1238             fprintf(out, "\t\t\t\t\t\t<details><summary>height = <div class='val'>%u</div></summary></details>\n", inst->surface_capabilities.maxImageExtent.height);
   1239             fprintf(out, "\t\t\t\t\t</details>\n");
   1240             fprintf(out, "\t\t\t\t\t<details><summary>maxImageArrayLayers = <div class='val'>%u</div></summary></details>\n", inst->surface_capabilities.maxImageArrayLayers);
   1241             fprintf(out, "\t\t\t\t\t<details><summary>supportedTransform</summary>\n");
   1242             if (inst->surface_capabilities.supportedTransforms == 0) { fprintf(out, "\t\t\t\t\t\t<details><summary>None</summary></details>\n"); }
   1243             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
   1244                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR</div></summary></details>\n");
   1245             }
   1246             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) {
   1247                 fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR</div></summary></details>\n");
   1248             }
   1249             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR) {
   1250                 fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR</div></summary></details>\n");
   1251             }
   1252             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) {
   1253                 fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR</div></summary></details>\n");
   1254             }
   1255             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR) {
   1256                 fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR</div></summary></details>\n");
   1257             }
   1258             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR) {
   1259                 fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR</div></summary></details>\n");
   1260             }
   1261             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR) {
   1262                 fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR</div></summary></details>\n");
   1263             }
   1264             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR) {
   1265                 fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR</div></summary></details>\n");
   1266             }
   1267             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR) {
   1268                 fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR</div></summary></details>\n");
   1269             }
   1270             fprintf(out, "\t\t\t\t\t</details>\n");
   1271             fprintf(out, "\t\t\t\t\t<details><summary>currentTransform</summary>\n");
   1272             if (inst->surface_capabilities.currentTransform == 0) { fprintf(out, "\t\t\t\t\t\t<details><summary>None</summary></details>\n"); }
   1273             if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
   1274                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR</div></summary></details>\n");
   1275             }
   1276             else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) {
   1277                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR</div></summary></details>\n");
   1278             }
   1279             else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR) {
   1280                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR</div></summary></details>\n");
   1281             }
   1282             else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) {
   1283                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR</div></summary></details>\n");
   1284             }
   1285             else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR) {
   1286                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR</div></summary></details>\n");
   1287             }
   1288             else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR) {
   1289                 fprintf(out, "\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR</div></summary></details>\n");
   1290             }
   1291             else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR) {
   1292                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR</div></summary></details>\n");
   1293             }
   1294             else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR) {
   1295                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR</div></summary></details>\n");
   1296             }
   1297             else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR) {
   1298                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR</div></summary></details>\n");
   1299             }
   1300             fprintf(out, "\t\t\t\t\t</details>\n");
   1301             fprintf(out, "\t\t\t\t\t<details><summary>supportedCompositeAlpha</summary>\n");
   1302             if (inst->surface_capabilities.supportedCompositeAlpha == 0) { fprintf(out, "\t\t\t\t\t\t<details><summary>None</summary></details>\n"); }
   1303             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) {
   1304                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR</div></summary></details>\n");
   1305             }
   1306             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) {
   1307                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR</div></summary></details>\n");
   1308             }
   1309             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) {
   1310                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR</div></summary></details>\n");
   1311             }
   1312             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) {
   1313                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR</div></summary></details>\n");
   1314             }
   1315             fprintf(out, "\t\t\t\t\t</details>\n");
   1316             fprintf(out, "\t\t\t\t\t<details><summary>supportedUsageFlags</summary>\n");
   1317             if (inst->surface_capabilities.supportedUsageFlags == 0) { fprintf(out, "\t\t\t\t\t\t<details><summary>None</summary></details>\n"); }
   1318             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) {
   1319                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_TRANSFER_SRC_BIT</div></summary></details>\n");
   1320             }
   1321             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) {
   1322                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_TRANSFER_DST_BIT</div></summary></details>\n");
   1323             }
   1324             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) {
   1325                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_SAMPLED_BIT</div></summary></details>\n");
   1326             }
   1327             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_STORAGE_BIT) {
   1328                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_STORAGE_BIT</div></summary></details>\n");
   1329             }
   1330             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
   1331                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT</div></summary></details>\n");
   1332             }
   1333             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
   1334                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT</div></summary></details>\n");
   1335             }
   1336             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) {
   1337                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT</div></summary></details>\n");
   1338             }
   1339             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) {
   1340                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT</div></summary></details>\n");
   1341             }
   1342             fprintf(out, "\t\t\t\t\t</details>\n");
   1343         } else {
   1344             printf("\nVkSurfaceCapabilitiesKHR:\n");
   1345             printf("=========================\n");
   1346             printf("\tminImageCount       = %u\n", inst->surface_capabilities.minImageCount);
   1347             printf("\tmaxImageCount       = %u\n", inst->surface_capabilities.maxImageCount);
   1348             printf("\tcurrentExtent:\n");
   1349             printf("\t\twidth       = %u\n", inst->surface_capabilities.currentExtent.width);
   1350             printf("\t\theight      = %u\n", inst->surface_capabilities.currentExtent.height);
   1351             printf("\tminImageExtent:\n");
   1352             printf("\t\twidth       = %u\n", inst->surface_capabilities.minImageExtent.width);
   1353             printf("\t\theight      = %u\n", inst->surface_capabilities.minImageExtent.height);
   1354             printf("\tmaxImageExtent:\n");
   1355             printf("\t\twidth       = %u\n", inst->surface_capabilities.maxImageExtent.width);
   1356             printf("\t\theight      = %u\n", inst->surface_capabilities.maxImageExtent.height);
   1357             printf("\tmaxImageArrayLayers = %u\n", inst->surface_capabilities.maxImageArrayLayers);
   1358             printf("\tsupportedTransform:\n");
   1359             if (inst->surface_capabilities.supportedTransforms == 0) { printf("\t\tNone\n"); }
   1360             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR\n"); }
   1361             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR\n"); }
   1362             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR\n"); }
   1363             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR\n"); }
   1364             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR\n"); }
   1365             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR\n"); }
   1366             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR\n"); }
   1367             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR\n"); }
   1368             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_INHERIT_BIT_KHR\n"); }
   1369             printf("\tcurrentTransform:\n");
   1370             if (inst->surface_capabilities.currentTransform == 0) { printf("\t\tNone\n"); }
   1371             if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR\n"); }
   1372             else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR\n"); }
   1373             else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR\n"); }
   1374             else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR\n"); }
   1375             else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR\n"); }
   1376             else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR\n"); }
   1377             else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR\n"); }
   1378             else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR\n"); }
   1379             else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_INHERIT_BIT_KHR\n"); }
   1380             printf("\tsupportedCompositeAlpha:\n");
   1381             if (inst->surface_capabilities.supportedCompositeAlpha == 0) { printf("\t\tNone\n"); }
   1382             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) { printf("\t\tVK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR\n"); }
   1383             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) { printf("\t\tVK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR\n"); }
   1384             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) { printf("\t\tVK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR\n"); }
   1385             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) { printf("\t\tVK_COMPOSITE_ALPHA_INHERIT_BIT_KHR\n"); }
   1386             printf("\tsupportedUsageFlags:\n");
   1387             if (inst->surface_capabilities.supportedUsageFlags == 0) { printf("\t\tNone\n"); }
   1388             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) { printf("\t\tVK_IMAGE_USAGE_TRANSFER_SRC_BIT\n"); }
   1389             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) { printf("\t\tVK_IMAGE_USAGE_TRANSFER_DST_BIT\n"); }
   1390             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) { printf("\t\tVK_IMAGE_USAGE_SAMPLED_BIT\n"); }
   1391             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_STORAGE_BIT) { printf("\t\tVK_IMAGE_USAGE_STORAGE_BIT\n"); }
   1392             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) { printf("\t\tVK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT\n"); }
   1393             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { printf("\t\tVK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT\n"); }
   1394             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) { printf("\t\tVK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT\n"); }
   1395             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) { printf("\t\tVK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT\n"); }
   1396         }
   1397 
   1398         // Get additional surface capability information from vkGetPhysicalDeviceSurfaceCapabilities2EXT
   1399         if (CheckExtensionEnabled(VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME, gpu->inst->inst_extensions, gpu->inst->inst_extensions_count)) {
   1400             memset(&inst->surface_capabilities2_ext, 0, sizeof(VkSurfaceCapabilities2EXT));
   1401             inst->surface_capabilities2_ext.sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT;
   1402             inst->surface_capabilities2_ext.pNext = NULL;
   1403 
   1404             inst->vkGetPhysicalDeviceSurfaceCapabilities2EXT(gpu->obj, inst->surface, &inst->surface_capabilities2_ext);
   1405 
   1406             if (html_output) {
   1407                 fprintf(out, "\t\t\t\t\t<details><summary>VkSurfaceCapabilities2EXT</summary>\n");
   1408                 fprintf(out, "\t\t\t\t\t\t<details><summary>supportedSurfaceCounters</summary>\n");
   1409                 if (inst->surface_capabilities2_ext.supportedSurfaceCounters == 0) { fprintf(out, "\t\t\t\t\t\t\t<details><summary>None</summary></details>\n"); }
   1410                 if (inst->surface_capabilities2_ext.supportedSurfaceCounters & VK_SURFACE_COUNTER_VBLANK_EXT) {
   1411                     fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_COUNTER_VBLANK_EXT</div></summary></details>\n");
   1412                 }
   1413                 fprintf(out, "\t\t\t\t\t\t</details>\n");
   1414                 fprintf(out, "\t\t\t\t\t</details>\n");
   1415             } else {
   1416                 printf("\nVkSurfaceCapabilities2EXT:\n");
   1417                 printf("==========================\n\n");
   1418                 printf("\tsupportedSurfaceCounters:\n");
   1419                 if (inst->surface_capabilities2_ext.supportedSurfaceCounters == 0) { printf("\t\tNone\n"); }
   1420                 if (inst->surface_capabilities2_ext.supportedSurfaceCounters & VK_SURFACE_COUNTER_VBLANK_EXT) { printf("\t\tVK_SURFACE_COUNTER_VBLANK_EXT\n"); }
   1421             }
   1422         }
   1423 
   1424         // Get additional surface capability information from vkGetPhysicalDeviceSurfaceCapabilities2KHR
   1425         if (CheckExtensionEnabled(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, gpu->inst->inst_extensions, gpu->inst->inst_extensions_count)) {
   1426             if (CheckExtensionEnabled(VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME, gpu->inst->inst_extensions, gpu->inst->inst_extensions_count)) {
   1427                 inst->shared_surface_capabilities.sType = VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR;
   1428                 inst->shared_surface_capabilities.pNext = NULL;
   1429                 inst->surface_capabilities2.pNext = &inst->shared_surface_capabilities;
   1430             } else {
   1431                 inst->surface_capabilities2.pNext = NULL;
   1432             }
   1433 
   1434             inst->surface_capabilities2.sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
   1435 
   1436             VkPhysicalDeviceSurfaceInfo2KHR surface_info;
   1437             surface_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR;
   1438             surface_info.pNext = NULL;
   1439             surface_info.surface = inst->surface;
   1440 
   1441             inst->vkGetPhysicalDeviceSurfaceCapabilities2KHR(gpu->obj, &surface_info, &inst->surface_capabilities2);
   1442 
   1443             void *place = inst->surface_capabilities2.pNext;
   1444             while (place) {
   1445                 struct VkStructureHeader* work = (struct VkStructureHeader*) place;
   1446                 if (work->sType == VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR) {
   1447                     if (html_output) {
   1448                         fprintf(out, "\t\t\t\t\t<details><summary>VkSharedPresentSurfaceCapabilitiesKHR</summary>\n");
   1449                         VkSharedPresentSurfaceCapabilitiesKHR* shared_surface_capabilities = (VkSharedPresentSurfaceCapabilitiesKHR*)place;
   1450                         fprintf(out, "\t\t\t\t\t\t<details><summary>sharedPresentSupportedUsageFlags</summary>\n");
   1451                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags == 0) { fprintf(out, "\t\t\t\t\t\t\t<details><summary>None</summary></details>\n"); }
   1452                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) {
   1453                             fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_TRANSFER_SRC_BIT</div></summary></details>\n");
   1454                         }
   1455                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) {
   1456                             fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_TRANSFER_DST_BIT</div></summary></details>\n");
   1457                         }
   1458                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) {
   1459                             fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_SAMPLED_BIT</div></summary></details>\n");
   1460                         }
   1461                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_STORAGE_BIT) {
   1462                             fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_STORAGE_BIT</div></summary></details>\n");
   1463                         }
   1464                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
   1465                             fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT</div></summary></details>\n");
   1466                         }
   1467                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
   1468                             fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT</div></summary></details>\n");
   1469                         }
   1470                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) {
   1471                             fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT</div></summary></details>\n");
   1472                         }
   1473                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) {
   1474                             fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT</div></summary></details>\n");
   1475                         }
   1476                         fprintf(out, "\t\t\t\t\t\t</details>\n");
   1477                         fprintf(out, "\t\t\t\t\t</details>\n");
   1478                     } else {
   1479                         printf("\nVkSharedPresentSurfaceCapabilitiesKHR:\n");
   1480                         printf("========================================\n");
   1481                         VkSharedPresentSurfaceCapabilitiesKHR* shared_surface_capabilities = (VkSharedPresentSurfaceCapabilitiesKHR*)place;
   1482                         printf("\tsharedPresentSupportedUsageFlags:\n");
   1483                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags == 0) { printf("\t\tNone\n"); }
   1484                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) { printf("\t\tVK_IMAGE_USAGE_TRANSFER_SRC_BIT\n"); }
   1485                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) { printf("\t\tVK_IMAGE_USAGE_TRANSFER_DST_BIT\n"); }
   1486                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) { printf("\t\tVK_IMAGE_USAGE_SAMPLED_BIT\n"); }
   1487                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_STORAGE_BIT) { printf("\t\tVK_IMAGE_USAGE_STORAGE_BIT\n"); }
   1488                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) { printf("\t\tVK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT\n"); }
   1489                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { printf("\t\tVK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT\n"); }
   1490                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) { printf("\t\tVK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT\n"); }
   1491                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) { printf("\t\tVK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT\n"); }
   1492                     }
   1493                 }
   1494                 place = work->pNext;
   1495             }
   1496         }
   1497         if (html_output) { fprintf(out, "\t\t\t\t</details>\n"); }
   1498     }
   1499 }
   1500 
   1501 #endif
   1502 
   1503 static void AppDevDumpFormatProps(const struct AppDev *dev, VkFormat fmt, FILE *out) {
   1504     const VkFormatProperties *props = &dev->format_props[fmt];
   1505     struct {
   1506         const char *name;
   1507         VkFlags flags;
   1508     } features[3];
   1509 
   1510     features[0].name  = "linearTiling   FormatFeatureFlags";
   1511     features[0].flags = props->linearTilingFeatures;
   1512     features[1].name  = "optimalTiling  FormatFeatureFlags";
   1513     features[1].flags = props->optimalTilingFeatures;
   1514     features[2].name  = "bufferFeatures FormatFeatureFlags";
   1515     features[2].flags = props->bufferFeatures;
   1516 
   1517     if (html_output) {
   1518         fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>FORMAT_%s</div></summary>\n", VkFormatString(fmt));
   1519     } else {
   1520         printf("\nFORMAT_%s:", VkFormatString(fmt));
   1521     }
   1522 
   1523     for (uint32_t i = 0; i < ARRAY_SIZE(features); i++) {
   1524         if (html_output) {
   1525             fprintf(out, "\t\t\t\t\t\t\t<details open><summary>%s</summary>\n", features[i].name);
   1526             if (features[i].flags == 0) {
   1527                 fprintf(out, "\t\t\t\t\t\t\t\t<details><summary>None</summary></details>\n");
   1528             } else {
   1529                 fprintf(out, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
   1530                         ((features[i].flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)                  ? "\t\t\t\t\t\t\t\t<details><summary><div class='type'>VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT</div></summary></details>\n"                  : ""),  //0x0001
   1531                         ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)                  ? "\t\t\t\t\t\t\t\t<details><summary><div class='type'>VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT</div></summary></details>\n"                  : ""),  //0x0002
   1532                         ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT)           ? "\t\t\t\t\t\t\t\t<details><summary><div class='type'>VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT</div></summary></details>\n"           : ""),  //0x0004
   1533                         ((features[i].flags & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT)           ? "\t\t\t\t\t\t\t\t<details><summary><div class='type'>VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT</div></summary></details>\n"           : ""),  //0x0008
   1534                         ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT)           ? "\t\t\t\t\t\t\t\t<details><summary><div class='type'>VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT</div></summary></details>\n"           : ""),  //0x0010
   1535                         ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT)    ? "\t\t\t\t\t\t\t\t<details><summary><div class='type'>VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT</div></summary></details>\n"    : ""),  //0x0020
   1536                         ((features[i].flags & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT)                  ? "\t\t\t\t\t\t\t\t<details><summary><div class='type'>VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT</div></summary></details>\n"                  : ""),  //0x0040
   1537                         ((features[i].flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)               ? "\t\t\t\t\t\t\t\t<details><summary><div class='type'>VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT</div></summary></details>\n"               : ""),  //0x0080
   1538                         ((features[i].flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT)         ? "\t\t\t\t\t\t\t\t<details><summary><div class='type'>VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT</div></summary></details>\n"         : ""),  //0x0100
   1539                         ((features[i].flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)       ? "\t\t\t\t\t\t\t\t<details><summary><div class='type'>VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT</div></summary></details>\n"       : ""),  //0x0200
   1540                         ((features[i].flags & VK_FORMAT_FEATURE_BLIT_SRC_BIT)                       ? "\t\t\t\t\t\t\t\t<details><summary><div class='type'>VK_FORMAT_FEATURE_BLIT_SRC_BIT</div></summary></details>\n"                       : ""),  //0x0400
   1541                         ((features[i].flags & VK_FORMAT_FEATURE_BLIT_DST_BIT)                       ? "\t\t\t\t\t\t\t\t<details><summary><div class='type'>VK_FORMAT_FEATURE_BLIT_DST_BIT</div></summary></details>\n"                       : ""),  //0x0800
   1542                         ((features[i].flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)    ? "\t\t\t\t\t\t\t\t<details><summary><div class='type'>VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT</div></summary></details>\n"    : ""),  //0x1000
   1543                         ((features[i].flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG) ? "\t\t\t\t\t\t\t\t<details><summary><div class='type'>VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG</div></summary></details>\n" : ""),  //0x2000
   1544                         ((features[i].flags & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR)               ? "\t\t\t\t\t\t\t\t<details><summary><div class='type'>VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR</div></summary></details>\n"               : ""),  //0x4000
   1545                         ((features[i].flags & VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR)               ? "\t\t\t\t\t\t\t\t<details><summary><div class='type'>VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR</div></summary></details>\n"               : "")); //0x8000
   1546             }
   1547             fprintf(out, "\t\t\t\t\t\t\t</details>\n");
   1548         } else {
   1549             printf("\n\t%s:", features[i].name);
   1550             if (features[i].flags == 0) {
   1551                 printf("\n\t\tNone");
   1552             } else {
   1553                 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
   1554                        ((features[i].flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)                  ? "\n\t\tVK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT"                  : ""),  //0x0001
   1555                        ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)                  ? "\n\t\tVK_FORMAT_FEATURE_STORAGE_IMAGE_BIT"                  : ""),  //0x0002
   1556                        ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT)           ? "\n\t\tVK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT"           : ""),  //0x0004
   1557                        ((features[i].flags & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT)           ? "\n\t\tVK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT"           : ""),  //0x0008
   1558                        ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT)           ? "\n\t\tVK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT"           : ""),  //0x0010
   1559                        ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT)    ? "\n\t\tVK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT"    : ""),  //0x0020
   1560                        ((features[i].flags & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT)                  ? "\n\t\tVK_FORMAT_FEATURE_VERTEX_BUFFER_BIT"                  : ""),  //0x0040
   1561                        ((features[i].flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)               ? "\n\t\tVK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT"               : ""),  //0x0080
   1562                        ((features[i].flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT)         ? "\n\t\tVK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT"         : ""),  //0x0100
   1563                        ((features[i].flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)       ? "\n\t\tVK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT"       : ""),  //0x0200
   1564                        ((features[i].flags & VK_FORMAT_FEATURE_BLIT_SRC_BIT)                       ? "\n\t\tVK_FORMAT_FEATURE_BLIT_SRC_BIT"                       : ""),  //0x0400
   1565                        ((features[i].flags & VK_FORMAT_FEATURE_BLIT_DST_BIT)                       ? "\n\t\tVK_FORMAT_FEATURE_BLIT_DST_BIT"                       : ""),  //0x0800
   1566                        ((features[i].flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)    ? "\n\t\tVK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT"    : ""),  //0x1000
   1567                        ((features[i].flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG) ? "\n\t\tVK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG" : ""),  //0x2000
   1568                        ((features[i].flags & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR)               ? "\n\t\tVK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR"               : ""),  //0x4000
   1569                        ((features[i].flags & VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR)               ? "\n\t\tVK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR"               : "")); //0x8000
   1570             }
   1571         }
   1572     }
   1573 
   1574     if (html_output) {
   1575         fprintf(out, "\t\t\t\t\t\t</details>\n");
   1576     } else {
   1577         printf("\n");
   1578     }
   1579 }
   1580 
   1581 static void AppDevDump(const struct AppDev *dev, FILE *out) {
   1582     if (html_output) {
   1583         fprintf(out, "\t\t\t\t\t<details><summary>Format Properties</summary>\n");
   1584     } else {
   1585         printf("Format Properties:\n");
   1586         printf("==================");
   1587     }
   1588     VkFormat fmt;
   1589     for (fmt = 0; fmt < VK_FORMAT_RANGE_SIZE; fmt++) {
   1590         AppDevDumpFormatProps(dev, fmt, out);
   1591     }
   1592     if (html_output) fprintf(out, "\t\t\t\t\t</details>\n");
   1593 }
   1594 
   1595 #ifdef _WIN32
   1596 #define PRINTF_SIZE_T_SPECIFIER    "%Iu"
   1597 #else
   1598 #define PRINTF_SIZE_T_SPECIFIER    "%zu"
   1599 #endif
   1600 
   1601 static void AppGpuDumpFeatures(const struct AppGpu *gpu, FILE *out) {
   1602     const VkPhysicalDeviceFeatures *features = &gpu->features;
   1603 
   1604     if (html_output) {
   1605         fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceFeatures</summary>\n");
   1606         fprintf(out, "\t\t\t\t\t\t<details><summary>robustBufferAccess                      = <div class='val'>%u</div></summary></details>\n", features->robustBufferAccess                     );
   1607         fprintf(out, "\t\t\t\t\t\t<details><summary>fullDrawIndexUint32                     = <div class='val'>%u</div></summary></details>\n", features->fullDrawIndexUint32                    );
   1608         fprintf(out, "\t\t\t\t\t\t<details><summary>imageCubeArray                          = <div class='val'>%u</div></summary></details>\n", features->imageCubeArray                         );
   1609         fprintf(out, "\t\t\t\t\t\t<details><summary>independentBlend                        = <div class='val'>%u</div></summary></details>\n", features->independentBlend                       );
   1610         fprintf(out, "\t\t\t\t\t\t<details><summary>geometryShader                          = <div class='val'>%u</div></summary></details>\n", features->geometryShader                         );
   1611         fprintf(out, "\t\t\t\t\t\t<details><summary>tessellationShader                      = <div class='val'>%u</div></summary></details>\n", features->tessellationShader                     );
   1612         fprintf(out, "\t\t\t\t\t\t<details><summary>sampleRateShading                       = <div class='val'>%u</div></summary></details>\n", features->sampleRateShading                      );
   1613         fprintf(out, "\t\t\t\t\t\t<details><summary>dualSrcBlend                            = <div class='val'>%u</div></summary></details>\n", features->dualSrcBlend                           );
   1614         fprintf(out, "\t\t\t\t\t\t<details><summary>logicOp                                 = <div class='val'>%u</div></summary></details>\n", features->logicOp                                );
   1615         fprintf(out, "\t\t\t\t\t\t<details><summary>multiDrawIndirect                       = <div class='val'>%u</div></summary></details>\n", features->multiDrawIndirect                      );
   1616         fprintf(out, "\t\t\t\t\t\t<details><summary>drawIndirectFirstInstance               = <div class='val'>%u</div></summary></details>\n", features->drawIndirectFirstInstance              );
   1617         fprintf(out, "\t\t\t\t\t\t<details><summary>depthClamp                              = <div class='val'>%u</div></summary></details>\n", features->depthClamp                             );
   1618         fprintf(out, "\t\t\t\t\t\t<details><summary>depthBiasClamp                          = <div class='val'>%u</div></summary></details>\n", features->depthBiasClamp                         );
   1619         fprintf(out, "\t\t\t\t\t\t<details><summary>fillModeNonSolid                        = <div class='val'>%u</div></summary></details>\n", features->fillModeNonSolid                       );
   1620         fprintf(out, "\t\t\t\t\t\t<details><summary>depthBounds                             = <div class='val'>%u</div></summary></details>\n", features->depthBounds                            );
   1621         fprintf(out, "\t\t\t\t\t\t<details><summary>wideLines                               = <div class='val'>%u</div></summary></details>\n", features->wideLines                              );
   1622         fprintf(out, "\t\t\t\t\t\t<details><summary>largePoints                             = <div class='val'>%u</div></summary></details>\n", features->largePoints                            );
   1623         fprintf(out, "\t\t\t\t\t\t<details><summary>alphaToOne                              = <div class='val'>%u</div></summary></details>\n", features->alphaToOne                             );
   1624         fprintf(out, "\t\t\t\t\t\t<details><summary>multiViewport                           = <div class='val'>%u</div></summary></details>\n", features->multiViewport                          );
   1625         fprintf(out, "\t\t\t\t\t\t<details><summary>samplerAnisotropy                       = <div class='val'>%u</div></summary></details>\n", features->samplerAnisotropy                      );
   1626         fprintf(out, "\t\t\t\t\t\t<details><summary>textureCompressionETC2                  = <div class='val'>%u</div></summary></details>\n", features->textureCompressionETC2                 );
   1627         fprintf(out, "\t\t\t\t\t\t<details><summary>textureCompressionASTC_LDR              = <div class='val'>%u</div></summary></details>\n", features->textureCompressionASTC_LDR             );
   1628         fprintf(out, "\t\t\t\t\t\t<details><summary>textureCompressionBC                    = <div class='val'>%u</div></summary></details>\n", features->textureCompressionBC                   );
   1629         fprintf(out, "\t\t\t\t\t\t<details><summary>occlusionQueryPrecise                   = <div class='val'>%u</div></summary></details>\n", features->occlusionQueryPrecise                  );
   1630         fprintf(out, "\t\t\t\t\t\t<details><summary>pipelineStatisticsQuery                 = <div class='val'>%u</div></summary></details>\n", features->pipelineStatisticsQuery                );
   1631         fprintf(out, "\t\t\t\t\t\t<details><summary>vertexPipelineStoresAndAtomics          = <div class='val'>%u</div></summary></details>\n", features->vertexPipelineStoresAndAtomics         );
   1632         fprintf(out, "\t\t\t\t\t\t<details><summary>fragmentStoresAndAtomics                = <div class='val'>%u</div></summary></details>\n", features->fragmentStoresAndAtomics               );
   1633         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderTessellationAndGeometryPointSize  = <div class='val'>%u</div></summary></details>\n", features->shaderTessellationAndGeometryPointSize );
   1634         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderImageGatherExtended               = <div class='val'>%u</div></summary></details>\n", features->shaderImageGatherExtended              );
   1635         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderStorageImageExtendedFormats       = <div class='val'>%u</div></summary></details>\n", features->shaderStorageImageExtendedFormats      );
   1636         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderStorageImageMultisample           = <div class='val'>%u</div></summary></details>\n", features->shaderStorageImageMultisample          );
   1637         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderStorageImageReadWithoutFormat     = <div class='val'>%u</div></summary></details>\n", features->shaderStorageImageReadWithoutFormat    );
   1638         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderStorageImageWriteWithoutFormat    = <div class='val'>%u</div></summary></details>\n", features->shaderStorageImageWriteWithoutFormat   );
   1639         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderUniformBufferArrayDynamicIndexing = <div class='val'>%u</div></summary></details>\n", features->shaderUniformBufferArrayDynamicIndexing);
   1640         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderSampledImageArrayDynamicIndexing  = <div class='val'>%u</div></summary></details>\n", features->shaderSampledImageArrayDynamicIndexing );
   1641         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderStorageBufferArrayDynamicIndexing = <div class='val'>%u</div></summary></details>\n", features->shaderStorageBufferArrayDynamicIndexing);
   1642         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderStorageImageArrayDynamicIndexing  = <div class='val'>%u</div></summary></details>\n", features->shaderStorageImageArrayDynamicIndexing );
   1643         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderClipDistance                      = <div class='val'>%u</div></summary></details>\n", features->shaderClipDistance                     );
   1644         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderCullDistance                      = <div class='val'>%u</div></summary></details>\n", features->shaderCullDistance                     );
   1645         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderFloat64                           = <div class='val'>%u</div></summary></details>\n", features->shaderFloat64                          );
   1646         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderInt64                             = <div class='val'>%u</div></summary></details>\n", features->shaderInt64                            );
   1647         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderInt16                             = <div class='val'>%u</div></summary></details>\n", features->shaderInt16                            );
   1648         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderResourceResidency                 = <div class='val'>%u</div></summary></details>\n", features->shaderResourceResidency                );
   1649         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderResourceMinLod                    = <div class='val'>%u</div></summary></details>\n", features->shaderResourceMinLod                   );
   1650         fprintf(out, "\t\t\t\t\t\t<details><summary>sparseBinding                           = <div class='val'>%u</div></summary></details>\n", features->sparseBinding                          );
   1651         fprintf(out, "\t\t\t\t\t\t<details><summary>sparseResidencyBuffer                   = <div class='val'>%u</div></summary></details>\n", features->sparseResidencyBuffer                  );
   1652         fprintf(out, "\t\t\t\t\t\t<details><summary>sparseResidencyImage2D                  = <div class='val'>%u</div></summary></details>\n", features->sparseResidencyImage2D                 );
   1653         fprintf(out, "\t\t\t\t\t\t<details><summary>sparseResidencyImage3D                  = <div class='val'>%u</div></summary></details>\n", features->sparseResidencyImage3D                 );
   1654         fprintf(out, "\t\t\t\t\t\t<details><summary>sparseResidency2Samples                 = <div class='val'>%u</div></summary></details>\n", features->sparseResidency2Samples                );
   1655         fprintf(out, "\t\t\t\t\t\t<details><summary>sparseResidency4Samples                 = <div class='val'>%u</div></summary></details>\n", features->sparseResidency4Samples                );
   1656         fprintf(out, "\t\t\t\t\t\t<details><summary>sparseResidency8Samples                 = <div class='val'>%u</div></summary></details>\n", features->sparseResidency8Samples                );
   1657         fprintf(out, "\t\t\t\t\t\t<details><summary>sparseResidency16Samples                = <div class='val'>%u</div></summary></details>\n", features->sparseResidency16Samples               );
   1658         fprintf(out, "\t\t\t\t\t\t<details><summary>sparseResidencyAliased                  = <div class='val'>%u</div></summary></details>\n", features->sparseResidencyAliased                 );
   1659         fprintf(out, "\t\t\t\t\t\t<details><summary>variableMultisampleRate                 = <div class='val'>%u</div></summary></details>\n", features->variableMultisampleRate                );
   1660         fprintf(out, "\t\t\t\t\t\t<details><summary>inheritedQueries                        = <div class='val'>%u</div></summary></details>\n", features->inheritedQueries                       );
   1661         fprintf(out, "\t\t\t\t\t</details>\n");
   1662     } else {
   1663         printf("VkPhysicalDeviceFeatures:\n");
   1664         printf("=========================\n");
   1665         printf("\trobustBufferAccess                      = %u\n", features->robustBufferAccess                     );
   1666         printf("\tfullDrawIndexUint32                     = %u\n", features->fullDrawIndexUint32                    );
   1667         printf("\timageCubeArray                          = %u\n", features->imageCubeArray                         );
   1668         printf("\tindependentBlend                        = %u\n", features->independentBlend                       );
   1669         printf("\tgeometryShader                          = %u\n", features->geometryShader                         );
   1670         printf("\ttessellationShader                      = %u\n", features->tessellationShader                     );
   1671         printf("\tsampleRateShading                       = %u\n", features->sampleRateShading                      );
   1672         printf("\tdualSrcBlend                            = %u\n", features->dualSrcBlend                           );
   1673         printf("\tlogicOp                                 = %u\n", features->logicOp                                );
   1674         printf("\tmultiDrawIndirect                       = %u\n", features->multiDrawIndirect                      );
   1675         printf("\tdrawIndirectFirstInstance               = %u\n", features->drawIndirectFirstInstance              );
   1676         printf("\tdepthClamp                              = %u\n", features->depthClamp                             );
   1677         printf("\tdepthBiasClamp                          = %u\n", features->depthBiasClamp                         );
   1678         printf("\tfillModeNonSolid                        = %u\n", features->fillModeNonSolid                       );
   1679         printf("\tdepthBounds                             = %u\n", features->depthBounds                            );
   1680         printf("\twideLines                               = %u\n", features->wideLines                              );
   1681         printf("\tlargePoints                             = %u\n", features->largePoints                            );
   1682         printf("\talphaToOne                              = %u\n", features->alphaToOne                             );
   1683         printf("\tmultiViewport                           = %u\n", features->multiViewport                          );
   1684         printf("\tsamplerAnisotropy                       = %u\n", features->samplerAnisotropy                      );
   1685         printf("\ttextureCompressionETC2                  = %u\n", features->textureCompressionETC2                 );
   1686         printf("\ttextureCompressionASTC_LDR              = %u\n", features->textureCompressionASTC_LDR             );
   1687         printf("\ttextureCompressionBC                    = %u\n", features->textureCompressionBC                   );
   1688         printf("\tocclusionQueryPrecise                   = %u\n", features->occlusionQueryPrecise                  );
   1689         printf("\tpipelineStatisticsQuery                 = %u\n", features->pipelineStatisticsQuery                );
   1690         printf("\tvertexPipelineStoresAndAtomics          = %u\n", features->vertexPipelineStoresAndAtomics         );
   1691         printf("\tfragmentStoresAndAtomics                = %u\n", features->fragmentStoresAndAtomics               );
   1692         printf("\tshaderTessellationAndGeometryPointSize  = %u\n", features->shaderTessellationAndGeometryPointSize );
   1693         printf("\tshaderImageGatherExtended               = %u\n", features->shaderImageGatherExtended              );
   1694         printf("\tshaderStorageImageExtendedFormats       = %u\n", features->shaderStorageImageExtendedFormats      );
   1695         printf("\tshaderStorageImageMultisample           = %u\n", features->shaderStorageImageMultisample          );
   1696         printf("\tshaderStorageImageReadWithoutFormat     = %u\n", features->shaderStorageImageReadWithoutFormat    );
   1697         printf("\tshaderStorageImageWriteWithoutFormat    = %u\n", features->shaderStorageImageWriteWithoutFormat   );
   1698         printf("\tshaderUniformBufferArrayDynamicIndexing = %u\n", features->shaderUniformBufferArrayDynamicIndexing);
   1699         printf("\tshaderSampledImageArrayDynamicIndexing  = %u\n", features->shaderSampledImageArrayDynamicIndexing );
   1700         printf("\tshaderStorageBufferArrayDynamicIndexing = %u\n", features->shaderStorageBufferArrayDynamicIndexing);
   1701         printf("\tshaderStorageImageArrayDynamicIndexing  = %u\n", features->shaderStorageImageArrayDynamicIndexing );
   1702         printf("\tshaderClipDistance                      = %u\n", features->shaderClipDistance                     );
   1703         printf("\tshaderCullDistance                      = %u\n", features->shaderCullDistance                     );
   1704         printf("\tshaderFloat64                           = %u\n", features->shaderFloat64                          );
   1705         printf("\tshaderInt64                             = %u\n", features->shaderInt64                            );
   1706         printf("\tshaderInt16                             = %u\n", features->shaderInt16                            );
   1707         printf("\tshaderResourceResidency                 = %u\n", features->shaderResourceResidency                );
   1708         printf("\tshaderResourceMinLod                    = %u\n", features->shaderResourceMinLod                   );
   1709         printf("\tsparseBinding                           = %u\n", features->sparseBinding                          );
   1710         printf("\tsparseResidencyBuffer                   = %u\n", features->sparseResidencyBuffer                  );
   1711         printf("\tsparseResidencyImage2D                  = %u\n", features->sparseResidencyImage2D                 );
   1712         printf("\tsparseResidencyImage3D                  = %u\n", features->sparseResidencyImage3D                 );
   1713         printf("\tsparseResidency2Samples                 = %u\n", features->sparseResidency2Samples                );
   1714         printf("\tsparseResidency4Samples                 = %u\n", features->sparseResidency4Samples                );
   1715         printf("\tsparseResidency8Samples                 = %u\n", features->sparseResidency8Samples                );
   1716         printf("\tsparseResidency16Samples                = %u\n", features->sparseResidency16Samples               );
   1717         printf("\tsparseResidencyAliased                  = %u\n", features->sparseResidencyAliased                 );
   1718         printf("\tvariableMultisampleRate                 = %u\n", features->variableMultisampleRate                );
   1719         printf("\tinheritedQueries                        = %u\n", features->inheritedQueries                       );
   1720     }
   1721 }
   1722 
   1723 static void AppDumpSparseProps(const VkPhysicalDeviceSparseProperties *sparse_props, FILE *out) {
   1724     if (html_output) {
   1725         fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceSparseProperties</summary>\n");
   1726         fprintf(out, "\t\t\t\t\t\t<details><summary>residencyStandard2DBlockShape            = <div class='val'>%u</div></summary></details>\n", sparse_props->residencyStandard2DBlockShape           );
   1727         fprintf(out, "\t\t\t\t\t\t<details><summary>residencyStandard2DMultisampleBlockShape = <div class='val'>%u</div></summary></details>\n", sparse_props->residencyStandard2DMultisampleBlockShape);
   1728         fprintf(out, "\t\t\t\t\t\t<details><summary>residencyStandard3DBlockShape            = <div class='val'>%u</div></summary></details>\n", sparse_props->residencyStandard3DBlockShape           );
   1729         fprintf(out, "\t\t\t\t\t\t<details><summary>residencyAlignedMipSize                  = <div class='val'>%u</div></summary></details>\n", sparse_props->residencyAlignedMipSize                 );
   1730         fprintf(out, "\t\t\t\t\t\t<details><summary>residencyNonResidentStrict               = <div class='val'>%u</div></summary></details>\n", sparse_props->residencyNonResidentStrict              );
   1731         fprintf(out, "\t\t\t\t\t</details>\n");
   1732     } else {
   1733         printf("\tVkPhysicalDeviceSparseProperties:\n");
   1734         printf("\t---------------------------------\n");
   1735         printf("\t\tresidencyStandard2DBlockShape            = %u\n", sparse_props->residencyStandard2DBlockShape           );
   1736         printf("\t\tresidencyStandard2DMultisampleBlockShape = %u\n", sparse_props->residencyStandard2DMultisampleBlockShape);
   1737         printf("\t\tresidencyStandard3DBlockShape            = %u\n", sparse_props->residencyStandard3DBlockShape           );
   1738         printf("\t\tresidencyAlignedMipSize                  = %u\n", sparse_props->residencyAlignedMipSize                 );
   1739         printf("\t\tresidencyNonResidentStrict               = %u\n", sparse_props->residencyNonResidentStrict              );
   1740     }
   1741 }
   1742 
   1743 static void AppDumpLimits(const VkPhysicalDeviceLimits *limits, FILE *out) {
   1744     if (html_output) {
   1745         fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceLimits</summary>\n");
   1746         fprintf(out, "\t\t\t\t\t\t<details><summary>maxImageDimension1D                     = <div class='val'>%u</div></summary></details>\n",                 limits->maxImageDimension1D                    );
   1747         fprintf(out, "\t\t\t\t\t\t<details><summary>maxImageDimension2D                     = <div class='val'>%u</div></summary></details>\n",                 limits->maxImageDimension2D                    );
   1748         fprintf(out, "\t\t\t\t\t\t<details><summary>maxImageDimension3D                     = <div class='val'>%u</div></summary></details>\n",                 limits->maxImageDimension3D                    );
   1749         fprintf(out, "\t\t\t\t\t\t<details><summary>maxImageDimensionCube                   = <div class='val'>%u</div></summary></details>\n",                 limits->maxImageDimensionCube                  );
   1750         fprintf(out, "\t\t\t\t\t\t<details><summary>maxImageArrayLayers                     = <div class='val'>%u</div></summary></details>\n",                 limits->maxImageArrayLayers                    );
   1751         fprintf(out, "\t\t\t\t\t\t<details><summary>maxTexelBufferElements                  = <div class='val'>0x%" PRIxLEAST32 "</div></summary></details>\n", limits->maxTexelBufferElements                 );
   1752         fprintf(out, "\t\t\t\t\t\t<details><summary>maxUniformBufferRange                   = <div class='val'>0x%" PRIxLEAST32 "</div></summary></details>\n", limits->maxUniformBufferRange                  );
   1753         fprintf(out, "\t\t\t\t\t\t<details><summary>maxStorageBufferRange                   = <div class='val'>0x%" PRIxLEAST32 "</div></summary></details>\n", limits->maxStorageBufferRange                  );
   1754         fprintf(out, "\t\t\t\t\t\t<details><summary>maxPushConstantsSize                    = <div class='val'>%u</div></summary></details>\n",                 limits->maxPushConstantsSize                   );
   1755         fprintf(out, "\t\t\t\t\t\t<details><summary>maxMemoryAllocationCount                = <div class='val'>%u</div></summary></details>\n",                 limits->maxMemoryAllocationCount               );
   1756         fprintf(out, "\t\t\t\t\t\t<details><summary>maxSamplerAllocationCount               = <div class='val'>%u</div></summary></details>\n",                 limits->maxSamplerAllocationCount              );
   1757         fprintf(out, "\t\t\t\t\t\t<details><summary>bufferImageGranularity                  = <div class='val'>0x%" PRIxLEAST64 "</div></summary></details>\n", limits->bufferImageGranularity                 );
   1758         fprintf(out, "\t\t\t\t\t\t<details><summary>sparseAddressSpaceSize                  = <div class='val'>0x%" PRIxLEAST64 "</div></summary></details>\n", limits->sparseAddressSpaceSize                 );
   1759         fprintf(out, "\t\t\t\t\t\t<details><summary>maxBoundDescriptorSets                  = <div class='val'>%u</div></summary></details>\n",                 limits->maxBoundDescriptorSets                 );
   1760         fprintf(out, "\t\t\t\t\t\t<details><summary>maxPerStageDescriptorSamplers           = <div class='val'>%u</div></summary></details>\n",                 limits->maxPerStageDescriptorSamplers          );
   1761         fprintf(out, "\t\t\t\t\t\t<details><summary>maxPerStageDescriptorUniformBuffers     = <div class='val'>%u</div></summary></details>\n",                 limits->maxPerStageDescriptorUniformBuffers    );
   1762         fprintf(out, "\t\t\t\t\t\t<details><summary>maxPerStageDescriptorStorageBuffers     = <div class='val'>%u</div></summary></details>\n",                 limits->maxPerStageDescriptorStorageBuffers    );
   1763         fprintf(out, "\t\t\t\t\t\t<details><summary>maxPerStageDescriptorSampledImages      = <div class='val'>%u</div></summary></details>\n",                 limits->maxPerStageDescriptorSampledImages     );
   1764         fprintf(out, "\t\t\t\t\t\t<details><summary>maxPerStageDescriptorStorageImages      = <div class='val'>%u</div></summary></details>\n",                 limits->maxPerStageDescriptorStorageImages     );
   1765         fprintf(out, "\t\t\t\t\t\t<details><summary>maxPerStageDescriptorInputAttachments   = <div class='val'>%u</div></summary></details>\n",                 limits->maxPerStageDescriptorInputAttachments  );
   1766         fprintf(out, "\t\t\t\t\t\t<details><summary>maxPerStageResources                    = <div class='val'>%u</div></summary></details>\n",                 limits->maxPerStageResources                   );
   1767         fprintf(out, "\t\t\t\t\t\t<details><summary>maxDescriptorSetSamplers                = <div class='val'>%u</div></summary></details>\n",                 limits->maxDescriptorSetSamplers               );
   1768         fprintf(out, "\t\t\t\t\t\t<details><summary>maxDescriptorSetUniformBuffers          = <div class='val'>%u</div></summary></details>\n",                 limits->maxDescriptorSetUniformBuffers         );
   1769         fprintf(out, "\t\t\t\t\t\t<details><summary>maxDescriptorSetUniformBuffersDynamic   = <div class='val'>%u</div></summary></details>\n",                 limits->maxDescriptorSetUniformBuffersDynamic  );
   1770         fprintf(out, "\t\t\t\t\t\t<details><summary>maxDescriptorSetStorageBuffers          = <div class='val'>%u</div></summary></details>\n",                 limits->maxDescriptorSetStorageBuffers         );
   1771         fprintf(out, "\t\t\t\t\t\t<details><summary>maxDescriptorSetStorageBuffersDynamic   = <div class='val'>%u</div></summary></details>\n",                 limits->maxDescriptorSetStorageBuffersDynamic  );
   1772         fprintf(out, "\t\t\t\t\t\t<details><summary>maxDescriptorSetSampledImages           = <div class='val'>%u</div></summary></details>\n",                 limits->maxDescriptorSetSampledImages          );
   1773         fprintf(out, "\t\t\t\t\t\t<details><summary>maxDescriptorSetStorageImages           = <div class='val'>%u</div></summary></details>\n",                 limits->maxDescriptorSetStorageImages          );
   1774         fprintf(out, "\t\t\t\t\t\t<details><summary>maxDescriptorSetInputAttachments        = <div class='val'>%u</div></summary></details>\n",                 limits->maxDescriptorSetInputAttachments       );
   1775         fprintf(out, "\t\t\t\t\t\t<details><summary>maxVertexInputAttributes                = <div class='val'>%u</div></summary></details>\n",                 limits->maxVertexInputAttributes               );
   1776         fprintf(out, "\t\t\t\t\t\t<details><summary>maxVertexInputBindings                  = <div class='val'>%u</div></summary></details>\n",                 limits->maxVertexInputBindings                 );
   1777         fprintf(out, "\t\t\t\t\t\t<details><summary>maxVertexInputAttributeOffset           = <div class='val'>0x%" PRIxLEAST32 "</div></summary></details>\n", limits->maxVertexInputAttributeOffset          );
   1778         fprintf(out, "\t\t\t\t\t\t<details><summary>maxVertexInputBindingStride             = <div class='val'>0x%" PRIxLEAST32 "</div></summary></details>\n", limits->maxVertexInputBindingStride            );
   1779         fprintf(out, "\t\t\t\t\t\t<details><summary>maxVertexOutputComponents               = <div class='val'>%u</div></summary></details>\n",                 limits->maxVertexOutputComponents              );
   1780         fprintf(out, "\t\t\t\t\t\t<details><summary>maxTessellationGenerationLevel          = <div class='val'>%u</div></summary></details>\n",                 limits->maxTessellationGenerationLevel         );
   1781         fprintf(out, "\t\t\t\t\t\t<details><summary>maxTessellationPatchSize                        = <div class='val'>%u</div></summary></details>\n",                 limits->maxTessellationPatchSize                       );
   1782         fprintf(out, "\t\t\t\t\t\t<details><summary>maxTessellationControlPerVertexInputComponents  = <div class='val'>%u</div></summary></details>\n",                 limits->maxTessellationControlPerVertexInputComponents );
   1783         fprintf(out, "\t\t\t\t\t\t<details><summary>maxTessellationControlPerVertexOutputComponents = <div class='val'>%u</div></summary></details>\n",                 limits->maxTessellationControlPerVertexOutputComponents);
   1784         fprintf(out, "\t\t\t\t\t\t<details><summary>maxTessellationControlPerPatchOutputComponents  = <div class='val'>%u</div></summary></details>\n",                 limits->maxTessellationControlPerPatchOutputComponents );
   1785         fprintf(out, "\t\t\t\t\t\t<details><summary>maxTessellationControlTotalOutputComponents     = <div class='val'>%u</div></summary></details>\n",                 limits->maxTessellationControlTotalOutputComponents    );
   1786         fprintf(out, "\t\t\t\t\t\t<details><summary>maxTessellationEvaluationInputComponents        = <div class='val'>%u</div></summary></details>\n",                 limits->maxTessellationEvaluationInputComponents       );
   1787         fprintf(out, "\t\t\t\t\t\t<details><summary>maxTessellationEvaluationOutputComponents       = <div class='val'>%u</div></summary></details>\n",                 limits->maxTessellationEvaluationOutputComponents      );
   1788         fprintf(out, "\t\t\t\t\t\t<details><summary>maxGeometryShaderInvocations            = <div class='val'>%u</div></summary></details>\n",                 limits->maxGeometryShaderInvocations           );
   1789         fprintf(out, "\t\t\t\t\t\t<details><summary>maxGeometryInputComponents              = <div class='val'>%u</div></summary></details>\n",                 limits->maxGeometryInputComponents             );
   1790         fprintf(out, "\t\t\t\t\t\t<details><summary>maxGeometryOutputComponents             = <div class='val'>%u</div></summary></details>\n",                 limits->maxGeometryOutputComponents            );
   1791         fprintf(out, "\t\t\t\t\t\t<details><summary>maxGeometryOutputVertices               = <div class='val'>%u</div></summary></details>\n",                 limits->maxGeometryOutputVertices              );
   1792         fprintf(out, "\t\t\t\t\t\t<details><summary>maxGeometryTotalOutputComponents        = <div class='val'>%u</div></summary></details>\n",                 limits->maxGeometryTotalOutputComponents       );
   1793         fprintf(out, "\t\t\t\t\t\t<details><summary>maxFragmentInputComponents              = <div class='val'>%u</div></summary></details>\n",                 limits->maxFragmentInputComponents             );
   1794         fprintf(out, "\t\t\t\t\t\t<details><summary>maxFragmentOutputAttachments            = <div class='val'>%u</div></summary></details>\n",                 limits->maxFragmentOutputAttachments           );
   1795         fprintf(out, "\t\t\t\t\t\t<details><summary>maxFragmentDualSrcAttachments           = <div class='val'>%u</div></summary></details>\n",                 limits->maxFragmentDualSrcAttachments          );
   1796         fprintf(out, "\t\t\t\t\t\t<details><summary>maxFragmentCombinedOutputResources      = <div class='val'>%u</div></summary></details>\n",                 limits->maxFragmentCombinedOutputResources     );
   1797         fprintf(out, "\t\t\t\t\t\t<details><summary>maxComputeSharedMemorySize              = <div class='val'>0x%" PRIxLEAST32 "</div></summary></details>\n", limits->maxComputeSharedMemorySize             );
   1798         fprintf(out, "\t\t\t\t\t\t<details><summary>maxComputeWorkGroupCount[0]             = <div class='val'>%u</div></summary></details>\n",                 limits->maxComputeWorkGroupCount[0]            );
   1799         fprintf(out, "\t\t\t\t\t\t<details><summary>maxComputeWorkGroupCount[1]             = <div class='val'>%u</div></summary></details>\n",                 limits->maxComputeWorkGroupCount[1]            );
   1800         fprintf(out, "\t\t\t\t\t\t<details><summary>maxComputeWorkGroupCount[2]             = <div class='val'>%u</div></summary></details>\n",                 limits->maxComputeWorkGroupCount[2]            );
   1801         fprintf(out, "\t\t\t\t\t\t<details><summary>maxComputeWorkGroupInvocations          = <div class='val'>%u</div></summary></details>\n",                 limits->maxComputeWorkGroupInvocations         );
   1802         fprintf(out, "\t\t\t\t\t\t<details><summary>maxComputeWorkGroupSize[0]              = <div class='val'>%u</div></summary></details>\n",                 limits->maxComputeWorkGroupSize[0]             );
   1803         fprintf(out, "\t\t\t\t\t\t<details><summary>maxComputeWorkGroupSize[1]              = <div class='val'>%u</div></summary></details>\n",                 limits->maxComputeWorkGroupSize[1]             );
   1804         fprintf(out, "\t\t\t\t\t\t<details><summary>maxComputeWorkGroupSize[2]              = <div class='val'>%u</div></summary></details>\n",                 limits->maxComputeWorkGroupSize[2]             );
   1805         fprintf(out, "\t\t\t\t\t\t<details><summary>subPixelPrecisionBits                   = <div class='val'>%u</div></summary></details>\n",                 limits->subPixelPrecisionBits                  );
   1806         fprintf(out, "\t\t\t\t\t\t<details><summary>subTexelPrecisionBits                   = <div class='val'>%u</div></summary></details>\n",                 limits->subTexelPrecisionBits                  );
   1807         fprintf(out, "\t\t\t\t\t\t<details><summary>mipmapPrecisionBits                     = <div class='val'>%u</div></summary></details>\n",                 limits->mipmapPrecisionBits                    );
   1808         fprintf(out, "\t\t\t\t\t\t<details><summary>maxDrawIndexedIndexValue                = <div class='val'>%u</div></summary></details>\n",                 limits->maxDrawIndexedIndexValue               );
   1809         fprintf(out, "\t\t\t\t\t\t<details><summary>maxDrawIndirectCount                    = <div class='val'>%u</div></summary></details>\n",                 limits->maxDrawIndirectCount                   );
   1810         fprintf(out, "\t\t\t\t\t\t<details><summary>maxSamplerLodBias                       = <div class='val'>%f</div></summary></details>\n",                 limits->maxSamplerLodBias                      );
   1811         fprintf(out, "\t\t\t\t\t\t<details><summary>maxSamplerAnisotropy                    = <div class='val'>%f</div></summary></details>\n",                 limits->maxSamplerAnisotropy                   );
   1812         fprintf(out, "\t\t\t\t\t\t<details><summary>maxViewports                            = <div class='val'>%u</div></summary></details>\n",                 limits->maxViewports                           );
   1813         fprintf(out, "\t\t\t\t\t\t<details><summary>maxViewportDimensions[0]                = <div class='val'>%u</div></summary></details>\n",                 limits->maxViewportDimensions[0]               );
   1814         fprintf(out, "\t\t\t\t\t\t<details><summary>maxViewportDimensions[1]                = <div class='val'>%u</div></summary></details>\n",                 limits->maxViewportDimensions[1]               );
   1815         fprintf(out, "\t\t\t\t\t\t<details><summary>viewportBoundsRange[0]                  =<div class='val'>%13f</div></summary></details>\n",                 limits->viewportBoundsRange[0]                 );
   1816         fprintf(out, "\t\t\t\t\t\t<details><summary>viewportBoundsRange[1]                  =<div class='val'>%13f</div></summary></details>\n",                 limits->viewportBoundsRange[1]                 );
   1817         fprintf(out, "\t\t\t\t\t\t<details><summary>viewportSubPixelBits                    = <div class='val'>%u</div></summary></details>\n",                 limits->viewportSubPixelBits                   );
   1818         fprintf(out, "\t\t\t\t\t\t<details><summary>minMemoryMapAlignment                   = <div class='val'>" PRINTF_SIZE_T_SPECIFIER "</div></summary></details>\n", limits->minMemoryMapAlignment         );
   1819         fprintf(out, "\t\t\t\t\t\t<details><summary>minTexelBufferOffsetAlignment           = <div class='val'>0x%" PRIxLEAST64 "</div></summary></details>\n", limits->minTexelBufferOffsetAlignment          );
   1820         fprintf(out, "\t\t\t\t\t\t<details><summary>minUniformBufferOffsetAlignment         = <div class='val'>0x%" PRIxLEAST64 "</div></summary></details>\n", limits->minUniformBufferOffsetAlignment        );
   1821         fprintf(out, "\t\t\t\t\t\t<details><summary>minStorageBufferOffsetAlignment         = <div class='val'>0x%" PRIxLEAST64 "</div></summary></details>\n", limits->minStorageBufferOffsetAlignment        );
   1822         fprintf(out, "\t\t\t\t\t\t<details><summary>minTexelOffset                          =<div class='val'>%3d</div></summary></details>\n",                 limits->minTexelOffset                         );
   1823         fprintf(out, "\t\t\t\t\t\t<details><summary>maxTexelOffset                          =<div class='val'>%3d</div></summary></details>\n",                 limits->maxTexelOffset                         );
   1824         fprintf(out, "\t\t\t\t\t\t<details><summary>minTexelGatherOffset                    =<div class='val'>%3d</div></summary></details>\n",                 limits->minTexelGatherOffset                   );
   1825         fprintf(out, "\t\t\t\t\t\t<details><summary>maxTexelGatherOffset                    =<div class='val'>%3d</div></summary></details>\n",                 limits->maxTexelGatherOffset                   );
   1826         fprintf(out, "\t\t\t\t\t\t<details><summary>minInterpolationOffset                  =<div class='val'>%9f</div></summary></details>\n",                 limits->minInterpolationOffset                 );
   1827         fprintf(out, "\t\t\t\t\t\t<details><summary>maxInterpolationOffset                  =<div class='val'>%9f</div></summary></details>\n",                 limits->maxInterpolationOffset                 );
   1828         fprintf(out, "\t\t\t\t\t\t<details><summary>subPixelInterpolationOffsetBits         = <div class='val'>%u</div></summary></details>\n",                 limits->subPixelInterpolationOffsetBits        );
   1829         fprintf(out, "\t\t\t\t\t\t<details><summary>maxFramebufferWidth                     = <div class='val'>%u</div></summary></details>\n",                 limits->maxFramebufferWidth                    );
   1830         fprintf(out, "\t\t\t\t\t\t<details><summary>maxFramebufferHeight                    = <div class='val'>%u</div></summary></details>\n",                 limits->maxFramebufferHeight                   );
   1831         fprintf(out, "\t\t\t\t\t\t<details><summary>maxFramebufferLayers                    = <div class='val'>%u</div></summary></details>\n",                 limits->maxFramebufferLayers                   );
   1832         fprintf(out, "\t\t\t\t\t\t<details><summary>framebufferColorSampleCounts            = <div class='val'>%u</div></summary></details>\n",                 limits->framebufferColorSampleCounts           );
   1833         fprintf(out, "\t\t\t\t\t\t<details><summary>framebufferDepthSampleCounts            = <div class='val'>%u</div></summary></details>\n",                 limits->framebufferDepthSampleCounts           );
   1834         fprintf(out, "\t\t\t\t\t\t<details><summary>framebufferStencilSampleCounts          = <div class='val'>%u</div></summary></details>\n",                 limits->framebufferStencilSampleCounts         );
   1835         fprintf(out, "\t\t\t\t\t\t<details><summary>framebufferNoAttachmentsSampleCounts    = <div class='val'>%u</div></summary></details>\n",                 limits->framebufferNoAttachmentsSampleCounts   );
   1836         fprintf(out, "\t\t\t\t\t\t<details><summary>maxColorAttachments                     = <div class='val'>%u</div></summary></details>\n",                 limits->maxColorAttachments                    );
   1837         fprintf(out, "\t\t\t\t\t\t<details><summary>sampledImageColorSampleCounts           = <div class='val'>%u</div></summary></details>\n",                 limits->sampledImageColorSampleCounts          );
   1838         fprintf(out, "\t\t\t\t\t\t<details><summary>sampledImageDepthSampleCounts           = <div class='val'>%u</div></summary></details>\n",                 limits->sampledImageDepthSampleCounts          );
   1839         fprintf(out, "\t\t\t\t\t\t<details><summary>sampledImageStencilSampleCounts         = <div class='val'>%u</div></summary></details>\n",                 limits->sampledImageStencilSampleCounts        );
   1840         fprintf(out, "\t\t\t\t\t\t<details><summary>sampledImageIntegerSampleCounts         = <div class='val'>%u</div></summary></details>\n",                 limits->sampledImageIntegerSampleCounts        );
   1841         fprintf(out, "\t\t\t\t\t\t<details><summary>storageImageSampleCounts                = <div class='val'>%u</div></summary></details>\n",                 limits->storageImageSampleCounts               );
   1842         fprintf(out, "\t\t\t\t\t\t<details><summary>maxSampleMaskWords                      = <div class='val'>%u</div></summary></details>\n",                 limits->maxSampleMaskWords                     );
   1843         fprintf(out, "\t\t\t\t\t\t<details><summary>timestampComputeAndGraphics             = <div class='val'>%u</div></summary></details>\n",                 limits->timestampComputeAndGraphics            );
   1844         fprintf(out, "\t\t\t\t\t\t<details><summary>timestampPeriod                         = <div class='val'>%f</div></summary></details>\n",                 limits->timestampPeriod                        );
   1845         fprintf(out, "\t\t\t\t\t\t<details><summary>maxClipDistances                        = <div class='val'>%u</div></summary></details>\n",                 limits->maxClipDistances                       );
   1846         fprintf(out, "\t\t\t\t\t\t<details><summary>maxCullDistances                        = <div class='val'>%u</div></summary></details>\n",                 limits->maxCullDistances                       );
   1847         fprintf(out, "\t\t\t\t\t\t<details><summary>maxCombinedClipAndCullDistances         = <div class='val'>%u</div></summary></details>\n",                 limits->maxCombinedClipAndCullDistances        );
   1848         fprintf(out, "\t\t\t\t\t\t<details><summary>discreteQueuePriorities                 = <div class='val'>%u</div></summary></details>\n",                 limits->discreteQueuePriorities                );
   1849         fprintf(out, "\t\t\t\t\t\t<details><summary>pointSizeRange[0]                       = <div class='val'>%f</div></summary></details>\n",                 limits->pointSizeRange[0]                      );
   1850         fprintf(out, "\t\t\t\t\t\t<details><summary>pointSizeRange[1]                       = <div class='val'>%f</div></summary></details>\n",                 limits->pointSizeRange[1]                      );
   1851         fprintf(out, "\t\t\t\t\t\t<details><summary>lineWidthRange[0]                       = <div class='val'>%f</div></summary></details>\n",                 limits->lineWidthRange[0]                      );
   1852         fprintf(out, "\t\t\t\t\t\t<details><summary>lineWidthRange[1]                       = <div class='val'>%f</div></summary></details>\n",                 limits->lineWidthRange[1]                      );
   1853         fprintf(out, "\t\t\t\t\t\t<details><summary>pointSizeGranularity                    = <div class='val'>%f</div></summary></details>\n",                 limits->pointSizeGranularity                   );
   1854         fprintf(out, "\t\t\t\t\t\t<details><summary>lineWidthGranularity                    = <div class='val'>%f</div></summary></details>\n",                 limits->lineWidthGranularity                   );
   1855         fprintf(out, "\t\t\t\t\t\t<details><summary>strictLines                             = <div class='val'>%u</div></summary></details>\n",                 limits->strictLines                            );
   1856         fprintf(out, "\t\t\t\t\t\t<details><summary>standardSampleLocations                 = <div class='val'>%u</div></summary></details>\n",                 limits->standardSampleLocations                );
   1857         fprintf(out, "\t\t\t\t\t\t<details><summary>optimalBufferCopyOffsetAlignment        = <div class='val'>0x%" PRIxLEAST64 "</div></summary></details>\n", limits->optimalBufferCopyOffsetAlignment       );
   1858         fprintf(out, "\t\t\t\t\t\t<details><summary>optimalBufferCopyRowPitchAlignment      = <div class='val'>0x%" PRIxLEAST64 "</div></summary></details>\n", limits->optimalBufferCopyRowPitchAlignment     );
   1859         fprintf(out, "\t\t\t\t\t\t<details><summary>nonCoherentAtomSize                     = <div class='val'>0x%" PRIxLEAST64 "</div></summary></details>\n", limits->nonCoherentAtomSize                    );
   1860         fprintf(out, "\t\t\t\t\t</details>\n");
   1861     } else {
   1862         printf("\tVkPhysicalDeviceLimits:\n");
   1863         printf("\t-----------------------\n");
   1864         printf("\t\tmaxImageDimension1D                     = %u\n",                 limits->maxImageDimension1D                    );
   1865         printf("\t\tmaxImageDimension2D                     = %u\n",                 limits->maxImageDimension2D                    );
   1866         printf("\t\tmaxImageDimension3D                     = %u\n",                 limits->maxImageDimension3D                    );
   1867         printf("\t\tmaxImageDimensionCube                   = %u\n",                 limits->maxImageDimensionCube                  );
   1868         printf("\t\tmaxImageArrayLayers                     = %u\n",                 limits->maxImageArrayLayers                    );
   1869         printf("\t\tmaxTexelBufferElements                  = 0x%" PRIxLEAST32 "\n", limits->maxTexelBufferElements                 );
   1870         printf("\t\tmaxUniformBufferRange                   = 0x%" PRIxLEAST32 "\n", limits->maxUniformBufferRange                  );
   1871         printf("\t\tmaxStorageBufferRange                   = 0x%" PRIxLEAST32 "\n", limits->maxStorageBufferRange                  );
   1872         printf("\t\tmaxPushConstantsSize                    = %u\n",                 limits->maxPushConstantsSize                   );
   1873         printf("\t\tmaxMemoryAllocationCount                = %u\n",                 limits->maxMemoryAllocationCount               );
   1874         printf("\t\tmaxSamplerAllocationCount               = %u\n",                 limits->maxSamplerAllocationCount              );
   1875         printf("\t\tbufferImageGranularity                  = 0x%" PRIxLEAST64 "\n", limits->bufferImageGranularity                 );
   1876         printf("\t\tsparseAddressSpaceSize                  = 0x%" PRIxLEAST64 "\n", limits->sparseAddressSpaceSize                 );
   1877         printf("\t\tmaxBoundDescriptorSets                  = %u\n",                 limits->maxBoundDescriptorSets                 );
   1878         printf("\t\tmaxPerStageDescriptorSamplers           = %u\n",                 limits->maxPerStageDescriptorSamplers          );
   1879         printf("\t\tmaxPerStageDescriptorUniformBuffers     = %u\n",                 limits->maxPerStageDescriptorUniformBuffers    );
   1880         printf("\t\tmaxPerStageDescriptorStorageBuffers     = %u\n",                 limits->maxPerStageDescriptorStorageBuffers    );
   1881         printf("\t\tmaxPerStageDescriptorSampledImages      = %u\n",                 limits->maxPerStageDescriptorSampledImages     );
   1882         printf("\t\tmaxPerStageDescriptorStorageImages      = %u\n",                 limits->maxPerStageDescriptorStorageImages     );
   1883         printf("\t\tmaxPerStageDescriptorInputAttachments   = %u\n",                 limits->maxPerStageDescriptorInputAttachments  );
   1884         printf("\t\tmaxPerStageResources                    = %u\n",                 limits->maxPerStageResources                   );
   1885         printf("\t\tmaxDescriptorSetSamplers                = %u\n",                 limits->maxDescriptorSetSamplers               );
   1886         printf("\t\tmaxDescriptorSetUniformBuffers          = %u\n",                 limits->maxDescriptorSetUniformBuffers         );
   1887         printf("\t\tmaxDescriptorSetUniformBuffersDynamic   = %u\n",                 limits->maxDescriptorSetUniformBuffersDynamic  );
   1888         printf("\t\tmaxDescriptorSetStorageBuffers          = %u\n",                 limits->maxDescriptorSetStorageBuffers         );
   1889         printf("\t\tmaxDescriptorSetStorageBuffersDynamic   = %u\n",                 limits->maxDescriptorSetStorageBuffersDynamic  );
   1890         printf("\t\tmaxDescriptorSetSampledImages           = %u\n",                 limits->maxDescriptorSetSampledImages          );
   1891         printf("\t\tmaxDescriptorSetStorageImages           = %u\n",                 limits->maxDescriptorSetStorageImages          );
   1892         printf("\t\tmaxDescriptorSetInputAttachments        = %u\n",                 limits->maxDescriptorSetInputAttachments       );
   1893         printf("\t\tmaxVertexInputAttributes                = %u\n",                 limits->maxVertexInputAttributes               );
   1894         printf("\t\tmaxVertexInputBindings                  = %u\n",                 limits->maxVertexInputBindings                 );
   1895         printf("\t\tmaxVertexInputAttributeOffset           = 0x%" PRIxLEAST32 "\n", limits->maxVertexInputAttributeOffset          );
   1896         printf("\t\tmaxVertexInputBindingStride             = 0x%" PRIxLEAST32 "\n", limits->maxVertexInputBindingStride            );
   1897         printf("\t\tmaxVertexOutputComponents               = %u\n",                 limits->maxVertexOutputComponents              );
   1898         printf("\t\tmaxTessellationGenerationLevel          = %u\n",                 limits->maxTessellationGenerationLevel         );
   1899         printf("\t\tmaxTessellationPatchSize                        = %u\n",                 limits->maxTessellationPatchSize                       );
   1900         printf("\t\tmaxTessellationControlPerVertexInputComponents  = %u\n",                 limits->maxTessellationControlPerVertexInputComponents );
   1901         printf("\t\tmaxTessellationControlPerVertexOutputComponents = %u\n",                 limits->maxTessellationControlPerVertexOutputComponents);
   1902         printf("\t\tmaxTessellationControlPerPatchOutputComponents  = %u\n",                 limits->maxTessellationControlPerPatchOutputComponents );
   1903         printf("\t\tmaxTessellationControlTotalOutputComponents     = %u\n",                 limits->maxTessellationControlTotalOutputComponents    );
   1904         printf("\t\tmaxTessellationEvaluationInputComponents        = %u\n",                 limits->maxTessellationEvaluationInputComponents       );
   1905         printf("\t\tmaxTessellationEvaluationOutputComponents       = %u\n",                 limits->maxTessellationEvaluationOutputComponents      );
   1906         printf("\t\tmaxGeometryShaderInvocations            = %u\n",                 limits->maxGeometryShaderInvocations           );
   1907         printf("\t\tmaxGeometryInputComponents              = %u\n",                 limits->maxGeometryInputComponents             );
   1908         printf("\t\tmaxGeometryOutputComponents             = %u\n",                 limits->maxGeometryOutputComponents            );
   1909         printf("\t\tmaxGeometryOutputVertices               = %u\n",                 limits->maxGeometryOutputVertices              );
   1910         printf("\t\tmaxGeometryTotalOutputComponents        = %u\n",                 limits->maxGeometryTotalOutputComponents       );
   1911         printf("\t\tmaxFragmentInputComponents              = %u\n",                 limits->maxFragmentInputComponents             );
   1912         printf("\t\tmaxFragmentOutputAttachments            = %u\n",                 limits->maxFragmentOutputAttachments           );
   1913         printf("\t\tmaxFragmentDualSrcAttachments           = %u\n",                 limits->maxFragmentDualSrcAttachments          );
   1914         printf("\t\tmaxFragmentCombinedOutputResources      = %u\n",                 limits->maxFragmentCombinedOutputResources     );
   1915         printf("\t\tmaxComputeSharedMemorySize              = 0x%" PRIxLEAST32 "\n", limits->maxComputeSharedMemorySize             );
   1916         printf("\t\tmaxComputeWorkGroupCount[0]             = %u\n",                 limits->maxComputeWorkGroupCount[0]            );
   1917         printf("\t\tmaxComputeWorkGroupCount[1]             = %u\n",                 limits->maxComputeWorkGroupCount[1]            );
   1918         printf("\t\tmaxComputeWorkGroupCount[2]             = %u\n",                 limits->maxComputeWorkGroupCount[2]            );
   1919         printf("\t\tmaxComputeWorkGroupInvocations          = %u\n",                 limits->maxComputeWorkGroupInvocations         );
   1920         printf("\t\tmaxComputeWorkGroupSize[0]              = %u\n",                 limits->maxComputeWorkGroupSize[0]             );
   1921         printf("\t\tmaxComputeWorkGroupSize[1]              = %u\n",                 limits->maxComputeWorkGroupSize[1]             );
   1922         printf("\t\tmaxComputeWorkGroupSize[2]              = %u\n",                 limits->maxComputeWorkGroupSize[2]             );
   1923         printf("\t\tsubPixelPrecisionBits                   = %u\n",                 limits->subPixelPrecisionBits                  );
   1924         printf("\t\tsubTexelPrecisionBits                   = %u\n",                 limits->subTexelPrecisionBits                  );
   1925         printf("\t\tmipmapPrecisionBits                     = %u\n",                 limits->mipmapPrecisionBits                    );
   1926         printf("\t\tmaxDrawIndexedIndexValue                = %u\n",                 limits->maxDrawIndexedIndexValue               );
   1927         printf("\t\tmaxDrawIndirectCount                    = %u\n",                 limits->maxDrawIndirectCount                   );
   1928         printf("\t\tmaxSamplerLodBias                       = %f\n",                 limits->maxSamplerLodBias                      );
   1929         printf("\t\tmaxSamplerAnisotropy                    = %f\n",                 limits->maxSamplerAnisotropy                   );
   1930         printf("\t\tmaxViewports                            = %u\n",                 limits->maxViewports                           );
   1931         printf("\t\tmaxViewportDimensions[0]                = %u\n",                 limits->maxViewportDimensions[0]               );
   1932         printf("\t\tmaxViewportDimensions[1]                = %u\n",                 limits->maxViewportDimensions[1]               );
   1933         printf("\t\tviewportBoundsRange[0]                  =%13f\n",                limits->viewportBoundsRange[0]                 );
   1934         printf("\t\tviewportBoundsRange[1]                  =%13f\n",                limits->viewportBoundsRange[1]                 );
   1935         printf("\t\tviewportSubPixelBits                    = %u\n",                 limits->viewportSubPixelBits                   );
   1936         printf("\t\tminMemoryMapAlignment                   = " PRINTF_SIZE_T_SPECIFIER "\n", limits->minMemoryMapAlignment         );
   1937         printf("\t\tminTexelBufferOffsetAlignment           = 0x%" PRIxLEAST64 "\n", limits->minTexelBufferOffsetAlignment          );
   1938         printf("\t\tminUniformBufferOffsetAlignment         = 0x%" PRIxLEAST64 "\n", limits->minUniformBufferOffsetAlignment        );
   1939         printf("\t\tminStorageBufferOffsetAlignment         = 0x%" PRIxLEAST64 "\n", limits->minStorageBufferOffsetAlignment        );
   1940         printf("\t\tminTexelOffset                          =%3d\n",                 limits->minTexelOffset                         );
   1941         printf("\t\tmaxTexelOffset                          =%3d\n",                 limits->maxTexelOffset                         );
   1942         printf("\t\tminTexelGatherOffset                    =%3d\n",                 limits->minTexelGatherOffset                   );
   1943         printf("\t\tmaxTexelGatherOffset                    =%3d\n",                 limits->maxTexelGatherOffset                   );
   1944         printf("\t\tminInterpolationOffset                  =%9f\n",                 limits->minInterpolationOffset                 );
   1945         printf("\t\tmaxInterpolationOffset                  =%9f\n",                 limits->maxInterpolationOffset                 );
   1946         printf("\t\tsubPixelInterpolationOffsetBits         = %u\n",                 limits->subPixelInterpolationOffsetBits        );
   1947         printf("\t\tmaxFramebufferWidth                     = %u\n",                 limits->maxFramebufferWidth                    );
   1948         printf("\t\tmaxFramebufferHeight                    = %u\n",                 limits->maxFramebufferHeight                   );
   1949         printf("\t\tmaxFramebufferLayers                    = %u\n",                 limits->maxFramebufferLayers                   );
   1950         printf("\t\tframebufferColorSampleCounts            = %u\n",                 limits->framebufferColorSampleCounts           );
   1951         printf("\t\tframebufferDepthSampleCounts            = %u\n",                 limits->framebufferDepthSampleCounts           );
   1952         printf("\t\tframebufferStencilSampleCounts          = %u\n",                 limits->framebufferStencilSampleCounts         );
   1953         printf("\t\tframebufferNoAttachmentsSampleCounts    = %u\n",                 limits->framebufferNoAttachmentsSampleCounts   );
   1954         printf("\t\tmaxColorAttachments                     = %u\n",                 limits->maxColorAttachments                    );
   1955         printf("\t\tsampledImageColorSampleCounts           = %u\n",                 limits->sampledImageColorSampleCounts          );
   1956         printf("\t\tsampledImageDepthSampleCounts           = %u\n",                 limits->sampledImageDepthSampleCounts          );
   1957         printf("\t\tsampledImageStencilSampleCounts         = %u\n",                 limits->sampledImageStencilSampleCounts        );
   1958         printf("\t\tsampledImageIntegerSampleCounts         = %u\n",                 limits->sampledImageIntegerSampleCounts        );
   1959         printf("\t\tstorageImageSampleCounts                = %u\n",                 limits->storageImageSampleCounts               );
   1960         printf("\t\tmaxSampleMaskWords                      = %u\n",                 limits->maxSampleMaskWords                     );
   1961         printf("\t\ttimestampComputeAndGraphics             = %u\n",                 limits->timestampComputeAndGraphics            );
   1962         printf("\t\ttimestampPeriod                         = %f\n",                 limits->timestampPeriod                        );
   1963         printf("\t\tmaxClipDistances                        = %u\n",                 limits->maxClipDistances                       );
   1964         printf("\t\tmaxCullDistances                        = %u\n",                 limits->maxCullDistances                       );
   1965         printf("\t\tmaxCombinedClipAndCullDistances         = %u\n",                 limits->maxCombinedClipAndCullDistances        );
   1966         printf("\t\tdiscreteQueuePriorities                 = %u\n",                 limits->discreteQueuePriorities                );
   1967         printf("\t\tpointSizeRange[0]                       = %f\n",                 limits->pointSizeRange[0]                      );
   1968         printf("\t\tpointSizeRange[1]                       = %f\n",                 limits->pointSizeRange[1]                      );
   1969         printf("\t\tlineWidthRange[0]                       = %f\n",                 limits->lineWidthRange[0]                      );
   1970         printf("\t\tlineWidthRange[1]                       = %f\n",                 limits->lineWidthRange[1]                      );
   1971         printf("\t\tpointSizeGranularity                    = %f\n",                 limits->pointSizeGranularity                   );
   1972         printf("\t\tlineWidthGranularity                    = %f\n",                 limits->lineWidthGranularity                   );
   1973         printf("\t\tstrictLines                             = %u\n",                 limits->strictLines                            );
   1974         printf("\t\tstandardSampleLocations                 = %u\n",                 limits->standardSampleLocations                );
   1975         printf("\t\toptimalBufferCopyOffsetAlignment        = 0x%" PRIxLEAST64 "\n", limits->optimalBufferCopyOffsetAlignment       );
   1976         printf("\t\toptimalBufferCopyRowPitchAlignment      = 0x%" PRIxLEAST64 "\n", limits->optimalBufferCopyRowPitchAlignment     );
   1977         printf("\t\tnonCoherentAtomSize                     = 0x%" PRIxLEAST64 "\n", limits->nonCoherentAtomSize                    );
   1978     }
   1979 }
   1980 
   1981 static void AppGpuDumpProps(const struct AppGpu *gpu, FILE *out) {
   1982     const VkPhysicalDeviceProperties *props = &gpu->props;
   1983     const uint32_t apiVersion=props->apiVersion;
   1984     const uint32_t major = VK_VERSION_MAJOR(apiVersion);
   1985     const uint32_t minor = VK_VERSION_MINOR(apiVersion);
   1986     const uint32_t patch = VK_VERSION_PATCH(apiVersion);
   1987 
   1988     if (html_output) {
   1989         fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceProperties</summary>\n");
   1990         fprintf(out, "\t\t\t\t\t\t<details><summary>apiVersion = <div class='val'>0x%" PRIxLEAST32 "</div>  (<div class='val'>%d.%d.%d</div>)</summary></details>\n", apiVersion, major, minor, patch);
   1991         fprintf(out, "\t\t\t\t\t\t<details><summary>driverVersion = <div class='val'>%u</div> (<div class='val'>0x%" PRIxLEAST32 "</div>)</summary></details>\n", props->driverVersion, props->driverVersion);
   1992         fprintf(out, "\t\t\t\t\t\t<details><summary>vendorID = <div class='val'>0x%04x</div></summary></details>\n", props->vendorID);
   1993         fprintf(out, "\t\t\t\t\t\t<details><summary>deviceID = <div class='val'>0x%04x</div></summary></details>\n", props->deviceID);
   1994         fprintf(out, "\t\t\t\t\t\t<details><summary>deviceType = %s</summary></details>\n", VkPhysicalDeviceTypeString(props->deviceType));
   1995         fprintf(out, "\t\t\t\t\t\t<details><summary>deviceName = %s</summary></details>\n", props->deviceName);
   1996     } else {
   1997         printf("VkPhysicalDeviceProperties:\n");
   1998         printf("===========================\n");
   1999         printf("\tapiVersion     = 0x%" PRIxLEAST32 "  (%d.%d.%d)\n", apiVersion, major, minor, patch);
   2000         printf("\tdriverVersion  = %u (0x%" PRIxLEAST32 ")\n", props->driverVersion, props->driverVersion);
   2001         printf("\tvendorID       = 0x%04x\n", props->vendorID);
   2002         printf("\tdeviceID       = 0x%04x\n", props->deviceID);
   2003         printf("\tdeviceType     = %s\n", VkPhysicalDeviceTypeString(props->deviceType));
   2004         printf("\tdeviceName     = %s\n", props->deviceName);
   2005     }
   2006     if (html_output) fprintf(out, "\t\t\t\t\t</details>\n");
   2007 
   2008     AppDumpLimits(&gpu->props.limits, out);
   2009     AppDumpSparseProps(&gpu->props.sparseProperties, out);
   2010 
   2011     fflush(out);
   2012 }
   2013 
   2014 static void AppDumpExtensions(const char *indent, const char *layer_name, const uint32_t extension_count,
   2015                               const VkExtensionProperties *extension_properties, FILE *out) {
   2016     uint32_t i;
   2017 
   2018     if (html_output) fprintf(out, "\t\t\t%s<details><summary>", indent);
   2019     if (layer_name && (strlen(layer_name) > 0)) {
   2020         if (html_output) {
   2021             fprintf(out, "%s Extensions", layer_name);
   2022         } else {
   2023             printf("%s%s Extensions", indent, layer_name);
   2024         }
   2025     } else {
   2026         fprintf(out, "%sExtensions", indent);
   2027     }
   2028     if (html_output) {
   2029         fprintf(out, "\tcount = <div class='val'>%d</div></summary>", extension_count);
   2030         if (extension_count > 0) fprintf(out, "\n");
   2031     } else {
   2032         printf("\tcount = %d\n", extension_count);
   2033     }
   2034 
   2035     for (i = 0; i < extension_count; i++) {
   2036         VkExtensionProperties const *ext_prop = &extension_properties[i];
   2037 
   2038         if (html_output) {
   2039             fprintf(out, "\t\t\t\t%s<details><summary>", indent);
   2040             fprintf(out, "<div class='type'>%s</div>: extension revision <div class='val'>%d</div>", ext_prop->extensionName,
   2041                     ext_prop->specVersion);
   2042             fprintf(out, "</summary></details>\n");
   2043         } else {
   2044             printf("%s\t", indent);
   2045             printf("%-36s: extension revision %2d\n", ext_prop->extensionName, ext_prop->specVersion);
   2046         }
   2047     }
   2048     if (html_output) {
   2049         if (extension_count > 0) {
   2050             fprintf(out, "\t\t\t%s</details>\n", indent);
   2051         } else {
   2052             fprintf(out, "</details>\n");
   2053         }
   2054     }
   2055 
   2056     fflush(out);
   2057 }
   2058 
   2059 static void AppGpuDumpQueueProps(const struct AppGpu *gpu, uint32_t id, FILE *out) {
   2060     const VkQueueFamilyProperties *props = &gpu->queue_props[id];
   2061 
   2062     if (html_output) {
   2063         fprintf(out, "\t\t\t\t\t<details><summary>VkQueueFamilyProperties[<div class='val'>%d</div>]</summary>\n", id);
   2064         fprintf(out, "\t\t\t\t\t\t<details><summary>queueFlags = ");
   2065     } else {
   2066         printf("VkQueueFamilyProperties[%d]:\n", id);
   2067         printf("===========================\n");
   2068         printf("\tqueueFlags         = ");
   2069     }
   2070 
   2071     char *sep = "";  // separator character
   2072     if (props->queueFlags & VK_QUEUE_GRAPHICS_BIT) {
   2073         fprintf(out, "GRAPHICS");
   2074         sep = " | ";
   2075     }
   2076     if (props->queueFlags & VK_QUEUE_COMPUTE_BIT) {
   2077         fprintf(out, "%sCOMPUTE", sep);
   2078         sep = " | ";
   2079     }
   2080     if (props->queueFlags & VK_QUEUE_TRANSFER_BIT) {
   2081         fprintf(out, "%sTRANSFER", sep);
   2082         sep = " | ";
   2083     }
   2084     if (props->queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) {
   2085         fprintf(out, "%sSPARSE", sep);
   2086     }
   2087     if (html_output) {
   2088         fprintf(out, "</summary></details>\n");
   2089         fprintf(out, "\t\t\t\t\t\t<details><summary>queueCount         = <div class='val'>%u</div></summary></details>\n", props->queueCount);
   2090         fprintf(out, "\t\t\t\t\t\t<details><summary>timestampValidBits = <div class='val'>%u</div></summary></details>\n", props->timestampValidBits);
   2091         fprintf(out, "\t\t\t\t\t\t<details><summary>minImageTransferGranularity = (<div class='val'>%d</div>, <div class='val'>%d</div>, <div class='val'>%d</div>)</summary></details>\n", props->minImageTransferGranularity.width,
   2092                 props->minImageTransferGranularity.height, props->minImageTransferGranularity.depth);
   2093         fprintf(out, "\t\t\t\t\t</details>\n");
   2094     } else {
   2095         printf("\n");
   2096         printf("\tqueueCount         = %u\n", props->queueCount);
   2097         printf("\ttimestampValidBits = %u\n", props->timestampValidBits);
   2098         printf("\tminImageTransferGranularity = (%d, %d, %d)\n", props->minImageTransferGranularity.width,
   2099                props->minImageTransferGranularity.height, props->minImageTransferGranularity.depth);
   2100     }
   2101 
   2102     fflush(out);
   2103 }
   2104 
   2105 // This prints a number of bytes in a human-readable format according to prefixes of the International System of Quantities (ISQ),
   2106 // defined in ISO/IEC 80000. The prefixes used here are not SI prefixes, but rather the binary prefixes based on powers of 1024
   2107 // (kibi-, mebi-, gibi- etc.).
   2108 #define kBufferSize 32
   2109 
   2110 static char *HumanReadable(const size_t sz) {
   2111     const char prefixes[] = "KMGTPEZY";
   2112     char buf[kBufferSize];
   2113     int which = -1;
   2114     double result = (double)sz;
   2115     while (result > 1024 && which < 7) {
   2116         result /= 1024;
   2117         ++which;
   2118     }
   2119 
   2120     char unit[] = "\0i";
   2121     if (which >= 0) {
   2122         unit[0] = prefixes[which];
   2123     }
   2124     snprintf(buf, kBufferSize, "%.2f %sB", result, unit);
   2125     return strndup(buf, kBufferSize);
   2126 }
   2127 
   2128 static void AppGpuDumpMemoryProps(const struct AppGpu *gpu, FILE *out) {
   2129     const VkPhysicalDeviceMemoryProperties *props = &gpu->memory_props;
   2130 
   2131     if (html_output) {
   2132         fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceMemoryProperties</summary>\n");
   2133         fprintf(out, "\t\t\t\t\t\t<details><summary>memoryTypeCount = <div class='val'>%u</div></summary>", props->memoryTypeCount);
   2134         if (props->memoryTypeCount > 0) {
   2135             fprintf(out, "\n");
   2136         } else {
   2137             fprintf(out, "</details>\n");
   2138         }
   2139     } else {
   2140         printf("VkPhysicalDeviceMemoryProperties:\n");
   2141         printf("=================================\n");
   2142         printf("\tmemoryTypeCount       = %u\n", props->memoryTypeCount);
   2143     }
   2144     for (uint32_t i = 0; i < props->memoryTypeCount; i++) {
   2145         if (html_output) {
   2146             fprintf(out, "\t\t\t\t\t\t\t<details><summary>memoryTypes[<div class='val'>%u</div>]</summary>\n", i);
   2147             fprintf(out, "\t\t\t\t\t\t\t\t<details><summary>heapIndex = <div class='val'>%u</div></summary></summary></details>\n", props->memoryTypes[i].heapIndex);
   2148             fprintf(out, "\t\t\t\t\t\t\t\t<details open><summary>propertyFlags = <div class='val'>0x%" PRIxLEAST32 "</div></summary>", props->memoryTypes[i].propertyFlags);
   2149             if (props->memoryTypes[i].propertyFlags == 0) {
   2150                 fprintf(out, "</details>\n");
   2151             } else {
   2152                 fprintf(out, "\n");
   2153             }
   2154         } else {
   2155             printf("\tmemoryTypes[%u] :\n", i);
   2156             printf("\t\theapIndex     = %u\n", props->memoryTypes[i].heapIndex);
   2157             printf("\t\tpropertyFlags = 0x%" PRIxLEAST32 ":\n", props->memoryTypes[i].propertyFlags);
   2158         }
   2159 
   2160         // Print each named flag, if it is set
   2161         VkFlags flags = props->memoryTypes[i].propertyFlags;
   2162         if (html_output) {
   2163             if (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { fprintf(out, "\t\t\t\t\t\t\t\t\t<details><summary><div class='type'>VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT</div></summary></details>\n");  }
   2164             if (flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { fprintf(out, "\t\t\t\t\t\t\t\t\t<details><summary><div class='type'>VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT</div></summary></details>\n");  }
   2165             if (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { fprintf(out, "\t\t\t\t\t\t\t\t\t<details><summary><div class='type'>VK_MEMORY_PROPERTY_HOST_COHERENT_BIT</div></summary></details>\n"); }
   2166             if (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { fprintf(out, "\t\t\t\t\t\t\t\t\t<details><summary><div class='type'>VK_MEMORY_PROPERTY_HOST_CACHED_BIT</div></summary></details>\n"); }
   2167             if (flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) { fprintf(out, "\t\t\t\t\t\t\t\t\t<details><summary><div class='type'>VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT</div></summary></details>\n"); }
   2168             if (props->memoryTypes[i].propertyFlags > 0) fprintf(out, "\t\t\t\t\t\t\t\t</details>\n");
   2169             fprintf(out, "\t\t\t\t\t\t\t</details>\n");
   2170         } else {
   2171             if (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { printf("\t\t\tVK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT\n"); }
   2172             if (flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { printf("\t\t\tVK_MEMORY_PROPERTY_HOST_VISIBLE_BIT\n"); }
   2173             if (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) { printf("\t\t\tVK_MEMORY_PROPERTY_HOST_COHERENT_BIT\n"); }
   2174             if (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { printf("\t\t\tVK_MEMORY_PROPERTY_HOST_CACHED_BIT\n"); }
   2175             if (flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) { printf("\t\t\tVK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT\n"); }
   2176         }
   2177     }
   2178 
   2179     if (html_output && props->memoryTypeCount > 0) {
   2180         fprintf(out, "\t\t\t\t\t\t</details>\n");
   2181     }
   2182 
   2183     if (html_output) {
   2184         fprintf(out, "\t\t\t\t\t\t<details><summary>memoryHeapCount = <div class='val'>%u</div></summary>", props->memoryHeapCount);
   2185         if (props->memoryTypeCount > 0) fprintf(out, "\n");
   2186     } else {
   2187         printf("\tmemoryHeapCount       = %u\n", props->memoryHeapCount);
   2188     }
   2189     for (uint32_t i = 0; i < props->memoryHeapCount; i++) {
   2190         const VkDeviceSize memSize = props->memoryHeaps[i].size;
   2191         char *mem_size_human_readable = HumanReadable((const size_t)memSize);
   2192 
   2193         if (html_output) {
   2194             fprintf(out, "\t\t\t\t\t\t\t<details><summary>memoryHeaps[<div class='val'>%u</div>]</summary>\n", i);
   2195             fprintf(out, "\t\t\t\t\t\t\t\t<details><summary>size = <div class='val'>" PRINTF_SIZE_T_SPECIFIER "</div> (<div class='val'>0x%" PRIxLEAST64 "</div>) (<div class='val'>%s</div>)</summary></details>\n",
   2196                     (size_t)memSize, memSize, mem_size_human_readable);
   2197         } else {
   2198             printf("\tmemoryHeaps[%u] :\n", i);
   2199             printf("\t\tsize          = " PRINTF_SIZE_T_SPECIFIER " (0x%" PRIxLEAST64 ") (%s)\n", (size_t)memSize, memSize,
   2200                    mem_size_human_readable);
   2201         }
   2202         free(mem_size_human_readable);
   2203 
   2204         VkMemoryHeapFlags heap_flags = props->memoryHeaps[i].flags;
   2205         if (html_output) {
   2206             fprintf(out, "\t\t\t\t\t\t\t\t<details open><summary>flags</summary>\n");
   2207             fprintf(out, "\t\t\t\t\t\t\t\t\t<details><summary>");
   2208             fprintf(out, (heap_flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) ? "<div class='type'>VK_MEMORY_HEAP_DEVICE_LOCAL_BIT</div>" : "None");
   2209             fprintf(out, "</summary></details>\n");
   2210             fprintf(out, "\t\t\t\t\t\t\t\t</details>\n");
   2211             fprintf(out, "\t\t\t\t\t\t\t</details>\n");
   2212         } else {
   2213             printf("\t\tflags:\n\t\t\t");
   2214             printf((heap_flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) ? "VK_MEMORY_HEAP_DEVICE_LOCAL_BIT\n" : "None\n");
   2215         }
   2216     }
   2217 
   2218     if (html_output) {
   2219         fprintf(out, "\t\t\t\t\t\t</details>\n");
   2220         fprintf(out, "\t\t\t\t\t</details>\n");
   2221     }
   2222 
   2223     fflush(out);
   2224 }
   2225 // clang-format on
   2226 
   2227 static void AppGpuDump(const struct AppGpu *gpu, FILE *out) {
   2228     uint32_t i;
   2229 
   2230     if (html_output) {
   2231         fprintf(out, "\t\t\t<details><summary>Device Properties and Extensions</summary>\n");
   2232         fprintf(out, "\t\t\t\t<details><summary>GPU%u</summary>\n", gpu->id);
   2233     } else {
   2234         printf("\nDevice Properties and Extensions :\n");
   2235         printf("==================================\n");
   2236         printf("GPU%u\n", gpu->id);
   2237     }
   2238 
   2239     AppGpuDumpProps(gpu, out);
   2240     if (html_output) {
   2241         AppDumpExtensions("\t\t", "Device", gpu->device_extension_count, gpu->device_extensions, out);
   2242     } else {
   2243         printf("\n");
   2244         AppDumpExtensions("", "Device", gpu->device_extension_count, gpu->device_extensions, out);
   2245         printf("\n");
   2246     }
   2247 
   2248     for (i = 0; i < gpu->queue_count; i++) {
   2249         AppGpuDumpQueueProps(gpu, i, out);
   2250         if (!html_output) printf("\n");
   2251     }
   2252     AppGpuDumpMemoryProps(gpu, out);
   2253     if (!html_output) printf("\n");
   2254     AppGpuDumpFeatures(gpu, out);
   2255     if (!html_output) printf("\n");
   2256     AppDevDump(&gpu->dev, out);
   2257     if (html_output) {
   2258         fprintf(out, "\t\t\t\t</details>\n");
   2259         fprintf(out, "\t\t\t</details>\n");
   2260     }
   2261 }
   2262 
   2263 #ifdef _WIN32
   2264 // Enlarges the console window to have a large scrollback size.
   2265 static void ConsoleEnlarge() {
   2266     HANDLE console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
   2267 
   2268     // make the console window bigger
   2269     CONSOLE_SCREEN_BUFFER_INFO csbi;
   2270     COORD buffer_size;
   2271     if (GetConsoleScreenBufferInfo(console_handle, &csbi)) {
   2272         buffer_size.X = csbi.dwSize.X + 30;
   2273         buffer_size.Y = 20000;
   2274         SetConsoleScreenBufferSize(console_handle, buffer_size);
   2275     }
   2276 
   2277     SMALL_RECT r;
   2278     r.Left = r.Top = 0;
   2279     r.Right = csbi.dwSize.X - 1 + 30;
   2280     r.Bottom = 50;
   2281     SetConsoleWindowInfo(console_handle, true, &r);
   2282 
   2283     // change the console window title
   2284     SetConsoleTitle(TEXT(APP_SHORT_NAME));
   2285 }
   2286 #endif
   2287 
   2288 int main(int argc, char **argv) {
   2289     uint32_t vulkan_major, vulkan_minor, vulkan_patch;
   2290     struct AppGpu *gpus;
   2291     VkPhysicalDevice *objs;
   2292     uint32_t gpu_count;
   2293     VkResult err;
   2294     struct AppInstance inst;
   2295     FILE *out = stdout;
   2296 
   2297 #ifdef _WIN32
   2298     if (ConsoleIsExclusive()) ConsoleEnlarge();
   2299 #endif
   2300 
   2301     vulkan_major = VK_VERSION_MAJOR(VK_API_VERSION_1_0);
   2302     vulkan_minor = VK_VERSION_MINOR(VK_API_VERSION_1_0);
   2303     vulkan_patch = VK_VERSION_PATCH(VK_HEADER_VERSION);
   2304     for (int i = 1; i < argc; i++) {
   2305         if (strcmp(argv[i], "--html") == 0) {
   2306             out = fopen("vulkaninfo.html", "w");
   2307             html_output = true;
   2308             continue;
   2309         }
   2310     }
   2311 
   2312     if (html_output) {
   2313         PrintHtmlHeader(out);
   2314         fprintf(out, "\t\t\t<details><summary>");
   2315     } else {
   2316         printf("===========\n");
   2317         printf("VULKAN INFO\n");
   2318         printf("===========\n\n");
   2319     }
   2320     fprintf(out, "Vulkan API Version: ");
   2321     if (html_output) {
   2322         fprintf(out, "<div class='val'>%d.%d.%d</div></summary></details>\n", vulkan_major, vulkan_minor, vulkan_patch);
   2323         fprintf(out, "\t\t\t<br />\n");
   2324     } else {
   2325         printf("%d.%d.%d\n\n", vulkan_major, vulkan_minor, vulkan_patch);
   2326     }
   2327 
   2328     AppCreateInstance(&inst);
   2329 
   2330     if (!html_output) {
   2331         printf("Instance Extensions:\n");
   2332         printf("====================\n");
   2333     }
   2334     AppDumpExtensions("", "Instance", inst.global_extension_count, inst.global_extensions, out);
   2335 
   2336     err = vkEnumeratePhysicalDevices(inst.instance, &gpu_count, NULL);
   2337     if (err) ERR_EXIT(err);
   2338     objs = malloc(sizeof(objs[0]) * gpu_count);
   2339     if (!objs) ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
   2340     err = vkEnumeratePhysicalDevices(inst.instance, &gpu_count, objs);
   2341     if (err) ERR_EXIT(err);
   2342 
   2343     gpus = malloc(sizeof(gpus[0]) * gpu_count);
   2344     if (!gpus) ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
   2345     for (uint32_t i = 0; i < gpu_count; i++) {
   2346         AppGpuInit(&gpus[i], &inst, i, objs[i]);
   2347         if (!html_output) printf("\n\n");
   2348     }
   2349 
   2350     //---Layer-Device-Extensions---
   2351     if (html_output) {
   2352         fprintf(out, "\t\t\t<details><summary>Layers: count = <div class='val'>%d</div></summary>", inst.global_layer_count);
   2353         if (inst.global_layer_count > 0) {
   2354             fprintf(out, "\n");
   2355         }
   2356     } else {
   2357         printf("Layers: count = %d\n", inst.global_layer_count);
   2358         printf("=======\n");
   2359     }
   2360 
   2361     for (uint32_t i = 0; i < inst.global_layer_count; i++) {
   2362         uint32_t layer_major, layer_minor, layer_patch;
   2363         char spec_version[64], layer_version[64];
   2364         VkLayerProperties const *layer_prop = &inst.global_layers[i].layer_properties;
   2365 
   2366         ExtractVersion(layer_prop->specVersion, &layer_major, &layer_minor, &layer_patch);
   2367         snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", layer_major, layer_minor, layer_patch);
   2368         snprintf(layer_version, sizeof(layer_version), "%d", layer_prop->implementationVersion);
   2369 
   2370         if (html_output) {
   2371             fprintf(out, "\t\t\t\t<details><summary>");
   2372             fprintf(out, "<div class='type'>%s</div> (%s) Vulkan version <div class='val'>%s</div>, ", layer_prop->layerName,
   2373                     (char *)layer_prop->description, spec_version);
   2374             fprintf(out, "layer version <div class='val'>%s</div></summary>\n", layer_version);
   2375             AppDumpExtensions("\t\t", "Layer", inst.global_layers[i].extension_count, inst.global_layers[i].extension_properties,
   2376                               out);
   2377         } else {
   2378             printf("%s (%s) Vulkan version %s, layer version %s\n", layer_prop->layerName, (char *) layer_prop->description,
   2379                    spec_version, layer_version);
   2380             AppDumpExtensions("\t", "Layer", inst.global_layers[i].extension_count, inst.global_layers[i].extension_properties,
   2381                               out);
   2382         }
   2383 
   2384         char *layer_name = inst.global_layers[i].layer_properties.layerName;
   2385 
   2386         if (html_output) {
   2387             fprintf(out, "\t\t\t\t\t<details><summary>Devices count = <div class='val'>%d</div></summary>\n", gpu_count);
   2388         } else {
   2389             printf("\tDevices \tcount = %d\n", gpu_count);
   2390         }
   2391         for (uint32_t j = 0; j < gpu_count; j++) {
   2392             if (html_output) {
   2393                 fprintf(out, "\t\t\t\t\t\t<details><summary>");
   2394                 fprintf(out, "GPU id: <div class='val'>%u</div> (%s)</summary></details>\n", j, gpus[j].props.deviceName);
   2395             } else {
   2396                 printf("\t\tGPU id       : %u (%s)\n", j, gpus[j].props.deviceName);
   2397             }
   2398             uint32_t count = 0;
   2399             VkExtensionProperties *props;
   2400             AppGetPhysicalDeviceLayerExtensions(&gpus[j], layer_name, &count, &props);
   2401             if (html_output) {
   2402                 AppDumpExtensions("\t\t\t", "Layer-Device", count, props, out);
   2403             } else {
   2404                 AppDumpExtensions("\t\t", "Layer-Device", count, props, out);
   2405             }
   2406             if (html_output) { fprintf(out, "\t\t\t\t\t</details>\n"); }
   2407             free(props);
   2408         }
   2409         if (html_output) {
   2410             fprintf(out, "\t\t\t\t</details>\n");
   2411         } else {
   2412             printf("\n");
   2413         }
   2414     }
   2415 
   2416     if (html_output) { fprintf(out, "\t\t\t</details>\n"); }
   2417 
   2418     fflush(out);
   2419     //-----------------------------
   2420 
   2421     if (html_output) {
   2422         fprintf(out, "\t\t\t<details><summary>Presentable Surfaces</summary>");
   2423         if (gpu_count > 0) {
   2424             fprintf(out, "\n");
   2425         } else {
   2426             fprintf(out, "</details>\n");
   2427         }
   2428     } else {
   2429         printf("Presentable Surfaces:\n");
   2430         printf("=====================\n");
   2431     }
   2432     inst.width = 256;
   2433     inst.height = 256;
   2434     int format_count = 0;
   2435     int present_mode_count = 0;
   2436 
   2437 #if defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR)
   2438     bool has_display = true;
   2439     const char *display_var = getenv("DISPLAY");
   2440     if (display_var == NULL || strlen(display_var) == 0) {
   2441         printf("'DISPLAY' environment variable not set... skipping surface info\n");
   2442         has_display = false;
   2443     }
   2444 #endif
   2445 
   2446 //--WIN32--
   2447 #ifdef VK_USE_PLATFORM_WIN32_KHR
   2448     if (CheckExtensionEnabled(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, inst.inst_extensions, inst.inst_extensions_count)) {
   2449         AppCreateWin32Window(&inst);
   2450         for (uint32_t i = 0; i < gpu_count; i++) {
   2451             AppCreateWin32Surface(&inst);
   2452             if (html_output) {
   2453                 fprintf(out, "\t\t\t\t<details><summary>GPU id : <div class='val'>%u</div> (%s)</summary></details>\n", i,
   2454                         gpus[i].props.deviceName);
   2455                 fprintf(out, "\t\t\t\t<details><summary>Surface type : <div class='type'>%s</div></summary></details>\n",
   2456                         VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
   2457             } else {
   2458                 printf("GPU id       : %u (%s)\n", i, gpus[i].props.deviceName);
   2459                 printf("Surface type : %s\n", VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
   2460             }
   2461             format_count += AppDumpSurfaceFormats(&inst, &gpus[i], out);
   2462             present_mode_count += AppDumpSurfacePresentModes(&inst, &gpus[i], out);
   2463             AppDumpSurfaceCapabilities(&inst, &gpus[i], out);
   2464             AppDestroySurface(&inst);
   2465         }
   2466         AppDestroyWin32Window(&inst);
   2467     }
   2468 //--XCB--
   2469 #elif VK_USE_PLATFORM_XCB_KHR
   2470     if (has_display && CheckExtensionEnabled(VK_KHR_XCB_SURFACE_EXTENSION_NAME, inst.inst_extensions, inst.inst_extensions_count)) {
   2471         AppCreateXcbWindow(&inst);
   2472         for (uint32_t i = 0; i < gpu_count; i++) {
   2473             AppCreateXcbSurface(&inst);
   2474             if (html_output) {
   2475                 fprintf(out, "\t\t\t\t<details><summary>GPU id : <div class='val'>%u</div> (%s)</summary></details>\n", i,
   2476                         gpus[i].props.deviceName);
   2477                 fprintf(out, "\t\t\t\t<details><summary>Surface type : <div class='type'>%s</div></summary></details>\n",
   2478                         VK_KHR_XCB_SURFACE_EXTENSION_NAME);
   2479             } else {
   2480                 printf("GPU id       : %u (%s)\n", i, gpus[i].props.deviceName);
   2481                 printf("Surface type : %s\n", VK_KHR_XCB_SURFACE_EXTENSION_NAME);
   2482             }
   2483             format_count += AppDumpSurfaceFormats(&inst, &gpus[i], out);
   2484             present_mode_count += AppDumpSurfacePresentModes(&inst, &gpus[i], out);
   2485             AppDumpSurfaceCapabilities(&inst, &gpus[i], out);
   2486             AppDestroySurface(&inst);
   2487         }
   2488         AppDestroyXcbWindow(&inst);
   2489     }
   2490 //--XLIB--
   2491 #elif VK_USE_PLATFORM_XLIB_KHR
   2492     if (has_display && CheckExtensionEnabled(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, inst.inst_extensions, inst.inst_extensions_count)) {
   2493         AppCreateXlibWindow(&inst);
   2494         for (uint32_t i = 0; i < gpu_count; i++) {
   2495             AppCreateXlibSurface(&inst);
   2496             if (html_output) {
   2497                 fprintf(out, "\t\t\t\t<details><summary>GPU id : <div class='val'>%u</div> (%s)</summary></details>\n", i,
   2498                         gpus[i].props.deviceName);
   2499                 fprintf(out, "\t\t\t\t<details><summary>Surface type : <div class='type'>%s</div></summary></details>\n",
   2500                         VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
   2501             } else {
   2502                 printf("GPU id       : %u (%s)\n", i, gpus[i].props.deviceName);
   2503                 printf("Surface type : %s\n", VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
   2504             }
   2505             format_count += AppDumpSurfaceFormats(&inst, &gpus[i], out);
   2506             present_mode_count += AppDumpSurfacePresentModes(&inst, &gpus[i], out);
   2507             AppDumpSurfaceCapabilities(&inst, &gpus[i], out);
   2508             AppDestroySurface(&inst);
   2509         }
   2510         AppDestroyXlibWindow(&inst);
   2511     }
   2512 #endif
   2513 
   2514     // TODO: Android / Wayland / MIR
   2515     if (!format_count && !present_mode_count) {
   2516         if (html_output) {
   2517             fprintf(out, "\t\t\t\t<details><summary>None found</summary></details>\n");
   2518         } else {
   2519             printf( "None found\n");
   2520         }
   2521     }
   2522 
   2523     if (html_output) {
   2524         fprintf(out, "\t\t\t</details>\n");
   2525     } else {
   2526         printf("\n");
   2527     }
   2528     //---------
   2529 
   2530     for (uint32_t i = 0; i < gpu_count; i++) {
   2531         AppGpuDump(&gpus[i], out);
   2532         printf("\n\n");
   2533     }
   2534 
   2535     for (uint32_t i = 0; i < gpu_count; i++) AppGpuDestroy(&gpus[i]);
   2536     free(gpus);
   2537     free(objs);
   2538 
   2539     AppDestroyInstance(&inst);
   2540 
   2541     fflush(out);
   2542 #ifdef _WIN32
   2543     if (ConsoleIsExclusive() && !html_output) Sleep(INFINITE);
   2544 #endif
   2545 
   2546     if (html_output) {
   2547         PrintHtmlFooter(out);
   2548         fclose(out);
   2549     }
   2550 
   2551     return 0;
   2552 }
   2553