2 * Copyright (c) 2015-2020 The Khronos Group Inc.
3 * Copyright (c) 2015-2020 Valve Corporation
4 * Copyright (c) 2015-2020 LunarG, Inc.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
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 * Author: Charles Giessen <charles@lunarg.com>
29 #include "vulkaninfo.hpp"
32 // Initialize User32 pointers
33 PFN_AdjustWindowRect User32Handles::pfnAdjustWindowRect = nullptr;
34 PFN_CreateWindowExA User32Handles::pfnCreateWindowExA = nullptr;
35 PFN_DefWindowProcA User32Handles::pfnDefWindowProcA = nullptr;
36 PFN_DestroyWindow User32Handles::pfnDestroyWindow = nullptr;
37 PFN_LoadIconA User32Handles::pfnLoadIconA = nullptr;
38 PFN_RegisterClassExA User32Handles::pfnRegisterClassExA = nullptr;
40 HMODULE User32Handles::user32DllHandle = nullptr;
44 // =========== Dump Functions ========= //
46 void DumpExtensions(Printer &p, std::string layer_name, std::vector<VkExtensionProperties> extensions, bool do_indent) {
47 std::sort(extensions.begin(), extensions.end(), [](VkExtensionProperties &a, VkExtensionProperties &b) -> int {
48 return std::string(a.extensionName) < std::string(b.extensionName);
51 size_t max_length = 0;
52 for (const auto &ext : extensions) {
53 max_length = std::max(max_length, std::strlen(ext.extensionName));
56 ObjectWrapper obj(p, layer_name + " Extensions", extensions.size());
57 if (do_indent) p.IndentDecrease();
58 for (auto &ext : extensions) {
59 p.PrintExtension(ext.extensionName, ext.specVersion, max_length);
61 if (do_indent) p.IndentIncrease();
63 void DumpExtensions(Printer &p, std::string layer_name, std::vector<VkExtensionProperties> extensions) {
64 DumpExtensions(p, layer_name, extensions, false);
66 void DumpLayers(Printer &p, std::vector<LayerExtensionList> layers, const std::vector<std::unique_ptr<AppGpu>> &gpus) {
67 std::sort(layers.begin(), layers.end(), [](LayerExtensionList &left, LayerExtensionList &right) -> int {
68 return std::strncmp(left.layer_properties.layerName, right.layer_properties.layerName, VK_MAX_DESCRIPTION_SIZE) < 0;
71 case OutputType::text:
72 case OutputType::html: {
74 ArrayWrapper arr(p, "Layers", layers.size());
75 IndentWrapper indent(p);
77 for (auto &layer : layers) {
78 auto v_str = VkVersionString(layer.layer_properties.specVersion);
79 auto props = layer.layer_properties;
81 std::string header = p.DecorateAsType(props.layerName) + " (" + props.description + ") Vulkan version " +
82 p.DecorateAsValue(v_str) + ", layer version " +
83 p.DecorateAsValue(std::to_string(props.implementationVersion));
84 ObjectWrapper obj(p, header);
85 DumpExtensions(p, "Layer", layer.extension_properties);
87 ArrayWrapper arr(p, "Devices", gpus.size());
88 for (auto &gpu : gpus) {
89 p.PrintKeyValue("GPU id", gpu->id, 0, gpu->props.deviceName);
90 auto exts = gpu->AppGetPhysicalDeviceLayerExtensions(props.layerName);
91 DumpExtensions(p, "Layer-Device", exts);
98 case OutputType::json: {
99 ArrayWrapper arr(p, "ArrayOfVkLayerProperties", layers.size());
101 for (auto &layer : layers) {
102 p.SetElementIndex(i++);
103 DumpVkLayerProperties(p, "layerProperty", layer.layer_properties);
107 case OutputType::vkconfig_output: {
108 ObjectWrapper obj(p, "Layer Properties");
109 for (auto &layer : layers) {
110 ObjectWrapper obj_name(p, layer.layer_properties.layerName);
111 p.PrintKeyString("layerName", layer.layer_properties.layerName, 21);
112 p.PrintKeyString("version", VkVersionString(layer.layer_properties.specVersion), 21);
113 p.PrintKeyValue("implementation version", layer.layer_properties.implementationVersion, 21);
114 p.PrintKeyString("description", layer.layer_properties.description, 21);
115 DumpExtensions(p, "Layer", layer.extension_properties);
116 ObjectWrapper obj_devices(p, "Devices");
117 for (auto &gpu : gpus) {
118 ObjectWrapper obj(p, gpu->props.deviceName);
119 p.PrintKeyValue("GPU id", gpu->id, 0, gpu->props.deviceName);
120 auto exts = gpu->AppGetPhysicalDeviceLayerExtensions(layer.layer_properties.layerName);
121 DumpExtensions(p, "Layer-Device", exts);
129 void DumpSurfaceFormats(Printer &p, AppInstance &inst, AppSurface &surface) {
130 std::vector<VkSurfaceFormatKHR> formats;
131 if (inst.CheckExtensionEnabled(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME)) {
132 for (auto &format : surface.surf_formats2) {
133 formats.push_back(format.surfaceFormat);
136 for (auto &format : surface.surf_formats) {
137 formats.push_back(format);
140 ObjectWrapper obj(p, "Formats", formats.size());
142 for (auto &format : formats) {
143 p.SetElementIndex(i++);
144 DumpVkSurfaceFormatKHR(p, "SurfaceFormat", format);
148 void DumpPresentModes(Printer &p, AppSurface &surface) {
149 ArrayWrapper arr(p, "Present Modes", surface.surf_present_modes.size());
150 for (auto &mode : surface.surf_present_modes) {
151 p.SetAsType().PrintString(VkPresentModeKHRString(mode));
155 void DumpSurfaceCapabilities(Printer &p, AppInstance &inst, AppGpu &gpu, AppSurface &surface) {
156 auto &surf_cap = surface.surface_capabilities;
158 DumpVkSurfaceCapabilitiesKHR(p, "VkSurfaceCapabilitiesKHR", surf_cap);
160 if (inst.CheckExtensionEnabled(VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME)) {
162 ObjectWrapper obj(p, "VkSurfaceCapabilities2EXT");
164 ArrayWrapper arr(p, "supportedSurfaceCounters");
165 if (surface.surface_capabilities2_ext.supportedSurfaceCounters == 0) p.PrintString("None");
166 if (surface.surface_capabilities2_ext.supportedSurfaceCounters & VK_SURFACE_COUNTER_VBLANK_EXT) {
167 p.SetAsType().PrintString("VK_SURFACE_COUNTER_VBLANK_EXT");
171 if (inst.CheckExtensionEnabled(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME)) {
172 chain_iterator_surface_capabilities2(p, inst, gpu, surface.surface_capabilities2_khr.pNext, inst.vk_version);
176 void DumpSurface(Printer &p, AppInstance &inst, AppGpu &gpu, AppSurface &surface, std::set<std::string> surface_types) {
177 ObjectWrapper obj(p, std::string("GPU id : ") + p.DecorateAsValue(std::to_string(gpu.id)) + " (" + gpu.props.deviceName + ")");
179 if (surface_types.size() == 0) {
180 p.SetAsType().PrintKeyString("Surface type", "No type found");
181 } else if (surface_types.size() == 1) {
182 p.SetAsType().PrintKeyString("Surface type", surface.surface_extension.name);
184 ArrayWrapper arr(p, "Surface types", surface_types.size());
185 for (auto &name : surface_types) {
190 DumpSurfaceFormats(p, inst, surface);
191 DumpPresentModes(p, surface);
192 DumpSurfaceCapabilities(p, inst, gpu, surface);
197 struct SurfaceTypeGroup {
200 std::set<std::string> surface_types;
203 bool operator==(AppSurface const &a, AppSurface const &b) {
204 return a.phys_device == b.phys_device && a.surf_present_modes == b.surf_present_modes && a.surf_formats == b.surf_formats &&
205 a.surf_formats2 == b.surf_formats2 && a.surface_capabilities == b.surface_capabilities &&
206 a.surface_capabilities2_khr == b.surface_capabilities2_khr && a.surface_capabilities2_ext == b.surface_capabilities2_ext;
209 void DumpPresentableSurfaces(Printer &p, AppInstance &inst, const std::vector<std::unique_ptr<AppGpu>> &gpus,
210 const std::vector<std::unique_ptr<AppSurface>> &surfaces) {
212 ObjectWrapper obj(p, "Presentable Surfaces");
213 IndentWrapper indent(p);
215 std::vector<SurfaceTypeGroup> surface_list;
217 for (auto &surface : surfaces) {
218 auto exists = surface_list.end();
219 for (auto it = surface_list.begin(); it != surface_list.end(); it++) {
220 // check for duplicat surfaces that differ only by the surface extension
221 if (*(it->surface) == *(surface.get())) {
226 if (exists != surface_list.end()) {
227 exists->surface_types.insert(surface.get()->surface_extension.name);
229 // find surface.phys_device's corresponding AppGpu
230 AppGpu *corresponding_gpu = nullptr;
231 for (auto &gpu : gpus) {
232 if (gpu->phys_device == surface->phys_device) corresponding_gpu = gpu.get();
234 if (corresponding_gpu != nullptr)
235 surface_list.push_back({surface.get(), corresponding_gpu, {surface.get()->surface_extension.name}});
238 for (auto &group : surface_list) {
239 DumpSurface(p, inst, *group.gpu, *group.surface, group.surface_types);
244 void DumpGroups(Printer &p, AppInstance &inst) {
245 if (inst.CheckExtensionEnabled(VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME)) {
246 auto groups = GetGroups(inst);
247 if (groups.size() == 0) {
249 ObjectWrapper obj(p, "Groups");
250 p.PrintString("No Device Groups Found");
256 ObjectWrapper obj(p, "Device Groups");
257 IndentWrapper indent(p);
260 for (auto &group : groups) {
261 ObjectWrapper obj(p, "Group " + std::to_string(group_id));
262 auto group_props = GetGroupProps(inst, group);
264 ObjectWrapper obj(p, "Properties");
266 ArrayWrapper arr(p, "physicalDevices", group.physicalDeviceCount);
268 for (auto &prop : group_props) {
269 p.PrintString(std::string(prop.deviceName) + " (ID: " + p.DecorateAsValue(std::to_string(id++)) + ")");
272 p.PrintKeyValue("subsetAllocation", group.subsetAllocation);
276 auto group_capabilities = GetGroupCapabilities(inst, group);
277 if (group_capabilities.first == false) {
278 p.PrintKeyString("Present Capabilities",
279 "Group does not support VK_KHR_device_group, skipping printing present capabilities");
281 ObjectWrapper obj(p, "Present Capabilities");
282 for (uint32_t i = 0; i < group.physicalDeviceCount; i++) {
284 p, std::string(group_props[i].deviceName) + " (ID: " + p.DecorateAsValue(std::to_string(i)) + ")");
285 ArrayWrapper arr(p, "Can present images from the following devices", group.physicalDeviceCount);
287 for (uint32_t j = 0; j < group.physicalDeviceCount; j++) {
288 uint32_t mask = 1 << j;
289 if (group_capabilities.second.presentMask[i] & mask) {
290 p.PrintString(std::string(group_props[j].deviceName) + " (ID: " + p.DecorateAsValue(std::to_string(j)) +
295 DumpVkDeviceGroupPresentModeFlagsKHR(p, "Present modes", group_capabilities.second.modes);
304 void GpuDumpProps(Printer &p, AppGpu &gpu) {
305 auto props = gpu.GetDeviceProperties();
308 ObjectWrapper obj(p, "VkPhysicalDeviceProperties");
309 p.PrintKeyValue("apiVersion", props.apiVersion, 14, VkVersionString(props.apiVersion));
310 p.PrintKeyValue("driverVersion", props.driverVersion, 14, to_hex_str(props.driverVersion));
311 p.PrintKeyString("vendorID", to_hex_str(props.vendorID), 14);
312 p.PrintKeyString("deviceID", to_hex_str(props.deviceID), 14);
313 p.PrintKeyString("deviceType", VkPhysicalDeviceTypeString(props.deviceType), 14);
314 p.PrintKeyString("deviceName", props.deviceName, 14);
315 if (p.Type() == OutputType::vkconfig_output) {
316 ArrayWrapper arr(p, "pipelineCacheUUID", VK_UUID_SIZE);
317 for (uint32_t i = 0; i < VK_UUID_SIZE; ++i) {
318 p.PrintElement(static_cast<uint32_t>(props.pipelineCacheUUID[i]));
323 DumpVkPhysicalDeviceLimits(p, "VkPhysicalDeviceLimits",
324 gpu.inst.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)
325 ? gpu.props2.properties.limits
328 DumpVkPhysicalDeviceSparseProperties(p, "VkPhysicalDeviceSparseProperties",
329 gpu.inst.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)
330 ? gpu.props2.properties.sparseProperties
331 : gpu.props.sparseProperties);
333 if (gpu.inst.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
334 void *place = gpu.props2.pNext;
335 chain_iterator_phys_device_props2(p, gpu.inst, gpu, place, gpu.api_version);
339 void GpuDumpPropsJson(Printer &p, AppGpu &gpu) {
340 auto props = gpu.GetDeviceProperties();
341 ObjectWrapper obj(p, "VkPhysicalDeviceProperties");
342 p.PrintKeyValue("apiVersion", props.apiVersion, 14, VkVersionString(props.apiVersion));
343 p.PrintKeyValue("driverVersion", props.driverVersion, 14, to_hex_str(props.driverVersion));
344 p.PrintKeyValue("vendorID", props.vendorID, 14);
345 p.PrintKeyValue("deviceID", props.deviceID, 14);
346 p.PrintKeyValue("deviceType", props.deviceType, 14);
347 p.PrintKeyString("deviceName", props.deviceName, 14);
349 ArrayWrapper arr(p, "pipelineCacheUUID", VK_UUID_SIZE);
350 for (uint32_t i = 0; i < VK_UUID_SIZE; ++i) {
351 p.PrintElement(static_cast<uint32_t>(props.pipelineCacheUUID[i]));
355 DumpVkPhysicalDeviceLimits(p, "VkPhysicalDeviceLimits",
356 gpu.inst.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)
357 ? gpu.props2.properties.limits
359 DumpVkPhysicalDeviceSparseProperties(p, "VkPhysicalDeviceSparseProperties",
360 gpu.inst.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)
361 ? gpu.props2.properties.sparseProperties
362 : gpu.props.sparseProperties);
365 void GpuDumpQueueProps(Printer &p, std::vector<SurfaceExtension> &surfaces, AppQueueFamilyProperties &queue) {
366 p.SetSubHeader().SetElementIndex(static_cast<int>(queue.queue_index));
367 ObjectWrapper obj(p, "queueProperties");
368 if (p.Type() == OutputType::vkconfig_output) {
369 DumpVkExtent3D(p, "minImageTransferGranularity", queue.props.minImageTransferGranularity);
371 p.PrintKeyValue("minImageTransferGranularity", queue.props.minImageTransferGranularity, 27);
373 p.PrintKeyValue("queueCount", queue.props.queueCount, 27);
374 p.PrintKeyString("queueFlags", VkQueueFlagsString(queue.props.queueFlags), 27);
375 p.PrintKeyValue("timestampValidBits", queue.props.timestampValidBits, 27);
377 if (queue.is_present_platform_agnostic) {
378 p.PrintKeyString("present support", queue.platforms_support_present ? "true" : "false", 27);
381 for (auto &surface : surfaces) {
382 if (surface.name.size() > width) width = surface.name.size();
384 ObjectWrapper obj(p, "present support");
385 for (auto &surface : surfaces) {
386 p.PrintKeyString(surface.name, surface.supports_present ? "true" : "false", width);
393 void GpuDumpQueuePropsJson(Printer &p, std::vector<SurfaceExtension> &surfaces, AppQueueFamilyProperties &queue) {
394 ObjectWrapper obj(p, "");
395 DumpVkExtent3D(p, "minImageTransferGranularity", queue.props.minImageTransferGranularity);
396 p.PrintKeyValue("queueCount", queue.props.queueCount, 27);
397 p.PrintKeyValue("queueFlags", queue.props.queueFlags, 27);
398 p.PrintKeyValue("timestampValidBits", queue.props.timestampValidBits, 27);
401 // This prints a number of bytes in a human-readable format according to prefixes of the International System of Quantities (ISQ),
402 // defined in ISO/IEC 80000. The prefixes used here are not SI prefixes, but rather the binary prefixes based on powers of 1024
403 // (kibi-, mebi-, gibi- etc.).
404 #define kBufferSize 32
406 std::string NumToNiceStr(const size_t sz) {
407 const char prefixes[] = "KMGTPEZY";
408 char buf[kBufferSize];
410 double result = (double)sz;
411 while (result > 1024 && which < 7) {
418 unit[0] = prefixes[which];
421 _snprintf_s(buf, kBufferSize * sizeof(char), kBufferSize, "%.2f %sB", result, unit);
423 snprintf(buf, kBufferSize, "%.2f %sB", result, unit);
425 return std::string(buf);
428 std::string append_human_readible(VkDeviceSize memory) {
429 return std::to_string(memory) + " (" + to_hex_str(memory) + ") (" + NumToNiceStr(static_cast<size_t>(memory)) + ")";
432 void GpuDumpMemoryProps(Printer &p, AppGpu &gpu) {
434 ObjectWrapper obj(p, "VkPhysicalDeviceMemoryProperties");
435 IndentWrapper indent(p);
437 ObjectWrapper obj(p, "memoryHeaps", gpu.memory_props.memoryHeapCount);
439 for (uint32_t i = 0; i < gpu.memory_props.memoryHeapCount; ++i) {
440 p.SetElementIndex(static_cast<int>(i));
441 ObjectWrapper obj(p, "memoryHeaps");
443 p.PrintKeyString("size", append_human_readible(gpu.memory_props.memoryHeaps[i].size), 6);
444 p.PrintKeyString("budget", append_human_readible(gpu.heapBudget[i]), 6);
445 p.PrintKeyString("usage", append_human_readible(gpu.heapUsage[i]), 6);
446 DumpVkMemoryHeapFlags(p, "flags", gpu.memory_props.memoryHeaps[i].flags, 6);
450 ObjectWrapper obj(p, "memoryTypes", gpu.memory_props.memoryTypeCount);
452 for (uint32_t i = 0; i < gpu.memory_props.memoryTypeCount; ++i) {
453 p.SetElementIndex(static_cast<int>(i));
454 ObjectWrapper obj(p, "memoryTypes");
455 p.PrintKeyValue("heapIndex", gpu.memory_props.memoryTypes[i].heapIndex, 13);
457 auto flags = gpu.memory_props.memoryTypes[i].propertyFlags;
458 DumpVkMemoryPropertyFlags(p, "propertyFlags = " + to_hex_str(flags), flags);
460 ObjectWrapper usable_for(p, "usable for");
461 const uint32_t memtype_bit = 1U << i;
463 // only linear and optimal tiling considered
464 std::vector<VkFormat> tiling_optimal_formats;
465 std::vector<VkFormat> tiling_linear_formats;
466 for (auto &image_tiling : gpu.memory_image_support_types) {
468 ArrayWrapper arr(p, VkImageTilingString(VkImageTiling(image_tiling.tiling)), -1);
469 bool has_any_support_types = false;
470 bool regular = false;
471 bool transient = false;
473 for (auto &image_format : image_tiling.formats) {
474 if (image_format.type_support.size() > 0) {
475 bool has_a_support_type = false;
476 for (auto &img_type : image_format.type_support) {
477 if (img_type.Compatible(memtype_bit)) {
478 has_a_support_type = true;
479 has_any_support_types = true;
480 if (img_type.type == ImageTypeSupport::Type::regular) regular = true;
481 if (img_type.type == ImageTypeSupport::Type::transient) transient = true;
482 if (img_type.type == ImageTypeSupport::Type::sparse) sparse = true;
485 if (has_a_support_type) {
486 if (image_format.format == color_format) {
487 p.PrintString("color images");
489 p.PrintString(VkFormatString(image_format.format));
494 if (!has_any_support_types) {
495 p.PrintString("None");
497 if (regular && !transient && sparse) p.PrintString("(non-transient)");
498 if (regular && transient && !sparse) p.PrintString("(non-sparse)");
499 if (regular && !transient && !sparse) p.PrintString("(non-sparse, non-transient)");
500 if (!regular && transient && sparse) p.PrintString("(sparse and transient only)");
501 if (!regular && !transient && sparse) p.PrintString("(sparse only)");
502 if (!regular && transient && !sparse) p.PrintString("(transient only)");
510 void GpuDumpMemoryPropsJson(Printer &p, AppGpu &gpu) {
511 ObjectWrapper obj(p, "VkPhysicalDeviceMemoryProperties");
513 ArrayWrapper arr(p, "memoryHeaps", gpu.memory_props.memoryHeapCount);
514 for (uint32_t i = 0; i < gpu.memory_props.memoryHeapCount; ++i) {
515 ObjectWrapper obj(p, "");
516 p.PrintKeyValue("flags", gpu.memory_props.memoryHeaps[i].flags);
517 p.PrintKeyValue("size", gpu.memory_props.memoryHeaps[i].size);
521 ArrayWrapper arr(p, "memoryTypes", gpu.memory_props.memoryTypeCount);
522 for (uint32_t i = 0; i < gpu.memory_props.memoryTypeCount; ++i) {
523 ObjectWrapper obj(p, "");
524 p.PrintKeyValue("heapIndex", gpu.memory_props.memoryTypes[i].heapIndex, 13);
525 p.PrintKeyValue("propertyFlags", gpu.memory_props.memoryTypes[i].propertyFlags, 13);
530 void GpuDumpFeatures(Printer &p, AppGpu &gpu) {
532 DumpVkPhysicalDeviceFeatures(p, "VkPhysicalDeviceFeatures", gpu.features);
534 if (gpu.inst.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
535 void *place = gpu.features2.pNext;
536 chain_iterator_phys_device_features2(p, gpu, place, gpu.api_version);
540 void GpuDumpFormatProperty(Printer &p, VkFormat fmt, VkFormatProperties prop) {
542 case OutputType::text: {
543 ObjectWrapper obj(p, "Properties");
544 DumpVkFormatFeatureFlags(p, "linearTiling", prop.linearTilingFeatures);
545 DumpVkFormatFeatureFlags(p, "optimalTiling", prop.optimalTilingFeatures);
546 DumpVkFormatFeatureFlags(p, "bufferFeatures", prop.bufferFeatures);
549 case OutputType::html: {
551 ObjectWrapper obj(p, VkFormatString(fmt));
553 DumpVkFormatFeatureFlags(p, "linearTiling", prop.linearTilingFeatures);
555 DumpVkFormatFeatureFlags(p, "optimalTiling", prop.optimalTilingFeatures);
557 DumpVkFormatFeatureFlags(p, "bufferFeatures", prop.bufferFeatures);
560 case OutputType::json: {
561 ObjectWrapper obj(p, "");
562 p.PrintKeyValue("formatID", fmt);
563 p.PrintKeyValue("linearTilingFeatures", prop.linearTilingFeatures);
564 p.PrintKeyValue("optimalTilingFeatures", prop.optimalTilingFeatures);
565 p.PrintKeyValue("bufferFeatures", prop.bufferFeatures);
568 case OutputType::vkconfig_output: {
569 ObjectWrapper obj(p, VkFormatString(fmt));
570 DumpVkFormatFeatureFlags(p, "linearTiling", prop.linearTilingFeatures);
571 DumpVkFormatFeatureFlags(p, "optimalTiling", prop.optimalTilingFeatures);
572 DumpVkFormatFeatureFlags(p, "bufferFeatures", prop.bufferFeatures);
578 void GpuDumpToolingInfo(Printer &p, AppGpu &gpu) {
579 auto tools = GetToolingInfo(gpu);
580 if (tools.size() > 0) {
582 ObjectWrapper obj(p, "Tooling Info");
583 for (auto tool : tools) {
584 DumpVkPhysicalDeviceToolPropertiesEXT(p, tool.name, tool);
590 void GpuDevDump(Printer &p, AppGpu &gpu) {
592 ObjectWrapper obj(p, "Format Properties");
593 IndentWrapper indent(p);
595 if (p.Type() == OutputType::text) {
596 auto fmtPropMap = FormatPropMap(gpu);
599 std::vector<VkFormat> unsupported_formats;
600 for (auto &prop : fmtPropMap) {
601 VkFormatProperties props;
602 props.linearTilingFeatures = prop.first.linear;
603 props.optimalTilingFeatures = prop.first.optimal;
604 props.bufferFeatures = prop.first.buffer;
605 if (props.linearTilingFeatures == 0 && props.optimalTilingFeatures == 0 && props.bufferFeatures == 0) {
606 unsupported_formats = prop.second;
610 p.SetElementIndex(counter++);
611 ObjectWrapper obj(p, "Common Format Group");
612 IndentWrapper indent(p);
614 ArrayWrapper arr(p, "Formats", prop.second.size());
615 for (auto &fmt : prop.second) {
616 p.SetAsType().PrintString(VkFormatString(fmt));
619 GpuDumpFormatProperty(p, VK_FORMAT_UNDEFINED, props);
623 ArrayWrapper arr(p, "Unsupported Formats", unsupported_formats.size());
624 for (auto &fmt : unsupported_formats) {
625 p.SetAsType().PrintString(VkFormatString(fmt));
628 for (auto &format : gpu.supported_format_ranges) {
629 if (gpu.FormatRangeSupported(format)) {
630 for (int32_t fmt_counter = format.first_format; fmt_counter <= format.last_format; ++fmt_counter) {
631 VkFormat fmt = static_cast<VkFormat>(fmt_counter);
633 VkFormatProperties props;
634 gpu.inst.dll.fp_vkGetPhysicalDeviceFormatProperties(gpu.phys_device, fmt, &props);
636 GpuDumpFormatProperty(p, fmt, props);
645 void GpuDevDumpJson(Printer &p, AppGpu &gpu) {
646 ArrayWrapper arr(p, "ArrayOfVkFormatProperties");
647 for (auto &format : gpu.supported_format_ranges) {
648 if (gpu.FormatRangeSupported(format)) {
649 for (int32_t fmt_counter = format.first_format; fmt_counter <= format.last_format; ++fmt_counter) {
650 VkFormat fmt = static_cast<VkFormat>(fmt_counter);
652 VkFormatProperties props;
653 gpu.inst.dll.fp_vkGetPhysicalDeviceFormatProperties(gpu.phys_device, fmt, &props);
655 // don't print format properties that are unsupported
656 if ((props.linearTilingFeatures || props.optimalTilingFeatures || props.bufferFeatures) == 0) continue;
658 GpuDumpFormatProperty(p, fmt, props);
663 // Print gpu info for text, html, & vkconfig_output
664 // Uses a seperate function than schema-json for clarity
665 void DumpGpu(Printer &p, AppGpu &gpu, bool show_formats) {
666 ObjectWrapper obj(p, "GPU" + std::to_string(gpu.id));
667 IndentWrapper indent(p);
669 GpuDumpProps(p, gpu);
670 DumpExtensions(p, "Device", gpu.device_extensions);
674 ObjectWrapper obj(p, "VkQueueFamilyProperties");
675 for (uint32_t i = 0; i < gpu.queue_count; i++) {
676 AppQueueFamilyProperties queue_props = AppQueueFamilyProperties(gpu, i);
677 GpuDumpQueueProps(p, gpu.inst.surface_extensions, queue_props);
680 GpuDumpMemoryProps(p, gpu);
681 GpuDumpFeatures(p, gpu);
682 GpuDumpToolingInfo(p, gpu);
684 if (p.Type() != OutputType::text || show_formats) {
691 // Print gpu info for json
692 void DumpGpuJson(Printer &p, AppGpu &gpu) {
693 GpuDumpPropsJson(p, gpu);
695 ArrayWrapper arr(p, "ArrayOfVkQueueFamilyProperties");
696 for (uint32_t i = 0; i < gpu.queue_count; i++) {
697 AppQueueFamilyProperties queue_props = AppQueueFamilyProperties(gpu, i);
698 GpuDumpQueuePropsJson(p, gpu.inst.surface_extensions, queue_props);
702 ArrayWrapper arr(p, "ArrayOfVkExtensionProperties");
703 for (auto &ext : gpu.device_extensions) {
704 p.PrintExtension(ext.extensionName, ext.specVersion);
708 GpuDumpMemoryPropsJson(p, gpu);
709 DumpVkPhysicalDeviceFeatures(p, "VkPhysicalDeviceFeatures", gpu.features);
710 GpuDevDumpJson(p, gpu);
713 // Print summary of system
714 void DumpSummaryInstance(Printer &p, AppInstance &inst) {
716 DumpExtensions(p, "Instance", inst.global_extensions, true);
720 ArrayWrapper arr(p, "Instance Layers", inst.global_layers.size());
721 IndentWrapper indent(p);
722 std::sort(inst.global_layers.begin(), inst.global_layers.end(), [](LayerExtensionList &left, LayerExtensionList &right) -> int {
723 return std::strncmp(left.layer_properties.layerName, right.layer_properties.layerName, VK_MAX_DESCRIPTION_SIZE) < 0;
725 size_t layer_name_max = 0;
726 size_t layer_desc_max = 0;
727 size_t layer_version_max = 0;
729 // find max of each type to align everything in columns
730 for (auto &layer : inst.global_layers) {
731 auto props = layer.layer_properties;
732 layer_name_max = std::max(layer_name_max, strlen(props.layerName));
733 layer_desc_max = std::max(layer_desc_max, strlen(props.description));
734 layer_version_max = std::max(layer_version_max, VkVersionString(layer.layer_properties.specVersion).size());
736 for (auto &layer : inst.global_layers) {
737 auto v_str = VkVersionString(layer.layer_properties.specVersion);
738 auto props = layer.layer_properties;
740 auto name_padding = std::string(layer_name_max - strlen(props.layerName), ' ');
741 auto desc_padding = std::string(layer_desc_max - strlen(props.description), ' ');
742 auto version_padding = std::string(layer_version_max - v_str.size(), ' ');
743 p.PrintString(std::string(props.layerName) + name_padding + " " + props.description + desc_padding + " " + v_str + " " +
744 version_padding + " version " + std::to_string(props.implementationVersion));
749 void DumpSummaryGPU(Printer &p, AppGpu &gpu) {
750 ObjectWrapper obj(p, "GPU" + std::to_string(gpu.id));
751 auto props = gpu.GetDeviceProperties();
752 p.PrintKeyValue("apiVersion", props.apiVersion, 18, VkVersionString(props.apiVersion));
753 p.PrintKeyValue("driverVersion", props.driverVersion, 18, to_hex_str(props.driverVersion));
754 p.PrintKeyString("vendorID", to_hex_str(props.vendorID), 18);
755 p.PrintKeyString("deviceID", to_hex_str(props.deviceID), 18);
756 p.PrintKeyString("deviceType", VkPhysicalDeviceTypeString(props.deviceType), 18);
757 p.PrintKeyString("deviceName", props.deviceName, 18);
759 if (gpu.inst.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) &&
760 (gpu.CheckPhysicalDeviceExtensionIncluded(VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME) || gpu.api_version.minor >= 2)) {
761 void *place = gpu.props2.pNext;
763 struct VkStructureHeader *structure = (struct VkStructureHeader *)place;
764 if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES) {
765 VkPhysicalDeviceDriverProperties *props = (VkPhysicalDeviceDriverProperties *)structure;
766 DumpVkDriverId(p, "driverID", props->driverID, 18);
767 p.PrintKeyString("driverName", props->driverName, 18);
768 p.PrintKeyString("driverInfo", props->driverInfo, 18);
769 DumpVkConformanceVersion(p, "conformanceVersion", props->conformanceVersion, 18);
771 place = structure->pNext;
776 #if defined(VK_ENABLE_BETA_EXTENSIONS)
777 void DumpPortability(Printer &p, AppGpu &gpu) {
778 if (gpu.CheckPhysicalDeviceExtensionIncluded(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) {
779 if (gpu.inst.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
780 void *props_place = gpu.props2.pNext;
781 while (props_place) {
782 struct VkStructureHeader *structure = (struct VkStructureHeader *)props_place;
783 if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_KHR) {
784 VkPhysicalDevicePortabilitySubsetPropertiesKHR *props =
785 (VkPhysicalDevicePortabilitySubsetPropertiesKHR *)structure;
786 DumpVkPhysicalDevicePortabilitySubsetPropertiesKHR(p, "VkPhysicalDevicePortabilitySubsetPropertiesKHR", *props);
789 props_place = structure->pNext;
792 void *feats_place = gpu.features2.pNext;
793 while (feats_place) {
794 struct VkStructureHeader *structure = (struct VkStructureHeader *)feats_place;
795 if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR) {
796 VkPhysicalDevicePortabilitySubsetFeaturesKHR *features =
797 (VkPhysicalDevicePortabilitySubsetFeaturesKHR *)structure;
798 DumpVkPhysicalDevicePortabilitySubsetFeaturesKHR(p, "VkPhysicalDevicePortabilitySubsetFeaturesKHR", *features);
801 feats_place = structure->pNext;
806 #endif // defined(VK_ENABLE_BETA_EXTENSIONS)
808 // ============ Printing Logic ============= //
811 // Enlarges the console window to have a large scrollback size.
812 static void ConsoleEnlarge() {
813 const HANDLE console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
815 // make the console window bigger
816 CONSOLE_SCREEN_BUFFER_INFO csbi;
818 if (GetConsoleScreenBufferInfo(console_handle, &csbi)) {
819 buffer_size.X = csbi.dwSize.X + 30;
820 buffer_size.Y = 20000;
821 SetConsoleScreenBufferSize(console_handle, buffer_size);
826 r.Right = csbi.dwSize.X - 1 + 30;
828 SetConsoleWindowInfo(console_handle, true, &r);
830 // change the console window title
831 SetConsoleTitle(TEXT(app_short_name));
835 void print_usage(const char *argv0) {
836 std::cout << "\nvulkaninfo - Summarize Vulkan information in relation to the current environment.\n\n";
837 std::cout << "USAGE: " << argv0 << " [options]\n\n";
838 std::cout << "OPTIONS:\n";
839 std::cout << "-h, --help Print this help.\n";
840 std::cout << "--html Produce an html version of vulkaninfo output, saved as\n";
841 std::cout << " \"vulkaninfo.html\" in the directory in which the command\n";
842 std::cout << " is run.\n";
843 std::cout << "-j, --json Produce a json version of vulkaninfo to standard output of the\n";
844 std::cout << " first gpu in the system conforming to the DevSim schema.\n";
845 std::cout << "--json=<gpu-number> For a multi-gpu system, a single gpu can be targetted by\n";
846 std::cout << " specifying the gpu-number associated with the gpu of \n";
847 std::cout << " interest. This number can be determined by running\n";
848 std::cout << " vulkaninfo without any options specified.\n";
849 #if defined(VK_ENABLE_BETA_EXTENSIONS)
850 std::cout << "--portability Produce a json version of vulkaninfo to standard output of the first\n";
851 std::cout << " gpu in the system conforming to the DevSim Portability Subset schema.\n";
852 std::cout << "--portability=<N> Produce the json output conforming to the DevSim Portability\n";
853 std::cout << " Subset Schema for the GPU specified to standard output,\n";
854 std::cout << " where N is the GPU desired.\n";
855 #endif // defined(VK_ENABLE_BETA_EXTENSIONS)
856 std::cout << "--show-formats Display the format properties of each physical device.\n";
857 std::cout << " Note: This option does not affect html or json output;\n";
858 std::cout << " they will always print format properties.\n\n";
859 std::cout << "--summary Show a summary of the instance and GPU's on a system.\n\n";
862 int main(int argc, char **argv) {
864 if (ConsoleIsExclusive()) ConsoleEnlarge();
865 if (!LoadUser32Dll()) {
866 fprintf(stderr, "Failed to load user32.dll library!\n");
867 WAIT_FOR_CONSOLE_DESTROY;
872 uint32_t selected_gpu = 0;
873 bool show_formats = false;
874 char *output_path = nullptr;
876 // Combinations of output: html only, html AND json, json only, human readable only
877 for (int i = 1; i < argc; ++i) {
878 // A internal-use-only format for communication with the Vulkan Configurator tool
879 // Usage "--vkconfig_output <path>"
880 if (0 == strcmp("--vkconfig_output", argv[i]) && argc > (i + 1)) {
881 human_readable_output = false;
882 vkconfig_output = true;
883 output_path = argv[i + 1];
885 } else if (strncmp("--json", argv[i], 6) == 0 || strcmp(argv[i], "-j") == 0) {
886 if (strlen(argv[i]) > 7 && strncmp("--json=", argv[i], 7) == 0) {
887 selected_gpu = static_cast<uint32_t>(strtol(argv[i] + 7, nullptr, 10));
889 human_readable_output = false;
891 portability_json = false;
892 #if defined(VK_ENABLE_BETA_EXTENSIONS)
893 } else if (strncmp("--portability", argv[i], 13) == 0) {
894 if (strlen(argv[i]) > 14 && strncmp("--portability=", argv[i], 14) == 0) {
895 selected_gpu = static_cast<uint32_t>(strtol(argv[i] + 14, nullptr, 10));
897 human_readable_output = false;
898 portability_json = true;
900 #endif // defined(VK_ENABLE_BETA_EXTENSIONS)
901 } else if (strcmp(argv[i], "--summary") == 0) {
903 } else if (strcmp(argv[i], "--html") == 0) {
904 human_readable_output = false;
906 } else if (strcmp(argv[i], "--show-formats") == 0) {
908 } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
909 print_usage(argv[0]);
912 print_usage(argv[0]);
916 std::vector<std::unique_ptr<Printer>> printers;
917 std::ostream out(std::cout.rdbuf());
918 std::ofstream html_out;
919 std::ofstream vkconfig_out;
921 // if any essential vulkan call fails, it throws an exception
923 AppInstance instance = {};
924 SetupWindowExtensions(instance);
926 auto pNext_chains = get_chain_infos();
928 auto phys_devices = instance.FindPhysicalDevices();
930 std::vector<std::unique_ptr<AppSurface>> surfaces;
931 #if defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || \
932 defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT) || defined(VK_USE_PLATFORM_WAYLAND_KHR) || \
933 defined(VK_USE_PLATFORM_DIRECTFB_EXT)
934 for (auto &surface_extension : instance.surface_extensions) {
935 surface_extension.create_window(instance);
936 surface_extension.surface = surface_extension.create_surface(instance);
937 for (auto &phys_device : phys_devices) {
938 surfaces.push_back(std::unique_ptr<AppSurface>(
939 new AppSurface(instance, phys_device, surface_extension, pNext_chains.surface_capabilities2)));
944 std::vector<std::unique_ptr<AppGpu>> gpus;
946 uint32_t gpu_counter = 0;
947 for (auto &phys_device : phys_devices) {
948 gpus.push_back(std::unique_ptr<AppGpu>(new AppGpu(instance, gpu_counter++, phys_device, pNext_chains)));
951 if (selected_gpu >= gpus.size()) {
952 std::cout << "The selected gpu (" << selected_gpu << ") is not a valid GPU index. ";
953 if (gpus.size() == 1)
954 std::cout << "The only available GPU selection is 0.\n";
956 std::cout << "The available GPUs are in the range of 0 to " << gpus.size() - 1 << ".\n";
960 if (human_readable_output) {
961 printers.push_back(std::unique_ptr<Printer>(new Printer(OutputType::text, out, selected_gpu, instance.vk_version)));
964 html_out = std::ofstream("vulkaninfo.html");
966 std::unique_ptr<Printer>(new Printer(OutputType::html, html_out, selected_gpu, instance.vk_version)));
969 std::string start_string =
970 std::string("{\n\t\"$schema\": \"https://schema.khronos.org/vulkan/devsim_1_0_0.json#\",\n") +
971 "\t\"comments\": {\n\t\t\"desc\": \"JSON configuration file describing GPU " + std::to_string(selected_gpu) +
972 ". Generated using the vulkaninfo program.\",\n\t\t\"vulkanApiVersion\": \"" +
973 VkVersionString(instance.vk_version) + "\"\n" + "\t}";
975 std::unique_ptr<Printer>(new Printer(OutputType::json, out, selected_gpu, instance.vk_version, start_string)));
977 #if defined(VK_ENABLE_BETA_EXTENSIONS)
978 if (portability_json) {
979 if (!gpus.at(selected_gpu)->CheckPhysicalDeviceExtensionIncluded(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME)) {
980 std::cerr << "Cannot create a json because the current selected GPU (" << selected_gpu
981 << ") does not support the VK_KHR_portability_subset extension.\n";
983 std::string start_string =
986 "\"https://schema.khronos.org/vulkan/devsim_VK_KHR_portability_subset-provisional-1.json#\",\n") +
987 "\t\"comments\": {\n\t\t\"desc\": \"JSON configuration file describing GPU " + std::to_string(selected_gpu) +
988 "'s portability features and properties. Generated using the vulkaninfo program.\",\n\t\t\"vulkanApiVersion\": "
990 VkVersionString(instance.vk_version) + "\"\n" + "\t}";
992 std::unique_ptr<Printer>(new Printer(OutputType::json, out, selected_gpu, instance.vk_version, start_string)));
995 #endif // defined(VK_ENABLE_BETA_EXTENSIONS)
996 if (vkconfig_output) {
998 vkconfig_out = std::ofstream(std::string(output_path) + "\\vulkaninfo.json");
1000 vkconfig_out = std::ofstream(std::string(output_path) + "/vulkaninfo.json");
1002 std::string start_string = "{\n\t\"Vulkan Instance Version\": \"" + VkVersionString(instance.vk_version) + "\"";
1003 printers.push_back(std::unique_ptr<Printer>(
1004 new Printer(OutputType::vkconfig_output, vkconfig_out, selected_gpu, instance.vk_version, start_string)));
1007 for (auto &p : printers) {
1009 DumpSummaryInstance(*p.get(), instance);
1011 ObjectWrapper obj(*p, "Devices");
1012 IndentWrapper indent(*p);
1013 for (auto &gpu : gpus) {
1014 DumpSummaryGPU(*p.get(), *gpu.get());
1016 } else if (p->Type() == OutputType::json) {
1017 if (portability_json) {
1018 #if defined(VK_ENABLE_BETA_EXTENSIONS)
1019 DumpPortability(*p.get(), *gpus.at(selected_gpu).get());
1020 #endif // defined(VK_ENABLE_BETA_EXTENSIONS)
1021 } else if (json_output) {
1022 DumpLayers(*p.get(), instance.global_layers, gpus);
1023 DumpGpuJson(*p.get(), *gpus.at(selected_gpu).get());
1026 // text, html, vkconfig_output
1028 DumpExtensions(*p.get(), "Instance", instance.global_extensions);
1031 DumpLayers(*p.get(), instance.global_layers, gpus);
1033 #if defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || \
1034 defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT) || defined(VK_USE_PLATFORM_WAYLAND_KHR) || \
1035 defined(VK_USE_PLATFORM_DIRECTFB_EXT)
1036 DumpPresentableSurfaces(*p.get(), instance, gpus, surfaces);
1038 DumpGroups(*p.get(), instance);
1041 ObjectWrapper obj(*p, "Device Properties and Extensions");
1042 IndentWrapper indent(*p);
1044 for (auto &gpu : gpus) {
1045 DumpGpu(*p.get(), *gpu.get(), show_formats);
1050 #if defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || \
1051 defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_METAL_EXT) || defined(VK_USE_PLATFORM_WAYLAND_KHR) || \
1052 defined(VK_USE_PLATFORM_DIRECTFB_EXT)
1054 for (auto &surface_extension : instance.surface_extensions) {
1055 AppDestroySurface(instance, surface_extension.surface);
1056 surface_extension.destroy_window(instance);
1059 } catch (std::exception &e) {
1060 // Print the error to stderr and leave all outputs in a valid state (mainly for json)
1061 std::cerr << "ERROR at " << e.what() << "\n";
1062 for (auto &p : printers) {
1068 // Call the printer's descrtuctor before the file handle gets closed
1069 for (auto &p : printers) {
1073 WAIT_FOR_CONSOLE_DESTROY;