c4c51924ec4bf27599f02ef3a85768cb06420097
[platform/upstream/Vulkan-LoaderAndValidationLayers.git] / demos / vulkaninfo.c
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@LunarG.com>
19  * Author: David Pinedo <david@lunarg.com>
20  * Author: Mark Lobodzinski <mark@lunarg.com>
21  * Author: Rene Lindsay <rene@lunarg.com>
22  * Author: Jeremy Kniager <jeremyk@lunarg.com>
23  * Author: Shannon McPherson <shannon@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) fprintf(stderr, "%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         fflush(stderr);           \
84         WAIT_FOR_CONSOLE_DESTROY; \
85         exit(-1);                 \
86     } while (0)
87
88 #if defined(NDEBUG) && defined(__GNUC__)
89 #define U_ASSERT_ONLY __attribute__((unused))
90 #else
91 #define U_ASSERT_ONLY
92 #endif
93
94 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
95
96 #define MAX_QUEUE_TYPES 5
97 #define APP_SHORT_NAME "vulkaninfo"
98
99 static bool html_output = false;
100 static bool human_readable_output = true;
101 static bool json_output = false;
102 static uint32_t selected_gpu = 0;
103
104 struct VkStructureHeader {
105     VkStructureType sType;
106     void *pNext;
107 };
108
109 struct pNextChainBuildingBlockInfo {
110     VkStructureType sType;
111     uint32_t mem_size;
112 };
113
114 struct LayerExtensionList {
115     VkLayerProperties layer_properties;
116     uint32_t extension_count;
117     VkExtensionProperties *extension_properties;
118 };
119
120 struct AppInstance {
121     VkInstance instance;
122     uint32_t global_layer_count;
123     struct LayerExtensionList *global_layers;
124     uint32_t global_extension_count;
125     VkExtensionProperties *global_extensions;  // Instance Extensions
126
127     const char **inst_extensions;
128     uint32_t inst_extensions_count;
129
130     PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR;
131     PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
132     PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR;
133     PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR;
134     PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR;
135     PFN_vkGetPhysicalDeviceFormatProperties2KHR vkGetPhysicalDeviceFormatProperties2KHR;
136     PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR vkGetPhysicalDeviceQueueFamilyProperties2KHR;
137     PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR;
138     PFN_vkGetPhysicalDeviceMemoryProperties2KHR vkGetPhysicalDeviceMemoryProperties2KHR;
139     PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR;
140     PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT vkGetPhysicalDeviceSurfaceCapabilities2EXT;
141
142     VkSurfaceCapabilitiesKHR surface_capabilities;
143     VkSurfaceCapabilities2KHR surface_capabilities2;
144     VkSharedPresentSurfaceCapabilitiesKHR shared_surface_capabilities;
145     VkSurfaceCapabilities2EXT surface_capabilities2_ext;
146
147     VkSurfaceKHR surface;
148     int width, height;
149
150 #ifdef VK_USE_PLATFORM_WIN32_KHR
151     HINSTANCE h_instance;  // Windows Instance
152     HWND h_wnd;            // window handle
153 #elif VK_USE_PLATFORM_XCB_KHR
154     xcb_connection_t *xcb_connection;
155     xcb_screen_t *xcb_screen;
156     xcb_window_t xcb_window;
157 #elif VK_USE_PLATFORM_XLIB_KHR
158     Display *xlib_display;
159     Window xlib_window;
160 #elif VK_USE_PLATFORM_ANDROID_KHR  // TODO
161     ANativeWindow *window;
162 #endif
163 };
164
165 struct AppGpu {
166     uint32_t id;
167     VkPhysicalDevice obj;
168
169     VkPhysicalDeviceProperties props;
170     VkPhysicalDeviceProperties2KHR props2;
171
172     uint32_t queue_count;
173     VkQueueFamilyProperties *queue_props;
174     VkQueueFamilyProperties2KHR *queue_props2;
175     VkDeviceQueueCreateInfo *queue_reqs;
176
177     struct AppInstance *inst;
178
179     VkPhysicalDeviceMemoryProperties memory_props;
180     VkPhysicalDeviceMemoryProperties2KHR memory_props2;
181
182     VkPhysicalDeviceFeatures features;
183     VkPhysicalDeviceFeatures2KHR features2;
184     VkPhysicalDevice limits;
185
186     uint32_t device_extension_count;
187     VkExtensionProperties *device_extensions;
188 };
189
190 static VKAPI_ATTR VkBool32 VKAPI_CALL DbgCallback(VkFlags msgFlags, VkDebugReportObjectTypeEXT objType, uint64_t srcObject,
191                                                   size_t location, int32_t msgCode, const char *pLayerPrefix, const char *pMsg,
192                                                   void *pUserData) {
193     char *message = (char *)malloc(strlen(pMsg) + 100);
194
195     assert(message);
196
197     if (msgFlags & VK_DEBUG_REPORT_ERROR_BIT_EXT) {
198         sprintf(message, "ERROR: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
199     } else if (msgFlags & VK_DEBUG_REPORT_WARNING_BIT_EXT) {
200         sprintf(message, "WARNING: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
201     } else if (msgFlags & VK_DEBUG_REPORT_INFORMATION_BIT_EXT) {
202         sprintf(message, "INFO: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
203     } else if (msgFlags & VK_DEBUG_REPORT_DEBUG_BIT_EXT) {
204         sprintf(message, "DEBUG: [%s] Code %d : %s", pLayerPrefix, msgCode, pMsg);
205     }
206
207     printf("%s\n", message);
208     fflush(stdout);
209     free(message);
210
211     /*
212      * false indicates that layer should not bail-out of an
213      * API call that had validation failures. This may mean that the
214      * app dies inside the driver due to invalid parameter(s).
215      * That's what would happen without validation layers, so we'll
216      * keep that behavior here.
217      */
218     return false;
219 }
220
221 static const char *VkResultString(VkResult err) {
222     switch (err) {
223 #define STR(r) \
224     case r:    \
225         return #r
226         STR(VK_SUCCESS);
227         STR(VK_NOT_READY);
228         STR(VK_TIMEOUT);
229         STR(VK_EVENT_SET);
230         STR(VK_EVENT_RESET);
231         STR(VK_ERROR_INITIALIZATION_FAILED);
232         STR(VK_ERROR_OUT_OF_HOST_MEMORY);
233         STR(VK_ERROR_OUT_OF_DEVICE_MEMORY);
234         STR(VK_ERROR_DEVICE_LOST);
235         STR(VK_ERROR_LAYER_NOT_PRESENT);
236         STR(VK_ERROR_EXTENSION_NOT_PRESENT);
237         STR(VK_ERROR_MEMORY_MAP_FAILED);
238         STR(VK_ERROR_INCOMPATIBLE_DRIVER);
239 #undef STR
240         default:
241             return "UNKNOWN_RESULT";
242     }
243 }
244
245 static const char *VkPhysicalDeviceTypeString(VkPhysicalDeviceType type) {
246     switch (type) {
247 #define STR(r)                        \
248     case VK_PHYSICAL_DEVICE_TYPE_##r: \
249         return #r
250         STR(OTHER);
251         STR(INTEGRATED_GPU);
252         STR(DISCRETE_GPU);
253         STR(VIRTUAL_GPU);
254         STR(CPU);
255 #undef STR
256         default:
257             return "UNKNOWN_DEVICE";
258     }
259 }
260
261 static const char *VkFormatString(VkFormat fmt) {
262     switch (fmt) {
263 #define STR(r)          \
264     case VK_FORMAT_##r: \
265         return #r
266         STR(UNDEFINED);
267         STR(R4G4_UNORM_PACK8);
268         STR(R4G4B4A4_UNORM_PACK16);
269         STR(B4G4R4A4_UNORM_PACK16);
270         STR(R5G6B5_UNORM_PACK16);
271         STR(B5G6R5_UNORM_PACK16);
272         STR(R5G5B5A1_UNORM_PACK16);
273         STR(B5G5R5A1_UNORM_PACK16);
274         STR(A1R5G5B5_UNORM_PACK16);
275         STR(R8_UNORM);
276         STR(R8_SNORM);
277         STR(R8_USCALED);
278         STR(R8_SSCALED);
279         STR(R8_UINT);
280         STR(R8_SINT);
281         STR(R8_SRGB);
282         STR(R8G8_UNORM);
283         STR(R8G8_SNORM);
284         STR(R8G8_USCALED);
285         STR(R8G8_SSCALED);
286         STR(R8G8_UINT);
287         STR(R8G8_SINT);
288         STR(R8G8_SRGB);
289         STR(R8G8B8_UNORM);
290         STR(R8G8B8_SNORM);
291         STR(R8G8B8_USCALED);
292         STR(R8G8B8_SSCALED);
293         STR(R8G8B8_UINT);
294         STR(R8G8B8_SINT);
295         STR(R8G8B8_SRGB);
296         STR(B8G8R8_UNORM);
297         STR(B8G8R8_SNORM);
298         STR(B8G8R8_USCALED);
299         STR(B8G8R8_SSCALED);
300         STR(B8G8R8_UINT);
301         STR(B8G8R8_SINT);
302         STR(B8G8R8_SRGB);
303         STR(R8G8B8A8_UNORM);
304         STR(R8G8B8A8_SNORM);
305         STR(R8G8B8A8_USCALED);
306         STR(R8G8B8A8_SSCALED);
307         STR(R8G8B8A8_UINT);
308         STR(R8G8B8A8_SINT);
309         STR(R8G8B8A8_SRGB);
310         STR(B8G8R8A8_UNORM);
311         STR(B8G8R8A8_SNORM);
312         STR(B8G8R8A8_USCALED);
313         STR(B8G8R8A8_SSCALED);
314         STR(B8G8R8A8_UINT);
315         STR(B8G8R8A8_SINT);
316         STR(B8G8R8A8_SRGB);
317         STR(A8B8G8R8_UNORM_PACK32);
318         STR(A8B8G8R8_SNORM_PACK32);
319         STR(A8B8G8R8_USCALED_PACK32);
320         STR(A8B8G8R8_SSCALED_PACK32);
321         STR(A8B8G8R8_UINT_PACK32);
322         STR(A8B8G8R8_SINT_PACK32);
323         STR(A8B8G8R8_SRGB_PACK32);
324         STR(A2R10G10B10_UNORM_PACK32);
325         STR(A2R10G10B10_SNORM_PACK32);
326         STR(A2R10G10B10_USCALED_PACK32);
327         STR(A2R10G10B10_SSCALED_PACK32);
328         STR(A2R10G10B10_UINT_PACK32);
329         STR(A2R10G10B10_SINT_PACK32);
330         STR(A2B10G10R10_UNORM_PACK32);
331         STR(A2B10G10R10_SNORM_PACK32);
332         STR(A2B10G10R10_USCALED_PACK32);
333         STR(A2B10G10R10_SSCALED_PACK32);
334         STR(A2B10G10R10_UINT_PACK32);
335         STR(A2B10G10R10_SINT_PACK32);
336         STR(R16_UNORM);
337         STR(R16_SNORM);
338         STR(R16_USCALED);
339         STR(R16_SSCALED);
340         STR(R16_UINT);
341         STR(R16_SINT);
342         STR(R16_SFLOAT);
343         STR(R16G16_UNORM);
344         STR(R16G16_SNORM);
345         STR(R16G16_USCALED);
346         STR(R16G16_SSCALED);
347         STR(R16G16_UINT);
348         STR(R16G16_SINT);
349         STR(R16G16_SFLOAT);
350         STR(R16G16B16_UNORM);
351         STR(R16G16B16_SNORM);
352         STR(R16G16B16_USCALED);
353         STR(R16G16B16_SSCALED);
354         STR(R16G16B16_UINT);
355         STR(R16G16B16_SINT);
356         STR(R16G16B16_SFLOAT);
357         STR(R16G16B16A16_UNORM);
358         STR(R16G16B16A16_SNORM);
359         STR(R16G16B16A16_USCALED);
360         STR(R16G16B16A16_SSCALED);
361         STR(R16G16B16A16_UINT);
362         STR(R16G16B16A16_SINT);
363         STR(R16G16B16A16_SFLOAT);
364         STR(R32_UINT);
365         STR(R32_SINT);
366         STR(R32_SFLOAT);
367         STR(R32G32_UINT);
368         STR(R32G32_SINT);
369         STR(R32G32_SFLOAT);
370         STR(R32G32B32_UINT);
371         STR(R32G32B32_SINT);
372         STR(R32G32B32_SFLOAT);
373         STR(R32G32B32A32_UINT);
374         STR(R32G32B32A32_SINT);
375         STR(R32G32B32A32_SFLOAT);
376         STR(R64_UINT);
377         STR(R64_SINT);
378         STR(R64_SFLOAT);
379         STR(R64G64_UINT);
380         STR(R64G64_SINT);
381         STR(R64G64_SFLOAT);
382         STR(R64G64B64_UINT);
383         STR(R64G64B64_SINT);
384         STR(R64G64B64_SFLOAT);
385         STR(R64G64B64A64_UINT);
386         STR(R64G64B64A64_SINT);
387         STR(R64G64B64A64_SFLOAT);
388         STR(B10G11R11_UFLOAT_PACK32);
389         STR(E5B9G9R9_UFLOAT_PACK32);
390         STR(D16_UNORM);
391         STR(X8_D24_UNORM_PACK32);
392         STR(D32_SFLOAT);
393         STR(S8_UINT);
394         STR(D16_UNORM_S8_UINT);
395         STR(D24_UNORM_S8_UINT);
396         STR(D32_SFLOAT_S8_UINT);
397         STR(BC1_RGB_UNORM_BLOCK);
398         STR(BC1_RGB_SRGB_BLOCK);
399         STR(BC1_RGBA_UNORM_BLOCK);
400         STR(BC1_RGBA_SRGB_BLOCK);
401         STR(BC2_UNORM_BLOCK);
402         STR(BC2_SRGB_BLOCK);
403         STR(BC3_UNORM_BLOCK);
404         STR(BC3_SRGB_BLOCK);
405         STR(BC4_UNORM_BLOCK);
406         STR(BC4_SNORM_BLOCK);
407         STR(BC5_UNORM_BLOCK);
408         STR(BC5_SNORM_BLOCK);
409         STR(BC6H_UFLOAT_BLOCK);
410         STR(BC6H_SFLOAT_BLOCK);
411         STR(BC7_UNORM_BLOCK);
412         STR(BC7_SRGB_BLOCK);
413         STR(ETC2_R8G8B8_UNORM_BLOCK);
414         STR(ETC2_R8G8B8_SRGB_BLOCK);
415         STR(ETC2_R8G8B8A1_UNORM_BLOCK);
416         STR(ETC2_R8G8B8A1_SRGB_BLOCK);
417         STR(ETC2_R8G8B8A8_UNORM_BLOCK);
418         STR(ETC2_R8G8B8A8_SRGB_BLOCK);
419         STR(EAC_R11_UNORM_BLOCK);
420         STR(EAC_R11_SNORM_BLOCK);
421         STR(EAC_R11G11_UNORM_BLOCK);
422         STR(EAC_R11G11_SNORM_BLOCK);
423         STR(ASTC_4x4_UNORM_BLOCK);
424         STR(ASTC_4x4_SRGB_BLOCK);
425         STR(ASTC_5x4_UNORM_BLOCK);
426         STR(ASTC_5x4_SRGB_BLOCK);
427         STR(ASTC_5x5_UNORM_BLOCK);
428         STR(ASTC_5x5_SRGB_BLOCK);
429         STR(ASTC_6x5_UNORM_BLOCK);
430         STR(ASTC_6x5_SRGB_BLOCK);
431         STR(ASTC_6x6_UNORM_BLOCK);
432         STR(ASTC_6x6_SRGB_BLOCK);
433         STR(ASTC_8x5_UNORM_BLOCK);
434         STR(ASTC_8x5_SRGB_BLOCK);
435         STR(ASTC_8x6_UNORM_BLOCK);
436         STR(ASTC_8x6_SRGB_BLOCK);
437         STR(ASTC_8x8_UNORM_BLOCK);
438         STR(ASTC_8x8_SRGB_BLOCK);
439         STR(ASTC_10x5_UNORM_BLOCK);
440         STR(ASTC_10x5_SRGB_BLOCK);
441         STR(ASTC_10x6_UNORM_BLOCK);
442         STR(ASTC_10x6_SRGB_BLOCK);
443         STR(ASTC_10x8_UNORM_BLOCK);
444         STR(ASTC_10x8_SRGB_BLOCK);
445         STR(ASTC_10x10_UNORM_BLOCK);
446         STR(ASTC_10x10_SRGB_BLOCK);
447         STR(ASTC_12x10_UNORM_BLOCK);
448         STR(ASTC_12x10_SRGB_BLOCK);
449         STR(ASTC_12x12_UNORM_BLOCK);
450         STR(ASTC_12x12_SRGB_BLOCK);
451 #undef STR
452         default:
453             return "UNKNOWN_FORMAT";
454     }
455 }
456 #if defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR)
457 static const char *VkPresentModeString(VkPresentModeKHR mode) {
458     switch (mode) {
459 #define STR(r)                \
460     case VK_PRESENT_MODE_##r: \
461         return #r
462         STR(IMMEDIATE_KHR);
463         STR(MAILBOX_KHR);
464         STR(FIFO_KHR);
465         STR(FIFO_RELAXED_KHR);
466 #undef STR
467         default:
468             return "UNKNOWN_FORMAT";
469     }
470 }
471 #endif
472
473 static bool CheckExtensionEnabled(const char *extension_to_check, const char **extension_list, uint32_t extension_count) {
474     for (uint32_t i = 0; i < extension_count; ++i) {
475         if (!strcmp(extension_to_check, extension_list[i])) {
476             return true;
477         }
478     }
479     return false;
480 }
481
482 static bool CheckPhysicalDeviceExtensionIncluded(const char *extension_to_check, VkExtensionProperties *extension_list,
483                                                  uint32_t extension_count) {
484     for (uint32_t i = 0; i < extension_count; ++i) {
485         if (!strcmp(extension_to_check, extension_list[i].extensionName)) {
486             return true;
487         }
488     }
489     return false;
490 }
491
492 static void buildpNextChain(struct VkStructureHeader *first, const struct pNextChainBuildingBlockInfo *chain_info,
493                             uint32_t chain_info_len) {
494     struct VkStructureHeader *place = first;
495
496     for (uint32_t i = 0; i < chain_info_len; i++) {
497         place->pNext = malloc(chain_info[i].mem_size);
498         if (!place->pNext) {
499             ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
500         }
501         place = place->pNext;
502         place->sType = chain_info[i].sType;
503     }
504
505     place->pNext = NULL;
506 }
507
508 static void freepNextChain(struct VkStructureHeader *first) {
509     struct VkStructureHeader *place = first;
510     struct VkStructureHeader *next = NULL;
511
512     while (place) {
513         next = place->pNext;
514         free(place);
515         place = next;
516     }
517 }
518
519 static void ExtractVersion(uint32_t version, uint32_t *major, uint32_t *minor, uint32_t *patch) {
520     *major = version >> 22;
521     *minor = (version >> 12) & 0x3ff;
522     *patch = version & 0xfff;
523 }
524
525 static void AppGetPhysicalDeviceLayerExtensions(struct AppGpu *gpu, char *layer_name, uint32_t *extension_count,
526                                                 VkExtensionProperties **extension_properties) {
527     VkResult err;
528     uint32_t ext_count = 0;
529     VkExtensionProperties *ext_ptr = NULL;
530
531     /* repeat get until VK_INCOMPLETE goes away */
532     do {
533         err = vkEnumerateDeviceExtensionProperties(gpu->obj, layer_name, &ext_count, NULL);
534         assert(!err);
535
536         if (ext_ptr) {
537             free(ext_ptr);
538         }
539         ext_ptr = malloc(ext_count * sizeof(VkExtensionProperties));
540         err = vkEnumerateDeviceExtensionProperties(gpu->obj, layer_name, &ext_count, ext_ptr);
541     } while (err == VK_INCOMPLETE);
542     assert(!err);
543
544     *extension_count = ext_count;
545     *extension_properties = ext_ptr;
546 }
547
548 static void AppGetGlobalLayerExtensions(char *layer_name, uint32_t *extension_count, VkExtensionProperties **extension_properties) {
549     VkResult err;
550     uint32_t ext_count = 0;
551     VkExtensionProperties *ext_ptr = NULL;
552
553     /* repeat get until VK_INCOMPLETE goes away */
554     do {
555         // gets the extension count if the last parameter is NULL
556         err = vkEnumerateInstanceExtensionProperties(layer_name, &ext_count, NULL);
557         assert(!err);
558
559         if (ext_ptr) {
560             free(ext_ptr);
561         }
562         ext_ptr = malloc(ext_count * sizeof(VkExtensionProperties));
563         // gets the extension properties if the last parameter is not NULL
564         err = vkEnumerateInstanceExtensionProperties(layer_name, &ext_count, ext_ptr);
565     } while (err == VK_INCOMPLETE);
566     assert(!err);
567     *extension_count = ext_count;
568     *extension_properties = ext_ptr;
569 }
570
571 /* Gets a list of layer and instance extensions */
572 static void AppGetInstanceExtensions(struct AppInstance *inst) {
573     VkResult U_ASSERT_ONLY err;
574
575     uint32_t count = 0;
576
577     /* Scan layers */
578     VkLayerProperties *global_layer_properties = NULL;
579     struct LayerExtensionList *global_layers = NULL;
580
581     do {
582         err = vkEnumerateInstanceLayerProperties(&count, NULL);
583         assert(!err);
584
585         if (global_layer_properties) {
586             free(global_layer_properties);
587         }
588         global_layer_properties = malloc(sizeof(VkLayerProperties) * count);
589         assert(global_layer_properties);
590
591         if (global_layers) {
592             free(global_layers);
593         }
594         global_layers = malloc(sizeof(struct LayerExtensionList) * count);
595         assert(global_layers);
596
597         err = vkEnumerateInstanceLayerProperties(&count, global_layer_properties);
598     } while (err == VK_INCOMPLETE);
599     assert(!err);
600
601     inst->global_layer_count = count;
602     inst->global_layers = global_layers;
603
604     for (uint32_t i = 0; i < inst->global_layer_count; ++i) {
605         VkLayerProperties *src_info = &global_layer_properties[i];
606         struct LayerExtensionList *dst_info = &inst->global_layers[i];
607         memcpy(&dst_info->layer_properties, src_info, sizeof(VkLayerProperties));
608
609         // Save away layer extension info for report
610         // Gets layer extensions, if first parameter is not NULL
611         AppGetGlobalLayerExtensions(src_info->layerName, &dst_info->extension_count, &dst_info->extension_properties);
612     }
613     free(global_layer_properties);
614
615     // Collect global extensions
616     inst->global_extension_count = 0;
617     // Gets instance extensions, if no layer was specified in the first
618     // paramteter
619     AppGetGlobalLayerExtensions(NULL, &inst->global_extension_count, &inst->global_extensions);
620 }
621
622 // Prints opening code for html output file
623 void PrintHtmlHeader(FILE *out) {
624     fprintf(out, "<!doctype html>\n");
625     fprintf(out, "<html>\n");
626     fprintf(out, "\t<head>\n");
627     fprintf(out, "\t\t<title>Vulkan Info</title>\n");
628     fprintf(out, "\t\t<style type='text/css'>\n");
629     fprintf(out, "\t\thtml {\n");
630     fprintf(out, "\t\t\tbackground-color: #0b1e48;\n");
631     fprintf(out, "\t\t\tbackground-image: url(\"https://vulkan.lunarg.com/img/bg-starfield.jpg\");\n");
632     fprintf(out, "\t\t\tbackground-position: center;\n");
633     fprintf(out, "\t\t\t-webkit-background-size: cover;\n");
634     fprintf(out, "\t\t\t-moz-background-size: cover;\n");
635     fprintf(out, "\t\t\t-o-background-size: cover;\n");
636     fprintf(out, "\t\t\tbackground-size: cover;\n");
637     fprintf(out, "\t\t\tbackground-attachment: fixed;\n");
638     fprintf(out, "\t\t\tbackground-repeat: no-repeat;\n");
639     fprintf(out, "\t\t\theight: 100%%;\n");
640     fprintf(out, "\t\t}\n");
641     fprintf(out, "\t\t#header {\n");
642     fprintf(out, "\t\t\tz-index: -1;\n");
643     fprintf(out, "\t\t}\n");
644     fprintf(out, "\t\t#header>img {\n");
645     fprintf(out, "\t\t\tposition: absolute;\n");
646     fprintf(out, "\t\t\twidth: 160px;\n");
647     fprintf(out, "\t\t\tmargin-left: -280px;\n");
648     fprintf(out, "\t\t\ttop: -10px;\n");
649     fprintf(out, "\t\t\tleft: 50%%;\n");
650     fprintf(out, "\t\t}\n");
651     fprintf(out, "\t\t#header>h1 {\n");
652     fprintf(out, "\t\t\tfont-family: Arial, \"Helvetica Neue\", Helvetica, sans-serif;\n");
653     fprintf(out, "\t\t\tfont-size: 44px;\n");
654     fprintf(out, "\t\t\tfont-weight: 200;\n");
655     fprintf(out, "\t\t\ttext-shadow: 4px 4px 5px #000;\n");
656     fprintf(out, "\t\t\tcolor: #eee;\n");
657     fprintf(out, "\t\t\tposition: absolute;\n");
658     fprintf(out, "\t\t\twidth: 400px;\n");
659     fprintf(out, "\t\t\tmargin-left: -80px;\n");
660     fprintf(out, "\t\t\ttop: 8px;\n");
661     fprintf(out, "\t\t\tleft: 50%%;\n");
662     fprintf(out, "\t\t}\n");
663     fprintf(out, "\t\tbody {\n");
664     fprintf(out, "\t\t\tfont-family: Consolas, monaco, monospace;\n");
665     fprintf(out, "\t\t\tfont-size: 14px;\n");
666     fprintf(out, "\t\t\tline-height: 20px;\n");
667     fprintf(out, "\t\t\tcolor: #eee;\n");
668     fprintf(out, "\t\t\theight: 100%%;\n");
669     fprintf(out, "\t\t\tmargin: 0;\n");
670     fprintf(out, "\t\t\toverflow: hidden;\n");
671     fprintf(out, "\t\t}\n");
672     fprintf(out, "\t\t#wrapper {\n");
673     fprintf(out, "\t\t\tbackground-color: rgba(0, 0, 0, 0.7);\n");
674     fprintf(out, "\t\t\tborder: 1px solid #446;\n");
675     fprintf(out, "\t\t\tbox-shadow: 0px 0px 10px #000;\n");
676     fprintf(out, "\t\t\tpadding: 8px 12px;\n\n");
677     fprintf(out, "\t\t\tdisplay: inline-block;\n");
678     fprintf(out, "\t\t\tposition: absolute;\n");
679     fprintf(out, "\t\t\ttop: 80px;\n");
680     fprintf(out, "\t\t\tbottom: 25px;\n");
681     fprintf(out, "\t\t\tleft: 50px;\n");
682     fprintf(out, "\t\t\tright: 50px;\n");
683     fprintf(out, "\t\t\toverflow: auto;\n");
684     fprintf(out, "\t\t}\n");
685     fprintf(out, "\t\tdetails>details {\n");
686     fprintf(out, "\t\t\tmargin-left: 22px;\n");
687     fprintf(out, "\t\t}\n");
688     fprintf(out, "\t\tdetails>summary:only-child::-webkit-details-marker {\n");
689     fprintf(out, "\t\t\tdisplay: none;\n");
690     fprintf(out, "\t\t}\n");
691     fprintf(out, "\t\t.var, .type, .val {\n");
692     fprintf(out, "\t\t\tdisplay: inline;\n");
693     fprintf(out, "\t\t}\n");
694     fprintf(out, "\t\t.var {\n");
695     fprintf(out, "\t\t}\n");
696     fprintf(out, "\t\t.type {\n");
697     fprintf(out, "\t\t\tcolor: #acf;\n");
698     fprintf(out, "\t\t\tmargin: 0 12px;\n");
699     fprintf(out, "\t\t}\n");
700     fprintf(out, "\t\t.val {\n");
701     fprintf(out, "\t\t\tcolor: #afa;\n");
702     fprintf(out, "\t\t\tbackground: #222;\n");
703     fprintf(out, "\t\t\ttext-align: right;\n");
704     fprintf(out, "\t\t}\n");
705     fprintf(out, "\t\t</style>\n");
706     fprintf(out, "\t</head>\n");
707     fprintf(out, "\t<body>\n");
708     fprintf(out, "\t\t<div id='header'>\n");
709     fprintf(out, "\t\t\t<h1>Vulkan Info</h1>\n");
710     fprintf(out, "\t\t</div>\n");
711     fprintf(out, "\t\t<div id='wrapper'>\n");
712 }
713
714 // Prints closing code for html output file
715 void PrintHtmlFooter(FILE *out) {
716     fprintf(out, "\t\t</div>\n");
717     fprintf(out, "\t</body>\n");
718     fprintf(out, "</html>");
719 }
720
721 // Prints opening code for json output file
722 void PrintJsonHeader(const int vulkan_major, const int vulkan_minor, const int vulkan_patch) {
723     printf("{\n");
724     printf("\t\"$schema\": \"https://schema.khronos.org/vulkan/devsim_1_0_0.json#\",\n");
725     printf("\t\"comments\": {\n");
726     printf("\t\t\"desc\": \"JSON configuration file describing GPU %u. Generated using the VulkanInfo program.\",\n", selected_gpu);
727     printf("\t\t\"vulkanApiVersion\": \"%d.%d.%d\"\n", vulkan_major, vulkan_minor, vulkan_patch);
728     printf("\t}");
729 }
730
731 // Checks if current argument specifies json output, interprets/updates gpu selection
732 void CheckForJsonOption(const char *arg) {
733     if (strncmp("--json", arg, 6) == 0 || strcmp(arg, "-j") == 0) {
734         if (strlen(arg) > 7 && strncmp("--json=", arg, 7) == 0) {
735             selected_gpu = strtol(arg + 7, NULL, 10);
736         }
737         human_readable_output = false;
738         json_output = true;
739     }
740 }
741
742 // static void AppCreateInstance(struct AppInstance *inst, int argc, ...) {
743 static void AppCreateInstance(struct AppInstance *inst) {
744     AppGetInstanceExtensions(inst);
745
746     //---Build a list of extensions to load---
747
748     const char *info_instance_extensions[] = {VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME,
749                                               VK_KHR_DISPLAY_EXTENSION_NAME,
750                                               VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
751                                               VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME,
752                                               VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME,
753                                               VK_KHR_SURFACE_EXTENSION_NAME,
754                                               VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME,
755 #ifdef VK_USE_PLATFORM_WIN32_KHR
756                                               VK_KHR_WIN32_SURFACE_EXTENSION_NAME
757 #elif VK_USE_PLATFORM_XCB_KHR
758                                               VK_KHR_XCB_SURFACE_EXTENSION_NAME
759 #elif VK_USE_PLATFORM_XLIB_KHR
760                                               VK_KHR_XLIB_SURFACE_EXTENSION_NAME
761 #elif VK_USE_PLATFORM_WAYLAND_KHR
762                                               VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME
763 #elif VK_USE_PLATFORM_ANDROID_KHR
764                                               VK_KHR_ANDROID_SURFACE_EXTENSION_NAME
765 #endif
766     };
767     const uint32_t info_instance_extensions_count = ARRAY_SIZE(info_instance_extensions);
768     inst->inst_extensions = malloc(sizeof(char *) * ARRAY_SIZE(info_instance_extensions));
769     inst->inst_extensions_count = 0;
770
771     for (uint32_t k = 0; (k < info_instance_extensions_count); ++k) {
772         for (uint32_t j = 0; (j < inst->global_extension_count); ++j) {
773             const char *found_name = inst->global_extensions[j].extensionName;
774             if (!strcmp(info_instance_extensions[k], found_name)) {
775                 inst->inst_extensions[inst->inst_extensions_count++] = info_instance_extensions[k];
776                 break;
777             }
778         }
779     }
780
781     //----------------------------------------
782
783     const VkApplicationInfo app_info = {
784         .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
785         .pNext = NULL,
786         .pApplicationName = APP_SHORT_NAME,
787         .applicationVersion = 1,
788         .pEngineName = APP_SHORT_NAME,
789         .engineVersion = 1,
790         .apiVersion = VK_API_VERSION_1_0,
791     };
792
793     VkInstanceCreateInfo inst_info = {.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
794                                       .pNext = NULL,
795                                       .pApplicationInfo = &app_info,
796                                       .enabledLayerCount = 0,
797                                       .ppEnabledLayerNames = NULL,
798                                       .enabledExtensionCount = inst->inst_extensions_count,
799                                       .ppEnabledExtensionNames = inst->inst_extensions};
800
801     VkDebugReportCallbackCreateInfoEXT dbg_info;
802     memset(&dbg_info, 0, sizeof(dbg_info));
803     dbg_info.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT;
804     dbg_info.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT;
805     dbg_info.pfnCallback = DbgCallback;
806     inst_info.pNext = &dbg_info;
807
808     VkResult U_ASSERT_ONLY err;
809     err = vkCreateInstance(&inst_info, NULL, &inst->instance);
810     if (err == VK_ERROR_INCOMPATIBLE_DRIVER) {
811         fprintf(stderr, "Cannot create Vulkan instance.\n");
812         ERR_EXIT(err);
813     } else if (err) {
814         ERR_EXIT(err);
815     }
816
817     inst->vkGetPhysicalDeviceSurfaceSupportKHR =
818         (PFN_vkGetPhysicalDeviceSurfaceSupportKHR)vkGetInstanceProcAddr(inst->instance, "vkGetPhysicalDeviceSurfaceSupportKHR");
819     inst->vkGetPhysicalDeviceSurfaceCapabilitiesKHR = (PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR)vkGetInstanceProcAddr(
820         inst->instance, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
821     inst->vkGetPhysicalDeviceSurfaceFormatsKHR =
822         (PFN_vkGetPhysicalDeviceSurfaceFormatsKHR)vkGetInstanceProcAddr(inst->instance, "vkGetPhysicalDeviceSurfaceFormatsKHR");
823     inst->vkGetPhysicalDeviceSurfacePresentModesKHR = (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR)vkGetInstanceProcAddr(
824         inst->instance, "vkGetPhysicalDeviceSurfacePresentModesKHR");
825     inst->vkGetPhysicalDeviceProperties2KHR =
826         (PFN_vkGetPhysicalDeviceProperties2KHR)vkGetInstanceProcAddr(inst->instance, "vkGetPhysicalDeviceProperties2KHR");
827     inst->vkGetPhysicalDeviceFormatProperties2KHR = (PFN_vkGetPhysicalDeviceFormatProperties2KHR)vkGetInstanceProcAddr(
828         inst->instance, "vkGetPhysicalDeviceFormatProperties2KHR");
829     inst->vkGetPhysicalDeviceQueueFamilyProperties2KHR = (PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR)vkGetInstanceProcAddr(
830         inst->instance, "vkGetPhysicalDeviceQueueFamilyProperties2KHR");
831     inst->vkGetPhysicalDeviceFeatures2KHR =
832         (PFN_vkGetPhysicalDeviceFeatures2KHR)vkGetInstanceProcAddr(inst->instance, "vkGetPhysicalDeviceFeatures2KHR");
833     inst->vkGetPhysicalDeviceMemoryProperties2KHR = (PFN_vkGetPhysicalDeviceMemoryProperties2KHR)vkGetInstanceProcAddr(
834         inst->instance, "vkGetPhysicalDeviceMemoryProperties2KHR");
835     inst->vkGetPhysicalDeviceSurfaceCapabilities2KHR = (PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR)vkGetInstanceProcAddr(
836         inst->instance, "vkGetPhysicalDeviceSurfaceCapabilities2KHR");
837     inst->vkGetPhysicalDeviceSurfaceCapabilities2EXT = (PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT)vkGetInstanceProcAddr(
838         inst->instance, "vkGetPhysicalDeviceSurfaceCapabilities2EXT");
839 }
840
841 //-----------------------------------------------------------
842
843 static void AppDestroyInstance(struct AppInstance *inst) {
844     free(inst->global_extensions);
845     for (uint32_t i = 0; i < inst->global_layer_count; ++i) {
846         free(inst->global_layers[i].extension_properties);
847     }
848     free(inst->global_layers);
849     free((char **)inst->inst_extensions);
850     vkDestroyInstance(inst->instance, NULL);
851 }
852
853 static void AppGpuInit(struct AppGpu *gpu, struct AppInstance *inst, uint32_t id, VkPhysicalDevice obj) {
854     uint32_t i;
855
856     memset(gpu, 0, sizeof(*gpu));
857
858     gpu->id = id;
859     gpu->obj = obj;
860     gpu->inst = inst;
861
862     vkGetPhysicalDeviceProperties(gpu->obj, &gpu->props);
863
864     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
865                               gpu->inst->inst_extensions_count)) {
866         struct pNextChainBuildingBlockInfo chain_info[] = {
867             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT,
868              .mem_size = sizeof(VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT)},
869             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR,
870              .mem_size = sizeof(VkPhysicalDevicePointClippingPropertiesKHR)},
871             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR,
872              .mem_size = sizeof(VkPhysicalDevicePushDescriptorPropertiesKHR)},
873             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT,
874              .mem_size = sizeof(VkPhysicalDeviceDiscardRectanglePropertiesEXT)},
875             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR,
876              .mem_size = sizeof(VkPhysicalDeviceMultiviewPropertiesKHR)}};
877
878         uint32_t chain_info_len = ARRAY_SIZE(chain_info);
879
880         gpu->props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR;
881         buildpNextChain((struct VkStructureHeader *)&gpu->props2, chain_info, chain_info_len);
882
883         inst->vkGetPhysicalDeviceProperties2KHR(gpu->obj, &gpu->props2);
884     }
885
886     /* get queue count */
887     vkGetPhysicalDeviceQueueFamilyProperties(gpu->obj, &gpu->queue_count, NULL);
888
889     gpu->queue_props = malloc(sizeof(gpu->queue_props[0]) * gpu->queue_count);
890
891     if (!gpu->queue_props) {
892         ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
893     }
894     vkGetPhysicalDeviceQueueFamilyProperties(gpu->obj, &gpu->queue_count, gpu->queue_props);
895
896     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
897                               gpu->inst->inst_extensions_count)) {
898         gpu->queue_props2 = malloc(sizeof(gpu->queue_props2[0]) * gpu->queue_count);
899
900         if (!gpu->queue_props2) {
901             ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
902         }
903
904         for (i = 0; i < gpu->queue_count; ++i) {
905             gpu->queue_props2[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR;
906             gpu->queue_props2[i].pNext = NULL;
907         }
908
909         inst->vkGetPhysicalDeviceQueueFamilyProperties2KHR(gpu->obj, &gpu->queue_count, gpu->queue_props2);
910     }
911
912     /* set up queue requests */
913     gpu->queue_reqs = malloc(sizeof(*gpu->queue_reqs) * gpu->queue_count);
914     if (!gpu->queue_reqs) {
915         ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
916     }
917     for (i = 0; i < gpu->queue_count; ++i) {
918         float *queue_priorities = NULL;
919         if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
920                                   gpu->inst->inst_extensions_count)) {
921             queue_priorities = malloc(gpu->queue_props2[i].queueFamilyProperties.queueCount * sizeof(float));
922         } else {
923             queue_priorities = malloc(gpu->queue_props[i].queueCount * sizeof(float));
924         }
925         if (!queue_priorities) {
926             ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
927         }
928
929         if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
930                                   gpu->inst->inst_extensions_count)) {
931             memset(queue_priorities, 0, gpu->queue_props2[i].queueFamilyProperties.queueCount * sizeof(float));
932         } else {
933             memset(queue_priorities, 0, gpu->queue_props[i].queueCount * sizeof(float));
934         }
935
936         gpu->queue_reqs[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
937         gpu->queue_reqs[i].pNext = NULL;
938         gpu->queue_reqs[i].flags = 0;
939         gpu->queue_reqs[i].queueFamilyIndex = i;
940
941         if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
942                                   gpu->inst->inst_extensions_count)) {
943             gpu->queue_reqs[i].queueCount = gpu->queue_props2[i].queueFamilyProperties.queueCount;
944         } else {
945             gpu->queue_reqs[i].queueCount = gpu->queue_props[i].queueCount;
946         }
947
948         gpu->queue_reqs[i].pQueuePriorities = queue_priorities;
949     }
950
951     vkGetPhysicalDeviceMemoryProperties(gpu->obj, &gpu->memory_props);
952
953     vkGetPhysicalDeviceFeatures(gpu->obj, &gpu->features);
954
955     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
956                               gpu->inst->inst_extensions_count)) {
957         gpu->memory_props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR;
958         gpu->memory_props2.pNext = NULL;
959
960         inst->vkGetPhysicalDeviceMemoryProperties2KHR(gpu->obj, &gpu->memory_props2);
961
962         struct pNextChainBuildingBlockInfo chain_info[] = {
963             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR,
964              .mem_size = sizeof(VkPhysicalDevice16BitStorageFeaturesKHR)},
965             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR,
966              .mem_size = sizeof(VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR)},
967             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR,
968              .mem_size = sizeof(VkPhysicalDeviceVariablePointerFeaturesKHR)},
969             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT,
970              .mem_size = sizeof(VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT)},
971             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR,
972              .mem_size = sizeof(VkPhysicalDeviceMultiviewFeaturesKHR)}};
973
974         uint32_t chain_info_len = ARRAY_SIZE(chain_info);
975
976         gpu->features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
977         buildpNextChain((struct VkStructureHeader *)&gpu->features2, chain_info, chain_info_len);
978
979         inst->vkGetPhysicalDeviceFeatures2KHR(gpu->obj, &gpu->features2);
980     }
981
982     AppGetPhysicalDeviceLayerExtensions(gpu, NULL, &gpu->device_extension_count, &gpu->device_extensions);
983 }
984
985 static void AppGpuDestroy(struct AppGpu *gpu) {
986     free(gpu->device_extensions);
987
988     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
989                               gpu->inst->inst_extensions_count)) {
990         freepNextChain(gpu->features2.pNext);
991     }
992
993     for (uint32_t i = 0; i < gpu->queue_count; ++i) {
994         free((void *)gpu->queue_reqs[i].pQueuePriorities);
995     }
996     free(gpu->queue_reqs);
997
998     free(gpu->queue_props);
999     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
1000                               gpu->inst->inst_extensions_count)) {
1001         free(gpu->queue_props2);
1002
1003         freepNextChain(gpu->props2.pNext);
1004     }
1005 }
1006
1007 // clang-format off
1008
1009 //-----------------------------------------------------------
1010
1011 //---------------------------Win32---------------------------
1012 #ifdef VK_USE_PLATFORM_WIN32_KHR
1013
1014 // MS-Windows event handling function:
1015 LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
1016     return (DefWindowProc(hWnd, uMsg, wParam, lParam));
1017 }
1018
1019 static void AppCreateWin32Window(struct AppInstance *inst) {
1020     inst->h_instance = GetModuleHandle(NULL);
1021
1022     WNDCLASSEX win_class;
1023
1024     // Initialize the window class structure:
1025     win_class.cbSize = sizeof(WNDCLASSEX);
1026     win_class.style = CS_HREDRAW | CS_VREDRAW;
1027     win_class.lpfnWndProc = WndProc;
1028     win_class.cbClsExtra = 0;
1029     win_class.cbWndExtra = 0;
1030     win_class.hInstance = inst->h_instance;
1031     win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1032     win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
1033     win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
1034     win_class.lpszMenuName = NULL;
1035     win_class.lpszClassName = APP_SHORT_NAME;
1036     win_class.hInstance = inst->h_instance;
1037     win_class.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
1038     // Register window class:
1039     if (!RegisterClassEx(&win_class)) {
1040         // It didn't work, so try to give a useful error:
1041         fprintf(stderr, "Failed to register the window class!\n");
1042         exit(1);
1043     }
1044     // Create window with the registered class:
1045     RECT wr = { 0, 0, inst->width, inst->height };
1046     AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
1047     inst->h_wnd = CreateWindowEx(0,
1048         APP_SHORT_NAME,       // class name
1049         APP_SHORT_NAME,       // app name
1050         //WS_VISIBLE | WS_SYSMENU |
1051         WS_OVERLAPPEDWINDOW,  // window style
1052         100, 100,             // x/y coords
1053         wr.right - wr.left,   // width
1054         wr.bottom - wr.top,   // height
1055         NULL,                 // handle to parent
1056         NULL,                 // handle to menu
1057         inst->h_instance,      // hInstance
1058         NULL);                // no extra parameters
1059     if (!inst->h_wnd) {
1060         // It didn't work, so try to give a useful error:
1061         fprintf(stderr, "Failed to create a window!\n");
1062         exit(1);
1063     }
1064 }
1065
1066 static void AppCreateWin32Surface(struct AppInstance *inst) {
1067     VkResult U_ASSERT_ONLY err;
1068     VkWin32SurfaceCreateInfoKHR createInfo;
1069     createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
1070     createInfo.pNext = NULL;
1071     createInfo.flags = 0;
1072     createInfo.hinstance = inst->h_instance;
1073     createInfo.hwnd = inst->h_wnd;
1074     err = vkCreateWin32SurfaceKHR(inst->instance, &createInfo, NULL, &inst->surface);
1075     assert(!err);
1076 }
1077
1078 static void AppDestroyWin32Window(struct AppInstance *inst) {
1079     DestroyWindow(inst->h_wnd);
1080 }
1081 #endif //VK_USE_PLATFORM_WIN32_KHR
1082 //-----------------------------------------------------------
1083
1084 #if defined(VK_USE_PLATFORM_XCB_KHR)     || \
1085     defined(VK_USE_PLATFORM_XLIB_KHR)    || \
1086     defined(VK_USE_PLATFORM_WIN32_KHR)
1087 static void AppDestroySurface(struct AppInstance *inst) { //same for all platforms
1088     vkDestroySurfaceKHR(inst->instance, inst->surface, NULL);
1089 }
1090 #endif
1091
1092 //----------------------------XCB----------------------------
1093
1094 #ifdef VK_USE_PLATFORM_XCB_KHR
1095 static void AppCreateXcbWindow(struct AppInstance *inst) {
1096     //--Init Connection--
1097     const xcb_setup_t *setup;
1098     xcb_screen_iterator_t iter;
1099     int scr;
1100
1101     // API guarantees non-null xcb_connection
1102     inst->xcb_connection = xcb_connect(NULL, &scr);
1103     int conn_error = xcb_connection_has_error(inst->xcb_connection);
1104     if (conn_error) {
1105         fprintf(stderr, "XCB failed to connect to the X server due to error:%d.\n", conn_error);
1106         fflush(stderr);
1107         inst->xcb_connection = NULL;
1108     }
1109
1110     setup = xcb_get_setup(inst->xcb_connection);
1111     iter = xcb_setup_roots_iterator(setup);
1112     while (scr-- > 0) {
1113         xcb_screen_next(&iter);
1114     }
1115
1116     inst->xcb_screen = iter.data;
1117     //-------------------
1118
1119     inst->xcb_window = xcb_generate_id(inst->xcb_connection);
1120     xcb_create_window(inst->xcb_connection, XCB_COPY_FROM_PARENT, inst->xcb_window,
1121                       inst->xcb_screen->root, 0, 0, inst->width, inst->height, 0,
1122                       XCB_WINDOW_CLASS_INPUT_OUTPUT, inst->xcb_screen->root_visual,
1123                       0, NULL);
1124
1125     xcb_intern_atom_cookie_t cookie = xcb_intern_atom(inst->xcb_connection, 1, 12, "WM_PROTOCOLS");
1126     xcb_intern_atom_reply_t *reply =  xcb_intern_atom_reply(inst->xcb_connection, cookie, 0);
1127     free(reply);
1128 }
1129
1130 static void AppCreateXcbSurface(struct AppInstance *inst) {
1131     if (!inst->xcb_connection) {
1132         return;
1133     }
1134
1135     VkResult U_ASSERT_ONLY err;
1136     VkXcbSurfaceCreateInfoKHR xcb_createInfo;
1137     xcb_createInfo.sType      = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
1138     xcb_createInfo.pNext      = NULL;
1139     xcb_createInfo.flags      = 0;
1140     xcb_createInfo.connection = inst->xcb_connection;
1141     xcb_createInfo.window     = inst->xcb_window;
1142     err = vkCreateXcbSurfaceKHR(inst->instance, &xcb_createInfo, NULL, &inst->surface);
1143     assert(!err);
1144 }
1145
1146 static void AppDestroyXcbWindow(struct AppInstance *inst) {
1147     if (!inst->xcb_connection) {
1148         return; // Nothing to destroy
1149     }
1150
1151     xcb_destroy_window(inst->xcb_connection, inst->xcb_window);
1152     xcb_disconnect(inst->xcb_connection);
1153 }
1154 //VK_USE_PLATFORM_XCB_KHR
1155 //-----------------------------------------------------------
1156
1157 //----------------------------XLib---------------------------
1158 #elif VK_USE_PLATFORM_XLIB_KHR
1159 static void AppCreateXlibWindow(struct AppInstance *inst) {
1160     long visualMask = VisualScreenMask;
1161     int numberOfVisuals;
1162
1163     inst->xlib_display = XOpenDisplay(NULL);
1164     if (inst->xlib_display == NULL) {
1165         fprintf(stderr, "XLib failed to connect to the X server.\nExiting ...\n");
1166         exit(1);
1167     }
1168
1169     XVisualInfo vInfoTemplate={};
1170     vInfoTemplate.screen = DefaultScreen(inst->xlib_display);
1171     XVisualInfo *visualInfo = XGetVisualInfo(inst->xlib_display, visualMask,
1172                                              &vInfoTemplate, &numberOfVisuals);
1173     inst->xlib_window = XCreateWindow(
1174                 inst->xlib_display, RootWindow(inst->xlib_display, vInfoTemplate.screen), 0, 0,
1175                 inst->width, inst->height, 0, visualInfo->depth, InputOutput,
1176                 visualInfo->visual, 0, NULL);
1177
1178     XSync(inst->xlib_display,false);
1179 }
1180
1181 static void AppCreateXlibSurface(struct AppInstance *inst) {
1182     VkResult U_ASSERT_ONLY err;
1183     VkXlibSurfaceCreateInfoKHR createInfo;
1184     createInfo.sType  = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
1185     createInfo.pNext  = NULL;
1186     createInfo.flags  = 0;
1187     createInfo.dpy    = inst->xlib_display;
1188     createInfo.window = inst->xlib_window;
1189     err = vkCreateXlibSurfaceKHR(inst->instance, &createInfo, NULL, &inst->surface);
1190     assert(!err);
1191 }
1192
1193 static void AppDestroyXlibWindow(struct AppInstance *inst) {
1194     XDestroyWindow(inst->xlib_display, inst->xlib_window);
1195     XCloseDisplay(inst->xlib_display);
1196 }
1197 #endif //VK_USE_PLATFORM_XLIB_KHR
1198 //-----------------------------------------------------------
1199
1200 #if defined(VK_USE_PLATFORM_XCB_KHR)     || \
1201     defined(VK_USE_PLATFORM_XLIB_KHR)    || \
1202     defined(VK_USE_PLATFORM_WIN32_KHR)
1203 static int AppDumpSurfaceFormats(struct AppInstance *inst, struct AppGpu *gpu, FILE *out) {
1204     // Get the list of VkFormat's that are supported
1205     VkResult U_ASSERT_ONLY err;
1206     uint32_t format_count = 0;
1207     err = inst->vkGetPhysicalDeviceSurfaceFormatsKHR(gpu->obj, inst->surface, &format_count, NULL);
1208     assert(!err);
1209
1210     VkSurfaceFormatKHR *surf_formats = (VkSurfaceFormatKHR *)malloc(format_count * sizeof(VkSurfaceFormatKHR));
1211     if (!surf_formats)
1212         ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
1213     err = inst->vkGetPhysicalDeviceSurfaceFormatsKHR(gpu->obj, inst->surface, &format_count, surf_formats);
1214     assert(!err);
1215
1216     if (html_output) {
1217         fprintf(out, "\t\t\t\t<details><summary>Formats: count = <div class='val'>%d</div></summary>", format_count);
1218         if (format_count > 0) {
1219             fprintf(out, "\n");
1220         } else {
1221             fprintf(out, "</details>\n");
1222         }
1223     } else if (human_readable_output) {
1224         printf("Formats:\t\tcount = %d\n", format_count);
1225     }
1226     for (uint32_t i = 0; i < format_count; ++i) {
1227         if (html_output) {
1228             fprintf(out, "\t\t\t\t\t<details><summary><div class='type'>%s</div></summary></details>\n",
1229                     VkFormatString(surf_formats[i].format));
1230         } else if (human_readable_output) {
1231             printf("\t%s\n", VkFormatString(surf_formats[i].format));
1232         }
1233     }
1234     if (format_count > 0 && html_output) {
1235         fprintf(out, "\t\t\t\t</details>\n");
1236     }
1237
1238     fflush(out);
1239     fflush(stdout);
1240     free(surf_formats);
1241
1242     return format_count;
1243 }
1244
1245 static int AppDumpSurfacePresentModes(struct AppInstance *inst, struct AppGpu *gpu, FILE *out) {
1246     // Get the list of VkPresentMode's that are supported:
1247     VkResult U_ASSERT_ONLY err;
1248     uint32_t present_mode_count = 0;
1249     err = inst->vkGetPhysicalDeviceSurfacePresentModesKHR(gpu->obj, inst->surface, &present_mode_count, NULL);
1250     assert(!err);
1251
1252     VkPresentModeKHR *surf_present_modes = (VkPresentModeKHR *)malloc(present_mode_count * sizeof(VkPresentInfoKHR));
1253     if (!surf_present_modes)
1254         ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
1255     err = inst->vkGetPhysicalDeviceSurfacePresentModesKHR(gpu->obj, inst->surface, &present_mode_count, surf_present_modes);
1256     assert(!err);
1257
1258     if (html_output) {
1259         fprintf(out, "\t\t\t\t<details><summary>Present Modes: count = <div class='val'>%d</div></summary>", present_mode_count);
1260         if (present_mode_count > 0) {
1261             fprintf(out, "\n");
1262         } else {
1263             fprintf(out, "</details>");
1264         }
1265     } else if (human_readable_output) {
1266         printf("Present Modes:\t\tcount = %d\n", present_mode_count);
1267     }
1268     for (uint32_t i = 0; i < present_mode_count; ++i) {
1269         if (html_output) {
1270             fprintf(out, "\t\t\t\t\t<details><summary><div class='type'>%s</div></summary></details>\n",
1271                     VkPresentModeString(surf_present_modes[i]));
1272         } else if (human_readable_output) {
1273             printf("\t%s\n", VkPresentModeString(surf_present_modes[i]));
1274         }
1275     }
1276     if (present_mode_count > 0 && html_output) {
1277         fprintf(out, "\t\t\t\t</details>\n");
1278     }
1279
1280     fflush(out);
1281     fflush(stdout);
1282     free(surf_present_modes);
1283
1284     return present_mode_count;
1285 }
1286
1287 static void AppDumpSurfaceCapabilities(struct AppInstance *inst, struct AppGpu *gpu, FILE *out) {
1288     if (CheckExtensionEnabled(VK_KHR_SURFACE_EXTENSION_NAME, gpu->inst->inst_extensions, gpu->inst->inst_extensions_count)) {
1289         inst->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(gpu->obj, inst->surface, &inst->surface_capabilities);
1290
1291         if (html_output) {
1292             fprintf(out, "\t\t\t\t<details><summary>VkSurfaceCapabilitiesKHR</summary>\n");
1293             fprintf(out, "\t\t\t\t\t<details><summary>minImageCount = <div class='val'>%u</div></summary></details>\n", inst->surface_capabilities.minImageCount);
1294             fprintf(out, "\t\t\t\t\t<details><summary>maxImageCount = <div class='val'>%u</div></summary></details>\n", inst->surface_capabilities.maxImageCount);
1295             fprintf(out, "\t\t\t\t\t<details><summary>currentExtent</summary>\n");
1296             fprintf(out, "\t\t\t\t\t\t<details><summary>width = <div class='val'>%u</div></summary></details>\n", inst->surface_capabilities.currentExtent.width);
1297             fprintf(out, "\t\t\t\t\t\t<details><summary>height = <div class='val'>%u</div></summary></details>\n", inst->surface_capabilities.currentExtent.height);
1298             fprintf(out, "\t\t\t\t\t</details>\n");
1299             fprintf(out, "\t\t\t\t\t<details><summary>minImageExtent</summary>\n");
1300             fprintf(out, "\t\t\t\t\t\t<details><summary>width = <div class='val'>%u</div></summary></details>\n", inst->surface_capabilities.minImageExtent.width);
1301             fprintf(out, "\t\t\t\t\t\t<details><summary>height = <div class='val'>%u</div></summary></details>\n", inst->surface_capabilities.minImageExtent.height);
1302             fprintf(out, "\t\t\t\t\t</details>\n");
1303             fprintf(out, "\t\t\t\t\t<details><summary>maxImageExtent</summary>\n");
1304             fprintf(out, "\t\t\t\t\t\t<details><summary>width = <div class='val'>%u</div></summary></details>\n", inst->surface_capabilities.maxImageExtent.width);
1305             fprintf(out, "\t\t\t\t\t\t<details><summary>height = <div class='val'>%u</div></summary></details>\n", inst->surface_capabilities.maxImageExtent.height);
1306             fprintf(out, "\t\t\t\t\t</details>\n");
1307             fprintf(out, "\t\t\t\t\t<details><summary>maxImageArrayLayers = <div class='val'>%u</div></summary></details>\n", inst->surface_capabilities.maxImageArrayLayers);
1308             fprintf(out, "\t\t\t\t\t<details><summary>supportedTransform</summary>\n");
1309             if (inst->surface_capabilities.supportedTransforms == 0) {
1310                 fprintf(out, "\t\t\t\t\t\t<details><summary>None</summary></details>\n");
1311             }
1312             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
1313                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR</div></summary></details>\n");
1314             }
1315             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) {
1316                 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");
1317             }
1318             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR) {
1319                 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");
1320             }
1321             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) {
1322                 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");
1323             }
1324             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR) {
1325                 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");
1326             }
1327             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR) {
1328                 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");
1329             }
1330             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR) {
1331                 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");
1332             }
1333             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR) {
1334                 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");
1335             }
1336             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR) {
1337                 fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR</div></summary></details>\n");
1338             }
1339             fprintf(out, "\t\t\t\t\t</details>\n");
1340             fprintf(out, "\t\t\t\t\t<details><summary>currentTransform</summary>\n");
1341             if (inst->surface_capabilities.currentTransform == 0) {
1342                 fprintf(out, "\t\t\t\t\t\t<details><summary>None</summary></details>\n");
1343             }
1344             if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
1345                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR</div></summary></details>\n");
1346             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) {
1347                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR</div></summary></details>\n");
1348             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR) {
1349                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR</div></summary></details>\n");
1350             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) {
1351                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR</div></summary></details>\n");
1352             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR) {
1353                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR</div></summary></details>\n");
1354             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR) {
1355                 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");
1356             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR) {
1357                 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");
1358             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR) {
1359                 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");
1360             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR) {
1361                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR</div></summary></details>\n");
1362             }
1363             fprintf(out, "\t\t\t\t\t</details>\n");
1364             fprintf(out, "\t\t\t\t\t<details><summary>supportedCompositeAlpha</summary>\n");
1365             if (inst->surface_capabilities.supportedCompositeAlpha == 0) {
1366                 fprintf(out, "\t\t\t\t\t\t<details><summary>None</summary></details>\n");
1367             }
1368             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) {
1369                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR</div></summary></details>\n");
1370             }
1371             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) {
1372                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR</div></summary></details>\n");
1373             }
1374             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) {
1375                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR</div></summary></details>\n");
1376             }
1377             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) {
1378                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR</div></summary></details>\n");
1379             }
1380             fprintf(out, "\t\t\t\t\t</details>\n");
1381             fprintf(out, "\t\t\t\t\t<details><summary>supportedUsageFlags</summary>\n");
1382             if (inst->surface_capabilities.supportedUsageFlags == 0) {
1383                 fprintf(out, "\t\t\t\t\t\t<details><summary>None</summary></details>\n");
1384             }
1385             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) {
1386                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_TRANSFER_SRC_BIT</div></summary></details>\n");
1387             }
1388             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) {
1389                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_TRANSFER_DST_BIT</div></summary></details>\n");
1390             }
1391             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) {
1392                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_SAMPLED_BIT</div></summary></details>\n");
1393             }
1394             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_STORAGE_BIT) {
1395                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_STORAGE_BIT</div></summary></details>\n");
1396             }
1397             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
1398                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT</div></summary></details>\n");
1399             }
1400             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
1401                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT</div></summary></details>\n");
1402             }
1403             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) {
1404                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT</div></summary></details>\n");
1405             }
1406             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) {
1407                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT</div></summary></details>\n");
1408             }
1409             fprintf(out, "\t\t\t\t\t</details>\n");
1410         } else if (human_readable_output) {
1411             printf("\nVkSurfaceCapabilitiesKHR:\n");
1412             printf("=========================\n");
1413             printf("\tminImageCount       = %u\n", inst->surface_capabilities.minImageCount);
1414             printf("\tmaxImageCount       = %u\n", inst->surface_capabilities.maxImageCount);
1415             printf("\tcurrentExtent:\n");
1416             printf("\t\twidth       = %u\n", inst->surface_capabilities.currentExtent.width);
1417             printf("\t\theight      = %u\n", inst->surface_capabilities.currentExtent.height);
1418             printf("\tminImageExtent:\n");
1419             printf("\t\twidth       = %u\n", inst->surface_capabilities.minImageExtent.width);
1420             printf("\t\theight      = %u\n", inst->surface_capabilities.minImageExtent.height);
1421             printf("\tmaxImageExtent:\n");
1422             printf("\t\twidth       = %u\n", inst->surface_capabilities.maxImageExtent.width);
1423             printf("\t\theight      = %u\n", inst->surface_capabilities.maxImageExtent.height);
1424             printf("\tmaxImageArrayLayers = %u\n", inst->surface_capabilities.maxImageArrayLayers);
1425             printf("\tsupportedTransform:\n");
1426             if (inst->surface_capabilities.supportedTransforms == 0) { printf("\t\tNone\n"); }
1427             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR\n"); }
1428             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR\n"); }
1429             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR\n"); }
1430             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR\n"); }
1431             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR\n"); }
1432             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"); }
1433             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"); }
1434             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"); }
1435             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_INHERIT_BIT_KHR\n"); }
1436             printf("\tcurrentTransform:\n");
1437             if (inst->surface_capabilities.currentTransform == 0) { printf("\t\tNone\n"); }
1438             if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR\n"); }
1439             else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR\n"); }
1440             else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR\n"); }
1441             else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR\n"); }
1442             else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR\n"); }
1443             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"); }
1444             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"); }
1445             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"); }
1446             else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR) { printf("\t\tVK_SURFACE_TRANSFORM_INHERIT_BIT_KHR\n"); }
1447             printf("\tsupportedCompositeAlpha:\n");
1448             if (inst->surface_capabilities.supportedCompositeAlpha == 0) { printf("\t\tNone\n"); }
1449             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) { printf("\t\tVK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR\n"); }
1450             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) { printf("\t\tVK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR\n"); }
1451             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) { printf("\t\tVK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR\n"); }
1452             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) { printf("\t\tVK_COMPOSITE_ALPHA_INHERIT_BIT_KHR\n"); }
1453             printf("\tsupportedUsageFlags:\n");
1454             if (inst->surface_capabilities.supportedUsageFlags == 0) { printf("\t\tNone\n"); }
1455             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) { printf("\t\tVK_IMAGE_USAGE_TRANSFER_SRC_BIT\n"); }
1456             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) { printf("\t\tVK_IMAGE_USAGE_TRANSFER_DST_BIT\n"); }
1457             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) { printf("\t\tVK_IMAGE_USAGE_SAMPLED_BIT\n"); }
1458             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_STORAGE_BIT) { printf("\t\tVK_IMAGE_USAGE_STORAGE_BIT\n"); }
1459             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) { printf("\t\tVK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT\n"); }
1460             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { printf("\t\tVK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT\n"); }
1461             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) { printf("\t\tVK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT\n"); }
1462             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) { printf("\t\tVK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT\n"); }
1463         }
1464
1465         // Get additional surface capability information from vkGetPhysicalDeviceSurfaceCapabilities2EXT
1466         if (CheckExtensionEnabled(VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME, gpu->inst->inst_extensions, gpu->inst->inst_extensions_count)) {
1467             memset(&inst->surface_capabilities2_ext, 0, sizeof(VkSurfaceCapabilities2EXT));
1468             inst->surface_capabilities2_ext.sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT;
1469             inst->surface_capabilities2_ext.pNext = NULL;
1470
1471             inst->vkGetPhysicalDeviceSurfaceCapabilities2EXT(gpu->obj, inst->surface, &inst->surface_capabilities2_ext);
1472
1473             if (html_output) {
1474                 fprintf(out, "\t\t\t\t\t<details><summary>VkSurfaceCapabilities2EXT</summary>\n");
1475                 fprintf(out, "\t\t\t\t\t\t<details><summary>supportedSurfaceCounters</summary>\n");
1476                 if (inst->surface_capabilities2_ext.supportedSurfaceCounters == 0) {
1477                     fprintf(out, "\t\t\t\t\t\t\t<details><summary>None</summary></details>\n");
1478                 }
1479                 if (inst->surface_capabilities2_ext.supportedSurfaceCounters & VK_SURFACE_COUNTER_VBLANK_EXT) {
1480                     fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_SURFACE_COUNTER_VBLANK_EXT</div></summary></details>\n");
1481                 }
1482                 fprintf(out, "\t\t\t\t\t\t</details>\n");
1483                 fprintf(out, "\t\t\t\t\t</details>\n");
1484             } else if (human_readable_output) {
1485                 printf("\nVkSurfaceCapabilities2EXT:\n");
1486                 printf("==========================\n");
1487                 printf("\tsupportedSurfaceCounters:\n");
1488                 if (inst->surface_capabilities2_ext.supportedSurfaceCounters == 0) {
1489                     printf("\t\tNone\n");
1490                 }
1491                 if (inst->surface_capabilities2_ext.supportedSurfaceCounters & VK_SURFACE_COUNTER_VBLANK_EXT) {
1492                     printf("\t\tVK_SURFACE_COUNTER_VBLANK_EXT\n");
1493                 }
1494             }
1495         }
1496
1497         // Get additional surface capability information from vkGetPhysicalDeviceSurfaceCapabilities2KHR
1498         if (CheckExtensionEnabled(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, gpu->inst->inst_extensions, gpu->inst->inst_extensions_count)) {
1499             if (CheckExtensionEnabled(VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME, gpu->inst->inst_extensions, gpu->inst->inst_extensions_count)) {
1500                 inst->shared_surface_capabilities.sType = VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR;
1501                 inst->shared_surface_capabilities.pNext = NULL;
1502                 inst->surface_capabilities2.pNext = &inst->shared_surface_capabilities;
1503             } else {
1504                 inst->surface_capabilities2.pNext = NULL;
1505             }
1506
1507             inst->surface_capabilities2.sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
1508
1509             VkPhysicalDeviceSurfaceInfo2KHR surface_info;
1510             surface_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR;
1511             surface_info.pNext = NULL;
1512             surface_info.surface = inst->surface;
1513
1514             inst->vkGetPhysicalDeviceSurfaceCapabilities2KHR(gpu->obj, &surface_info, &inst->surface_capabilities2);
1515
1516             void *place = inst->surface_capabilities2.pNext;
1517             while (place) {
1518                 struct VkStructureHeader* work = (struct VkStructureHeader*) place;
1519                 if (work->sType == VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR) {
1520                     VkSharedPresentSurfaceCapabilitiesKHR* shared_surface_capabilities = (VkSharedPresentSurfaceCapabilitiesKHR*)place;
1521                     if (html_output) {
1522                         fprintf(out, "\t\t\t\t\t<details><summary>VkSharedPresentSurfaceCapabilitiesKHR</summary>\n");
1523                         fprintf(out, "\t\t\t\t\t\t<details><summary>sharedPresentSupportedUsageFlags</summary>\n");
1524                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags == 0) {
1525                             fprintf(out, "\t\t\t\t\t\t\t<details><summary>None</summary></details>\n");
1526                         }
1527                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) {
1528                             fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_TRANSFER_SRC_BIT</div></summary></details>\n");
1529                         }
1530                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) {
1531                             fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_TRANSFER_DST_BIT</div></summary></details>\n");
1532                         }
1533                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) {
1534                             fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_SAMPLED_BIT</div></summary></details>\n");
1535                         }
1536                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_STORAGE_BIT) {
1537                             fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_STORAGE_BIT</div></summary></details>\n");
1538                         }
1539                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
1540                             fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT</div></summary></details>\n");
1541                         }
1542                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
1543                             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");
1544                         }
1545                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) {
1546                             fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT</div></summary></details>\n");
1547                         }
1548                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) {
1549                             fprintf(out, "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT</div></summary></details>\n");
1550                         }
1551                         fprintf(out, "\t\t\t\t\t\t</details>\n");
1552                         fprintf(out, "\t\t\t\t\t</details>\n");
1553                     } else if (human_readable_output) {
1554                         printf("\nVkSharedPresentSurfaceCapabilitiesKHR:\n");
1555                         printf("========================================\n");
1556                         printf("\tsharedPresentSupportedUsageFlags:\n");
1557                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags == 0) { printf("\t\tNone\n"); }
1558                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) { printf("\t\tVK_IMAGE_USAGE_TRANSFER_SRC_BIT\n"); }
1559                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) { printf("\t\tVK_IMAGE_USAGE_TRANSFER_DST_BIT\n"); }
1560                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) { printf("\t\tVK_IMAGE_USAGE_SAMPLED_BIT\n"); }
1561                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_STORAGE_BIT) { printf("\t\tVK_IMAGE_USAGE_STORAGE_BIT\n"); }
1562                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) { printf("\t\tVK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT\n"); }
1563                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) { printf("\t\tVK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT\n"); }
1564                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) { printf("\t\tVK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT\n"); }
1565                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) { printf("\t\tVK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT\n"); }
1566                     }
1567                 }
1568                 place = work->pNext;
1569             }
1570         }
1571         if (html_output) {
1572             fprintf(out, "\t\t\t\t</details>\n");
1573         }
1574     }
1575 }
1576
1577 #endif
1578
1579 static void AppDevDumpFormatProps(const struct AppGpu *gpu, VkFormat fmt, bool *first_in_list, FILE *out) {
1580     VkFormatProperties props;
1581     vkGetPhysicalDeviceFormatProperties(gpu->obj, fmt, &props);
1582     struct {
1583         const char *name;
1584         VkFlags flags;
1585     } features[3];
1586
1587     features[0].name  = "linearTiling   FormatFeatureFlags";
1588     features[0].flags = props.linearTilingFeatures;
1589     features[1].name  = "optimalTiling  FormatFeatureFlags";
1590     features[1].flags = props.optimalTilingFeatures;
1591     features[2].name  = "bufferFeatures FormatFeatureFlags";
1592     features[2].flags = props.bufferFeatures;
1593
1594     if (html_output) {
1595         fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>FORMAT_%s</div></summary>\n", VkFormatString(fmt));
1596     } else if (human_readable_output) {
1597         printf("\nFORMAT_%s:", VkFormatString(fmt));
1598     }
1599     for (uint32_t i = 0; i < ARRAY_SIZE(features); ++i) {
1600         if (html_output) {
1601             fprintf(out, "\t\t\t\t\t\t\t<details open><summary>%s</summary>\n", features[i].name);
1602             if (features[i].flags == 0) {
1603                 fprintf(out, "\t\t\t\t\t\t\t\t<details><summary>None</summary></details>\n");
1604             } else {
1605                 fprintf(out, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
1606                         ((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
1607                         ((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
1608                         ((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
1609                         ((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
1610                         ((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
1611                         ((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
1612                         ((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
1613                         ((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
1614                         ((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
1615                         ((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
1616                         ((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
1617                         ((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
1618                         ((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
1619                         ((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
1620                         ((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
1621                         ((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
1622             }
1623             fprintf(out, "\t\t\t\t\t\t\t</details>\n");
1624         } else if (human_readable_output) {
1625             printf("\n\t%s:", features[i].name);
1626             if (features[i].flags == 0) {
1627                 printf("\n\t\tNone");
1628             } else {
1629                 printf("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
1630                        ((features[i].flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)                  ? "\n\t\tVK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT"                  : ""),  //0x0001
1631                        ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)                  ? "\n\t\tVK_FORMAT_FEATURE_STORAGE_IMAGE_BIT"                  : ""),  //0x0002
1632                        ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT)           ? "\n\t\tVK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT"           : ""),  //0x0004
1633                        ((features[i].flags & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT)           ? "\n\t\tVK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT"           : ""),  //0x0008
1634                        ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT)           ? "\n\t\tVK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT"           : ""),  //0x0010
1635                        ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT)    ? "\n\t\tVK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT"    : ""),  //0x0020
1636                        ((features[i].flags & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT)                  ? "\n\t\tVK_FORMAT_FEATURE_VERTEX_BUFFER_BIT"                  : ""),  //0x0040
1637                        ((features[i].flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)               ? "\n\t\tVK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT"               : ""),  //0x0080
1638                        ((features[i].flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT)         ? "\n\t\tVK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT"         : ""),  //0x0100
1639                        ((features[i].flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)       ? "\n\t\tVK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT"       : ""),  //0x0200
1640                        ((features[i].flags & VK_FORMAT_FEATURE_BLIT_SRC_BIT)                       ? "\n\t\tVK_FORMAT_FEATURE_BLIT_SRC_BIT"                       : ""),  //0x0400
1641                        ((features[i].flags & VK_FORMAT_FEATURE_BLIT_DST_BIT)                       ? "\n\t\tVK_FORMAT_FEATURE_BLIT_DST_BIT"                       : ""),  //0x0800
1642                        ((features[i].flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)    ? "\n\t\tVK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT"    : ""),  //0x1000
1643                        ((features[i].flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG) ? "\n\t\tVK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG" : ""),  //0x2000
1644                        ((features[i].flags & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR)               ? "\n\t\tVK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR"               : ""),  //0x4000
1645                        ((features[i].flags & VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR)               ? "\n\t\tVK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR"               : "")); //0x8000
1646             }
1647         }
1648     }
1649     if (html_output) {
1650         fprintf(out, "\t\t\t\t\t\t</details>\n");
1651     } else if (human_readable_output) {
1652         printf("\n");
1653     }
1654     if (json_output && (props.linearTilingFeatures || props.optimalTilingFeatures || props.bufferFeatures)) {
1655         if (!(*first_in_list)) {
1656             printf(",");
1657         } else {
1658             *first_in_list = false;
1659         }
1660         printf("\n");
1661         printf("\t\t{\n");
1662         printf("\t\t\t\"formatID\": %d,\n", fmt);
1663         printf("\t\t\t\"linearTilingFeatures\": %u,\n", props.linearTilingFeatures);
1664         printf("\t\t\t\"optimalTilingFeatures\": %u,\n", props.optimalTilingFeatures);
1665         printf("\t\t\t\"bufferFeatures\": %u\n", props.bufferFeatures);
1666         printf("\t\t}");
1667     }
1668 }
1669
1670 static void AppDevDump(const struct AppGpu *gpu, FILE *out) {
1671     if (html_output) {
1672         fprintf(out, "\t\t\t\t\t<details><summary>Format Properties</summary>\n");
1673     } else if (human_readable_output) {
1674         printf("Format Properties:\n");
1675         printf("==================");
1676     }
1677     if (json_output) {
1678         printf(",\n");
1679         printf("\t\"ArrayOfVkFormatProperties\": [");
1680     }
1681
1682     bool first_in_list = true;   // Used for commas in json output
1683     for (VkFormat fmt = 0; fmt < VK_FORMAT_RANGE_SIZE; ++fmt) {
1684         AppDevDumpFormatProps(gpu, fmt, &first_in_list, out);
1685     }
1686     if (html_output) {
1687         fprintf(out, "\t\t\t\t\t</details>\n");
1688     }
1689     if (json_output) {
1690         printf("\n\t]");
1691     }
1692 }
1693
1694 #ifdef _WIN32
1695 #define PRINTF_SIZE_T_SPECIFIER    "%Iu"
1696 #else
1697 #define PRINTF_SIZE_T_SPECIFIER    "%zu"
1698 #endif
1699
1700 static void AppGpuDumpFeatures(const struct AppGpu *gpu, FILE *out) {
1701     VkPhysicalDeviceFeatures features;
1702
1703     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
1704         gpu->inst->inst_extensions_count)) {
1705         const VkPhysicalDeviceFeatures *features2_const = &gpu->features2.features;
1706         features = *features2_const;
1707     } else {
1708         const VkPhysicalDeviceFeatures *features_const = &gpu->features;
1709         features = *features_const;
1710     }
1711
1712     if (html_output) {
1713         fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceFeatures</summary>\n");
1714         fprintf(out, "\t\t\t\t\t\t<details><summary>alphaToOne                              = <div class='val'>%u</div></summary></details>\n", features.alphaToOne                             );
1715         fprintf(out, "\t\t\t\t\t\t<details><summary>depthBiasClamp                          = <div class='val'>%u</div></summary></details>\n", features.depthBiasClamp                         );
1716         fprintf(out, "\t\t\t\t\t\t<details><summary>depthBounds                             = <div class='val'>%u</div></summary></details>\n", features.depthBounds                            );
1717         fprintf(out, "\t\t\t\t\t\t<details><summary>depthClamp                              = <div class='val'>%u</div></summary></details>\n", features.depthClamp                             );
1718         fprintf(out, "\t\t\t\t\t\t<details><summary>drawIndirectFirstInstance               = <div class='val'>%u</div></summary></details>\n", features.drawIndirectFirstInstance              );
1719         fprintf(out, "\t\t\t\t\t\t<details><summary>dualSrcBlend                            = <div class='val'>%u</div></summary></details>\n", features.dualSrcBlend                           );
1720         fprintf(out, "\t\t\t\t\t\t<details><summary>fillModeNonSolid                        = <div class='val'>%u</div></summary></details>\n", features.fillModeNonSolid                       );
1721         fprintf(out, "\t\t\t\t\t\t<details><summary>fragmentStoresAndAtomics                = <div class='val'>%u</div></summary></details>\n", features.fragmentStoresAndAtomics               );
1722         fprintf(out, "\t\t\t\t\t\t<details><summary>fullDrawIndexUint32                     = <div class='val'>%u</div></summary></details>\n", features.fullDrawIndexUint32                    );
1723         fprintf(out, "\t\t\t\t\t\t<details><summary>geometryShader                          = <div class='val'>%u</div></summary></details>\n", features.geometryShader                         );
1724         fprintf(out, "\t\t\t\t\t\t<details><summary>imageCubeArray                          = <div class='val'>%u</div></summary></details>\n", features.imageCubeArray                         );
1725         fprintf(out, "\t\t\t\t\t\t<details><summary>independentBlend                        = <div class='val'>%u</div></summary></details>\n", features.independentBlend                       );
1726         fprintf(out, "\t\t\t\t\t\t<details><summary>inheritedQueries                        = <div class='val'>%u</div></summary></details>\n", features.inheritedQueries                       );
1727         fprintf(out, "\t\t\t\t\t\t<details><summary>largePoints                             = <div class='val'>%u</div></summary></details>\n", features.largePoints                            );
1728         fprintf(out, "\t\t\t\t\t\t<details><summary>logicOp                                 = <div class='val'>%u</div></summary></details>\n", features.logicOp                                );
1729         fprintf(out, "\t\t\t\t\t\t<details><summary>multiDrawIndirect                       = <div class='val'>%u</div></summary></details>\n", features.multiDrawIndirect                      );
1730         fprintf(out, "\t\t\t\t\t\t<details><summary>multiViewport                           = <div class='val'>%u</div></summary></details>\n", features.multiViewport                          );
1731         fprintf(out, "\t\t\t\t\t\t<details><summary>occlusionQueryPrecise                   = <div class='val'>%u</div></summary></details>\n", features.occlusionQueryPrecise                  );
1732         fprintf(out, "\t\t\t\t\t\t<details><summary>pipelineStatisticsQuery                 = <div class='val'>%u</div></summary></details>\n", features.pipelineStatisticsQuery                );
1733         fprintf(out, "\t\t\t\t\t\t<details><summary>robustBufferAccess                      = <div class='val'>%u</div></summary></details>\n", features.robustBufferAccess                     );
1734         fprintf(out, "\t\t\t\t\t\t<details><summary>samplerAnisotropy                       = <div class='val'>%u</div></summary></details>\n", features.samplerAnisotropy                      );
1735         fprintf(out, "\t\t\t\t\t\t<details><summary>sampleRateShading                       = <div class='val'>%u</div></summary></details>\n", features.sampleRateShading                      );
1736         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderClipDistance                      = <div class='val'>%u</div></summary></details>\n", features.shaderClipDistance                     );
1737         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderCullDistance                      = <div class='val'>%u</div></summary></details>\n", features.shaderCullDistance                     );
1738         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderFloat64                           = <div class='val'>%u</div></summary></details>\n", features.shaderFloat64                          );
1739         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderImageGatherExtended               = <div class='val'>%u</div></summary></details>\n", features.shaderImageGatherExtended              );
1740         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderInt16                             = <div class='val'>%u</div></summary></details>\n", features.shaderInt16                            );
1741         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderInt64                             = <div class='val'>%u</div></summary></details>\n", features.shaderInt64                            );
1742         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderResourceMinLod                    = <div class='val'>%u</div></summary></details>\n", features.shaderResourceMinLod                   );
1743         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderResourceResidency                 = <div class='val'>%u</div></summary></details>\n", features.shaderResourceResidency                );
1744         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderSampledImageArrayDynamicIndexing  = <div class='val'>%u</div></summary></details>\n", features.shaderSampledImageArrayDynamicIndexing );
1745         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderStorageBufferArrayDynamicIndexing = <div class='val'>%u</div></summary></details>\n", features.shaderStorageBufferArrayDynamicIndexing);
1746         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderStorageImageArrayDynamicIndexing  = <div class='val'>%u</div></summary></details>\n", features.shaderStorageImageArrayDynamicIndexing );
1747         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderStorageImageExtendedFormats       = <div class='val'>%u</div></summary></details>\n", features.shaderStorageImageExtendedFormats      );
1748         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderStorageImageMultisample           = <div class='val'>%u</div></summary></details>\n", features.shaderStorageImageMultisample          );
1749         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderStorageImageReadWithoutFormat     = <div class='val'>%u</div></summary></details>\n", features.shaderStorageImageReadWithoutFormat    );
1750         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderStorageImageWriteWithoutFormat    = <div class='val'>%u</div></summary></details>\n", features.shaderStorageImageWriteWithoutFormat   );
1751         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderTessellationAndGeometryPointSize  = <div class='val'>%u</div></summary></details>\n", features.shaderTessellationAndGeometryPointSize );
1752         fprintf(out, "\t\t\t\t\t\t<details><summary>shaderUniformBufferArrayDynamicIndexing = <div class='val'>%u</div></summary></details>\n", features.shaderUniformBufferArrayDynamicIndexing);
1753         fprintf(out, "\t\t\t\t\t\t<details><summary>sparseBinding                           = <div class='val'>%u</div></summary></details>\n", features.sparseBinding                          );
1754         fprintf(out, "\t\t\t\t\t\t<details><summary>sparseResidency2Samples                 = <div class='val'>%u</div></summary></details>\n", features.sparseResidency2Samples                );
1755         fprintf(out, "\t\t\t\t\t\t<details><summary>sparseResidency4Samples                 = <div class='val'>%u</div></summary></details>\n", features.sparseResidency4Samples                );
1756         fprintf(out, "\t\t\t\t\t\t<details><summary>sparseResidency8Samples                 = <div class='val'>%u</div></summary></details>\n", features.sparseResidency8Samples                );
1757         fprintf(out, "\t\t\t\t\t\t<details><summary>sparseResidency16Samples                = <div class='val'>%u</div></summary></details>\n", features.sparseResidency16Samples               );
1758         fprintf(out, "\t\t\t\t\t\t<details><summary>sparseResidencyAliased                  = <div class='val'>%u</div></summary></details>\n", features.sparseResidencyAliased                 );
1759         fprintf(out, "\t\t\t\t\t\t<details><summary>sparseResidencyBuffer                   = <div class='val'>%u</div></summary></details>\n", features.sparseResidencyBuffer                  );
1760         fprintf(out, "\t\t\t\t\t\t<details><summary>sparseResidencyImage2D                  = <div class='val'>%u</div></summary></details>\n", features.sparseResidencyImage2D                 );
1761         fprintf(out, "\t\t\t\t\t\t<details><summary>sparseResidencyImage3D                  = <div class='val'>%u</div></summary></details>\n", features.sparseResidencyImage3D                 );
1762         fprintf(out, "\t\t\t\t\t\t<details><summary>tessellationShader                      = <div class='val'>%u</div></summary></details>\n", features.tessellationShader                     );
1763         fprintf(out, "\t\t\t\t\t\t<details><summary>textureCompressionASTC_LDR              = <div class='val'>%u</div></summary></details>\n", features.textureCompressionASTC_LDR             );
1764         fprintf(out, "\t\t\t\t\t\t<details><summary>textureCompressionBC                    = <div class='val'>%u</div></summary></details>\n", features.textureCompressionBC                   );
1765         fprintf(out, "\t\t\t\t\t\t<details><summary>textureCompressionETC2                  = <div class='val'>%u</div></summary></details>\n", features.textureCompressionETC2                 );
1766         fprintf(out, "\t\t\t\t\t\t<details><summary>variableMultisampleRate                 = <div class='val'>%u</div></summary></details>\n", features.variableMultisampleRate                );
1767         fprintf(out, "\t\t\t\t\t\t<details><summary>vertexPipelineStoresAndAtomics          = <div class='val'>%u</div></summary></details>\n", features.vertexPipelineStoresAndAtomics         );
1768         fprintf(out, "\t\t\t\t\t\t<details><summary>wideLines                               = <div class='val'>%u</div></summary></details>\n", features.wideLines                              );
1769         fprintf(out, "\t\t\t\t\t</details>\n");
1770     } else if (human_readable_output) {
1771         printf("VkPhysicalDeviceFeatures:\n");
1772         printf("=========================\n");
1773         printf("\talphaToOne                              = %u\n", features.alphaToOne                             );
1774         printf("\tdepthBiasClamp                          = %u\n", features.depthBiasClamp                         );
1775         printf("\tdepthBounds                             = %u\n", features.depthBounds                            );
1776         printf("\tdepthClamp                              = %u\n", features.depthClamp                             );
1777         printf("\tdrawIndirectFirstInstance               = %u\n", features.drawIndirectFirstInstance              );
1778         printf("\tdualSrcBlend                            = %u\n", features.dualSrcBlend                           );
1779         printf("\tfillModeNonSolid                        = %u\n", features.fillModeNonSolid                       );
1780         printf("\tfragmentStoresAndAtomics                = %u\n", features.fragmentStoresAndAtomics               );
1781         printf("\tfullDrawIndexUint32                     = %u\n", features.fullDrawIndexUint32                    );
1782         printf("\tgeometryShader                          = %u\n", features.geometryShader                         );
1783         printf("\timageCubeArray                          = %u\n", features.imageCubeArray                         );
1784         printf("\tindependentBlend                        = %u\n", features.independentBlend                       );
1785         printf("\tinheritedQueries                        = %u\n", features.inheritedQueries                       );
1786         printf("\tlargePoints                             = %u\n", features.largePoints                            );
1787         printf("\tlogicOp                                 = %u\n", features.logicOp                                );
1788         printf("\tmultiDrawIndirect                       = %u\n", features.multiDrawIndirect                      );
1789         printf("\tmultiViewport                           = %u\n", features.multiViewport                          );
1790         printf("\tocclusionQueryPrecise                   = %u\n", features.occlusionQueryPrecise                  );
1791         printf("\tpipelineStatisticsQuery                 = %u\n", features.pipelineStatisticsQuery                );
1792         printf("\trobustBufferAccess                      = %u\n", features.robustBufferAccess                     );
1793         printf("\tsamplerAnisotropy                       = %u\n", features.samplerAnisotropy                      );
1794         printf("\tsampleRateShading                       = %u\n", features.sampleRateShading                      );
1795         printf("\tshaderClipDistance                      = %u\n", features.shaderClipDistance                     );
1796         printf("\tshaderCullDistance                      = %u\n", features.shaderCullDistance                     );
1797         printf("\tshaderFloat64                           = %u\n", features.shaderFloat64                          );
1798         printf("\tshaderImageGatherExtended               = %u\n", features.shaderImageGatherExtended              );
1799         printf("\tshaderInt16                             = %u\n", features.shaderInt16                            );
1800         printf("\tshaderInt64                             = %u\n", features.shaderInt64                            );
1801         printf("\tshaderSampledImageArrayDynamicIndexing  = %u\n", features.shaderSampledImageArrayDynamicIndexing );
1802         printf("\tshaderStorageBufferArrayDynamicIndexing = %u\n", features.shaderStorageBufferArrayDynamicIndexing);
1803         printf("\tshaderStorageImageArrayDynamicIndexing  = %u\n", features.shaderStorageImageArrayDynamicIndexing );
1804         printf("\tshaderStorageImageExtendedFormats       = %u\n", features.shaderStorageImageExtendedFormats      );
1805         printf("\tshaderStorageImageMultisample           = %u\n", features.shaderStorageImageMultisample          );
1806         printf("\tshaderStorageImageReadWithoutFormat     = %u\n", features.shaderStorageImageReadWithoutFormat    );
1807         printf("\tshaderStorageImageWriteWithoutFormat    = %u\n", features.shaderStorageImageWriteWithoutFormat   );
1808         printf("\tshaderTessellationAndGeometryPointSize  = %u\n", features.shaderTessellationAndGeometryPointSize );
1809         printf("\tshaderUniformBufferArrayDynamicIndexing = %u\n", features.shaderUniformBufferArrayDynamicIndexing);
1810         printf("\tsparseBinding                           = %u\n", features.sparseBinding                          );
1811         printf("\tsparseResidency2Samples                 = %u\n", features.sparseResidency2Samples                );
1812         printf("\tsparseResidency4Samples                 = %u\n", features.sparseResidency4Samples                );
1813         printf("\tsparseResidency8Samples                 = %u\n", features.sparseResidency8Samples                );
1814         printf("\tsparseResidency16Samples                = %u\n", features.sparseResidency16Samples               );
1815         printf("\tsparseResidencyAliased                  = %u\n", features.sparseResidencyAliased                 );
1816         printf("\tsparseResidencyBuffer                   = %u\n", features.sparseResidencyBuffer                  );
1817         printf("\tsparseResidencyImage2D                  = %u\n", features.sparseResidencyImage2D                 );
1818         printf("\tsparseResidencyImage3D                  = %u\n", features.sparseResidencyImage3D                 );
1819         printf("\tshaderResourceMinLod                    = %u\n", features.shaderResourceMinLod                   );
1820         printf("\tshaderResourceResidency                 = %u\n", features.shaderResourceResidency                );
1821         printf("\ttessellationShader                      = %u\n", features.tessellationShader                     );
1822         printf("\ttextureCompressionASTC_LDR              = %u\n", features.textureCompressionASTC_LDR             );
1823         printf("\ttextureCompressionBC                    = %u\n", features.textureCompressionBC                   );
1824         printf("\ttextureCompressionETC2                  = %u\n", features.textureCompressionETC2                 );
1825         printf("\tvariableMultisampleRate                 = %u\n", features.variableMultisampleRate                );
1826         printf("\tvertexPipelineStoresAndAtomics          = %u\n", features.vertexPipelineStoresAndAtomics         );
1827         printf("\twideLines                               = %u\n", features.wideLines                              );
1828     }
1829     if (json_output) {
1830         printf(",\n");
1831         printf("\t\"VkPhysicalDeviceFeatures\": {\n");
1832         printf("\t\t\"alphaToOne\": %u,\n",                              features.alphaToOne);
1833         printf("\t\t\"depthBiasClamp\": %u,\n",                          features.depthBiasClamp);
1834         printf("\t\t\"depthBounds\": %u,\n",                             features.depthBounds);
1835         printf("\t\t\"depthClamp\": %u,\n",                              features.depthClamp);
1836         printf("\t\t\"drawIndirectFirstInstance\": %u,\n",               features.drawIndirectFirstInstance);
1837         printf("\t\t\"dualSrcBlend\": %u,\n",                            features.dualSrcBlend);
1838         printf("\t\t\"fillModeNonSolid\": %u,\n",                        features.fillModeNonSolid);
1839         printf("\t\t\"fragmentStoresAndAtomics\": %u,\n",                features.fragmentStoresAndAtomics);
1840         printf("\t\t\"fullDrawIndexUint32\": %u,\n",                     features.fullDrawIndexUint32);
1841         printf("\t\t\"geometryShader\": %u,\n",                          features.geometryShader);
1842         printf("\t\t\"imageCubeArray\": %u,\n",                          features.imageCubeArray);
1843         printf("\t\t\"independentBlend\": %u,\n",                        features.independentBlend);
1844         printf("\t\t\"inheritedQueries\": %u,\n",                        features.inheritedQueries);
1845         printf("\t\t\"largePoints\": %u,\n",                             features.largePoints);
1846         printf("\t\t\"logicOp\": %u,\n",                                 features.logicOp);
1847         printf("\t\t\"multiDrawIndirect\": %u,\n",                       features.multiDrawIndirect);
1848         printf("\t\t\"multiViewport\": %u,\n",                           features.multiViewport);
1849         printf("\t\t\"occlusionQueryPrecise\": %u,\n",                   features.occlusionQueryPrecise);
1850         printf("\t\t\"pipelineStatisticsQuery\": %u,\n",                 features.pipelineStatisticsQuery);
1851         printf("\t\t\"robustBufferAccess\": %u,\n",                      features.robustBufferAccess);
1852         printf("\t\t\"samplerAnisotropy\": %u,\n",                       features.samplerAnisotropy);
1853         printf("\t\t\"sampleRateShading\": %u,\n",                       features.sampleRateShading);
1854         printf("\t\t\"shaderClipDistance\": %u,\n",                      features.shaderClipDistance);
1855         printf("\t\t\"shaderCullDistance\": %u,\n",                      features.shaderCullDistance);
1856         printf("\t\t\"shaderFloat64\": %u,\n",                           features.shaderFloat64);
1857         printf("\t\t\"shaderImageGatherExtended\": %u,\n",               features.shaderImageGatherExtended);
1858         printf("\t\t\"shaderInt16\": %u,\n",                             features.shaderInt16);
1859         printf("\t\t\"shaderInt64\": %u,\n",                             features.shaderInt64);
1860         printf("\t\t\"shaderResourceMinLod\": %u,\n",                    features.shaderResourceMinLod);
1861         printf("\t\t\"shaderResourceResidency\": %u,\n",                 features.shaderResourceResidency);
1862         printf("\t\t\"shaderSampledImageArrayDynamicIndexing\": %u,\n",  features.shaderSampledImageArrayDynamicIndexing);
1863         printf("\t\t\"shaderStorageBufferArrayDynamicIndexing\": %u,\n", features.shaderStorageBufferArrayDynamicIndexing);
1864         printf("\t\t\"shaderStorageImageArrayDynamicIndexing\": %u,\n",  features.shaderStorageImageArrayDynamicIndexing);
1865         printf("\t\t\"shaderStorageImageExtendedFormats\": %u,\n",       features.shaderStorageImageExtendedFormats);
1866         printf("\t\t\"shaderStorageImageMultisample\": %u,\n",           features.shaderStorageImageMultisample);
1867         printf("\t\t\"shaderStorageImageReadWithoutFormat\": %u,\n",     features.shaderStorageImageReadWithoutFormat);
1868         printf("\t\t\"shaderStorageImageWriteWithoutFormat\": %u,\n",    features.shaderStorageImageWriteWithoutFormat);
1869         printf("\t\t\"shaderTessellationAndGeometryPointSize\": %u,\n",  features.shaderTessellationAndGeometryPointSize);
1870         printf("\t\t\"shaderUniformBufferArrayDynamicIndexing\": %u,\n", features.shaderUniformBufferArrayDynamicIndexing);
1871         printf("\t\t\"sparseBinding\": %u,\n",                           features.sparseBinding);
1872         printf("\t\t\"sparseResidency2Samples\": %u,\n",                 features.sparseResidency2Samples);
1873         printf("\t\t\"sparseResidency4Samples\": %u,\n",                 features.sparseResidency4Samples);
1874         printf("\t\t\"sparseResidency8Samples\": %u,\n",                 features.sparseResidency8Samples);
1875         printf("\t\t\"sparseResidency16Samples\": %u,\n",                features.sparseResidency16Samples);
1876         printf("\t\t\"sparseResidencyAliased\": %u,\n",                  features.sparseResidencyAliased);
1877         printf("\t\t\"sparseResidencyBuffer\": %u,\n",                   features.sparseResidencyBuffer);
1878         printf("\t\t\"sparseResidencyImage2D\": %u,\n",                  features.sparseResidencyImage2D);
1879         printf("\t\t\"sparseResidencyImage3D\": %u,\n",                  features.sparseResidencyImage3D);
1880         printf("\t\t\"tessellationShader\": %u,\n",                      features.tessellationShader);
1881         printf("\t\t\"textureCompressionASTC_LDR\": %u,\n",              features.textureCompressionASTC_LDR);
1882         printf("\t\t\"textureCompressionBC\": %u,\n",                    features.textureCompressionBC);
1883         printf("\t\t\"textureCompressionETC2\": %u,\n",                  features.textureCompressionETC2);
1884         printf("\t\t\"variableMultisampleRate\": %u,\n",                 features.variableMultisampleRate);
1885         printf("\t\t\"vertexPipelineStoresAndAtomics\": %u,\n",          features.vertexPipelineStoresAndAtomics);
1886         printf("\t\t\"wideLines\": %u\n",                                features.wideLines);
1887         printf("\t}");
1888     }
1889
1890     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
1891         gpu->inst->inst_extensions_count)) {
1892         void *place = gpu->features2.pNext;
1893         while (place) {
1894             struct VkStructureHeader *structure = (struct VkStructureHeader*) place;
1895             if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR && CheckPhysicalDeviceExtensionIncluded(VK_KHR_16BIT_STORAGE_EXTENSION_NAME, gpu->device_extensions, gpu->device_extension_count)) {
1896                 VkPhysicalDevice16BitStorageFeaturesKHR *b16_store_features = (VkPhysicalDevice16BitStorageFeaturesKHR*)structure;
1897                 if (html_output) {
1898                     fprintf(out, "\n\t\t\t\t\t<details><summary>VkPhysicalDevice16BitStorageFeatures</summary>\n");
1899                     fprintf(out, "\t\t\t\t\t\t<details><summary>storageBuffer16BitAccess           = <div class='val'>%u</div></summary></details>\n", b16_store_features->storageBuffer16BitAccess          );
1900                     fprintf(out, "\t\t\t\t\t\t<details><summary>uniformAndStorageBuffer16BitAccess = <div class='val'>%u</div></summary></details>\n", b16_store_features->uniformAndStorageBuffer16BitAccess);
1901                     fprintf(out, "\t\t\t\t\t\t<details><summary>storagePushConstant16              = <div class='val'>%u</div></summary></details>\n", b16_store_features->storagePushConstant16             );
1902                     fprintf(out, "\t\t\t\t\t\t<details><summary>storageInputOutput16               = <div class='val'>%u</div></summary></details>\n", b16_store_features->storageInputOutput16              );
1903                     fprintf(out, "\t\t\t\t\t</details>\n");
1904                 } else if (human_readable_output) {
1905                     printf("\nVkPhysicalDevice16BitStorageFeatures:\n");
1906                     printf("=====================================\n");
1907                     printf("\tstorageBuffer16BitAccess           = %u\n", b16_store_features->storageBuffer16BitAccess          );
1908                     printf("\tuniformAndStorageBuffer16BitAccess = %u\n", b16_store_features->uniformAndStorageBuffer16BitAccess);
1909                     printf("\tstoragePushConstant16              = %u\n", b16_store_features->storagePushConstant16             );
1910                     printf("\tstorageInputOutput16               = %u\n", b16_store_features->storageInputOutput16              );
1911                 }
1912             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR && CheckPhysicalDeviceExtensionIncluded(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, gpu->device_extensions, gpu->device_extension_count)) {
1913                 VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR *sampler_ycbcr_features = (VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR*)structure;
1914                 if (html_output) {
1915                     fprintf(out, "\n\t\t\t\t\t<details><summary>VkPhysicalDeviceSamplerYcbcrConversionFeatures</summary>\n");
1916                     fprintf(out, "\t\t\t\t\t\t<details><summary>samplerYcbcrConversion = <div class='val'>%u</div></summary></details>\n", sampler_ycbcr_features->samplerYcbcrConversion);
1917                     fprintf(out, "\t\t\t\t\t</details>\n");
1918                 } else if (human_readable_output) {
1919                     printf("\nVkPhysicalDeviceSamplerYcbcrConversionFeatures:\n");
1920                     printf("===============================================\n");
1921                     printf("\tsamplerYcbcrConversion = %u\n", sampler_ycbcr_features->samplerYcbcrConversion);
1922                 }
1923             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR && CheckPhysicalDeviceExtensionIncluded(VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME, gpu->device_extensions, gpu->device_extension_count)) {
1924                 VkPhysicalDeviceVariablePointerFeaturesKHR *var_pointer_features = (VkPhysicalDeviceVariablePointerFeaturesKHR*)structure;
1925                 if (html_output) {
1926                     fprintf(out, "\n\t\t\t\t\t<details><summary>VkPhysicalDeviceVariablePointerFeatures</summary>\n");
1927                     fprintf(out, "\t\t\t\t\t\t<details><summary>variablePointersStorageBuffer = <div class='val'>%u</div></summary></details>\n", var_pointer_features->variablePointersStorageBuffer);
1928                     fprintf(out, "\t\t\t\t\t\t<details><summary>variablePointers              = <div class='val'>%u</div></summary></details>\n", var_pointer_features->variablePointers             );
1929                     fprintf(out, "\t\t\t\t\t</details>\n");
1930                 } else if (human_readable_output) {
1931                     printf("\nVkPhysicalDeviceVariablePointerFeatures:\n");
1932                     printf("========================================\n");
1933                     printf("\tvariablePointersStorageBuffer = %u\n", var_pointer_features->variablePointersStorageBuffer);
1934                     printf("\tvariablePointers              = %u\n", var_pointer_features->variablePointers             );
1935                 }
1936             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT && CheckPhysicalDeviceExtensionIncluded(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME, gpu->device_extensions, gpu->device_extension_count)) {
1937                 VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT *blend_op_adv_features = (VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT*)structure;
1938                 if (html_output) {
1939                     fprintf(out, "\n\t\t\t\t\t<details><summary>VkPhysicalDeviceBlendOperationAdvancedFeatures</summary>\n");
1940                     fprintf(out, "\t\t\t\t\t\t<details><summary>advancedBlendCoherentOperations = <div class='val'>%u</div></summary></details>\n", blend_op_adv_features->advancedBlendCoherentOperations);
1941                     fprintf(out, "\t\t\t\t\t</details>\n");
1942                 } else if (human_readable_output) {
1943                     printf("\nVkPhysicalDeviceBlendOperationAdvancedFeatures:\n");
1944                     printf("===============================================\n");
1945                     printf("\tadvancedBlendCoherentOperations = %u\n", blend_op_adv_features->advancedBlendCoherentOperations);
1946                 }
1947             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR && CheckPhysicalDeviceExtensionIncluded(VK_KHR_MULTIVIEW_EXTENSION_NAME, gpu->device_extensions, gpu->device_extension_count)) {
1948                 VkPhysicalDeviceMultiviewFeaturesKHR *multiview_features = (VkPhysicalDeviceMultiviewFeaturesKHR*)structure;
1949                 if (html_output) {
1950                     fprintf(out, "\n\t\t\t\t\t<details><summary>VkPhysicalDeviceMultiviewFeatures</summary>\n");
1951                     fprintf(out, "\t\t\t\t\t\t<details><summary>multiview                   = <div class='val'>%u</div></summary></details>\n", multiview_features->multiview                  );
1952                     fprintf(out, "\t\t\t\t\t\t<details><summary>multiviewGeometryShader     = <div class='val'>%u</div></summary></details>\n", multiview_features->multiviewGeometryShader    );
1953                     fprintf(out, "\t\t\t\t\t\t<details><summary>multiviewTessellationShader = <div class='val'>%u</div></summary></details>\n", multiview_features->multiviewTessellationShader);
1954                     fprintf(out, "\t\t\t\t\t</details>\n");
1955                 }
1956                 else if (human_readable_output) {
1957                     printf("\nVkPhysicalDeviceMultiviewFeatures:\n");
1958                     printf("==================================\n");
1959                     printf("\tmultiview                   = %u\n", multiview_features->multiview                  );
1960                     printf("\tmultiviewGeometryShader     = %u\n", multiview_features->multiviewGeometryShader    );
1961                     printf("\tmultiviewTessellationShader = %u\n", multiview_features->multiviewTessellationShader);
1962                 }
1963             }
1964             place = structure->pNext;
1965         }
1966     }
1967 }
1968
1969 static void AppDumpSparseProps(const VkPhysicalDeviceSparseProperties *sparse_props, FILE *out) {
1970     if (html_output) {
1971         fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceSparseProperties</summary>\n");
1972         fprintf(out, "\t\t\t\t\t\t<details><summary>residencyStandard2DBlockShape            = <div class='val'>%u</div></summary></details>\n", sparse_props->residencyStandard2DBlockShape           );
1973         fprintf(out, "\t\t\t\t\t\t<details><summary>residencyStandard2DMultisampleBlockShape = <div class='val'>%u</div></summary></details>\n", sparse_props->residencyStandard2DMultisampleBlockShape);
1974         fprintf(out, "\t\t\t\t\t\t<details><summary>residencyStandard3DBlockShape            = <div class='val'>%u</div></summary></details>\n", sparse_props->residencyStandard3DBlockShape           );
1975         fprintf(out, "\t\t\t\t\t\t<details><summary>residencyAlignedMipSize                  = <div class='val'>%u</div></summary></details>\n", sparse_props->residencyAlignedMipSize                 );
1976         fprintf(out, "\t\t\t\t\t\t<details><summary>residencyNonResidentStrict               = <div class='val'>%u</div></summary></details>\n", sparse_props->residencyNonResidentStrict              );
1977         fprintf(out, "\t\t\t\t\t</details>\n");
1978     } else if (human_readable_output) {
1979         printf("\tVkPhysicalDeviceSparseProperties:\n");
1980         printf("\t---------------------------------\n");
1981         printf("\t\tresidencyStandard2DBlockShape            = %u\n", sparse_props->residencyStandard2DBlockShape           );
1982         printf("\t\tresidencyStandard2DMultisampleBlockShape = %u\n", sparse_props->residencyStandard2DMultisampleBlockShape);
1983         printf("\t\tresidencyStandard3DBlockShape            = %u\n", sparse_props->residencyStandard3DBlockShape           );
1984         printf("\t\tresidencyAlignedMipSize                  = %u\n", sparse_props->residencyAlignedMipSize                 );
1985         printf("\t\tresidencyNonResidentStrict               = %u\n", sparse_props->residencyNonResidentStrict              );
1986     }
1987     if (json_output) {
1988         printf(",\n");
1989         printf("\t\t\"sparseProperties\": {\n");
1990         printf("\t\t\t\"residencyAlignedMipSize\": %u,\n",                  sparse_props->residencyAlignedMipSize);
1991         printf("\t\t\t\"residencyNonResidentStrict\": %u,\n",               sparse_props->residencyNonResidentStrict);
1992         printf("\t\t\t\"residencyStandard2DBlockShape\": %u,\n",            sparse_props->residencyStandard2DBlockShape);
1993         printf("\t\t\t\"residencyStandard2DMultisampleBlockShape\": %u,\n", sparse_props->residencyStandard2DMultisampleBlockShape);
1994         printf("\t\t\t\"residencyStandard3DBlockShape\": %u\n",             sparse_props->residencyStandard3DBlockShape);
1995         printf("\t\t}");
1996     }
1997 }
1998
1999 static void AppDumpLimits(const VkPhysicalDeviceLimits *limits, FILE *out) {
2000     if (html_output) {
2001         fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceLimits</summary>\n");
2002         fprintf(out, "\t\t\t\t\t\t<details><summary>maxImageDimension1D                     = <div class='val'>%u</div></summary></details>\n",                 limits->maxImageDimension1D                    );
2003         fprintf(out, "\t\t\t\t\t\t<details><summary>maxImageDimension2D                     = <div class='val'>%u</div></summary></details>\n",                 limits->maxImageDimension2D                    );
2004         fprintf(out, "\t\t\t\t\t\t<details><summary>maxImageDimension3D                     = <div class='val'>%u</div></summary></details>\n",                 limits->maxImageDimension3D                    );
2005         fprintf(out, "\t\t\t\t\t\t<details><summary>maxImageDimensionCube                   = <div class='val'>%u</div></summary></details>\n",                 limits->maxImageDimensionCube                  );
2006         fprintf(out, "\t\t\t\t\t\t<details><summary>maxImageArrayLayers                     = <div class='val'>%u</div></summary></details>\n",                 limits->maxImageArrayLayers                    );
2007         fprintf(out, "\t\t\t\t\t\t<details><summary>maxTexelBufferElements                  = <div class='val'>0x%" PRIxLEAST32 "</div></summary></details>\n", limits->maxTexelBufferElements                 );
2008         fprintf(out, "\t\t\t\t\t\t<details><summary>maxUniformBufferRange                   = <div class='val'>0x%" PRIxLEAST32 "</div></summary></details>\n", limits->maxUniformBufferRange                  );
2009         fprintf(out, "\t\t\t\t\t\t<details><summary>maxStorageBufferRange                   = <div class='val'>0x%" PRIxLEAST32 "</div></summary></details>\n", limits->maxStorageBufferRange                  );
2010         fprintf(out, "\t\t\t\t\t\t<details><summary>maxPushConstantsSize                    = <div class='val'>%u</div></summary></details>\n",                 limits->maxPushConstantsSize                   );
2011         fprintf(out, "\t\t\t\t\t\t<details><summary>maxMemoryAllocationCount                = <div class='val'>%u</div></summary></details>\n",                 limits->maxMemoryAllocationCount               );
2012         fprintf(out, "\t\t\t\t\t\t<details><summary>maxSamplerAllocationCount               = <div class='val'>%u</div></summary></details>\n",                 limits->maxSamplerAllocationCount              );
2013         fprintf(out, "\t\t\t\t\t\t<details><summary>bufferImageGranularity                  = <div class='val'>0x%" PRIxLEAST64 "</div></summary></details>\n", limits->bufferImageGranularity                 );
2014         fprintf(out, "\t\t\t\t\t\t<details><summary>sparseAddressSpaceSize                  = <div class='val'>0x%" PRIxLEAST64 "</div></summary></details>\n", limits->sparseAddressSpaceSize                 );
2015         fprintf(out, "\t\t\t\t\t\t<details><summary>maxBoundDescriptorSets                  = <div class='val'>%u</div></summary></details>\n",                 limits->maxBoundDescriptorSets                 );
2016         fprintf(out, "\t\t\t\t\t\t<details><summary>maxPerStageDescriptorSamplers           = <div class='val'>%u</div></summary></details>\n",                 limits->maxPerStageDescriptorSamplers          );
2017         fprintf(out, "\t\t\t\t\t\t<details><summary>maxPerStageDescriptorUniformBuffers     = <div class='val'>%u</div></summary></details>\n",                 limits->maxPerStageDescriptorUniformBuffers    );
2018         fprintf(out, "\t\t\t\t\t\t<details><summary>maxPerStageDescriptorStorageBuffers     = <div class='val'>%u</div></summary></details>\n",                 limits->maxPerStageDescriptorStorageBuffers    );
2019         fprintf(out, "\t\t\t\t\t\t<details><summary>maxPerStageDescriptorSampledImages      = <div class='val'>%u</div></summary></details>\n",                 limits->maxPerStageDescriptorSampledImages     );
2020         fprintf(out, "\t\t\t\t\t\t<details><summary>maxPerStageDescriptorStorageImages      = <div class='val'>%u</div></summary></details>\n",                 limits->maxPerStageDescriptorStorageImages     );
2021         fprintf(out, "\t\t\t\t\t\t<details><summary>maxPerStageDescriptorInputAttachments   = <div class='val'>%u</div></summary></details>\n",                 limits->maxPerStageDescriptorInputAttachments  );
2022         fprintf(out, "\t\t\t\t\t\t<details><summary>maxPerStageResources                    = <div class='val'>%u</div></summary></details>\n",                 limits->maxPerStageResources                   );
2023         fprintf(out, "\t\t\t\t\t\t<details><summary>maxDescriptorSetSamplers                = <div class='val'>%u</div></summary></details>\n",                 limits->maxDescriptorSetSamplers               );
2024         fprintf(out, "\t\t\t\t\t\t<details><summary>maxDescriptorSetUniformBuffers          = <div class='val'>%u</div></summary></details>\n",                 limits->maxDescriptorSetUniformBuffers         );
2025         fprintf(out, "\t\t\t\t\t\t<details><summary>maxDescriptorSetUniformBuffersDynamic   = <div class='val'>%u</div></summary></details>\n",                 limits->maxDescriptorSetUniformBuffersDynamic  );
2026         fprintf(out, "\t\t\t\t\t\t<details><summary>maxDescriptorSetStorageBuffers          = <div class='val'>%u</div></summary></details>\n",                 limits->maxDescriptorSetStorageBuffers         );
2027         fprintf(out, "\t\t\t\t\t\t<details><summary>maxDescriptorSetStorageBuffersDynamic   = <div class='val'>%u</div></summary></details>\n",                 limits->maxDescriptorSetStorageBuffersDynamic  );
2028         fprintf(out, "\t\t\t\t\t\t<details><summary>maxDescriptorSetSampledImages           = <div class='val'>%u</div></summary></details>\n",                 limits->maxDescriptorSetSampledImages          );
2029         fprintf(out, "\t\t\t\t\t\t<details><summary>maxDescriptorSetStorageImages           = <div class='val'>%u</div></summary></details>\n",                 limits->maxDescriptorSetStorageImages          );
2030         fprintf(out, "\t\t\t\t\t\t<details><summary>maxDescriptorSetInputAttachments        = <div class='val'>%u</div></summary></details>\n",                 limits->maxDescriptorSetInputAttachments       );
2031         fprintf(out, "\t\t\t\t\t\t<details><summary>maxVertexInputAttributes                = <div class='val'>%u</div></summary></details>\n",                 limits->maxVertexInputAttributes               );
2032         fprintf(out, "\t\t\t\t\t\t<details><summary>maxVertexInputBindings                  = <div class='val'>%u</div></summary></details>\n",                 limits->maxVertexInputBindings                 );
2033         fprintf(out, "\t\t\t\t\t\t<details><summary>maxVertexInputAttributeOffset           = <div class='val'>0x%" PRIxLEAST32 "</div></summary></details>\n", limits->maxVertexInputAttributeOffset          );
2034         fprintf(out, "\t\t\t\t\t\t<details><summary>maxVertexInputBindingStride             = <div class='val'>0x%" PRIxLEAST32 "</div></summary></details>\n", limits->maxVertexInputBindingStride            );
2035         fprintf(out, "\t\t\t\t\t\t<details><summary>maxVertexOutputComponents               = <div class='val'>%u</div></summary></details>\n",                 limits->maxVertexOutputComponents              );
2036         fprintf(out, "\t\t\t\t\t\t<details><summary>maxTessellationGenerationLevel          = <div class='val'>%u</div></summary></details>\n",                 limits->maxTessellationGenerationLevel         );
2037         fprintf(out, "\t\t\t\t\t\t<details><summary>maxTessellationPatchSize                        = <div class='val'>%u</div></summary></details>\n",                 limits->maxTessellationPatchSize                       );
2038         fprintf(out, "\t\t\t\t\t\t<details><summary>maxTessellationControlPerVertexInputComponents  = <div class='val'>%u</div></summary></details>\n",                 limits->maxTessellationControlPerVertexInputComponents );
2039         fprintf(out, "\t\t\t\t\t\t<details><summary>maxTessellationControlPerVertexOutputComponents = <div class='val'>%u</div></summary></details>\n",                 limits->maxTessellationControlPerVertexOutputComponents);
2040         fprintf(out, "\t\t\t\t\t\t<details><summary>maxTessellationControlPerPatchOutputComponents  = <div class='val'>%u</div></summary></details>\n",                 limits->maxTessellationControlPerPatchOutputComponents );
2041         fprintf(out, "\t\t\t\t\t\t<details><summary>maxTessellationControlTotalOutputComponents     = <div class='val'>%u</div></summary></details>\n",                 limits->maxTessellationControlTotalOutputComponents    );
2042         fprintf(out, "\t\t\t\t\t\t<details><summary>maxTessellationEvaluationInputComponents        = <div class='val'>%u</div></summary></details>\n",                 limits->maxTessellationEvaluationInputComponents       );
2043         fprintf(out, "\t\t\t\t\t\t<details><summary>maxTessellationEvaluationOutputComponents       = <div class='val'>%u</div></summary></details>\n",                 limits->maxTessellationEvaluationOutputComponents      );
2044         fprintf(out, "\t\t\t\t\t\t<details><summary>maxGeometryShaderInvocations            = <div class='val'>%u</div></summary></details>\n",                 limits->maxGeometryShaderInvocations           );
2045         fprintf(out, "\t\t\t\t\t\t<details><summary>maxGeometryInputComponents              = <div class='val'>%u</div></summary></details>\n",                 limits->maxGeometryInputComponents             );
2046         fprintf(out, "\t\t\t\t\t\t<details><summary>maxGeometryOutputComponents             = <div class='val'>%u</div></summary></details>\n",                 limits->maxGeometryOutputComponents            );
2047         fprintf(out, "\t\t\t\t\t\t<details><summary>maxGeometryOutputVertices               = <div class='val'>%u</div></summary></details>\n",                 limits->maxGeometryOutputVertices              );
2048         fprintf(out, "\t\t\t\t\t\t<details><summary>maxGeometryTotalOutputComponents        = <div class='val'>%u</div></summary></details>\n",                 limits->maxGeometryTotalOutputComponents       );
2049         fprintf(out, "\t\t\t\t\t\t<details><summary>maxFragmentInputComponents              = <div class='val'>%u</div></summary></details>\n",                 limits->maxFragmentInputComponents             );
2050         fprintf(out, "\t\t\t\t\t\t<details><summary>maxFragmentOutputAttachments            = <div class='val'>%u</div></summary></details>\n",                 limits->maxFragmentOutputAttachments           );
2051         fprintf(out, "\t\t\t\t\t\t<details><summary>maxFragmentDualSrcAttachments           = <div class='val'>%u</div></summary></details>\n",                 limits->maxFragmentDualSrcAttachments          );
2052         fprintf(out, "\t\t\t\t\t\t<details><summary>maxFragmentCombinedOutputResources      = <div class='val'>%u</div></summary></details>\n",                 limits->maxFragmentCombinedOutputResources     );
2053         fprintf(out, "\t\t\t\t\t\t<details><summary>maxComputeSharedMemorySize              = <div class='val'>0x%" PRIxLEAST32 "</div></summary></details>\n", limits->maxComputeSharedMemorySize             );
2054         fprintf(out, "\t\t\t\t\t\t<details><summary>maxComputeWorkGroupCount[0]             = <div class='val'>%u</div></summary></details>\n",                 limits->maxComputeWorkGroupCount[0]            );
2055         fprintf(out, "\t\t\t\t\t\t<details><summary>maxComputeWorkGroupCount[1]             = <div class='val'>%u</div></summary></details>\n",                 limits->maxComputeWorkGroupCount[1]            );
2056         fprintf(out, "\t\t\t\t\t\t<details><summary>maxComputeWorkGroupCount[2]             = <div class='val'>%u</div></summary></details>\n",                 limits->maxComputeWorkGroupCount[2]            );
2057         fprintf(out, "\t\t\t\t\t\t<details><summary>maxComputeWorkGroupInvocations          = <div class='val'>%u</div></summary></details>\n",                 limits->maxComputeWorkGroupInvocations         );
2058         fprintf(out, "\t\t\t\t\t\t<details><summary>maxComputeWorkGroupSize[0]              = <div class='val'>%u</div></summary></details>\n",                 limits->maxComputeWorkGroupSize[0]             );
2059         fprintf(out, "\t\t\t\t\t\t<details><summary>maxComputeWorkGroupSize[1]              = <div class='val'>%u</div></summary></details>\n",                 limits->maxComputeWorkGroupSize[1]             );
2060         fprintf(out, "\t\t\t\t\t\t<details><summary>maxComputeWorkGroupSize[2]              = <div class='val'>%u</div></summary></details>\n",                 limits->maxComputeWorkGroupSize[2]             );
2061         fprintf(out, "\t\t\t\t\t\t<details><summary>subPixelPrecisionBits                   = <div class='val'>%u</div></summary></details>\n",                 limits->subPixelPrecisionBits                  );
2062         fprintf(out, "\t\t\t\t\t\t<details><summary>subTexelPrecisionBits                   = <div class='val'>%u</div></summary></details>\n",                 limits->subTexelPrecisionBits                  );
2063         fprintf(out, "\t\t\t\t\t\t<details><summary>mipmapPrecisionBits                     = <div class='val'>%u</div></summary></details>\n",                 limits->mipmapPrecisionBits                    );
2064         fprintf(out, "\t\t\t\t\t\t<details><summary>maxDrawIndexedIndexValue                = <div class='val'>%u</div></summary></details>\n",                 limits->maxDrawIndexedIndexValue               );
2065         fprintf(out, "\t\t\t\t\t\t<details><summary>maxDrawIndirectCount                    = <div class='val'>%u</div></summary></details>\n",                 limits->maxDrawIndirectCount                   );
2066         fprintf(out, "\t\t\t\t\t\t<details><summary>maxSamplerLodBias                       = <div class='val'>%f</div></summary></details>\n",                 limits->maxSamplerLodBias                      );
2067         fprintf(out, "\t\t\t\t\t\t<details><summary>maxSamplerAnisotropy                    = <div class='val'>%f</div></summary></details>\n",                 limits->maxSamplerAnisotropy                   );
2068         fprintf(out, "\t\t\t\t\t\t<details><summary>maxViewports                            = <div class='val'>%u</div></summary></details>\n",                 limits->maxViewports                           );
2069         fprintf(out, "\t\t\t\t\t\t<details><summary>maxViewportDimensions[0]                = <div class='val'>%u</div></summary></details>\n",                 limits->maxViewportDimensions[0]               );
2070         fprintf(out, "\t\t\t\t\t\t<details><summary>maxViewportDimensions[1]                = <div class='val'>%u</div></summary></details>\n",                 limits->maxViewportDimensions[1]               );
2071         fprintf(out, "\t\t\t\t\t\t<details><summary>viewportBoundsRange[0]                  =<div class='val'>%13f</div></summary></details>\n",                limits->viewportBoundsRange[0]                 );
2072         fprintf(out, "\t\t\t\t\t\t<details><summary>viewportBoundsRange[1]                  =<div class='val'>%13f</div></summary></details>\n",                limits->viewportBoundsRange[1]                 );
2073         fprintf(out, "\t\t\t\t\t\t<details><summary>viewportSubPixelBits                    = <div class='val'>%u</div></summary></details>\n",                 limits->viewportSubPixelBits                   );
2074         fprintf(out, "\t\t\t\t\t\t<details><summary>minMemoryMapAlignment                   = <div class='val'>" PRINTF_SIZE_T_SPECIFIER "</div></summary></details>\n", limits->minMemoryMapAlignment         );
2075         fprintf(out, "\t\t\t\t\t\t<details><summary>minTexelBufferOffsetAlignment           = <div class='val'>0x%" PRIxLEAST64 "</div></summary></details>\n", limits->minTexelBufferOffsetAlignment          );
2076         fprintf(out, "\t\t\t\t\t\t<details><summary>minUniformBufferOffsetAlignment         = <div class='val'>0x%" PRIxLEAST64 "</div></summary></details>\n", limits->minUniformBufferOffsetAlignment        );
2077         fprintf(out, "\t\t\t\t\t\t<details><summary>minStorageBufferOffsetAlignment         = <div class='val'>0x%" PRIxLEAST64 "</div></summary></details>\n", limits->minStorageBufferOffsetAlignment        );
2078         fprintf(out, "\t\t\t\t\t\t<details><summary>minTexelOffset                          =<div class='val'>%3d</div></summary></details>\n",                 limits->minTexelOffset                         );
2079         fprintf(out, "\t\t\t\t\t\t<details><summary>maxTexelOffset                          =<div class='val'>%3d</div></summary></details>\n",                 limits->maxTexelOffset                         );
2080         fprintf(out, "\t\t\t\t\t\t<details><summary>minTexelGatherOffset                    =<div class='val'>%3d</div></summary></details>\n",                 limits->minTexelGatherOffset                   );
2081         fprintf(out, "\t\t\t\t\t\t<details><summary>maxTexelGatherOffset                    =<div class='val'>%3d</div></summary></details>\n",                 limits->maxTexelGatherOffset                   );
2082         fprintf(out, "\t\t\t\t\t\t<details><summary>minInterpolationOffset                  =<div class='val'>%9f</div></summary></details>\n",                 limits->minInterpolationOffset                 );
2083         fprintf(out, "\t\t\t\t\t\t<details><summary>maxInterpolationOffset                  =<div class='val'>%9f</div></summary></details>\n",                 limits->maxInterpolationOffset                 );
2084         fprintf(out, "\t\t\t\t\t\t<details><summary>subPixelInterpolationOffsetBits         = <div class='val'>%u</div></summary></details>\n",                 limits->subPixelInterpolationOffsetBits        );
2085         fprintf(out, "\t\t\t\t\t\t<details><summary>maxFramebufferWidth                     = <div class='val'>%u</div></summary></details>\n",                 limits->maxFramebufferWidth                    );
2086         fprintf(out, "\t\t\t\t\t\t<details><summary>maxFramebufferHeight                    = <div class='val'>%u</div></summary></details>\n",                 limits->maxFramebufferHeight                   );
2087         fprintf(out, "\t\t\t\t\t\t<details><summary>maxFramebufferLayers                    = <div class='val'>%u</div></summary></details>\n",                 limits->maxFramebufferLayers                   );
2088         fprintf(out, "\t\t\t\t\t\t<details><summary>framebufferColorSampleCounts            = <div class='val'>%u</div></summary></details>\n",                 limits->framebufferColorSampleCounts           );
2089         fprintf(out, "\t\t\t\t\t\t<details><summary>framebufferDepthSampleCounts            = <div class='val'>%u</div></summary></details>\n",                 limits->framebufferDepthSampleCounts           );
2090         fprintf(out, "\t\t\t\t\t\t<details><summary>framebufferStencilSampleCounts          = <div class='val'>%u</div></summary></details>\n",                 limits->framebufferStencilSampleCounts         );
2091         fprintf(out, "\t\t\t\t\t\t<details><summary>framebufferNoAttachmentsSampleCounts    = <div class='val'>%u</div></summary></details>\n",                 limits->framebufferNoAttachmentsSampleCounts   );
2092         fprintf(out, "\t\t\t\t\t\t<details><summary>maxColorAttachments                     = <div class='val'>%u</div></summary></details>\n",                 limits->maxColorAttachments                    );
2093         fprintf(out, "\t\t\t\t\t\t<details><summary>sampledImageColorSampleCounts           = <div class='val'>%u</div></summary></details>\n",                 limits->sampledImageColorSampleCounts          );
2094         fprintf(out, "\t\t\t\t\t\t<details><summary>sampledImageDepthSampleCounts           = <div class='val'>%u</div></summary></details>\n",                 limits->sampledImageDepthSampleCounts          );
2095         fprintf(out, "\t\t\t\t\t\t<details><summary>sampledImageStencilSampleCounts         = <div class='val'>%u</div></summary></details>\n",                 limits->sampledImageStencilSampleCounts        );
2096         fprintf(out, "\t\t\t\t\t\t<details><summary>sampledImageIntegerSampleCounts         = <div class='val'>%u</div></summary></details>\n",                 limits->sampledImageIntegerSampleCounts        );
2097         fprintf(out, "\t\t\t\t\t\t<details><summary>storageImageSampleCounts                = <div class='val'>%u</div></summary></details>\n",                 limits->storageImageSampleCounts               );
2098         fprintf(out, "\t\t\t\t\t\t<details><summary>maxSampleMaskWords                      = <div class='val'>%u</div></summary></details>\n",                 limits->maxSampleMaskWords                     );
2099         fprintf(out, "\t\t\t\t\t\t<details><summary>timestampComputeAndGraphics             = <div class='val'>%u</div></summary></details>\n",                 limits->timestampComputeAndGraphics            );
2100         fprintf(out, "\t\t\t\t\t\t<details><summary>timestampPeriod                         = <div class='val'>%f</div></summary></details>\n",                 limits->timestampPeriod                        );
2101         fprintf(out, "\t\t\t\t\t\t<details><summary>maxClipDistances                        = <div class='val'>%u</div></summary></details>\n",                 limits->maxClipDistances                       );
2102         fprintf(out, "\t\t\t\t\t\t<details><summary>maxCullDistances                        = <div class='val'>%u</div></summary></details>\n",                 limits->maxCullDistances                       );
2103         fprintf(out, "\t\t\t\t\t\t<details><summary>maxCombinedClipAndCullDistances         = <div class='val'>%u</div></summary></details>\n",                 limits->maxCombinedClipAndCullDistances        );
2104         fprintf(out, "\t\t\t\t\t\t<details><summary>discreteQueuePriorities                 = <div class='val'>%u</div></summary></details>\n",                 limits->discreteQueuePriorities                );
2105         fprintf(out, "\t\t\t\t\t\t<details><summary>pointSizeRange[0]                       = <div class='val'>%f</div></summary></details>\n",                 limits->pointSizeRange[0]                      );
2106         fprintf(out, "\t\t\t\t\t\t<details><summary>pointSizeRange[1]                       = <div class='val'>%f</div></summary></details>\n",                 limits->pointSizeRange[1]                      );
2107         fprintf(out, "\t\t\t\t\t\t<details><summary>lineWidthRange[0]                       = <div class='val'>%f</div></summary></details>\n",                 limits->lineWidthRange[0]                      );
2108         fprintf(out, "\t\t\t\t\t\t<details><summary>lineWidthRange[1]                       = <div class='val'>%f</div></summary></details>\n",                 limits->lineWidthRange[1]                      );
2109         fprintf(out, "\t\t\t\t\t\t<details><summary>pointSizeGranularity                    = <div class='val'>%f</div></summary></details>\n",                 limits->pointSizeGranularity                   );
2110         fprintf(out, "\t\t\t\t\t\t<details><summary>lineWidthGranularity                    = <div class='val'>%f</div></summary></details>\n",                 limits->lineWidthGranularity                   );
2111         fprintf(out, "\t\t\t\t\t\t<details><summary>strictLines                             = <div class='val'>%u</div></summary></details>\n",                 limits->strictLines                            );
2112         fprintf(out, "\t\t\t\t\t\t<details><summary>standardSampleLocations                 = <div class='val'>%u</div></summary></details>\n",                 limits->standardSampleLocations                );
2113         fprintf(out, "\t\t\t\t\t\t<details><summary>optimalBufferCopyOffsetAlignment        = <div class='val'>0x%" PRIxLEAST64 "</div></summary></details>\n", limits->optimalBufferCopyOffsetAlignment       );
2114         fprintf(out, "\t\t\t\t\t\t<details><summary>optimalBufferCopyRowPitchAlignment      = <div class='val'>0x%" PRIxLEAST64 "</div></summary></details>\n", limits->optimalBufferCopyRowPitchAlignment     );
2115         fprintf(out, "\t\t\t\t\t\t<details><summary>nonCoherentAtomSize                     = <div class='val'>0x%" PRIxLEAST64 "</div></summary></details>\n", limits->nonCoherentAtomSize                    );
2116         fprintf(out, "\t\t\t\t\t</details>\n");
2117     } else if (human_readable_output) {
2118         printf("\tVkPhysicalDeviceLimits:\n");
2119         printf("\t-----------------------\n");
2120         printf("\t\tmaxImageDimension1D                     = %u\n",                 limits->maxImageDimension1D                    );
2121         printf("\t\tmaxImageDimension2D                     = %u\n",                 limits->maxImageDimension2D                    );
2122         printf("\t\tmaxImageDimension3D                     = %u\n",                 limits->maxImageDimension3D                    );
2123         printf("\t\tmaxImageDimensionCube                   = %u\n",                 limits->maxImageDimensionCube                  );
2124         printf("\t\tmaxImageArrayLayers                     = %u\n",                 limits->maxImageArrayLayers                    );
2125         printf("\t\tmaxTexelBufferElements                  = 0x%" PRIxLEAST32 "\n", limits->maxTexelBufferElements                 );
2126         printf("\t\tmaxUniformBufferRange                   = 0x%" PRIxLEAST32 "\n", limits->maxUniformBufferRange                  );
2127         printf("\t\tmaxStorageBufferRange                   = 0x%" PRIxLEAST32 "\n", limits->maxStorageBufferRange                  );
2128         printf("\t\tmaxPushConstantsSize                    = %u\n",                 limits->maxPushConstantsSize                   );
2129         printf("\t\tmaxMemoryAllocationCount                = %u\n",                 limits->maxMemoryAllocationCount               );
2130         printf("\t\tmaxSamplerAllocationCount               = %u\n",                 limits->maxSamplerAllocationCount              );
2131         printf("\t\tbufferImageGranularity                  = 0x%" PRIxLEAST64 "\n", limits->bufferImageGranularity                 );
2132         printf("\t\tsparseAddressSpaceSize                  = 0x%" PRIxLEAST64 "\n", limits->sparseAddressSpaceSize                 );
2133         printf("\t\tmaxBoundDescriptorSets                  = %u\n",                 limits->maxBoundDescriptorSets                 );
2134         printf("\t\tmaxPerStageDescriptorSamplers           = %u\n",                 limits->maxPerStageDescriptorSamplers          );
2135         printf("\t\tmaxPerStageDescriptorUniformBuffers     = %u\n",                 limits->maxPerStageDescriptorUniformBuffers    );
2136         printf("\t\tmaxPerStageDescriptorStorageBuffers     = %u\n",                 limits->maxPerStageDescriptorStorageBuffers    );
2137         printf("\t\tmaxPerStageDescriptorSampledImages      = %u\n",                 limits->maxPerStageDescriptorSampledImages     );
2138         printf("\t\tmaxPerStageDescriptorStorageImages      = %u\n",                 limits->maxPerStageDescriptorStorageImages     );
2139         printf("\t\tmaxPerStageDescriptorInputAttachments   = %u\n",                 limits->maxPerStageDescriptorInputAttachments  );
2140         printf("\t\tmaxPerStageResources                    = %u\n",                 limits->maxPerStageResources                   );
2141         printf("\t\tmaxDescriptorSetSamplers                = %u\n",                 limits->maxDescriptorSetSamplers               );
2142         printf("\t\tmaxDescriptorSetUniformBuffers          = %u\n",                 limits->maxDescriptorSetUniformBuffers         );
2143         printf("\t\tmaxDescriptorSetUniformBuffersDynamic   = %u\n",                 limits->maxDescriptorSetUniformBuffersDynamic  );
2144         printf("\t\tmaxDescriptorSetStorageBuffers          = %u\n",                 limits->maxDescriptorSetStorageBuffers         );
2145         printf("\t\tmaxDescriptorSetStorageBuffersDynamic   = %u\n",                 limits->maxDescriptorSetStorageBuffersDynamic  );
2146         printf("\t\tmaxDescriptorSetSampledImages           = %u\n",                 limits->maxDescriptorSetSampledImages          );
2147         printf("\t\tmaxDescriptorSetStorageImages           = %u\n",                 limits->maxDescriptorSetStorageImages          );
2148         printf("\t\tmaxDescriptorSetInputAttachments        = %u\n",                 limits->maxDescriptorSetInputAttachments       );
2149         printf("\t\tmaxVertexInputAttributes                = %u\n",                 limits->maxVertexInputAttributes               );
2150         printf("\t\tmaxVertexInputBindings                  = %u\n",                 limits->maxVertexInputBindings                 );
2151         printf("\t\tmaxVertexInputAttributeOffset           = 0x%" PRIxLEAST32 "\n", limits->maxVertexInputAttributeOffset          );
2152         printf("\t\tmaxVertexInputBindingStride             = 0x%" PRIxLEAST32 "\n", limits->maxVertexInputBindingStride            );
2153         printf("\t\tmaxVertexOutputComponents               = %u\n",                 limits->maxVertexOutputComponents              );
2154         printf("\t\tmaxTessellationGenerationLevel          = %u\n",                 limits->maxTessellationGenerationLevel         );
2155         printf("\t\tmaxTessellationPatchSize                        = %u\n",                 limits->maxTessellationPatchSize                       );
2156         printf("\t\tmaxTessellationControlPerVertexInputComponents  = %u\n",                 limits->maxTessellationControlPerVertexInputComponents );
2157         printf("\t\tmaxTessellationControlPerVertexOutputComponents = %u\n",                 limits->maxTessellationControlPerVertexOutputComponents);
2158         printf("\t\tmaxTessellationControlPerPatchOutputComponents  = %u\n",                 limits->maxTessellationControlPerPatchOutputComponents );
2159         printf("\t\tmaxTessellationControlTotalOutputComponents     = %u\n",                 limits->maxTessellationControlTotalOutputComponents    );
2160         printf("\t\tmaxTessellationEvaluationInputComponents        = %u\n",                 limits->maxTessellationEvaluationInputComponents       );
2161         printf("\t\tmaxTessellationEvaluationOutputComponents       = %u\n",                 limits->maxTessellationEvaluationOutputComponents      );
2162         printf("\t\tmaxGeometryShaderInvocations            = %u\n",                 limits->maxGeometryShaderInvocations           );
2163         printf("\t\tmaxGeometryInputComponents              = %u\n",                 limits->maxGeometryInputComponents             );
2164         printf("\t\tmaxGeometryOutputComponents             = %u\n",                 limits->maxGeometryOutputComponents            );
2165         printf("\t\tmaxGeometryOutputVertices               = %u\n",                 limits->maxGeometryOutputVertices              );
2166         printf("\t\tmaxGeometryTotalOutputComponents        = %u\n",                 limits->maxGeometryTotalOutputComponents       );
2167         printf("\t\tmaxFragmentInputComponents              = %u\n",                 limits->maxFragmentInputComponents             );
2168         printf("\t\tmaxFragmentOutputAttachments            = %u\n",                 limits->maxFragmentOutputAttachments           );
2169         printf("\t\tmaxFragmentDualSrcAttachments           = %u\n",                 limits->maxFragmentDualSrcAttachments          );
2170         printf("\t\tmaxFragmentCombinedOutputResources      = %u\n",                 limits->maxFragmentCombinedOutputResources     );
2171         printf("\t\tmaxComputeSharedMemorySize              = 0x%" PRIxLEAST32 "\n", limits->maxComputeSharedMemorySize             );
2172         printf("\t\tmaxComputeWorkGroupCount[0]             = %u\n",                 limits->maxComputeWorkGroupCount[0]            );
2173         printf("\t\tmaxComputeWorkGroupCount[1]             = %u\n",                 limits->maxComputeWorkGroupCount[1]            );
2174         printf("\t\tmaxComputeWorkGroupCount[2]             = %u\n",                 limits->maxComputeWorkGroupCount[2]            );
2175         printf("\t\tmaxComputeWorkGroupInvocations          = %u\n",                 limits->maxComputeWorkGroupInvocations         );
2176         printf("\t\tmaxComputeWorkGroupSize[0]              = %u\n",                 limits->maxComputeWorkGroupSize[0]             );
2177         printf("\t\tmaxComputeWorkGroupSize[1]              = %u\n",                 limits->maxComputeWorkGroupSize[1]             );
2178         printf("\t\tmaxComputeWorkGroupSize[2]              = %u\n",                 limits->maxComputeWorkGroupSize[2]             );
2179         printf("\t\tsubPixelPrecisionBits                   = %u\n",                 limits->subPixelPrecisionBits                  );
2180         printf("\t\tsubTexelPrecisionBits                   = %u\n",                 limits->subTexelPrecisionBits                  );
2181         printf("\t\tmipmapPrecisionBits                     = %u\n",                 limits->mipmapPrecisionBits                    );
2182         printf("\t\tmaxDrawIndexedIndexValue                = %u\n",                 limits->maxDrawIndexedIndexValue               );
2183         printf("\t\tmaxDrawIndirectCount                    = %u\n",                 limits->maxDrawIndirectCount                   );
2184         printf("\t\tmaxSamplerLodBias                       = %f\n",                 limits->maxSamplerLodBias                      );
2185         printf("\t\tmaxSamplerAnisotropy                    = %f\n",                 limits->maxSamplerAnisotropy                   );
2186         printf("\t\tmaxViewports                            = %u\n",                 limits->maxViewports                           );
2187         printf("\t\tmaxViewportDimensions[0]                = %u\n",                 limits->maxViewportDimensions[0]               );
2188         printf("\t\tmaxViewportDimensions[1]                = %u\n",                 limits->maxViewportDimensions[1]               );
2189         printf("\t\tviewportBoundsRange[0]                  =%13f\n",                limits->viewportBoundsRange[0]                 );
2190         printf("\t\tviewportBoundsRange[1]                  =%13f\n",                limits->viewportBoundsRange[1]                 );
2191         printf("\t\tviewportSubPixelBits                    = %u\n",                 limits->viewportSubPixelBits                   );
2192         printf("\t\tminMemoryMapAlignment                   = " PRINTF_SIZE_T_SPECIFIER "\n", limits->minMemoryMapAlignment         );
2193         printf("\t\tminTexelBufferOffsetAlignment           = 0x%" PRIxLEAST64 "\n", limits->minTexelBufferOffsetAlignment          );
2194         printf("\t\tminUniformBufferOffsetAlignment         = 0x%" PRIxLEAST64 "\n", limits->minUniformBufferOffsetAlignment        );
2195         printf("\t\tminStorageBufferOffsetAlignment         = 0x%" PRIxLEAST64 "\n", limits->minStorageBufferOffsetAlignment        );
2196         printf("\t\tminTexelOffset                          =%3d\n",                 limits->minTexelOffset                         );
2197         printf("\t\tmaxTexelOffset                          =%3d\n",                 limits->maxTexelOffset                         );
2198         printf("\t\tminTexelGatherOffset                    =%3d\n",                 limits->minTexelGatherOffset                   );
2199         printf("\t\tmaxTexelGatherOffset                    =%3d\n",                 limits->maxTexelGatherOffset                   );
2200         printf("\t\tminInterpolationOffset                  =%9f\n",                 limits->minInterpolationOffset                 );
2201         printf("\t\tmaxInterpolationOffset                  =%9f\n",                 limits->maxInterpolationOffset                 );
2202         printf("\t\tsubPixelInterpolationOffsetBits         = %u\n",                 limits->subPixelInterpolationOffsetBits        );
2203         printf("\t\tmaxFramebufferWidth                     = %u\n",                 limits->maxFramebufferWidth                    );
2204         printf("\t\tmaxFramebufferHeight                    = %u\n",                 limits->maxFramebufferHeight                   );
2205         printf("\t\tmaxFramebufferLayers                    = %u\n",                 limits->maxFramebufferLayers                   );
2206         printf("\t\tframebufferColorSampleCounts            = %u\n",                 limits->framebufferColorSampleCounts           );
2207         printf("\t\tframebufferDepthSampleCounts            = %u\n",                 limits->framebufferDepthSampleCounts           );
2208         printf("\t\tframebufferStencilSampleCounts          = %u\n",                 limits->framebufferStencilSampleCounts         );
2209         printf("\t\tframebufferNoAttachmentsSampleCounts    = %u\n",                 limits->framebufferNoAttachmentsSampleCounts   );
2210         printf("\t\tmaxColorAttachments                     = %u\n",                 limits->maxColorAttachments                    );
2211         printf("\t\tsampledImageColorSampleCounts           = %u\n",                 limits->sampledImageColorSampleCounts          );
2212         printf("\t\tsampledImageDepthSampleCounts           = %u\n",                 limits->sampledImageDepthSampleCounts          );
2213         printf("\t\tsampledImageStencilSampleCounts         = %u\n",                 limits->sampledImageStencilSampleCounts        );
2214         printf("\t\tsampledImageIntegerSampleCounts         = %u\n",                 limits->sampledImageIntegerSampleCounts        );
2215         printf("\t\tstorageImageSampleCounts                = %u\n",                 limits->storageImageSampleCounts               );
2216         printf("\t\tmaxSampleMaskWords                      = %u\n",                 limits->maxSampleMaskWords                     );
2217         printf("\t\ttimestampComputeAndGraphics             = %u\n",                 limits->timestampComputeAndGraphics            );
2218         printf("\t\ttimestampPeriod                         = %f\n",                 limits->timestampPeriod                        );
2219         printf("\t\tmaxClipDistances                        = %u\n",                 limits->maxClipDistances                       );
2220         printf("\t\tmaxCullDistances                        = %u\n",                 limits->maxCullDistances                       );
2221         printf("\t\tmaxCombinedClipAndCullDistances         = %u\n",                 limits->maxCombinedClipAndCullDistances        );
2222         printf("\t\tdiscreteQueuePriorities                 = %u\n",                 limits->discreteQueuePriorities                );
2223         printf("\t\tpointSizeRange[0]                       = %f\n",                 limits->pointSizeRange[0]                      );
2224         printf("\t\tpointSizeRange[1]                       = %f\n",                 limits->pointSizeRange[1]                      );
2225         printf("\t\tlineWidthRange[0]                       = %f\n",                 limits->lineWidthRange[0]                      );
2226         printf("\t\tlineWidthRange[1]                       = %f\n",                 limits->lineWidthRange[1]                      );
2227         printf("\t\tpointSizeGranularity                    = %f\n",                 limits->pointSizeGranularity                   );
2228         printf("\t\tlineWidthGranularity                    = %f\n",                 limits->lineWidthGranularity                   );
2229         printf("\t\tstrictLines                             = %u\n",                 limits->strictLines                            );
2230         printf("\t\tstandardSampleLocations                 = %u\n",                 limits->standardSampleLocations                );
2231         printf("\t\toptimalBufferCopyOffsetAlignment        = 0x%" PRIxLEAST64 "\n", limits->optimalBufferCopyOffsetAlignment       );
2232         printf("\t\toptimalBufferCopyRowPitchAlignment      = 0x%" PRIxLEAST64 "\n", limits->optimalBufferCopyRowPitchAlignment     );
2233         printf("\t\tnonCoherentAtomSize                     = 0x%" PRIxLEAST64 "\n", limits->nonCoherentAtomSize                    );
2234     }
2235     if (json_output) {
2236         printf(",\n");
2237         printf("\t\t\"limits\": {\n");
2238         printf("\t\t\t\"bufferImageGranularity\": %llu,\n",                               (unsigned long long)limits->bufferImageGranularity);
2239         printf("\t\t\t\"discreteQueuePriorities\": %u,\n",                                limits->discreteQueuePriorities);
2240         printf("\t\t\t\"framebufferColorSampleCounts\": %u,\n",                           limits->framebufferColorSampleCounts);
2241         printf("\t\t\t\"framebufferDepthSampleCounts\": %u,\n",                           limits->framebufferDepthSampleCounts);
2242         printf("\t\t\t\"framebufferNoAttachmentsSampleCounts\": %u,\n",                   limits->framebufferNoAttachmentsSampleCounts);
2243         printf("\t\t\t\"framebufferStencilSampleCounts\": %u,\n",                         limits->framebufferStencilSampleCounts);
2244         printf("\t\t\t\"lineWidthGranularity\": %g,\n",                                   limits->lineWidthGranularity);
2245         printf("\t\t\t\"lineWidthRange\": [\n");
2246         printf("\t\t\t\t%g,\n",                                                           limits->lineWidthRange[0]);
2247         printf("\t\t\t\t%g\n",                                                            limits->lineWidthRange[1]);
2248         printf("\t\t\t],\n");
2249         printf("\t\t\t\"maxBoundDescriptorSets\": %u,\n",                                 limits->maxBoundDescriptorSets);
2250         printf("\t\t\t\"maxClipDistances\": %u,\n",                                       limits->maxClipDistances);
2251         printf("\t\t\t\"maxColorAttachments\": %u,\n",                                    limits->maxColorAttachments);
2252         printf("\t\t\t\"maxCombinedClipAndCullDistances\": %u,\n",                        limits->maxCombinedClipAndCullDistances);
2253         printf("\t\t\t\"maxComputeSharedMemorySize\": %u,\n",                             limits->maxComputeSharedMemorySize);
2254         printf("\t\t\t\"maxComputeWorkGroupCount\": [\n");
2255         printf("\t\t\t\t%u,\n",                                                           limits->maxComputeWorkGroupCount[0]);
2256         printf("\t\t\t\t%u,\n",                                                           limits->maxComputeWorkGroupCount[1]);
2257         printf("\t\t\t\t%u\n",                                                            limits->maxComputeWorkGroupCount[2]);
2258         printf("\t\t\t],\n");
2259         printf("\t\t\t\"maxComputeWorkGroupInvocations\": %u,\n",                         limits->maxComputeWorkGroupInvocations);
2260         printf("\t\t\t\"maxComputeWorkGroupSize\": [\n");
2261         printf("\t\t\t\t%u,\n",                                                           limits->maxComputeWorkGroupSize[0]);
2262         printf("\t\t\t\t%u,\n",                                                           limits->maxComputeWorkGroupSize[1]);
2263         printf("\t\t\t\t%u\n",                                                            limits->maxComputeWorkGroupSize[2]);
2264         printf("\t\t\t],\n");
2265         printf("\t\t\t\"maxCullDistances\": %u,\n",                                       limits->maxCullDistances);
2266         printf("\t\t\t\"maxDescriptorSetInputAttachments\": %u,\n",                       limits->maxDescriptorSetInputAttachments);
2267         printf("\t\t\t\"maxDescriptorSetSampledImages\": %u,\n",                          limits->maxDescriptorSetSampledImages);
2268         printf("\t\t\t\"maxDescriptorSetSamplers\": %u,\n",                               limits->maxDescriptorSetSamplers);
2269         printf("\t\t\t\"maxDescriptorSetStorageBuffers\": %u,\n",                         limits->maxDescriptorSetStorageBuffers);
2270         printf("\t\t\t\"maxDescriptorSetStorageBuffersDynamic\": %u,\n",                  limits->maxDescriptorSetStorageBuffersDynamic);
2271         printf("\t\t\t\"maxDescriptorSetStorageImages\": %u,\n",                          limits->maxDescriptorSetStorageImages);
2272         printf("\t\t\t\"maxDescriptorSetUniformBuffers\": %u,\n",                         limits->maxDescriptorSetUniformBuffers);
2273         printf("\t\t\t\"maxDescriptorSetUniformBuffersDynamic\": %u,\n",                  limits->maxDescriptorSetUniformBuffersDynamic);
2274         printf("\t\t\t\"maxDrawIndexedIndexValue\": %u,\n",                               limits->maxDrawIndexedIndexValue);
2275         printf("\t\t\t\"maxDrawIndirectCount\": %u,\n",                                   limits->maxDrawIndirectCount);
2276         printf("\t\t\t\"maxFragmentCombinedOutputResources\": %u,\n",                     limits->maxFragmentCombinedOutputResources);
2277         printf("\t\t\t\"maxFragmentDualSrcAttachments\": %u,\n",                          limits->maxFragmentDualSrcAttachments);
2278         printf("\t\t\t\"maxFragmentInputComponents\": %u,\n",                             limits->maxFragmentInputComponents);
2279         printf("\t\t\t\"maxFragmentOutputAttachments\": %u,\n",                           limits->maxFragmentOutputAttachments);
2280         printf("\t\t\t\"maxFramebufferHeight\": %u,\n",                                   limits->maxFramebufferHeight);
2281         printf("\t\t\t\"maxFramebufferLayers\": %u,\n",                                   limits->maxFramebufferLayers);
2282         printf("\t\t\t\"maxFramebufferWidth\": %u,\n",                                    limits->maxFramebufferWidth);
2283         printf("\t\t\t\"maxGeometryInputComponents\": %u,\n",                             limits->maxGeometryInputComponents);
2284         printf("\t\t\t\"maxGeometryOutputComponents\": %u,\n",                            limits->maxGeometryOutputComponents);
2285         printf("\t\t\t\"maxGeometryOutputVertices\": %u,\n",                              limits->maxGeometryOutputVertices);
2286         printf("\t\t\t\"maxGeometryShaderInvocations\": %u,\n",                           limits->maxGeometryShaderInvocations);
2287         printf("\t\t\t\"maxGeometryTotalOutputComponents\": %u,\n",                       limits->maxGeometryTotalOutputComponents);
2288         printf("\t\t\t\"maxImageArrayLayers\": %u,\n",                                    limits->maxImageArrayLayers);
2289         printf("\t\t\t\"maxImageDimension1D\": %u,\n",                                    limits->maxImageDimension1D);
2290         printf("\t\t\t\"maxImageDimension2D\": %u,\n",                                    limits->maxImageDimension2D);
2291         printf("\t\t\t\"maxImageDimension3D\": %u,\n",                                    limits->maxImageDimension3D);
2292         printf("\t\t\t\"maxImageDimensionCube\": %u,\n",                                  limits->maxImageDimensionCube);
2293         printf("\t\t\t\"maxInterpolationOffset\": %g,\n",                                 limits->maxInterpolationOffset);
2294         printf("\t\t\t\"maxMemoryAllocationCount\": %u,\n",                               limits->maxMemoryAllocationCount);
2295         printf("\t\t\t\"maxPerStageDescriptorInputAttachments\": %u,\n",                  limits->maxPerStageDescriptorInputAttachments);
2296         printf("\t\t\t\"maxPerStageDescriptorSampledImages\": %u,\n",                     limits->maxPerStageDescriptorSampledImages);
2297         printf("\t\t\t\"maxPerStageDescriptorSamplers\": %u,\n",                          limits->maxPerStageDescriptorSamplers);
2298         printf("\t\t\t\"maxPerStageDescriptorStorageBuffers\": %u,\n",                    limits->maxPerStageDescriptorStorageBuffers);
2299         printf("\t\t\t\"maxPerStageDescriptorStorageImages\": %u,\n",                     limits->maxPerStageDescriptorStorageImages);
2300         printf("\t\t\t\"maxPerStageDescriptorUniformBuffers\": %u,\n",                    limits->maxPerStageDescriptorUniformBuffers);
2301         printf("\t\t\t\"maxPerStageResources\": %u,\n",                                   limits->maxPerStageResources);
2302         printf("\t\t\t\"maxPushConstantsSize\": %u,\n",                                   limits->maxPushConstantsSize);
2303         printf("\t\t\t\"maxSampleMaskWords\": %u,\n",                                     limits->maxSampleMaskWords);
2304         printf("\t\t\t\"maxSamplerAllocationCount\": %u,\n",                              limits->maxSamplerAllocationCount);
2305         printf("\t\t\t\"maxSamplerAnisotropy\": %g,\n",                                   limits->maxSamplerAnisotropy);
2306         printf("\t\t\t\"maxSamplerLodBias\": %g,\n",                                      limits->maxSamplerLodBias);
2307         printf("\t\t\t\"maxStorageBufferRange\": %u,\n",                                  limits->maxStorageBufferRange);
2308         printf("\t\t\t\"maxTessellationControlPerPatchOutputComponents\": %u,\n",         limits->maxTessellationControlPerPatchOutputComponents);
2309         printf("\t\t\t\"maxTessellationControlPerVertexInputComponents\": %u,\n",         limits->maxTessellationControlPerVertexInputComponents);
2310         printf("\t\t\t\"maxTessellationControlPerVertexOutputComponents\": %u,\n",        limits->maxTessellationControlPerVertexOutputComponents);
2311         printf("\t\t\t\"maxTessellationControlTotalOutputComponents\": %u,\n",            limits->maxTessellationControlTotalOutputComponents);
2312         printf("\t\t\t\"maxTessellationEvaluationInputComponents\": %u,\n",               limits->maxTessellationEvaluationInputComponents);
2313         printf("\t\t\t\"maxTessellationEvaluationOutputComponents\": %u,\n",              limits->maxTessellationEvaluationOutputComponents);
2314         printf("\t\t\t\"maxTessellationGenerationLevel\": %u,\n",                         limits->maxTessellationGenerationLevel);
2315         printf("\t\t\t\"maxTessellationPatchSize\": %u,\n",                               limits->maxTessellationPatchSize);
2316         printf("\t\t\t\"maxTexelBufferElements\": %u,\n",                                 limits->maxTexelBufferElements);
2317         printf("\t\t\t\"maxTexelGatherOffset\": %u,\n",                                   limits->maxTexelGatherOffset);
2318         printf("\t\t\t\"maxTexelOffset\": %u,\n",                                         limits->maxTexelOffset);
2319         printf("\t\t\t\"maxUniformBufferRange\": %u,\n",                                  limits->maxUniformBufferRange);
2320         printf("\t\t\t\"maxVertexInputAttributeOffset\": %u,\n",                          limits->maxVertexInputAttributeOffset);
2321         printf("\t\t\t\"maxVertexInputAttributes\": %u,\n",                               limits->maxVertexInputAttributes);
2322         printf("\t\t\t\"maxVertexInputBindings\": %u,\n",                                 limits->maxVertexInputBindings);
2323         printf("\t\t\t\"maxVertexInputBindingStride\": %u,\n",                            limits->maxVertexInputBindingStride);
2324         printf("\t\t\t\"maxVertexOutputComponents\": %u,\n",                              limits->maxVertexOutputComponents);
2325         printf("\t\t\t\"maxViewportDimensions\": [\n");
2326         printf("\t\t\t\t%u,\n",                                                           limits->maxViewportDimensions[0]);
2327         printf("\t\t\t\t%u\n",                                                            limits->maxViewportDimensions[1]);
2328         printf("\t\t\t],\n");
2329         printf("\t\t\t\"maxViewports\": %u,\n",                                           limits->maxViewports);
2330         printf("\t\t\t\"minInterpolationOffset\": %g,\n",                                 limits->minInterpolationOffset);
2331         printf("\t\t\t\"minMemoryMapAlignment\": " PRINTF_SIZE_T_SPECIFIER ",\n",         limits->minMemoryMapAlignment);
2332         printf("\t\t\t\"minStorageBufferOffsetAlignment\": %llu,\n",                      (unsigned long long)limits->minStorageBufferOffsetAlignment);
2333         printf("\t\t\t\"minTexelBufferOffsetAlignment\": %llu,\n",                        (unsigned long long)limits->minTexelBufferOffsetAlignment);
2334         printf("\t\t\t\"minTexelGatherOffset\": %d,\n",                                   limits->minTexelGatherOffset);
2335         printf("\t\t\t\"minTexelOffset\": %d,\n",                                         limits->minTexelOffset);
2336         printf("\t\t\t\"minUniformBufferOffsetAlignment\": %llu,\n",                      (unsigned long long)limits->minUniformBufferOffsetAlignment);
2337         printf("\t\t\t\"mipmapPrecisionBits\": %u,\n",                                    limits->mipmapPrecisionBits);
2338         printf("\t\t\t\"nonCoherentAtomSize\": %llu,\n",                                  (unsigned long long)limits->nonCoherentAtomSize);
2339         printf("\t\t\t\"optimalBufferCopyOffsetAlignment\": %llu,\n",                     (unsigned long long)limits->optimalBufferCopyOffsetAlignment);
2340         printf("\t\t\t\"optimalBufferCopyRowPitchAlignment\": %llu,\n",                   (unsigned long long)limits->optimalBufferCopyRowPitchAlignment);
2341         printf("\t\t\t\"pointSizeGranularity\": %g,\n",                                   limits->pointSizeGranularity);
2342         printf("\t\t\t\"pointSizeRange\": [\n");
2343         printf("\t\t\t\t%g,\n",                                                           limits->pointSizeRange[0]);
2344         printf("\t\t\t\t%g\n",                                                            limits->pointSizeRange[1]);
2345         printf("\t\t\t],\n");
2346         printf("\t\t\t\"sampledImageColorSampleCounts\": %u,\n",                          limits->sampledImageColorSampleCounts);
2347         printf("\t\t\t\"sampledImageDepthSampleCounts\": %u,\n",                          limits->sampledImageDepthSampleCounts);
2348         printf("\t\t\t\"sampledImageIntegerSampleCounts\": %u,\n",                        limits->sampledImageIntegerSampleCounts);
2349         printf("\t\t\t\"sampledImageStencilSampleCounts\": %u,\n",                        limits->sampledImageStencilSampleCounts);
2350         printf("\t\t\t\"sparseAddressSpaceSize\": %llu,\n",                               (unsigned long long)limits->sparseAddressSpaceSize);
2351         printf("\t\t\t\"standardSampleLocations\": %u,\n",                                limits->standardSampleLocations);
2352         printf("\t\t\t\"storageImageSampleCounts\": %u,\n",                               limits->storageImageSampleCounts);
2353         printf("\t\t\t\"strictLines\": %u,\n",                                            limits->strictLines);
2354         printf("\t\t\t\"subPixelInterpolationOffsetBits\": %u,\n",                        limits->subPixelInterpolationOffsetBits);
2355         printf("\t\t\t\"subPixelPrecisionBits\": %u,\n",                                  limits->subPixelPrecisionBits);
2356         printf("\t\t\t\"subTexelPrecisionBits\": %u,\n",                                  limits->subTexelPrecisionBits);
2357         printf("\t\t\t\"timestampComputeAndGraphics\": %u,\n",                            limits->timestampComputeAndGraphics);
2358         printf("\t\t\t\"timestampPeriod\": %g,\n",                                        limits->timestampPeriod);
2359         printf("\t\t\t\"viewportBoundsRange\": [\n");
2360         printf("\t\t\t\t%g,\n",                                                           limits->viewportBoundsRange[0]);
2361         printf("\t\t\t\t%g\n",                                                            limits->viewportBoundsRange[1]);
2362         printf("\t\t\t],\n");
2363         printf("\t\t\t\"viewportSubPixelBits\": %u\n",                                    limits->viewportSubPixelBits);
2364         printf("\t\t}");
2365     }
2366 }
2367
2368 static void AppGpuDumpProps(const struct AppGpu *gpu, FILE *out) {
2369      VkPhysicalDeviceProperties props;
2370
2371     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
2372         gpu->inst->inst_extensions_count)) {
2373         const VkPhysicalDeviceProperties *props2_const = &gpu->props2.properties;
2374         props = *props2_const;
2375     } else {
2376         const VkPhysicalDeviceProperties *props_const = &gpu->props;
2377         props = *props_const;
2378     }
2379     const uint32_t apiVersion = props.apiVersion;
2380     const uint32_t major = VK_VERSION_MAJOR(apiVersion);
2381     const uint32_t minor = VK_VERSION_MINOR(apiVersion);
2382     const uint32_t patch = VK_VERSION_PATCH(apiVersion);
2383
2384     if (html_output) {
2385         fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceProperties</summary>\n");
2386         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);
2387         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);
2388         fprintf(out, "\t\t\t\t\t\t<details><summary>vendorID = <div class='val'>0x%04x</div></summary></details>\n", props.vendorID);
2389         fprintf(out, "\t\t\t\t\t\t<details><summary>deviceID = <div class='val'>0x%04x</div></summary></details>\n", props.deviceID);
2390         fprintf(out, "\t\t\t\t\t\t<details><summary>deviceType = %s</summary></details>\n", VkPhysicalDeviceTypeString(props.deviceType));
2391         fprintf(out, "\t\t\t\t\t\t<details><summary>deviceName = %s</summary></details>\n", props.deviceName);
2392         fprintf(out, "\t\t\t\t\t</details>\n");
2393     } else if (human_readable_output) {
2394         printf("VkPhysicalDeviceProperties:\n");
2395         printf("===========================\n");
2396         printf("\tapiVersion     = 0x%" PRIxLEAST32 "  (%d.%d.%d)\n", apiVersion, major, minor, patch);
2397         printf("\tdriverVersion  = %u (0x%" PRIxLEAST32 ")\n", props.driverVersion, props.driverVersion);
2398         printf("\tvendorID       = 0x%04x\n", props.vendorID);
2399         printf("\tdeviceID       = 0x%04x\n", props.deviceID);
2400         printf("\tdeviceType     = %s\n", VkPhysicalDeviceTypeString(props.deviceType));
2401         printf("\tdeviceName     = %s\n", props.deviceName);
2402     }
2403     if (json_output) {
2404         printf(",\n");
2405         printf("\t\"VkPhysicalDeviceProperties\": {\n");
2406         printf("\t\t\"apiVersion\": %u,\n", apiVersion);
2407         printf("\t\t\"deviceID\": %u,\n", props.deviceID);
2408         printf("\t\t\"deviceName\": \"%s\",\n", props.deviceName);
2409         printf("\t\t\"deviceType\": %u,\n", props.deviceType);
2410         printf("\t\t\"driverVersion\": %u", props.driverVersion);
2411     }
2412
2413     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions, gpu->inst->inst_extensions_count)) {
2414         AppDumpLimits(&gpu->props2.properties.limits, out);
2415     } else {
2416         AppDumpLimits(&gpu->props.limits, out);
2417     }
2418
2419     // Dump pipeline cache UUIDs to json
2420     if (json_output) {
2421         printf(",\n");
2422         printf("\t\t\"pipelineCacheUUID\": [");
2423         for (uint32_t i = 0; i < VK_UUID_SIZE; ++i) {
2424             if (i > 0) {
2425                 printf(",");
2426             }
2427             printf("\n");
2428             printf("\t\t\t%u", props.pipelineCacheUUID[i]);
2429         }
2430         printf("\n");
2431         printf("\t\t]");
2432     }
2433
2434     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions, gpu->inst->inst_extensions_count)) {
2435         AppDumpSparseProps(&gpu->props2.properties.sparseProperties, out);
2436     } else {
2437         AppDumpSparseProps(&gpu->props.sparseProperties, out);
2438     }
2439
2440     if (json_output) {
2441         printf(",\n");
2442         printf("\t\t\"vendorID\": %u\n", props.vendorID);
2443         printf("\t}");
2444     }
2445
2446     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
2447         gpu->inst->inst_extensions_count)) {
2448         void *place = gpu->props2.pNext;
2449         while (place) {
2450             struct VkStructureHeader *structure = (struct VkStructureHeader*) place;
2451             if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT && CheckPhysicalDeviceExtensionIncluded(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME, gpu->device_extensions, gpu->device_extension_count)) {
2452                 VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT *blend_op_adv_props = (VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT*)structure;
2453                 if (html_output) {
2454                     fprintf(out, "\n\t\t\t\t\t<details><summary>VkPhysicalDeviceBlendOperationAdvancedProperties</summary>\n");
2455                     fprintf(out, "\t\t\t\t\t\t<details><summary>advancedBlendMaxColorAttachments                = <div class='val'>%u</div></summary></details>\n", blend_op_adv_props->advancedBlendMaxColorAttachments     );
2456                     fprintf(out, "\t\t\t\t\t\t<details><summary>advancedBlendIndependentBlend                   = <div class='val'>%u</div></summary></details>\n", blend_op_adv_props->advancedBlendIndependentBlend        );
2457                     fprintf(out, "\t\t\t\t\t\t<details><summary>advancedBlendNonPremultipliedSrcColor           = <div class='val'>%u</div></summary></details>\n", blend_op_adv_props->advancedBlendNonPremultipliedSrcColor);
2458                     fprintf(out, "\t\t\t\t\t\t<details><summary>advancedBlendNonPremultipliedDstColor           = <div class='val'>%u</div></summary></details>\n", blend_op_adv_props->advancedBlendNonPremultipliedDstColor);
2459                     fprintf(out, "\t\t\t\t\t\t<details><summary>advancedBlendCorrelatedOverlap                  = <div class='val'>%u</div></summary></details>\n", blend_op_adv_props->advancedBlendCorrelatedOverlap       );
2460                     fprintf(out, "\t\t\t\t\t\t<details><summary>advancedBlendAllOperations                      = <div class='val'>%u</div></summary></details>\n", blend_op_adv_props->advancedBlendAllOperations           );
2461                     fprintf(out, "\t\t\t\t\t</details>\n");
2462                 } else if (human_readable_output) {
2463                     printf("\nVkPhysicalDeviceBlendOperationAdvancedProperties:\n");
2464                     printf("=================================================\n");
2465                     printf("\tadvancedBlendMaxColorAttachments               = %u\n", blend_op_adv_props->advancedBlendMaxColorAttachments     );
2466                     printf("\tadvancedBlendIndependentBlend                  = %u\n", blend_op_adv_props->advancedBlendIndependentBlend        );
2467                     printf("\tadvancedBlendNonPremultipliedSrcColor          = %u\n", blend_op_adv_props->advancedBlendNonPremultipliedSrcColor);
2468                     printf("\tadvancedBlendNonPremultipliedDstColor          = %u\n", blend_op_adv_props->advancedBlendNonPremultipliedDstColor);
2469                     printf("\tadvancedBlendCorrelatedOverlap                 = %u\n", blend_op_adv_props->advancedBlendCorrelatedOverlap       );
2470                     printf("\tadvancedBlendAllOperations                     = %u\n", blend_op_adv_props->advancedBlendAllOperations           );
2471                 }
2472             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR && CheckPhysicalDeviceExtensionIncluded(VK_KHR_MAINTENANCE2_EXTENSION_NAME, gpu->device_extensions, gpu->device_extension_count)) {
2473                 VkPhysicalDevicePointClippingPropertiesKHR *pt_clip_props = (VkPhysicalDevicePointClippingPropertiesKHR*)structure;
2474                 if (html_output) {
2475                     fprintf(out, "\n\t\t\t\t\t<details><summary>VkPhysicalDevicePointClippingProperties</summary>\n");
2476                     fprintf(out, "\t\t\t\t\t\t<details><summary>pointClippingBehavior               = <div class='val'>%u</div></summary></details>\n", pt_clip_props->pointClippingBehavior);
2477                     fprintf(out, "\t\t\t\t\t</details>\n");
2478                 } else if (human_readable_output) {
2479                     printf("\nVkPhysicalDevicePointClippingProperties:\n");
2480                     printf("========================================\n");
2481                     printf("\tpointClippingBehavior               = %u\n", pt_clip_props->pointClippingBehavior);
2482                 }
2483             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR && CheckPhysicalDeviceExtensionIncluded(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, gpu->device_extensions, gpu->device_extension_count)) {
2484                 VkPhysicalDevicePushDescriptorPropertiesKHR *push_desc_props = (VkPhysicalDevicePushDescriptorPropertiesKHR*)structure;
2485                 if (html_output) {
2486                     fprintf(out, "\n\t\t\t\t\t<details><summary>VkPhysicalDevicePushDescriptorProperties</summary>\n");
2487                     fprintf(out, "\t\t\t\t\t\t<details><summary>maxPushDescriptors                = <div class='val'>%u</div></summary></details>\n", push_desc_props->maxPushDescriptors);
2488                     fprintf(out, "\t\t\t\t\t</details>\n");
2489                 } else if (human_readable_output) {
2490                     printf("\nVkPhysicalDevicePushDescriptorProperties:\n");
2491                     printf("=========================================\n");
2492                     printf("\tmaxPushDescriptors               = %u\n", push_desc_props->maxPushDescriptors);
2493                 }
2494             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT && CheckPhysicalDeviceExtensionIncluded(VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME, gpu->device_extensions, gpu->device_extension_count)) {
2495                 VkPhysicalDeviceDiscardRectanglePropertiesEXT *discard_rect_props = (VkPhysicalDeviceDiscardRectanglePropertiesEXT*)structure;
2496                 if (html_output) {
2497                     fprintf(out, "\n\t\t\t\t\t<details><summary>VkPhysicalDeviceDiscardRectangleProperties</summary>\n");
2498                     fprintf(out, "\t\t\t\t\t\t<details><summary>maxDiscardRectangles               = <div class='val'>%u</div></summary></details>\n", discard_rect_props->maxDiscardRectangles);
2499                     fprintf(out, "\t\t\t\t\t</details>\n");
2500                 } else if (human_readable_output) {
2501                     printf("\nVkPhysicalDeviceDiscardRectangleProperties:\n");
2502                     printf("=========================================\n");
2503                     printf("\tmaxDiscardRectangles               = %u\n", discard_rect_props->maxDiscardRectangles);
2504                 }
2505             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR && CheckPhysicalDeviceExtensionIncluded(VK_KHR_MULTIVIEW_EXTENSION_NAME, gpu->device_extensions, gpu->device_extension_count)) {
2506                 VkPhysicalDeviceMultiviewPropertiesKHR *multiview_props = (VkPhysicalDeviceMultiviewPropertiesKHR*)structure;
2507                 if (html_output) {
2508                     fprintf(out, "\n\t\t\t\t\t<details><summary>VkPhysicalDeviceMultiviewProperties</summary>\n");
2509                     fprintf(out, "\t\t\t\t\t\t<details><summary>maxMultiviewInstanceIndex = <div class='val'>%u</div></summary></details>\n", multiview_props->maxMultiviewInstanceIndex);
2510                     fprintf(out, "\t\t\t\t\t\t<details><summary>maxMultiviewViewCount     = <div class='val'>%u</div></summary></details>\n", multiview_props->maxMultiviewViewCount    );
2511                     fprintf(out, "\t\t\t\t\t</details>\n");
2512                 }
2513                 else if (human_readable_output) {
2514                     printf("\nVkPhysicalDeviceMultiviewProperties:\n");
2515                     printf("=========================================\n");
2516                     printf("\tmaxMultiviewInstanceIndex = %u\n", multiview_props->maxMultiviewInstanceIndex);
2517                     printf("\tmaxMultiviewViewCount     = %u\n", multiview_props->maxMultiviewViewCount    );
2518                 }
2519             }
2520             place = structure->pNext;
2521         }
2522     }
2523
2524     fflush(out);
2525     fflush(stdout);
2526 }
2527
2528 static void AppDumpExtensions(const char *indent, const char *layer_name, const uint32_t extension_count,
2529                               const VkExtensionProperties *extension_properties, FILE *out) {
2530     if (html_output) {
2531         fprintf(out, "\t\t\t%s<details><summary>", indent);
2532     }
2533     if (layer_name && (strlen(layer_name) > 0)) {
2534         if (html_output) {
2535             fprintf(out, "%s Extensions", layer_name);
2536         } else if (human_readable_output) {
2537             printf("%s%s Extensions", indent, layer_name);
2538         }
2539     } else {
2540         if (html_output) {
2541             fprintf(out, "Extensions");
2542         } else if (human_readable_output) {
2543             printf("%sExtensions", indent);
2544         }
2545     }
2546     if (html_output) {
2547         fprintf(out, "\tcount = <div class='val'>%d</div></summary>", extension_count);
2548         if (extension_count > 0) {
2549             fprintf(out, "\n");
2550         }
2551     } else if (human_readable_output) {
2552         printf("\tcount = %d\n", extension_count);
2553     }
2554
2555     const bool is_device_type = strcmp(layer_name, "Device") == 0;
2556     if (is_device_type && json_output) {
2557         printf(",\n");
2558         printf("\t\"ArrayOfVkExtensionProperties\": [");
2559     }
2560
2561     for (uint32_t i = 0; i < extension_count; ++i) {
2562         VkExtensionProperties const *ext_prop = &extension_properties[i];
2563         if (html_output) {
2564             fprintf(out, "\t\t\t\t%s<details><summary>", indent);
2565             fprintf(out, "<div class='type'>%s</div>: extension revision <div class='val'>%d</div>", ext_prop->extensionName,
2566                     ext_prop->specVersion);
2567             fprintf(out, "</summary></details>\n");
2568         } else if (human_readable_output) {
2569             printf("%s\t", indent);
2570             printf("%-36s: extension revision %2d\n", ext_prop->extensionName, ext_prop->specVersion);
2571         }
2572         if (is_device_type && json_output) {
2573             if (i > 0) {
2574                 printf(",");
2575             }
2576             printf("\n");
2577             printf("\t\t{\n");
2578             printf("\t\t\t\"extensionName\": \"%s\",\n", ext_prop->extensionName);
2579             printf("\t\t\t\"specVersion\": %u\n", ext_prop->specVersion);
2580             printf("\t\t}");
2581         }
2582     }
2583     if (html_output) {
2584         if (extension_count > 0) {
2585             fprintf(out, "\t\t\t%s</details>\n", indent);
2586         } else {
2587             fprintf(out, "</details>\n");
2588         }
2589     }
2590     if (is_device_type && json_output) {
2591         if (extension_count > 0) {
2592             printf("\n\t");
2593         }
2594         printf("]");
2595     }
2596
2597     fflush(out);
2598     fflush(stdout);
2599 }
2600
2601 static void AppGpuDumpQueueProps(const struct AppGpu *gpu, uint32_t id, FILE *out) {
2602     VkQueueFamilyProperties props;
2603
2604     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
2605         gpu->inst->inst_extensions_count)) {
2606         const VkQueueFamilyProperties *props2_const = &gpu->queue_props2[id].queueFamilyProperties;
2607         props = *props2_const;
2608     } else {
2609         const VkQueueFamilyProperties *props_const = &gpu->queue_props[id];
2610         props = *props_const;
2611     }
2612
2613     if (html_output) {
2614         fprintf(out, "\t\t\t\t\t<details><summary>VkQueueFamilyProperties[<div class='val'>%d</div>]</summary>\n", id);
2615         fprintf(out, "\t\t\t\t\t\t<details><summary>queueFlags = ");
2616     } else if (human_readable_output) {
2617         printf("VkQueueFamilyProperties[%d]:\n", id);
2618         printf("===========================\n");
2619         printf("\tqueueFlags         = ");
2620     }
2621     if (html_output || human_readable_output) {
2622         char *sep = "";  // separator character
2623         if (props.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
2624             fprintf(out, "GRAPHICS");
2625             sep = " | ";
2626         }
2627         if (props.queueFlags & VK_QUEUE_COMPUTE_BIT) {
2628             fprintf(out, "%sCOMPUTE", sep);
2629             sep = " | ";
2630         }
2631         if (props.queueFlags & VK_QUEUE_TRANSFER_BIT) {
2632             fprintf(out, "%sTRANSFER", sep);
2633             sep = " | ";
2634         }
2635         if (props.queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) {
2636             fprintf(out, "%sSPARSE", sep);
2637         }
2638     }
2639
2640     if (html_output) {
2641         fprintf(out, "</summary></details>\n");
2642         fprintf(out, "\t\t\t\t\t\t<details><summary>queueCount         = <div class='val'>%u</div></summary></details>\n", props.queueCount);
2643         fprintf(out, "\t\t\t\t\t\t<details><summary>timestampValidBits = <div class='val'>%u</div></summary></details>\n", props.timestampValidBits);
2644         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",
2645                 props.minImageTransferGranularity.width, props.minImageTransferGranularity.height, props.minImageTransferGranularity.depth);
2646         fprintf(out, "\t\t\t\t\t</details>\n");
2647     } else if (human_readable_output) {
2648         printf("\n");
2649         printf("\tqueueCount         = %u\n", props.queueCount);
2650         printf("\ttimestampValidBits = %u\n", props.timestampValidBits);
2651         printf("\tminImageTransferGranularity = (%d, %d, %d)\n", props.minImageTransferGranularity.width,
2652                props.minImageTransferGranularity.height, props.minImageTransferGranularity.depth);
2653     }
2654     if (json_output) {
2655         printf("\t\t{\n");
2656         printf("\t\t\t\"minImageTransferGranularity\": {\n");
2657         printf("\t\t\t\t\"depth\": %u,\n", props.minImageTransferGranularity.depth);
2658         printf("\t\t\t\t\"height\": %u,\n", props.minImageTransferGranularity.height);
2659         printf("\t\t\t\t\"width\": %u\n", props.minImageTransferGranularity.width);
2660         printf("\t\t\t},\n");
2661         printf("\t\t\t\"queueCount\": %u,\n", props.queueCount);
2662         printf("\t\t\t\"queueFlags\": %u,\n", props.queueFlags);
2663         printf("\t\t\t\"timestampValidBits\": %u\n", props.timestampValidBits);
2664         printf("\t\t}");
2665     }
2666
2667     fflush(out);
2668     fflush(stdout);
2669 }
2670
2671 // This prints a number of bytes in a human-readable format according to prefixes of the International System of Quantities (ISQ),
2672 // defined in ISO/IEC 80000. The prefixes used here are not SI prefixes, but rather the binary prefixes based on powers of 1024
2673 // (kibi-, mebi-, gibi- etc.).
2674 #define kBufferSize 32
2675
2676 static char *HumanReadable(const size_t sz) {
2677     const char prefixes[] = "KMGTPEZY";
2678     char buf[kBufferSize];
2679     int which = -1;
2680     double result = (double)sz;
2681     while (result > 1024 && which < 7) {
2682         result /= 1024;
2683         ++which;
2684     }
2685
2686     char unit[] = "\0i";
2687     if (which >= 0) {
2688         unit[0] = prefixes[which];
2689     }
2690     snprintf(buf, kBufferSize, "%.2f %sB", result, unit);
2691     return strndup(buf, kBufferSize);
2692 }
2693
2694 static void AppGpuDumpMemoryProps(const struct AppGpu *gpu, FILE *out) {
2695     VkPhysicalDeviceMemoryProperties props;
2696
2697     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
2698         gpu->inst->inst_extensions_count)) {
2699         const VkPhysicalDeviceMemoryProperties *props2_const = &gpu->memory_props2.memoryProperties;
2700         props = *props2_const;
2701     } else {
2702         const VkPhysicalDeviceMemoryProperties *props_const = &gpu->memory_props;
2703         props = *props_const;
2704     }
2705
2706     if (html_output) {
2707         fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceMemoryProperties</summary>\n");
2708         fprintf(out, "\t\t\t\t\t\t<details><summary>memoryHeapCount = <div class='val'>%u</div></summary>", props.memoryHeapCount);
2709         if (props.memoryHeapCount > 0) {
2710             fprintf(out, "\n");
2711         }
2712     } else if (human_readable_output) {
2713         printf("VkPhysicalDeviceMemoryProperties:\n");
2714         printf("=================================\n");
2715         printf("\tmemoryHeapCount       = %u\n", props.memoryHeapCount);
2716     }
2717     if (json_output) {
2718         printf(",\n");
2719         printf("\t\"VkPhysicalDeviceMemoryProperties\": {\n");
2720         printf("\t\t\"memoryHeaps\": [");
2721     }
2722     for (uint32_t i = 0; i < props.memoryHeapCount; ++i) {
2723         const VkDeviceSize memSize = props.memoryHeaps[i].size;
2724         char *mem_size_human_readable = HumanReadable((const size_t)memSize);
2725
2726         if (html_output) {
2727             fprintf(out, "\t\t\t\t\t\t\t<details><summary>memoryHeaps[<div class='val'>%u</div>]</summary>\n", i);
2728             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",
2729                     (size_t)memSize, memSize, mem_size_human_readable);
2730         } else if (human_readable_output) {
2731             printf("\tmemoryHeaps[%u] :\n", i);
2732             printf("\t\tsize          = " PRINTF_SIZE_T_SPECIFIER " (0x%" PRIxLEAST64 ") (%s)\n", (size_t)memSize, memSize,
2733                    mem_size_human_readable);
2734         }
2735         free(mem_size_human_readable);
2736
2737         const VkMemoryHeapFlags heap_flags = props.memoryHeaps[i].flags;
2738         if (html_output) {
2739             fprintf(out, "\t\t\t\t\t\t\t\t<details open><summary>flags</summary>\n");
2740             fprintf(out, "\t\t\t\t\t\t\t\t\t<details><summary>");
2741             fprintf(out, (heap_flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) ? "<div class='type'>VK_MEMORY_HEAP_DEVICE_LOCAL_BIT</div>" : "None");
2742             fprintf(out, "</summary></details>\n");
2743             fprintf(out, "\t\t\t\t\t\t\t\t</details>\n");
2744             fprintf(out, "\t\t\t\t\t\t\t</details>\n");
2745         } else if (human_readable_output) {
2746             printf("\t\tflags:\n\t\t\t");
2747             printf((heap_flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) ? "VK_MEMORY_HEAP_DEVICE_LOCAL_BIT\n" : "None\n");
2748         }
2749         if (json_output) {
2750             if (i > 0) {
2751                 printf(",");
2752             }
2753             printf("\n");
2754             printf("\t\t\t{\n");
2755             printf("\t\t\t\t\"flags\": %u,\n", heap_flags);
2756             printf("\t\t\t\t\"size\": " PRINTF_SIZE_T_SPECIFIER "\n", (size_t)memSize);
2757             printf("\t\t\t}");
2758         }
2759     }
2760     if (html_output) {
2761         if (props.memoryHeapCount > 0) {
2762             fprintf(out, "\t\t\t\t\t\t");
2763         }
2764         fprintf(out, "</details>\n");
2765     }
2766     if (json_output) {
2767         if (props.memoryHeapCount > 0) {
2768             printf("\n\t\t");
2769         }
2770         printf("]");
2771     }
2772
2773     if (html_output) {
2774         fprintf(out, "\t\t\t\t\t\t<details><summary>memoryTypeCount = <div class='val'>%u</div></summary>", props.memoryTypeCount);
2775         if (props.memoryTypeCount > 0) {
2776             fprintf(out, "\n");
2777         }
2778     } else if (human_readable_output) {
2779         printf("\tmemoryTypeCount       = %u\n", props.memoryTypeCount);
2780     }
2781     if (json_output) {
2782         printf(",\n");
2783         printf("\t\t\"memoryTypes\": [");
2784     }
2785     for (uint32_t i = 0; i < props.memoryTypeCount; ++i) {
2786         if (html_output) {
2787             fprintf(out, "\t\t\t\t\t\t\t<details><summary>memoryTypes[<div class='val'>%u</div>]</summary>\n", i);
2788             fprintf(out, "\t\t\t\t\t\t\t\t<details><summary>heapIndex = <div class='val'>%u</div></summary></details>\n", props.memoryTypes[i].heapIndex);
2789             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);
2790             if (props.memoryTypes[i].propertyFlags == 0) {
2791                 fprintf(out, "</details>\n");
2792             } else {
2793                 fprintf(out, "\n");
2794             }
2795         } else if (human_readable_output) {
2796             printf("\tmemoryTypes[%u] :\n", i);
2797             printf("\t\theapIndex     = %u\n", props.memoryTypes[i].heapIndex);
2798             printf("\t\tpropertyFlags = 0x%" PRIxLEAST32 ":\n", props.memoryTypes[i].propertyFlags);
2799         }
2800         if (json_output) {
2801             if (i > 0) {
2802                 printf(",");
2803             }
2804             printf("\n");
2805             printf("\t\t\t{\n");
2806             printf("\t\t\t\t\"heapIndex\": %u,\n", props.memoryTypes[i].heapIndex);
2807             printf("\t\t\t\t\"propertyFlags\": %u\n", props.memoryTypes[i].propertyFlags);
2808             printf("\t\t\t}");
2809         }
2810
2811         // Print each named flag to html or std output if it is set
2812         const VkFlags flags = props.memoryTypes[i].propertyFlags;
2813         if (html_output) {
2814             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");
2815             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");
2816             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");
2817             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");
2818             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");
2819             if (props.memoryTypes[i].propertyFlags > 0)         fprintf(out, "\t\t\t\t\t\t\t\t</details>\n");
2820             fprintf(out, "\t\t\t\t\t\t\t</details>\n");
2821         } else if (human_readable_output) {
2822             if (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)     printf("\t\t\tVK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT\n");
2823             if (flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)     printf("\t\t\tVK_MEMORY_PROPERTY_HOST_VISIBLE_BIT\n");
2824             if (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)    printf("\t\t\tVK_MEMORY_PROPERTY_HOST_COHERENT_BIT\n");
2825             if (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT)      printf("\t\t\tVK_MEMORY_PROPERTY_HOST_CACHED_BIT\n");
2826             if (flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) printf("\t\t\tVK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT\n");
2827         }
2828     }
2829     if (html_output) {
2830         if (props.memoryTypeCount > 0) {
2831             fprintf(out, "\t\t\t\t\t\t");
2832         }
2833         fprintf(out, "</details>\n");
2834         fprintf(out, "\t\t\t\t\t</details>\n");
2835     }
2836     if (json_output) {
2837         if (props.memoryTypeCount > 0) {
2838             printf("\n\t\t");
2839         }
2840         printf("]\n");
2841         printf("\t}");
2842     }
2843
2844     fflush(out);
2845     fflush(stdout);
2846 }
2847 // clang-format on
2848
2849 static void AppGpuDump(const struct AppGpu *gpu, FILE *out) {
2850     if (html_output) {
2851         fprintf(out, "\t\t\t<details><summary>Device Properties and Extensions</summary>\n");
2852         fprintf(out, "\t\t\t\t<details><summary>GPU%u</summary>\n", gpu->id);
2853     } else if (human_readable_output) {
2854         printf("\nDevice Properties and Extensions :\n");
2855         printf("==================================\n");
2856         printf("GPU%u\n", gpu->id);
2857     }
2858
2859     AppGpuDumpProps(gpu, out);
2860     if (html_output) {
2861         AppDumpExtensions("\t\t", "Device", gpu->device_extension_count, gpu->device_extensions, out);
2862     } else if (human_readable_output) {
2863         printf("\n");
2864         AppDumpExtensions("", "Device", gpu->device_extension_count, gpu->device_extensions, out);
2865         printf("\n");
2866     }
2867
2868     if (json_output) {
2869         printf(",\n");
2870         printf("\t\"ArrayOfVkQueueFamilyProperties\": [");
2871     }
2872     for (uint32_t i = 0; i < gpu->queue_count; ++i) {
2873         if (json_output) {
2874             if (i > 0) {
2875                 printf(",");
2876             }
2877             printf("\n");
2878         }
2879         AppGpuDumpQueueProps(gpu, i, out);
2880         if (human_readable_output) {
2881             printf("\n");
2882         }
2883     }
2884     if (json_output) {
2885         if (gpu->queue_count > 0) {
2886             printf("\n\t");
2887         }
2888         printf("]");
2889     }
2890
2891     AppGpuDumpMemoryProps(gpu, out);
2892     if (human_readable_output) {
2893         printf("\n");
2894     }
2895
2896     AppGpuDumpFeatures(gpu, out);
2897     if (human_readable_output) {
2898         printf("\n");
2899     }
2900
2901     AppDevDump(gpu, out);
2902     if (html_output) {
2903         fprintf(out, "\t\t\t\t</details>\n");
2904         fprintf(out, "\t\t\t</details>\n");
2905     }
2906 }
2907
2908 static void AppGroupDump(const VkPhysicalDeviceGroupProperties *group, const uint32_t id, const struct AppInstance *inst,
2909                          FILE *out) {
2910     if (html_output) {
2911         fprintf(out, "\t\t\t\t<details><summary>Device Group Properties (Group %u)</summary>\n", id);
2912         fprintf(out, "\t\t\t\t\t<details><summary>physicalDeviceCount = <div class='val'>%u</div></summary>\n",
2913                 group->physicalDeviceCount);
2914     } else if (human_readable_output) {
2915         printf("\tDevice Group Properties (Group %u) :\n", id);
2916         printf("\t\tphysicalDeviceCount = %u\n", group->physicalDeviceCount);
2917     }
2918
2919     // Keep a record of all physical device properties to give the user clearer information as output.
2920     VkPhysicalDeviceProperties *props = malloc(sizeof(props[0]) * group->physicalDeviceCount);
2921     if (!props) {
2922         ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
2923     }
2924     for (uint32_t i = 0; i < group->physicalDeviceCount; ++i) {
2925         vkGetPhysicalDeviceProperties(group->physicalDevices[i], &props[i]);
2926     }
2927
2928     // Output information to the user.
2929     for (uint32_t i = 0; i < group->physicalDeviceCount; ++i) {
2930         if (html_output) {
2931             fprintf(out, "\t\t\t\t\t\t<details><summary>%s (ID: <div class='val'>%d</div>)</summary></details>\n",
2932                     props[i].deviceName, i);
2933         } else if (human_readable_output) {
2934             printf("\n\t\t\t%s (ID: %d)\n", props[i].deviceName, i);
2935         }
2936     }
2937
2938     if (html_output) {
2939         fprintf(out, "\t\t\t\t\t</details>\n");
2940     }
2941
2942     if (html_output) {
2943         fprintf(out, "\t\t\t\t\t<details><summary>subsetAllocation = <div class='val'>%u</div></summary></details>\n",
2944                 group->subsetAllocation);
2945     } else if (human_readable_output) {
2946         printf("\n\t\tsubsetAllocation = %u\n", group->subsetAllocation);
2947     }
2948
2949     if (html_output) {
2950         fprintf(out, "\t\t\t\t</details>\n");
2951     }
2952
2953     // Build create info for logical device made from all physical devices in this group.
2954     const char *extensions_list = VK_KHR_DEVICE_GROUP_EXTENSION_NAME;
2955
2956     VkDeviceGroupDeviceCreateInfoKHR dg_ci = {.sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR,
2957                                               .pNext = NULL,
2958                                               .physicalDeviceCount = group->physicalDeviceCount,
2959                                               .pPhysicalDevices = group->physicalDevices};
2960
2961     VkDeviceQueueCreateInfo q_ci = {
2962         .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, .pNext = NULL, .queueFamilyIndex = 0, .queueCount = 1};
2963
2964     VkDeviceCreateInfo device_ci = {.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
2965                                     .pNext = &dg_ci,
2966                                     .queueCreateInfoCount = 1,
2967                                     .pQueueCreateInfos = &q_ci,
2968                                     .enabledExtensionCount = 1,
2969                                     .ppEnabledExtensionNames = &extensions_list};
2970
2971     VkDevice logical_device = VK_NULL_HANDLE;
2972
2973     VkResult err = vkCreateDevice(group->physicalDevices[0], &device_ci, NULL, &logical_device);
2974
2975     if (!err) {
2976         if (html_output) {
2977             fprintf(out, "\t\t\t\t<details><summary>Device Group Present Capabilities (Group %d)</summary>\n", id);
2978         } else if (human_readable_output) {
2979             printf("\n\tDevice Group Present Capabilities (Group %d) :\n", id);
2980         }
2981
2982         VkDeviceGroupPresentCapabilitiesKHR group_capabilities = {.sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR,
2983                                                                   .pNext = NULL};
2984
2985         // If the KHR_device_group extension is present, write the capabilities of the logical device into a struct for later output
2986         // to user.
2987         PFN_vkGetDeviceGroupPresentCapabilitiesKHR vkGetDeviceGroupPresentCapabilitiesKHR =
2988             (PFN_vkGetDeviceGroupPresentCapabilitiesKHR)vkGetInstanceProcAddr(inst->instance,
2989                                                                               "vkGetDeviceGroupPresentCapabilitiesKHR");
2990         vkGetDeviceGroupPresentCapabilitiesKHR(logical_device, &group_capabilities);
2991
2992         for (uint32_t i = 0; i < group->physicalDeviceCount; i++) {
2993             if (html_output) {
2994                 fprintf(out, "\t\t\t\t\t<details><summary>%s (ID: <div class='val'>%d</div>)</summary></details>\n",
2995                         props[i].deviceName, i);
2996                 fprintf(out, "\t\t\t\t\t<details><summary>Can present images from the following devices:</summary>\n");
2997                 if (group_capabilities.presentMask[i] != 0) {
2998                     for (uint32_t j = 0; j < group->physicalDeviceCount; ++j) {
2999                         uint32_t mask = 1 << j;
3000                         if (group_capabilities.presentMask[i] & mask) {
3001                             fprintf(out, "\t\t\t\t\t\t<details><summary>%s (ID: <div class='val'>%d</div>)</summary></details>\n",
3002                                     props[j].deviceName, j);
3003                         }
3004                     }
3005                 } else {
3006                     fprintf(out, "\t\t\t\t\t\t<details><summary>None</summary></details>\n");
3007                 }
3008                 fprintf(out, "\t\t\t\t\t</details>\n");
3009             } else if (human_readable_output) {
3010                 printf("\n\t\t%s (ID: %d)\n", props[i].deviceName, i);
3011                 printf("\t\tCan present images from the following devices:\n");
3012                 if (group_capabilities.presentMask[i] != 0) {
3013                     for (uint32_t j = 0; j < group->physicalDeviceCount; ++j) {
3014                         uint32_t mask = 1 << j;
3015                         if (group_capabilities.presentMask[i] & mask) {
3016                             printf("\t\t\t%s (ID: %d)\n", props[j].deviceName, j);
3017                         }
3018                     }
3019                 } else {
3020                     printf("\t\t\tNone\n");
3021                 }
3022                 printf("\n");
3023             }
3024         }
3025
3026         if (html_output) {
3027             fprintf(out, "\t\t\t\t\t<details><summary>Present modes</summary>\n");
3028             if (group_capabilities.modes & VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR)
3029                 fprintf(out, "\t\t\t\t\t\t<details><summary>VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR</summary></details>\n");
3030             if (group_capabilities.modes & VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR)
3031                 fprintf(out, "\t\t\t\t\t\t<details><summary>VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR</summary></details>\n");
3032             if (group_capabilities.modes & VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR)
3033                 fprintf(out, "\t\t\t\t\t\t<details><summary>VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR</summary></details>\n");
3034             if (group_capabilities.modes & VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR)
3035                 fprintf(
3036                     out,
3037                     "\t\t\t\t\t\t<details><summary>VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR</summary></details>\n");
3038             fprintf(out, "\t\t\t\t\t</details>\n");
3039         } else if (human_readable_output) {
3040             printf("\t\tPresent modes:\n");
3041             if (group_capabilities.modes & VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR)
3042                 printf("\t\t\tVK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR\n");
3043             if (group_capabilities.modes & VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR)
3044                 printf("\t\t\tVK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR\n");
3045             if (group_capabilities.modes & VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR)
3046                 printf("\t\t\tVK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR\n");
3047             if (group_capabilities.modes & VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR)
3048                 printf("\t\t\tVK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR\n");
3049         }
3050
3051         if (html_output) {
3052             fprintf(out, "\t\t\t\t</details>\n");
3053         }
3054     }
3055
3056     // Clean up after ourselves.
3057     free(props);
3058     vkDestroyDevice(logical_device, NULL);
3059 }
3060
3061 #ifdef _WIN32
3062 // Enlarges the console window to have a large scrollback size.
3063 static void ConsoleEnlarge() {
3064     const HANDLE console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
3065
3066     // make the console window bigger
3067     CONSOLE_SCREEN_BUFFER_INFO csbi;
3068     COORD buffer_size;
3069     if (GetConsoleScreenBufferInfo(console_handle, &csbi)) {
3070         buffer_size.X = csbi.dwSize.X + 30;
3071         buffer_size.Y = 20000;
3072         SetConsoleScreenBufferSize(console_handle, buffer_size);
3073     }
3074
3075     SMALL_RECT r;
3076     r.Left = r.Top = 0;
3077     r.Right = csbi.dwSize.X - 1 + 30;
3078     r.Bottom = 50;
3079     SetConsoleWindowInfo(console_handle, true, &r);
3080
3081     // change the console window title
3082     SetConsoleTitle(TEXT(APP_SHORT_NAME));
3083 }
3084 #endif
3085
3086 int main(int argc, char **argv) {
3087     uint32_t gpu_count;
3088     VkResult err;
3089     struct AppInstance inst;
3090     FILE *out = stdout;
3091
3092 #ifdef _WIN32
3093     if (ConsoleIsExclusive()) ConsoleEnlarge();
3094 #endif
3095     PFN_vkEnumerateInstanceVersion enumerate_instance_version =
3096         (PFN_vkEnumerateInstanceVersion)vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion");
3097
3098     uint32_t instance_version = VK_API_VERSION_1_0;
3099
3100     if (enumerate_instance_version != NULL) {
3101         enumerate_instance_version(&instance_version);
3102     }
3103
3104     const uint32_t vulkan_major = VK_VERSION_MAJOR(instance_version);
3105     const uint32_t vulkan_minor = VK_VERSION_MINOR(instance_version);
3106     const uint32_t vulkan_patch = VK_VERSION_PATCH(VK_HEADER_VERSION);
3107
3108     for (int i = 1; i < argc; i++) {
3109         if (strcmp(argv[i], "--html") == 0) {
3110             out = fopen("vulkaninfo.html", "w");
3111             human_readable_output = false;
3112             html_output = true;
3113             continue;
3114         }
3115         CheckForJsonOption(argv[i]);
3116     }
3117
3118     if (html_output) {
3119         PrintHtmlHeader(out);
3120         fprintf(out, "\t\t\t<details><summary>");
3121     } else if (human_readable_output) {
3122         printf("===========\n");
3123         printf("VULKAN INFO\n");
3124         printf("===========\n\n");
3125     }
3126     if (html_output || human_readable_output) {
3127         fprintf(out, "Vulkan Instance Version: ");
3128     }
3129     if (html_output) {
3130         fprintf(out, "<div class='val'>%d.%d.%d</div></summary></details>\n", vulkan_major, vulkan_minor, vulkan_patch);
3131         fprintf(out, "\t\t\t<br />\n");
3132     } else if (human_readable_output) {
3133         printf("%d.%d.%d\n\n", vulkan_major, vulkan_minor, vulkan_patch);
3134     }
3135
3136     AppCreateInstance(&inst);
3137
3138     err = vkEnumeratePhysicalDevices(inst.instance, &gpu_count, NULL);
3139     if (err) {
3140         ERR_EXIT(err);
3141     }
3142
3143     VkPhysicalDevice *objs = malloc(sizeof(objs[0]) * gpu_count);
3144     if (!objs) {
3145         ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
3146     }
3147
3148     err = vkEnumeratePhysicalDevices(inst.instance, &gpu_count, objs);
3149     if (err) {
3150         ERR_EXIT(err);
3151     }
3152
3153     struct AppGpu *gpus = malloc(sizeof(gpus[0]) * gpu_count);
3154     if (!gpus) {
3155         ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
3156     }
3157
3158     for (uint32_t i = 0; i < gpu_count; ++i) {
3159         AppGpuInit(&gpus[i], &inst, i, objs[i]);
3160         if (human_readable_output) {
3161             printf("\n\n");
3162         }
3163     }
3164
3165     // If json output, confirm the desired gpu exists
3166     if (json_output) {
3167         if (selected_gpu >= gpu_count) {
3168             selected_gpu = 0;
3169         }
3170         PrintJsonHeader(vulkan_major, vulkan_minor, vulkan_patch);
3171     }
3172
3173     if (human_readable_output) {
3174         printf("Instance Extensions:\n");
3175         printf("====================\n");
3176     }
3177     AppDumpExtensions("", "Instance", inst.global_extension_count, inst.global_extensions, out);
3178
3179     //---Layer-Device-Extensions---
3180     if (html_output) {
3181         fprintf(out, "\t\t\t<details><summary>Layers: count = <div class='val'>%d</div></summary>", inst.global_layer_count);
3182         if (inst.global_layer_count > 0) {
3183             fprintf(out, "\n");
3184         }
3185     } else if (human_readable_output) {
3186         printf("Layers: count = %d\n", inst.global_layer_count);
3187         printf("=======\n");
3188     }
3189     if (json_output && (inst.global_layer_count > 0)) {
3190         printf(",\n");
3191         printf("\t\"ArrayOfVkLayerProperties\": [");
3192     }
3193     for (uint32_t i = 0; i < inst.global_layer_count; ++i) {
3194         uint32_t layer_major, layer_minor, layer_patch;
3195         char spec_version[64], layer_version[64];
3196         VkLayerProperties const *layer_prop = &inst.global_layers[i].layer_properties;
3197
3198         ExtractVersion(layer_prop->specVersion, &layer_major, &layer_minor, &layer_patch);
3199         snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", layer_major, layer_minor, layer_patch);
3200         snprintf(layer_version, sizeof(layer_version), "%d", layer_prop->implementationVersion);
3201
3202         if (html_output) {
3203             fprintf(out, "\t\t\t\t<details><summary>");
3204             fprintf(out, "<div class='type'>%s</div> (%s) Vulkan version <div class='val'>%s</div>, ", layer_prop->layerName,
3205                     (char *)layer_prop->description, spec_version);
3206             fprintf(out, "layer version <div class='val'>%s</div></summary>\n", layer_version);
3207             AppDumpExtensions("\t\t", "Layer", inst.global_layers[i].extension_count, inst.global_layers[i].extension_properties,
3208                               out);
3209         } else if (human_readable_output) {
3210             printf("%s (%s) Vulkan version %s, layer version %s\n", layer_prop->layerName, (char *)layer_prop->description,
3211                    spec_version, layer_version);
3212             AppDumpExtensions("\t", "Layer", inst.global_layers[i].extension_count, inst.global_layers[i].extension_properties,
3213                               out);
3214         }
3215         if (json_output) {
3216             if (i > 0) {
3217                 printf(",");
3218             }
3219             printf("\n");
3220             printf("\t\t{\n");
3221             printf("\t\t\t\"layerName\": \"%s\",\n", layer_prop->layerName);
3222             printf("\t\t\t\"specVersion\": %u,\n", layer_prop->specVersion);
3223             printf("\t\t\t\"implementationVersion\": %u,\n", layer_prop->implementationVersion);
3224             printf("\t\t\t\"description\": \"%s\"\n", layer_prop->description);
3225             printf("\t\t}");
3226         }
3227
3228         if (html_output) {
3229             fprintf(out, "\t\t\t\t\t<details><summary>Devices count = <div class='val'>%d</div></summary>\n", gpu_count);
3230         } else if (human_readable_output) {
3231             printf("\tDevices \tcount = %d\n", gpu_count);
3232         }
3233
3234         char *layer_name = inst.global_layers[i].layer_properties.layerName;
3235
3236         for (uint32_t j = 0; j < gpu_count; ++j) {
3237             if (html_output) {
3238                 fprintf(out, "\t\t\t\t\t\t<details><summary>");
3239                 fprintf(out, "GPU id: <div class='val'>%u</div> (%s)</summary></details>\n", j, gpus[j].props.deviceName);
3240             } else if (human_readable_output) {
3241                 printf("\t\tGPU id       : %u (%s)\n", j, gpus[j].props.deviceName);
3242             }
3243             uint32_t count = 0;
3244             VkExtensionProperties *props;
3245             AppGetPhysicalDeviceLayerExtensions(&gpus[j], layer_name, &count, &props);
3246             if (html_output) {
3247                 AppDumpExtensions("\t\t\t", "Layer-Device", count, props, out);
3248                 fprintf(out, "\t\t\t\t\t</details>\n");
3249             } else if (human_readable_output) {
3250                 AppDumpExtensions("\t\t", "Layer-Device", count, props, out);
3251             }
3252             free(props);
3253         }
3254
3255         if (html_output) {
3256             fprintf(out, "\t\t\t\t</details>\n");
3257         } else if (human_readable_output) {
3258             printf("\n");
3259         }
3260     }
3261
3262     if (html_output) {
3263         fprintf(out, "\t\t\t</details>\n");
3264     }
3265     if (json_output && (inst.global_layer_count > 0)) {
3266         printf("\n\t]");
3267     }
3268
3269     fflush(out);
3270     fflush(stdout);
3271     //-----------------------------
3272
3273     if (html_output) {
3274         fprintf(out, "\t\t\t<details><summary>Presentable Surfaces</summary>");
3275         if (gpu_count > 0) {
3276             fprintf(out, "\n");
3277         } else {
3278             fprintf(out, "</details>\n");
3279         }
3280     } else if (human_readable_output) {
3281         printf("Presentable Surfaces:\n");
3282         printf("=====================\n");
3283     }
3284     inst.width = 256;
3285     inst.height = 256;
3286     int format_count = 0;
3287     int present_mode_count = 0;
3288
3289 #if defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR)
3290     bool has_display = true;
3291     const char *display_var = getenv("DISPLAY");
3292     if (display_var == NULL || strlen(display_var) == 0) {
3293         fprintf(stderr, "'DISPLAY' environment variable not set... skipping surface info\n");
3294         fflush(stderr);
3295         has_display = false;
3296     }
3297 #endif
3298
3299 //--WIN32--
3300 #ifdef VK_USE_PLATFORM_WIN32_KHR
3301     if (CheckExtensionEnabled(VK_KHR_WIN32_SURFACE_EXTENSION_NAME, inst.inst_extensions, inst.inst_extensions_count)) {
3302         AppCreateWin32Window(&inst);
3303         for (uint32_t i = 0; i < gpu_count; ++i) {
3304             AppCreateWin32Surface(&inst);
3305             if (html_output) {
3306                 fprintf(out, "\t\t\t\t<details><summary>GPU id : <div class='val'>%u</div> (%s)</summary></details>\n", i,
3307                         gpus[i].props.deviceName);
3308                 fprintf(out, "\t\t\t\t<details><summary>Surface type : <div class='type'>%s</div></summary></details>\n",
3309                         VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
3310             } else if (human_readable_output) {
3311                 printf("GPU id       : %u (%s)\n", i, gpus[i].props.deviceName);
3312                 printf("Surface type : %s\n", VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
3313             }
3314             format_count += AppDumpSurfaceFormats(&inst, &gpus[i], out);
3315             present_mode_count += AppDumpSurfacePresentModes(&inst, &gpus[i], out);
3316             AppDumpSurfaceCapabilities(&inst, &gpus[i], out);
3317             AppDestroySurface(&inst);
3318         }
3319         AppDestroyWin32Window(&inst);
3320     }
3321 //--XCB--
3322 #elif VK_USE_PLATFORM_XCB_KHR
3323     if (has_display && CheckExtensionEnabled(VK_KHR_XCB_SURFACE_EXTENSION_NAME, inst.inst_extensions, inst.inst_extensions_count)) {
3324         AppCreateXcbWindow(&inst);
3325         for (uint32_t i = 0; i < gpu_count; ++i) {
3326             AppCreateXcbSurface(&inst);
3327             if (html_output) {
3328                 fprintf(out, "\t\t\t\t<details><summary>GPU id : <div class='val'>%u</div> (%s)</summary></details>\n", i,
3329                         gpus[i].props.deviceName);
3330                 fprintf(out, "\t\t\t\t<details><summary>Surface type : <div class='type'>%s</div></summary></details>\n",
3331                         VK_KHR_XCB_SURFACE_EXTENSION_NAME);
3332             } else if (human_readable_output) {
3333                 printf("GPU id       : %u (%s)\n", i, gpus[i].props.deviceName);
3334                 printf("Surface type : %s\n", VK_KHR_XCB_SURFACE_EXTENSION_NAME);
3335             }
3336             format_count += AppDumpSurfaceFormats(&inst, &gpus[i], out);
3337             present_mode_count += AppDumpSurfacePresentModes(&inst, &gpus[i], out);
3338             AppDumpSurfaceCapabilities(&inst, &gpus[i], out);
3339             AppDestroySurface(&inst);
3340         }
3341         AppDestroyXcbWindow(&inst);
3342     }
3343 //--XLIB--
3344 #elif VK_USE_PLATFORM_XLIB_KHR
3345     if (has_display &&
3346         CheckExtensionEnabled(VK_KHR_XLIB_SURFACE_EXTENSION_NAME, inst.inst_extensions, inst.inst_extensions_count)) {
3347         AppCreateXlibWindow(&inst);
3348         for (uint32_t i = 0; i < gpu_count; ++i) {
3349             AppCreateXlibSurface(&inst);
3350             if (html_output) {
3351                 fprintf(out, "\t\t\t\t<details><summary>GPU id : <div class='val'>%u</div> (%s)</summary></details>\n", i,
3352                         gpus[i].props.deviceName);
3353                 fprintf(out, "\t\t\t\t<details><summary>Surface type : <div class='type'>%s</div></summary></details>\n",
3354                         VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
3355             } else if (human_readable_output) {
3356                 printf("GPU id       : %u (%s)\n", i, gpus[i].props.deviceName);
3357                 printf("Surface type : %s\n", VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
3358             }
3359             format_count += AppDumpSurfaceFormats(&inst, &gpus[i], out);
3360             present_mode_count += AppDumpSurfacePresentModes(&inst, &gpus[i], out);
3361             AppDumpSurfaceCapabilities(&inst, &gpus[i], out);
3362             AppDestroySurface(&inst);
3363         }
3364         AppDestroyXlibWindow(&inst);
3365     }
3366 #endif
3367
3368     // TODO: Android / Wayland / MIR
3369     if (!format_count && !present_mode_count) {
3370         if (html_output) {
3371             fprintf(out, "\t\t\t\t<details><summary>None found</summary></details>\n");
3372         } else if (human_readable_output) {
3373             printf("None found\n");
3374         }
3375     }
3376
3377     if (html_output) {
3378         fprintf(out, "\t\t\t</details>\n");
3379     } else if (human_readable_output) {
3380         printf("\n");
3381     }
3382     //---------
3383
3384     if (CheckExtensionEnabled(VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME, inst.inst_extensions, inst.inst_extensions_count)) {
3385         PFN_vkEnumeratePhysicalDeviceGroupsKHR vkEnumeratePhysicalDeviceGroupsKHR =
3386             (PFN_vkEnumeratePhysicalDeviceGroupsKHR)vkGetInstanceProcAddr(inst.instance, "vkEnumeratePhysicalDeviceGroupsKHR");
3387
3388         uint32_t group_count;
3389         err = vkEnumeratePhysicalDeviceGroupsKHR(inst.instance, &group_count, NULL);
3390         if (err) {
3391             ERR_EXIT(err);
3392         }
3393
3394         VkPhysicalDeviceGroupProperties *groups = malloc(sizeof(groups[0]) * group_count);
3395         if (!groups) {
3396             ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
3397         }
3398
3399         err = vkEnumeratePhysicalDeviceGroupsKHR(inst.instance, &group_count, groups);
3400         if (err) {
3401             ERR_EXIT(err);
3402         }
3403
3404         if (html_output) {
3405             fprintf(out, "\t\t\t<details><summary>Groups</summary>\n");
3406         } else if (human_readable_output) {
3407             printf("\nGroups :\n");
3408             printf("========\n");
3409         }
3410
3411         for (uint32_t i = 0; i < group_count; ++i) {
3412             AppGroupDump(&groups[i], i, &inst, out);
3413             if (human_readable_output) {
3414                 printf("\n\n");
3415             }
3416         }
3417
3418         if (html_output) {
3419             fprintf(out, "\t\t\t</details>\n");
3420         }
3421
3422         free(groups);
3423     }
3424
3425     for (uint32_t i = 0; i < gpu_count; ++i) {
3426         if (json_output && selected_gpu != i) {
3427             // Toggle json_output to allow html output without json output
3428             json_output = false;
3429             AppGpuDump(&gpus[i], out);
3430             json_output = true;
3431         } else {
3432             AppGpuDump(&gpus[i], out);
3433         }
3434         if (human_readable_output) {
3435             printf("\n\n");
3436         }
3437     }
3438
3439     for (uint32_t i = 0; i < gpu_count; ++i) {
3440         AppGpuDestroy(&gpus[i]);
3441     }
3442     free(gpus);
3443     free(objs);
3444
3445     AppDestroyInstance(&inst);
3446
3447     if (html_output) {
3448         PrintHtmlFooter(out);
3449         fflush(out);
3450         fclose(out);
3451     }
3452     if (json_output) {
3453         printf("\n}\n");
3454     }
3455
3456     fflush(stdout);
3457
3458 #ifdef _WIN32
3459     if (ConsoleIsExclusive() && human_readable_output) {
3460         Sleep(INFINITE);
3461     }
3462 #endif
3463
3464     return 0;
3465 }