2 * Copyright (c) 2015-2021 The Khronos Group Inc.
3 * Copyright (c) 2015-2021 Valve Corporation
4 * Copyright (c) 2015-2021 LunarG, Inc.
5 * Copyright (c) 2023-2024 RasterGrid Kft.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
20 * Author: David Pinedo <david@lunarg.com>
21 * Author: Mark Lobodzinski <mark@lunarg.com>
22 * Author: Rene Lindsay <rene@lunarg.com>
23 * Author: Jeremy Kniager <jeremyk@lunarg.com>
24 * Author: Shannon McPherson <shannon@lunarg.com>
25 * Author: Bob Ellison <bob@lunarg.com>
26 * Author: Richard Wright <richard@lunarg.com>
27 * Author: Charles Giessen <charles@lunarg.com>
34 #include "vulkaninfo.hpp"
36 // Used to sort the formats into buckets by their properties.
37 std::unordered_map
<PropFlags
, std::set
<VkFormat
>> FormatPropMap(AppGpu
&gpu
) {
38 std::unordered_map
<PropFlags
, std::set
<VkFormat
>> map
;
39 for (const auto fmtRange
: format_ranges
) {
40 if (gpu
.FormatRangeSupported(fmtRange
)) {
41 for (int32_t fmt
= fmtRange
.first_format
; fmt
<= fmtRange
.last_format
; ++fmt
) {
42 PropFlags pf
= get_format_properties(gpu
, static_cast<VkFormat
>(fmt
));
43 map
[pf
].insert(static_cast<VkFormat
>(fmt
));
50 // =========== Dump Functions ========= //
52 void DumpExtensions(Printer
&p
, std::string section_name
, std::vector
<VkExtensionProperties
> extensions
, bool do_indent
= false) {
53 std::sort(extensions
.begin(), extensions
.end(), [](VkExtensionProperties
&a
, VkExtensionProperties
&b
) -> int {
54 return std::string(a
.extensionName
) < std::string(b
.extensionName
);
57 size_t max_length
= 0;
58 for (const auto &ext
: extensions
) {
59 max_length
= std::max(max_length
, std::strlen(ext
.extensionName
));
61 #if defined(VK_ENABLE_BETA_EXTENSIONS)
62 const std::string portability_ext_name
= VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME
;
63 #endif // defined(VK_ENABLE_BETA_EXTENSIONS)
64 ObjectWrapper
obj(p
, section_name
, extensions
.size());
65 if (do_indent
) p
.IndentDecrease();
66 for (auto &ext
: extensions
) {
67 #if defined(VK_ENABLE_BETA_EXTENSIONS)
68 if (p
.Type() == OutputType::json
&& portability_ext_name
== ext
.extensionName
) continue;
69 #endif // defined(VK_ENABLE_BETA_EXTENSIONS)
70 p
.PrintExtension(ext
.extensionName
, ext
.specVersion
, max_length
);
72 if (do_indent
) p
.IndentIncrease();
75 void DumpLayers(Printer
&p
, std::vector
<LayerExtensionList
> layers
, const std::vector
<std::unique_ptr
<AppGpu
>> &gpus
) {
76 std::sort(layers
.begin(), layers
.end(), [](LayerExtensionList
&left
, LayerExtensionList
&right
) -> int {
77 return std::strncmp(left
.layer_properties
.layerName
, right
.layer_properties
.layerName
, VK_MAX_DESCRIPTION_SIZE
) < 0;
80 case OutputType::text
:
81 case OutputType::html
: {
83 ArrayWrapper
arr_layers(p
, "Layers", layers
.size());
84 IndentWrapper
indent(p
);
86 for (auto &layer
: layers
) {
87 std::string v_str
= APIVersion(layer
.layer_properties
.specVersion
);
88 auto props
= layer
.layer_properties
;
90 std::string header
= p
.DecorateAsType(props
.layerName
) + " (" + props
.description
+ ") " API_NAME
" version " +
91 p
.DecorateAsValue(v_str
) + ", layer version " +
92 p
.DecorateAsValue(std::to_string(props
.implementationVersion
));
93 ObjectWrapper
obj(p
, header
);
94 DumpExtensions(p
, "Layer Extensions", layer
.extension_properties
);
96 ObjectWrapper
arr_devices(p
, "Devices", gpus
.size());
97 for (auto &gpu
: gpus
) {
98 p
.SetValueDescription(std::string(gpu
->props
.deviceName
)).PrintKeyValue("GPU id", gpu
->id
);
99 auto exts
= gpu
->inst
.AppGetPhysicalDeviceLayerExtensions(gpu
->phys_device
, props
.layerName
);
100 DumpExtensions(p
, "Layer-Device Extensions", exts
);
107 case OutputType::json
: {
108 assert(false && "unimplemented");
111 case OutputType::vkconfig_output
: {
112 ObjectWrapper
obj(p
, "Layer Properties");
113 for (auto &layer
: layers
) {
114 ObjectWrapper
obj_name(p
, layer
.layer_properties
.layerName
);
115 p
.SetMinKeyWidth(21);
116 p
.PrintKeyString("layerName", layer
.layer_properties
.layerName
);
117 p
.PrintKeyString("version", APIVersion(layer
.layer_properties
.specVersion
).str());
118 p
.PrintKeyValue("implementation version", layer
.layer_properties
.implementationVersion
);
119 p
.PrintKeyString("description", layer
.layer_properties
.description
);
120 DumpExtensions(p
, "Layer Extensions", layer
.extension_properties
);
121 ObjectWrapper
obj_devices(p
, "Devices");
122 for (auto &gpu
: gpus
) {
123 ObjectWrapper
obj_gpu(p
, gpu
->props
.deviceName
);
124 p
.SetValueDescription(std::string(gpu
->props
.deviceName
)).PrintKeyValue("GPU id", gpu
->id
);
125 auto exts
= gpu
->inst
.AppGetPhysicalDeviceLayerExtensions(gpu
->phys_device
, layer
.layer_properties
.layerName
);
126 DumpExtensions(p
, "Layer-Device Extensions", exts
);
134 void DumpSurfaceFormats(Printer
&p
, AppInstance
&inst
, AppSurface
&surface
) {
135 std::vector
<VkSurfaceFormatKHR
> formats
;
136 if (inst
.CheckExtensionEnabled(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME
)) {
137 for (auto &format
: surface
.surf_formats2
) {
138 formats
.push_back(format
.surfaceFormat
);
141 for (auto &format
: surface
.surf_formats
) {
142 formats
.push_back(format
);
145 ObjectWrapper
obj(p
, "Formats", formats
.size());
147 for (auto &format
: formats
) {
148 p
.SetElementIndex(i
++);
149 DumpVkSurfaceFormatKHR(p
, "SurfaceFormat", format
);
153 void DumpPresentModes(Printer
&p
, AppSurface
&surface
) {
154 ArrayWrapper
arr(p
, "Present Modes", surface
.surf_present_modes
.size());
155 for (auto &mode
: surface
.surf_present_modes
) {
156 p
.SetAsType().PrintString(VkPresentModeKHRString(mode
));
160 void DumpSurfaceCapabilities(Printer
&p
, AppInstance
&inst
, AppGpu
&gpu
, AppSurface
&surface
) {
161 auto &surf_cap
= surface
.surface_capabilities
;
162 p
.SetSubHeader().SetIgnoreMinWidthInChild();
163 DumpVkSurfaceCapabilitiesKHR(p
, "VkSurfaceCapabilitiesKHR", surf_cap
);
165 if (inst
.CheckExtensionEnabled(VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME
)) {
167 ObjectWrapper
obj(p
, "VkSurfaceCapabilities2EXT");
168 DumpVkSurfaceCounterFlagsEXT(p
, "supportedSurfaceCounters", surface
.surface_capabilities2_ext
.supportedSurfaceCounters
);
170 if (inst
.CheckExtensionEnabled(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME
)) {
171 chain_iterator_surface_capabilities2(p
, inst
, gpu
, surface
.surface_capabilities2_khr
.pNext
);
173 if (inst
.CheckExtensionEnabled(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME
)) {
175 ObjectWrapper
obj(p
, "VK_EXT_surface_maintenance1");
176 for (auto &mode
: surface
.surf_present_modes
) {
177 VkSurfacePresentModeEXT present_mode
{};
178 present_mode
.sType
= VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT
;
179 present_mode
.presentMode
= mode
;
181 VkPhysicalDeviceSurfaceInfo2KHR surface_info
{};
182 surface_info
.sType
= VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR
;
183 surface_info
.surface
= surface
.surface_extension
.surface
;
184 surface_info
.pNext
= &present_mode
;
186 VkSurfacePresentModeCompatibilityEXT SurfacePresentModeCompatibilityEXT
{};
187 SurfacePresentModeCompatibilityEXT
.sType
= VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT
;
189 VkSurfacePresentScalingCapabilitiesEXT SurfacePresentScalingCapabilitiesEXT
{};
190 SurfacePresentScalingCapabilitiesEXT
.sType
= VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT
;
191 SurfacePresentScalingCapabilitiesEXT
.pNext
= &SurfacePresentModeCompatibilityEXT
;
193 VkSurfaceCapabilities2KHR surface_caps2
{};
194 surface_caps2
.sType
= VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR
;
195 surface_caps2
.pNext
= &SurfacePresentScalingCapabilitiesEXT
;
197 VkResult err
= vkGetPhysicalDeviceSurfaceCapabilities2KHR(gpu
.phys_device
, &surface_info
, &surface_caps2
);
198 if (err
!= VK_SUCCESS
) {
202 std::vector
<VkPresentModeKHR
> compatible_present_modes
{SurfacePresentModeCompatibilityEXT
.presentModeCount
};
203 SurfacePresentModeCompatibilityEXT
.pPresentModes
= compatible_present_modes
.data();
205 err
= vkGetPhysicalDeviceSurfaceCapabilities2KHR(gpu
.phys_device
, &surface_info
, &surface_caps2
);
207 if (err
== VK_SUCCESS
) {
208 ObjectWrapper
present_mode_obj(p
, VkPresentModeKHRString(mode
));
210 p
.PrintKeyValue("minImageCount", surface_caps2
.surfaceCapabilities
.minImageCount
);
211 p
.PrintKeyValue("maxImageCount", surface_caps2
.surfaceCapabilities
.maxImageCount
);
213 DumpVkSurfacePresentScalingCapabilitiesEXT(p
, "VkSurfacePresentScalingCapabilitiesEXT",
214 SurfacePresentScalingCapabilitiesEXT
);
215 DumpVkSurfacePresentModeCompatibilityEXT(p
, "VkSurfacePresentModeCompatibilityEXT",
216 SurfacePresentModeCompatibilityEXT
);
222 void DumpSurface(Printer
&p
, AppInstance
&inst
, AppGpu
&gpu
, AppSurface
&surface
, std::set
<std::string
> surface_types
) {
223 ObjectWrapper
obj(p
, std::string("GPU id : ") + p
.DecorateAsValue(std::to_string(gpu
.id
)) + " (" + gpu
.props
.deviceName
+ ")");
225 if (surface_types
.size() == 0) {
226 p
.SetAsType().PrintKeyString("Surface type", "No type found");
227 } else if (surface_types
.size() == 1) {
228 p
.SetAsType().PrintKeyString("Surface type", surface
.surface_extension
.name
);
230 ArrayWrapper
arr(p
, "Surface types", surface_types
.size());
231 for (auto &name
: surface_types
) {
236 DumpSurfaceFormats(p
, inst
, surface
);
237 DumpPresentModes(p
, surface
);
238 DumpSurfaceCapabilities(p
, inst
, gpu
, surface
);
243 struct SurfaceTypeGroup
{
246 std::set
<std::string
> surface_types
;
249 bool operator==(AppSurface
const &a
, AppSurface
const &b
) {
250 return a
.phys_device
== b
.phys_device
&& a
.surf_present_modes
== b
.surf_present_modes
&& a
.surf_formats
== b
.surf_formats
&&
251 a
.surf_formats2
== b
.surf_formats2
&& a
.surface_capabilities
== b
.surface_capabilities
&&
252 a
.surface_capabilities2_khr
== b
.surface_capabilities2_khr
&& a
.surface_capabilities2_ext
== b
.surface_capabilities2_ext
;
255 #if defined(VULKANINFO_WSI_ENABLED)
256 void DumpPresentableSurfaces(Printer
&p
, AppInstance
&inst
, const std::vector
<std::unique_ptr
<AppGpu
>> &gpus
,
257 const std::vector
<std::unique_ptr
<AppSurface
>> &surfaces
) {
258 // Don't print anything if no surfaces are found
259 if (surfaces
.size() == 0) return;
261 ObjectWrapper
obj(p
, "Presentable Surfaces");
262 IndentWrapper
indent(p
);
264 std::vector
<SurfaceTypeGroup
> surface_list
;
266 for (auto &surface
: surfaces
) {
267 auto exists
= surface_list
.end();
268 for (auto it
= surface_list
.begin(); it
!= surface_list
.end(); it
++) {
269 // check for duplicate surfaces that differ only by the surface extension
270 if (*(it
->surface
) == *(surface
.get())) {
275 if (exists
!= surface_list
.end()) {
276 exists
->surface_types
.insert(surface
.get()->surface_extension
.name
);
278 // find surface.phys_device's corresponding AppGpu
279 AppGpu
*corresponding_gpu
= nullptr;
280 for (auto &gpu
: gpus
) {
281 if (gpu
->phys_device
== surface
->phys_device
) corresponding_gpu
= gpu
.get();
283 if (corresponding_gpu
!= nullptr)
284 surface_list
.push_back({surface
.get(), corresponding_gpu
, {surface
.get()->surface_extension
.name
}});
287 for (auto &group
: surface_list
) {
288 DumpSurface(p
, inst
, *group
.gpu
, *group
.surface
, group
.surface_types
);
292 #endif // defined(VULKANINFO_WSI_ENABLED)
294 void DumpGroups(Printer
&p
, AppInstance
&inst
) {
295 if (inst
.CheckExtensionEnabled(VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME
)) {
296 auto groups
= GetGroups(inst
);
297 if (groups
.size() == 0) {
299 ObjectWrapper
obj(p
, "Groups");
300 p
.PrintString("No Device Groups Found");
306 ObjectWrapper
obj_device_groups(p
, "Device Groups");
307 IndentWrapper
indent(p
);
310 for (auto &group
: groups
) {
311 ObjectWrapper
obj_group(p
, "Group " + std::to_string(group_id
));
312 auto group_props
= GetGroupProps(inst
, group
);
314 ObjectWrapper
obj_properties(p
, "Properties");
316 ArrayWrapper
arr(p
, "physicalDevices", group
.physicalDeviceCount
);
318 for (auto &prop
: group_props
) {
319 p
.PrintString(std::string(prop
.deviceName
) + " (ID: " + p
.DecorateAsValue(std::to_string(id
++)) + ")");
322 p
.PrintKeyValue("subsetAllocation", group
.subsetAllocation
);
326 auto group_capabilities
= GetGroupCapabilities(inst
, group
);
327 if (!group_capabilities
) {
328 p
.PrintKeyString("Present Capabilities",
329 "Group does not support VK_KHR_device_group, skipping printing present capabilities");
331 ObjectWrapper
obj_caps(p
, "Present Capabilities");
332 for (uint32_t i
= 0; i
< group
.physicalDeviceCount
; i
++) {
333 ObjectWrapper
obj_device(
334 p
, std::string(group_props
[i
].deviceName
) + " (ID: " + p
.DecorateAsValue(std::to_string(i
)) + ")");
335 ArrayWrapper
arr(p
, "Can present images from the following devices", group
.physicalDeviceCount
);
337 for (uint32_t j
= 0; j
< group
.physicalDeviceCount
; j
++) {
338 uint32_t mask
= 1 << j
;
339 if (group_capabilities
->presentMask
[i
] & mask
) {
340 p
.PrintString(std::string(group_props
[j
].deviceName
) + " (ID: " + p
.DecorateAsValue(std::to_string(j
)) +
345 DumpVkDeviceGroupPresentModeFlagsKHR(p
, "Present modes", group_capabilities
->modes
);
354 void GpuDumpProps(Printer
&p
, AppGpu
&gpu
, bool show_promoted_structs
) {
355 auto props
= gpu
.GetDeviceProperties();
358 ObjectWrapper
obj(p
, "VkPhysicalDeviceProperties");
359 p
.SetMinKeyWidth(17);
360 if (p
.Type() == OutputType::json
) {
361 p
.PrintKeyValue("apiVersion", props
.apiVersion
);
362 p
.PrintKeyValue("driverVersion", props
.driverVersion
);
364 p
.SetValueDescription(std::to_string(props
.apiVersion
)).PrintKeyString("apiVersion", APIVersion(props
.apiVersion
));
365 p
.SetValueDescription(std::to_string(props
.driverVersion
))
366 .PrintKeyString("driverVersion", gpu
.GetDriverVersionString());
368 p
.PrintKeyString("vendorID", to_hex_str(props
.vendorID
));
369 p
.PrintKeyString("deviceID", to_hex_str(props
.deviceID
));
370 p
.PrintKeyString("deviceType", VkPhysicalDeviceTypeString(props
.deviceType
));
371 p
.PrintKeyString("deviceName", props
.deviceName
);
372 p
.PrintKeyValue("pipelineCacheUUID", props
.pipelineCacheUUID
);
375 DumpVkPhysicalDeviceLimits(p
, "VkPhysicalDeviceLimits", gpu
.props
.limits
);
377 DumpVkPhysicalDeviceSparseProperties(p
, "VkPhysicalDeviceSparseProperties", gpu
.props
.sparseProperties
);
379 if (gpu
.inst
.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME
)) {
380 void *place
= gpu
.props2
.pNext
;
381 chain_iterator_phys_device_props2(p
, gpu
.inst
, gpu
, show_promoted_structs
, place
);
385 void GpuDumpQueueProps(Printer
&p
, AppGpu
&gpu
, const AppQueueFamilyProperties
&queue
) {
386 VkQueueFamilyProperties props
= queue
.props
;
387 p
.SetSubHeader().SetElementIndex(static_cast<int>(queue
.queue_index
));
388 ObjectWrapper
obj_queue_props(p
, "queueProperties");
389 p
.SetMinKeyWidth(27);
390 if (p
.Type() == OutputType::vkconfig_output
) {
391 DumpVkExtent3D(p
, "minImageTransferGranularity", props
.minImageTransferGranularity
);
393 p
.PrintKeyValue("minImageTransferGranularity", props
.minImageTransferGranularity
);
395 p
.PrintKeyValue("queueCount", props
.queueCount
);
396 p
.PrintKeyString("queueFlags", VkQueueFlagsString(props
.queueFlags
));
397 p
.PrintKeyValue("timestampValidBits", props
.timestampValidBits
);
399 if (!queue
.can_present
) {
400 p
.PrintKeyString("present support", "false");
401 } else if (queue
.can_always_present
) {
402 p
.PrintKeyString("present support", "true");
405 for (const auto &support
: queue
.present_support
) {
406 if (support
.first
.size() > width
) width
= support
.first
.size();
408 ObjectWrapper
obj_present_support(p
, "present support");
409 p
.SetMinKeyWidth(width
);
410 for (const auto &support
: queue
.present_support
) {
411 p
.PrintKeyString(support
.first
, support
.second
? "true" : "false");
414 chain_iterator_queue_properties2(p
, gpu
, queue
.pNext
);
419 // This prints a number of bytes in a human-readable format according to prefixes of the International System of Quantities (ISQ),
420 // defined in ISO/IEC 80000. The prefixes used here are not SI prefixes, but rather the binary prefixes based on powers of 1024
421 // (kibi-, mebi-, gibi- etc.).
422 #define kBufferSize 32
424 std::string
NumToNiceStr(const size_t sz
) {
425 const char prefixes
[] = "KMGTPEZY";
426 char buf
[kBufferSize
];
428 double result
= (double)sz
;
429 while (result
> 1024 && which
< 7) {
436 unit
[0] = prefixes
[which
];
439 _snprintf_s(buf
, kBufferSize
* sizeof(char), kBufferSize
, "%.2f %sB", result
, unit
);
441 snprintf(buf
, kBufferSize
, "%.2f %sB", result
, unit
);
443 return std::string(buf
);
446 std::string
append_human_readable(VkDeviceSize memory
) {
447 return std::to_string(memory
) + " (" + to_hex_str(memory
) + ") (" + NumToNiceStr(static_cast<size_t>(memory
)) + ")";
450 void GpuDumpMemoryProps(Printer
&p
, AppGpu
&gpu
) {
452 ObjectWrapper
obj_mem_props(p
, "VkPhysicalDeviceMemoryProperties");
453 IndentWrapper
indent(p
);
455 ObjectWrapper
obj_mem_heaps(p
, "memoryHeaps", gpu
.memory_props
.memoryHeapCount
);
457 for (uint32_t i
= 0; i
< gpu
.memory_props
.memoryHeapCount
; ++i
) {
458 p
.SetElementIndex(static_cast<int>(i
));
459 ObjectWrapper
obj_mem_heap(p
, "memoryHeaps");
461 p
.PrintKeyString("size", append_human_readable(gpu
.memory_props
.memoryHeaps
[i
].size
));
462 if (gpu
.CheckPhysicalDeviceExtensionIncluded(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME
)) {
463 p
.PrintKeyString("budget", append_human_readable(gpu
.heapBudget
[i
]));
464 p
.PrintKeyString("usage", append_human_readable(gpu
.heapUsage
[i
]));
466 DumpVkMemoryHeapFlags(p
, "flags", gpu
.memory_props
.memoryHeaps
[i
].flags
);
470 ObjectWrapper
obj_mem_types(p
, "memoryTypes", gpu
.memory_props
.memoryTypeCount
);
471 for (uint32_t i
= 0; i
< gpu
.memory_props
.memoryTypeCount
; ++i
) {
472 p
.SetElementIndex(static_cast<int>(i
));
473 ObjectWrapper
obj_mem_type(p
, "memoryTypes");
474 p
.SetMinKeyWidth(13);
475 p
.PrintKeyValue("heapIndex", gpu
.memory_props
.memoryTypes
[i
].heapIndex
);
477 auto flags
= gpu
.memory_props
.memoryTypes
[i
].propertyFlags
;
478 DumpVkMemoryPropertyFlags(p
, "propertyFlags = " + to_hex_str(flags
), flags
);
480 ObjectWrapper
usable_for(p
, "usable for");
481 const uint32_t memtype_bit
= 1U << i
;
483 // only linear and optimal tiling considered
484 for (auto &image_tiling
: gpu
.memory_image_support_types
) {
486 ArrayWrapper
arr(p
, VkImageTilingString(VkImageTiling(image_tiling
.tiling
)));
487 bool has_any_support_types
= false;
488 bool regular
= false;
489 bool transient
= false;
491 for (auto &image_format
: image_tiling
.formats
) {
492 if (image_format
.type_support
.size() > 0) {
493 bool has_a_support_type
= false;
494 for (auto &img_type
: image_format
.type_support
) {
495 if (img_type
.Compatible(memtype_bit
)) {
496 has_a_support_type
= true;
497 has_any_support_types
= true;
498 if (img_type
.type
== ImageTypeSupport::Type::regular
) regular
= true;
499 if (img_type
.type
== ImageTypeSupport::Type::transient
) transient
= true;
500 if (img_type
.type
== ImageTypeSupport::Type::sparse
) sparse
= true;
503 if (has_a_support_type
) {
504 if (image_format
.format
== color_format
) {
505 p
.PrintString("color images");
507 p
.PrintString(VkFormatString(image_format
.format
));
512 if (!has_any_support_types
) {
513 p
.PrintString("None");
515 if (regular
&& !transient
&& sparse
) p
.PrintString("(non-transient)");
516 if (regular
&& transient
&& !sparse
) p
.PrintString("(non-sparse)");
517 if (regular
&& !transient
&& !sparse
) p
.PrintString("(non-sparse, non-transient)");
518 if (!regular
&& transient
&& sparse
) p
.PrintString("(sparse and transient only)");
519 if (!regular
&& !transient
&& sparse
) p
.PrintString("(sparse only)");
520 if (!regular
&& transient
&& !sparse
) p
.PrintString("(transient only)");
528 void GpuDumpFeatures(Printer
&p
, AppGpu
&gpu
, bool show_promoted_structs
) {
530 DumpVkPhysicalDeviceFeatures(p
, "VkPhysicalDeviceFeatures", gpu
.features
);
532 if (gpu
.inst
.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME
)) {
533 void *place
= gpu
.features2
.pNext
;
534 chain_iterator_phys_device_features2(p
, gpu
, show_promoted_structs
, place
);
538 void GpuDumpTextFormatProperty(Printer
&p
, const AppGpu
&gpu
, PropFlags formats
, const std::set
<VkFormat
> &format_list
,
540 p
.SetElementIndex(counter
);
541 ObjectWrapper
obj_common_group(p
, "Common Format Group");
542 IndentWrapper
indent_inner(p
);
544 ArrayWrapper
arr_formats(p
, "Formats", format_list
.size());
545 for (auto &fmt
: format_list
) {
546 p
.SetAsType().PrintString(VkFormatString(fmt
));
549 ObjectWrapper
obj(p
, "Properties");
550 if (gpu
.CheckPhysicalDeviceExtensionIncluded(VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME
)) {
551 DumpVkFormatFeatureFlags2(p
, "linearTilingFeatures", formats
.props3
.linearTilingFeatures
);
552 DumpVkFormatFeatureFlags2(p
, "optimalTilingFeatures", formats
.props3
.optimalTilingFeatures
);
553 DumpVkFormatFeatureFlags2(p
, "bufferFeatures", formats
.props3
.bufferFeatures
);
555 DumpVkFormatFeatureFlags(p
, "linearTilingFeatures", formats
.props
.linearTilingFeatures
);
556 DumpVkFormatFeatureFlags(p
, "optimalTilingFeatures", formats
.props
.optimalTilingFeatures
);
557 DumpVkFormatFeatureFlags(p
, "bufferFeatures", formats
.props
.bufferFeatures
);
562 void GpuDumpToolingInfo(Printer
&p
, AppGpu
&gpu
) {
563 auto tools
= GetToolingInfo(gpu
);
564 if (tools
.size() > 0) {
566 ObjectWrapper
obj(p
, "Tooling Info");
567 for (auto tool
: tools
) {
568 DumpVkPhysicalDeviceToolProperties(p
, tool
.name
, tool
);
574 void GpuDevDump(Printer
&p
, AppGpu
&gpu
) {
576 ObjectWrapper
obj_format_props(p
, "Format Properties");
577 IndentWrapper
indent_outer(p
);
579 if (p
.Type() == OutputType::text
) {
580 auto fmtPropMap
= FormatPropMap(gpu
);
582 std::set
<VkFormat
> unsupported_formats
;
583 for (auto &prop
: fmtPropMap
) {
584 VkFormatProperties props
= prop
.first
.props
;
585 VkFormatProperties3 props3
= prop
.first
.props3
;
586 if (props
.linearTilingFeatures
== 0 && props
.optimalTilingFeatures
== 0 && props
.bufferFeatures
== 0 &&
587 props3
.linearTilingFeatures
== 0 && props3
.optimalTilingFeatures
== 0 && props3
.bufferFeatures
== 0) {
588 unsupported_formats
= prop
.second
;
591 GpuDumpTextFormatProperty(p
, gpu
, prop
.first
, prop
.second
, counter
++);
594 ArrayWrapper
arr_unsupported_formats(p
, "Unsupported Formats", unsupported_formats
.size());
595 for (auto &fmt
: unsupported_formats
) {
596 p
.SetAsType().PrintString(VkFormatString(fmt
));
599 std::set
<VkFormat
> formats_to_print
;
600 for (auto &format_range
: format_ranges
) {
601 if (gpu
.FormatRangeSupported(format_range
)) {
602 for (int32_t fmt_counter
= format_range
.first_format
; fmt_counter
<= format_range
.last_format
; ++fmt_counter
) {
603 formats_to_print
.insert(static_cast<VkFormat
>(fmt_counter
));
607 for (const auto &fmt
: formats_to_print
) {
608 auto formats
= get_format_properties(gpu
, fmt
);
610 if (gpu
.CheckPhysicalDeviceExtensionIncluded(VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME
)) {
611 DumpVkFormatProperties3(p
, VkFormatString(fmt
), formats
.props3
);
613 DumpVkFormatProperties(p
, VkFormatString(fmt
), formats
.props
);
621 void DumpVkVideoProfileInfoKHRCustom(Printer
&p
, std::string name
, const VkVideoProfileInfoKHR
&obj
) {
622 // We use custom dumping here because we do not want to output ignored fields
623 // e.g. for monochrome chromaBitDepth is ignored
624 ObjectWrapper object
{p
, name
};
625 DumpVkVideoCodecOperationFlagBitsKHR(p
, "videoCodecOperation", obj
.videoCodecOperation
);
626 DumpVkVideoChromaSubsamplingFlagsKHR(p
, "chromaSubsampling", obj
.chromaSubsampling
);
627 DumpVkVideoComponentBitDepthFlagsKHR(p
, "lumaBitDepth", obj
.lumaBitDepth
);
628 if (obj
.chromaSubsampling
!= VK_VIDEO_CHROMA_SUBSAMPLING_MONOCHROME_BIT_KHR
) {
629 DumpVkVideoComponentBitDepthFlagsKHR(p
, "chromaBitDepth", obj
.chromaBitDepth
);
631 DumpVkVideoComponentBitDepthFlagsKHR(p
, "chromaBitDepth", 0);
635 void GpuDumpVideoProfiles(Printer
&p
, AppGpu
&gpu
, bool show_video_props
) {
637 ArrayWrapper
video_profiles_obj(p
, "Video Profiles", gpu
.video_profiles
.size());
638 IndentWrapper
indent_outer(p
);
640 if (p
.Type() != OutputType::text
|| show_video_props
) {
641 // Video profile details per profile
642 for (const auto &video_profile
: gpu
.video_profiles
) {
644 ObjectWrapper
video_profile_obj(p
, video_profile
->name
);
645 IndentWrapper
indent_inner(p
);
648 ObjectWrapper
profile_info_obj(p
, "Video Profile Definition");
650 DumpVkVideoProfileInfoKHRCustom(p
, "VkVideoProfileInfoKHR", video_profile
->profile_info
);
651 chain_iterator_video_profile_info(p
, gpu
, video_profile
->profile_info
.pNext
);
655 ObjectWrapper
capabilities_obj(p
, "Video Profile Capabilities");
657 DumpVkVideoCapabilitiesKHR(p
, "VkVideoCapabilitiesKHR", video_profile
->capabilities
);
658 chain_iterator_video_capabilities(p
, gpu
, video_profile
->capabilities
.pNext
);
662 ObjectWrapper
video_formats_obj(p
, "Video Formats");
663 for (const auto &video_formats_it
: video_profile
->formats_by_category
) {
664 const auto &video_format_category_name
= video_formats_it
.first
;
665 const auto &video_format_props
= video_formats_it
.second
;
666 ArrayWrapper
video_format_category(p
, video_format_category_name
, video_format_props
.size());
667 for (size_t i
= 0; i
< video_format_props
.size(); ++i
) {
668 ObjectWrapper
video_format_obj(p
, video_format_category_name
+ " Format #" + std::to_string(i
+ 1));
670 DumpVkVideoFormatPropertiesKHR(p
, "VkVideoFormatPropertiesKHR", video_format_props
[i
]);
671 chain_iterator_video_format_properties(p
, gpu
, video_format_props
[i
].pNext
);
679 // Video profile list only
680 for (const auto &video_profile
: gpu
.video_profiles
) {
681 p
.PrintString(video_profile
->name
);
688 // Print gpu info for text, html, & vkconfig_output
689 // Uses a separate function than schema-json for clarity
690 void DumpGpu(Printer
&p
, AppGpu
&gpu
, bool show_tooling_info
, bool show_formats
, bool show_promoted_structs
,
691 bool show_video_props
) {
692 ObjectWrapper
obj_gpu(p
, "GPU" + std::to_string(gpu
.id
));
693 IndentWrapper
indent(p
);
695 GpuDumpProps(p
, gpu
, show_promoted_structs
);
696 DumpExtensions(p
, "Device Extensions", gpu
.device_extensions
);
700 ObjectWrapper
obj_family_props(p
, "VkQueueFamilyProperties");
701 for (const auto &queue_prop
: gpu
.extended_queue_props
) {
702 GpuDumpQueueProps(p
, gpu
, queue_prop
);
705 GpuDumpMemoryProps(p
, gpu
);
706 GpuDumpFeatures(p
, gpu
, show_promoted_structs
);
707 if (show_tooling_info
) {
708 GpuDumpToolingInfo(p
, gpu
);
711 if (p
.Type() != OutputType::text
|| show_formats
) {
715 if (!gpu
.video_profiles
.empty()) {
716 GpuDumpVideoProfiles(p
, gpu
, show_video_props
);
722 // Print capabilities section of profiles schema
723 void DumpGpuProfileCapabilities(Printer
&p
, AppGpu
&gpu
) {
724 ObjectWrapper
capabilities(p
, "capabilities");
726 ObjectWrapper
temp_name_obj(p
, "device");
727 DumpExtensions(p
, "extensions", gpu
.device_extensions
);
729 ObjectWrapper
obj(p
, "features");
730 GpuDumpFeatures(p
, gpu
, false);
733 ObjectWrapper
obj(p
, "properties");
735 ObjectWrapper
props_obj(p
, "VkPhysicalDeviceProperties");
736 auto props
= gpu
.GetDeviceProperties();
737 p
.PrintKeyValue("apiVersion", props
.apiVersion
);
738 p
.PrintKeyValue("deviceID", props
.deviceID
);
739 p
.PrintKeyString("deviceName", props
.deviceName
);
740 p
.PrintKeyString("deviceType", std::string("VK_") + VkPhysicalDeviceTypeString(props
.deviceType
));
741 p
.PrintKeyValue("driverVersion", props
.driverVersion
);
743 DumpVkPhysicalDeviceLimits(p
, "VkPhysicalDeviceLimits", gpu
.props
.limits
);
745 ArrayWrapper
arr(p
, "pipelineCacheUUID");
746 for (const auto &uuid
: props
.pipelineCacheUUID
) p
.PrintElement(static_cast<uint32_t>(uuid
));
748 DumpVkPhysicalDeviceSparseProperties(p
, "VkPhysicalDeviceSparseProperties", gpu
.props
.sparseProperties
);
749 p
.PrintKeyValue("vendorID", props
.vendorID
);
751 if (gpu
.inst
.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME
)) {
752 void *place
= gpu
.props2
.pNext
;
753 chain_iterator_phys_device_props2(p
, gpu
.inst
, gpu
, false, place
);
757 ObjectWrapper
obj(p
, "formats");
758 std::set
<VkFormat
> already_printed_formats
;
759 for (const auto &format
: format_ranges
) {
760 if (gpu
.FormatRangeSupported(format
)) {
761 for (int32_t fmt_counter
= format
.first_format
; fmt_counter
<= format
.last_format
; ++fmt_counter
) {
762 VkFormat fmt
= static_cast<VkFormat
>(fmt_counter
);
763 if (already_printed_formats
.count(fmt
) > 0) {
766 auto formats
= get_format_properties(gpu
, fmt
);
768 // don't print format properties that are unsupported
769 if (formats
.props
.linearTilingFeatures
== 0 && formats
.props
.optimalTilingFeatures
== 0 &&
770 formats
.props
.bufferFeatures
== 0 && formats
.props3
.linearTilingFeatures
== 0 &&
771 formats
.props3
.optimalTilingFeatures
== 0 && formats
.props3
.bufferFeatures
== 0)
774 ObjectWrapper
format_obj(p
, std::string("VK_") + VkFormatString(fmt
));
776 // Want to explicitly list VkFormatProperties in addition to VkFormatProperties3 if available
777 DumpVkFormatProperties(p
, "VkFormatProperties", formats
.props
);
778 VkFormatProperties2 format_props2
{};
779 format_props2
.sType
= VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2
;
780 format_props2
.formatProperties
= formats
.props
;
781 std::unique_ptr
<format_properties2_chain
> chain_for_format_props2
;
782 setup_format_properties2_chain(format_props2
, chain_for_format_props2
, gpu
);
783 vkGetPhysicalDeviceFormatProperties2KHR(gpu
.phys_device
, fmt
, &format_props2
);
784 chain_iterator_format_properties2(p
, gpu
, format_props2
.pNext
);
786 already_printed_formats
.insert(fmt
);
792 ArrayWrapper
arr(p
, "queueFamiliesProperties");
793 for (const auto &extended_queue_prop
: gpu
.extended_queue_props
) {
794 ObjectWrapper
queue_obj(p
, "");
796 ObjectWrapper
obj_queue_props(p
, "VkQueueFamilyProperties");
797 VkQueueFamilyProperties props
= extended_queue_prop
.props
;
798 DumpVkExtent3D(p
, "minImageTransferGranularity", props
.minImageTransferGranularity
);
799 p
.PrintKeyValue("queueCount", props
.queueCount
);
800 DumpVkQueueFlags(p
, "queueFlags", props
.queueFlags
);
801 p
.PrintKeyValue("timestampValidBits", props
.timestampValidBits
);
803 chain_iterator_queue_properties2(p
, gpu
, extended_queue_prop
.pNext
);
806 if (!gpu
.video_profiles
.empty()) {
807 ArrayWrapper
video_profiles(p
, "videoProfiles");
808 for (const auto &video_profile
: gpu
.video_profiles
) {
809 ObjectWrapper
video_profile_obj(p
, "");
811 ObjectWrapper
profile_info_obj(p
, "profile");
812 DumpVkVideoProfileInfoKHRCustom(p
, "VkVideoProfileInfoKHR", video_profile
->profile_info
);
813 chain_iterator_video_profile_info(p
, gpu
, video_profile
->profile_info
.pNext
);
816 ObjectWrapper
capabilities_obj(p
, "capabilities");
817 DumpVkVideoCapabilitiesKHR(p
, "VkVideoCapabilitiesKHR", video_profile
->capabilities
);
818 chain_iterator_video_capabilities(p
, gpu
, video_profile
->capabilities
.pNext
);
821 ArrayWrapper
video_formats(p
, "formats");
822 for (const auto &video_format
: video_profile
->formats
) {
823 ObjectWrapper
video_format_obj(p
, "");
824 DumpVkVideoFormatPropertiesKHR(p
, "VkVideoFormatPropertiesKHR", video_format
.properties
);
825 chain_iterator_video_format_properties(p
, gpu
, video_format
.properties
.pNext
);
831 #if defined(VK_ENABLE_BETA_EXTENSIONS)
832 // Print portability subset extension, features, and properties if available
833 if (gpu
.CheckPhysicalDeviceExtensionIncluded(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME
) &&
834 (gpu
.inst
.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME
) ||
835 gpu
.inst
.api_version
>= VK_API_VERSION_1_1
)) {
836 ObjectWrapper
macos_obj(p
, "macos-specific");
838 ObjectWrapper
ext_obj(p
, "extensions");
839 const std::string portability_ext_name
= VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME
;
840 for (const auto &ext
: gpu
.device_extensions
) {
841 if (portability_ext_name
== ext
.extensionName
) {
842 p
.PrintExtension(ext
.extensionName
, ext
.specVersion
);
847 ObjectWrapper
features_obj(p
, "features");
848 void *feats_place
= gpu
.features2
.pNext
;
849 while (feats_place
) {
850 VkBaseOutStructure
*structure
= static_cast<VkBaseOutStructure
*>(feats_place
);
851 if (structure
->sType
== VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR
) {
852 auto *features
= reinterpret_cast<VkPhysicalDevicePortabilitySubsetFeaturesKHR
*>(structure
);
853 DumpVkPhysicalDevicePortabilitySubsetFeaturesKHR(p
, "VkPhysicalDevicePortabilitySubsetFeaturesKHR", *features
);
856 feats_place
= structure
->pNext
;
860 ObjectWrapper
property_obj(p
, "properties");
861 void *props_place
= gpu
.props2
.pNext
;
862 while (props_place
) {
863 VkBaseOutStructure
*structure
= static_cast<VkBaseOutStructure
*>(props_place
);
864 if (structure
->sType
== VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_KHR
) {
865 auto *props
= reinterpret_cast<VkPhysicalDevicePortabilitySubsetPropertiesKHR
*>(structure
);
866 DumpVkPhysicalDevicePortabilitySubsetPropertiesKHR(p
, "VkPhysicalDevicePortabilitySubsetPropertiesKHR", *props
);
869 props_place
= structure
->pNext
;
873 #endif // defined(VK_ENABLE_BETA_EXTENSIONS)
875 void PrintProfileBaseInfo(Printer
&p
, const std::string
&device_name
, uint32_t apiVersion
, const std::string
&device_label
,
876 const std::vector
<std::string
> &capabilities
) {
877 ObjectWrapper
vk_info(p
, device_name
);
878 p
.PrintKeyValue("version", 1);
879 p
.PrintKeyString("api-version", APIVersion(apiVersion
).str());
880 p
.PrintKeyString("label", device_label
);
881 p
.PrintKeyString("description", std::string("Exported from ") + APP_SHORT_NAME
);
882 { ObjectWrapper
contributors(p
, "contributors"); }
884 ArrayWrapper
contributors(p
, "history");
885 ObjectWrapper
element(p
, "");
886 p
.PrintKeyValue("revision", 1);
887 std::time_t t
= std::time(0); // get time now
888 std::tm
*now
= std::localtime(&t
);
890 std::to_string(now
->tm_year
+ 1900) + '-' + std::to_string(now
->tm_mon
+ 1) + '-' + std::to_string(now
->tm_mday
);
891 p
.PrintKeyString("date", date
);
892 p
.PrintKeyString("author", std::string("Automated export from ") + APP_SHORT_NAME
);
893 p
.PrintKeyString("comment", "");
895 ArrayWrapper
contributors(p
, "capabilities");
896 for (const auto &str
: capabilities
) p
.PrintString(str
);
899 // Prints profiles section of profiles schema
900 void DumpGpuProfileInfo(Printer
&p
, AppGpu
&gpu
) {
901 ObjectWrapper
profiles(p
, "profiles");
903 std::string device_label
= std::string(gpu
.props
.deviceName
) + " driver " + gpu
.GetDriverVersionString();
904 std::string device_name
=
905 std::string("VP_" APP_UPPER_CASE_NAME
"_") + std::string(gpu
.props
.deviceName
) + "_" + gpu
.GetDriverVersionString();
907 for (auto &c
: device_name
) {
908 if (c
== ' ' || c
== '.') c
= '_';
910 PrintProfileBaseInfo(p
, device_name
, gpu
.props
.apiVersion
, device_label
, {"device"});
911 #if defined(VK_ENABLE_BETA_EXTENSIONS)
912 if (gpu
.CheckPhysicalDeviceExtensionIncluded(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME
) &&
913 (gpu
.inst
.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME
) ||
914 gpu
.inst
.api_version
>= VK_API_VERSION_1_1
)) {
915 PrintProfileBaseInfo(p
, device_name
+ "_portability_subset", gpu
.props
.apiVersion
, device_label
+ " subset",
916 {"device", "macos-specific"});
918 #endif // defined(VK_ENABLE_BETA_EXTENSIONS)
921 // Print summary of system
922 void DumpSummaryInstance(Printer
&p
, AppInstance
&inst
) {
924 DumpExtensions(p
, "Instance Extensions", inst
.global_extensions
, true);
928 ArrayWrapper
arr(p
, "Instance Layers", inst
.global_layers
.size());
929 IndentWrapper
indent(p
);
930 std::sort(inst
.global_layers
.begin(), inst
.global_layers
.end(), [](LayerExtensionList
&left
, LayerExtensionList
&right
) -> int {
931 return std::strncmp(left
.layer_properties
.layerName
, right
.layer_properties
.layerName
, VK_MAX_DESCRIPTION_SIZE
) < 0;
933 size_t layer_name_max
= 0;
934 size_t layer_desc_max
= 0;
935 size_t layer_version_max
= 0;
937 // find max of each type to align everything in columns
938 for (auto &layer
: inst
.global_layers
) {
939 auto props
= layer
.layer_properties
;
940 layer_name_max
= std::max(layer_name_max
, strlen(props
.layerName
));
941 layer_desc_max
= std::max(layer_desc_max
, strlen(props
.description
));
942 layer_version_max
= std::max(layer_version_max
, APIVersion(layer
.layer_properties
.specVersion
).str().size());
944 for (auto &layer
: inst
.global_layers
) {
945 auto v_str
= APIVersion(layer
.layer_properties
.specVersion
).str();
946 auto props
= layer
.layer_properties
;
948 auto name_padding
= std::string(layer_name_max
- strlen(props
.layerName
), ' ');
949 auto desc_padding
= std::string(layer_desc_max
- strlen(props
.description
), ' ');
950 auto version_padding
= std::string(layer_version_max
- v_str
.size(), ' ');
951 p
.PrintString(std::string(props
.layerName
) + name_padding
+ " " + props
.description
+ desc_padding
+ " " + v_str
+ " " +
952 version_padding
+ " version " + std::to_string(props
.implementationVersion
));
957 void DumpSummaryGPU(Printer
&p
, AppGpu
&gpu
) {
958 ObjectWrapper
obj(p
, "GPU" + std::to_string(gpu
.id
));
959 p
.SetMinKeyWidth(18);
960 auto props
= gpu
.GetDeviceProperties();
961 p
.PrintKeyValue("apiVersion", APIVersion(props
.apiVersion
));
962 if (gpu
.found_driver_props
) {
963 p
.PrintKeyString("driverVersion", gpu
.GetDriverVersionString());
965 p
.PrintKeyValue("driverVersion", props
.driverVersion
);
967 p
.PrintKeyString("vendorID", to_hex_str(props
.vendorID
));
968 p
.PrintKeyString("deviceID", to_hex_str(props
.deviceID
));
969 p
.PrintKeyString("deviceType", VkPhysicalDeviceTypeString(props
.deviceType
));
970 p
.PrintKeyString("deviceName", props
.deviceName
);
972 if (gpu
.found_driver_props
) {
973 DumpVkDriverId(p
, "driverID", gpu
.driverID
);
974 p
.PrintKeyString("driverName", gpu
.driverName
);
975 p
.PrintKeyString("driverInfo", gpu
.driverInfo
);
976 p
.PrintKeyValue("conformanceVersion", gpu
.conformanceVersion
);
978 if (gpu
.found_device_id_props
) {
979 p
.PrintKeyValue("deviceUUID", gpu
.deviceUUID
);
980 p
.PrintKeyValue("driverUUID", gpu
.driverUUID
);
984 // ============ Printing Logic ============= //
987 // Enlarges the console window to have a large scrollback size.
988 static void ConsoleEnlarge() {
989 const HANDLE console_handle
= GetStdHandle(STD_OUTPUT_HANDLE
);
991 // make the console window bigger
992 CONSOLE_SCREEN_BUFFER_INFO csbi
;
994 if (GetConsoleScreenBufferInfo(console_handle
, &csbi
)) {
995 buffer_size
.X
= csbi
.dwSize
.X
+ 30;
996 buffer_size
.Y
= 20000;
997 SetConsoleScreenBufferSize(console_handle
, buffer_size
);
1002 r
.Right
= csbi
.dwSize
.X
- 1 + 30;
1004 SetConsoleWindowInfo(console_handle
, true, &r
);
1006 // change the console window title
1007 SetConsoleTitle(TEXT(APP_SHORT_NAME
));
1011 // Global configuration
1012 enum class OutputCategory
{ text
, html
, profile_json
, vkconfig_output
, summary
};
1013 const char *help_message_body
=
1015 "[-h, --help] Print this help.\n"
1016 "[--summary] Show a summary of the instance and GPU's on a system.\n"
1017 "[-o <filename>, --output <filename>]\n"
1018 " Print output to a new file whose name is specified by filename.\n"
1019 " File will be written to the current working directory.\n"
1020 "[--text] Produce a text version of " APP_SHORT_NAME
1021 " output to stdout. This is\n"
1022 " the default output.\n"
1023 "[--html] Produce an html version of " APP_SHORT_NAME
1024 " output, saved as\n"
1025 " \"" APP_SHORT_NAME
1026 ".html\" in the directory in which the command\n"
1028 "[-j, --json] Produce a json version of " APP_SHORT_NAME
1029 " output conforming to the Vulkan\n"
1030 " Profiles schema, saved as \n"
1031 " \"VP_" APP_UPPER_CASE_NAME
1032 "_[DEVICE_NAME]_[DRIVER_VERSION].json\"\n"
1033 " of the first gpu in the system.\n"
1034 "[-j=<gpu-number>, --json=<gpu-number>]\n"
1035 " For a multi-gpu system, a single gpu can be targetted by\n"
1036 " specifying the gpu-number associated with the gpu of \n"
1037 " interest. This number can be determined by running\n"
1039 " without any options specified.\n"
1040 "[--show-tool-props] Show the active VkPhysicalDeviceToolPropertiesEXT that " APP_SHORT_NAME
1042 "[--show-formats] Display the format properties of each physical device.\n"
1043 " Note: This only affects text output.\n"
1044 "[--show-promoted-structs] Include structs promoted to core in pNext Chains.\n"
1045 "[--show-video-props]\n"
1046 " Display the video profile info, video capabilities and\n"
1047 " video format properties of each video profile supported\n"
1048 " by each physical device.\n"
1049 " Note: This only affects text output which by default\n"
1050 " only contains the list of supported video profile names.\n";
1052 void print_usage(const std::string
&executable_name
) {
1053 std::cout
<< "\n" APP_SHORT_NAME
" - Summarize " API_NAME
" information in relation to the current environment.\n\n";
1054 std::cout
<< "USAGE: \n";
1055 std::cout
<< " " << executable_name
<< " --summary\n";
1056 std::cout
<< " " << executable_name
<< " -o <filename> | --output <filename>\n";
1057 std::cout
<< " " << executable_name
<< " -j | -j=<gpu-number> | --json | --json=<gpu-number>\n";
1058 std::cout
<< " " << executable_name
<< " --text\n";
1059 std::cout
<< " " << executable_name
<< " --html\n";
1060 std::cout
<< " " << executable_name
<< " --show-formats\n";
1061 std::cout
<< " " << executable_name
<< " --show-tool-props\n";
1062 std::cout
<< " " << executable_name
<< " --show-promoted-structs\n";
1063 std::cout
<< "\n" << help_message_body
<< std::endl
;
1066 struct ParsedResults
{
1067 OutputCategory output_category
;
1068 uint32_t selected_gpu
;
1069 bool has_selected_gpu
; // differentiate between selecting the 0th gpu and using the default 0th value
1070 bool show_tool_props
;
1072 bool show_promoted_structs
;
1073 bool show_video_props
;
1075 std::string filename
; // set if explicitely given, or if vkconfig_output has a <path> argument
1076 std::string default_filename
;
1079 util::vulkaninfo_optional
<ParsedResults
> parse_arguments(int argc
, char **argv
, std::string executable_name
) {
1080 ParsedResults results
{}; // default it to zero init everything
1081 results
.output_category
= OutputCategory::text
; // default output category
1082 results
.default_filename
= APP_SHORT_NAME
".txt";
1083 for (int i
= 1; i
< argc
; ++i
) {
1084 // A internal-use-only format for communication with the Vulkan Configurator tool
1085 // Usage "--vkconfig_output <path>"
1086 // -o can be used to specify the filename instead
1087 if (0 == strcmp("--vkconfig_output", argv
[i
])) {
1088 results
.output_category
= OutputCategory::vkconfig_output
;
1089 results
.print_to_file
= true;
1090 results
.default_filename
= APP_SHORT_NAME
".json";
1091 if (argc
> (i
+ 1) && argv
[i
+ 1][0] != '-') {
1093 results
.filename
= (std::string(argv
[i
+ 1]) + "\\" APP_SHORT_NAME
".json");
1095 results
.filename
= (std::string(argv
[i
+ 1]) + "/" APP_SHORT_NAME
".json");
1099 } else if (strncmp("--json", argv
[i
], 6) == 0 || strncmp(argv
[i
], "-j", 2) == 0) {
1100 if (strlen(argv
[i
]) > 7 && strncmp("--json=", argv
[i
], 7) == 0) {
1101 results
.selected_gpu
= static_cast<uint32_t>(strtol(argv
[i
] + 7, nullptr, 10));
1102 results
.has_selected_gpu
= true;
1104 if (strlen(argv
[i
]) > 3 && strncmp("-j=", argv
[i
], 3) == 0) {
1105 results
.selected_gpu
= static_cast<uint32_t>(strtol(argv
[i
] + 3, nullptr, 10));
1106 results
.has_selected_gpu
= true;
1108 results
.output_category
= OutputCategory::profile_json
;
1109 results
.default_filename
= APP_SHORT_NAME
".json";
1110 results
.print_to_file
= true;
1111 } else if (strcmp(argv
[i
], "--summary") == 0) {
1112 results
.output_category
= OutputCategory::summary
;
1113 } else if (strcmp(argv
[i
], "--text") == 0) {
1114 results
.output_category
= OutputCategory::text
;
1115 results
.default_filename
= APP_SHORT_NAME
".txt";
1116 } else if (strcmp(argv
[i
], "--html") == 0) {
1117 results
.output_category
= OutputCategory::html
;
1118 results
.print_to_file
= true;
1119 results
.default_filename
= APP_SHORT_NAME
".html";
1120 } else if (strcmp(argv
[i
], "--show-tool-props") == 0) {
1121 results
.show_tool_props
= true;
1122 } else if (strcmp(argv
[i
], "--show-formats") == 0) {
1123 results
.show_formats
= true;
1124 } else if (strcmp(argv
[i
], "--show-promoted-structs") == 0) {
1125 results
.show_promoted_structs
= true;
1126 } else if (strcmp(argv
[i
], "--show-video-props") == 0) {
1127 results
.show_video_props
= true;
1128 } else if ((strcmp(argv
[i
], "--output") == 0 || strcmp(argv
[i
], "-o") == 0) && argc
> (i
+ 1)) {
1129 if (argv
[i
+ 1][0] == '-') {
1130 std::cout
<< "-o or --output must be followed by a filename\n";
1133 results
.print_to_file
= true;
1134 results
.filename
= argv
[i
+ 1];
1136 } else if (strcmp(argv
[i
], "--help") == 0 || strcmp(argv
[i
], "-h") == 0) {
1137 print_usage(executable_name
);
1140 print_usage(executable_name
);
1147 PrinterCreateDetails
get_printer_create_details(ParsedResults
&parse_data
, AppInstance
&inst
, AppGpu
&selected_gpu
,
1148 std::string
const &executable_name
) {
1149 PrinterCreateDetails create
{};
1150 create
.print_to_file
= parse_data
.print_to_file
;
1151 create
.file_name
= (!parse_data
.filename
.empty()) ? parse_data
.filename
: parse_data
.default_filename
;
1152 switch (parse_data
.output_category
) {
1154 case (OutputCategory::text
):
1155 create
.output_type
= OutputType::text
;
1157 case (OutputCategory::html
):
1158 create
.output_type
= OutputType::html
;
1160 case (OutputCategory::profile_json
):
1161 create
.output_type
= OutputType::json
;
1162 create
.start_string
=
1163 std::string("{\n\t\"$schema\": ") + "\"https://schema.khronos.org/vulkan/profiles-0.8-latest.json\"";
1164 if (parse_data
.filename
.empty()) {
1165 create
.file_name
= std::string("VP_" APP_UPPER_CASE_NAME
"_") + std::string(selected_gpu
.props
.deviceName
) + "_" +
1166 selected_gpu
.GetDriverVersionString();
1167 for (auto &c
: create
.file_name
) {
1168 if (c
== ' ' || c
== '.') c
= '_';
1170 create
.file_name
+= ".json";
1173 case (OutputCategory::vkconfig_output
):
1174 create
.output_type
= OutputType::vkconfig_output
;
1175 create
.start_string
= "{\n\t\"" API_NAME
" Instance Version\": \"" + inst
.api_version
.str() + "\"";
1181 void RunPrinter(Printer
&p
, ParsedResults parse_data
, AppInstance
&instance
, std::vector
<std::unique_ptr
<AppGpu
>> &gpus
,
1182 std::vector
<std::unique_ptr
<AppSurface
>> &surfaces
) {
1183 #ifdef VK_USE_PLATFORM_IOS_MVK
1184 p
.SetAlwaysOpenDetails(true);
1186 if (parse_data
.output_category
== OutputCategory::summary
) {
1187 DumpSummaryInstance(p
, instance
);
1189 ObjectWrapper
obj(p
, "Devices");
1190 IndentWrapper
indent(p
);
1191 for (auto &gpu
: gpus
) {
1192 DumpSummaryGPU(p
, *(gpu
.get()));
1194 } else if (parse_data
.output_category
== OutputCategory::profile_json
) {
1195 DumpGpuProfileCapabilities(p
, *(gpus
.at(parse_data
.selected_gpu
).get()));
1196 DumpGpuProfileInfo(p
, *(gpus
.at(parse_data
.selected_gpu
).get()));
1198 // text, html, vkconfig_output
1200 DumpExtensions(p
, "Instance Extensions", instance
.global_extensions
);
1203 DumpLayers(p
, instance
.global_layers
, gpus
);
1204 #if defined(VULKANINFO_WSI_ENABLED)
1205 // Doesn't print anything if no surfaces are available
1206 DumpPresentableSurfaces(p
, instance
, gpus
, surfaces
);
1207 #endif // defined(VULKANINFO_WSI_ENABLED)
1208 DumpGroups(p
, instance
);
1211 ObjectWrapper
obj(p
, "Device Properties and Extensions");
1212 IndentWrapper
indent(p
);
1214 for (auto &gpu
: gpus
) {
1215 DumpGpu(p
, *(gpu
.get()), parse_data
.show_tool_props
, parse_data
.show_formats
, parse_data
.show_promoted_structs
,
1216 parse_data
.show_video_props
);
1221 #ifdef VK_USE_PLATFORM_IOS_MVK
1222 // On iOS, we'll call this ourselves from a parent routine in the GUI
1223 int vulkanInfoMain(int argc
, char **argv
) {
1225 int main(int argc
, char **argv
) {
1228 // Figure out the name of the executable, pull out the name if given a path
1229 // Default is `vulkaninfo`
1230 std::string executable_name
= APP_SHORT_NAME
;
1232 const auto argv_0
= std::string(argv
[0]);
1233 // don't include path separator
1234 // Look for forward slash first, only look for backslash if that found nothing
1235 auto last_occurrence
= argv_0
.rfind('/');
1236 if (last_occurrence
== std::string::npos
) {
1237 last_occurrence
= argv_0
.rfind('\\');
1239 if (last_occurrence
!= std::string::npos
&& last_occurrence
+ 1 < argv_0
.size()) {
1240 executable_name
= argv_0
.substr(last_occurrence
+ 1);
1244 auto parsing_return
= parse_arguments(argc
, argv
, executable_name
);
1245 if (!parsing_return
) return 1;
1246 ParsedResults parse_data
= parsing_return
.value();
1248 #if defined(_MSC_VER)
1249 _set_abort_behavior(0, _WRITE_ABORT_MSG
| _CALL_REPORTFAULT
);
1250 SetErrorMode(SEM_FAILCRITICALERRORS
| SEM_NOGPFAULTERRORBOX
);
1251 _CrtSetReportMode(_CRT_ASSERT
, _CRTDBG_MODE_FILE
);
1252 _CrtSetReportFile(_CRT_ASSERT
, _CRTDBG_FILE_STDERR
);
1254 if (ConsoleIsExclusive()) ConsoleEnlarge();
1255 User32Handles local_user32_handles
;
1256 user32_handles
= &local_user32_handles
;
1257 if (!local_user32_handles
.load()) {
1258 fprintf(stderr
, "Failed to load user32.dll library!\n");
1259 if (parse_data
.output_category
== OutputCategory::text
&& !parse_data
.print_to_file
) wait_for_console_destroy();
1264 int return_code
= 0; // set in case of error
1265 std::unique_ptr
<Printer
> printer
;
1266 std::ostream
std_out(std::cout
.rdbuf());
1267 std::ofstream file_out
;
1268 std::ostream
*out
= &std_out
;
1270 // if any essential vulkan call fails, it throws an exception
1272 AppInstance instance
= {};
1273 SetupWindowExtensions(instance
);
1275 auto phys_devices
= instance
.FindPhysicalDevices();
1277 #if defined(VULKANINFO_WSI_ENABLED)
1278 for (auto &surface_extension
: instance
.surface_extensions
) {
1279 surface_extension
.create_window(instance
);
1280 surface_extension
.surface
= surface_extension
.create_surface(instance
);
1282 #endif // defined(VULKANINFO_WSI_ENABLED)
1284 std::vector
<std::unique_ptr
<AppGpu
>> gpus
;
1286 uint32_t gpu_counter
= 0;
1287 for (auto &phys_device
: phys_devices
) {
1289 std::unique_ptr
<AppGpu
>(new AppGpu(instance
, gpu_counter
++, phys_device
, parse_data
.show_promoted_structs
)));
1292 std::vector
<std::unique_ptr
<AppSurface
>> surfaces
;
1293 #if defined(VULKANINFO_WSI_ENABLED)
1294 for (auto &surface_extension
: instance
.surface_extensions
) {
1295 for (auto &gpu
: gpus
) {
1297 // check if the surface is supported by the physical device before adding it to the list
1298 VkBool32 supported
= VK_FALSE
;
1299 VkResult err
= vkGetPhysicalDeviceSurfaceSupportKHR(gpu
->phys_device
, 0, surface_extension
.surface
, &supported
);
1300 if (err
!= VK_SUCCESS
|| supported
== VK_FALSE
) continue;
1303 std::unique_ptr
<AppSurface
>(new AppSurface(instance
, *gpu
.get(), gpu
->phys_device
, surface_extension
)));
1304 } catch (std::exception
&e
) {
1305 std::cerr
<< "ERROR while creating surface for extension " << surface_extension
.name
<< " : " << e
.what()
1310 #endif // defined(VULKANINFO_WSI_ENABLED)
1312 if (parse_data
.selected_gpu
>= gpus
.size()) {
1313 if (parse_data
.has_selected_gpu
) {
1314 std::cout
<< "The selected gpu (" << parse_data
.selected_gpu
<< ") is not a valid GPU index. ";
1315 if (gpus
.size() == 0) {
1316 std::cout
<< APP_SHORT_NAME
" could not find any GPU's.\n";
1319 if (gpus
.size() == 1) {
1320 std::cout
<< "The only available GPU selection is 0.\n";
1322 std::cout
<< "The available GPUs are in the range of 0 to " << gpus
.size() - 1 << ".\n";
1326 } else if (parse_data
.output_category
== OutputCategory::profile_json
) {
1327 std::cout
<< APP_SHORT_NAME
" could not find any GPU's.\n";
1331 auto printer_data
= get_printer_create_details(parse_data
, instance
, *gpus
.at(parse_data
.selected_gpu
), executable_name
);
1332 if (printer_data
.print_to_file
) {
1333 file_out
= std::ofstream(printer_data
.file_name
);
1336 printer
= std::unique_ptr
<Printer
>(new Printer(printer_data
, *out
, instance
.api_version
));
1338 RunPrinter(*(printer
.get()), parse_data
, instance
, gpus
, surfaces
);
1340 // Call the printer's destructor before the file handle gets closed
1341 printer
.reset(nullptr);
1342 #if defined(VULKANINFO_WSI_ENABLED)
1343 for (auto &surface_extension
: instance
.surface_extensions
) {
1344 AppDestroySurface(instance
, surface_extension
.surface
);
1345 surface_extension
.destroy_window(instance
);
1347 #endif // defined(VULKANINFO_WSI_ENABLED)
1348 } catch (std::exception
&e
) {
1349 // Print the error to stderr and leave all outputs in a valid state (mainly for json)
1350 std::cerr
<< "ERROR at " << e
.what() << "\n";
1352 printer
->FinishOutput();
1356 // Call the printer's destructor before the file handle gets closed
1357 printer
.reset(nullptr);
1361 if (parse_data
.output_category
== OutputCategory::text
&& !parse_data
.print_to_file
) wait_for_console_destroy();