vulkaninfo: Revert "Fix Issue 136"
[platform/upstream/Vulkan-Tools.git] / vulkaninfo / vulkaninfo.c
1 /*
2  * Copyright (c) 2015-2019 The Khronos Group Inc.
3  * Copyright (c) 2015-2019 Valve Corporation
4  * Copyright (c) 2015-2019 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  * Author: Bob Ellison <bob@lunarg.com>
25  */
26
27 #ifdef __GNUC__
28 #ifndef _POSIX_C_SOURCE
29 #define _POSIX_C_SOURCE 200809L
30 #endif
31 #else
32 #define strndup(p, n) strdup(p)
33 #endif
34
35 #include <assert.h>
36 #include <inttypes.h>
37 #include <stdbool.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41
42 #ifdef _WIN32
43 #include <fcntl.h>
44 #include <io.h>
45 #endif  // _WIN32
46
47 #if defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_XCB_KHR)
48 #include <X11/Xutil.h>
49 #endif
50
51 #if defined(VK_USE_PLATFORM_MACOS_MVK)
52 #include "metal_view.h"
53 #endif
54
55 #include <vulkan/vulkan.h>
56
57 #define ERR(err) fprintf(stderr, "%s:%d: failed with %s\n", __FILE__, __LINE__, VkResultString(err));
58
59 #ifdef _WIN32
60
61 #define snprintf _snprintf
62 #define strdup _strdup
63
64 // Returns nonzero if the console is used only for this process. Will return
65 // zero if another process (such as cmd.exe) is also attached.
66 static int ConsoleIsExclusive(void) {
67     DWORD pids[2];
68     DWORD num_pids = GetConsoleProcessList(pids, ARRAYSIZE(pids));
69     return num_pids <= 1;
70 }
71
72 #define WAIT_FOR_CONSOLE_DESTROY                   \
73     do {                                           \
74         if (ConsoleIsExclusive()) Sleep(INFINITE); \
75     } while (0)
76 #else
77 #define WAIT_FOR_CONSOLE_DESTROY
78 #endif
79
80 #define ERR_EXIT(err)             \
81     do {                          \
82         ERR(err);                 \
83         fflush(stdout);           \
84         fflush(stderr);           \
85         WAIT_FOR_CONSOLE_DESTROY; \
86         exit(-1);                 \
87     } while (0)
88
89 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
90
91 #define MAX_QUEUE_TYPES 5
92 #define APP_SHORT_NAME "vulkaninfo"
93
94 static bool html_output = false;
95 static bool human_readable_output = true;
96 static bool json_output = false;
97 static uint32_t selected_gpu = 0;
98
99 struct VkStructureHeader {
100     VkStructureType sType;
101     void *pNext;
102 };
103
104 struct pNextChainBuildingBlockInfo {
105     VkStructureType sType;
106     uint32_t mem_size;
107 };
108
109 struct LayerExtensionList {
110     VkLayerProperties layer_properties;
111     uint32_t extension_count;
112     VkExtensionProperties *extension_properties;
113 };
114
115 struct AppInstance {
116     VkInstance instance;
117     uint32_t instance_version;
118     uint32_t vulkan_major;
119     uint32_t vulkan_minor;
120     uint32_t vulkan_patch;
121
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     // Functions from vkGetInstanceProcAddress
131     PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR;
132     PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR;
133     PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR;
134     PFN_vkGetPhysicalDeviceSurfaceFormats2KHR vkGetPhysicalDeviceSurfaceFormats2KHR;
135     PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR;
136     PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR;
137     PFN_vkGetPhysicalDeviceFormatProperties2KHR vkGetPhysicalDeviceFormatProperties2KHR;
138     PFN_vkGetPhysicalDeviceQueueFamilyProperties2KHR vkGetPhysicalDeviceQueueFamilyProperties2KHR;
139     PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR;
140     PFN_vkGetPhysicalDeviceMemoryProperties2KHR vkGetPhysicalDeviceMemoryProperties2KHR;
141     PFN_vkGetPhysicalDeviceSurfaceCapabilities2KHR vkGetPhysicalDeviceSurfaceCapabilities2KHR;
142     PFN_vkGetPhysicalDeviceSurfaceCapabilities2EXT vkGetPhysicalDeviceSurfaceCapabilities2EXT;
143
144     VkSurfaceCapabilitiesKHR surface_capabilities;
145     VkSurfaceCapabilities2KHR surface_capabilities2;
146     VkSharedPresentSurfaceCapabilitiesKHR shared_surface_capabilities;
147     VkSurfaceCapabilities2EXT surface_capabilities2_ext;
148
149     VkSurfaceKHR surface;
150     int width, height;
151
152 #ifdef VK_USE_PLATFORM_WIN32_KHR
153     HINSTANCE h_instance;  // Windows Instance
154     HWND h_wnd;            // window handle
155 #endif
156 #ifdef VK_USE_PLATFORM_XCB_KHR
157     xcb_connection_t *xcb_connection;
158     xcb_screen_t *xcb_screen;
159     xcb_window_t xcb_window;
160 #endif
161 #ifdef VK_USE_PLATFORM_XLIB_KHR
162     Display *xlib_display;
163     Window xlib_window;
164 #endif
165 #ifdef VK_USE_PLATFORM_ANDROID_KHR  // TODO
166     struct ANativeWindow *window;
167 #endif
168 #ifdef VK_USE_PLATFORM_MACOS_MVK
169     void *window;
170 #endif
171 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
172     struct wl_display *wayland_display;
173     struct wl_surface *wayland_surface;
174 #endif
175 };
176
177 struct AppGpu {
178     uint32_t id;
179     VkPhysicalDevice obj;
180
181     VkPhysicalDeviceProperties props;
182     VkPhysicalDeviceProperties2KHR props2;
183
184     uint32_t queue_count;
185     VkQueueFamilyProperties *queue_props;
186     VkQueueFamilyProperties2KHR *queue_props2;
187     VkDeviceQueueCreateInfo *queue_reqs;
188
189     struct AppInstance *inst;
190
191     VkPhysicalDeviceMemoryProperties memory_props;
192     VkPhysicalDeviceMemoryProperties2KHR memory_props2;
193
194     VkPhysicalDeviceFeatures features;
195     VkPhysicalDeviceFeatures2KHR features2;
196     VkPhysicalDevice limits;
197
198     uint32_t device_extension_count;
199     VkExtensionProperties *device_extensions;
200 };
201
202 // return most severe flag only
203 static const char *DebugReportFlagString(const VkDebugReportFlagsEXT flags) {
204     switch (flags) {
205         case VK_DEBUG_REPORT_ERROR_BIT_EXT:
206             return "ERROR";
207         case VK_DEBUG_REPORT_WARNING_BIT_EXT:
208             return "WARNING";
209         case VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT:
210             return "PERF";
211         case VK_DEBUG_REPORT_INFORMATION_BIT_EXT:
212             return "INFO";
213         case VK_DEBUG_REPORT_DEBUG_BIT_EXT:
214             return "DEBUG";
215         default:
216             return "UNKNOWN";
217     }
218 }
219
220 static VKAPI_ATTR VkBool32 VKAPI_CALL DbgCallback(VkDebugReportFlagsEXT msgFlags, VkDebugReportObjectTypeEXT objType,
221                                                   uint64_t srcObject, size_t location, int32_t msgCode, const char *pLayerPrefix,
222                                                   const char *pMsg, void *pUserData) {
223     fprintf(stderr, "%s: [%s] Code %d : %s\n", DebugReportFlagString(msgFlags), pLayerPrefix, msgCode, pMsg);
224     fflush(stderr);
225
226     // True is reserved for layer developers, and MAY mean calls are not distributed down the layer chain after validation error.
227     // False SHOULD always be returned by apps:
228     return VK_FALSE;
229 }
230
231 static const char *VkResultString(VkResult err) {
232     switch (err) {
233 #define STR(r) \
234     case r:    \
235         return #r
236         STR(VK_SUCCESS);
237         STR(VK_NOT_READY);
238         STR(VK_TIMEOUT);
239         STR(VK_EVENT_SET);
240         STR(VK_EVENT_RESET);
241         STR(VK_INCOMPLETE);
242         STR(VK_ERROR_OUT_OF_HOST_MEMORY);
243         STR(VK_ERROR_OUT_OF_DEVICE_MEMORY);
244         STR(VK_ERROR_INITIALIZATION_FAILED);
245         STR(VK_ERROR_DEVICE_LOST);
246         STR(VK_ERROR_MEMORY_MAP_FAILED);
247         STR(VK_ERROR_LAYER_NOT_PRESENT);
248         STR(VK_ERROR_EXTENSION_NOT_PRESENT);
249         STR(VK_ERROR_FEATURE_NOT_PRESENT);
250         STR(VK_ERROR_INCOMPATIBLE_DRIVER);
251         STR(VK_ERROR_TOO_MANY_OBJECTS);
252         STR(VK_ERROR_FORMAT_NOT_SUPPORTED);
253         STR(VK_ERROR_FRAGMENTED_POOL);
254         STR(VK_ERROR_OUT_OF_POOL_MEMORY);
255         STR(VK_ERROR_INVALID_EXTERNAL_HANDLE);
256         STR(VK_ERROR_SURFACE_LOST_KHR);
257         STR(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR);
258         STR(VK_SUBOPTIMAL_KHR);
259         STR(VK_ERROR_OUT_OF_DATE_KHR);
260         STR(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR);
261         STR(VK_ERROR_VALIDATION_FAILED_EXT);
262         STR(VK_ERROR_INVALID_SHADER_NV);
263         STR(VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT);
264         STR(VK_ERROR_FRAGMENTATION_EXT);
265         STR(VK_ERROR_NOT_PERMITTED_EXT);
266 #undef STR
267         default:
268             return "UNKNOWN_RESULT";
269     }
270 }
271
272 static const char *VkPhysicalDeviceTypeString(VkPhysicalDeviceType type) {
273     switch (type) {
274 #define STR(r)                        \
275     case VK_PHYSICAL_DEVICE_TYPE_##r: \
276         return #r
277         STR(OTHER);
278         STR(INTEGRATED_GPU);
279         STR(DISCRETE_GPU);
280         STR(VIRTUAL_GPU);
281         STR(CPU);
282 #undef STR
283         default:
284             return "UNKNOWN_DEVICE";
285     }
286 }
287
288 static const char *VkFormatString(VkFormat fmt) {
289     switch (fmt) {
290 #define STR(r)          \
291     case VK_FORMAT_##r: \
292         return #r
293         STR(UNDEFINED);
294         STR(R4G4_UNORM_PACK8);
295         STR(R4G4B4A4_UNORM_PACK16);
296         STR(B4G4R4A4_UNORM_PACK16);
297         STR(R5G6B5_UNORM_PACK16);
298         STR(B5G6R5_UNORM_PACK16);
299         STR(R5G5B5A1_UNORM_PACK16);
300         STR(B5G5R5A1_UNORM_PACK16);
301         STR(A1R5G5B5_UNORM_PACK16);
302         STR(R8_UNORM);
303         STR(R8_SNORM);
304         STR(R8_USCALED);
305         STR(R8_SSCALED);
306         STR(R8_UINT);
307         STR(R8_SINT);
308         STR(R8_SRGB);
309         STR(R8G8_UNORM);
310         STR(R8G8_SNORM);
311         STR(R8G8_USCALED);
312         STR(R8G8_SSCALED);
313         STR(R8G8_UINT);
314         STR(R8G8_SINT);
315         STR(R8G8_SRGB);
316         STR(R8G8B8_UNORM);
317         STR(R8G8B8_SNORM);
318         STR(R8G8B8_USCALED);
319         STR(R8G8B8_SSCALED);
320         STR(R8G8B8_UINT);
321         STR(R8G8B8_SINT);
322         STR(R8G8B8_SRGB);
323         STR(B8G8R8_UNORM);
324         STR(B8G8R8_SNORM);
325         STR(B8G8R8_USCALED);
326         STR(B8G8R8_SSCALED);
327         STR(B8G8R8_UINT);
328         STR(B8G8R8_SINT);
329         STR(B8G8R8_SRGB);
330         STR(R8G8B8A8_UNORM);
331         STR(R8G8B8A8_SNORM);
332         STR(R8G8B8A8_USCALED);
333         STR(R8G8B8A8_SSCALED);
334         STR(R8G8B8A8_UINT);
335         STR(R8G8B8A8_SINT);
336         STR(R8G8B8A8_SRGB);
337         STR(B8G8R8A8_UNORM);
338         STR(B8G8R8A8_SNORM);
339         STR(B8G8R8A8_USCALED);
340         STR(B8G8R8A8_SSCALED);
341         STR(B8G8R8A8_UINT);
342         STR(B8G8R8A8_SINT);
343         STR(B8G8R8A8_SRGB);
344         STR(A8B8G8R8_UNORM_PACK32);
345         STR(A8B8G8R8_SNORM_PACK32);
346         STR(A8B8G8R8_USCALED_PACK32);
347         STR(A8B8G8R8_SSCALED_PACK32);
348         STR(A8B8G8R8_UINT_PACK32);
349         STR(A8B8G8R8_SINT_PACK32);
350         STR(A8B8G8R8_SRGB_PACK32);
351         STR(A2R10G10B10_UNORM_PACK32);
352         STR(A2R10G10B10_SNORM_PACK32);
353         STR(A2R10G10B10_USCALED_PACK32);
354         STR(A2R10G10B10_SSCALED_PACK32);
355         STR(A2R10G10B10_UINT_PACK32);
356         STR(A2R10G10B10_SINT_PACK32);
357         STR(A2B10G10R10_UNORM_PACK32);
358         STR(A2B10G10R10_SNORM_PACK32);
359         STR(A2B10G10R10_USCALED_PACK32);
360         STR(A2B10G10R10_SSCALED_PACK32);
361         STR(A2B10G10R10_UINT_PACK32);
362         STR(A2B10G10R10_SINT_PACK32);
363         STR(R16_UNORM);
364         STR(R16_SNORM);
365         STR(R16_USCALED);
366         STR(R16_SSCALED);
367         STR(R16_UINT);
368         STR(R16_SINT);
369         STR(R16_SFLOAT);
370         STR(R16G16_UNORM);
371         STR(R16G16_SNORM);
372         STR(R16G16_USCALED);
373         STR(R16G16_SSCALED);
374         STR(R16G16_UINT);
375         STR(R16G16_SINT);
376         STR(R16G16_SFLOAT);
377         STR(R16G16B16_UNORM);
378         STR(R16G16B16_SNORM);
379         STR(R16G16B16_USCALED);
380         STR(R16G16B16_SSCALED);
381         STR(R16G16B16_UINT);
382         STR(R16G16B16_SINT);
383         STR(R16G16B16_SFLOAT);
384         STR(R16G16B16A16_UNORM);
385         STR(R16G16B16A16_SNORM);
386         STR(R16G16B16A16_USCALED);
387         STR(R16G16B16A16_SSCALED);
388         STR(R16G16B16A16_UINT);
389         STR(R16G16B16A16_SINT);
390         STR(R16G16B16A16_SFLOAT);
391         STR(R32_UINT);
392         STR(R32_SINT);
393         STR(R32_SFLOAT);
394         STR(R32G32_UINT);
395         STR(R32G32_SINT);
396         STR(R32G32_SFLOAT);
397         STR(R32G32B32_UINT);
398         STR(R32G32B32_SINT);
399         STR(R32G32B32_SFLOAT);
400         STR(R32G32B32A32_UINT);
401         STR(R32G32B32A32_SINT);
402         STR(R32G32B32A32_SFLOAT);
403         STR(R64_UINT);
404         STR(R64_SINT);
405         STR(R64_SFLOAT);
406         STR(R64G64_UINT);
407         STR(R64G64_SINT);
408         STR(R64G64_SFLOAT);
409         STR(R64G64B64_UINT);
410         STR(R64G64B64_SINT);
411         STR(R64G64B64_SFLOAT);
412         STR(R64G64B64A64_UINT);
413         STR(R64G64B64A64_SINT);
414         STR(R64G64B64A64_SFLOAT);
415         STR(B10G11R11_UFLOAT_PACK32);
416         STR(E5B9G9R9_UFLOAT_PACK32);
417         STR(D16_UNORM);
418         STR(X8_D24_UNORM_PACK32);
419         STR(D32_SFLOAT);
420         STR(S8_UINT);
421         STR(D16_UNORM_S8_UINT);
422         STR(D24_UNORM_S8_UINT);
423         STR(D32_SFLOAT_S8_UINT);
424         STR(BC1_RGB_UNORM_BLOCK);
425         STR(BC1_RGB_SRGB_BLOCK);
426         STR(BC1_RGBA_UNORM_BLOCK);
427         STR(BC1_RGBA_SRGB_BLOCK);
428         STR(BC2_UNORM_BLOCK);
429         STR(BC2_SRGB_BLOCK);
430         STR(BC3_UNORM_BLOCK);
431         STR(BC3_SRGB_BLOCK);
432         STR(BC4_UNORM_BLOCK);
433         STR(BC4_SNORM_BLOCK);
434         STR(BC5_UNORM_BLOCK);
435         STR(BC5_SNORM_BLOCK);
436         STR(BC6H_UFLOAT_BLOCK);
437         STR(BC6H_SFLOAT_BLOCK);
438         STR(BC7_UNORM_BLOCK);
439         STR(BC7_SRGB_BLOCK);
440         STR(ETC2_R8G8B8_UNORM_BLOCK);
441         STR(ETC2_R8G8B8_SRGB_BLOCK);
442         STR(ETC2_R8G8B8A1_UNORM_BLOCK);
443         STR(ETC2_R8G8B8A1_SRGB_BLOCK);
444         STR(ETC2_R8G8B8A8_UNORM_BLOCK);
445         STR(ETC2_R8G8B8A8_SRGB_BLOCK);
446         STR(EAC_R11_UNORM_BLOCK);
447         STR(EAC_R11_SNORM_BLOCK);
448         STR(EAC_R11G11_UNORM_BLOCK);
449         STR(EAC_R11G11_SNORM_BLOCK);
450         STR(ASTC_4x4_UNORM_BLOCK);
451         STR(ASTC_4x4_SRGB_BLOCK);
452         STR(ASTC_5x4_UNORM_BLOCK);
453         STR(ASTC_5x4_SRGB_BLOCK);
454         STR(ASTC_5x5_UNORM_BLOCK);
455         STR(ASTC_5x5_SRGB_BLOCK);
456         STR(ASTC_6x5_UNORM_BLOCK);
457         STR(ASTC_6x5_SRGB_BLOCK);
458         STR(ASTC_6x6_UNORM_BLOCK);
459         STR(ASTC_6x6_SRGB_BLOCK);
460         STR(ASTC_8x5_UNORM_BLOCK);
461         STR(ASTC_8x5_SRGB_BLOCK);
462         STR(ASTC_8x6_UNORM_BLOCK);
463         STR(ASTC_8x6_SRGB_BLOCK);
464         STR(ASTC_8x8_UNORM_BLOCK);
465         STR(ASTC_8x8_SRGB_BLOCK);
466         STR(ASTC_10x5_UNORM_BLOCK);
467         STR(ASTC_10x5_SRGB_BLOCK);
468         STR(ASTC_10x6_UNORM_BLOCK);
469         STR(ASTC_10x6_SRGB_BLOCK);
470         STR(ASTC_10x8_UNORM_BLOCK);
471         STR(ASTC_10x8_SRGB_BLOCK);
472         STR(ASTC_10x10_UNORM_BLOCK);
473         STR(ASTC_10x10_SRGB_BLOCK);
474         STR(ASTC_12x10_UNORM_BLOCK);
475         STR(ASTC_12x10_SRGB_BLOCK);
476         STR(ASTC_12x12_UNORM_BLOCK);
477         STR(ASTC_12x12_SRGB_BLOCK);
478         STR(G8B8G8R8_422_UNORM);
479         STR(B8G8R8G8_422_UNORM);
480         STR(G8_B8_R8_3PLANE_420_UNORM);
481         STR(G8_B8R8_2PLANE_420_UNORM);
482         STR(G8_B8_R8_3PLANE_422_UNORM);
483         STR(G8_B8R8_2PLANE_422_UNORM);
484         STR(G8_B8_R8_3PLANE_444_UNORM);
485         STR(R10X6_UNORM_PACK16);
486         STR(R10X6G10X6_UNORM_2PACK16);
487         STR(R10X6G10X6B10X6A10X6_UNORM_4PACK16);
488         STR(G10X6B10X6G10X6R10X6_422_UNORM_4PACK16);
489         STR(B10X6G10X6R10X6G10X6_422_UNORM_4PACK16);
490         STR(G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16);
491         STR(G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16);
492         STR(G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16);
493         STR(G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16);
494         STR(G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16);
495         STR(R12X4_UNORM_PACK16);
496         STR(R12X4G12X4_UNORM_2PACK16);
497         STR(R12X4G12X4B12X4A12X4_UNORM_4PACK16);
498         STR(G12X4B12X4G12X4R12X4_422_UNORM_4PACK16);
499         STR(B12X4G12X4R12X4G12X4_422_UNORM_4PACK16);
500         STR(G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16);
501         STR(G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16);
502         STR(G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16);
503         STR(G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16);
504         STR(G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16);
505         STR(G16B16G16R16_422_UNORM);
506         STR(B16G16R16G16_422_UNORM);
507         STR(G16_B16_R16_3PLANE_420_UNORM);
508         STR(G16_B16R16_2PLANE_420_UNORM);
509         STR(G16_B16_R16_3PLANE_422_UNORM);
510         STR(G16_B16R16_2PLANE_422_UNORM);
511         STR(G16_B16_R16_3PLANE_444_UNORM);
512         STR(PVRTC1_2BPP_UNORM_BLOCK_IMG);
513         STR(PVRTC1_4BPP_UNORM_BLOCK_IMG);
514         STR(PVRTC2_2BPP_UNORM_BLOCK_IMG);
515         STR(PVRTC2_4BPP_UNORM_BLOCK_IMG);
516         STR(PVRTC1_2BPP_SRGB_BLOCK_IMG);
517         STR(PVRTC1_4BPP_SRGB_BLOCK_IMG);
518         STR(PVRTC2_2BPP_SRGB_BLOCK_IMG);
519         STR(PVRTC2_4BPP_SRGB_BLOCK_IMG);
520 #undef STR
521         default:
522             return "UNKNOWN_FORMAT";
523     }
524 }
525 #if defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || \
526     defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_WAYLAND_KHR)
527 static const char *VkPresentModeString(VkPresentModeKHR mode) {
528     switch (mode) {
529 #define STR(r)                \
530     case VK_PRESENT_MODE_##r: \
531         return #r
532         STR(IMMEDIATE_KHR);
533         STR(MAILBOX_KHR);
534         STR(FIFO_KHR);
535         STR(FIFO_RELAXED_KHR);
536         STR(SHARED_DEMAND_REFRESH_KHR);
537         STR(SHARED_CONTINUOUS_REFRESH_KHR);
538 #undef STR
539         default:
540             return "UNKNOWN_FORMAT";
541     }
542 }
543 #endif
544
545 static bool CheckExtensionEnabled(const char *extension_to_check, const char **extension_list, uint32_t extension_count) {
546     for (uint32_t i = 0; i < extension_count; ++i) {
547         if (!strcmp(extension_to_check, extension_list[i])) {
548             return true;
549         }
550     }
551     return false;
552 }
553
554 static bool CheckPhysicalDeviceExtensionIncluded(const char *extension_to_check, VkExtensionProperties *extension_list,
555                                                  uint32_t extension_count) {
556     for (uint32_t i = 0; i < extension_count; ++i) {
557         if (!strcmp(extension_to_check, extension_list[i].extensionName)) {
558             return true;
559         }
560     }
561     return false;
562 }
563
564 static void buildpNextChain(struct VkStructureHeader *first, const struct pNextChainBuildingBlockInfo *chain_info,
565                             uint32_t chain_info_len) {
566     struct VkStructureHeader *place = first;
567
568     for (uint32_t i = 0; i < chain_info_len; i++) {
569         place->pNext = malloc(chain_info[i].mem_size);
570         if (!place->pNext) {
571             ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
572         }
573         memset(place->pNext, 0, chain_info[i].mem_size);
574         place = place->pNext;
575         place->sType = chain_info[i].sType;
576     }
577
578     place->pNext = NULL;
579 }
580
581 static void freepNextChain(struct VkStructureHeader *first) {
582     struct VkStructureHeader *place = first;
583     struct VkStructureHeader *next = NULL;
584
585     while (place) {
586         next = place->pNext;
587         free(place);
588         place = next;
589     }
590 }
591
592 static void ExtractVersion(uint32_t version, uint32_t *major, uint32_t *minor, uint32_t *patch) {
593     *major = version >> 22;
594     *minor = (version >> 12) & 0x3ff;
595     *patch = version & 0xfff;
596 }
597
598 static void AppGetPhysicalDeviceLayerExtensions(struct AppGpu *gpu, char *layer_name, uint32_t *extension_count,
599                                                 VkExtensionProperties **extension_properties) {
600     VkResult err;
601     uint32_t ext_count = 0;
602     VkExtensionProperties *ext_ptr = NULL;
603
604     /* repeat get until VK_INCOMPLETE goes away */
605     do {
606         err = vkEnumerateDeviceExtensionProperties(gpu->obj, layer_name, &ext_count, NULL);
607         if (err) ERR_EXIT(err);
608
609         if (ext_ptr) {
610             free(ext_ptr);
611         }
612         ext_ptr = malloc(ext_count * sizeof(VkExtensionProperties));
613         err = vkEnumerateDeviceExtensionProperties(gpu->obj, layer_name, &ext_count, ext_ptr);
614     } while (err == VK_INCOMPLETE);
615     if (err) ERR_EXIT(err);
616
617     *extension_count = ext_count;
618     *extension_properties = ext_ptr;
619 }
620
621 static void AppGetGlobalLayerExtensions(char *layer_name, uint32_t *extension_count, VkExtensionProperties **extension_properties) {
622     VkResult err;
623     uint32_t ext_count = 0;
624     VkExtensionProperties *ext_ptr = NULL;
625
626     /* repeat get until VK_INCOMPLETE goes away */
627     do {
628         // gets the extension count if the last parameter is NULL
629         err = vkEnumerateInstanceExtensionProperties(layer_name, &ext_count, NULL);
630         if (err) ERR_EXIT(err);
631
632         if (ext_ptr) {
633             free(ext_ptr);
634         }
635         ext_ptr = malloc(ext_count * sizeof(VkExtensionProperties));
636         // gets the extension properties if the last parameter is not NULL
637         err = vkEnumerateInstanceExtensionProperties(layer_name, &ext_count, ext_ptr);
638     } while (err == VK_INCOMPLETE);
639     if (err) ERR_EXIT(err);
640     *extension_count = ext_count;
641     *extension_properties = ext_ptr;
642 }
643
644 /* Gets a list of layer and instance extensions */
645 static void AppGetInstanceExtensions(struct AppInstance *inst) {
646     VkResult err;
647
648     uint32_t count = 0;
649
650     /* Scan layers */
651     VkLayerProperties *global_layer_properties = NULL;
652     struct LayerExtensionList *global_layers = NULL;
653
654     do {
655         err = vkEnumerateInstanceLayerProperties(&count, NULL);
656         if (err) ERR_EXIT(err);
657
658         if (global_layer_properties) {
659             free(global_layer_properties);
660         }
661         global_layer_properties = malloc(sizeof(VkLayerProperties) * count);
662         assert(global_layer_properties);
663
664         if (global_layers) {
665             free(global_layers);
666         }
667         global_layers = malloc(sizeof(struct LayerExtensionList) * count);
668         assert(global_layers);
669
670         err = vkEnumerateInstanceLayerProperties(&count, global_layer_properties);
671     } while (err == VK_INCOMPLETE);
672     if (err) ERR_EXIT(err);
673
674     inst->global_layer_count = count;
675     inst->global_layers = global_layers;
676
677     for (uint32_t i = 0; i < inst->global_layer_count; ++i) {
678         VkLayerProperties *src_info = &global_layer_properties[i];
679         struct LayerExtensionList *dst_info = &inst->global_layers[i];
680         memcpy(&dst_info->layer_properties, src_info, sizeof(VkLayerProperties));
681
682         // Save away layer extension info for report
683         // Gets layer extensions, if first parameter is not NULL
684         AppGetGlobalLayerExtensions(src_info->layerName, &dst_info->extension_count, &dst_info->extension_properties);
685     }
686     free(global_layer_properties);
687
688     // Collect global extensions
689     inst->global_extension_count = 0;
690     // Gets instance extensions, if no layer was specified in the first
691     // paramteter
692     AppGetGlobalLayerExtensions(NULL, &inst->global_extension_count, &inst->global_extensions);
693 }
694
695 // Prints opening code for html output file
696 void PrintHtmlHeader(FILE *out) {
697     fprintf(out, "<!doctype html>\n");
698     fprintf(out, "<html>\n");
699     fprintf(out, "\t<head>\n");
700     fprintf(out, "\t\t<title>vulkaninfo</title>\n");
701     fprintf(out, "\t\t<style type='text/css'>\n");
702     fprintf(out, "\t\thtml {\n");
703     fprintf(out, "\t\t\tbackground-color: #0b1e48;\n");
704     fprintf(out, "\t\t\tbackground-image: url(\"https://vulkan.lunarg.com/img/bg-starfield.jpg\");\n");
705     fprintf(out, "\t\t\tbackground-position: center;\n");
706     fprintf(out, "\t\t\t-webkit-background-size: cover;\n");
707     fprintf(out, "\t\t\t-moz-background-size: cover;\n");
708     fprintf(out, "\t\t\t-o-background-size: cover;\n");
709     fprintf(out, "\t\t\tbackground-size: cover;\n");
710     fprintf(out, "\t\t\tbackground-attachment: fixed;\n");
711     fprintf(out, "\t\t\tbackground-repeat: no-repeat;\n");
712     fprintf(out, "\t\t\theight: 100%%;\n");
713     fprintf(out, "\t\t}\n");
714     fprintf(out, "\t\t#header {\n");
715     fprintf(out, "\t\t\tz-index: -1;\n");
716     fprintf(out, "\t\t}\n");
717     fprintf(out, "\t\t#header>img {\n");
718     fprintf(out, "\t\t\tposition: absolute;\n");
719     fprintf(out, "\t\t\twidth: 160px;\n");
720     fprintf(out, "\t\t\tmargin-left: -280px;\n");
721     fprintf(out, "\t\t\ttop: -10px;\n");
722     fprintf(out, "\t\t\tleft: 50%%;\n");
723     fprintf(out, "\t\t}\n");
724     fprintf(out, "\t\t#header>h1 {\n");
725     fprintf(out, "\t\t\tfont-family: Arial, \"Helvetica Neue\", Helvetica, sans-serif;\n");
726     fprintf(out, "\t\t\tfont-size: 44px;\n");
727     fprintf(out, "\t\t\tfont-weight: 200;\n");
728     fprintf(out, "\t\t\ttext-shadow: 4px 4px 5px #000;\n");
729     fprintf(out, "\t\t\tcolor: #eee;\n");
730     fprintf(out, "\t\t\tposition: absolute;\n");
731     fprintf(out, "\t\t\twidth: 400px;\n");
732     fprintf(out, "\t\t\tmargin-left: -80px;\n");
733     fprintf(out, "\t\t\ttop: 8px;\n");
734     fprintf(out, "\t\t\tleft: 50%%;\n");
735     fprintf(out, "\t\t}\n");
736     fprintf(out, "\t\tbody {\n");
737     fprintf(out, "\t\t\tfont-family: Consolas, monaco, monospace;\n");
738     fprintf(out, "\t\t\tfont-size: 14px;\n");
739     fprintf(out, "\t\t\tline-height: 20px;\n");
740     fprintf(out, "\t\t\tcolor: #eee;\n");
741     fprintf(out, "\t\t\theight: 100%%;\n");
742     fprintf(out, "\t\t\tmargin: 0;\n");
743     fprintf(out, "\t\t\toverflow: hidden;\n");
744     fprintf(out, "\t\t}\n");
745     fprintf(out, "\t\t#wrapper {\n");
746     fprintf(out, "\t\t\tbackground-color: rgba(0, 0, 0, 0.7);\n");
747     fprintf(out, "\t\t\tborder: 1px solid #446;\n");
748     fprintf(out, "\t\t\tbox-shadow: 0px 0px 10px #000;\n");
749     fprintf(out, "\t\t\tpadding: 8px 12px;\n\n");
750     fprintf(out, "\t\t\tdisplay: inline-block;\n");
751     fprintf(out, "\t\t\tposition: absolute;\n");
752     fprintf(out, "\t\t\ttop: 80px;\n");
753     fprintf(out, "\t\t\tbottom: 25px;\n");
754     fprintf(out, "\t\t\tleft: 50px;\n");
755     fprintf(out, "\t\t\tright: 50px;\n");
756     fprintf(out, "\t\t\toverflow: auto;\n");
757     fprintf(out, "\t\t}\n");
758     fprintf(out, "\t\tdetails>details {\n");
759     fprintf(out, "\t\t\tmargin-left: 22px;\n");
760     fprintf(out, "\t\t}\n");
761     fprintf(out, "\t\tdetails>summary:only-child::-webkit-details-marker {\n");
762     fprintf(out, "\t\t\tdisplay: none;\n");
763     fprintf(out, "\t\t}\n");
764     fprintf(out, "\t\t.var, .type, .val {\n");
765     fprintf(out, "\t\t\tdisplay: inline;\n");
766     fprintf(out, "\t\t}\n");
767     fprintf(out, "\t\t.var {\n");
768     fprintf(out, "\t\t}\n");
769     fprintf(out, "\t\t.type {\n");
770     fprintf(out, "\t\t\tcolor: #acf;\n");
771     fprintf(out, "\t\t\tmargin: 0 12px;\n");
772     fprintf(out, "\t\t}\n");
773     fprintf(out, "\t\t.val {\n");
774     fprintf(out, "\t\t\tcolor: #afa;\n");
775     fprintf(out, "\t\t\tbackground: #222;\n");
776     fprintf(out, "\t\t\ttext-align: right;\n");
777     fprintf(out, "\t\t}\n");
778     fprintf(out, "\t\t</style>\n");
779     fprintf(out, "\t</head>\n");
780     fprintf(out, "\t<body>\n");
781     fprintf(out, "\t\t<div id='header'>\n");
782     fprintf(out, "\t\t\t<h1>vulkaninfo</h1>\n");
783     fprintf(out, "\t\t</div>\n");
784     fprintf(out, "\t\t<div id='wrapper'>\n");
785 }
786
787 // Prints closing code for html output file
788 void PrintHtmlFooter(FILE *out) {
789     fprintf(out, "\t\t</div>\n");
790     fprintf(out, "\t</body>\n");
791     fprintf(out, "</html>");
792 }
793
794 // Prints opening code for json output file
795 void PrintJsonHeader(const int vulkan_major, const int vulkan_minor, const int vulkan_patch) {
796     printf("{\n");
797     printf("\t\"$schema\": \"https://schema.khronos.org/vulkan/devsim_1_0_0.json#\",\n");
798     printf("\t\"comments\": {\n");
799     printf("\t\t\"desc\": \"JSON configuration file describing GPU %u. Generated using the vulkaninfo program.\",\n", selected_gpu);
800     printf("\t\t\"vulkanApiVersion\": \"%d.%d.%d\"\n", vulkan_major, vulkan_minor, vulkan_patch);
801     printf("\t}");
802 }
803
804 // Checks if current argument specifies json output, interprets/updates gpu selection
805 bool CheckForJsonOption(const char *arg) {
806     if (strncmp("--json", arg, 6) == 0 || strcmp(arg, "-j") == 0) {
807         if (strlen(arg) > 7 && strncmp("--json=", arg, 7) == 0) {
808             selected_gpu = strtol(arg + 7, NULL, 10);
809         }
810         human_readable_output = false;
811         json_output = true;
812         return true;
813     } else {
814         return false;
815     }
816 }
817
818 static void AppCompileInstanceExtensionsToEnable(struct AppInstance *inst) {
819     // Get all supported Instance extensions (excl. layer-provided ones)
820     inst->inst_extensions_count = inst->global_extension_count;
821     inst->inst_extensions = malloc(sizeof(char *) * inst->inst_extensions_count);
822     if (!inst->inst_extensions) ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
823
824     for (uint32_t i = 0; i < inst->global_extension_count; ++i) {
825         inst->inst_extensions[i] = inst->global_extensions[i].extensionName;
826     }
827 }
828
829 static void AppLoadInstanceCommands(struct AppInstance *inst) {
830 #define LOAD_INSTANCE_VK_CMD(cmd) inst->cmd = (PFN_##cmd)vkGetInstanceProcAddr(inst->instance, #cmd)
831
832     LOAD_INSTANCE_VK_CMD(vkGetPhysicalDeviceSurfaceSupportKHR);
833     LOAD_INSTANCE_VK_CMD(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
834     LOAD_INSTANCE_VK_CMD(vkGetPhysicalDeviceSurfaceFormatsKHR);
835     LOAD_INSTANCE_VK_CMD(vkGetPhysicalDeviceSurfaceFormats2KHR);
836     LOAD_INSTANCE_VK_CMD(vkGetPhysicalDeviceSurfacePresentModesKHR);
837     LOAD_INSTANCE_VK_CMD(vkGetPhysicalDeviceProperties2KHR);
838     LOAD_INSTANCE_VK_CMD(vkGetPhysicalDeviceFormatProperties2KHR);
839     LOAD_INSTANCE_VK_CMD(vkGetPhysicalDeviceQueueFamilyProperties2KHR);
840     LOAD_INSTANCE_VK_CMD(vkGetPhysicalDeviceFeatures2KHR);
841     LOAD_INSTANCE_VK_CMD(vkGetPhysicalDeviceMemoryProperties2KHR);
842     LOAD_INSTANCE_VK_CMD(vkGetPhysicalDeviceSurfaceCapabilities2KHR);
843     LOAD_INSTANCE_VK_CMD(vkGetPhysicalDeviceSurfaceCapabilities2EXT);
844
845 #undef LOAD_INSTANCE_VK_CMD
846 }
847
848 static void AppCreateInstance(struct AppInstance *inst) {
849     PFN_vkEnumerateInstanceVersion enumerate_instance_version =
850         (PFN_vkEnumerateInstanceVersion)vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion");
851
852     if (!enumerate_instance_version) {
853         inst->instance_version = VK_API_VERSION_1_0;
854     } else {
855         const VkResult err = enumerate_instance_version(&inst->instance_version);
856         if (err) ERR_EXIT(err);
857     }
858
859     inst->vulkan_major = VK_VERSION_MAJOR(inst->instance_version);
860     inst->vulkan_minor = VK_VERSION_MINOR(inst->instance_version);
861     inst->vulkan_patch = VK_VERSION_PATCH(VK_HEADER_VERSION);
862
863     AppGetInstanceExtensions(inst);
864
865     const VkDebugReportCallbackCreateInfoEXT dbg_info = {.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT,
866                                                          .flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT,
867                                                          .pfnCallback = DbgCallback};
868
869     const VkApplicationInfo app_info = {.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
870                                         .pApplicationName = APP_SHORT_NAME,
871                                         .applicationVersion = 1,
872                                         .apiVersion = VK_API_VERSION_1_0};
873
874     AppCompileInstanceExtensionsToEnable(inst);
875     const VkInstanceCreateInfo inst_info = {.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
876                                             .pNext = &dbg_info,
877                                             .pApplicationInfo = &app_info,
878                                             .enabledExtensionCount = inst->inst_extensions_count,
879                                             .ppEnabledExtensionNames = inst->inst_extensions};
880
881     VkResult err = vkCreateInstance(&inst_info, NULL, &inst->instance);
882     if (err == VK_ERROR_INCOMPATIBLE_DRIVER) {
883         fprintf(stderr, "Cannot create Vulkan instance.\n");
884         ERR_EXIT(err);
885     } else if (err) {
886         ERR_EXIT(err);
887     }
888
889     AppLoadInstanceCommands(inst);
890 }
891
892 static void AppDestroyInstance(struct AppInstance *inst) {
893     free(inst->global_extensions);
894     for (uint32_t i = 0; i < inst->global_layer_count; ++i) {
895         free(inst->global_layers[i].extension_properties);
896     }
897     free(inst->global_layers);
898     free((char **)inst->inst_extensions);
899     vkDestroyInstance(inst->instance, NULL);
900 }
901
902 static void AppGpuInit(struct AppGpu *gpu, struct AppInstance *inst, uint32_t id, VkPhysicalDevice obj) {
903     uint32_t i;
904
905     memset(gpu, 0, sizeof(*gpu));
906
907     gpu->id = id;
908     gpu->obj = obj;
909     gpu->inst = inst;
910
911     vkGetPhysicalDeviceProperties(gpu->obj, &gpu->props);
912
913     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
914                               gpu->inst->inst_extensions_count)) {
915         struct pNextChainBuildingBlockInfo chain_info[] = {
916             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT,
917              .mem_size = sizeof(VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT)},
918             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR,
919              .mem_size = sizeof(VkPhysicalDevicePointClippingPropertiesKHR)},
920             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR,
921              .mem_size = sizeof(VkPhysicalDevicePushDescriptorPropertiesKHR)},
922             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT,
923              .mem_size = sizeof(VkPhysicalDeviceDiscardRectanglePropertiesEXT)},
924             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR,
925              .mem_size = sizeof(VkPhysicalDeviceMultiviewPropertiesKHR)},
926             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES_KHR,
927              .mem_size = sizeof(VkPhysicalDeviceMaintenance3PropertiesKHR)},
928             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR, .mem_size = sizeof(VkPhysicalDeviceIDPropertiesKHR)},
929             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR,
930              .mem_size = sizeof(VkPhysicalDeviceDriverPropertiesKHR)},
931             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR,
932              .mem_size = sizeof(VkPhysicalDeviceFloatControlsPropertiesKHR)},
933             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT,
934              .mem_size = sizeof(VkPhysicalDevicePCIBusInfoPropertiesEXT)},
935             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT,
936              .mem_size = sizeof(VkPhysicalDeviceTransformFeedbackPropertiesEXT)},
937             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT,
938              .mem_size = sizeof(VkPhysicalDeviceFragmentDensityMapPropertiesEXT)}};
939
940         uint32_t chain_info_len = ARRAY_SIZE(chain_info);
941
942         gpu->props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR;
943         buildpNextChain((struct VkStructureHeader *)&gpu->props2, chain_info, chain_info_len);
944
945         inst->vkGetPhysicalDeviceProperties2KHR(gpu->obj, &gpu->props2);
946     }
947
948     /* get queue count */
949     vkGetPhysicalDeviceQueueFamilyProperties(gpu->obj, &gpu->queue_count, NULL);
950
951     gpu->queue_props = malloc(sizeof(gpu->queue_props[0]) * gpu->queue_count);
952
953     if (!gpu->queue_props) {
954         ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
955     }
956     vkGetPhysicalDeviceQueueFamilyProperties(gpu->obj, &gpu->queue_count, gpu->queue_props);
957
958     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
959                               gpu->inst->inst_extensions_count)) {
960         gpu->queue_props2 = malloc(sizeof(gpu->queue_props2[0]) * gpu->queue_count);
961
962         if (!gpu->queue_props2) {
963             ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
964         }
965
966         for (i = 0; i < gpu->queue_count; ++i) {
967             gpu->queue_props2[i].sType = VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR;
968             gpu->queue_props2[i].pNext = NULL;
969         }
970
971         inst->vkGetPhysicalDeviceQueueFamilyProperties2KHR(gpu->obj, &gpu->queue_count, gpu->queue_props2);
972     }
973
974     /* set up queue requests */
975     gpu->queue_reqs = malloc(sizeof(*gpu->queue_reqs) * gpu->queue_count);
976     if (!gpu->queue_reqs) {
977         ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
978     }
979     for (i = 0; i < gpu->queue_count; ++i) {
980         float *queue_priorities = NULL;
981         if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
982                                   gpu->inst->inst_extensions_count)) {
983             queue_priorities = malloc(gpu->queue_props2[i].queueFamilyProperties.queueCount * sizeof(float));
984         } else {
985             queue_priorities = malloc(gpu->queue_props[i].queueCount * sizeof(float));
986         }
987         if (!queue_priorities) {
988             ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
989         }
990
991         if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
992                                   gpu->inst->inst_extensions_count)) {
993             memset(queue_priorities, 0, gpu->queue_props2[i].queueFamilyProperties.queueCount * sizeof(float));
994         } else {
995             memset(queue_priorities, 0, gpu->queue_props[i].queueCount * sizeof(float));
996         }
997
998         gpu->queue_reqs[i].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
999         gpu->queue_reqs[i].pNext = NULL;
1000         gpu->queue_reqs[i].flags = 0;
1001         gpu->queue_reqs[i].queueFamilyIndex = i;
1002
1003         if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
1004                                   gpu->inst->inst_extensions_count)) {
1005             gpu->queue_reqs[i].queueCount = gpu->queue_props2[i].queueFamilyProperties.queueCount;
1006         } else {
1007             gpu->queue_reqs[i].queueCount = gpu->queue_props[i].queueCount;
1008         }
1009
1010         gpu->queue_reqs[i].pQueuePriorities = queue_priorities;
1011     }
1012
1013     vkGetPhysicalDeviceMemoryProperties(gpu->obj, &gpu->memory_props);
1014
1015     vkGetPhysicalDeviceFeatures(gpu->obj, &gpu->features);
1016
1017     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
1018                               gpu->inst->inst_extensions_count)) {
1019         gpu->memory_props2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR;
1020         gpu->memory_props2.pNext = NULL;
1021
1022         inst->vkGetPhysicalDeviceMemoryProperties2KHR(gpu->obj, &gpu->memory_props2);
1023
1024         struct pNextChainBuildingBlockInfo chain_info[] = {
1025             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR,
1026              .mem_size = sizeof(VkPhysicalDevice8BitStorageFeaturesKHR)},
1027             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR,
1028              .mem_size = sizeof(VkPhysicalDevice16BitStorageFeaturesKHR)},
1029             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR,
1030              .mem_size = sizeof(VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR)},
1031             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR,
1032              .mem_size = sizeof(VkPhysicalDeviceVariablePointerFeaturesKHR)},
1033             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT,
1034              .mem_size = sizeof(VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT)},
1035             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR,
1036              .mem_size = sizeof(VkPhysicalDeviceMultiviewFeaturesKHR)},
1037             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR,
1038              .mem_size = sizeof(VkPhysicalDeviceFloat16Int8FeaturesKHR)},
1039             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR,
1040              .mem_size = sizeof(VkPhysicalDeviceShaderAtomicInt64FeaturesKHR)},
1041             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT,
1042              .mem_size = sizeof(VkPhysicalDeviceTransformFeedbackFeaturesEXT)},
1043             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT,
1044              .mem_size = sizeof(VkPhysicalDeviceScalarBlockLayoutFeaturesEXT)},
1045             {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT,
1046              .mem_size = sizeof(VkPhysicalDeviceFragmentDensityMapFeaturesEXT)}};
1047
1048         uint32_t chain_info_len = ARRAY_SIZE(chain_info);
1049
1050         gpu->features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
1051         buildpNextChain((struct VkStructureHeader *)&gpu->features2, chain_info, chain_info_len);
1052
1053         inst->vkGetPhysicalDeviceFeatures2KHR(gpu->obj, &gpu->features2);
1054     }
1055
1056     AppGetPhysicalDeviceLayerExtensions(gpu, NULL, &gpu->device_extension_count, &gpu->device_extensions);
1057 }
1058
1059 static void AppGpuDestroy(struct AppGpu *gpu) {
1060     free(gpu->device_extensions);
1061
1062     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
1063                               gpu->inst->inst_extensions_count)) {
1064         freepNextChain(gpu->features2.pNext);
1065     }
1066
1067     for (uint32_t i = 0; i < gpu->queue_count; ++i) {
1068         free((void *)gpu->queue_reqs[i].pQueuePriorities);
1069     }
1070     free(gpu->queue_reqs);
1071
1072     free(gpu->queue_props);
1073     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
1074                               gpu->inst->inst_extensions_count)) {
1075         free(gpu->queue_props2);
1076
1077         freepNextChain(gpu->props2.pNext);
1078     }
1079 }
1080
1081 //-----------------------------------------------------------
1082
1083 //---------------------------Win32---------------------------
1084 #ifdef VK_USE_PLATFORM_WIN32_KHR
1085
1086 // MS-Windows event handling function:
1087 LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { return (DefWindowProc(hWnd, uMsg, wParam, lParam)); }
1088
1089 static void AppCreateWin32Window(struct AppInstance *inst) {
1090     inst->h_instance = GetModuleHandle(NULL);
1091
1092     WNDCLASSEX win_class;
1093
1094     // Initialize the window class structure:
1095     win_class.cbSize = sizeof(WNDCLASSEX);
1096     win_class.style = CS_HREDRAW | CS_VREDRAW;
1097     win_class.lpfnWndProc = WndProc;
1098     win_class.cbClsExtra = 0;
1099     win_class.cbWndExtra = 0;
1100     win_class.hInstance = inst->h_instance;
1101     win_class.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1102     win_class.hCursor = LoadCursor(NULL, IDC_ARROW);
1103     win_class.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
1104     win_class.lpszMenuName = NULL;
1105     win_class.lpszClassName = APP_SHORT_NAME;
1106     win_class.hInstance = inst->h_instance;
1107     win_class.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
1108     // Register window class:
1109     if (!RegisterClassEx(&win_class)) {
1110         // It didn't work, so try to give a useful error:
1111         fprintf(stderr, "Failed to register the window class!\n");
1112         exit(1);
1113     }
1114     // Create window with the registered class:
1115     RECT wr = {0, 0, inst->width, inst->height};
1116     AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
1117     inst->h_wnd = CreateWindowEx(0,
1118                                  APP_SHORT_NAME,  // class name
1119                                  APP_SHORT_NAME,  // app name
1120                                  // WS_VISIBLE | WS_SYSMENU |
1121                                  WS_OVERLAPPEDWINDOW,  // window style
1122                                  100, 100,             // x/y coords
1123                                  wr.right - wr.left,   // width
1124                                  wr.bottom - wr.top,   // height
1125                                  NULL,                 // handle to parent
1126                                  NULL,                 // handle to menu
1127                                  inst->h_instance,     // hInstance
1128                                  NULL);                // no extra parameters
1129     if (!inst->h_wnd) {
1130         // It didn't work, so try to give a useful error:
1131         fprintf(stderr, "Failed to create a window!\n");
1132         exit(1);
1133     }
1134 }
1135
1136 static void AppCreateWin32Surface(struct AppInstance *inst) {
1137     VkWin32SurfaceCreateInfoKHR createInfo;
1138     createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
1139     createInfo.pNext = NULL;
1140     createInfo.flags = 0;
1141     createInfo.hinstance = inst->h_instance;
1142     createInfo.hwnd = inst->h_wnd;
1143     VkResult err = vkCreateWin32SurfaceKHR(inst->instance, &createInfo, NULL, &inst->surface);
1144     if (err) ERR_EXIT(err);
1145 }
1146
1147 static void AppDestroyWin32Window(struct AppInstance *inst) { DestroyWindow(inst->h_wnd); }
1148 #endif  // VK_USE_PLATFORM_WIN32_KHR
1149 //-----------------------------------------------------------
1150
1151 #if defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || \
1152     defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_WAYLAND_KHR) || defined(VK_USE_PLATFORM_ANDROID_KHR)
1153 static void AppDestroySurface(struct AppInstance *inst) {  // same for all platforms
1154     vkDestroySurfaceKHR(inst->instance, inst->surface, NULL);
1155 }
1156 #endif
1157
1158 //----------------------------XCB----------------------------
1159
1160 #ifdef VK_USE_PLATFORM_XCB_KHR
1161 static void AppCreateXcbWindow(struct AppInstance *inst) {
1162     //--Init Connection--
1163     const xcb_setup_t *setup;
1164     xcb_screen_iterator_t iter;
1165     int scr;
1166
1167     // API guarantees non-null xcb_connection
1168     inst->xcb_connection = xcb_connect(NULL, &scr);
1169     int conn_error = xcb_connection_has_error(inst->xcb_connection);
1170     if (conn_error) {
1171         fprintf(stderr, "XCB failed to connect to the X server due to error:%d.\n", conn_error);
1172         fflush(stderr);
1173         inst->xcb_connection = NULL;
1174     }
1175
1176     setup = xcb_get_setup(inst->xcb_connection);
1177     iter = xcb_setup_roots_iterator(setup);
1178     while (scr-- > 0) {
1179         xcb_screen_next(&iter);
1180     }
1181
1182     inst->xcb_screen = iter.data;
1183     //-------------------
1184
1185     inst->xcb_window = xcb_generate_id(inst->xcb_connection);
1186     xcb_create_window(inst->xcb_connection, XCB_COPY_FROM_PARENT, inst->xcb_window, inst->xcb_screen->root, 0, 0, inst->width,
1187                       inst->height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, inst->xcb_screen->root_visual, 0, NULL);
1188
1189     xcb_intern_atom_cookie_t cookie = xcb_intern_atom(inst->xcb_connection, 1, 12, "WM_PROTOCOLS");
1190     xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(inst->xcb_connection, cookie, 0);
1191     free(reply);
1192 }
1193
1194 static void AppCreateXcbSurface(struct AppInstance *inst) {
1195     if (!inst->xcb_connection) {
1196         return;
1197     }
1198
1199     VkXcbSurfaceCreateInfoKHR xcb_createInfo;
1200     xcb_createInfo.sType = VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR;
1201     xcb_createInfo.pNext = NULL;
1202     xcb_createInfo.flags = 0;
1203     xcb_createInfo.connection = inst->xcb_connection;
1204     xcb_createInfo.window = inst->xcb_window;
1205     VkResult err = vkCreateXcbSurfaceKHR(inst->instance, &xcb_createInfo, NULL, &inst->surface);
1206     if (err) ERR_EXIT(err);
1207 }
1208
1209 static void AppDestroyXcbWindow(struct AppInstance *inst) {
1210     if (!inst->xcb_connection) {
1211         return;  // Nothing to destroy
1212     }
1213
1214     xcb_destroy_window(inst->xcb_connection, inst->xcb_window);
1215     xcb_disconnect(inst->xcb_connection);
1216 }
1217 #endif  // VK_USE_PLATFORM_XCB_KHR
1218 //-----------------------------------------------------------
1219
1220 //----------------------------XLib---------------------------
1221 #ifdef VK_USE_PLATFORM_XLIB_KHR
1222 static void AppCreateXlibWindow(struct AppInstance *inst) {
1223     long visualMask = VisualScreenMask;
1224     int numberOfVisuals;
1225
1226     inst->xlib_display = XOpenDisplay(NULL);
1227     if (inst->xlib_display == NULL) {
1228         fprintf(stderr, "XLib failed to connect to the X server.\nExiting ...\n");
1229         exit(1);
1230     }
1231
1232     XVisualInfo vInfoTemplate = {};
1233     vInfoTemplate.screen = DefaultScreen(inst->xlib_display);
1234     XVisualInfo *visualInfo = XGetVisualInfo(inst->xlib_display, visualMask, &vInfoTemplate, &numberOfVisuals);
1235     inst->xlib_window = XCreateWindow(inst->xlib_display, RootWindow(inst->xlib_display, vInfoTemplate.screen), 0, 0, inst->width,
1236                                       inst->height, 0, visualInfo->depth, InputOutput, visualInfo->visual, 0, NULL);
1237
1238     XSync(inst->xlib_display, false);
1239     XFree(visualInfo);
1240 }
1241
1242 static void AppCreateXlibSurface(struct AppInstance *inst) {
1243     VkXlibSurfaceCreateInfoKHR createInfo;
1244     createInfo.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR;
1245     createInfo.pNext = NULL;
1246     createInfo.flags = 0;
1247     createInfo.dpy = inst->xlib_display;
1248     createInfo.window = inst->xlib_window;
1249     VkResult err = vkCreateXlibSurfaceKHR(inst->instance, &createInfo, NULL, &inst->surface);
1250     if (err) ERR_EXIT(err);
1251 }
1252
1253 static void AppDestroyXlibWindow(struct AppInstance *inst) {
1254     XDestroyWindow(inst->xlib_display, inst->xlib_window);
1255     XCloseDisplay(inst->xlib_display);
1256 }
1257 #endif  // VK_USE_PLATFORM_XLIB_KHR
1258 //-----------------------------------------------------------
1259
1260 #ifdef VK_USE_PLATFORM_MACOS_MVK
1261
1262 static void AppCreateMacOSWindow(struct AppInstance *inst) {
1263     inst->window = CreateMetalView(inst->width, inst->height);
1264     if (inst->window == NULL) {
1265         fprintf(stderr, "Could not create a native Metal view.\nExiting...\n");
1266         exit(1);
1267     }
1268 }
1269
1270 static void AppCreateMacOSSurface(struct AppInstance *inst) {
1271     VkMacOSSurfaceCreateInfoMVK surface;
1272     surface.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK;
1273     surface.pNext = NULL;
1274     surface.flags = 0;
1275     surface.pView = inst->window;
1276
1277     VkResult err = vkCreateMacOSSurfaceMVK(inst->instance, &surface, NULL, &inst->surface);
1278     if (err) ERR_EXIT(err);
1279 }
1280
1281 static void AppDestroyMacOSWindow(struct AppInstance *inst) { DestroyMetalView(inst->window); }
1282 #endif  // VK_USE_PLATFORM_MACOS_MVK
1283 //-----------------------------------------------------------
1284
1285 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
1286
1287 static void wayland_registry_global(void *data, struct wl_registry *registry, uint32_t id, const char *interface,
1288                                     uint32_t version) {
1289     struct AppInstance *inst = (struct AppInstance *)data;
1290     if (strcmp(interface, "wl_compositor") == 0) {
1291         struct wl_compositor *compositor = (struct wl_compositor *)wl_registry_bind(registry, id, &wl_compositor_interface, 1);
1292         inst->wayland_surface = wl_compositor_create_surface(compositor);
1293     }
1294 }
1295 static void wayland_registry_global_remove(void *data, struct wl_registry *registry, uint32_t id) {}
1296 static const struct wl_registry_listener wayland_registry_listener = {wayland_registry_global, wayland_registry_global_remove};
1297
1298 static void AppCreateWaylandWindow(struct AppInstance *inst) {
1299     inst->wayland_display = wl_display_connect(NULL);
1300     struct wl_registry *registry = wl_display_get_registry(inst->wayland_display);
1301     wl_registry_add_listener(wl_display_get_registry(inst->wayland_display), &wayland_registry_listener, inst);
1302     wl_display_roundtrip(inst->wayland_display);
1303     wl_registry_destroy(registry);
1304 }
1305
1306 static void AppCreateWaylandSurface(struct AppInstance *inst) {
1307     VkWaylandSurfaceCreateInfoKHR createInfo;
1308     createInfo.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
1309     createInfo.pNext = NULL;
1310     createInfo.flags = 0;
1311     createInfo.display = inst->wayland_display;
1312     createInfo.surface = inst->wayland_surface;
1313     VkResult err = vkCreateWaylandSurfaceKHR(inst->instance, &createInfo, NULL, &inst->surface);
1314     if (err) ERR_EXIT(err);
1315 }
1316
1317 static void AppDestroyWaylandWindow(struct AppInstance *inst) { wl_display_disconnect(inst->wayland_display); }
1318 #endif  // VK_USE_PLATFORM_WAYLAND_KHR
1319
1320 #if defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || \
1321     defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_WAYLAND_KHR)
1322 static int AppDumpSurfaceFormats(struct AppInstance *inst, struct AppGpu *gpu, FILE *out) {
1323     // Get the list of VkFormat's that are supported
1324     VkResult err;
1325     uint32_t format_count = 0;
1326     VkSurfaceFormatKHR *surf_formats = NULL;
1327     VkSurfaceFormat2KHR *surf_formats2 = NULL;
1328
1329     const VkPhysicalDeviceSurfaceInfo2KHR surface_info2 = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR,
1330                                                            .surface = inst->surface};
1331
1332     if (CheckExtensionEnabled(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
1333                               gpu->inst->inst_extensions_count)) {
1334         err = inst->vkGetPhysicalDeviceSurfaceFormats2KHR(gpu->obj, &surface_info2, &format_count, NULL);
1335         if (err) ERR_EXIT(err);
1336         surf_formats2 = (VkSurfaceFormat2KHR *)malloc(format_count * sizeof(VkSurfaceFormat2KHR));
1337         if (!surf_formats2) ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
1338         for (uint32_t i = 0; i < format_count; ++i) {
1339             surf_formats2[i].sType = VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR;
1340             surf_formats2[i].pNext = NULL;
1341         }
1342         err = inst->vkGetPhysicalDeviceSurfaceFormats2KHR(gpu->obj, &surface_info2, &format_count, surf_formats2);
1343         if (err) ERR_EXIT(err);
1344     } else {
1345         err = inst->vkGetPhysicalDeviceSurfaceFormatsKHR(gpu->obj, inst->surface, &format_count, NULL);
1346         if (err) ERR_EXIT(err);
1347         surf_formats = (VkSurfaceFormatKHR *)malloc(format_count * sizeof(VkSurfaceFormatKHR));
1348         if (!surf_formats) ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
1349         err = inst->vkGetPhysicalDeviceSurfaceFormatsKHR(gpu->obj, inst->surface, &format_count, surf_formats);
1350         if (err) ERR_EXIT(err);
1351     }
1352
1353     if (html_output) {
1354         fprintf(out, "\t\t\t\t\t<details><summary>Formats: count = <div class='val'>%d</div></summary>", format_count);
1355         if (format_count > 0) {
1356             fprintf(out, "\n");
1357         } else {
1358             fprintf(out, "</details>\n");
1359         }
1360     } else if (human_readable_output) {
1361         printf("Formats:\t\tcount = %d\n", format_count);
1362     }
1363     for (uint32_t i = 0; i < format_count; ++i) {
1364         if (html_output) {
1365             if (CheckExtensionEnabled(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
1366                                       gpu->inst->inst_extensions_count)) {
1367                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>%s</div></summary></details>\n",
1368                         VkFormatString(surf_formats2[i].surfaceFormat.format));
1369             } else {
1370                 fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>%s</div></summary></details>\n",
1371                         VkFormatString(surf_formats[i].format));
1372             }
1373         } else if (human_readable_output) {
1374             if (CheckExtensionEnabled(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
1375                                       gpu->inst->inst_extensions_count)) {
1376                 printf("\t%s\n", VkFormatString(surf_formats2[i].surfaceFormat.format));
1377             } else {
1378                 printf("\t%s\n", VkFormatString(surf_formats[i].format));
1379             }
1380         }
1381     }
1382     if (format_count > 0 && html_output) {
1383         fprintf(out, "\t\t\t\t\t</details>\n");
1384     }
1385
1386     fflush(out);
1387     fflush(stdout);
1388     if (CheckExtensionEnabled(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
1389                               gpu->inst->inst_extensions_count)) {
1390         free(surf_formats2);
1391     } else {
1392         free(surf_formats);
1393     }
1394
1395     return format_count;
1396 }
1397
1398 static int AppDumpSurfacePresentModes(struct AppInstance *inst, struct AppGpu *gpu, FILE *out) {
1399     // Get the list of VkPresentMode's that are supported:
1400     VkResult err;
1401     uint32_t present_mode_count = 0;
1402     err = inst->vkGetPhysicalDeviceSurfacePresentModesKHR(gpu->obj, inst->surface, &present_mode_count, NULL);
1403     if (err) ERR_EXIT(err);
1404
1405     VkPresentModeKHR *surf_present_modes = (VkPresentModeKHR *)malloc(present_mode_count * sizeof(VkPresentInfoKHR));
1406     if (!surf_present_modes) ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
1407     err = inst->vkGetPhysicalDeviceSurfacePresentModesKHR(gpu->obj, inst->surface, &present_mode_count, surf_present_modes);
1408     if (err) ERR_EXIT(err);
1409
1410     if (html_output) {
1411         fprintf(out, "\t\t\t\t\t<details><summary>Present Modes: count = <div class='val'>%d</div></summary>", present_mode_count);
1412         if (present_mode_count > 0) {
1413             fprintf(out, "\n");
1414         } else {
1415             fprintf(out, "</details>");
1416         }
1417     } else if (human_readable_output) {
1418         printf("Present Modes:\t\tcount = %d\n", present_mode_count);
1419     }
1420     for (uint32_t i = 0; i < present_mode_count; ++i) {
1421         if (html_output) {
1422             fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>%s</div></summary></details>\n",
1423                     VkPresentModeString(surf_present_modes[i]));
1424         } else if (human_readable_output) {
1425             printf("\t%s\n", VkPresentModeString(surf_present_modes[i]));
1426         }
1427     }
1428     if (present_mode_count > 0 && html_output) {
1429         fprintf(out, "\t\t\t\t\t</details>\n");
1430     }
1431
1432     fflush(out);
1433     fflush(stdout);
1434     free(surf_present_modes);
1435
1436     return present_mode_count;
1437 }
1438
1439 static void AppDumpSurfaceCapabilities(struct AppInstance *inst, struct AppGpu *gpu, FILE *out) {
1440     if (CheckExtensionEnabled(VK_KHR_SURFACE_EXTENSION_NAME, gpu->inst->inst_extensions, gpu->inst->inst_extensions_count)) {
1441         VkResult err;
1442         err = inst->vkGetPhysicalDeviceSurfaceCapabilitiesKHR(gpu->obj, inst->surface, &inst->surface_capabilities);
1443         if (err) ERR_EXIT(err);
1444
1445         if (html_output) {
1446             fprintf(out, "\t\t\t\t\t<details><summary>VkSurfaceCapabilitiesKHR</summary>\n");
1447             fprintf(out, "\t\t\t\t\t\t<details><summary>minImageCount = <div class='val'>%u</div></summary></details>\n",
1448                     inst->surface_capabilities.minImageCount);
1449             fprintf(out, "\t\t\t\t\t\t<details><summary>maxImageCount = <div class='val'>%u</div></summary></details>\n",
1450                     inst->surface_capabilities.maxImageCount);
1451             fprintf(out, "\t\t\t\t\t\t<details><summary>currentExtent</summary>\n");
1452             fprintf(out, "\t\t\t\t\t\t\t<details><summary>width = <div class='val'>%u</div></summary></details>\n",
1453                     inst->surface_capabilities.currentExtent.width);
1454             fprintf(out, "\t\t\t\t\t\t\t<details><summary>height = <div class='val'>%u</div></summary></details>\n",
1455                     inst->surface_capabilities.currentExtent.height);
1456             fprintf(out, "\t\t\t\t\t\t</details>\n");
1457             fprintf(out, "\t\t\t\t\t\t<details><summary>minImageExtent</summary>\n");
1458             fprintf(out, "\t\t\t\t\t\t\t<details><summary>width = <div class='val'>%u</div></summary></details>\n",
1459                     inst->surface_capabilities.minImageExtent.width);
1460             fprintf(out, "\t\t\t\t\t\t\t<details><summary>height = <div class='val'>%u</div></summary></details>\n",
1461                     inst->surface_capabilities.minImageExtent.height);
1462             fprintf(out, "\t\t\t\t\t\t</details>\n");
1463             fprintf(out, "\t\t\t\t\t\t<details><summary>maxImageExtent</summary>\n");
1464             fprintf(out, "\t\t\t\t\t\t\t<details><summary>width = <div class='val'>%u</div></summary></details>\n",
1465                     inst->surface_capabilities.maxImageExtent.width);
1466             fprintf(out, "\t\t\t\t\t\t\t<details><summary>height = <div class='val'>%u</div></summary></details>\n",
1467                     inst->surface_capabilities.maxImageExtent.height);
1468             fprintf(out, "\t\t\t\t\t\t</details>\n");
1469             fprintf(out, "\t\t\t\t\t\t<details><summary>maxImageArrayLayers = <div class='val'>%u</div></summary></details>\n",
1470                     inst->surface_capabilities.maxImageArrayLayers);
1471             fprintf(out, "\t\t\t\t\t\t<details><summary>supportedTransform</summary>\n");
1472             if (inst->surface_capabilities.supportedTransforms == 0) {
1473                 fprintf(out, "\t\t\t\t\t\t\t<details><summary>None</summary></details>\n");
1474             }
1475             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
1476                 fprintf(out,
1477                         "\t\t\t\t\t\t\t<details><summary><div "
1478                         "class='type'>VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR</div></summary></details>\n");
1479             }
1480             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) {
1481                 fprintf(out,
1482                         "\t\t\t\t\t\t\t\t<details><summary><div "
1483                         "class='type'>VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR</div></summary></details>\n");
1484             }
1485             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR) {
1486                 fprintf(out,
1487                         "\t\t\t\t\t\t\t\t<details><summary><div "
1488                         "class='type'>VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR</div></summary></details>\n");
1489             }
1490             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) {
1491                 fprintf(out,
1492                         "\t\t\t\t\t\t\t\t<details><summary><div "
1493                         "class='type'>VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR</div></summary></details>\n");
1494             }
1495             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR) {
1496                 fprintf(out,
1497                         "\t\t\t\t\t\t\t\t<details><summary><div "
1498                         "class='type'>VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR</div></summary></details>\n");
1499             }
1500             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR) {
1501                 fprintf(out,
1502                         "\t\t\t\t\t\t\t\t<details><summary><div "
1503                         "class='type'>VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR</div></summary></details>\n");
1504             }
1505             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR) {
1506                 fprintf(out,
1507                         "\t\t\t\t\t\t\t\t<details><summary><div "
1508                         "class='type'>VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR</div></summary></details>\n");
1509             }
1510             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR) {
1511                 fprintf(out,
1512                         "\t\t\t\t\t\t\t\t<details><summary><div "
1513                         "class='type'>VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR</div></summary></details>\n");
1514             }
1515             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR) {
1516                 fprintf(out,
1517                         "\t\t\t\t\t\t\t\t<details><summary><div "
1518                         "class='type'>VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR</div></summary></details>\n");
1519             }
1520             fprintf(out, "\t\t\t\t\t\t</details>\n");
1521             fprintf(out, "\t\t\t\t\t\t<details><summary>currentTransform</summary>\n");
1522             if (inst->surface_capabilities.currentTransform == 0) {
1523                 fprintf(out, "\t\t\t\t\t\t\t<details><summary>None</summary></details>\n");
1524             }
1525             if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
1526                 fprintf(out,
1527                         "\t\t\t\t\t\t\t<details><summary><div "
1528                         "class='type'>VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR</div></summary></details>\n");
1529             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) {
1530                 fprintf(out,
1531                         "\t\t\t\t\t\t\t<details><summary><div "
1532                         "class='type'>VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR</div></summary></details>\n");
1533             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR) {
1534                 fprintf(out,
1535                         "\t\t\t\t\t\t\t<details><summary><div "
1536                         "class='type'>VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR</div></summary></details>\n");
1537             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) {
1538                 fprintf(out,
1539                         "\t\t\t\t\t\t\t<details><summary><div "
1540                         "class='type'>VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR</div></summary></details>\n");
1541             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR) {
1542                 fprintf(out,
1543                         "\t\t\t\t\t\t\t<details><summary><div "
1544                         "class='type'>VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR</div></summary></details>\n");
1545             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR) {
1546                 fprintf(out,
1547                         "\t\t\t\t\t\t<details><summary><div "
1548                         "class='type'>VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR</div></summary></details>\n");
1549             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR) {
1550                 fprintf(out,
1551                         "\t\t\t\t\t\t\t<details><summary><div "
1552                         "class='type'>VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR</div></summary></details>\n");
1553             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR) {
1554                 fprintf(out,
1555                         "\t\t\t\t\t\t\t<details><summary><div "
1556                         "class='type'>VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR</div></summary></details>\n");
1557             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR) {
1558                 fprintf(out,
1559                         "\t\t\t\t\t\t\t<details><summary><div "
1560                         "class='type'>VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR</div></summary></details>\n");
1561             }
1562             fprintf(out, "\t\t\t\t\t\t</details>\n");
1563             fprintf(out, "\t\t\t\t\t\t<details><summary>supportedCompositeAlpha</summary>\n");
1564             if (inst->surface_capabilities.supportedCompositeAlpha == 0) {
1565                 fprintf(out, "\t\t\t\t\t\t\t<details><summary>None</summary></details>\n");
1566             }
1567             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) {
1568                 fprintf(out,
1569                         "\t\t\t\t\t\t\t<details><summary><div "
1570                         "class='type'>VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR</div></summary></details>\n");
1571             }
1572             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) {
1573                 fprintf(out,
1574                         "\t\t\t\t\t\t\t<details><summary><div "
1575                         "class='type'>VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR</div></summary></details>\n");
1576             }
1577             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) {
1578                 fprintf(out,
1579                         "\t\t\t\t\t\t\t<details><summary><div "
1580                         "class='type'>VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR</div></summary></details>\n");
1581             }
1582             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) {
1583                 fprintf(out,
1584                         "\t\t\t\t\t\t\t<details><summary><div "
1585                         "class='type'>VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR</div></summary></details>\n");
1586             }
1587             fprintf(out, "\t\t\t\t\t\t</details>\n");
1588             fprintf(out, "\t\t\t\t\t\t<details><summary>supportedUsageFlags</summary>\n");
1589             if (inst->surface_capabilities.supportedUsageFlags == 0) {
1590                 fprintf(out, "\t\t\t\t\t\t\t<details><summary>None</summary></details>\n");
1591             }
1592             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) {
1593                 fprintf(out,
1594                         "\t\t\t\t\t\t\t<details><summary><div "
1595                         "class='type'>VK_IMAGE_USAGE_TRANSFER_SRC_BIT</div></summary></details>\n");
1596             }
1597             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) {
1598                 fprintf(out,
1599                         "\t\t\t\t\t\t\t<details><summary><div "
1600                         "class='type'>VK_IMAGE_USAGE_TRANSFER_DST_BIT</div></summary></details>\n");
1601             }
1602             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) {
1603                 fprintf(out,
1604                         "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_SAMPLED_BIT</div></summary></details>\n");
1605             }
1606             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_STORAGE_BIT) {
1607                 fprintf(out,
1608                         "\t\t\t\t\t\t\t<details><summary><div class='type'>VK_IMAGE_USAGE_STORAGE_BIT</div></summary></details>\n");
1609             }
1610             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
1611                 fprintf(out,
1612                         "\t\t\t\t\t\t\t<details><summary><div "
1613                         "class='type'>VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT</div></summary></details>\n");
1614             }
1615             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
1616                 fprintf(out,
1617                         "\t\t\t\t\t\t\t<details><summary><div "
1618                         "class='type'>VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT</div></summary></details>\n");
1619             }
1620             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) {
1621                 fprintf(out,
1622                         "\t\t\t\t\t\t\t<details><summary><div "
1623                         "class='type'>VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT</div></summary></details>\n");
1624             }
1625             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) {
1626                 fprintf(out,
1627                         "\t\t\t\t\t\t\t<details><summary><div "
1628                         "class='type'>VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT</div></summary></details>\n");
1629             }
1630             fprintf(out, "\t\t\t\t\t\t</details>\n");
1631         } else if (human_readable_output) {
1632             printf("VkSurfaceCapabilitiesKHR:\n");
1633             printf("\tminImageCount       = %u\n", inst->surface_capabilities.minImageCount);
1634             printf("\tmaxImageCount       = %u\n", inst->surface_capabilities.maxImageCount);
1635             printf("\tcurrentExtent:\n");
1636             printf("\t\twidth       = %u\n", inst->surface_capabilities.currentExtent.width);
1637             printf("\t\theight      = %u\n", inst->surface_capabilities.currentExtent.height);
1638             printf("\tminImageExtent:\n");
1639             printf("\t\twidth       = %u\n", inst->surface_capabilities.minImageExtent.width);
1640             printf("\t\theight      = %u\n", inst->surface_capabilities.minImageExtent.height);
1641             printf("\tmaxImageExtent:\n");
1642             printf("\t\twidth       = %u\n", inst->surface_capabilities.maxImageExtent.width);
1643             printf("\t\theight      = %u\n", inst->surface_capabilities.maxImageExtent.height);
1644             printf("\tmaxImageArrayLayers = %u\n", inst->surface_capabilities.maxImageArrayLayers);
1645             printf("\tsupportedTransform:\n");
1646             if (inst->surface_capabilities.supportedTransforms == 0) {
1647                 printf("\t\tNone\n");
1648             }
1649             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
1650                 printf("\t\tVK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR\n");
1651             }
1652             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) {
1653                 printf("\t\tVK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR\n");
1654             }
1655             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR) {
1656                 printf("\t\tVK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR\n");
1657             }
1658             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) {
1659                 printf("\t\tVK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR\n");
1660             }
1661             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR) {
1662                 printf("\t\tVK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR\n");
1663             }
1664             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR) {
1665                 printf("\t\tVK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR\n");
1666             }
1667             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR) {
1668                 printf("\t\tVK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR\n");
1669             }
1670             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR) {
1671                 printf("\t\tVK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR\n");
1672             }
1673             if (inst->surface_capabilities.supportedTransforms & VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR) {
1674                 printf("\t\tVK_SURFACE_TRANSFORM_INHERIT_BIT_KHR\n");
1675             }
1676             printf("\tcurrentTransform:\n");
1677             if (inst->surface_capabilities.currentTransform == 0) {
1678                 printf("\t\tNone\n");
1679             }
1680             if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) {
1681                 printf("\t\tVK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR\n");
1682             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) {
1683                 printf("\t\tVK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR\n");
1684             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR) {
1685                 printf("\t\tVK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR\n");
1686             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) {
1687                 printf("\t\tVK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR\n");
1688             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR) {
1689                 printf("\t\tVK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR\n");
1690             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR) {
1691                 printf("\t\tVK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR\n");
1692             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR) {
1693                 printf("\t\tVK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR\n");
1694             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR) {
1695                 printf("\t\tVK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR\n");
1696             } else if (inst->surface_capabilities.currentTransform & VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR) {
1697                 printf("\t\tVK_SURFACE_TRANSFORM_INHERIT_BIT_KHR\n");
1698             }
1699             printf("\tsupportedCompositeAlpha:\n");
1700             if (inst->surface_capabilities.supportedCompositeAlpha == 0) {
1701                 printf("\t\tNone\n");
1702             }
1703             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) {
1704                 printf("\t\tVK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR\n");
1705             }
1706             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) {
1707                 printf("\t\tVK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR\n");
1708             }
1709             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) {
1710                 printf("\t\tVK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR\n");
1711             }
1712             if (inst->surface_capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) {
1713                 printf("\t\tVK_COMPOSITE_ALPHA_INHERIT_BIT_KHR\n");
1714             }
1715             printf("\tsupportedUsageFlags:\n");
1716             if (inst->surface_capabilities.supportedUsageFlags == 0) {
1717                 printf("\t\tNone\n");
1718             }
1719             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) {
1720                 printf("\t\tVK_IMAGE_USAGE_TRANSFER_SRC_BIT\n");
1721             }
1722             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) {
1723                 printf("\t\tVK_IMAGE_USAGE_TRANSFER_DST_BIT\n");
1724             }
1725             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) {
1726                 printf("\t\tVK_IMAGE_USAGE_SAMPLED_BIT\n");
1727             }
1728             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_STORAGE_BIT) {
1729                 printf("\t\tVK_IMAGE_USAGE_STORAGE_BIT\n");
1730             }
1731             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
1732                 printf("\t\tVK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT\n");
1733             }
1734             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
1735                 printf("\t\tVK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT\n");
1736             }
1737             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) {
1738                 printf("\t\tVK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT\n");
1739             }
1740             if (inst->surface_capabilities.supportedUsageFlags & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) {
1741                 printf("\t\tVK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT\n");
1742             }
1743         }
1744
1745         // Get additional surface capability information from vkGetPhysicalDeviceSurfaceCapabilities2EXT
1746         if (CheckExtensionEnabled(VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME, gpu->inst->inst_extensions,
1747                                   gpu->inst->inst_extensions_count)) {
1748             memset(&inst->surface_capabilities2_ext, 0, sizeof(VkSurfaceCapabilities2EXT));
1749             inst->surface_capabilities2_ext.sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT;
1750             inst->surface_capabilities2_ext.pNext = NULL;
1751
1752             err = inst->vkGetPhysicalDeviceSurfaceCapabilities2EXT(gpu->obj, inst->surface, &inst->surface_capabilities2_ext);
1753             if (err) ERR_EXIT(err);
1754
1755             if (html_output) {
1756                 fprintf(out, "\t\t\t\t\t\t<details><summary>VkSurfaceCapabilities2EXT</summary>\n");
1757                 fprintf(out, "\t\t\t\t\t\t\t<details><summary>supportedSurfaceCounters</summary>\n");
1758                 if (inst->surface_capabilities2_ext.supportedSurfaceCounters == 0) {
1759                     fprintf(out, "\t\t\t\t\t\t\t\t<details><summary>None</summary></details>\n");
1760                 }
1761                 if (inst->surface_capabilities2_ext.supportedSurfaceCounters & VK_SURFACE_COUNTER_VBLANK_EXT) {
1762                     fprintf(out,
1763                             "\t\t\t\t\t\t\t\t<details><summary><div "
1764                             "class='type'>VK_SURFACE_COUNTER_VBLANK_EXT</div></summary></details>\n");
1765                 }
1766                 fprintf(out, "\t\t\t\t\t\t\t</details>\n");
1767                 fprintf(out, "\t\t\t\t\t\t</details>\n");
1768             } else if (human_readable_output) {
1769                 printf("VkSurfaceCapabilities2EXT:\n");
1770                 printf("\tsupportedSurfaceCounters:\n");
1771                 if (inst->surface_capabilities2_ext.supportedSurfaceCounters == 0) {
1772                     printf("\t\tNone\n");
1773                 }
1774                 if (inst->surface_capabilities2_ext.supportedSurfaceCounters & VK_SURFACE_COUNTER_VBLANK_EXT) {
1775                     printf("\t\tVK_SURFACE_COUNTER_VBLANK_EXT\n");
1776                 }
1777             }
1778         }
1779
1780         // Get additional surface capability information from vkGetPhysicalDeviceSurfaceCapabilities2KHR
1781         if (CheckExtensionEnabled(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
1782                                   gpu->inst->inst_extensions_count)) {
1783             if (CheckExtensionEnabled(VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME, gpu->inst->inst_extensions,
1784                                       gpu->inst->inst_extensions_count)) {
1785                 inst->shared_surface_capabilities.sType = VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR;
1786                 inst->shared_surface_capabilities.pNext = NULL;
1787                 inst->surface_capabilities2.pNext = &inst->shared_surface_capabilities;
1788             } else {
1789                 inst->surface_capabilities2.pNext = NULL;
1790             }
1791
1792             inst->surface_capabilities2.sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
1793
1794             VkPhysicalDeviceSurfaceInfo2KHR surface_info;
1795             surface_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR;
1796             surface_info.pNext = NULL;
1797             surface_info.surface = inst->surface;
1798
1799             err = inst->vkGetPhysicalDeviceSurfaceCapabilities2KHR(gpu->obj, &surface_info, &inst->surface_capabilities2);
1800             if (err) ERR_EXIT(err);
1801
1802             void *place = inst->surface_capabilities2.pNext;
1803             while (place) {
1804                 struct VkStructureHeader *work = (struct VkStructureHeader *)place;
1805                 if (work->sType == VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR) {
1806                     VkSharedPresentSurfaceCapabilitiesKHR *shared_surface_capabilities =
1807                         (VkSharedPresentSurfaceCapabilitiesKHR *)place;
1808                     if (html_output) {
1809                         fprintf(out, "\t\t\t\t\t\t<details><summary>VkSharedPresentSurfaceCapabilitiesKHR</summary>\n");
1810                         fprintf(out, "\t\t\t\t\t\t\t<details><summary>sharedPresentSupportedUsageFlags</summary>\n");
1811                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags == 0) {
1812                             fprintf(out, "\t\t\t\t\t\t\t\t<details><summary>None</summary></details>\n");
1813                         }
1814                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) {
1815                             fprintf(out,
1816                                     "\t\t\t\t\t\t\t\t<details><summary><div "
1817                                     "class='type'>VK_IMAGE_USAGE_TRANSFER_SRC_BIT</div></summary></details>\n");
1818                         }
1819                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) {
1820                             fprintf(out,
1821                                     "\t\t\t\t\t\t\t\t<details><summary><div "
1822                                     "class='type'>VK_IMAGE_USAGE_TRANSFER_DST_BIT</div></summary></details>\n");
1823                         }
1824                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) {
1825                             fprintf(out,
1826                                     "\t\t\t\t\t\t\t\t<details><summary><div "
1827                                     "class='type'>VK_IMAGE_USAGE_SAMPLED_BIT</div></summary></details>\n");
1828                         }
1829                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_STORAGE_BIT) {
1830                             fprintf(out,
1831                                     "\t\t\t\t\t\t\t\t<details><summary><div "
1832                                     "class='type'>VK_IMAGE_USAGE_STORAGE_BIT</div></summary></details>\n");
1833                         }
1834                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
1835                             fprintf(out,
1836                                     "\t\t\t\t\t\t\t\t<details><summary><div "
1837                                     "class='type'>VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT</div></summary></details>\n");
1838                         }
1839                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags &
1840                             VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
1841                             fprintf(out,
1842                                     "\t\t\t\t\t\t\t\t<details><summary><div "
1843                                     "class='type'>VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT</div></summary></details>\n");
1844                         }
1845                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags &
1846                             VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) {
1847                             fprintf(out,
1848                                     "\t\t\t\t\t\t\t\t<details><summary><div "
1849                                     "class='type'>VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT</div></summary></details>\n");
1850                         }
1851                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) {
1852                             fprintf(out,
1853                                     "\t\t\t\t\t\t\t\t<details><summary><div "
1854                                     "class='type'>VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT</div></summary></details>\n");
1855                         }
1856                         fprintf(out, "\t\t\t\t\t\t\t</details>\n");
1857                         fprintf(out, "\t\t\t\t\t\t</details>\n");
1858                     } else if (human_readable_output) {
1859                         printf("VkSharedPresentSurfaceCapabilitiesKHR:\n");
1860                         printf("\tsharedPresentSupportedUsageFlags:\n");
1861                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags == 0) {
1862                             printf("\t\tNone\n");
1863                         }
1864                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) {
1865                             printf("\t\tVK_IMAGE_USAGE_TRANSFER_SRC_BIT\n");
1866                         }
1867                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) {
1868                             printf("\t\tVK_IMAGE_USAGE_TRANSFER_DST_BIT\n");
1869                         }
1870                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) {
1871                             printf("\t\tVK_IMAGE_USAGE_SAMPLED_BIT\n");
1872                         }
1873                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_STORAGE_BIT) {
1874                             printf("\t\tVK_IMAGE_USAGE_STORAGE_BIT\n");
1875                         }
1876                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) {
1877                             printf("\t\tVK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT\n");
1878                         }
1879                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags &
1880                             VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) {
1881                             printf("\t\tVK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT\n");
1882                         }
1883                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags &
1884                             VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT) {
1885                             printf("\t\tVK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT\n");
1886                         }
1887                         if (shared_surface_capabilities->sharedPresentSupportedUsageFlags & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) {
1888                             printf("\t\tVK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT\n");
1889                         }
1890                     }
1891                 }
1892                 place = work->pNext;
1893             }
1894         }
1895         if (html_output) {
1896             fprintf(out, "\t\t\t\t\t</details>\n");
1897         }
1898     }
1899 }
1900
1901 struct SurfaceExtensionInfo {
1902     const char *name;
1903     void (*create_window)(struct AppInstance *);
1904     void (*create_surface)(struct AppInstance *);
1905     void (*destroy_window)(struct AppInstance *);
1906 };
1907
1908 static void AppDumpSurfaceExtension(struct AppInstance *inst, struct AppGpu *gpus, uint32_t gpu_count,
1909                                     struct SurfaceExtensionInfo *surface_extension, int *format_count, int *present_mode_count,
1910                                     FILE *out) {
1911     if (!CheckExtensionEnabled(surface_extension->name, inst->inst_extensions, inst->inst_extensions_count)) {
1912         return;
1913     }
1914
1915     surface_extension->create_window(inst);
1916     for (uint32_t i = 0; i < gpu_count; ++i) {
1917         surface_extension->create_surface(inst);
1918         if (html_output) {
1919             fprintf(out, "\t\t\t\t<details><summary>GPU id : <div class='val'>%u</div> (%s)</summary>\n", i,
1920                     gpus[i].props.deviceName);
1921             fprintf(out, "\t\t\t\t\t<details><summary>Surface type : <div class='type'>%s</div></summary></details>\n",
1922                     surface_extension->name);
1923         } else if (human_readable_output) {
1924             printf("GPU id       : %u (%s)\n", i, gpus[i].props.deviceName);
1925             printf("Surface type : %s\n", surface_extension->name);
1926         }
1927         *format_count += AppDumpSurfaceFormats(inst, &gpus[i], out);
1928         *present_mode_count += AppDumpSurfacePresentModes(inst, &gpus[i], out);
1929         AppDumpSurfaceCapabilities(inst, &gpus[i], out);
1930
1931         if (html_output) {
1932             fprintf(out, "\t\t\t\t</details>\n");
1933         } else if (human_readable_output) {
1934             printf("\n");
1935         }
1936     }
1937     surface_extension->destroy_window(inst);
1938 }
1939
1940 #endif
1941
1942 static void AppDevDumpFormatProps(const struct AppGpu *gpu, VkFormat fmt, bool *first_in_list, FILE *out) {
1943     VkFormatProperties props;
1944     vkGetPhysicalDeviceFormatProperties(gpu->obj, fmt, &props);
1945     struct {
1946         const char *name;
1947         VkFlags flags;
1948     } features[3];
1949
1950     features[0].name = "linearTiling   FormatFeatureFlags";
1951     features[0].flags = props.linearTilingFeatures;
1952     features[1].name = "optimalTiling  FormatFeatureFlags";
1953     features[1].flags = props.optimalTilingFeatures;
1954     features[2].name = "bufferFeatures FormatFeatureFlags";
1955     features[2].flags = props.bufferFeatures;
1956
1957     if (html_output) {
1958         fprintf(out, "\t\t\t\t\t\t<details><summary><div class='type'>FORMAT_%s</div></summary>\n", VkFormatString(fmt));
1959     } else if (human_readable_output) {
1960         printf("\nFORMAT_%s:", VkFormatString(fmt));
1961     }
1962     for (uint32_t i = 0; i < ARRAY_SIZE(features); ++i) {
1963         if (html_output) {
1964             fprintf(out, "\t\t\t\t\t\t\t<details open><summary>%s</summary>\n", features[i].name);
1965             if (features[i].flags == 0) {
1966                 fprintf(out, "\t\t\t\t\t\t\t\t<details><summary>None</summary></details>\n");
1967             } else {
1968                 fprintf(out, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
1969                         ((features[i].flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) ? "\t\t\t\t\t\t\t\t<details><summary><div "
1970                                                                                      "class='type'>VK_FORMAT_FEATURE_SAMPLED_IMAGE_"
1971                                                                                      "BIT</div></summary></details>\n"
1972                                                                                    : ""),  // 0x0001
1973                         ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) ? "\t\t\t\t\t\t\t\t<details><summary><div "
1974                                                                                      "class='type'>VK_FORMAT_FEATURE_STORAGE_IMAGE_"
1975                                                                                      "BIT</div></summary></details>\n"
1976                                                                                    : ""),  // 0x0002
1977                         ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT)
1978                              ? "\t\t\t\t\t\t\t\t<details><summary><div "
1979                                "class='type'>VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT</div></summary></details>\n"
1980                              : ""),  // 0x0004
1981                         ((features[i].flags & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT)
1982                              ? "\t\t\t\t\t\t\t\t<details><summary><div "
1983                                "class='type'>VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT</div></summary></details>\n"
1984                              : ""),  // 0x0008
1985                         ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT)
1986                              ? "\t\t\t\t\t\t\t\t<details><summary><div "
1987                                "class='type'>VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT</div></summary></details>\n"
1988                              : ""),  // 0x0010
1989                         ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT)
1990                              ? "\t\t\t\t\t\t\t\t<details><summary><div "
1991                                "class='type'>VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT</div></summary></details>\n"
1992                              : ""),  // 0x0020
1993                         ((features[i].flags & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) ? "\t\t\t\t\t\t\t\t<details><summary><div "
1994                                                                                      "class='type'>VK_FORMAT_FEATURE_VERTEX_BUFFER_"
1995                                                                                      "BIT</div></summary></details>\n"
1996                                                                                    : ""),  // 0x0040
1997                         ((features[i].flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) ? "\t\t\t\t\t\t\t\t<details><summary><div "
1998                                                                                         "class='type'>VK_FORMAT_FEATURE_COLOR_"
1999                                                                                         "ATTACHMENT_BIT</div></summary></details>\n"
2000                                                                                       : ""),  // 0x0080
2001                         ((features[i].flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT)
2002                              ? "\t\t\t\t\t\t\t\t<details><summary><div "
2003                                "class='type'>VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT</div></summary></details>\n"
2004                              : ""),  // 0x0100
2005                         ((features[i].flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
2006                              ? "\t\t\t\t\t\t\t\t<details><summary><div "
2007                                "class='type'>VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT</div></summary></details>\n"
2008                              : ""),  // 0x0200
2009                         ((features[i].flags & VK_FORMAT_FEATURE_BLIT_SRC_BIT) ? "\t\t\t\t\t\t\t\t<details><summary><div "
2010                                                                                 "class='type'>VK_FORMAT_FEATURE_BLIT_SRC_BIT</"
2011                                                                                 "div></summary></details>\n"
2012                                                                               : ""),  // 0x0400
2013                         ((features[i].flags & VK_FORMAT_FEATURE_BLIT_DST_BIT) ? "\t\t\t\t\t\t\t\t<details><summary><div "
2014                                                                                 "class='type'>VK_FORMAT_FEATURE_BLIT_DST_BIT</"
2015                                                                                 "div></summary></details>\n"
2016                                                                               : ""),  // 0x0800
2017                         ((features[i].flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)
2018                              ? "\t\t\t\t\t\t\t\t<details><summary><div "
2019                                "class='type'>VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT</div></summary></details>\n"
2020                              : ""),  // 0x1000
2021                         ((features[i].flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG)
2022                              ? "\t\t\t\t\t\t\t\t<details><summary><div "
2023                                "class='type'>VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG</div></summary></details>\n"
2024                              : ""),  // 0x2000
2025                         ((features[i].flags & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR) ? "\t\t\t\t\t\t\t\t<details><summary><div "
2026                                                                                         "class='type'>VK_FORMAT_FEATURE_TRANSFER_"
2027                                                                                         "SRC_BIT_KHR</div></summary></details>\n"
2028                                                                                       : ""),  // 0x4000
2029                         ((features[i].flags & VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR) ? "\t\t\t\t\t\t\t\t<details><summary><div "
2030                                                                                         "class='type'>VK_FORMAT_FEATURE_TRANSFER_"
2031                                                                                         "DST_BIT_KHR</div></summary></details>\n"
2032                                                                                       : ""));  // 0x8000
2033             }
2034             fprintf(out, "\t\t\t\t\t\t\t</details>\n");
2035         } else if (human_readable_output) {
2036             printf("\n\t%s:", features[i].name);
2037             if (features[i].flags == 0) {
2038                 printf("\n\t\tNone");
2039             } else {
2040                 printf(
2041                     "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
2042                     ((features[i].flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) ? "\n\t\tVK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT"
2043                                                                                : ""),  // 0x0001
2044                     ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) ? "\n\t\tVK_FORMAT_FEATURE_STORAGE_IMAGE_BIT"
2045                                                                                : ""),  // 0x0002
2046                     ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT)
2047                          ? "\n\t\tVK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT"
2048                          : ""),  // 0x0004
2049                     ((features[i].flags & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT)
2050                          ? "\n\t\tVK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT"
2051                          : ""),  // 0x0008
2052                     ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT)
2053                          ? "\n\t\tVK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT"
2054                          : ""),  // 0x0010
2055                     ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT)
2056                          ? "\n\t\tVK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT"
2057                          : ""),  // 0x0020
2058                     ((features[i].flags & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) ? "\n\t\tVK_FORMAT_FEATURE_VERTEX_BUFFER_BIT"
2059                                                                                : ""),  // 0x0040
2060                     ((features[i].flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) ? "\n\t\tVK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT"
2061                                                                                   : ""),  // 0x0080
2062                     ((features[i].flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT)
2063                          ? "\n\t\tVK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT"
2064                          : ""),  // 0x0100
2065                     ((features[i].flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
2066                          ? "\n\t\tVK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT"
2067                          : ""),                                                                                            // 0x0200
2068                     ((features[i].flags & VK_FORMAT_FEATURE_BLIT_SRC_BIT) ? "\n\t\tVK_FORMAT_FEATURE_BLIT_SRC_BIT" : ""),  // 0x0400
2069                     ((features[i].flags & VK_FORMAT_FEATURE_BLIT_DST_BIT) ? "\n\t\tVK_FORMAT_FEATURE_BLIT_DST_BIT" : ""),  // 0x0800
2070                     ((features[i].flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)
2071                          ? "\n\t\tVK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT"
2072                          : ""),  // 0x1000
2073                     ((features[i].flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG)
2074                          ? "\n\t\tVK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG"
2075                          : ""),  // 0x2000
2076                     ((features[i].flags & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR) ? "\n\t\tVK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR"
2077                                                                                   : ""),  // 0x4000
2078                     ((features[i].flags & VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR) ? "\n\t\tVK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR"
2079                                                                                   : ""));  // 0x8000
2080             }
2081         }
2082     }
2083     if (html_output) {
2084         fprintf(out, "\t\t\t\t\t\t</details>\n");
2085     } else if (human_readable_output) {
2086         printf("\n");
2087     }
2088     if (json_output && (props.linearTilingFeatures || props.optimalTilingFeatures || props.bufferFeatures)) {
2089         if (!(*first_in_list)) {
2090             printf(",");
2091         } else {
2092             *first_in_list = false;
2093         }
2094         printf("\n");
2095         printf("\t\t{\n");
2096         printf("\t\t\t\"formatID\": %d,\n", fmt);
2097         printf("\t\t\t\"linearTilingFeatures\": %u,\n", props.linearTilingFeatures);
2098         printf("\t\t\t\"optimalTilingFeatures\": %u,\n", props.optimalTilingFeatures);
2099         printf("\t\t\t\"bufferFeatures\": %u\n", props.bufferFeatures);
2100         printf("\t\t}");
2101     }
2102 }
2103
2104 /* This structure encodes all the format ranges to be queried.
2105  * It ensures that a format is not queried if the instance
2106  * doesn't support it (either through the instance version or
2107  * through extensions).
2108  */
2109 static struct FormatRange {
2110     // the Vulkan standard version that supports this format range, or 0 if non-standard
2111     uint32_t minimum_instance_version;
2112
2113     // The name of the extension that supports this format range, or NULL if the range
2114     // is only part of the standard
2115     char *extension_name;
2116
2117     // The first and last supported formats within this range.
2118     VkFormat first_format;
2119     VkFormat last_format;
2120 } supported_format_ranges[] = {
2121     {
2122         // Standard formats in Vulkan 1.0
2123         VK_MAKE_VERSION(1, 0, 0),
2124         NULL,
2125         VK_FORMAT_BEGIN_RANGE,
2126         VK_FORMAT_END_RANGE,
2127     },
2128     {
2129         // YCBCR extension, standard in Vulkan 1.1
2130         VK_MAKE_VERSION(1, 1, 0),
2131         VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME,
2132         VK_FORMAT_G8B8G8R8_422_UNORM,
2133         VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM,
2134     },
2135     {
2136         // PVRTC extension, not standardized
2137         0,
2138         VK_IMG_FORMAT_PVRTC_EXTENSION_NAME,
2139         VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG,
2140         VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG,
2141     },
2142 };
2143
2144 // Helper function to determine whether a format range is currently supported.
2145 bool FormatRangeSupported(const struct FormatRange *format_range, const struct AppGpu *gpu) {
2146     // True if standard and supported by both this instance and this GPU
2147     if (format_range->minimum_instance_version > 0 && gpu->inst->instance_version >= format_range->minimum_instance_version &&
2148         gpu->props.apiVersion >= format_range->minimum_instance_version) {
2149         return true;
2150     }
2151
2152     // True if this extension is present
2153     if (format_range->extension_name != NULL) {
2154         return CheckExtensionEnabled(format_range->extension_name, gpu->inst->inst_extensions, gpu->inst->inst_extensions_count);
2155     }
2156
2157     // Otherwise, not supported.
2158     return false;
2159 }
2160
2161 bool FormatPropsEq(const VkFormatProperties *props1, const VkFormatProperties *props2) {
2162     if (props1->bufferFeatures == props2->bufferFeatures && props1->linearTilingFeatures == props2->linearTilingFeatures &&
2163         props1->optimalTilingFeatures == props2->optimalTilingFeatures) {
2164         return true;
2165     } else {
2166         return false;
2167     }
2168 }
2169
2170 struct PropFormats {
2171     VkFormatProperties props;
2172
2173     uint32_t format_count;
2174     uint32_t format_reserve;
2175     VkFormat *formats;
2176 };
2177
2178 void FormatPropsShortenedDump(const struct AppGpu *gpu) {
2179     const VkFormatProperties unsupported_prop = {0};
2180     uint32_t unique_props_count = 1;
2181     uint32_t unique_props_reserve = 50;
2182     struct PropFormats *prop_map = malloc(sizeof(struct PropFormats) * unique_props_reserve);
2183     if (!prop_map) ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
2184     prop_map[0].props = unsupported_prop;
2185     prop_map[0].format_count = 0;
2186     prop_map[0].format_reserve = 20;
2187     prop_map[0].formats = malloc(sizeof(VkFormat) * prop_map[0].format_reserve);
2188     if (!prop_map[0].formats) ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
2189
2190     for (uint32_t ri = 0; ri < ARRAY_SIZE(supported_format_ranges); ++ri) {
2191         struct FormatRange format_range = supported_format_ranges[ri];
2192         if (FormatRangeSupported(&format_range, gpu)) {
2193             for (VkFormat fmt = format_range.first_format; fmt <= format_range.last_format; ++fmt) {
2194                 VkFormatProperties props;
2195                 vkGetPhysicalDeviceFormatProperties(gpu->obj, fmt, &props);
2196
2197                 uint32_t formats_prop_i = 0;
2198                 for (; formats_prop_i < unique_props_count; ++formats_prop_i) {
2199                     if (FormatPropsEq(&prop_map[formats_prop_i].props, &props)) break;
2200                 }
2201
2202                 if (formats_prop_i < unique_props_count) {
2203                     struct PropFormats *propFormats = &prop_map[formats_prop_i];
2204                     ++propFormats->format_count;
2205
2206                     if (propFormats->format_count > propFormats->format_reserve) {
2207                         propFormats->format_reserve *= 2;
2208                         propFormats->formats = realloc(propFormats->formats, sizeof(VkFormat) * propFormats->format_reserve);
2209                         if (!propFormats->formats) ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
2210                     }
2211
2212                     propFormats->formats[propFormats->format_count - 1] = fmt;
2213                 } else {
2214                     assert(formats_prop_i == unique_props_count);
2215                     ++unique_props_count;
2216
2217                     if (unique_props_count > unique_props_reserve) {
2218                         unique_props_reserve *= 2;
2219                         prop_map = realloc(prop_map, sizeof(struct PropFormats) * unique_props_reserve);
2220                         if (!prop_map) ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
2221                     }
2222
2223                     struct PropFormats *propFormats = &prop_map[formats_prop_i];
2224                     propFormats->props = props;
2225                     propFormats->format_count = 1;
2226                     propFormats->format_reserve = 20;
2227                     propFormats->formats = malloc(sizeof(VkFormat) * propFormats->format_reserve);
2228                     if (!propFormats->formats) ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
2229                     propFormats->formats[0] = fmt;
2230                 }
2231             }
2232         }
2233     }
2234
2235     for (uint32_t pi = 1; pi < unique_props_count; ++pi) {
2236         struct PropFormats *propFormats = &prop_map[pi];
2237
2238         for (uint32_t fi = 0; fi < propFormats->format_count; ++fi) {
2239             const VkFormat fmt = propFormats->formats[fi];
2240
2241             printf("\nFORMAT_%s", VkFormatString(fmt));
2242
2243             if (fi < propFormats->format_count - 1)
2244                 printf(",");
2245             else
2246                 printf(":");
2247         }
2248
2249         struct {
2250             const char *name;
2251             VkFlags flags;
2252         } features[3];
2253
2254         features[0].name = "linearTiling   FormatFeatureFlags";
2255         features[0].flags = propFormats->props.linearTilingFeatures;
2256         features[1].name = "optimalTiling  FormatFeatureFlags";
2257         features[1].flags = propFormats->props.optimalTilingFeatures;
2258         features[2].name = "bufferFeatures FormatFeatureFlags";
2259         features[2].flags = propFormats->props.bufferFeatures;
2260
2261         for (uint32_t i = 0; i < ARRAY_SIZE(features); ++i) {
2262             printf("\n\t%s:", features[i].name);
2263             if (features[i].flags == 0) {
2264                 printf("\n\t\tNone");
2265             } else {
2266                 printf(
2267                     "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
2268                     ((features[i].flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT) ? "\n\t\tVK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT"
2269                                                                                : ""),  // 0x0001
2270                     ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) ? "\n\t\tVK_FORMAT_FEATURE_STORAGE_IMAGE_BIT"
2271                                                                                : ""),  // 0x0002
2272                     ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT)
2273                          ? "\n\t\tVK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT"
2274                          : ""),  // 0x0004
2275                     ((features[i].flags & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT)
2276                          ? "\n\t\tVK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT"
2277                          : ""),  // 0x0008
2278                     ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT)
2279                          ? "\n\t\tVK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT"
2280                          : ""),  // 0x0010
2281                     ((features[i].flags & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT)
2282                          ? "\n\t\tVK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT"
2283                          : ""),  // 0x0020
2284                     ((features[i].flags & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) ? "\n\t\tVK_FORMAT_FEATURE_VERTEX_BUFFER_BIT"
2285                                                                                : ""),  // 0x0040
2286                     ((features[i].flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT) ? "\n\t\tVK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT"
2287                                                                                   : ""),  // 0x0080
2288                     ((features[i].flags & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT)
2289                          ? "\n\t\tVK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT"
2290                          : ""),  // 0x0100
2291                     ((features[i].flags & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
2292                          ? "\n\t\tVK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT"
2293                          : ""),                                                                                            // 0x0200
2294                     ((features[i].flags & VK_FORMAT_FEATURE_BLIT_SRC_BIT) ? "\n\t\tVK_FORMAT_FEATURE_BLIT_SRC_BIT" : ""),  // 0x0400
2295                     ((features[i].flags & VK_FORMAT_FEATURE_BLIT_DST_BIT) ? "\n\t\tVK_FORMAT_FEATURE_BLIT_DST_BIT" : ""),  // 0x0800
2296                     ((features[i].flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)
2297                          ? "\n\t\tVK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT"
2298                          : ""),  // 0x1000
2299                     ((features[i].flags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG)
2300                          ? "\n\t\tVK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG"
2301                          : ""),  // 0x2000
2302                     ((features[i].flags & VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR) ? "\n\t\tVK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR"
2303                                                                                   : ""),  // 0x4000
2304                     ((features[i].flags & VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR) ? "\n\t\tVK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR"
2305                                                                                   : ""));  // 0x8000
2306             }
2307
2308             printf("\n");
2309         }
2310     }
2311
2312     printf("\nUnsupported formats:");
2313     if (prop_map[0].format_count == 0) printf("\nNone");
2314     for (uint32_t fi = 0; fi < prop_map[0].format_count; ++fi) {
2315         const VkFormat fmt = prop_map[0].formats[fi];
2316
2317         printf("\nFORMAT_%s", VkFormatString(fmt));
2318     }
2319
2320     // cleanup
2321     for (uint32_t pi = 0; pi < unique_props_count; ++pi) free(prop_map[pi].formats);
2322     free(prop_map);
2323 }
2324
2325 static void AppDevDump(const struct AppGpu *gpu, FILE *out) {
2326     if (html_output) {
2327         fprintf(out, "\t\t\t\t\t<details><summary>Format Properties</summary>\n");
2328     } else if (human_readable_output) {
2329         printf("Format Properties:\n");
2330         printf("==================\n");
2331     }
2332     if (json_output) {
2333         printf(",\n");
2334         printf("\t\"ArrayOfVkFormatProperties\": [");
2335     }
2336
2337     if (human_readable_output) {
2338         FormatPropsShortenedDump(gpu);
2339     } else {
2340         bool first_in_list = true;  // Used for commas in json output
2341         for (uint32_t i = 0; i < ARRAY_SIZE(supported_format_ranges); ++i) {
2342             struct FormatRange format_range = supported_format_ranges[i];
2343             if (FormatRangeSupported(&format_range, gpu)) {
2344                 for (VkFormat fmt = format_range.first_format; fmt <= format_range.last_format; ++fmt) {
2345                     AppDevDumpFormatProps(gpu, fmt, &first_in_list, out);
2346                 }
2347             }
2348         }
2349     }
2350
2351     if (html_output) {
2352         fprintf(out, "\t\t\t\t\t</details>\n");
2353     }
2354     if (json_output) {
2355         printf("\n\t]");
2356     }
2357 }
2358
2359 #ifdef _WIN32
2360 #define PRINTF_SIZE_T_SPECIFIER "%Iu"
2361 #else
2362 #define PRINTF_SIZE_T_SPECIFIER "%zu"
2363 #endif
2364
2365 static void AppGpuDumpFeatures(const struct AppGpu *gpu, FILE *out) {
2366     VkPhysicalDeviceFeatures features;
2367
2368     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
2369                               gpu->inst->inst_extensions_count)) {
2370         const VkPhysicalDeviceFeatures *features2_const = &gpu->features2.features;
2371         features = *features2_const;
2372     } else {
2373         const VkPhysicalDeviceFeatures *features_const = &gpu->features;
2374         features = *features_const;
2375     }
2376
2377     if (html_output) {
2378         fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceFeatures</summary>\n");
2379         fprintf(out,
2380                 "\t\t\t\t\t\t<details><summary>robustBufferAccess                      = <div "
2381                 "class='val'>%u</div></summary></details>\n",
2382                 features.robustBufferAccess);
2383         fprintf(out,
2384                 "\t\t\t\t\t\t<details><summary>fullDrawIndexUint32                     = <div "
2385                 "class='val'>%u</div></summary></details>\n",
2386                 features.fullDrawIndexUint32);
2387         fprintf(out,
2388                 "\t\t\t\t\t\t<details><summary>imageCubeArray                          = <div "
2389                 "class='val'>%u</div></summary></details>\n",
2390                 features.imageCubeArray);
2391         fprintf(out,
2392                 "\t\t\t\t\t\t<details><summary>independentBlend                        = <div "
2393                 "class='val'>%u</div></summary></details>\n",
2394                 features.independentBlend);
2395         fprintf(out,
2396                 "\t\t\t\t\t\t<details><summary>geometryShader                          = <div "
2397                 "class='val'>%u</div></summary></details>\n",
2398                 features.geometryShader);
2399         fprintf(out,
2400                 "\t\t\t\t\t\t<details><summary>tessellationShader                      = <div "
2401                 "class='val'>%u</div></summary></details>\n",
2402                 features.tessellationShader);
2403         fprintf(out,
2404                 "\t\t\t\t\t\t<details><summary>sampleRateShading                       = <div "
2405                 "class='val'>%u</div></summary></details>\n",
2406                 features.sampleRateShading);
2407         fprintf(out,
2408                 "\t\t\t\t\t\t<details><summary>dualSrcBlend                            = <div "
2409                 "class='val'>%u</div></summary></details>\n",
2410                 features.dualSrcBlend);
2411         fprintf(out,
2412                 "\t\t\t\t\t\t<details><summary>logicOp                                 = <div "
2413                 "class='val'>%u</div></summary></details>\n",
2414                 features.logicOp);
2415         fprintf(out,
2416                 "\t\t\t\t\t\t<details><summary>multiDrawIndirect                       = <div "
2417                 "class='val'>%u</div></summary></details>\n",
2418                 features.multiDrawIndirect);
2419         fprintf(out,
2420                 "\t\t\t\t\t\t<details><summary>drawIndirectFirstInstance               = <div "
2421                 "class='val'>%u</div></summary></details>\n",
2422                 features.drawIndirectFirstInstance);
2423         fprintf(out,
2424                 "\t\t\t\t\t\t<details><summary>depthClamp                              = <div "
2425                 "class='val'>%u</div></summary></details>\n",
2426                 features.depthClamp);
2427         fprintf(out,
2428                 "\t\t\t\t\t\t<details><summary>depthBiasClamp                          = <div "
2429                 "class='val'>%u</div></summary></details>\n",
2430                 features.depthBiasClamp);
2431         fprintf(out,
2432                 "\t\t\t\t\t\t<details><summary>fillModeNonSolid                        = <div "
2433                 "class='val'>%u</div></summary></details>\n",
2434                 features.fillModeNonSolid);
2435         fprintf(out,
2436                 "\t\t\t\t\t\t<details><summary>depthBounds                             = <div "
2437                 "class='val'>%u</div></summary></details>\n",
2438                 features.depthBounds);
2439         fprintf(out,
2440                 "\t\t\t\t\t\t<details><summary>wideLines                               = <div "
2441                 "class='val'>%u</div></summary></details>\n",
2442                 features.wideLines);
2443         fprintf(out,
2444                 "\t\t\t\t\t\t<details><summary>largePoints                             = <div "
2445                 "class='val'>%u</div></summary></details>\n",
2446                 features.largePoints);
2447         fprintf(out,
2448                 "\t\t\t\t\t\t<details><summary>alphaToOne                              = <div "
2449                 "class='val'>%u</div></summary></details>\n",
2450                 features.alphaToOne);
2451         fprintf(out,
2452                 "\t\t\t\t\t\t<details><summary>multiViewport                           = <div "
2453                 "class='val'>%u</div></summary></details>\n",
2454                 features.multiViewport);
2455         fprintf(out,
2456                 "\t\t\t\t\t\t<details><summary>samplerAnisotropy                       = <div "
2457                 "class='val'>%u</div></summary></details>\n",
2458                 features.samplerAnisotropy);
2459         fprintf(out,
2460                 "\t\t\t\t\t\t<details><summary>textureCompressionETC2                  = <div "
2461                 "class='val'>%u</div></summary></details>\n",
2462                 features.textureCompressionETC2);
2463         fprintf(out,
2464                 "\t\t\t\t\t\t<details><summary>textureCompressionASTC_LDR              = <div "
2465                 "class='val'>%u</div></summary></details>\n",
2466                 features.textureCompressionASTC_LDR);
2467         fprintf(out,
2468                 "\t\t\t\t\t\t<details><summary>textureCompressionBC                    = <div "
2469                 "class='val'>%u</div></summary></details>\n",
2470                 features.textureCompressionBC);
2471         fprintf(out,
2472                 "\t\t\t\t\t\t<details><summary>occlusionQueryPrecise                   = <div "
2473                 "class='val'>%u</div></summary></details>\n",
2474                 features.occlusionQueryPrecise);
2475         fprintf(out,
2476                 "\t\t\t\t\t\t<details><summary>pipelineStatisticsQuery                 = <div "
2477                 "class='val'>%u</div></summary></details>\n",
2478                 features.pipelineStatisticsQuery);
2479         fprintf(out,
2480                 "\t\t\t\t\t\t<details><summary>vertexPipelineStoresAndAtomics          = <div "
2481                 "class='val'>%u</div></summary></details>\n",
2482                 features.vertexPipelineStoresAndAtomics);
2483         fprintf(out,
2484                 "\t\t\t\t\t\t<details><summary>fragmentStoresAndAtomics                = <div "
2485                 "class='val'>%u</div></summary></details>\n",
2486                 features.fragmentStoresAndAtomics);
2487         fprintf(out,
2488                 "\t\t\t\t\t\t<details><summary>shaderTessellationAndGeometryPointSize  = <div "
2489                 "class='val'>%u</div></summary></details>\n",
2490                 features.shaderTessellationAndGeometryPointSize);
2491         fprintf(out,
2492                 "\t\t\t\t\t\t<details><summary>shaderImageGatherExtended               = <div "
2493                 "class='val'>%u</div></summary></details>\n",
2494                 features.shaderImageGatherExtended);
2495         fprintf(out,
2496                 "\t\t\t\t\t\t<details><summary>shaderStorageImageExtendedFormats       = <div "
2497                 "class='val'>%u</div></summary></details>\n",
2498                 features.shaderStorageImageExtendedFormats);
2499         fprintf(out,
2500                 "\t\t\t\t\t\t<details><summary>shaderStorageImageMultisample           = <div "
2501                 "class='val'>%u</div></summary></details>\n",
2502                 features.shaderStorageImageMultisample);
2503         fprintf(out,
2504                 "\t\t\t\t\t\t<details><summary>shaderStorageImageReadWithoutFormat     = <div "
2505                 "class='val'>%u</div></summary></details>\n",
2506                 features.shaderStorageImageReadWithoutFormat);
2507         fprintf(out,
2508                 "\t\t\t\t\t\t<details><summary>shaderStorageImageWriteWithoutFormat    = <div "
2509                 "class='val'>%u</div></summary></details>\n",
2510                 features.shaderStorageImageWriteWithoutFormat);
2511         fprintf(out,
2512                 "\t\t\t\t\t\t<details><summary>shaderUniformBufferArrayDynamicIndexing = <div "
2513                 "class='val'>%u</div></summary></details>\n",
2514                 features.shaderUniformBufferArrayDynamicIndexing);
2515         fprintf(out,
2516                 "\t\t\t\t\t\t<details><summary>shaderSampledImageArrayDynamicIndexing  = <div "
2517                 "class='val'>%u</div></summary></details>\n",
2518                 features.shaderSampledImageArrayDynamicIndexing);
2519         fprintf(out,
2520                 "\t\t\t\t\t\t<details><summary>shaderStorageBufferArrayDynamicIndexing = <div "
2521                 "class='val'>%u</div></summary></details>\n",
2522                 features.shaderStorageBufferArrayDynamicIndexing);
2523         fprintf(out,
2524                 "\t\t\t\t\t\t<details><summary>shaderStorageImageArrayDynamicIndexing  = <div "
2525                 "class='val'>%u</div></summary></details>\n",
2526                 features.shaderStorageImageArrayDynamicIndexing);
2527         fprintf(out,
2528                 "\t\t\t\t\t\t<details><summary>shaderClipDistance                      = <div "
2529                 "class='val'>%u</div></summary></details>\n",
2530                 features.shaderClipDistance);
2531         fprintf(out,
2532                 "\t\t\t\t\t\t<details><summary>shaderCullDistance                      = <div "
2533                 "class='val'>%u</div></summary></details>\n",
2534                 features.shaderCullDistance);
2535         fprintf(out,
2536                 "\t\t\t\t\t\t<details><summary>shaderFloat64                           = <div "
2537                 "class='val'>%u</div></summary></details>\n",
2538                 features.shaderFloat64);
2539         fprintf(out,
2540                 "\t\t\t\t\t\t<details><summary>shaderInt64                             = <div "
2541                 "class='val'>%u</div></summary></details>\n",
2542                 features.shaderInt64);
2543         fprintf(out,
2544                 "\t\t\t\t\t\t<details><summary>shaderInt16                             = <div "
2545                 "class='val'>%u</div></summary></details>\n",
2546                 features.shaderInt16);
2547         fprintf(out,
2548                 "\t\t\t\t\t\t<details><summary>shaderResourceResidency                 = <div "
2549                 "class='val'>%u</div></summary></details>\n",
2550                 features.shaderResourceResidency);
2551         fprintf(out,
2552                 "\t\t\t\t\t\t<details><summary>shaderResourceMinLod                    = <div "
2553                 "class='val'>%u</div></summary></details>\n",
2554                 features.shaderResourceMinLod);
2555         fprintf(out,
2556                 "\t\t\t\t\t\t<details><summary>sparseBinding                           = <div "
2557                 "class='val'>%u</div></summary></details>\n",
2558                 features.sparseBinding);
2559         fprintf(out,
2560                 "\t\t\t\t\t\t<details><summary>sparseResidencyBuffer                   = <div "
2561                 "class='val'>%u</div></summary></details>\n",
2562                 features.sparseResidencyBuffer);
2563         fprintf(out,
2564                 "\t\t\t\t\t\t<details><summary>sparseResidencyImage2D                  = <div "
2565                 "class='val'>%u</div></summary></details>\n",
2566                 features.sparseResidencyImage2D);
2567         fprintf(out,
2568                 "\t\t\t\t\t\t<details><summary>sparseResidencyImage3D                  = <div "
2569                 "class='val'>%u</div></summary></details>\n",
2570                 features.sparseResidencyImage3D);
2571         fprintf(out,
2572                 "\t\t\t\t\t\t<details><summary>sparseResidency2Samples                 = <div "
2573                 "class='val'>%u</div></summary></details>\n",
2574                 features.sparseResidency2Samples);
2575         fprintf(out,
2576                 "\t\t\t\t\t\t<details><summary>sparseResidency4Samples                 = <div "
2577                 "class='val'>%u</div></summary></details>\n",
2578                 features.sparseResidency4Samples);
2579         fprintf(out,
2580                 "\t\t\t\t\t\t<details><summary>sparseResidency8Samples                 = <div "
2581                 "class='val'>%u</div></summary></details>\n",
2582                 features.sparseResidency8Samples);
2583         fprintf(out,
2584                 "\t\t\t\t\t\t<details><summary>sparseResidency16Samples                = <div "
2585                 "class='val'>%u</div></summary></details>\n",
2586                 features.sparseResidency16Samples);
2587         fprintf(out,
2588                 "\t\t\t\t\t\t<details><summary>sparseResidencyAliased                  = <div "
2589                 "class='val'>%u</div></summary></details>\n",
2590                 features.sparseResidencyAliased);
2591         fprintf(out,
2592                 "\t\t\t\t\t\t<details><summary>variableMultisampleRate                 = <div "
2593                 "class='val'>%u</div></summary></details>\n",
2594                 features.variableMultisampleRate);
2595         fprintf(out,
2596                 "\t\t\t\t\t\t<details><summary>inheritedQueries                        = <div "
2597                 "class='val'>%u</div></summary></details>\n",
2598                 features.inheritedQueries);
2599         fprintf(out, "\t\t\t\t\t</details>\n");
2600     } else if (human_readable_output) {
2601         printf("VkPhysicalDeviceFeatures:\n");
2602         printf("=========================\n");
2603         printf("\trobustBufferAccess                      = %u\n", features.robustBufferAccess);
2604         printf("\tfullDrawIndexUint32                     = %u\n", features.fullDrawIndexUint32);
2605         printf("\timageCubeArray                          = %u\n", features.imageCubeArray);
2606         printf("\tindependentBlend                        = %u\n", features.independentBlend);
2607         printf("\tgeometryShader                          = %u\n", features.geometryShader);
2608         printf("\ttessellationShader                      = %u\n", features.tessellationShader);
2609         printf("\tsampleRateShading                       = %u\n", features.sampleRateShading);
2610         printf("\tdualSrcBlend                            = %u\n", features.dualSrcBlend);
2611         printf("\tlogicOp                                 = %u\n", features.logicOp);
2612         printf("\tmultiDrawIndirect                       = %u\n", features.multiDrawIndirect);
2613         printf("\tdrawIndirectFirstInstance               = %u\n", features.drawIndirectFirstInstance);
2614         printf("\tdepthClamp                              = %u\n", features.depthClamp);
2615         printf("\tdepthBiasClamp                          = %u\n", features.depthBiasClamp);
2616         printf("\tfillModeNonSolid                        = %u\n", features.fillModeNonSolid);
2617         printf("\tdepthBounds                             = %u\n", features.depthBounds);
2618         printf("\twideLines                               = %u\n", features.wideLines);
2619         printf("\tlargePoints                             = %u\n", features.largePoints);
2620         printf("\talphaToOne                              = %u\n", features.alphaToOne);
2621         printf("\tmultiViewport                           = %u\n", features.multiViewport);
2622         printf("\tsamplerAnisotropy                       = %u\n", features.samplerAnisotropy);
2623         printf("\ttextureCompressionETC2                  = %u\n", features.textureCompressionETC2);
2624         printf("\ttextureCompressionASTC_LDR              = %u\n", features.textureCompressionASTC_LDR);
2625         printf("\ttextureCompressionBC                    = %u\n", features.textureCompressionBC);
2626         printf("\tocclusionQueryPrecise                   = %u\n", features.occlusionQueryPrecise);
2627         printf("\tpipelineStatisticsQuery                 = %u\n", features.pipelineStatisticsQuery);
2628         printf("\tvertexPipelineStoresAndAtomics          = %u\n", features.vertexPipelineStoresAndAtomics);
2629         printf("\tfragmentStoresAndAtomics                = %u\n", features.fragmentStoresAndAtomics);
2630         printf("\tshaderTessellationAndGeometryPointSize  = %u\n", features.shaderTessellationAndGeometryPointSize);
2631         printf("\tshaderImageGatherExtended               = %u\n", features.shaderImageGatherExtended);
2632         printf("\tshaderStorageImageExtendedFormats       = %u\n", features.shaderStorageImageExtendedFormats);
2633         printf("\tshaderStorageImageMultisample           = %u\n", features.shaderStorageImageMultisample);
2634         printf("\tshaderStorageImageReadWithoutFormat     = %u\n", features.shaderStorageImageReadWithoutFormat);
2635         printf("\tshaderStorageImageWriteWithoutFormat    = %u\n", features.shaderStorageImageWriteWithoutFormat);
2636         printf("\tshaderUniformBufferArrayDynamicIndexing = %u\n", features.shaderUniformBufferArrayDynamicIndexing);
2637         printf("\tshaderSampledImageArrayDynamicIndexing  = %u\n", features.shaderSampledImageArrayDynamicIndexing);
2638         printf("\tshaderStorageBufferArrayDynamicIndexing = %u\n", features.shaderStorageBufferArrayDynamicIndexing);
2639         printf("\tshaderStorageImageArrayDynamicIndexing  = %u\n", features.shaderStorageImageArrayDynamicIndexing);
2640         printf("\tshaderClipDistance                      = %u\n", features.shaderClipDistance);
2641         printf("\tshaderCullDistance                      = %u\n", features.shaderCullDistance);
2642         printf("\tshaderFloat64                           = %u\n", features.shaderFloat64);
2643         printf("\tshaderInt64                             = %u\n", features.shaderInt64);
2644         printf("\tshaderInt16                             = %u\n", features.shaderInt16);
2645         printf("\tshaderResourceResidency                 = %u\n", features.shaderResourceResidency);
2646         printf("\tshaderResourceMinLod                    = %u\n", features.shaderResourceMinLod);
2647         printf("\tsparseBinding                           = %u\n", features.sparseBinding);
2648         printf("\tsparseResidencyBuffer                   = %u\n", features.sparseResidencyBuffer);
2649         printf("\tsparseResidencyImage2D                  = %u\n", features.sparseResidencyImage2D);
2650         printf("\tsparseResidencyImage3D                  = %u\n", features.sparseResidencyImage3D);
2651         printf("\tsparseResidency2Samples                 = %u\n", features.sparseResidency2Samples);
2652         printf("\tsparseResidency4Samples                 = %u\n", features.sparseResidency4Samples);
2653         printf("\tsparseResidency8Samples                 = %u\n", features.sparseResidency8Samples);
2654         printf("\tsparseResidency16Samples                = %u\n", features.sparseResidency16Samples);
2655         printf("\tsparseResidencyAliased                  = %u\n", features.sparseResidencyAliased);
2656         printf("\tvariableMultisampleRate                 = %u\n", features.variableMultisampleRate);
2657         printf("\tinheritedQueries                        = %u\n", features.inheritedQueries);
2658     }
2659     if (json_output) {
2660         printf(",\n");
2661         printf("\t\"VkPhysicalDeviceFeatures\": {\n");
2662         printf("\t\t\"robustBufferAccess\": %u,\n", features.robustBufferAccess);
2663         printf("\t\t\"fullDrawIndexUint32\": %u,\n", features.fullDrawIndexUint32);
2664         printf("\t\t\"imageCubeArray\": %u,\n", features.imageCubeArray);
2665         printf("\t\t\"independentBlend\": %u,\n", features.independentBlend);
2666         printf("\t\t\"geometryShader\": %u,\n", features.geometryShader);
2667         printf("\t\t\"tessellationShader\": %u,\n", features.tessellationShader);
2668         printf("\t\t\"sampleRateShading\": %u,\n", features.sampleRateShading);
2669         printf("\t\t\"dualSrcBlend\": %u,\n", features.dualSrcBlend);
2670         printf("\t\t\"logicOp\": %u,\n", features.logicOp);
2671         printf("\t\t\"multiDrawIndirect\": %u,\n", features.multiDrawIndirect);
2672         printf("\t\t\"drawIndirectFirstInstance\": %u,\n", features.drawIndirectFirstInstance);
2673         printf("\t\t\"depthClamp\": %u,\n", features.depthClamp);
2674         printf("\t\t\"depthBiasClamp\": %u,\n", features.depthBiasClamp);
2675         printf("\t\t\"fillModeNonSolid\": %u,\n", features.fillModeNonSolid);
2676         printf("\t\t\"depthBounds\": %u,\n", features.depthBounds);
2677         printf("\t\t\"wideLines\": %u,\n", features.wideLines);
2678         printf("\t\t\"largePoints\": %u,\n", features.largePoints);
2679         printf("\t\t\"alphaToOne\": %u,\n", features.alphaToOne);
2680         printf("\t\t\"multiViewport\": %u,\n", features.multiViewport);
2681         printf("\t\t\"samplerAnisotropy\": %u,\n", features.samplerAnisotropy);
2682         printf("\t\t\"textureCompressionETC2\": %u,\n", features.textureCompressionETC2);
2683         printf("\t\t\"textureCompressionASTC_LDR\": %u,\n", features.textureCompressionASTC_LDR);
2684         printf("\t\t\"textureCompressionBC\": %u,\n", features.textureCompressionBC);
2685         printf("\t\t\"occlusionQueryPrecise\": %u,\n", features.occlusionQueryPrecise);
2686         printf("\t\t\"pipelineStatisticsQuery\": %u,\n", features.pipelineStatisticsQuery);
2687         printf("\t\t\"vertexPipelineStoresAndAtomics\": %u,\n", features.vertexPipelineStoresAndAtomics);
2688         printf("\t\t\"fragmentStoresAndAtomics\": %u,\n", features.fragmentStoresAndAtomics);
2689         printf("\t\t\"shaderTessellationAndGeometryPointSize\": %u,\n", features.shaderTessellationAndGeometryPointSize);
2690         printf("\t\t\"shaderImageGatherExtended\": %u,\n", features.shaderImageGatherExtended);
2691         printf("\t\t\"shaderStorageImageExtendedFormats\": %u,\n", features.shaderStorageImageExtendedFormats);
2692         printf("\t\t\"shaderStorageImageMultisample\": %u,\n", features.shaderStorageImageMultisample);
2693         printf("\t\t\"shaderStorageImageReadWithoutFormat\": %u,\n", features.shaderStorageImageReadWithoutFormat);
2694         printf("\t\t\"shaderStorageImageWriteWithoutFormat\": %u,\n", features.shaderStorageImageWriteWithoutFormat);
2695         printf("\t\t\"shaderUniformBufferArrayDynamicIndexing\": %u,\n", features.shaderUniformBufferArrayDynamicIndexing);
2696         printf("\t\t\"shaderSampledImageArrayDynamicIndexing\": %u,\n", features.shaderSampledImageArrayDynamicIndexing);
2697         printf("\t\t\"shaderStorageBufferArrayDynamicIndexing\": %u,\n", features.shaderStorageBufferArrayDynamicIndexing);
2698         printf("\t\t\"shaderStorageImageArrayDynamicIndexing\": %u,\n", features.shaderStorageImageArrayDynamicIndexing);
2699         printf("\t\t\"shaderClipDistance\": %u,\n", features.shaderClipDistance);
2700         printf("\t\t\"shaderCullDistance\": %u,\n", features.shaderCullDistance);
2701         printf("\t\t\"shaderFloat64\": %u,\n", features.shaderFloat64);
2702         printf("\t\t\"shaderInt64\": %u,\n", features.shaderInt64);
2703         printf("\t\t\"shaderInt16\": %u,\n", features.shaderInt16);
2704         printf("\t\t\"shaderResourceResidency\": %u,\n", features.shaderResourceResidency);
2705         printf("\t\t\"shaderResourceMinLod\": %u,\n", features.shaderResourceMinLod);
2706         printf("\t\t\"sparseBinding\": %u,\n", features.sparseBinding);
2707         printf("\t\t\"sparseResidencyBuffer\": %u,\n", features.sparseResidencyBuffer);
2708         printf("\t\t\"sparseResidencyImage2D\": %u,\n", features.sparseResidencyImage2D);
2709         printf("\t\t\"sparseResidencyImage3D\": %u,\n", features.sparseResidencyImage3D);
2710         printf("\t\t\"sparseResidency2Samples\": %u,\n", features.sparseResidency2Samples);
2711         printf("\t\t\"sparseResidency4Samples\": %u,\n", features.sparseResidency4Samples);
2712         printf("\t\t\"sparseResidency8Samples\": %u,\n", features.sparseResidency8Samples);
2713         printf("\t\t\"sparseResidency16Samples\": %u,\n", features.sparseResidency16Samples);
2714         printf("\t\t\"sparseResidencyAliased\": %u,\n", features.sparseResidencyAliased);
2715         printf("\t\t\"variableMultisampleRate\": %u,\n", features.variableMultisampleRate);
2716         printf("\t\t\"inheritedQueries\": %u\n", features.inheritedQueries);
2717         printf("\t}");
2718     }
2719
2720     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
2721                               gpu->inst->inst_extensions_count)) {
2722         void *place = gpu->features2.pNext;
2723         while (place) {
2724             struct VkStructureHeader *structure = (struct VkStructureHeader *)place;
2725             if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR &&
2726                 CheckPhysicalDeviceExtensionIncluded(VK_KHR_8BIT_STORAGE_EXTENSION_NAME, gpu->device_extensions,
2727                                                      gpu->device_extension_count)) {
2728                 VkPhysicalDevice8BitStorageFeaturesKHR *b8_store_features = (VkPhysicalDevice8BitStorageFeaturesKHR *)structure;
2729                 if (html_output) {
2730                     fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDevice8BitStorageFeatures</summary>\n");
2731                     fprintf(out,
2732                             "\t\t\t\t\t\t<details><summary>storageBuffer8BitAccess           = <div "
2733                             "class='val'>%u</div></summary></details>\n",
2734                             b8_store_features->storageBuffer8BitAccess);
2735                     fprintf(out,
2736                             "\t\t\t\t\t\t<details><summary>uniformAndStorageBuffer8BitAccess = <div "
2737                             "class='val'>%u</div></summary></details>\n",
2738                             b8_store_features->uniformAndStorageBuffer8BitAccess);
2739                     fprintf(out,
2740                             "\t\t\t\t\t\t<details><summary>storagePushConstant8              = <div "
2741                             "class='val'>%u</div></summary></details>\n",
2742                             b8_store_features->storagePushConstant8);
2743                     fprintf(out, "\t\t\t\t\t</details>\n");
2744                 } else if (human_readable_output) {
2745                     printf("\nVkPhysicalDevice8BitStorageFeatures:\n");
2746                     printf("=====================================\n");
2747                     printf("\tstorageBuffer8BitAccess           = %u\n", b8_store_features->storageBuffer8BitAccess);
2748                     printf("\tuniformAndStorageBuffer8BitAccess = %u\n", b8_store_features->uniformAndStorageBuffer8BitAccess);
2749                     printf("\tstoragePushConstant8              = %u\n", b8_store_features->storagePushConstant8);
2750                 }
2751             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR &&
2752                        CheckPhysicalDeviceExtensionIncluded(VK_KHR_16BIT_STORAGE_EXTENSION_NAME, gpu->device_extensions,
2753                                                             gpu->device_extension_count)) {
2754                 VkPhysicalDevice16BitStorageFeaturesKHR *b16_store_features = (VkPhysicalDevice16BitStorageFeaturesKHR *)structure;
2755                 if (html_output) {
2756                     fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDevice16BitStorageFeatures</summary>\n");
2757                     fprintf(out,
2758                             "\t\t\t\t\t\t<details><summary>storageBuffer16BitAccess           = <div "
2759                             "class='val'>%u</div></summary></details>\n",
2760                             b16_store_features->storageBuffer16BitAccess);
2761                     fprintf(out,
2762                             "\t\t\t\t\t\t<details><summary>uniformAndStorageBuffer16BitAccess = <div "
2763                             "class='val'>%u</div></summary></details>\n",
2764                             b16_store_features->uniformAndStorageBuffer16BitAccess);
2765                     fprintf(out,
2766                             "\t\t\t\t\t\t<details><summary>storagePushConstant16              = <div "
2767                             "class='val'>%u</div></summary></details>\n",
2768                             b16_store_features->storagePushConstant16);
2769                     fprintf(out,
2770                             "\t\t\t\t\t\t<details><summary>storageInputOutput16               = <div "
2771                             "class='val'>%u</div></summary></details>\n",
2772                             b16_store_features->storageInputOutput16);
2773                     fprintf(out, "\t\t\t\t\t</details>\n");
2774                 } else if (human_readable_output) {
2775                     printf("\nVkPhysicalDevice16BitStorageFeatures:\n");
2776                     printf("=====================================\n");
2777                     printf("\tstorageBuffer16BitAccess           = %u\n", b16_store_features->storageBuffer16BitAccess);
2778                     printf("\tuniformAndStorageBuffer16BitAccess = %u\n", b16_store_features->uniformAndStorageBuffer16BitAccess);
2779                     printf("\tstoragePushConstant16              = %u\n", b16_store_features->storagePushConstant16);
2780                     printf("\tstorageInputOutput16               = %u\n", b16_store_features->storageInputOutput16);
2781                 }
2782             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR &&
2783                        CheckPhysicalDeviceExtensionIncluded(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME, gpu->device_extensions,
2784                                                             gpu->device_extension_count)) {
2785                 VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR *sampler_ycbcr_features =
2786                     (VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR *)structure;
2787                 if (html_output) {
2788                     fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceSamplerYcbcrConversionFeatures</summary>\n");
2789                     fprintf(
2790                         out,
2791                         "\t\t\t\t\t\t<details><summary>samplerYcbcrConversion = <div class='val'>%u</div></summary></details>\n",
2792                         sampler_ycbcr_features->samplerYcbcrConversion);
2793                     fprintf(out, "\t\t\t\t\t</details>\n");
2794                 } else if (human_readable_output) {
2795                     printf("\nVkPhysicalDeviceSamplerYcbcrConversionFeatures:\n");
2796                     printf("===============================================\n");
2797                     printf("\tsamplerYcbcrConversion = %u\n", sampler_ycbcr_features->samplerYcbcrConversion);
2798                 }
2799             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR &&
2800                        CheckPhysicalDeviceExtensionIncluded(VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME, gpu->device_extensions,
2801                                                             gpu->device_extension_count)) {
2802                 VkPhysicalDeviceVariablePointerFeaturesKHR *var_pointer_features =
2803                     (VkPhysicalDeviceVariablePointerFeaturesKHR *)structure;
2804                 if (html_output) {
2805                     fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceVariablePointerFeatures</summary>\n");
2806                     fprintf(out,
2807                             "\t\t\t\t\t\t<details><summary>variablePointersStorageBuffer = <div "
2808                             "class='val'>%u</div></summary></details>\n",
2809                             var_pointer_features->variablePointersStorageBuffer);
2810                     fprintf(out,
2811                             "\t\t\t\t\t\t<details><summary>variablePointers              = <div "
2812                             "class='val'>%u</div></summary></details>\n",
2813                             var_pointer_features->variablePointers);
2814                     fprintf(out, "\t\t\t\t\t</details>\n");
2815                 } else if (human_readable_output) {
2816                     printf("\nVkPhysicalDeviceVariablePointerFeatures:\n");
2817                     printf("========================================\n");
2818                     printf("\tvariablePointersStorageBuffer = %u\n", var_pointer_features->variablePointersStorageBuffer);
2819                     printf("\tvariablePointers              = %u\n", var_pointer_features->variablePointers);
2820                 }
2821             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT &&
2822                        CheckPhysicalDeviceExtensionIncluded(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME, gpu->device_extensions,
2823                                                             gpu->device_extension_count)) {
2824                 VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT *blend_op_adv_features =
2825                     (VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT *)structure;
2826                 if (html_output) {
2827                     fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceBlendOperationAdvancedFeatures</summary>\n");
2828                     fprintf(out,
2829                             "\t\t\t\t\t\t<details><summary>advancedBlendCoherentOperations = <div "
2830                             "class='val'>%u</div></summary></details>\n",
2831                             blend_op_adv_features->advancedBlendCoherentOperations);
2832                     fprintf(out, "\t\t\t\t\t</details>\n");
2833                 } else if (human_readable_output) {
2834                     printf("\nVkPhysicalDeviceBlendOperationAdvancedFeatures:\n");
2835                     printf("===============================================\n");
2836                     printf("\tadvancedBlendCoherentOperations = %u\n", blend_op_adv_features->advancedBlendCoherentOperations);
2837                 }
2838             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR &&
2839                        CheckPhysicalDeviceExtensionIncluded(VK_KHR_MULTIVIEW_EXTENSION_NAME, gpu->device_extensions,
2840                                                             gpu->device_extension_count)) {
2841                 VkPhysicalDeviceMultiviewFeaturesKHR *multiview_features = (VkPhysicalDeviceMultiviewFeaturesKHR *)structure;
2842                 if (html_output) {
2843                     fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceMultiviewFeatures</summary>\n");
2844                     fprintf(out,
2845                             "\t\t\t\t\t\t<details><summary>multiview                   = <div "
2846                             "class='val'>%u</div></summary></details>\n",
2847                             multiview_features->multiview);
2848                     fprintf(out,
2849                             "\t\t\t\t\t\t<details><summary>multiviewGeometryShader     = <div "
2850                             "class='val'>%u</div></summary></details>\n",
2851                             multiview_features->multiviewGeometryShader);
2852                     fprintf(out,
2853                             "\t\t\t\t\t\t<details><summary>multiviewTessellationShader = <div "
2854                             "class='val'>%u</div></summary></details>\n",
2855                             multiview_features->multiviewTessellationShader);
2856                     fprintf(out, "\t\t\t\t\t</details>\n");
2857                 } else if (human_readable_output) {
2858                     printf("\nVkPhysicalDeviceMultiviewFeatures:\n");
2859                     printf("==================================\n");
2860                     printf("\tmultiview                   = %u\n", multiview_features->multiview);
2861                     printf("\tmultiviewGeometryShader     = %u\n", multiview_features->multiviewGeometryShader);
2862                     printf("\tmultiviewTessellationShader = %u\n", multiview_features->multiviewTessellationShader);
2863                 }
2864             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR &&
2865                        CheckPhysicalDeviceExtensionIncluded(VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME, gpu->device_extensions,
2866                                                             gpu->device_extension_count)) {
2867                 VkPhysicalDeviceFloat16Int8FeaturesKHR *float_int_features = (VkPhysicalDeviceFloat16Int8FeaturesKHR *)structure;
2868                 if (html_output) {
2869                     fprintf(out, "\n\t\t\t\t\t<details><summary>VkPhysicalDeviceFloat16Int8Features</summary>\n");
2870                     fprintf(out,
2871                             "\t\t\t\t\t\t<details><summary>shaderFloat16 = <div class='val'>%" PRIuLEAST32
2872                             "</div></summary></details>\n",
2873                             float_int_features->shaderFloat16);
2874                     fprintf(out,
2875                             "\t\t\t\t\t\t<details><summary>shaderInt8    = <div class='val'>%" PRIuLEAST32
2876                             "</div></summary></details>\n",
2877                             float_int_features->shaderInt8);
2878                     fprintf(out, "\t\t\t\t\t</details>\n");
2879                 } else if (human_readable_output) {
2880                     printf("\nVkPhysicalDeviceFloat16Int8Features:\n");
2881                     printf("====================================\n");
2882                     printf("\tshaderFloat16 = %" PRIuLEAST32 "\n", float_int_features->shaderFloat16);
2883                     printf("\tshaderInt8    = %" PRIuLEAST32 "\n", float_int_features->shaderInt8);
2884                 }
2885             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR &&
2886                        CheckPhysicalDeviceExtensionIncluded(VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME, gpu->device_extensions,
2887                                                             gpu->device_extension_count)) {
2888                 VkPhysicalDeviceShaderAtomicInt64FeaturesKHR *shader_atomic_int64_features =
2889                     (VkPhysicalDeviceShaderAtomicInt64FeaturesKHR *)structure;
2890                 if (html_output) {
2891                     fprintf(out, "\n\t\t\t\t\t<details><summary>VkPhysicalDeviceShaderAtomicInt64Features</summary>\n");
2892                     fprintf(out,
2893                             "\t\t\t\t\t\t<details><summary>shaderBufferInt64Atomics = <div class='val'>%" PRIuLEAST32
2894                             "</div></summary></details>\n",
2895                             shader_atomic_int64_features->shaderBufferInt64Atomics);
2896                     fprintf(out,
2897                             "\t\t\t\t\t\t<details><summary>shaderSharedInt64Atomics = <div class='val'>%" PRIuLEAST32
2898                             "</div></summary></details>\n",
2899                             shader_atomic_int64_features->shaderSharedInt64Atomics);
2900                     fprintf(out, "\t\t\t\t\t</details>\n");
2901                 } else if (human_readable_output) {
2902                     printf("\nVkPhysicalDeviceShaderAtomicInt64Features:\n");
2903                     printf("==========================================\n");
2904                     printf("\tshaderBufferInt64Atomics = %" PRIuLEAST32 "\n",
2905                            shader_atomic_int64_features->shaderBufferInt64Atomics);
2906                     printf("\tshaderSharedInt64Atomics = %" PRIuLEAST32 "\n",
2907                            shader_atomic_int64_features->shaderSharedInt64Atomics);
2908                 }
2909             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT &&
2910                        CheckPhysicalDeviceExtensionIncluded(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, gpu->device_extensions,
2911                                                             gpu->device_extension_count)) {
2912                 VkPhysicalDeviceTransformFeedbackFeaturesEXT *transform_feedback_features =
2913                     (VkPhysicalDeviceTransformFeedbackFeaturesEXT *)structure;
2914                 if (html_output) {
2915                     fprintf(out, "\n\t\t\t\t\t<details><summary>VkPhysicalDeviceTransformFeedbackFeatures</summary>\n");
2916                     fprintf(out,
2917                             "\t\t\t\t\t\t<details><summary>transformFeedback = <div class='val'>%" PRIuLEAST32
2918                             "</div></summary></details>\n",
2919                             transform_feedback_features->transformFeedback);
2920                     fprintf(out,
2921                             "\t\t\t\t\t\t<details><summary>geometryStreams   = <div class='val'>%" PRIuLEAST32
2922                             "</div></summary></details>\n",
2923                             transform_feedback_features->geometryStreams);
2924                     fprintf(out, "\t\t\t\t\t</details>\n");
2925                 } else if (human_readable_output) {
2926                     printf("\nVkPhysicalDeviceTransformFeedbackFeatures:\n");
2927                     printf("==========================================\n");
2928                     printf("\ttransformFeedback = %" PRIuLEAST32 "\n", transform_feedback_features->transformFeedback);
2929                     printf("\tgeometryStreams   = %" PRIuLEAST32 "\n", transform_feedback_features->geometryStreams);
2930                 }
2931             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT &&
2932                        CheckPhysicalDeviceExtensionIncluded(VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME, gpu->device_extensions,
2933                                                             gpu->device_extension_count)) {
2934                 VkPhysicalDeviceScalarBlockLayoutFeaturesEXT *scalar_block_layout_features =
2935                     (VkPhysicalDeviceScalarBlockLayoutFeaturesEXT *)structure;
2936                 if (html_output) {
2937                     fprintf(out, "\n\t\t\t\t\t<details><summary>VkPhysicalDeviceScalarBlockLayoutFeatures</summary>\n");
2938                     fprintf(out,
2939                             "\t\t\t\t\t\t<details><summary>scalarBlockLayout = <div class='val'>%" PRIuLEAST32
2940                             "</div></summary></details>\n",
2941                             scalar_block_layout_features->scalarBlockLayout);
2942                     fprintf(out, "\t\t\t\t\t</details>\n");
2943                 } else if (human_readable_output) {
2944                     printf("\nVkPhysicalDeviceScalarBlockLayoutFeatures:\n");
2945                     printf("==========================================\n");
2946                     printf("\tscalarBlockLayout = %" PRIuLEAST32 "\n", scalar_block_layout_features->scalarBlockLayout);
2947                 }
2948             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT &&
2949                        CheckPhysicalDeviceExtensionIncluded(VK_EXT_FRAGMENT_DENSITY_MAP_EXTENSION_NAME, gpu->device_extensions,
2950                                                             gpu->device_extension_count)) {
2951                 VkPhysicalDeviceFragmentDensityMapFeaturesEXT *fragment_density_map_features =
2952                     (VkPhysicalDeviceFragmentDensityMapFeaturesEXT *)structure;
2953                 if (html_output) {
2954                     fprintf(out, "\n\t\t\t\t\t<details><summary>VkPhysicalDeviceFragmentDensityMapFeatures</summary>\n");
2955                     fprintf(out,
2956                             "\t\t\t\t\t\t<details><summary>fragmentDensityMap                    = <div class='val'>%" PRIuLEAST32
2957                             "</div></summary></details>\n",
2958                             fragment_density_map_features->fragmentDensityMap);
2959                     fprintf(out,
2960                             "\t\t\t\t\t\t<details><summary>fragmentDensityMapDynamic             = <div class='val'>%" PRIuLEAST32
2961                             "</div></summary></details>\n",
2962                             fragment_density_map_features->fragmentDensityMapDynamic);
2963                     fprintf(out,
2964                             "\t\t\t\t\t\t<details><summary>fragmentDensityMapNonSubsampledImages = <div class='val'>%" PRIuLEAST32
2965                             "</div></summary></details>\n",
2966                             fragment_density_map_features->fragmentDensityMapNonSubsampledImages);
2967                     fprintf(out, "\t\t\t\t\t</details>\n");
2968                 } else if (human_readable_output) {
2969                     printf("\nVkPhysicalDeviceFragmentDensityMapFeatures:\n");
2970                     printf("==========================================\n");
2971                     printf("\tfragmentDensityMap                    = %" PRIuLEAST32 "\n",
2972                            fragment_density_map_features->fragmentDensityMap);
2973                     printf("\tfragmentDensityMapDynamic             = %" PRIuLEAST32 "\n",
2974                            fragment_density_map_features->fragmentDensityMapDynamic);
2975                     printf("\tfragmentDensityMapNonSubsampledImages = %" PRIuLEAST32 "\n",
2976                            fragment_density_map_features->fragmentDensityMapNonSubsampledImages);
2977                 }
2978             }
2979             place = structure->pNext;
2980         }
2981     }
2982 }
2983
2984 static void AppDumpSparseProps(const VkPhysicalDeviceSparseProperties *sparse_props, FILE *out) {
2985     if (html_output) {
2986         fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceSparseProperties</summary>\n");
2987         fprintf(out,
2988                 "\t\t\t\t\t\t<details><summary>residencyStandard2DBlockShape            = <div "
2989                 "class='val'>%u</div></summary></details>\n",
2990                 sparse_props->residencyStandard2DBlockShape);
2991         fprintf(out,
2992                 "\t\t\t\t\t\t<details><summary>residencyStandard2DMultisampleBlockShape = <div "
2993                 "class='val'>%u</div></summary></details>\n",
2994                 sparse_props->residencyStandard2DMultisampleBlockShape);
2995         fprintf(out,
2996                 "\t\t\t\t\t\t<details><summary>residencyStandard3DBlockShape            = <div "
2997                 "class='val'>%u</div></summary></details>\n",
2998                 sparse_props->residencyStandard3DBlockShape);
2999         fprintf(out,
3000                 "\t\t\t\t\t\t<details><summary>residencyAlignedMipSize                  = <div "
3001                 "class='val'>%u</div></summary></details>\n",
3002                 sparse_props->residencyAlignedMipSize);
3003         fprintf(out,
3004                 "\t\t\t\t\t\t<details><summary>residencyNonResidentStrict               = <div "
3005                 "class='val'>%u</div></summary></details>\n",
3006                 sparse_props->residencyNonResidentStrict);
3007         fprintf(out, "\t\t\t\t\t</details>\n");
3008     } else if (human_readable_output) {
3009         printf("\tVkPhysicalDeviceSparseProperties:\n");
3010         printf("\t---------------------------------\n");
3011         printf("\t\tresidencyStandard2DBlockShape            = %u\n", sparse_props->residencyStandard2DBlockShape);
3012         printf("\t\tresidencyStandard2DMultisampleBlockShape = %u\n", sparse_props->residencyStandard2DMultisampleBlockShape);
3013         printf("\t\tresidencyStandard3DBlockShape            = %u\n", sparse_props->residencyStandard3DBlockShape);
3014         printf("\t\tresidencyAlignedMipSize                  = %u\n", sparse_props->residencyAlignedMipSize);
3015         printf("\t\tresidencyNonResidentStrict               = %u\n", sparse_props->residencyNonResidentStrict);
3016     }
3017     if (json_output) {
3018         printf(",\n");
3019         printf("\t\t\"sparseProperties\": {\n");
3020         printf("\t\t\t\"residencyStandard2DBlockShape\": %u,\n", sparse_props->residencyStandard2DBlockShape);
3021         printf("\t\t\t\"residencyStandard2DMultisampleBlockShape\": %u,\n", sparse_props->residencyStandard2DMultisampleBlockShape);
3022         printf("\t\t\t\"residencyStandard3DBlockShape\": %u,\n", sparse_props->residencyStandard3DBlockShape);
3023         printf("\t\t\t\"residencyAlignedMipSize\": %u,\n", sparse_props->residencyAlignedMipSize);
3024         printf("\t\t\t\"residencyNonResidentStrict\": %u\n", sparse_props->residencyNonResidentStrict);
3025         printf("\t\t}");
3026     }
3027 }
3028
3029 static void AppDumpLimits(const VkPhysicalDeviceLimits *limits, FILE *out) {
3030     if (html_output) {
3031         fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceLimits</summary>\n");
3032         fprintf(out,
3033                 "\t\t\t\t\t\t<details><summary>maxImageDimension1D                     = <div "
3034                 "class='val'>%u</div></summary></details>\n",
3035                 limits->maxImageDimension1D);
3036         fprintf(out,
3037                 "\t\t\t\t\t\t<details><summary>maxImageDimension2D                     = <div "
3038                 "class='val'>%u</div></summary></details>\n",
3039                 limits->maxImageDimension2D);
3040         fprintf(out,
3041                 "\t\t\t\t\t\t<details><summary>maxImageDimension3D                     = <div "
3042                 "class='val'>%u</div></summary></details>\n",
3043                 limits->maxImageDimension3D);
3044         fprintf(out,
3045                 "\t\t\t\t\t\t<details><summary>maxImageDimensionCube                   = <div "
3046                 "class='val'>%u</div></summary></details>\n",
3047                 limits->maxImageDimensionCube);
3048         fprintf(out,
3049                 "\t\t\t\t\t\t<details><summary>maxImageArrayLayers                     = <div "
3050                 "class='val'>%u</div></summary></details>\n",
3051                 limits->maxImageArrayLayers);
3052         fprintf(out,
3053                 "\t\t\t\t\t\t<details><summary>maxTexelBufferElements                  = <div class='val'>0x%" PRIxLEAST32
3054                 "</div></summary></details>\n",
3055                 limits->maxTexelBufferElements);
3056         fprintf(out,
3057                 "\t\t\t\t\t\t<details><summary>maxUniformBufferRange                   = <div class='val'>0x%" PRIxLEAST32
3058                 "</div></summary></details>\n",
3059                 limits->maxUniformBufferRange);
3060         fprintf(out,
3061                 "\t\t\t\t\t\t<details><summary>maxStorageBufferRange                   = <div class='val'>0x%" PRIxLEAST32
3062                 "</div></summary></details>\n",
3063                 limits->maxStorageBufferRange);
3064         fprintf(out,
3065                 "\t\t\t\t\t\t<details><summary>maxPushConstantsSize                    = <div "
3066                 "class='val'>%u</div></summary></details>\n",
3067                 limits->maxPushConstantsSize);
3068         fprintf(out,
3069                 "\t\t\t\t\t\t<details><summary>maxMemoryAllocationCount                = <div "
3070                 "class='val'>%u</div></summary></details>\n",
3071                 limits->maxMemoryAllocationCount);
3072         fprintf(out,
3073                 "\t\t\t\t\t\t<details><summary>maxSamplerAllocationCount               = <div "
3074                 "class='val'>%u</div></summary></details>\n",
3075                 limits->maxSamplerAllocationCount);
3076         fprintf(out,
3077                 "\t\t\t\t\t\t<details><summary>bufferImageGranularity                  = <div class='val'>0x%" PRIxLEAST64
3078                 "</div></summary></details>\n",
3079                 limits->bufferImageGranularity);
3080         fprintf(out,
3081                 "\t\t\t\t\t\t<details><summary>sparseAddressSpaceSize                  = <div class='val'>0x%" PRIxLEAST64
3082                 "</div></summary></details>\n",
3083                 limits->sparseAddressSpaceSize);
3084         fprintf(out,
3085                 "\t\t\t\t\t\t<details><summary>maxBoundDescriptorSets                  = <div "
3086                 "class='val'>%u</div></summary></details>\n",
3087                 limits->maxBoundDescriptorSets);
3088         fprintf(out,
3089                 "\t\t\t\t\t\t<details><summary>maxPerStageDescriptorSamplers           = <div "
3090                 "class='val'>%u</div></summary></details>\n",
3091                 limits->maxPerStageDescriptorSamplers);
3092         fprintf(out,
3093                 "\t\t\t\t\t\t<details><summary>maxPerStageDescriptorUniformBuffers     = <div "
3094                 "class='val'>%u</div></summary></details>\n",
3095                 limits->maxPerStageDescriptorUniformBuffers);
3096         fprintf(out,
3097                 "\t\t\t\t\t\t<details><summary>maxPerStageDescriptorStorageBuffers     = <div "
3098                 "class='val'>%u</div></summary></details>\n",
3099                 limits->maxPerStageDescriptorStorageBuffers);
3100         fprintf(out,
3101                 "\t\t\t\t\t\t<details><summary>maxPerStageDescriptorSampledImages      = <div "
3102                 "class='val'>%u</div></summary></details>\n",
3103                 limits->maxPerStageDescriptorSampledImages);
3104         fprintf(out,
3105                 "\t\t\t\t\t\t<details><summary>maxPerStageDescriptorStorageImages      = <div "
3106                 "class='val'>%u</div></summary></details>\n",
3107                 limits->maxPerStageDescriptorStorageImages);
3108         fprintf(out,
3109                 "\t\t\t\t\t\t<details><summary>maxPerStageDescriptorInputAttachments   = <div "
3110                 "class='val'>%u</div></summary></details>\n",
3111                 limits->maxPerStageDescriptorInputAttachments);
3112         fprintf(out,
3113                 "\t\t\t\t\t\t<details><summary>maxPerStageResources                    = <div "
3114                 "class='val'>%u</div></summary></details>\n",
3115                 limits->maxPerStageResources);
3116         fprintf(out,
3117                 "\t\t\t\t\t\t<details><summary>maxDescriptorSetSamplers                = <div "
3118                 "class='val'>%u</div></summary></details>\n",
3119                 limits->maxDescriptorSetSamplers);
3120         fprintf(out,
3121                 "\t\t\t\t\t\t<details><summary>maxDescriptorSetUniformBuffers          = <div "
3122                 "class='val'>%u</div></summary></details>\n",
3123                 limits->maxDescriptorSetUniformBuffers);
3124         fprintf(out,
3125                 "\t\t\t\t\t\t<details><summary>maxDescriptorSetUniformBuffersDynamic   = <div "
3126                 "class='val'>%u</div></summary></details>\n",
3127                 limits->maxDescriptorSetUniformBuffersDynamic);
3128         fprintf(out,
3129                 "\t\t\t\t\t\t<details><summary>maxDescriptorSetStorageBuffers          = <div "
3130                 "class='val'>%u</div></summary></details>\n",
3131                 limits->maxDescriptorSetStorageBuffers);
3132         fprintf(out,
3133                 "\t\t\t\t\t\t<details><summary>maxDescriptorSetStorageBuffersDynamic   = <div "
3134                 "class='val'>%u</div></summary></details>\n",
3135                 limits->maxDescriptorSetStorageBuffersDynamic);
3136         fprintf(out,
3137                 "\t\t\t\t\t\t<details><summary>maxDescriptorSetSampledImages           = <div "
3138                 "class='val'>%u</div></summary></details>\n",
3139                 limits->maxDescriptorSetSampledImages);
3140         fprintf(out,
3141                 "\t\t\t\t\t\t<details><summary>maxDescriptorSetStorageImages           = <div "
3142                 "class='val'>%u</div></summary></details>\n",
3143                 limits->maxDescriptorSetStorageImages);
3144         fprintf(out,
3145                 "\t\t\t\t\t\t<details><summary>maxDescriptorSetInputAttachments        = <div "
3146                 "class='val'>%u</div></summary></details>\n",
3147                 limits->maxDescriptorSetInputAttachments);
3148         fprintf(out,
3149                 "\t\t\t\t\t\t<details><summary>maxVertexInputAttributes                = <div "
3150                 "class='val'>%u</div></summary></details>\n",
3151                 limits->maxVertexInputAttributes);
3152         fprintf(out,
3153                 "\t\t\t\t\t\t<details><summary>maxVertexInputBindings                  = <div "
3154                 "class='val'>%u</div></summary></details>\n",
3155                 limits->maxVertexInputBindings);
3156         fprintf(out,
3157                 "\t\t\t\t\t\t<details><summary>maxVertexInputAttributeOffset           = <div class='val'>0x%" PRIxLEAST32
3158                 "</div></summary></details>\n",
3159                 limits->maxVertexInputAttributeOffset);
3160         fprintf(out,
3161                 "\t\t\t\t\t\t<details><summary>maxVertexInputBindingStride             = <div class='val'>0x%" PRIxLEAST32
3162                 "</div></summary></details>\n",
3163                 limits->maxVertexInputBindingStride);
3164         fprintf(out,
3165                 "\t\t\t\t\t\t<details><summary>maxVertexOutputComponents               = <div "
3166                 "class='val'>%u</div></summary></details>\n",
3167                 limits->maxVertexOutputComponents);
3168         fprintf(out,
3169                 "\t\t\t\t\t\t<details><summary>maxTessellationGenerationLevel          = <div "
3170                 "class='val'>%u</div></summary></details>\n",
3171                 limits->maxTessellationGenerationLevel);
3172         fprintf(out,
3173                 "\t\t\t\t\t\t<details><summary>maxTessellationPatchSize                        = <div "
3174                 "class='val'>%u</div></summary></details>\n",
3175                 limits->maxTessellationPatchSize);
3176         fprintf(out,
3177                 "\t\t\t\t\t\t<details><summary>maxTessellationControlPerVertexInputComponents  = <div "
3178                 "class='val'>%u</div></summary></details>\n",
3179                 limits->maxTessellationControlPerVertexInputComponents);
3180         fprintf(out,
3181                 "\t\t\t\t\t\t<details><summary>maxTessellationControlPerVertexOutputComponents = <div "
3182                 "class='val'>%u</div></summary></details>\n",
3183                 limits->maxTessellationControlPerVertexOutputComponents);
3184         fprintf(out,
3185                 "\t\t\t\t\t\t<details><summary>maxTessellationControlPerPatchOutputComponents  = <div "
3186                 "class='val'>%u</div></summary></details>\n",
3187                 limits->maxTessellationControlPerPatchOutputComponents);
3188         fprintf(out,
3189                 "\t\t\t\t\t\t<details><summary>maxTessellationControlTotalOutputComponents     = <div "
3190                 "class='val'>%u</div></summary></details>\n",
3191                 limits->maxTessellationControlTotalOutputComponents);
3192         fprintf(out,
3193                 "\t\t\t\t\t\t<details><summary>maxTessellationEvaluationInputComponents        = <div "
3194                 "class='val'>%u</div></summary></details>\n",
3195                 limits->maxTessellationEvaluationInputComponents);
3196         fprintf(out,
3197                 "\t\t\t\t\t\t<details><summary>maxTessellationEvaluationOutputComponents       = <div "
3198                 "class='val'>%u</div></summary></details>\n",
3199                 limits->maxTessellationEvaluationOutputComponents);
3200         fprintf(out,
3201                 "\t\t\t\t\t\t<details><summary>maxGeometryShaderInvocations            = <div "
3202                 "class='val'>%u</div></summary></details>\n",
3203                 limits->maxGeometryShaderInvocations);
3204         fprintf(out,
3205                 "\t\t\t\t\t\t<details><summary>maxGeometryInputComponents              = <div "
3206                 "class='val'>%u</div></summary></details>\n",
3207                 limits->maxGeometryInputComponents);
3208         fprintf(out,
3209                 "\t\t\t\t\t\t<details><summary>maxGeometryOutputComponents             = <div "
3210                 "class='val'>%u</div></summary></details>\n",
3211                 limits->maxGeometryOutputComponents);
3212         fprintf(out,
3213                 "\t\t\t\t\t\t<details><summary>maxGeometryOutputVertices               = <div "
3214                 "class='val'>%u</div></summary></details>\n",
3215                 limits->maxGeometryOutputVertices);
3216         fprintf(out,
3217                 "\t\t\t\t\t\t<details><summary>maxGeometryTotalOutputComponents        = <div "
3218                 "class='val'>%u</div></summary></details>\n",
3219                 limits->maxGeometryTotalOutputComponents);
3220         fprintf(out,
3221                 "\t\t\t\t\t\t<details><summary>maxFragmentInputComponents              = <div "
3222                 "class='val'>%u</div></summary></details>\n",
3223                 limits->maxFragmentInputComponents);
3224         fprintf(out,
3225                 "\t\t\t\t\t\t<details><summary>maxFragmentOutputAttachments            = <div "
3226                 "class='val'>%u</div></summary></details>\n",
3227                 limits->maxFragmentOutputAttachments);
3228         fprintf(out,
3229                 "\t\t\t\t\t\t<details><summary>maxFragmentDualSrcAttachments           = <div "
3230                 "class='val'>%u</div></summary></details>\n",
3231                 limits->maxFragmentDualSrcAttachments);
3232         fprintf(out,
3233                 "\t\t\t\t\t\t<details><summary>maxFragmentCombinedOutputResources      = <div "
3234                 "class='val'>%u</div></summary></details>\n",
3235                 limits->maxFragmentCombinedOutputResources);
3236         fprintf(out,
3237                 "\t\t\t\t\t\t<details><summary>maxComputeSharedMemorySize              = <div class='val'>0x%" PRIxLEAST32
3238                 "</div></summary></details>\n",
3239                 limits->maxComputeSharedMemorySize);
3240         fprintf(out,
3241                 "\t\t\t\t\t\t<details><summary>maxComputeWorkGroupCount[0]             = <div "
3242                 "class='val'>%u</div></summary></details>\n",
3243                 limits->maxComputeWorkGroupCount[0]);
3244         fprintf(out,
3245                 "\t\t\t\t\t\t<details><summary>maxComputeWorkGroupCount[1]             = <div "
3246                 "class='val'>%u</div></summary></details>\n",
3247                 limits->maxComputeWorkGroupCount[1]);
3248         fprintf(out,
3249                 "\t\t\t\t\t\t<details><summary>maxComputeWorkGroupCount[2]             = <div "
3250                 "class='val'>%u</div></summary></details>\n",
3251                 limits->maxComputeWorkGroupCount[2]);
3252         fprintf(out,
3253                 "\t\t\t\t\t\t<details><summary>maxComputeWorkGroupInvocations          = <div "
3254                 "class='val'>%u</div></summary></details>\n",
3255                 limits->maxComputeWorkGroupInvocations);
3256         fprintf(out,
3257                 "\t\t\t\t\t\t<details><summary>maxComputeWorkGroupSize[0]              = <div "
3258                 "class='val'>%u</div></summary></details>\n",
3259                 limits->maxComputeWorkGroupSize[0]);
3260         fprintf(out,
3261                 "\t\t\t\t\t\t<details><summary>maxComputeWorkGroupSize[1]              = <div "
3262                 "class='val'>%u</div></summary></details>\n",
3263                 limits->maxComputeWorkGroupSize[1]);
3264         fprintf(out,
3265                 "\t\t\t\t\t\t<details><summary>maxComputeWorkGroupSize[2]              = <div "
3266                 "class='val'>%u</div></summary></details>\n",
3267                 limits->maxComputeWorkGroupSize[2]);
3268         fprintf(out,
3269                 "\t\t\t\t\t\t<details><summary>subPixelPrecisionBits                   = <div "
3270                 "class='val'>%u</div></summary></details>\n",
3271                 limits->subPixelPrecisionBits);
3272         fprintf(out,
3273                 "\t\t\t\t\t\t<details><summary>subTexelPrecisionBits                   = <div "
3274                 "class='val'>%u</div></summary></details>\n",
3275                 limits->subTexelPrecisionBits);
3276         fprintf(out,
3277                 "\t\t\t\t\t\t<details><summary>mipmapPrecisionBits                     = <div "
3278                 "class='val'>%u</div></summary></details>\n",
3279                 limits->mipmapPrecisionBits);
3280         fprintf(out,
3281                 "\t\t\t\t\t\t<details><summary>maxDrawIndexedIndexValue                = <div "
3282                 "class='val'>%u</div></summary></details>\n",
3283                 limits->maxDrawIndexedIndexValue);
3284         fprintf(out,
3285                 "\t\t\t\t\t\t<details><summary>maxDrawIndirectCount                    = <div "
3286                 "class='val'>%u</div></summary></details>\n",
3287                 limits->maxDrawIndirectCount);
3288         fprintf(out,
3289                 "\t\t\t\t\t\t<details><summary>maxSamplerLodBias                       = <div "
3290                 "class='val'>%f</div></summary></details>\n",
3291                 limits->maxSamplerLodBias);
3292         fprintf(out,
3293                 "\t\t\t\t\t\t<details><summary>maxSamplerAnisotropy                    = <div "
3294                 "class='val'>%f</div></summary></details>\n",
3295                 limits->maxSamplerAnisotropy);
3296         fprintf(out,
3297                 "\t\t\t\t\t\t<details><summary>maxViewports                            = <div "
3298                 "class='val'>%u</div></summary></details>\n",
3299                 limits->maxViewports);
3300         fprintf(out,
3301                 "\t\t\t\t\t\t<details><summary>maxViewportDimensions[0]                = <div "
3302                 "class='val'>%u</div></summary></details>\n",
3303                 limits->maxViewportDimensions[0]);
3304         fprintf(out,
3305                 "\t\t\t\t\t\t<details><summary>maxViewportDimensions[1]                = <div "
3306                 "class='val'>%u</div></summary></details>\n",
3307                 limits->maxViewportDimensions[1]);
3308         fprintf(out,
3309                 "\t\t\t\t\t\t<details><summary>viewportBoundsRange[0]                  = <div "
3310                 "class='val'>%13f</div></summary></details>\n",
3311                 limits->viewportBoundsRange[0]);
3312         fprintf(out,
3313                 "\t\t\t\t\t\t<details><summary>viewportBoundsRange[1]                  = <div "
3314                 "class='val'>%13f</div></summary></details>\n",
3315                 limits->viewportBoundsRange[1]);
3316         fprintf(out,
3317                 "\t\t\t\t\t\t<details><summary>viewportSubPixelBits                    = <div "
3318                 "class='val'>%u</div></summary></details>\n",
3319                 limits->viewportSubPixelBits);
3320         fprintf(out,
3321                 "\t\t\t\t\t\t<details><summary>minMemoryMapAlignment                   = <div class='val'>" PRINTF_SIZE_T_SPECIFIER
3322                 "</div></summary></details>\n",
3323                 limits->minMemoryMapAlignment);
3324         fprintf(out,
3325                 "\t\t\t\t\t\t<details><summary>minTexelBufferOffsetAlignment           = <div class='val'>0x%" PRIxLEAST64
3326                 "</div></summary></details>\n",
3327                 limits->minTexelBufferOffsetAlignment);
3328         fprintf(out,
3329                 "\t\t\t\t\t\t<details><summary>minUniformBufferOffsetAlignment         = <div class='val'>0x%" PRIxLEAST64
3330                 "</div></summary></details>\n",
3331                 limits->minUniformBufferOffsetAlignment);
3332         fprintf(out,
3333                 "\t\t\t\t\t\t<details><summary>minStorageBufferOffsetAlignment         = <div class='val'>0x%" PRIxLEAST64
3334                 "</div></summary></details>\n",
3335                 limits->minStorageBufferOffsetAlignment);
3336         fprintf(out,
3337                 "\t\t\t\t\t\t<details><summary>minTexelOffset                          = <div "
3338                 "class='val'>%3d</div></summary></details>\n",
3339                 limits->minTexelOffset);
3340         fprintf(out,
3341                 "\t\t\t\t\t\t<details><summary>maxTexelOffset                          = <div "
3342                 "class='val'>%3d</div></summary></details>\n",
3343                 limits->maxTexelOffset);
3344         fprintf(out,
3345                 "\t\t\t\t\t\t<details><summary>minTexelGatherOffset                    = <div "
3346                 "class='val'>%3d</div></summary></details>\n",
3347                 limits->minTexelGatherOffset);
3348         fprintf(out,
3349                 "\t\t\t\t\t\t<details><summary>maxTexelGatherOffset                    = <div "
3350                 "class='val'>%3d</div></summary></details>\n",
3351                 limits->maxTexelGatherOffset);
3352         fprintf(out,
3353                 "\t\t\t\t\t\t<details><summary>minInterpolationOffset                  = <div "
3354                 "class='val'>%9f</div></summary></details>\n",
3355                 limits->minInterpolationOffset);
3356         fprintf(out,
3357                 "\t\t\t\t\t\t<details><summary>maxInterpolationOffset                  = <div "
3358                 "class='val'>%9f</div></summary></details>\n",
3359                 limits->maxInterpolationOffset);
3360         fprintf(out,
3361                 "\t\t\t\t\t\t<details><summary>subPixelInterpolationOffsetBits         = <div "
3362                 "class='val'>%u</div></summary></details>\n",
3363                 limits->subPixelInterpolationOffsetBits);
3364         fprintf(out,
3365                 "\t\t\t\t\t\t<details><summary>maxFramebufferWidth                     = <div "
3366                 "class='val'>%u</div></summary></details>\n",
3367                 limits->maxFramebufferWidth);
3368         fprintf(out,
3369                 "\t\t\t\t\t\t<details><summary>maxFramebufferHeight                    = <div "
3370                 "class='val'>%u</div></summary></details>\n",
3371                 limits->maxFramebufferHeight);
3372         fprintf(out,
3373                 "\t\t\t\t\t\t<details><summary>maxFramebufferLayers                    = <div "
3374                 "class='val'>%u</div></summary></details>\n",
3375                 limits->maxFramebufferLayers);
3376         fprintf(out,
3377                 "\t\t\t\t\t\t<details><summary>framebufferColorSampleCounts            = <div "
3378                 "class='val'>%u</div></summary></details>\n",
3379                 limits->framebufferColorSampleCounts);
3380         fprintf(out,
3381                 "\t\t\t\t\t\t<details><summary>framebufferDepthSampleCounts            = <div "
3382                 "class='val'>%u</div></summary></details>\n",
3383                 limits->framebufferDepthSampleCounts);
3384         fprintf(out,
3385                 "\t\t\t\t\t\t<details><summary>framebufferStencilSampleCounts          = <div "
3386                 "class='val'>%u</div></summary></details>\n",
3387                 limits->framebufferStencilSampleCounts);
3388         fprintf(out,
3389                 "\t\t\t\t\t\t<details><summary>framebufferNoAttachmentsSampleCounts    = <div "
3390                 "class='val'>%u</div></summary></details>\n",
3391                 limits->framebufferNoAttachmentsSampleCounts);
3392         fprintf(out,
3393                 "\t\t\t\t\t\t<details><summary>maxColorAttachments                     = <div "
3394                 "class='val'>%u</div></summary></details>\n",
3395                 limits->maxColorAttachments);
3396         fprintf(out,
3397                 "\t\t\t\t\t\t<details><summary>sampledImageColorSampleCounts           = <div "
3398                 "class='val'>%u</div></summary></details>\n",
3399                 limits->sampledImageColorSampleCounts);
3400         fprintf(out,
3401                 "\t\t\t\t\t\t<details><summary>sampledImageDepthSampleCounts           = <div "
3402                 "class='val'>%u</div></summary></details>\n",
3403                 limits->sampledImageDepthSampleCounts);
3404         fprintf(out,
3405                 "\t\t\t\t\t\t<details><summary>sampledImageStencilSampleCounts         = <div "
3406                 "class='val'>%u</div></summary></details>\n",
3407                 limits->sampledImageStencilSampleCounts);
3408         fprintf(out,
3409                 "\t\t\t\t\t\t<details><summary>sampledImageIntegerSampleCounts         = <div "
3410                 "class='val'>%u</div></summary></details>\n",
3411                 limits->sampledImageIntegerSampleCounts);
3412         fprintf(out,
3413                 "\t\t\t\t\t\t<details><summary>storageImageSampleCounts                = <div "
3414                 "class='val'>%u</div></summary></details>\n",
3415                 limits->storageImageSampleCounts);
3416         fprintf(out,
3417                 "\t\t\t\t\t\t<details><summary>maxSampleMaskWords                      = <div "
3418                 "class='val'>%u</div></summary></details>\n",
3419                 limits->maxSampleMaskWords);
3420         fprintf(out,
3421                 "\t\t\t\t\t\t<details><summary>timestampComputeAndGraphics             = <div "
3422                 "class='val'>%u</div></summary></details>\n",
3423                 limits->timestampComputeAndGraphics);
3424         fprintf(out,
3425                 "\t\t\t\t\t\t<details><summary>timestampPeriod                         = <div "
3426                 "class='val'>%f</div></summary></details>\n",
3427                 limits->timestampPeriod);
3428         fprintf(out,
3429                 "\t\t\t\t\t\t<details><summary>maxClipDistances                        = <div "
3430                 "class='val'>%u</div></summary></details>\n",
3431                 limits->maxClipDistances);
3432         fprintf(out,
3433                 "\t\t\t\t\t\t<details><summary>maxCullDistances                        = <div "
3434                 "class='val'>%u</div></summary></details>\n",
3435                 limits->maxCullDistances);
3436         fprintf(out,
3437                 "\t\t\t\t\t\t<details><summary>maxCombinedClipAndCullDistances         = <div "
3438                 "class='val'>%u</div></summary></details>\n",
3439                 limits->maxCombinedClipAndCullDistances);
3440         fprintf(out,
3441                 "\t\t\t\t\t\t<details><summary>discreteQueuePriorities                 = <div "
3442                 "class='val'>%u</div></summary></details>\n",
3443                 limits->discreteQueuePriorities);
3444         fprintf(out,
3445                 "\t\t\t\t\t\t<details><summary>pointSizeRange[0]                       = <div "
3446                 "class='val'>%f</div></summary></details>\n",
3447                 limits->pointSizeRange[0]);
3448         fprintf(out,
3449                 "\t\t\t\t\t\t<details><summary>pointSizeRange[1]                       = <div "
3450                 "class='val'>%f</div></summary></details>\n",
3451                 limits->pointSizeRange[1]);
3452         fprintf(out,
3453                 "\t\t\t\t\t\t<details><summary>lineWidthRange[0]                       = <div "
3454                 "class='val'>%f</div></summary></details>\n",
3455                 limits->lineWidthRange[0]);
3456         fprintf(out,
3457                 "\t\t\t\t\t\t<details><summary>lineWidthRange[1]                       = <div "
3458                 "class='val'>%f</div></summary></details>\n",
3459                 limits->lineWidthRange[1]);
3460         fprintf(out,
3461                 "\t\t\t\t\t\t<details><summary>pointSizeGranularity                    = <div "
3462                 "class='val'>%f</div></summary></details>\n",
3463                 limits->pointSizeGranularity);
3464         fprintf(out,
3465                 "\t\t\t\t\t\t<details><summary>lineWidthGranularity                    = <div "
3466                 "class='val'>%f</div></summary></details>\n",
3467                 limits->lineWidthGranularity);
3468         fprintf(out,
3469                 "\t\t\t\t\t\t<details><summary>strictLines                             = <div "
3470                 "class='val'>%u</div></summary></details>\n",
3471                 limits->strictLines);
3472         fprintf(out,
3473                 "\t\t\t\t\t\t<details><summary>standardSampleLocations                 = <div "
3474                 "class='val'>%u</div></summary></details>\n",
3475                 limits->standardSampleLocations);
3476         fprintf(out,
3477                 "\t\t\t\t\t\t<details><summary>optimalBufferCopyOffsetAlignment        = <div class='val'>0x%" PRIxLEAST64
3478                 "</div></summary></details>\n",
3479                 limits->optimalBufferCopyOffsetAlignment);
3480         fprintf(out,
3481                 "\t\t\t\t\t\t<details><summary>optimalBufferCopyRowPitchAlignment      = <div class='val'>0x%" PRIxLEAST64
3482                 "</div></summary></details>\n",
3483                 limits->optimalBufferCopyRowPitchAlignment);
3484         fprintf(out,
3485                 "\t\t\t\t\t\t<details><summary>nonCoherentAtomSize                     = <div class='val'>0x%" PRIxLEAST64
3486                 "</div></summary></details>\n",
3487                 limits->nonCoherentAtomSize);
3488         fprintf(out, "\t\t\t\t\t</details>\n");
3489     } else if (human_readable_output) {
3490         printf("\tVkPhysicalDeviceLimits:\n");
3491         printf("\t-----------------------\n");
3492         printf("\t\tmaxImageDimension1D                     = %u\n", limits->maxImageDimension1D);
3493         printf("\t\tmaxImageDimension2D                     = %u\n", limits->maxImageDimension2D);
3494         printf("\t\tmaxImageDimension3D                     = %u\n", limits->maxImageDimension3D);
3495         printf("\t\tmaxImageDimensionCube                   = %u\n", limits->maxImageDimensionCube);
3496         printf("\t\tmaxImageArrayLayers                     = %u\n", limits->maxImageArrayLayers);
3497         printf("\t\tmaxTexelBufferElements                  = 0x%" PRIxLEAST32 "\n", limits->maxTexelBufferElements);
3498         printf("\t\tmaxUniformBufferRange                   = 0x%" PRIxLEAST32 "\n", limits->maxUniformBufferRange);
3499         printf("\t\tmaxStorageBufferRange                   = 0x%" PRIxLEAST32 "\n", limits->maxStorageBufferRange);
3500         printf("\t\tmaxPushConstantsSize                    = %u\n", limits->maxPushConstantsSize);
3501         printf("\t\tmaxMemoryAllocationCount                = %u\n", limits->maxMemoryAllocationCount);
3502         printf("\t\tmaxSamplerAllocationCount               = %u\n", limits->maxSamplerAllocationCount);
3503         printf("\t\tbufferImageGranularity                  = 0x%" PRIxLEAST64 "\n", limits->bufferImageGranularity);
3504         printf("\t\tsparseAddressSpaceSize                  = 0x%" PRIxLEAST64 "\n", limits->sparseAddressSpaceSize);
3505         printf("\t\tmaxBoundDescriptorSets                  = %u\n", limits->maxBoundDescriptorSets);
3506         printf("\t\tmaxPerStageDescriptorSamplers           = %u\n", limits->maxPerStageDescriptorSamplers);
3507         printf("\t\tmaxPerStageDescriptorUniformBuffers     = %u\n", limits->maxPerStageDescriptorUniformBuffers);
3508         printf("\t\tmaxPerStageDescriptorStorageBuffers     = %u\n", limits->maxPerStageDescriptorStorageBuffers);
3509         printf("\t\tmaxPerStageDescriptorSampledImages      = %u\n", limits->maxPerStageDescriptorSampledImages);
3510         printf("\t\tmaxPerStageDescriptorStorageImages      = %u\n", limits->maxPerStageDescriptorStorageImages);
3511         printf("\t\tmaxPerStageDescriptorInputAttachments   = %u\n", limits->maxPerStageDescriptorInputAttachments);
3512         printf("\t\tmaxPerStageResources                    = %u\n", limits->maxPerStageResources);
3513         printf("\t\tmaxDescriptorSetSamplers                = %u\n", limits->maxDescriptorSetSamplers);
3514         printf("\t\tmaxDescriptorSetUniformBuffers          = %u\n", limits->maxDescriptorSetUniformBuffers);
3515         printf("\t\tmaxDescriptorSetUniformBuffersDynamic   = %u\n", limits->maxDescriptorSetUniformBuffersDynamic);
3516         printf("\t\tmaxDescriptorSetStorageBuffers          = %u\n", limits->maxDescriptorSetStorageBuffers);
3517         printf("\t\tmaxDescriptorSetStorageBuffersDynamic   = %u\n", limits->maxDescriptorSetStorageBuffersDynamic);
3518         printf("\t\tmaxDescriptorSetSampledImages           = %u\n", limits->maxDescriptorSetSampledImages);
3519         printf("\t\tmaxDescriptorSetStorageImages           = %u\n", limits->maxDescriptorSetStorageImages);
3520         printf("\t\tmaxDescriptorSetInputAttachments        = %u\n", limits->maxDescriptorSetInputAttachments);
3521         printf("\t\tmaxVertexInputAttributes                = %u\n", limits->maxVertexInputAttributes);
3522         printf("\t\tmaxVertexInputBindings                  = %u\n", limits->maxVertexInputBindings);
3523         printf("\t\tmaxVertexInputAttributeOffset           = 0x%" PRIxLEAST32 "\n", limits->maxVertexInputAttributeOffset);
3524         printf("\t\tmaxVertexInputBindingStride             = 0x%" PRIxLEAST32 "\n", limits->maxVertexInputBindingStride);
3525         printf("\t\tmaxVertexOutputComponents               = %u\n", limits->maxVertexOutputComponents);
3526         printf("\t\tmaxTessellationGenerationLevel          = %u\n", limits->maxTessellationGenerationLevel);
3527         printf("\t\tmaxTessellationPatchSize                        = %u\n", limits->maxTessellationPatchSize);
3528         printf("\t\tmaxTessellationControlPerVertexInputComponents  = %u\n",
3529                limits->maxTessellationControlPerVertexInputComponents);
3530         printf("\t\tmaxTessellationControlPerVertexOutputComponents = %u\n",
3531                limits->maxTessellationControlPerVertexOutputComponents);
3532         printf("\t\tmaxTessellationControlPerPatchOutputComponents  = %u\n",
3533                limits->maxTessellationControlPerPatchOutputComponents);
3534         printf("\t\tmaxTessellationControlTotalOutputComponents     = %u\n", limits->maxTessellationControlTotalOutputComponents);
3535         printf("\t\tmaxTessellationEvaluationInputComponents        = %u\n", limits->maxTessellationEvaluationInputComponents);
3536         printf("\t\tmaxTessellationEvaluationOutputComponents       = %u\n", limits->maxTessellationEvaluationOutputComponents);
3537         printf("\t\tmaxGeometryShaderInvocations            = %u\n", limits->maxGeometryShaderInvocations);
3538         printf("\t\tmaxGeometryInputComponents              = %u\n", limits->maxGeometryInputComponents);
3539         printf("\t\tmaxGeometryOutputComponents             = %u\n", limits->maxGeometryOutputComponents);
3540         printf("\t\tmaxGeometryOutputVertices               = %u\n", limits->maxGeometryOutputVertices);
3541         printf("\t\tmaxGeometryTotalOutputComponents        = %u\n", limits->maxGeometryTotalOutputComponents);
3542         printf("\t\tmaxFragmentInputComponents              = %u\n", limits->maxFragmentInputComponents);
3543         printf("\t\tmaxFragmentOutputAttachments            = %u\n", limits->maxFragmentOutputAttachments);
3544         printf("\t\tmaxFragmentDualSrcAttachments           = %u\n", limits->maxFragmentDualSrcAttachments);
3545         printf("\t\tmaxFragmentCombinedOutputResources      = %u\n", limits->maxFragmentCombinedOutputResources);
3546         printf("\t\tmaxComputeSharedMemorySize              = 0x%" PRIxLEAST32 "\n", limits->maxComputeSharedMemorySize);
3547         printf("\t\tmaxComputeWorkGroupCount[0]             = %u\n", limits->maxComputeWorkGroupCount[0]);
3548         printf("\t\tmaxComputeWorkGroupCount[1]             = %u\n", limits->maxComputeWorkGroupCount[1]);
3549         printf("\t\tmaxComputeWorkGroupCount[2]             = %u\n", limits->maxComputeWorkGroupCount[2]);
3550         printf("\t\tmaxComputeWorkGroupInvocations          = %u\n", limits->maxComputeWorkGroupInvocations);
3551         printf("\t\tmaxComputeWorkGroupSize[0]              = %u\n", limits->maxComputeWorkGroupSize[0]);
3552         printf("\t\tmaxComputeWorkGroupSize[1]              = %u\n", limits->maxComputeWorkGroupSize[1]);
3553         printf("\t\tmaxComputeWorkGroupSize[2]              = %u\n", limits->maxComputeWorkGroupSize[2]);
3554         printf("\t\tsubPixelPrecisionBits                   = %u\n", limits->subPixelPrecisionBits);
3555         printf("\t\tsubTexelPrecisionBits                   = %u\n", limits->subTexelPrecisionBits);
3556         printf("\t\tmipmapPrecisionBits                     = %u\n", limits->mipmapPrecisionBits);
3557         printf("\t\tmaxDrawIndexedIndexValue                = %u\n", limits->maxDrawIndexedIndexValue);
3558         printf("\t\tmaxDrawIndirectCount                    = %u\n", limits->maxDrawIndirectCount);
3559         printf("\t\tmaxSamplerLodBias                       = %f\n", limits->maxSamplerLodBias);
3560         printf("\t\tmaxSamplerAnisotropy                    = %f\n", limits->maxSamplerAnisotropy);
3561         printf("\t\tmaxViewports                            = %u\n", limits->maxViewports);
3562         printf("\t\tmaxViewportDimensions[0]                = %u\n", limits->maxViewportDimensions[0]);
3563         printf("\t\tmaxViewportDimensions[1]                = %u\n", limits->maxViewportDimensions[1]);
3564         printf("\t\tviewportBoundsRange[0]                  = %13f\n", limits->viewportBoundsRange[0]);
3565         printf("\t\tviewportBoundsRange[1]                  = %13f\n", limits->viewportBoundsRange[1]);
3566         printf("\t\tviewportSubPixelBits                    = %u\n", limits->viewportSubPixelBits);
3567         printf("\t\tminMemoryMapAlignment                   = " PRINTF_SIZE_T_SPECIFIER "\n", limits->minMemoryMapAlignment);
3568         printf("\t\tminTexelBufferOffsetAlignment           = 0x%" PRIxLEAST64 "\n", limits->minTexelBufferOffsetAlignment);
3569         printf("\t\tminUniformBufferOffsetAlignment         = 0x%" PRIxLEAST64 "\n", limits->minUniformBufferOffsetAlignment);
3570         printf("\t\tminStorageBufferOffsetAlignment         = 0x%" PRIxLEAST64 "\n", limits->minStorageBufferOffsetAlignment);
3571         printf("\t\tminTexelOffset                          = %3d\n", limits->minTexelOffset);
3572         printf("\t\tmaxTexelOffset                          = %3d\n", limits->maxTexelOffset);
3573         printf("\t\tminTexelGatherOffset                    = %3d\n", limits->minTexelGatherOffset);
3574         printf("\t\tmaxTexelGatherOffset                    = %3d\n", limits->maxTexelGatherOffset);
3575         printf("\t\tminInterpolationOffset                  = %9f\n", limits->minInterpolationOffset);
3576         printf("\t\tmaxInterpolationOffset                  = %9f\n", limits->maxInterpolationOffset);
3577         printf("\t\tsubPixelInterpolationOffsetBits         = %u\n", limits->subPixelInterpolationOffsetBits);
3578         printf("\t\tmaxFramebufferWidth                     = %u\n", limits->maxFramebufferWidth);
3579         printf("\t\tmaxFramebufferHeight                    = %u\n", limits->maxFramebufferHeight);
3580         printf("\t\tmaxFramebufferLayers                    = %u\n", limits->maxFramebufferLayers);
3581         printf("\t\tframebufferColorSampleCounts            = %u\n", limits->framebufferColorSampleCounts);
3582         printf("\t\tframebufferDepthSampleCounts            = %u\n", limits->framebufferDepthSampleCounts);
3583         printf("\t\tframebufferStencilSampleCounts          = %u\n", limits->framebufferStencilSampleCounts);
3584         printf("\t\tframebufferNoAttachmentsSampleCounts    = %u\n", limits->framebufferNoAttachmentsSampleCounts);
3585         printf("\t\tmaxColorAttachments                     = %u\n", limits->maxColorAttachments);
3586         printf("\t\tsampledImageColorSampleCounts           = %u\n", limits->sampledImageColorSampleCounts);
3587         printf("\t\tsampledImageDepthSampleCounts           = %u\n", limits->sampledImageDepthSampleCounts);
3588         printf("\t\tsampledImageStencilSampleCounts         = %u\n", limits->sampledImageStencilSampleCounts);
3589         printf("\t\tsampledImageIntegerSampleCounts         = %u\n", limits->sampledImageIntegerSampleCounts);
3590         printf("\t\tstorageImageSampleCounts                = %u\n", limits->storageImageSampleCounts);
3591         printf("\t\tmaxSampleMaskWords                      = %u\n", limits->maxSampleMaskWords);
3592         printf("\t\ttimestampComputeAndGraphics             = %u\n", limits->timestampComputeAndGraphics);
3593         printf("\t\ttimestampPeriod                         = %f\n", limits->timestampPeriod);
3594         printf("\t\tmaxClipDistances                        = %u\n", limits->maxClipDistances);
3595         printf("\t\tmaxCullDistances                        = %u\n", limits->maxCullDistances);
3596         printf("\t\tmaxCombinedClipAndCullDistances         = %u\n", limits->maxCombinedClipAndCullDistances);
3597         printf("\t\tdiscreteQueuePriorities                 = %u\n", limits->discreteQueuePriorities);
3598         printf("\t\tpointSizeRange[0]                       = %f\n", limits->pointSizeRange[0]);
3599         printf("\t\tpointSizeRange[1]                       = %f\n", limits->pointSizeRange[1]);
3600         printf("\t\tlineWidthRange[0]                       = %f\n", limits->lineWidthRange[0]);
3601         printf("\t\tlineWidthRange[1]                       = %f\n", limits->lineWidthRange[1]);
3602         printf("\t\tpointSizeGranularity                    = %f\n", limits->pointSizeGranularity);
3603         printf("\t\tlineWidthGranularity                    = %f\n", limits->lineWidthGranularity);
3604         printf("\t\tstrictLines                             = %u\n", limits->strictLines);
3605         printf("\t\tstandardSampleLocations                 = %u\n", limits->standardSampleLocations);
3606         printf("\t\toptimalBufferCopyOffsetAlignment        = 0x%" PRIxLEAST64 "\n", limits->optimalBufferCopyOffsetAlignment);
3607         printf("\t\toptimalBufferCopyRowPitchAlignment      = 0x%" PRIxLEAST64 "\n", limits->optimalBufferCopyRowPitchAlignment);
3608         printf("\t\tnonCoherentAtomSize                     = 0x%" PRIxLEAST64 "\n", limits->nonCoherentAtomSize);
3609     }
3610     if (json_output) {
3611         printf(",\n");
3612         printf("\t\t\"limits\": {\n");
3613         printf("\t\t\t\"maxImageDimension1D\": %u,\n", limits->maxImageDimension1D);
3614         printf("\t\t\t\"maxImageDimension2D\": %u,\n", limits->maxImageDimension2D);
3615         printf("\t\t\t\"maxImageDimension3D\": %u,\n", limits->maxImageDimension3D);
3616         printf("\t\t\t\"maxImageDimensionCube\": %u,\n", limits->maxImageDimensionCube);
3617         printf("\t\t\t\"maxImageArrayLayers\": %u,\n", limits->maxImageArrayLayers);
3618         printf("\t\t\t\"maxTexelBufferElements\": %u,\n", limits->maxTexelBufferElements);
3619         printf("\t\t\t\"maxUniformBufferRange\": %u,\n", limits->maxUniformBufferRange);
3620         printf("\t\t\t\"maxStorageBufferRange\": %u,\n", limits->maxStorageBufferRange);
3621         printf("\t\t\t\"maxPushConstantsSize\": %u,\n", limits->maxPushConstantsSize);
3622         printf("\t\t\t\"maxMemoryAllocationCount\": %u,\n", limits->maxMemoryAllocationCount);
3623         printf("\t\t\t\"maxSamplerAllocationCount\": %u,\n", limits->maxSamplerAllocationCount);
3624         printf("\t\t\t\"bufferImageGranularity\": %llu,\n", (unsigned long long)limits->bufferImageGranularity);
3625         printf("\t\t\t\"sparseAddressSpaceSize\": %llu,\n", (unsigned long long)limits->sparseAddressSpaceSize);
3626         printf("\t\t\t\"maxBoundDescriptorSets\": %u,\n", limits->maxBoundDescriptorSets);
3627         printf("\t\t\t\"maxPerStageDescriptorSamplers\": %u,\n", limits->maxPerStageDescriptorSamplers);
3628         printf("\t\t\t\"maxPerStageDescriptorUniformBuffers\": %u,\n", limits->maxPerStageDescriptorUniformBuffers);
3629         printf("\t\t\t\"maxPerStageDescriptorStorageBuffers\": %u,\n", limits->maxPerStageDescriptorStorageBuffers);
3630         printf("\t\t\t\"maxPerStageDescriptorSampledImages\": %u,\n", limits->maxPerStageDescriptorSampledImages);
3631         printf("\t\t\t\"maxPerStageDescriptorStorageImages\": %u,\n", limits->maxPerStageDescriptorStorageImages);
3632         printf("\t\t\t\"maxPerStageDescriptorInputAttachments\": %u,\n", limits->maxPerStageDescriptorInputAttachments);
3633         printf("\t\t\t\"maxPerStageResources\": %u,\n", limits->maxPerStageResources);
3634         printf("\t\t\t\"maxDescriptorSetSamplers\": %u,\n", limits->maxDescriptorSetSamplers);
3635         printf("\t\t\t\"maxDescriptorSetUniformBuffers\": %u,\n", limits->maxDescriptorSetUniformBuffers);
3636         printf("\t\t\t\"maxDescriptorSetUniformBuffersDynamic\": %u,\n", limits->maxDescriptorSetUniformBuffersDynamic);
3637         printf("\t\t\t\"maxDescriptorSetStorageBuffers\": %u,\n", limits->maxDescriptorSetStorageBuffers);
3638         printf("\t\t\t\"maxDescriptorSetStorageBuffersDynamic\": %u,\n", limits->maxDescriptorSetStorageBuffersDynamic);
3639         printf("\t\t\t\"maxDescriptorSetSampledImages\": %u,\n", limits->maxDescriptorSetSampledImages);
3640         printf("\t\t\t\"maxDescriptorSetStorageImages\": %u,\n", limits->maxDescriptorSetStorageImages);
3641         printf("\t\t\t\"maxDescriptorSetInputAttachments\": %u,\n", limits->maxDescriptorSetInputAttachments);
3642         printf("\t\t\t\"maxVertexInputAttributes\": %u,\n", limits->maxVertexInputAttributes);
3643         printf("\t\t\t\"maxVertexInputBindings\": %u,\n", limits->maxVertexInputBindings);
3644         printf("\t\t\t\"maxVertexInputAttributeOffset\": %u,\n", limits->maxVertexInputAttributeOffset);
3645         printf("\t\t\t\"maxVertexInputBindingStride\": %u,\n", limits->maxVertexInputBindingStride);
3646         printf("\t\t\t\"maxVertexOutputComponents\": %u,\n", limits->maxVertexOutputComponents);
3647         printf("\t\t\t\"maxTessellationGenerationLevel\": %u,\n", limits->maxTessellationGenerationLevel);
3648         printf("\t\t\t\"maxTessellationPatchSize\": %u,\n", limits->maxTessellationPatchSize);
3649         printf("\t\t\t\"maxTessellationControlPerVertexInputComponents\": %u,\n",
3650                limits->maxTessellationControlPerVertexInputComponents);
3651         printf("\t\t\t\"maxTessellationControlPerVertexOutputComponents\": %u,\n",
3652                limits->maxTessellationControlPerVertexOutputComponents);
3653         printf("\t\t\t\"maxTessellationControlPerPatchOutputComponents\": %u,\n",
3654                limits->maxTessellationControlPerPatchOutputComponents);
3655         printf("\t\t\t\"maxTessellationControlTotalOutputComponents\": %u,\n", limits->maxTessellationControlTotalOutputComponents);
3656         printf("\t\t\t\"maxTessellationEvaluationInputComponents\": %u,\n", limits->maxTessellationEvaluationInputComponents);
3657         printf("\t\t\t\"maxTessellationEvaluationOutputComponents\": %u,\n", limits->maxTessellationEvaluationOutputComponents);
3658         printf("\t\t\t\"maxGeometryShaderInvocations\": %u,\n", limits->maxGeometryShaderInvocations);
3659         printf("\t\t\t\"maxGeometryInputComponents\": %u,\n", limits->maxGeometryInputComponents);
3660         printf("\t\t\t\"maxGeometryOutputComponents\": %u,\n", limits->maxGeometryOutputComponents);
3661         printf("\t\t\t\"maxGeometryOutputVertices\": %u,\n", limits->maxGeometryOutputVertices);
3662         printf("\t\t\t\"maxGeometryTotalOutputComponents\": %u,\n", limits->maxGeometryTotalOutputComponents);
3663         printf("\t\t\t\"maxFragmentInputComponents\": %u,\n", limits->maxFragmentInputComponents);
3664         printf("\t\t\t\"maxFragmentOutputAttachments\": %u,\n", limits->maxFragmentOutputAttachments);
3665         printf("\t\t\t\"maxFragmentDualSrcAttachments\": %u,\n", limits->maxFragmentDualSrcAttachments);
3666         printf("\t\t\t\"maxFragmentCombinedOutputResources\": %u,\n", limits->maxFragmentCombinedOutputResources);
3667         printf("\t\t\t\"maxComputeSharedMemorySize\": %u,\n", limits->maxComputeSharedMemorySize);
3668         printf("\t\t\t\"maxComputeWorkGroupCount\": [\n");
3669         printf("\t\t\t\t%u,\n", limits->maxComputeWorkGroupCount[0]);
3670         printf("\t\t\t\t%u,\n", limits->maxComputeWorkGroupCount[1]);
3671         printf("\t\t\t\t%u\n", limits->maxComputeWorkGroupCount[2]);
3672         printf("\t\t\t],\n");
3673         printf("\t\t\t\"maxComputeWorkGroupInvocations\": %u,\n", limits->maxComputeWorkGroupInvocations);
3674         printf("\t\t\t\"maxComputeWorkGroupSize\": [\n");
3675         printf("\t\t\t\t%u,\n", limits->maxComputeWorkGroupSize[0]);
3676         printf("\t\t\t\t%u,\n", limits->maxComputeWorkGroupSize[1]);
3677         printf("\t\t\t\t%u\n", limits->maxComputeWorkGroupSize[2]);
3678         printf("\t\t\t],\n");
3679         printf("\t\t\t\"subPixelPrecisionBits\": %u,\n", limits->subPixelPrecisionBits);
3680         printf("\t\t\t\"subTexelPrecisionBits\": %u,\n", limits->subTexelPrecisionBits);
3681         printf("\t\t\t\"mipmapPrecisionBits\": %u,\n", limits->mipmapPrecisionBits);
3682         printf("\t\t\t\"maxDrawIndexedIndexValue\": %u,\n", limits->maxDrawIndexedIndexValue);
3683         printf("\t\t\t\"maxDrawIndirectCount\": %u,\n", limits->maxDrawIndirectCount);
3684         printf("\t\t\t\"maxSamplerLodBias\": %g,\n", limits->maxSamplerLodBias);
3685         printf("\t\t\t\"maxSamplerAnisotropy\": %g,\n", limits->maxSamplerAnisotropy);
3686         printf("\t\t\t\"maxViewports\": %u,\n", limits->maxViewports);
3687         printf("\t\t\t\"maxViewportDimensions\": [\n");
3688         printf("\t\t\t\t%u,\n", limits->maxViewportDimensions[0]);
3689         printf("\t\t\t\t%u\n", limits->maxViewportDimensions[1]);
3690         printf("\t\t\t],\n");
3691         printf("\t\t\t\"viewportBoundsRange\": [\n");
3692         printf("\t\t\t\t%g,\n", limits->viewportBoundsRange[0]);
3693         printf("\t\t\t\t%g\n", limits->viewportBoundsRange[1]);
3694         printf("\t\t\t],\n");
3695         printf("\t\t\t\"viewportSubPixelBits\": %u,\n", limits->viewportSubPixelBits);
3696         printf("\t\t\t\"minMemoryMapAlignment\": " PRINTF_SIZE_T_SPECIFIER ",\n", limits->minMemoryMapAlignment);
3697         printf("\t\t\t\"minTexelBufferOffsetAlignment\": %llu,\n", (unsigned long long)limits->minTexelBufferOffsetAlignment);
3698         printf("\t\t\t\"minUniformBufferOffsetAlignment\": %llu,\n", (unsigned long long)limits->minUniformBufferOffsetAlignment);
3699         printf("\t\t\t\"minStorageBufferOffsetAlignment\": %llu,\n", (unsigned long long)limits->minStorageBufferOffsetAlignment);
3700         printf("\t\t\t\"minTexelOffset\": %d,\n", limits->minTexelOffset);
3701         printf("\t\t\t\"maxTexelOffset\": %u,\n", limits->maxTexelOffset);
3702         printf("\t\t\t\"minTexelGatherOffset\": %d,\n", limits->minTexelGatherOffset);
3703         printf("\t\t\t\"maxTexelGatherOffset\": %u,\n", limits->maxTexelGatherOffset);
3704         printf("\t\t\t\"minInterpolationOffset\": %g,\n", limits->minInterpolationOffset);
3705         printf("\t\t\t\"maxInterpolationOffset\": %g,\n", limits->maxInterpolationOffset);
3706         printf("\t\t\t\"subPixelInterpolationOffsetBits\": %u,\n", limits->subPixelInterpolationOffsetBits);
3707         printf("\t\t\t\"maxFramebufferWidth\": %u,\n", limits->maxFramebufferWidth);
3708         printf("\t\t\t\"maxFramebufferHeight\": %u,\n", limits->maxFramebufferHeight);
3709         printf("\t\t\t\"maxFramebufferLayers\": %u,\n", limits->maxFramebufferLayers);
3710         printf("\t\t\t\"framebufferColorSampleCounts\": %u,\n", limits->framebufferColorSampleCounts);
3711         printf("\t\t\t\"framebufferDepthSampleCounts\": %u,\n", limits->framebufferDepthSampleCounts);
3712         printf("\t\t\t\"framebufferStencilSampleCounts\": %u,\n", limits->framebufferStencilSampleCounts);
3713         printf("\t\t\t\"framebufferNoAttachmentsSampleCounts\": %u,\n", limits->framebufferNoAttachmentsSampleCounts);
3714         printf("\t\t\t\"maxColorAttachments\": %u,\n", limits->maxColorAttachments);
3715         printf("\t\t\t\"sampledImageColorSampleCounts\": %u,\n", limits->sampledImageColorSampleCounts);
3716         printf("\t\t\t\"sampledImageIntegerSampleCounts\": %u,\n", limits->sampledImageIntegerSampleCounts);
3717         printf("\t\t\t\"sampledImageDepthSampleCounts\": %u,\n", limits->sampledImageDepthSampleCounts);
3718         printf("\t\t\t\"sampledImageStencilSampleCounts\": %u,\n", limits->sampledImageStencilSampleCounts);
3719         printf("\t\t\t\"storageImageSampleCounts\": %u,\n", limits->storageImageSampleCounts);
3720         printf("\t\t\t\"maxSampleMaskWords\": %u,\n", limits->maxSampleMaskWords);
3721         printf("\t\t\t\"timestampComputeAndGraphics\": %u,\n", limits->timestampComputeAndGraphics);
3722         printf("\t\t\t\"timestampPeriod\": %g,\n", limits->timestampPeriod);
3723         printf("\t\t\t\"maxClipDistances\": %u,\n", limits->maxClipDistances);
3724         printf("\t\t\t\"maxCullDistances\": %u,\n", limits->maxCullDistances);
3725         printf("\t\t\t\"maxCombinedClipAndCullDistances\": %u,\n", limits->maxCombinedClipAndCullDistances);
3726         printf("\t\t\t\"discreteQueuePriorities\": %u,\n", limits->discreteQueuePriorities);
3727         printf("\t\t\t\"pointSizeRange\": [\n");
3728         printf("\t\t\t\t%g,\n", limits->pointSizeRange[0]);
3729         printf("\t\t\t\t%g\n", limits->pointSizeRange[1]);
3730         printf("\t\t\t],\n");
3731         printf("\t\t\t\"lineWidthRange\": [\n");
3732         printf("\t\t\t\t%g,\n", limits->lineWidthRange[0]);
3733         printf("\t\t\t\t%g\n", limits->lineWidthRange[1]);
3734         printf("\t\t\t],\n");
3735         printf("\t\t\t\"pointSizeGranularity\": %g,\n", limits->pointSizeGranularity);
3736         printf("\t\t\t\"lineWidthGranularity\": %g,\n", limits->lineWidthGranularity);
3737         printf("\t\t\t\"strictLines\": %u,\n", limits->strictLines);
3738         printf("\t\t\t\"standardSampleLocations\": %u,\n", limits->standardSampleLocations);
3739         printf("\t\t\t\"optimalBufferCopyOffsetAlignment\": %llu,\n", (unsigned long long)limits->optimalBufferCopyOffsetAlignment);
3740         printf("\t\t\t\"optimalBufferCopyRowPitchAlignment\": %llu,\n",
3741                (unsigned long long)limits->optimalBufferCopyRowPitchAlignment);
3742         printf("\t\t\t\"nonCoherentAtomSize\": %llu\n", (unsigned long long)limits->nonCoherentAtomSize);
3743         printf("\t\t}");
3744     }
3745 }
3746
3747 static void AppGpuDumpProps(const struct AppGpu *gpu, FILE *out) {
3748     VkPhysicalDeviceProperties props;
3749
3750     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
3751                               gpu->inst->inst_extensions_count)) {
3752         const VkPhysicalDeviceProperties *props2_const = &gpu->props2.properties;
3753         props = *props2_const;
3754     } else {
3755         const VkPhysicalDeviceProperties *props_const = &gpu->props;
3756         props = *props_const;
3757     }
3758     const uint32_t apiVersion = props.apiVersion;
3759     const uint32_t major = VK_VERSION_MAJOR(apiVersion);
3760     const uint32_t minor = VK_VERSION_MINOR(apiVersion);
3761     const uint32_t patch = VK_VERSION_PATCH(apiVersion);
3762
3763     if (html_output) {
3764         fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceProperties</summary>\n");
3765         fprintf(out,
3766                 "\t\t\t\t\t\t<details><summary>apiVersion = <div class='val'>0x%" PRIxLEAST32
3767                 "</div>  (<div class='val'>%d.%d.%d</div>)</summary></details>\n",
3768                 apiVersion, major, minor, patch);
3769         fprintf(out,
3770                 "\t\t\t\t\t\t<details><summary>driverVersion = <div class='val'>%u</div> (<div class='val'>0x%" PRIxLEAST32
3771                 "</div>)</summary></details>\n",
3772                 props.driverVersion, props.driverVersion);
3773         fprintf(out, "\t\t\t\t\t\t<details><summary>vendorID = <div class='val'>0x%04x</div></summary></details>\n",
3774                 props.vendorID);
3775         fprintf(out, "\t\t\t\t\t\t<details><summary>deviceID = <div class='val'>0x%04x</div></summary></details>\n",
3776                 props.deviceID);
3777         fprintf(out, "\t\t\t\t\t\t<details><summary>deviceType = %s</summary></details>\n",
3778                 VkPhysicalDeviceTypeString(props.deviceType));
3779         fprintf(out, "\t\t\t\t\t\t<details><summary>deviceName = %s</summary></details>\n", props.deviceName);
3780         fprintf(out, "\t\t\t\t\t</details>\n");
3781     } else if (human_readable_output) {
3782         printf("VkPhysicalDeviceProperties:\n");
3783         printf("===========================\n");
3784         printf("\tapiVersion     = 0x%" PRIxLEAST32 "  (%d.%d.%d)\n", apiVersion, major, minor, patch);
3785         printf("\tdriverVersion  = %u (0x%" PRIxLEAST32 ")\n", props.driverVersion, props.driverVersion);
3786         printf("\tvendorID       = 0x%04x\n", props.vendorID);
3787         printf("\tdeviceID       = 0x%04x\n", props.deviceID);
3788         printf("\tdeviceType     = %s\n", VkPhysicalDeviceTypeString(props.deviceType));
3789         printf("\tdeviceName     = %s\n", props.deviceName);
3790     }
3791     if (json_output) {
3792         printf(",\n");
3793         printf("\t\"VkPhysicalDeviceProperties\": {\n");
3794         printf("\t\t\"apiVersion\": %u,\n", apiVersion);
3795         printf("\t\t\"driverVersion\": %u,\n", props.driverVersion);
3796         printf("\t\t\"vendorID\": %u,\n", props.vendorID);
3797         printf("\t\t\"deviceID\": %u,\n", props.deviceID);
3798         printf("\t\t\"deviceType\": %u,\n", props.deviceType);
3799         printf("\t\t\"deviceName\": \"%s\",\n", props.deviceName);
3800         printf("\t\t\"pipelineCacheUUID\": [");
3801         for (uint32_t i = 0; i < VK_UUID_SIZE; ++i) {
3802             if (i > 0) {
3803                 printf(",");
3804             }
3805             printf("\n");
3806             printf("\t\t\t%u", props.pipelineCacheUUID[i]);
3807         }
3808         printf("\n");
3809         printf("\t\t]");
3810     }
3811
3812     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
3813                               gpu->inst->inst_extensions_count)) {
3814         AppDumpLimits(&gpu->props2.properties.limits, out);
3815     } else {
3816         AppDumpLimits(&gpu->props.limits, out);
3817     }
3818
3819     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
3820                               gpu->inst->inst_extensions_count)) {
3821         AppDumpSparseProps(&gpu->props2.properties.sparseProperties, out);
3822     } else {
3823         AppDumpSparseProps(&gpu->props.sparseProperties, out);
3824     }
3825
3826     if (json_output) {
3827         printf("\n\t}");
3828     }
3829
3830     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
3831                               gpu->inst->inst_extensions_count)) {
3832         void *place = gpu->props2.pNext;
3833         while (place) {
3834             struct VkStructureHeader *structure = (struct VkStructureHeader *)place;
3835             if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT &&
3836                 CheckPhysicalDeviceExtensionIncluded(VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME, gpu->device_extensions,
3837                                                      gpu->device_extension_count)) {
3838                 VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT *blend_op_adv_props =
3839                     (VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT *)structure;
3840                 if (html_output) {
3841                     fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceBlendOperationAdvancedProperties</summary>\n");
3842                     fprintf(out,
3843                             "\t\t\t\t\t\t<details><summary>advancedBlendMaxColorAttachments                = <div "
3844                             "class='val'>%u</div></summary></details>\n",
3845                             blend_op_adv_props->advancedBlendMaxColorAttachments);
3846                     fprintf(out,
3847                             "\t\t\t\t\t\t<details><summary>advancedBlendIndependentBlend                   = <div "
3848                             "class='val'>%u</div></summary></details>\n",
3849                             blend_op_adv_props->advancedBlendIndependentBlend);
3850                     fprintf(out,
3851                             "\t\t\t\t\t\t<details><summary>advancedBlendNonPremultipliedSrcColor           = <div "
3852                             "class='val'>%u</div></summary></details>\n",
3853                             blend_op_adv_props->advancedBlendNonPremultipliedSrcColor);
3854                     fprintf(out,
3855                             "\t\t\t\t\t\t<details><summary>advancedBlendNonPremultipliedDstColor           = <div "
3856                             "class='val'>%u</div></summary></details>\n",
3857                             blend_op_adv_props->advancedBlendNonPremultipliedDstColor);
3858                     fprintf(out,
3859                             "\t\t\t\t\t\t<details><summary>advancedBlendCorrelatedOverlap                  = <div "
3860                             "class='val'>%u</div></summary></details>\n",
3861                             blend_op_adv_props->advancedBlendCorrelatedOverlap);
3862                     fprintf(out,
3863                             "\t\t\t\t\t\t<details><summary>advancedBlendAllOperations                      = <div "
3864                             "class='val'>%u</div></summary></details>\n",
3865                             blend_op_adv_props->advancedBlendAllOperations);
3866                     fprintf(out, "\t\t\t\t\t</details>\n");
3867                 } else if (human_readable_output) {
3868                     printf("\nVkPhysicalDeviceBlendOperationAdvancedProperties:\n");
3869                     printf("=================================================\n");
3870                     printf("\tadvancedBlendMaxColorAttachments               = %u\n",
3871                            blend_op_adv_props->advancedBlendMaxColorAttachments);
3872                     printf("\tadvancedBlendIndependentBlend                  = %u\n",
3873                            blend_op_adv_props->advancedBlendIndependentBlend);
3874                     printf("\tadvancedBlendNonPremultipliedSrcColor          = %u\n",
3875                            blend_op_adv_props->advancedBlendNonPremultipliedSrcColor);
3876                     printf("\tadvancedBlendNonPremultipliedDstColor          = %u\n",
3877                            blend_op_adv_props->advancedBlendNonPremultipliedDstColor);
3878                     printf("\tadvancedBlendCorrelatedOverlap                 = %u\n",
3879                            blend_op_adv_props->advancedBlendCorrelatedOverlap);
3880                     printf("\tadvancedBlendAllOperations                     = %u\n",
3881                            blend_op_adv_props->advancedBlendAllOperations);
3882                 }
3883             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR &&
3884                        CheckPhysicalDeviceExtensionIncluded(VK_KHR_MAINTENANCE2_EXTENSION_NAME, gpu->device_extensions,
3885                                                             gpu->device_extension_count)) {
3886                 VkPhysicalDevicePointClippingPropertiesKHR *pt_clip_props = (VkPhysicalDevicePointClippingPropertiesKHR *)structure;
3887                 if (html_output) {
3888                     fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDevicePointClippingProperties</summary>\n");
3889                     fprintf(out,
3890                             "\t\t\t\t\t\t<details><summary>pointClippingBehavior               = <div "
3891                             "class='val'>%u</div></summary></details>\n",
3892                             pt_clip_props->pointClippingBehavior);
3893                     fprintf(out, "\t\t\t\t\t</details>\n");
3894                 } else if (human_readable_output) {
3895                     printf("\nVkPhysicalDevicePointClippingProperties:\n");
3896                     printf("========================================\n");
3897                     printf("\tpointClippingBehavior               = %u\n", pt_clip_props->pointClippingBehavior);
3898                 }
3899             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR &&
3900                        CheckPhysicalDeviceExtensionIncluded(VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME, gpu->device_extensions,
3901                                                             gpu->device_extension_count)) {
3902                 VkPhysicalDevicePushDescriptorPropertiesKHR *push_desc_props =
3903                     (VkPhysicalDevicePushDescriptorPropertiesKHR *)structure;
3904                 if (html_output) {
3905                     fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDevicePushDescriptorProperties</summary>\n");
3906                     fprintf(out,
3907                             "\t\t\t\t\t\t<details><summary>maxPushDescriptors                = <div "
3908                             "class='val'>%u</div></summary></details>\n",
3909                             push_desc_props->maxPushDescriptors);
3910                     fprintf(out, "\t\t\t\t\t</details>\n");
3911                 } else if (human_readable_output) {
3912                     printf("\nVkPhysicalDevicePushDescriptorProperties:\n");
3913                     printf("=========================================\n");
3914                     printf("\tmaxPushDescriptors               = %u\n", push_desc_props->maxPushDescriptors);
3915                 }
3916             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT &&
3917                        CheckPhysicalDeviceExtensionIncluded(VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME, gpu->device_extensions,
3918                                                             gpu->device_extension_count)) {
3919                 VkPhysicalDeviceDiscardRectanglePropertiesEXT *discard_rect_props =
3920                     (VkPhysicalDeviceDiscardRectanglePropertiesEXT *)structure;
3921                 if (html_output) {
3922                     fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceDiscardRectangleProperties</summary>\n");
3923                     fprintf(out,
3924                             "\t\t\t\t\t\t<details><summary>maxDiscardRectangles               = <div "
3925                             "class='val'>%u</div></summary></details>\n",
3926                             discard_rect_props->maxDiscardRectangles);
3927                     fprintf(out, "\t\t\t\t\t</details>\n");
3928                 } else if (human_readable_output) {
3929                     printf("\nVkPhysicalDeviceDiscardRectangleProperties:\n");
3930                     printf("===========================================\n");
3931                     printf("\tmaxDiscardRectangles               = %u\n", discard_rect_props->maxDiscardRectangles);
3932                 }
3933             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR &&
3934                        CheckPhysicalDeviceExtensionIncluded(VK_KHR_MULTIVIEW_EXTENSION_NAME, gpu->device_extensions,
3935                                                             gpu->device_extension_count)) {
3936                 VkPhysicalDeviceMultiviewPropertiesKHR *multiview_props = (VkPhysicalDeviceMultiviewPropertiesKHR *)structure;
3937                 if (html_output) {
3938                     fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceMultiviewProperties</summary>\n");
3939                     fprintf(
3940                         out,
3941                         "\t\t\t\t\t\t<details><summary>maxMultiviewViewCount     = <div class='val'>%u</div></summary></details>\n",
3942                         multiview_props->maxMultiviewViewCount);
3943                     fprintf(
3944                         out,
3945                         "\t\t\t\t\t\t<details><summary>maxMultiviewInstanceIndex = <div class='val'>%u</div></summary></details>\n",
3946                         multiview_props->maxMultiviewInstanceIndex);
3947                     fprintf(out, "\t\t\t\t\t</details>\n");
3948                 } else if (human_readable_output) {
3949                     printf("\nVkPhysicalDeviceMultiviewProperties:\n");
3950                     printf("====================================\n");
3951                     printf("\tmaxMultiviewViewCount     = %u\n", multiview_props->maxMultiviewViewCount);
3952                     printf("\tmaxMultiviewInstanceIndex = %u\n", multiview_props->maxMultiviewInstanceIndex);
3953                 }
3954             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES_KHR) {
3955                 VkPhysicalDeviceMaintenance3PropertiesKHR *maintenance3_props =
3956                     (VkPhysicalDeviceMaintenance3PropertiesKHR *)structure;
3957                 if (html_output) {
3958                     fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceMaintenance3Properties</summary>\n");
3959                     fprintf(out,
3960                             "\t\t\t\t\t\t<details><summary>maxPerSetDescriptors    = <div class='val'>%" PRIuLEAST32
3961                             "</div></summary></details>\n",
3962                             maintenance3_props->maxPerSetDescriptors);
3963                     fprintf(out,
3964                             "\t\t\t\t\t\t<details><summary>maxMemoryAllocationSize = <div class='val'>%" PRIuLEAST64
3965                             "</div></summary></details>\n",
3966                             maintenance3_props->maxMemoryAllocationSize);
3967                     fprintf(out, "\t\t\t\t\t</details>\n");
3968                 } else if (human_readable_output) {
3969                     printf("\nVkPhysicalDeviceMaintenance3Properties:\n");
3970                     printf("=======================================\n");
3971                     printf("\tmaxPerSetDescriptors    = %" PRIuLEAST32 "\n", maintenance3_props->maxPerSetDescriptors);
3972                     printf("\tmaxMemoryAllocationSize = %" PRIuLEAST64 "\n", maintenance3_props->maxMemoryAllocationSize);
3973                 }
3974             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR) {
3975                 const VkPhysicalDeviceIDPropertiesKHR *id_props = (VkPhysicalDeviceIDPropertiesKHR *)structure;
3976                 if (html_output) {
3977                     fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceIDProperties</summary>\n");
3978                     // Visual Studio 2013's printf does not support the "hh"
3979                     // length modifier so cast the operands and use field width
3980                     // "2" to fake it.
3981                     fprintf(out,
3982                             "\t\t\t\t\t\t<details><summary>deviceUUID      = <div "
3983                             "class='val'>%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x</div></summary></"
3984                             "details>\n",
3985                             (uint32_t)id_props->deviceUUID[0], (uint32_t)id_props->deviceUUID[1], (uint32_t)id_props->deviceUUID[2],
3986                             (uint32_t)id_props->deviceUUID[3], (uint32_t)id_props->deviceUUID[4], (uint32_t)id_props->deviceUUID[5],
3987                             (uint32_t)id_props->deviceUUID[6], (uint32_t)id_props->deviceUUID[7], (uint32_t)id_props->deviceUUID[8],
3988                             (uint32_t)id_props->deviceUUID[9], (uint32_t)id_props->deviceUUID[10],
3989                             (uint32_t)id_props->deviceUUID[11], (uint32_t)id_props->deviceUUID[12],
3990                             (uint32_t)id_props->deviceUUID[13], (uint32_t)id_props->deviceUUID[14],
3991                             (uint32_t)id_props->deviceUUID[15]);
3992                     fprintf(out,
3993                             "\t\t\t\t\t\t<details><summary>driverUUID      = <div "
3994                             "class='val'>%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x</div></summary></"
3995                             "details>\n",
3996                             (uint32_t)id_props->driverUUID[0], (uint32_t)id_props->driverUUID[1], (uint32_t)id_props->driverUUID[2],
3997                             (uint32_t)id_props->driverUUID[3], (uint32_t)id_props->driverUUID[4], (uint32_t)id_props->driverUUID[5],
3998                             (uint32_t)id_props->driverUUID[6], (uint32_t)id_props->driverUUID[7], (uint32_t)id_props->driverUUID[8],
3999                             (uint32_t)id_props->driverUUID[9], (uint32_t)id_props->driverUUID[10],
4000                             (uint32_t)id_props->driverUUID[11], (uint32_t)id_props->driverUUID[12],
4001                             (uint32_t)id_props->driverUUID[13], (uint32_t)id_props->driverUUID[14],
4002                             (uint32_t)id_props->driverUUID[15]);
4003                     fprintf(out, "\t\t\t\t\t\t<details><summary>deviceLUIDValid = <div class='val'>%s</div></summary></details>\n",
4004                             id_props->deviceLUIDValid ? "true" : "false");
4005                     if (id_props->deviceLUIDValid) {
4006                         fprintf(out,
4007                                 "\t\t\t\t\t\t<details><summary>deviceLUID      = <div "
4008                                 "class='val'>%02x%02x%02x%02x-%02x%02x%02x%02x</div></summary></details>\n",
4009                                 (uint32_t)id_props->deviceLUID[0], (uint32_t)id_props->deviceLUID[1],
4010                                 (uint32_t)id_props->deviceLUID[2], (uint32_t)id_props->deviceLUID[3],
4011                                 (uint32_t)id_props->deviceLUID[4], (uint32_t)id_props->deviceLUID[5],
4012                                 (uint32_t)id_props->deviceLUID[6], (uint32_t)id_props->deviceLUID[7]);
4013                         fprintf(
4014                             out,
4015                             "\t\t\t\t\t\t<details><summary>deviceNodeMask  = <div class='val'>0x%08x</div></summary></details>\n",
4016                             id_props->deviceNodeMask);
4017                     }
4018                     fprintf(out, "\t\t\t\t\t</details>\n");
4019                 } else if (human_readable_output) {
4020                     printf("\nVkPhysicalDeviceIDProperties:\n");
4021                     printf("=========================================\n");
4022                     printf("\tdeviceUUID      = %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
4023                            (uint32_t)id_props->deviceUUID[0], (uint32_t)id_props->deviceUUID[1], (uint32_t)id_props->deviceUUID[2],
4024                            (uint32_t)id_props->deviceUUID[3], (uint32_t)id_props->deviceUUID[4], (uint32_t)id_props->deviceUUID[5],
4025                            (uint32_t)id_props->deviceUUID[6], (uint32_t)id_props->deviceUUID[7], (uint32_t)id_props->deviceUUID[8],
4026                            (uint32_t)id_props->deviceUUID[9], (uint32_t)id_props->deviceUUID[10],
4027                            (uint32_t)id_props->deviceUUID[11], (uint32_t)id_props->deviceUUID[12],
4028                            (uint32_t)id_props->deviceUUID[13], (uint32_t)id_props->deviceUUID[14],
4029                            (uint32_t)id_props->deviceUUID[15]);
4030                     printf("\tdriverUUID      = %02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
4031                            (uint32_t)id_props->driverUUID[0], (uint32_t)id_props->driverUUID[1], (uint32_t)id_props->driverUUID[2],
4032                            (uint32_t)id_props->driverUUID[3], (uint32_t)id_props->driverUUID[4], (uint32_t)id_props->driverUUID[5],
4033                            (uint32_t)id_props->driverUUID[6], (uint32_t)id_props->driverUUID[7], (uint32_t)id_props->driverUUID[8],
4034                            (uint32_t)id_props->driverUUID[9], (uint32_t)id_props->driverUUID[10],
4035                            (uint32_t)id_props->driverUUID[11], (uint32_t)id_props->driverUUID[12],
4036                            (uint32_t)id_props->driverUUID[13], (uint32_t)id_props->driverUUID[14],
4037                            (uint32_t)id_props->driverUUID[15]);
4038                     printf("\tdeviceLUIDValid = %s\n", id_props->deviceLUIDValid ? "true" : "false");
4039                     if (id_props->deviceLUIDValid) {
4040                         printf("\tdeviceLUID      = %02x%02x%02x%02x-%02x%02x%02x%02x\n", (uint32_t)id_props->deviceLUID[0],
4041                                (uint32_t)id_props->deviceLUID[1], (uint32_t)id_props->deviceLUID[2],
4042                                (uint32_t)id_props->deviceLUID[3], (uint32_t)id_props->deviceLUID[4],
4043                                (uint32_t)id_props->deviceLUID[5], (uint32_t)id_props->deviceLUID[6],
4044                                (uint32_t)id_props->deviceLUID[7]);
4045                         printf("\tdeviceNodeMask  = 0x%08x\n", id_props->deviceNodeMask);
4046                     }
4047                 }
4048             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR &&
4049                        CheckPhysicalDeviceExtensionIncluded(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME, gpu->device_extensions,
4050                                                             gpu->device_extension_count)) {
4051                 VkPhysicalDeviceDriverPropertiesKHR *driver_props = (VkPhysicalDeviceDriverPropertiesKHR *)structure;
4052                 if (html_output) {
4053                     fprintf(out, "\n\t\t\t\t\t<details><summary>VkPhysicalDeviceDriverProperties</summary>\n");
4054                     fprintf(out,
4055                             "\t\t\t\t\t\t<details><summary>driverID   = <div class='val'>%" PRIuLEAST32
4056                             "</div></summary></details>\n",
4057                             driver_props->driverID);
4058                     fprintf(out, "\t\t\t\t\t\t<details><summary>driverName = %s</summary></details>\n", driver_props->driverName);
4059                     fprintf(out, "\t\t\t\t\t\t<details><summary>driverInfo = %s</summary></details>\n", driver_props->driverInfo);
4060                     fprintf(out, "\t\t\t\t\t\t<details><summary>conformanceVersion:</summary></details>\n");
4061                     fprintf(out,
4062                             "\t\t\t\t\t\t\t<details><summary>major    = <div class='val'>%" PRIuLEAST8
4063                             "</div></summary></details>\n",
4064                             driver_props->conformanceVersion.major);
4065                     fprintf(out,
4066                             "\t\t\t\t\t\t\t<details><summary>minor    = <div class='val'>%" PRIuLEAST8
4067                             "</div></summary></details>\n",
4068                             driver_props->conformanceVersion.minor);
4069                     fprintf(out,
4070                             "\t\t\t\t\t\t\t<details><summary>subminor = <div class='val'>%" PRIuLEAST8
4071                             "</div></summary></details>\n",
4072                             driver_props->conformanceVersion.subminor);
4073                     fprintf(out,
4074                             "\t\t\t\t\t\t\t<details><summary>patch    = <div class='val'>%" PRIuLEAST8
4075                             "</div></summary></details>\n",
4076                             driver_props->conformanceVersion.patch);
4077                     fprintf(out, "\t\t\t\t\t</details>\n");
4078                 } else if (human_readable_output) {
4079                     printf("\nVkPhysicalDeviceDriverProperties:\n");
4080                     printf("=================================\n");
4081                     printf("\tdriverID   = %" PRIuLEAST32 "\n", driver_props->driverID);
4082                     printf("\tdriverName = %s\n", driver_props->driverName);
4083                     printf("\tdriverInfo = %s\n", driver_props->driverInfo);
4084                     printf("\tconformanceVersion:\n");
4085                     printf("\t\tmajor    = %" PRIuLEAST8 "\n", driver_props->conformanceVersion.major);
4086                     printf("\t\tminor    = %" PRIuLEAST8 "\n", driver_props->conformanceVersion.minor);
4087                     printf("\t\tsubminor = %" PRIuLEAST8 "\n", driver_props->conformanceVersion.subminor);
4088                     printf("\t\tpatch    = %" PRIuLEAST8 "\n", driver_props->conformanceVersion.patch);
4089                 }
4090             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR &&
4091                        CheckPhysicalDeviceExtensionIncluded(VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME, gpu->device_extensions,
4092                                                             gpu->device_extension_count)) {
4093                 VkPhysicalDeviceFloatControlsPropertiesKHR *float_control_props =
4094                     (VkPhysicalDeviceFloatControlsPropertiesKHR *)structure;
4095                 if (html_output) {
4096                     fprintf(out, "\n\t\t\t\t\t<details><summary>VkPhysicalDeviceFloatControlsProperties</summary>\n");
4097                     fprintf(out,
4098                             "\t\t\t\t\t\t<details><summary>separateDenormSettings       = <div class='val'>%" PRIuLEAST32
4099                             "</div></summary></details>\n",
4100                             float_control_props->separateDenormSettings);
4101                     fprintf(out,
4102                             "\t\t\t\t\t\t<details><summary>separateRoundingModeSettings = <div class='val'>%" PRIuLEAST32
4103                             "</div></summary></details>\n",
4104                             float_control_props->separateRoundingModeSettings);
4105                     fprintf(out,
4106                             "\t\t\t\t\t\t<details><summary>shaderSignedZeroInfNanPreserveFloat16 = <div class='val'>%" PRIuLEAST32
4107                             "</div></summary></details>\n",
4108                             float_control_props->shaderSignedZeroInfNanPreserveFloat16);
4109                     fprintf(out,
4110                             "\t\t\t\t\t\t<details><summary>shaderSignedZeroInfNanPreserveFloat32 = <div class='val'>%" PRIuLEAST32
4111                             "</div></summary></details>\n",
4112                             float_control_props->shaderSignedZeroInfNanPreserveFloat32);
4113                     fprintf(out,
4114                             "\t\t\t\t\t\t<details><summary>shaderSignedZeroInfNanPreserveFloat64 = <div class='val'>%" PRIuLEAST32
4115                             "</div></summary></details>\n",
4116                             float_control_props->shaderSignedZeroInfNanPreserveFloat64);
4117                     fprintf(out,
4118                             "\t\t\t\t\t\t<details><summary>shaderDenormPreserveFloat16           = <div class='val'>%" PRIuLEAST32
4119                             "</div></summary></details>\n",
4120                             float_control_props->shaderDenormPreserveFloat16);
4121                     fprintf(out,
4122                             "\t\t\t\t\t\t<details><summary>shaderDenormPreserveFloat32           = <div class='val'>%" PRIuLEAST32
4123                             "</div></summary></details>\n",
4124                             float_control_props->shaderDenormPreserveFloat32);
4125                     fprintf(out,
4126                             "\t\t\t\t\t\t<details><summary>shaderDenormPreserveFloat64           = <div class='val'>%" PRIuLEAST32
4127                             "</div></summary></details>\n",
4128                             float_control_props->shaderDenormPreserveFloat64);
4129                     fprintf(out,
4130                             "\t\t\t\t\t\t<details><summary>shaderDenormFlushToZeroFloat16        = <div class='val'>%" PRIuLEAST32
4131                             "</div></summary></details>\n",
4132                             float_control_props->shaderDenormFlushToZeroFloat16);
4133                     fprintf(out,
4134                             "\t\t\t\t\t\t<details><summary>shaderDenormFlushToZeroFloat32        = <div class='val'>%" PRIuLEAST32
4135                             "</div></summary></details>\n",
4136                             float_control_props->shaderDenormFlushToZeroFloat32);
4137                     fprintf(out,
4138                             "\t\t\t\t\t\t<details><summary>shaderDenormFlushToZeroFloat64        = <div class='val'>%" PRIuLEAST32
4139                             "</div></summary></details>\n",
4140                             float_control_props->shaderDenormFlushToZeroFloat64);
4141                     fprintf(out,
4142                             "\t\t\t\t\t\t<details><summary>shaderRoundingModeRTEFloat16          = <div class='val'>%" PRIuLEAST32
4143                             "</div></summary></details>\n",
4144                             float_control_props->shaderRoundingModeRTEFloat16);
4145                     fprintf(out,
4146                             "\t\t\t\t\t\t<details><summary>shaderRoundingModeRTEFloat32          = <div class='val'>%" PRIuLEAST32
4147                             "</div></summary></details>\n",
4148                             float_control_props->shaderRoundingModeRTEFloat32);
4149                     fprintf(out,
4150                             "\t\t\t\t\t\t<details><summary>shaderRoundingModeRTEFloat64          = <div class='val'>%" PRIuLEAST32
4151                             "</div></summary></details>\n",
4152                             float_control_props->shaderRoundingModeRTEFloat64);
4153                     fprintf(out,
4154                             "\t\t\t\t\t\t<details><summary>shaderRoundingModeRTZFloat16          = <div class='val'>%" PRIuLEAST32
4155                             "</div></summary></details>\n",
4156                             float_control_props->shaderRoundingModeRTZFloat16);
4157                     fprintf(out,
4158                             "\t\t\t\t\t\t<details><summary>shaderRoundingModeRTZFloat32          = <div class='val'>%" PRIuLEAST32
4159                             "</div></summary></details>\n",
4160                             float_control_props->shaderRoundingModeRTZFloat32);
4161                     fprintf(out,
4162                             "\t\t\t\t\t\t<details><summary>shaderRoundingModeRTZFloat64          = <div class='val'>%" PRIuLEAST32
4163                             "</div></summary></details>\n",
4164                             float_control_props->shaderRoundingModeRTZFloat64);
4165                     fprintf(out, "\t\t\t\t\t</details>\n");
4166                 } else if (human_readable_output) {
4167                     printf("\nVkPhysicalDeviceFloatControlsProperties:\n");
4168                     printf("========================================\n");
4169                     printf("\tseparateDenormSettings       = %" PRIuLEAST32 "\n", float_control_props->separateDenormSettings);
4170                     printf("\tseparateRoundingModeSettings = %" PRIuLEAST32 "\n",
4171                            float_control_props->separateRoundingModeSettings);
4172                     printf("\tshaderSignedZeroInfNanPreserveFloat16 = %" PRIuLEAST32 "\n",
4173                            float_control_props->shaderSignedZeroInfNanPreserveFloat16);
4174                     printf("\tshaderSignedZeroInfNanPreserveFloat32 = %" PRIuLEAST32 "\n",
4175                            float_control_props->shaderSignedZeroInfNanPreserveFloat32);
4176                     printf("\tshaderSignedZeroInfNanPreserveFloat64 = %" PRIuLEAST32 "\n",
4177                            float_control_props->shaderSignedZeroInfNanPreserveFloat64);
4178                     printf("\tshaderDenormPreserveFloat16          = %" PRIuLEAST32 "\n",
4179                            float_control_props->shaderDenormPreserveFloat16);
4180                     printf("\tshaderDenormPreserveFloat32           = %" PRIuLEAST32 "\n",
4181                            float_control_props->shaderDenormPreserveFloat32);
4182                     printf("\tshaderDenormPreserveFloat64           = %" PRIuLEAST32 "\n",
4183                            float_control_props->shaderDenormPreserveFloat64);
4184                     printf("\tshaderDenormFlushToZeroFloat16        = %" PRIuLEAST32 "\n",
4185                            float_control_props->shaderDenormFlushToZeroFloat16);
4186                     printf("\tshaderDenormFlushToZeroFloat32        = %" PRIuLEAST32 "\n",
4187                            float_control_props->shaderDenormFlushToZeroFloat32);
4188                     printf("\tshaderDenormFlushToZeroFloat64        = %" PRIuLEAST32 "\n",
4189                            float_control_props->shaderDenormFlushToZeroFloat64);
4190                     printf("\tshaderRoundingModeRTEFloat16          = %" PRIuLEAST32 "\n",
4191                            float_control_props->shaderRoundingModeRTEFloat16);
4192                     printf("\tshaderRoundingModeRTEFloat32          = %" PRIuLEAST32 "\n",
4193                            float_control_props->shaderRoundingModeRTEFloat32);
4194                     printf("\tshaderRoundingModeRTEFloat64         = %" PRIuLEAST32 "\n",
4195                            float_control_props->shaderRoundingModeRTEFloat64);
4196                     printf("\tshaderRoundingModeRTZFloat16          = %" PRIuLEAST32 "\n",
4197                            float_control_props->shaderRoundingModeRTZFloat16);
4198                     printf("\tshaderRoundingModeRTZFloat32          = %" PRIuLEAST32 "\n",
4199                            float_control_props->shaderRoundingModeRTZFloat32);
4200                     printf("\tshaderRoundingModeRTZFloat64          = %" PRIuLEAST32 "\n",
4201                            float_control_props->shaderRoundingModeRTZFloat64);
4202                 }
4203             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT &&
4204                        CheckPhysicalDeviceExtensionIncluded(VK_EXT_PCI_BUS_INFO_EXTENSION_NAME, gpu->device_extensions,
4205                                                             gpu->device_extension_count)) {
4206                 VkPhysicalDevicePCIBusInfoPropertiesEXT *pci_bus_properties = (VkPhysicalDevicePCIBusInfoPropertiesEXT *)structure;
4207                 if (html_output) {
4208                     fprintf(out, "\n\t\t\t\t\t<details><summary>VkPhysicalDevicePCIBusInfoProperties</summary>\n");
4209                     fprintf(out,
4210                             "\t\t\t\t\t\t<details><summary>pciDomain   = <div class='val'>%" PRIuLEAST32
4211                             "</div></summary></details>\n",
4212                             pci_bus_properties->pciDomain);
4213                     fprintf(out,
4214                             "\t\t\t\t\t\t<details><summary>pciBus      = <div class='val'>%" PRIuLEAST32
4215                             "</div></summary></details>\n",
4216                             pci_bus_properties->pciBus);
4217                     fprintf(out,
4218                             "\t\t\t\t\t\t<details><summary>pciDevice   = <div class='val'>%" PRIuLEAST32
4219                             "</div></summary></details>\n",
4220                             pci_bus_properties->pciDevice);
4221                     fprintf(out,
4222                             "\t\t\t\t\t\t<details><summary>pciFunction = <div class='val'>%" PRIuLEAST32
4223                             "</div></summary></details>\n",
4224                             pci_bus_properties->pciFunction);
4225                 } else if (human_readable_output) {
4226                     printf("\nVkPhysicalDevicePCIBusInfoProperties\n");
4227                     printf("====================================\n");
4228                     printf("\tpciDomain   = %" PRIuLEAST32 "\n", pci_bus_properties->pciDomain);
4229                     printf("\tpciBus      = %" PRIuLEAST32 "\n", pci_bus_properties->pciBus);
4230                     printf("\tpciDevice   = %" PRIuLEAST32 "\n", pci_bus_properties->pciDevice);
4231                     printf("\tpciFunction = %" PRIuLEAST32 "\n", pci_bus_properties->pciFunction);
4232                 }
4233             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT &&
4234                        CheckPhysicalDeviceExtensionIncluded(VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, gpu->device_extensions,
4235                                                             gpu->device_extension_count)) {
4236                 VkPhysicalDeviceTransformFeedbackPropertiesEXT *transform_feedback_properties =
4237                     (VkPhysicalDeviceTransformFeedbackPropertiesEXT *)structure;
4238                 if (html_output) {
4239                     fprintf(out, "\n\t\t\t\t\t<details><summary>VkPhysicalDeviceTransformFeedbackProperties</summary>\n");
4240                     fprintf(
4241                         out,
4242                         "\t\t\t\t\t\t<details><summary>maxTransformFeedbackStreams                = <div class='val'>%" PRIuLEAST32
4243                         "</div></summary></details>\n",
4244                         transform_feedback_properties->maxTransformFeedbackStreams);
4245                     fprintf(
4246                         out,
4247                         "\t\t\t\t\t\t<details><summary>maxTransformFeedbackBuffers                = <div class='val'>%" PRIuLEAST32
4248                         "</div></summary></details>\n",
4249                         transform_feedback_properties->maxTransformFeedbackBuffers);
4250                     fprintf(
4251                         out,
4252                         "\t\t\t\t\t\t<details><summary>maxTransformFeedbackBufferSize             = <div class='val'>%" PRIuLEAST64
4253                         "</div></summary></details>\n",
4254                         transform_feedback_properties->maxTransformFeedbackBufferSize);
4255                     fprintf(
4256                         out,
4257                         "\t\t\t\t\t\t<details><summary>maxTransformFeedbackStreamDataSize         = <div class='val'>%" PRIuLEAST32
4258                         "</div></summary></details>\n",
4259                         transform_feedback_properties->maxTransformFeedbackStreamDataSize);
4260                     fprintf(
4261                         out,
4262                         "\t\t\t\t\t\t<details><summary>maxTransformFeedbackBufferDataSize         = <div class='val'>%" PRIuLEAST32
4263                         "</div></summary></details>\n",
4264                         transform_feedback_properties->maxTransformFeedbackBufferDataSize);
4265                     fprintf(
4266                         out,
4267                         "\t\t\t\t\t\t<details><summary>maxTransformFeedbackBufferDataStride       = <div class='val'>%" PRIuLEAST32
4268                         "</div></summary></details>\n",
4269                         transform_feedback_properties->maxTransformFeedbackBufferDataStride);
4270                     fprintf(
4271                         out,
4272                         "\t\t\t\t\t\t<details><summary>transformFeedbackQueries                   = <div class='val'>%" PRIuLEAST32
4273                         "</div></summary></details>\n",
4274                         transform_feedback_properties->transformFeedbackQueries);
4275                     fprintf(
4276                         out,
4277                         "\t\t\t\t\t\t<details><summary>transformFeedbackStreamsLinesTriangles     = <div class='val'>%" PRIuLEAST32
4278                         "</div></summary></details>\n",
4279                         transform_feedback_properties->transformFeedbackStreamsLinesTriangles);
4280                     fprintf(
4281                         out,
4282                         "\t\t\t\t\t\t<details><summary>transformFeedbackRasterizationStreamSelect = <div class='val'>%" PRIuLEAST32
4283                         "</div></summary></details>\n",
4284                         transform_feedback_properties->transformFeedbackRasterizationStreamSelect);
4285                     fprintf(
4286                         out,
4287                         "\t\t\t\t\t\t<details><summary>transformFeedbackDraw                      = <div class='val'>%" PRIuLEAST32
4288                         "</div></summary></details>\n",
4289                         transform_feedback_properties->transformFeedbackDraw);
4290                 } else if (human_readable_output) {
4291                     printf("\nVkPhysicalDeviceTransformFeedbackProperties\n");
4292                     printf("===========================================\n");
4293                     printf("\tmaxTransformFeedbackStreams                = %" PRIuLEAST32 "\n",
4294                            transform_feedback_properties->maxTransformFeedbackStreams);
4295                     printf("\tmaxTransformFeedbackBuffers                = %" PRIuLEAST32 "\n",
4296                            transform_feedback_properties->maxTransformFeedbackBuffers);
4297                     printf("\tmaxTransformFeedbackBufferSize             = %" PRIuLEAST64 "\n",
4298                            transform_feedback_properties->maxTransformFeedbackBufferSize);
4299                     printf("\tmaxTransformFeedbackStreamDataSize         = %" PRIuLEAST32 "\n",
4300                            transform_feedback_properties->maxTransformFeedbackStreamDataSize);
4301                     printf("\tmaxTransformFeedbackBufferDataSize         = %" PRIuLEAST32 "\n",
4302                            transform_feedback_properties->maxTransformFeedbackBufferDataSize);
4303                     printf("\tmaxTransformFeedbackBufferDataStride       = %" PRIuLEAST32 "\n",
4304                            transform_feedback_properties->maxTransformFeedbackBufferDataStride);
4305                     printf("\ttransformFeedbackQueries                   = %" PRIuLEAST32 "\n",
4306                            transform_feedback_properties->transformFeedbackQueries);
4307                     printf("\ttransformFeedbackStreamsLinesTriangles     = %" PRIuLEAST32 "\n",
4308                            transform_feedback_properties->transformFeedbackStreamsLinesTriangles);
4309                     printf("\ttransformFeedbackRasterizationStreamSelect = %" PRIuLEAST32 "\n",
4310                            transform_feedback_properties->transformFeedbackRasterizationStreamSelect);
4311                     printf("\ttransformFeedbackDraw                      = %" PRIuLEAST32 "\n",
4312                            transform_feedback_properties->transformFeedbackDraw);
4313                 }
4314             } else if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT &&
4315                        CheckPhysicalDeviceExtensionIncluded(VK_EXT_FRAGMENT_DENSITY_MAP_EXTENSION_NAME, gpu->device_extensions,
4316                                                             gpu->device_extension_count)) {
4317                 VkPhysicalDeviceFragmentDensityMapPropertiesEXT *fragment_density_map_properties =
4318                     (VkPhysicalDeviceFragmentDensityMapPropertiesEXT *)structure;
4319                 if (html_output) {
4320                     fprintf(out, "\n\t\t\t\t\t<details><summary>VkPhysicalDeviceFragmentDensityMapProperties</summary>\n");
4321                     fprintf(out, "\t\t\t\t\t\t<details><summary>minFragmentDensityTexelSize</summary>\n");
4322                     fprintf(out,
4323                             "\t\t\t\t\t\t\t<details><summary>width = <div class='val'>%" PRIuLEAST32 "</div></summary></details>\n",
4324                             fragment_density_map_properties->minFragmentDensityTexelSize.width);
4325                     fprintf(out,
4326                             "\t\t\t\t\t\t\t<details><summary>height = <div class='val'>%" PRIuLEAST32
4327                             "</div></summary></details>\n",
4328                             fragment_density_map_properties->minFragmentDensityTexelSize.height);
4329                     fprintf(out, "\t\t\t\t\t\t<details><summary>maxFragmentDensityTexelSize</summary>\n");
4330                     fprintf(out,
4331                             "\t\t\t\t\t\t\t<details><summary>width = <div class='val'>%" PRIuLEAST32 "</div></summary></details>\n",
4332                             fragment_density_map_properties->maxFragmentDensityTexelSize.width);
4333                     fprintf(out,
4334                             "\t\t\t\t\t\t\t<details><summary>height = <div class='val'>%" PRIuLEAST32
4335                             "</div></summary></details>\n",
4336                             fragment_density_map_properties->maxFragmentDensityTexelSize.height);
4337                     fprintf(out,
4338                             "\t\t\t\t\t\t<details><summary>fragmentDensityInvocations = <div class='val'>%" PRIuLEAST32
4339                             "</div></summary></details>\n",
4340                             fragment_density_map_properties->fragmentDensityInvocations);
4341                 } else if (human_readable_output) {
4342                     printf("\nVkPhysicalDeviceFragmentDensityMapProperties\n");
4343                     printf("============================================\n");
4344                     printf("\tminFragmentDensityTexelSize\n");
4345                     printf("\t\twidth = %" PRIuLEAST32 "\n", fragment_density_map_properties->minFragmentDensityTexelSize.width);
4346                     printf("\t\theight = %" PRIuLEAST32 "\n", fragment_density_map_properties->minFragmentDensityTexelSize.height);
4347                     printf("\tmaxFragmentDensityTexelSize\n");
4348                     printf("\t\twidth = %" PRIuLEAST32 "\n", fragment_density_map_properties->maxFragmentDensityTexelSize.width);
4349                     printf("\t\theight = %" PRIuLEAST32 "\n", fragment_density_map_properties->maxFragmentDensityTexelSize.height);
4350                     printf("\tfragmentDensityInvocations = %" PRIuLEAST32 "\n",
4351                            fragment_density_map_properties->fragmentDensityInvocations);
4352                 }
4353             }
4354             place = structure->pNext;
4355         }
4356     }
4357
4358     fflush(out);
4359     fflush(stdout);
4360 }
4361
4362 // Compare function for sorting extensions by name
4363 static int CompareExtensionName(const void *a, const void *b) {
4364     const char *this = ((const VkExtensionProperties *)a)->extensionName;
4365     const char *that = ((const VkExtensionProperties *)b)->extensionName;
4366     return strcmp(this, that);
4367 }
4368
4369 // Compare function for sorting layers by name
4370 static int CompareLayerName(const void *a, const void *b) {
4371     const char *this = ((const struct LayerExtensionList *)a)->layer_properties.layerName;
4372     const char *that = ((const struct LayerExtensionList *)b)->layer_properties.layerName;
4373     return strcmp(this, that);
4374 }
4375
4376 static void AppDumpExtensions(const char *indent, const char *layer_name, const uint32_t extension_count,
4377                               VkExtensionProperties *extension_properties, FILE *out) {
4378     if (html_output) {
4379         fprintf(out, "\t\t\t%s<details><summary>", indent);
4380     }
4381     if (layer_name && (strlen(layer_name) > 0)) {
4382         if (html_output) {
4383             fprintf(out, "%s Extensions", layer_name);
4384         } else if (human_readable_output) {
4385             printf("%s%s Extensions", indent, layer_name);
4386         }
4387     } else {
4388         if (html_output) {
4389             fprintf(out, "Extensions");
4390         } else if (human_readable_output) {
4391             printf("%sExtensions", indent);
4392         }
4393     }
4394     if (html_output) {
4395         fprintf(out, "\tcount = <div class='val'>%d</div></summary>", extension_count);
4396         if (extension_count > 0) {
4397             fprintf(out, "\n");
4398         }
4399     } else if (human_readable_output) {
4400         printf("\tcount = %d\n", extension_count);
4401     }
4402
4403     const bool is_device_type = strcmp(layer_name, "Device") == 0;
4404     if (is_device_type && json_output) {
4405         printf(",\n");
4406         printf("\t\"ArrayOfVkExtensionProperties\": [");
4407     }
4408
4409     qsort(extension_properties, extension_count, sizeof(VkExtensionProperties), CompareExtensionName);
4410
4411     for (uint32_t i = 0; i < extension_count; ++i) {
4412         VkExtensionProperties const *ext_prop = &extension_properties[i];
4413         if (html_output) {
4414             fprintf(out, "\t\t\t\t%s<details><summary>", indent);
4415             fprintf(out, "<div class='type'>%s</div>: extension revision <div class='val'>%d</div>", ext_prop->extensionName,
4416                     ext_prop->specVersion);
4417             fprintf(out, "</summary></details>\n");
4418         } else if (human_readable_output) {
4419             printf("%s\t", indent);
4420             printf("%-36s: extension revision %2d\n", ext_prop->extensionName, ext_prop->specVersion);
4421         }
4422         if (is_device_type && json_output) {
4423             if (i > 0) {
4424                 printf(",");
4425             }
4426             printf("\n");
4427             printf("\t\t{\n");
4428             printf("\t\t\t\"extensionName\": \"%s\",\n", ext_prop->extensionName);
4429             printf("\t\t\t\"specVersion\": %u\n", ext_prop->specVersion);
4430             printf("\t\t}");
4431         }
4432     }
4433     if (html_output) {
4434         if (extension_count > 0) {
4435             fprintf(out, "\t\t\t%s</details>\n", indent);
4436         } else {
4437             fprintf(out, "</details>\n");
4438         }
4439     }
4440     if (is_device_type && json_output) {
4441         if (extension_count > 0) {
4442             printf("\n\t");
4443         }
4444         printf("]");
4445     }
4446
4447     fflush(out);
4448     fflush(stdout);
4449 }
4450
4451 static void AppGpuDumpQueueProps(const struct AppGpu *gpu, uint32_t id, FILE *out) {
4452     VkQueueFamilyProperties props;
4453
4454     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
4455                               gpu->inst->inst_extensions_count)) {
4456         const VkQueueFamilyProperties *props2_const = &gpu->queue_props2[id].queueFamilyProperties;
4457         props = *props2_const;
4458     } else {
4459         const VkQueueFamilyProperties *props_const = &gpu->queue_props[id];
4460         props = *props_const;
4461     }
4462
4463     VkBool32 supports_present = VK_FALSE;
4464     if (gpu->inst->surface) {
4465         VkResult err = vkGetPhysicalDeviceSurfaceSupportKHR(gpu->obj, id, gpu->inst->surface, &supports_present);
4466         if (err) ERR_EXIT(err);
4467     }
4468
4469     if (html_output) {
4470         fprintf(out, "\t\t\t\t\t<details><summary>VkQueueFamilyProperties[<div class='val'>%d</div>]</summary>\n", id);
4471         fprintf(out, "\t\t\t\t\t\t<details><summary>queueFlags = ");
4472     } else if (human_readable_output) {
4473         printf("VkQueueFamilyProperties[%d]:\n", id);
4474         printf("===========================\n");
4475         printf("\tqueueFlags         = ");
4476     }
4477     if (html_output || human_readable_output) {
4478         char *sep = "";  // separator character
4479         if (props.queueFlags & VK_QUEUE_GRAPHICS_BIT) {
4480             fprintf(out, "GRAPHICS");
4481             sep = " | ";
4482         }
4483         if (props.queueFlags & VK_QUEUE_COMPUTE_BIT) {
4484             fprintf(out, "%sCOMPUTE", sep);
4485             sep = " | ";
4486         }
4487         if (props.queueFlags & VK_QUEUE_TRANSFER_BIT) {
4488             fprintf(out, "%sTRANSFER", sep);
4489             sep = " | ";
4490         }
4491         if (props.queueFlags & VK_QUEUE_SPARSE_BINDING_BIT) {
4492             fprintf(out, "%sSPARSE", sep);
4493         }
4494     }
4495
4496     if (html_output) {
4497         fprintf(out, "</summary></details>\n");
4498         fprintf(out, "\t\t\t\t\t\t<details><summary>queueCount         = <div class='val'>%u</div></summary></details>\n",
4499                 props.queueCount);
4500         fprintf(out, "\t\t\t\t\t\t<details><summary>timestampValidBits = <div class='val'>%u</div></summary></details>\n",
4501                 props.timestampValidBits);
4502         fprintf(out,
4503                 "\t\t\t\t\t\t<details><summary>minImageTransferGranularity = (<div class='val'>%d</div>, <div "
4504                 "class='val'>%d</div>, <div class='val'>%d</div>)</summary></details>\n",
4505                 props.minImageTransferGranularity.width, props.minImageTransferGranularity.height,
4506                 props.minImageTransferGranularity.depth);
4507         fprintf(out, "\t\t\t\t\t\t<details><summary>present support    = <div class='val'>%s</div></summary></details>\n",
4508                 supports_present ? "true" : "false");
4509         fprintf(out, "\t\t\t\t\t</details>\n");
4510     } else if (human_readable_output) {
4511         printf("\n");
4512         printf("\tqueueCount         = %u\n", props.queueCount);
4513         printf("\ttimestampValidBits = %u\n", props.timestampValidBits);
4514         printf("\tminImageTransferGranularity = (%d, %d, %d)\n", props.minImageTransferGranularity.width,
4515                props.minImageTransferGranularity.height, props.minImageTransferGranularity.depth);
4516         printf("\tpresent support    = %s\n", supports_present ? "true" : "false");
4517     }
4518     if (json_output) {
4519         printf("\t\t{\n");
4520         printf("\t\t\t\"minImageTransferGranularity\": {\n");
4521         printf("\t\t\t\t\"depth\": %u,\n", props.minImageTransferGranularity.depth);
4522         printf("\t\t\t\t\"height\": %u,\n", props.minImageTransferGranularity.height);
4523         printf("\t\t\t\t\"width\": %u\n", props.minImageTransferGranularity.width);
4524         printf("\t\t\t},\n");
4525         printf("\t\t\t\"queueCount\": %u,\n", props.queueCount);
4526         printf("\t\t\t\"queueFlags\": %u,\n", props.queueFlags);
4527         printf("\t\t\t\"timestampValidBits\": %u,\n", props.timestampValidBits);
4528         printf("\t\t\t\"present_support\": %s\n", supports_present ? "\"true\"" : "\"false\"");
4529         printf("\t\t}");
4530     }
4531
4532     fflush(out);
4533     fflush(stdout);
4534 }
4535
4536 // This prints a number of bytes in a human-readable format according to prefixes of the International System of Quantities (ISQ),
4537 // defined in ISO/IEC 80000. The prefixes used here are not SI prefixes, but rather the binary prefixes based on powers of 1024
4538 // (kibi-, mebi-, gibi- etc.).
4539 #define kBufferSize 32
4540
4541 static char *HumanReadable(const size_t sz) {
4542     const char prefixes[] = "KMGTPEZY";
4543     char buf[kBufferSize];
4544     int which = -1;
4545     double result = (double)sz;
4546     while (result > 1024 && which < 7) {
4547         result /= 1024;
4548         ++which;
4549     }
4550
4551     char unit[] = "\0i";
4552     if (which >= 0) {
4553         unit[0] = prefixes[which];
4554     }
4555     snprintf(buf, kBufferSize, "%.2f %sB", result, unit);
4556     return strndup(buf, kBufferSize);
4557 }
4558
4559 static void AppGpuDumpMemoryProps(const struct AppGpu *gpu, FILE *out) {
4560     VkPhysicalDeviceMemoryProperties props;
4561
4562     if (CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME, gpu->inst->inst_extensions,
4563                               gpu->inst->inst_extensions_count)) {
4564         const VkPhysicalDeviceMemoryProperties *props2_const = &gpu->memory_props2.memoryProperties;
4565         props = *props2_const;
4566     } else {
4567         const VkPhysicalDeviceMemoryProperties *props_const = &gpu->memory_props;
4568         props = *props_const;
4569     }
4570
4571     if (html_output) {
4572         fprintf(out, "\t\t\t\t\t<details><summary>VkPhysicalDeviceMemoryProperties</summary>\n");
4573         fprintf(out, "\t\t\t\t\t\t<details><summary>memoryHeapCount = <div class='val'>%u</div></summary>", props.memoryHeapCount);
4574         if (props.memoryHeapCount > 0) {
4575             fprintf(out, "\n");
4576         }
4577     } else if (human_readable_output) {
4578         printf("VkPhysicalDeviceMemoryProperties:\n");
4579         printf("=================================\n");
4580         printf("\tmemoryHeapCount       = %u\n", props.memoryHeapCount);
4581     }
4582     if (json_output) {
4583         printf(",\n");
4584         printf("\t\"VkPhysicalDeviceMemoryProperties\": {\n");
4585         printf("\t\t\"memoryHeaps\": [");
4586     }
4587     for (uint32_t i = 0; i < props.memoryHeapCount; ++i) {
4588         const VkDeviceSize memSize = props.memoryHeaps[i].size;
4589         char *mem_size_human_readable = HumanReadable((const size_t)memSize);
4590
4591         if (html_output) {
4592             fprintf(out, "\t\t\t\t\t\t\t<details><summary>memoryHeaps[<div class='val'>%u</div>]</summary>\n", i);
4593             fprintf(out,
4594                     "\t\t\t\t\t\t\t\t<details><summary>size = <div class='val'>" PRINTF_SIZE_T_SPECIFIER
4595                     "</div> (<div class='val'>0x%" PRIxLEAST64 "</div>) (<div class='val'>%s</div>)</summary></details>\n",
4596                     (size_t)memSize, memSize, mem_size_human_readable);
4597         } else if (human_readable_output) {
4598             printf("\tmemoryHeaps[%u] :\n", i);
4599             printf("\t\tsize          = " PRINTF_SIZE_T_SPECIFIER " (0x%" PRIxLEAST64 ") (%s)\n", (size_t)memSize, memSize,
4600                    mem_size_human_readable);
4601         }
4602         free(mem_size_human_readable);
4603
4604         const VkMemoryHeapFlags heap_flags = props.memoryHeaps[i].flags;
4605         if (html_output) {
4606             fprintf(out, "\t\t\t\t\t\t\t\t<details open><summary>flags</summary>\n");
4607             fprintf(out, "\t\t\t\t\t\t\t\t\t<details><summary>");
4608             fprintf(out, (heap_flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) ? "<div class='type'>VK_MEMORY_HEAP_DEVICE_LOCAL_BIT</div>"
4609                                                                         : "None");
4610             fprintf(out, "</summary></details>\n");
4611             fprintf(out, "\t\t\t\t\t\t\t\t</details>\n");
4612             fprintf(out, "\t\t\t\t\t\t\t</details>\n");
4613         } else if (human_readable_output) {
4614             printf("\t\tflags:\n\t\t\t");
4615             printf((heap_flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) ? "VK_MEMORY_HEAP_DEVICE_LOCAL_BIT\n" : "None\n");
4616         }
4617         if (json_output) {
4618             if (i > 0) {
4619                 printf(",");
4620             }
4621             printf("\n");
4622             printf("\t\t\t{\n");
4623             printf("\t\t\t\t\"flags\": %u,\n", heap_flags);
4624             printf("\t\t\t\t\"size\": " PRINTF_SIZE_T_SPECIFIER "\n", (size_t)memSize);
4625             printf("\t\t\t}");
4626         }
4627     }
4628     if (html_output) {
4629         if (props.memoryHeapCount > 0) {
4630             fprintf(out, "\t\t\t\t\t\t");
4631         }
4632         fprintf(out, "</details>\n");
4633     }
4634     if (json_output) {
4635         if (props.memoryHeapCount > 0) {
4636             printf("\n\t\t");
4637         }
4638         printf("]");
4639     }
4640
4641     if (html_output) {
4642         fprintf(out, "\t\t\t\t\t\t<details><summary>memoryTypeCount = <div class='val'>%u</div></summary>", props.memoryTypeCount);
4643         if (props.memoryTypeCount > 0) {
4644             fprintf(out, "\n");
4645         }
4646     } else if (human_readable_output) {
4647         printf("\tmemoryTypeCount       = %u\n", props.memoryTypeCount);
4648     }
4649     if (json_output) {
4650         printf(",\n");
4651         printf("\t\t\"memoryTypes\": [");
4652     }
4653     for (uint32_t i = 0; i < props.memoryTypeCount; ++i) {
4654         if (html_output) {
4655             fprintf(out, "\t\t\t\t\t\t\t<details><summary>memoryTypes[<div class='val'>%u</div>]</summary>\n", i);
4656             fprintf(out, "\t\t\t\t\t\t\t\t<details><summary>heapIndex = <div class='val'>%u</div></summary></details>\n",
4657                     props.memoryTypes[i].heapIndex);
4658             fprintf(out,
4659                     "\t\t\t\t\t\t\t\t<details open><summary>propertyFlags = <div class='val'>0x%" PRIxLEAST32 "</div></summary>",
4660                     props.memoryTypes[i].propertyFlags);
4661             if (props.memoryTypes[i].propertyFlags == 0) {
4662                 fprintf(out, "</details>\n");
4663             } else {
4664                 fprintf(out, "\n");
4665             }
4666         } else if (human_readable_output) {
4667             printf("\tmemoryTypes[%u] :\n", i);
4668             printf("\t\theapIndex     = %u\n", props.memoryTypes[i].heapIndex);
4669             printf("\t\tpropertyFlags = 0x%" PRIxLEAST32 ":\n", props.memoryTypes[i].propertyFlags);
4670         }
4671         if (json_output) {
4672             if (i > 0) {
4673                 printf(",");
4674             }
4675             printf("\n");
4676             printf("\t\t\t{\n");
4677             printf("\t\t\t\t\"heapIndex\": %u,\n", props.memoryTypes[i].heapIndex);
4678             printf("\t\t\t\t\"propertyFlags\": %u\n", props.memoryTypes[i].propertyFlags);
4679             printf("\t\t\t}");
4680         }
4681
4682         // Print each named flag to html or std output if it is set
4683         const VkFlags flags = props.memoryTypes[i].propertyFlags;
4684         if (html_output) {
4685             if (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
4686                 fprintf(out,
4687                         "\t\t\t\t\t\t\t\t\t<details><summary><div "
4688                         "class='type'>VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT</div></summary></details>\n");
4689             if (flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
4690                 fprintf(out,
4691                         "\t\t\t\t\t\t\t\t\t<details><summary><div "
4692                         "class='type'>VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT</div></summary></details>\n");
4693             if (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
4694                 fprintf(out,
4695                         "\t\t\t\t\t\t\t\t\t<details><summary><div "
4696                         "class='type'>VK_MEMORY_PROPERTY_HOST_COHERENT_BIT</div></summary></details>\n");
4697             if (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT)
4698                 fprintf(out,
4699                         "\t\t\t\t\t\t\t\t\t<details><summary><div "
4700                         "class='type'>VK_MEMORY_PROPERTY_HOST_CACHED_BIT</div></summary></details>\n");
4701             if (flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT)
4702                 fprintf(out,
4703                         "\t\t\t\t\t\t\t\t\t<details><summary><div "
4704                         "class='type'>VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT</div></summary></details>\n");
4705             if (flags & VK_MEMORY_PROPERTY_PROTECTED_BIT)
4706                 fprintf(out,
4707                         "\t\t\t\t\t\t\t\t\t<details><summary><div "
4708                         "class='type'>VK_MEMORY_PROPERTY_PROTECTED_BIT</div></summary></details>\n");
4709             if (props.memoryTypes[i].propertyFlags > 0) fprintf(out, "\t\t\t\t\t\t\t\t</details>\n");
4710             fprintf(out, "\t\t\t\t\t\t\t</details>\n");
4711         } else if (human_readable_output) {
4712             if (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) printf("\t\t\tVK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT\n");
4713             if (flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) printf("\t\t\tVK_MEMORY_PROPERTY_HOST_VISIBLE_BIT\n");
4714             if (flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) printf("\t\t\tVK_MEMORY_PROPERTY_HOST_COHERENT_BIT\n");
4715             if (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) printf("\t\t\tVK_MEMORY_PROPERTY_HOST_CACHED_BIT\n");
4716             if (flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) printf("\t\t\tVK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT\n");
4717             if (flags & VK_MEMORY_PROPERTY_PROTECTED_BIT) printf("\t\t\tVK_MEMORY_PROPERTY_PROTECTED_BIT\n");
4718         }
4719     }
4720     if (html_output) {
4721         if (props.memoryTypeCount > 0) {
4722             fprintf(out, "\t\t\t\t\t\t");
4723         }
4724         fprintf(out, "</details>\n");
4725         fprintf(out, "\t\t\t\t\t</details>\n");
4726     }
4727     if (json_output) {
4728         if (props.memoryTypeCount > 0) {
4729             printf("\n\t\t");
4730         }
4731         printf("]\n");
4732         printf("\t}");
4733     }
4734
4735     fflush(out);
4736     fflush(stdout);
4737 }
4738
4739 static void AppGpuDump(const struct AppGpu *gpu, FILE *out) {
4740     if (html_output) {
4741         fprintf(out, "\t\t\t\t<details><summary>GPU%u</summary>\n", gpu->id);
4742     } else if (human_readable_output) {
4743         printf("\nDevice Properties and Extensions :\n");
4744         printf("==================================\n");
4745         printf("GPU%u\n", gpu->id);
4746     }
4747
4748     AppGpuDumpProps(gpu, out);
4749     if (html_output) {
4750         AppDumpExtensions("\t\t", "Device", gpu->device_extension_count, gpu->device_extensions, out);
4751     } else if (human_readable_output) {
4752         printf("\n");
4753         AppDumpExtensions("", "Device", gpu->device_extension_count, gpu->device_extensions, out);
4754         printf("\n");
4755     }
4756
4757     if (json_output) {
4758         printf(",\n");
4759         printf("\t\"ArrayOfVkQueueFamilyProperties\": [");
4760     }
4761     for (uint32_t i = 0; i < gpu->queue_count; ++i) {
4762         if (json_output) {
4763             if (i > 0) {
4764                 printf(",");
4765             }
4766             printf("\n");
4767         }
4768         AppGpuDumpQueueProps(gpu, i, out);
4769         if (human_readable_output) {
4770             printf("\n");
4771         }
4772     }
4773     if (json_output) {
4774         if (gpu->queue_count > 0) {
4775             printf("\n\t");
4776         }
4777         printf("]");
4778     }
4779
4780     AppGpuDumpMemoryProps(gpu, out);
4781     if (human_readable_output) {
4782         printf("\n");
4783     }
4784
4785     AppGpuDumpFeatures(gpu, out);
4786     if (human_readable_output) {
4787         printf("\n");
4788     }
4789
4790     AppDevDump(gpu, out);
4791     if (html_output) {
4792         fprintf(out, "\t\t\t\t</details>\n");
4793     }
4794 }
4795
4796 static void AppGroupDump(const VkPhysicalDeviceGroupProperties *group, const uint32_t id, const struct AppInstance *inst,
4797                          FILE *out) {
4798     if (html_output) {
4799         fprintf(out, "\t\t\t\t<details><summary>Device Group Properties (Group %u)</summary>\n", id);
4800         fprintf(out, "\t\t\t\t\t<details><summary>physicalDeviceCount = <div class='val'>%u</div></summary>\n",
4801                 group->physicalDeviceCount);
4802     } else if (human_readable_output) {
4803         printf("\tDevice Group Properties (Group %u) :\n", id);
4804         printf("\t\tphysicalDeviceCount = %u\n", group->physicalDeviceCount);
4805     }
4806
4807     // Keep a record of all physical device properties to give the user clearer information as output.
4808     VkPhysicalDeviceProperties *props = malloc(sizeof(props[0]) * group->physicalDeviceCount);
4809     if (!props) {
4810         ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
4811     }
4812     for (uint32_t i = 0; i < group->physicalDeviceCount; ++i) {
4813         vkGetPhysicalDeviceProperties(group->physicalDevices[i], &props[i]);
4814     }
4815
4816     // Output information to the user.
4817     for (uint32_t i = 0; i < group->physicalDeviceCount; ++i) {
4818         if (html_output) {
4819             fprintf(out, "\t\t\t\t\t\t<details><summary>%s (ID: <div class='val'>%d</div>)</summary></details>\n",
4820                     props[i].deviceName, i);
4821         } else if (human_readable_output) {
4822             printf("\n\t\t\t%s (ID: %d)\n", props[i].deviceName, i);
4823         }
4824     }
4825
4826     if (html_output) {
4827         fprintf(out, "\t\t\t\t\t</details>\n");
4828     }
4829
4830     if (html_output) {
4831         fprintf(out, "\t\t\t\t\t<details><summary>subsetAllocation = <div class='val'>%u</div></summary></details>\n",
4832                 group->subsetAllocation);
4833     } else if (human_readable_output) {
4834         printf("\n\t\tsubsetAllocation = %u\n", group->subsetAllocation);
4835     }
4836
4837     if (html_output) {
4838         fprintf(out, "\t\t\t\t</details>\n");
4839     }
4840
4841     // Build create info for logical device made from all physical devices in this group.
4842     const char *extensions_list[] = {VK_KHR_SWAPCHAIN_EXTENSION_NAME, VK_KHR_DEVICE_GROUP_EXTENSION_NAME};
4843
4844     VkDeviceGroupDeviceCreateInfoKHR dg_ci = {.sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR,
4845                                               .pNext = NULL,
4846                                               .physicalDeviceCount = group->physicalDeviceCount,
4847                                               .pPhysicalDevices = group->physicalDevices};
4848
4849     VkDeviceQueueCreateInfo q_ci = {
4850         .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, .pNext = NULL, .queueFamilyIndex = 0, .queueCount = 1};
4851
4852     VkDeviceCreateInfo device_ci = {.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
4853                                     .pNext = &dg_ci,
4854                                     .queueCreateInfoCount = 1,
4855                                     .pQueueCreateInfos = &q_ci,
4856                                     .enabledExtensionCount = ARRAY_SIZE(extensions_list),
4857                                     .ppEnabledExtensionNames = extensions_list};
4858
4859     VkDevice logical_device = VK_NULL_HANDLE;
4860
4861     VkResult err = vkCreateDevice(group->physicalDevices[0], &device_ci, NULL, &logical_device);
4862     if (err != VK_SUCCESS && err != VK_ERROR_EXTENSION_NOT_PRESENT) ERR_EXIT(err);
4863
4864     if (!err) {
4865         if (html_output) {
4866             fprintf(out, "\t\t\t\t<details><summary>Device Group Present Capabilities (Group %d)</summary>\n", id);
4867         } else if (human_readable_output) {
4868             printf("\n\tDevice Group Present Capabilities (Group %d) :\n", id);
4869         }
4870
4871         VkDeviceGroupPresentCapabilitiesKHR group_capabilities = {.sType = VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR,
4872                                                                   .pNext = NULL};
4873
4874         // If the KHR_device_group extension is present, write the capabilities of the logical device into a struct for later output
4875         // to user.
4876         PFN_vkGetDeviceGroupPresentCapabilitiesKHR vkGetDeviceGroupPresentCapabilitiesKHR =
4877             (PFN_vkGetDeviceGroupPresentCapabilitiesKHR)vkGetInstanceProcAddr(inst->instance,
4878                                                                               "vkGetDeviceGroupPresentCapabilitiesKHR");
4879         err = vkGetDeviceGroupPresentCapabilitiesKHR(logical_device, &group_capabilities);
4880         if (err) ERR_EXIT(err);
4881
4882         for (uint32_t i = 0; i < group->physicalDeviceCount; i++) {
4883             if (html_output) {
4884                 fprintf(out, "\t\t\t\t\t<details><summary>%s (ID: <div class='val'>%d</div>)</summary></details>\n",
4885                         props[i].deviceName, i);
4886                 fprintf(out, "\t\t\t\t\t<details><summary>Can present images from the following devices:</summary>\n");
4887                 if (group_capabilities.presentMask[i] != 0) {
4888                     for (uint32_t j = 0; j < group->physicalDeviceCount; ++j) {
4889                         uint32_t mask = 1 << j;
4890                         if (group_capabilities.presentMask[i] & mask) {
4891                             fprintf(out, "\t\t\t\t\t\t<details><summary>%s (ID: <div class='val'>%d</div>)</summary></details>\n",
4892                                     props[j].deviceName, j);
4893                         }
4894                     }
4895                 } else {
4896                     fprintf(out, "\t\t\t\t\t\t<details><summary>None</summary></details>\n");
4897                 }
4898                 fprintf(out, "\t\t\t\t\t</details>\n");
4899             } else if (human_readable_output) {
4900                 printf("\n\t\t%s (ID: %d)\n", props[i].deviceName, i);
4901                 printf("\t\tCan present images from the following devices:\n");
4902                 if (group_capabilities.presentMask[i] != 0) {
4903                     for (uint32_t j = 0; j < group->physicalDeviceCount; ++j) {
4904                         uint32_t mask = 1 << j;
4905                         if (group_capabilities.presentMask[i] & mask) {
4906                             printf("\t\t\t%s (ID: %d)\n", props[j].deviceName, j);
4907                         }
4908                     }
4909                 } else {
4910                     printf("\t\t\tNone\n");
4911                 }
4912                 printf("\n");
4913             }
4914         }
4915
4916         if (html_output) {
4917             fprintf(out, "\t\t\t\t\t<details><summary>Present modes</summary>\n");
4918             if (group_capabilities.modes & VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR)
4919                 fprintf(out, "\t\t\t\t\t\t<details><summary>VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR</summary></details>\n");
4920             if (group_capabilities.modes & VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR)
4921                 fprintf(out, "\t\t\t\t\t\t<details><summary>VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR</summary></details>\n");
4922             if (group_capabilities.modes & VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR)
4923                 fprintf(out, "\t\t\t\t\t\t<details><summary>VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR</summary></details>\n");
4924             if (group_capabilities.modes & VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR)
4925                 fprintf(
4926                     out,
4927                     "\t\t\t\t\t\t<details><summary>VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR</summary></details>\n");
4928             fprintf(out, "\t\t\t\t\t</details>\n");
4929         } else if (human_readable_output) {
4930             printf("\t\tPresent modes:\n");
4931             if (group_capabilities.modes & VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR)
4932                 printf("\t\t\tVK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR\n");
4933             if (group_capabilities.modes & VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR)
4934                 printf("\t\t\tVK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR\n");
4935             if (group_capabilities.modes & VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR)
4936                 printf("\t\t\tVK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR\n");
4937             if (group_capabilities.modes & VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR)
4938                 printf("\t\t\tVK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR\n");
4939         }
4940
4941         if (html_output) {
4942             fprintf(out, "\t\t\t\t</details>\n");
4943         }
4944     }
4945
4946     // Clean up after ourselves.
4947     free(props);
4948     vkDestroyDevice(logical_device, NULL);
4949 }
4950
4951 #ifdef _WIN32
4952 // Enlarges the console window to have a large scrollback size.
4953 static void ConsoleEnlarge() {
4954     const HANDLE console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
4955
4956     // make the console window bigger
4957     CONSOLE_SCREEN_BUFFER_INFO csbi;
4958     COORD buffer_size;
4959     if (GetConsoleScreenBufferInfo(console_handle, &csbi)) {
4960         buffer_size.X = csbi.dwSize.X + 30;
4961         buffer_size.Y = 20000;
4962         SetConsoleScreenBufferSize(console_handle, buffer_size);
4963     }
4964
4965     SMALL_RECT r;
4966     r.Left = r.Top = 0;
4967     r.Right = csbi.dwSize.X - 1 + 30;
4968     r.Bottom = 50;
4969     SetConsoleWindowInfo(console_handle, true, &r);
4970
4971     // change the console window title
4972     SetConsoleTitle(TEXT(APP_SHORT_NAME));
4973 }
4974 #endif
4975
4976 void print_usage(char *argv0) {
4977     printf("\nvulkaninfo - Summarize Vulkan information in relation to the current environment.\n\n");
4978     printf("USAGE: %s [options]\n\n", argv0);
4979     printf("OPTIONS:\n");
4980     printf("-h, --help            Print this help.\n");
4981     printf("--html                Produce an html version of vulkaninfo output, saved as\n");
4982     printf("                      \"vulkaninfo.html\" in the directory in which the command is\n");
4983     printf("                      run.\n");
4984     printf("-j, --json            Produce a json version of vulkaninfo output to standard\n");
4985     printf("                      output.\n");
4986     printf("--json=<gpu-number>   For a multi-gpu system, a single gpu can be targetted by\n");
4987     printf("                      specifying the gpu-number associated with the gpu of \n");
4988     printf("                      interest. This number can be determined by running\n");
4989     printf("                      vulkaninfo without any options specified.\n\n");
4990 }
4991
4992 int main(int argc, char **argv) {
4993     uint32_t gpu_count;
4994     VkResult err;
4995     struct AppInstance inst = {0};
4996     FILE *out = stdout;
4997
4998 #ifdef _WIN32
4999     if (ConsoleIsExclusive()) ConsoleEnlarge();
5000 #endif
5001
5002     // Combinations of output: html only, html AND json, json only, human readable only
5003     for (int i = 1; i < argc; ++i) {
5004         if (!CheckForJsonOption(argv[i])) {
5005             if (strcmp(argv[i], "--html") == 0) {
5006                 human_readable_output = false;
5007                 html_output = true;
5008                 continue;
5009             } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
5010                 print_usage(argv[0]);
5011                 return 1;
5012             } else {
5013                 print_usage(argv[0]);
5014                 return 1;
5015             }
5016         }
5017     }
5018
5019     AppCreateInstance(&inst);
5020
5021     if (html_output) {
5022         out = fopen("vulkaninfo.html", "w");
5023         PrintHtmlHeader(out);
5024         fprintf(out, "\t\t\t<details><summary>");
5025     } else if (human_readable_output) {
5026         printf("==========\n");
5027         printf("VULKANINFO\n");
5028         printf("==========\n\n");
5029     }
5030     if (html_output || human_readable_output) {
5031         fprintf(out, "Vulkan Instance Version: ");
5032     }
5033     if (html_output) {
5034         fprintf(out, "<div class='val'>%d.%d.%d</div></summary></details>\n", inst.vulkan_major, inst.vulkan_minor,
5035                 inst.vulkan_patch);
5036         fprintf(out, "\t\t\t<br />\n");
5037     } else if (human_readable_output) {
5038         printf("%d.%d.%d\n\n", inst.vulkan_major, inst.vulkan_minor, inst.vulkan_patch);
5039     }
5040
5041     err = vkEnumeratePhysicalDevices(inst.instance, &gpu_count, NULL);
5042     if (err) {
5043         ERR_EXIT(err);
5044     }
5045
5046     VkPhysicalDevice *objs = malloc(sizeof(objs[0]) * gpu_count);
5047     if (!objs) {
5048         ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
5049     }
5050
5051     err = vkEnumeratePhysicalDevices(inst.instance, &gpu_count, objs);
5052     if (err) {
5053         ERR_EXIT(err);
5054     }
5055
5056     struct AppGpu *gpus = malloc(sizeof(gpus[0]) * gpu_count);
5057     if (!gpus) {
5058         ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
5059     }
5060
5061     for (uint32_t i = 0; i < gpu_count; ++i) {
5062         AppGpuInit(&gpus[i], &inst, i, objs[i]);
5063         if (human_readable_output) {
5064             printf("\n\n");
5065         }
5066     }
5067
5068     // If json output, confirm the desired gpu exists
5069     if (json_output) {
5070         if (selected_gpu >= gpu_count) {
5071             selected_gpu = 0;
5072         }
5073         PrintJsonHeader(inst.vulkan_major, inst.vulkan_minor, inst.vulkan_patch);
5074     }
5075
5076     if (human_readable_output) {
5077         printf("Instance Extensions:\n");
5078         printf("====================\n");
5079     }
5080     AppDumpExtensions("", "Instance", inst.global_extension_count, inst.global_extensions, out);
5081
5082     //---Layer-Device-Extensions---
5083     if (html_output) {
5084         fprintf(out, "\t\t\t<details><summary>Layers: count = <div class='val'>%d</div></summary>", inst.global_layer_count);
5085         if (inst.global_layer_count > 0) {
5086             fprintf(out, "\n");
5087         }
5088     } else if (human_readable_output) {
5089         printf("Layers: count = %d\n", inst.global_layer_count);
5090         printf("=======\n");
5091     }
5092     if (json_output && (inst.global_layer_count > 0)) {
5093         printf(",\n");
5094         printf("\t\"ArrayOfVkLayerProperties\": [");
5095     }
5096
5097     qsort(inst.global_layers, inst.global_layer_count, sizeof(struct LayerExtensionList), CompareLayerName);
5098
5099     for (uint32_t i = 0; i < inst.global_layer_count; ++i) {
5100         uint32_t layer_major, layer_minor, layer_patch;
5101         char spec_version[64], layer_version[64];
5102         VkLayerProperties const *layer_prop = &inst.global_layers[i].layer_properties;
5103
5104         ExtractVersion(layer_prop->specVersion, &layer_major, &layer_minor, &layer_patch);
5105         snprintf(spec_version, sizeof(spec_version), "%d.%d.%d", layer_major, layer_minor, layer_patch);
5106         snprintf(layer_version, sizeof(layer_version), "%d", layer_prop->implementationVersion);
5107
5108         if (html_output) {
5109             fprintf(out, "\t\t\t\t<details><summary>");
5110             fprintf(out, "<div class='type'>%s</div> (%s) Vulkan version <div class='val'>%s</div>, ", layer_prop->layerName,
5111                     (char *)layer_prop->description, spec_version);
5112             fprintf(out, "layer version <div class='val'>%s</div></summary>\n", layer_version);
5113             AppDumpExtensions("\t\t", "Layer", inst.global_layers[i].extension_count, inst.global_layers[i].extension_properties,
5114                               out);
5115         } else if (human_readable_output) {
5116             printf("%s (%s) Vulkan version %s, layer version %s\n", layer_prop->layerName, (char *)layer_prop->description,
5117                    spec_version, layer_version);
5118             AppDumpExtensions("\t", "Layer", inst.global_layers[i].extension_count, inst.global_layers[i].extension_properties,
5119                               out);
5120         }
5121         if (json_output) {
5122             if (i > 0) {
5123                 printf(",");
5124             }
5125             printf("\n");
5126             printf("\t\t{\n");
5127             printf("\t\t\t\"layerName\": \"%s\",\n", layer_prop->layerName);
5128             printf("\t\t\t\"specVersion\": %u,\n", layer_prop->specVersion);
5129             printf("\t\t\t\"implementationVersion\": %u,\n", layer_prop->implementationVersion);
5130             printf("\t\t\t\"description\": \"%s\"\n", layer_prop->description);
5131             printf("\t\t}");
5132         }
5133
5134         if (html_output) {
5135             fprintf(out, "\t\t\t\t\t<details><summary>Devices count = <div class='val'>%d</div></summary>\n", gpu_count);
5136         } else if (human_readable_output) {
5137             printf("\tDevices \tcount = %d\n", gpu_count);
5138         }
5139
5140         char *layer_name = inst.global_layers[i].layer_properties.layerName;
5141
5142         for (uint32_t j = 0; j < gpu_count; ++j) {
5143             if (html_output) {
5144                 fprintf(out, "\t\t\t\t\t\t<details><summary>");
5145                 fprintf(out, "GPU id: <div class='val'>%u</div> (%s)</summary></details>\n", j, gpus[j].props.deviceName);
5146             } else if (human_readable_output) {
5147                 printf("\t\tGPU id       : %u (%s)\n", j, gpus[j].props.deviceName);
5148             }
5149             uint32_t count = 0;
5150             VkExtensionProperties *props;
5151             AppGetPhysicalDeviceLayerExtensions(&gpus[j], layer_name, &count, &props);
5152             if (html_output) {
5153                 AppDumpExtensions("\t\t\t", "Layer-Device", count, props, out);
5154             } else if (human_readable_output) {
5155                 AppDumpExtensions("\t\t", "Layer-Device", count, props, out);
5156             }
5157             free(props);
5158         }
5159
5160         if (html_output) {
5161             fprintf(out, "\t\t\t\t\t</details>\n");
5162             fprintf(out, "\t\t\t\t</details>\n");
5163         } else if (human_readable_output) {
5164             printf("\n");
5165         }
5166     }
5167
5168     if (html_output) {
5169         fprintf(out, "\t\t\t</details>\n");
5170     }
5171     if (json_output && (inst.global_layer_count > 0)) {
5172         printf("\n\t]");
5173     }
5174
5175     fflush(out);
5176     fflush(stdout);
5177     //-----------------------------
5178
5179     if (html_output) {
5180         fprintf(out, "\t\t\t<details><summary>Presentable Surfaces</summary>");
5181         if (gpu_count > 0) {
5182             fprintf(out, "\n");
5183         } else {
5184             fprintf(out, "</details>\n");
5185         }
5186     } else if (human_readable_output) {
5187         printf("Presentable Surfaces:\n");
5188         printf("=====================\n");
5189     }
5190     inst.width = 256;
5191     inst.height = 256;
5192     int format_count = 0;
5193     int present_mode_count = 0;
5194
5195 #if defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR)
5196     bool has_display = true;
5197     const char *display_var = getenv("DISPLAY");
5198     if (display_var == NULL || strlen(display_var) == 0) {
5199         fprintf(stderr, "'DISPLAY' environment variable not set... skipping surface info\n");
5200         fflush(stderr);
5201         has_display = false;
5202     }
5203 #endif
5204
5205 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
5206     struct wl_display *wayland_display = wl_display_connect(NULL);
5207     bool has_wayland_display = false;
5208     if (wayland_display != NULL) {
5209         wl_display_disconnect(wayland_display);
5210         has_wayland_display = true;
5211     }
5212 #endif
5213
5214 //--WIN32--
5215 #ifdef VK_USE_PLATFORM_WIN32_KHR
5216     struct SurfaceExtensionInfo surface_ext_win32;
5217     surface_ext_win32.name = VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
5218     surface_ext_win32.create_window = AppCreateWin32Window;
5219     surface_ext_win32.create_surface = AppCreateWin32Surface;
5220     surface_ext_win32.destroy_window = AppDestroyWin32Window;
5221     AppDumpSurfaceExtension(&inst, gpus, gpu_count, &surface_ext_win32, &format_count, &present_mode_count, out);
5222 #endif
5223 //--XCB--
5224 #ifdef VK_USE_PLATFORM_XCB_KHR
5225     struct SurfaceExtensionInfo surface_ext_xcb;
5226     surface_ext_xcb.name = VK_KHR_XCB_SURFACE_EXTENSION_NAME;
5227     surface_ext_xcb.create_window = AppCreateXcbWindow;
5228     surface_ext_xcb.create_surface = AppCreateXcbSurface;
5229     surface_ext_xcb.destroy_window = AppDestroyXcbWindow;
5230     if (has_display) {
5231         AppDumpSurfaceExtension(&inst, gpus, gpu_count, &surface_ext_xcb, &format_count, &present_mode_count, out);
5232     }
5233 #endif
5234 //--XLIB--
5235 #ifdef VK_USE_PLATFORM_XLIB_KHR
5236     struct SurfaceExtensionInfo surface_ext_xlib;
5237     surface_ext_xlib.name = VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
5238     surface_ext_xlib.create_window = AppCreateXlibWindow;
5239     surface_ext_xlib.create_surface = AppCreateXlibSurface;
5240     surface_ext_xlib.destroy_window = AppDestroyXlibWindow;
5241     if (has_display) {
5242         AppDumpSurfaceExtension(&inst, gpus, gpu_count, &surface_ext_xlib, &format_count, &present_mode_count, out);
5243     }
5244 #endif
5245 //--MACOS--
5246 #ifdef VK_USE_PLATFORM_MACOS_MVK
5247     struct SurfaceExtensionInfo surface_ext_macos;
5248     surface_ext_macos.name = VK_MVK_MACOS_SURFACE_EXTENSION_NAME;
5249     surface_ext_macos.create_window = AppCreateMacOSWindow;
5250     surface_ext_macos.create_surface = AppCreateMacOSSurface;
5251     surface_ext_macos.destroy_window = AppDestroyMacOSWindow;
5252     AppDumpSurfaceExtension(&inst, gpus, gpu_count, &surface_ext_macos, &format_count, &present_mode_count, out);
5253 #endif
5254 //--WAYLAND--
5255 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
5256     struct SurfaceExtensionInfo surface_ext_wayland;
5257     surface_ext_wayland.name = VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
5258     surface_ext_wayland.create_window = AppCreateWaylandWindow;
5259     surface_ext_wayland.create_surface = AppCreateWaylandSurface;
5260     surface_ext_wayland.destroy_window = AppDestroyWaylandWindow;
5261     if (has_wayland_display) {
5262         AppDumpSurfaceExtension(&inst, gpus, gpu_count, &surface_ext_wayland, &format_count, &present_mode_count, out);
5263     }
5264 #endif
5265
5266     // TODO: Android
5267     if (!format_count && !present_mode_count) {
5268         if (html_output) {
5269             fprintf(out, "\t\t\t\t<details><summary>None found</summary></details>\n");
5270         } else if (human_readable_output) {
5271             printf("None found\n\n");
5272         }
5273     }
5274
5275     if (html_output) {
5276         fprintf(out, "\t\t\t</details>\n");
5277     }
5278     //---------
5279
5280     if (CheckExtensionEnabled(VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME, inst.inst_extensions, inst.inst_extensions_count)) {
5281         PFN_vkEnumeratePhysicalDeviceGroupsKHR vkEnumeratePhysicalDeviceGroupsKHR =
5282             (PFN_vkEnumeratePhysicalDeviceGroupsKHR)vkGetInstanceProcAddr(inst.instance, "vkEnumeratePhysicalDeviceGroupsKHR");
5283
5284         uint32_t group_count;
5285         err = vkEnumeratePhysicalDeviceGroupsKHR(inst.instance, &group_count, NULL);
5286         if (err) {
5287             ERR_EXIT(err);
5288         }
5289
5290         VkPhysicalDeviceGroupProperties *groups = malloc(sizeof(groups[0]) * group_count);
5291         if (!groups) {
5292             ERR_EXIT(VK_ERROR_OUT_OF_HOST_MEMORY);
5293         }
5294
5295         err = vkEnumeratePhysicalDeviceGroupsKHR(inst.instance, &group_count, groups);
5296         if (err) {
5297             ERR_EXIT(err);
5298         }
5299
5300         if (html_output) {
5301             fprintf(out, "\t\t\t<details><summary>Groups</summary>\n");
5302         } else if (human_readable_output) {
5303             printf("\nGroups :\n");
5304             printf("========\n");
5305         }
5306
5307         for (uint32_t i = 0; i < group_count; ++i) {
5308             AppGroupDump(&groups[i], i, &inst, out);
5309             if (human_readable_output) {
5310                 printf("\n\n");
5311             }
5312         }
5313
5314         if (html_output) {
5315             fprintf(out, "\t\t\t</details>\n");
5316         }
5317
5318         free(groups);
5319     }
5320
5321     if (html_output) {
5322         fprintf(out, "\t\t\t<details><summary>Device Properties and Extensions</summary>\n");
5323     }
5324
5325     for (uint32_t i = 0; i < gpu_count; ++i) {
5326         if (json_output && selected_gpu != i) {
5327             // Toggle json_output to allow html output without json output
5328             json_output = false;
5329             AppGpuDump(&gpus[i], out);
5330             json_output = true;
5331         } else {
5332             AppGpuDump(&gpus[i], out);
5333         }
5334         if (human_readable_output) {
5335             printf("\n\n");
5336         }
5337     }
5338
5339     if (html_output) {
5340         fprintf(out, "\t\t\t</details>\n");
5341     }
5342
5343     for (uint32_t i = 0; i < gpu_count; ++i) {
5344         AppGpuDestroy(&gpus[i]);
5345     }
5346     free(gpus);
5347     free(objs);
5348
5349     AppDestroySurface(&inst);
5350     AppDestroyInstance(&inst);
5351
5352     if (html_output) {
5353         PrintHtmlFooter(out);
5354         fflush(out);
5355         fclose(out);
5356     }
5357     if (json_output) {
5358         printf("\n}\n");
5359     }
5360
5361     fflush(stdout);
5362
5363 #ifdef _WIN32
5364     if (ConsoleIsExclusive() && human_readable_output) {
5365         Sleep(INFINITE);
5366     }
5367 #endif
5368
5369     return 0;
5370 }