aboutsummaryrefslogtreecommitdiff
path: root/tools/Vulkan-Tools/vulkaninfo/vulkaninfo.cpp
diff options
context:
space:
mode:
authorLizzy Fleckenstein <lizzy@vlhl.dev>2026-03-31 01:30:36 +0200
committerLizzy Fleckenstein <lizzy@vlhl.dev>2026-03-31 01:30:36 +0200
commit8e2ff15dbd3fe70fe2b52397b1eaba3fe2d7a5e8 (patch)
tree925fa596210d1a1f01e00e0743a643f4552e7a7a /tools/Vulkan-Tools/vulkaninfo/vulkaninfo.cpp
parent1f17b4df127bd280e50d93a46ae93df704adc2b0 (diff)
parent90bf5bc4fd8bea0d300f6564af256a51a34124b8 (diff)
downloadusermoji-8e2ff15dbd3fe70fe2b52397b1eaba3fe2d7a5e8.tar.xz
add tools/Vulkan-Tools
Diffstat (limited to 'tools/Vulkan-Tools/vulkaninfo/vulkaninfo.cpp')
-rw-r--r--tools/Vulkan-Tools/vulkaninfo/vulkaninfo.cpp1604
1 files changed, 1604 insertions, 0 deletions
diff --git a/tools/Vulkan-Tools/vulkaninfo/vulkaninfo.cpp b/tools/Vulkan-Tools/vulkaninfo/vulkaninfo.cpp
new file mode 100644
index 00000000..2c11226a
--- /dev/null
+++ b/tools/Vulkan-Tools/vulkaninfo/vulkaninfo.cpp
@@ -0,0 +1,1604 @@
+/*
+ * Copyright (c) 2015-2026 The Khronos Group Inc.
+ * Copyright (c) 2015-2026 Valve Corporation
+ * Copyright (c) 2015-2026 LunarG, Inc.
+ * Copyright (c) 2023-2024 RasterGrid Kft.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Author: Courtney Goeltzenleuchter <courtney@LunarG.com>
+ * Author: David Pinedo <david@lunarg.com>
+ * Author: Mark Lobodzinski <mark@lunarg.com>
+ * Author: Rene Lindsay <rene@lunarg.com>
+ * Author: Jeremy Kniager <jeremyk@lunarg.com>
+ * Author: Shannon McPherson <shannon@lunarg.com>
+ * Author: Bob Ellison <bob@lunarg.com>
+ * Author: Richard Wright <richard@lunarg.com>
+ * Author: Charles Giessen <charles@lunarg.com>
+ *
+ */
+
+#include <string>
+#ifdef _WIN32
+#include <crtdbg.h>
+#endif
+#include "vulkaninfo.hpp"
+
+// Used to sort the formats into buckets by their properties.
+std::unordered_map<PropFlags, std::set<VkFormat>> FormatPropMap(AppGpu &gpu) {
+ std::unordered_map<PropFlags, std::set<VkFormat>> map;
+ for (const auto fmtRange : format_ranges) {
+ if (gpu.FormatRangeSupported(fmtRange)) {
+ for (int32_t fmt = fmtRange.first_format; fmt <= fmtRange.last_format; ++fmt) {
+ PropFlags pf = get_format_properties(gpu, static_cast<VkFormat>(fmt));
+ map[pf].insert(static_cast<VkFormat>(fmt));
+ }
+ }
+ }
+ return map;
+}
+
+// =========== Dump Functions ========= //
+
+void DumpExtensions(Printer &p, std::string section_name, std::vector<VkExtensionProperties> extensions, bool do_indent = false) {
+ std::sort(extensions.begin(), extensions.end(), [](VkExtensionProperties &a, VkExtensionProperties &b) -> int {
+ return std::string(a.extensionName) < std::string(b.extensionName);
+ });
+
+ size_t max_length = 0;
+ for (const auto &ext : extensions) {
+ max_length = std::max(max_length, std::strlen(ext.extensionName));
+ }
+#if defined(VK_ENABLE_BETA_EXTENSIONS)
+ const std::string portability_ext_name = VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME;
+#endif // defined(VK_ENABLE_BETA_EXTENSIONS)
+ ObjectWrapper obj(p, section_name, extensions.size());
+ if (do_indent) p.IndentDecrease();
+ for (auto &ext : extensions) {
+#if defined(VK_ENABLE_BETA_EXTENSIONS)
+ if (p.Type() == OutputType::json && portability_ext_name == ext.extensionName) continue;
+#endif // defined(VK_ENABLE_BETA_EXTENSIONS)
+ p.PrintExtension(ext.extensionName, ext.specVersion, max_length);
+ }
+ if (do_indent) p.IndentIncrease();
+}
+
+void DumpLayers(Printer &p, std::vector<LayerExtensionList> layers, const std::vector<std::unique_ptr<AppGpu>> &gpus) {
+ std::sort(layers.begin(), layers.end(), [](LayerExtensionList &left, LayerExtensionList &right) -> int {
+ return std::strncmp(left.layer_properties.layerName, right.layer_properties.layerName, VK_MAX_DESCRIPTION_SIZE) < 0;
+ });
+ switch (p.Type()) {
+ case OutputType::text:
+ case OutputType::html: {
+ p.SetHeader();
+ ArrayWrapper arr_layers(p, "Layers", layers.size());
+ IndentWrapper indent(p);
+
+ for (auto &layer : layers) {
+ std::string v_str = APIVersion(layer.layer_properties.specVersion);
+ auto props = layer.layer_properties;
+
+ std::string header = p.DecorateAsType(props.layerName) + " (" + props.description + ") " API_NAME " version " +
+ p.DecorateAsValue(v_str) + ", layer version " +
+ p.DecorateAsValue(std::to_string(props.implementationVersion));
+ ObjectWrapper obj(p, header);
+ DumpExtensions(p, "Layer Extensions", layer.extension_properties);
+
+ ObjectWrapper arr_devices(p, "Devices", gpus.size());
+ for (auto &gpu : gpus) {
+ p.SetValueDescription(std::string(gpu->props.deviceName)).PrintKeyValue("GPU id", gpu->id);
+ auto exts = gpu->inst.AppGetPhysicalDeviceLayerExtensions(gpu->phys_device, props.layerName);
+ DumpExtensions(p, "Layer-Device Extensions", exts);
+ p.AddNewline();
+ }
+ }
+ break;
+ }
+
+ case OutputType::json: {
+ assert(false && "unimplemented");
+ break;
+ }
+ case OutputType::vkconfig_output: {
+ ObjectWrapper obj(p, "Layer Properties");
+ for (auto &layer : layers) {
+ ObjectWrapper obj_name(p, layer.layer_properties.layerName);
+ p.SetMinKeyWidth(21);
+ p.PrintKeyString("layerName", layer.layer_properties.layerName);
+ p.PrintKeyString("version", APIVersion(layer.layer_properties.specVersion).str());
+ p.PrintKeyValue("implementation version", layer.layer_properties.implementationVersion);
+ p.PrintKeyString("description", layer.layer_properties.description);
+ DumpExtensions(p, "Layer Extensions", layer.extension_properties);
+ ObjectWrapper obj_devices(p, "Devices");
+ for (auto &gpu : gpus) {
+ ObjectWrapper obj_gpu(p, gpu->props.deviceName);
+ p.SetValueDescription(std::string(gpu->props.deviceName)).PrintKeyValue("GPU id", gpu->id);
+ auto exts = gpu->inst.AppGetPhysicalDeviceLayerExtensions(gpu->phys_device, layer.layer_properties.layerName);
+ DumpExtensions(p, "Layer-Device Extensions", exts);
+ }
+ }
+ break;
+ }
+ }
+}
+
+void DumpSurfaceFormats(Printer &p, AppInstance &inst, AppSurface &surface) {
+ std::vector<VkSurfaceFormatKHR> formats;
+ if (inst.CheckExtensionEnabled(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME)) {
+ for (auto &format : surface.surf_formats2) {
+ formats.push_back(format.surfaceFormat);
+ }
+ } else {
+ for (auto &format : surface.surf_formats) {
+ formats.push_back(format);
+ }
+ }
+ ObjectWrapper obj(p, "Formats", formats.size());
+ int i = 0;
+ for (auto &format : formats) {
+ p.SetElementIndex(i++);
+ DumpVkSurfaceFormatKHR(p, "SurfaceFormat", format);
+ }
+}
+
+void DumpPresentModes(Printer &p, AppSurface &surface) {
+ ArrayWrapper arr(p, "Present Modes", surface.surf_present_modes.size());
+ for (auto &mode : surface.surf_present_modes) {
+ p.SetAsType().PrintString(VkPresentModeKHRString(mode));
+ }
+}
+
+void DumpSurfaceCapabilities(Printer &p, AppInstance &inst, AppGpu &gpu, AppSurface &surface) {
+ auto &surf_cap = surface.surface_capabilities;
+ p.SetSubHeader().SetIgnoreMinWidthInChild();
+ DumpVkSurfaceCapabilitiesKHR(p, "VkSurfaceCapabilitiesKHR", surf_cap);
+
+ if (inst.CheckExtensionEnabled(VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME)) {
+ p.SetSubHeader();
+ ObjectWrapper obj(p, "VkSurfaceCapabilities2EXT");
+ DumpVkSurfaceCounterFlagsEXT(p, "supportedSurfaceCounters", surface.surface_capabilities2_ext.supportedSurfaceCounters);
+ }
+ if (inst.CheckExtensionEnabled(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME)) {
+ chain_iterator_surface_capabilities2(p, inst, gpu, surface.surface_capabilities2_khr.pNext);
+ }
+ if (inst.CheckExtensionEnabled(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME) ||
+ inst.CheckExtensionEnabled(VK_KHR_SURFACE_MAINTENANCE_1_EXTENSION_NAME)) {
+ const char *surf_ext_name = VK_KHR_SURFACE_MAINTENANCE_1_EXTENSION_NAME;
+ if (!inst.CheckExtensionEnabled(VK_KHR_SURFACE_MAINTENANCE_1_EXTENSION_NAME)) {
+ surf_ext_name = VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME;
+ }
+ p.SetSubHeader();
+ ObjectWrapper obj(p, surf_ext_name);
+ for (auto &mode : surface.surf_present_modes) {
+ VkSurfacePresentModeKHR present_mode{};
+ present_mode.sType = VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_KHR;
+ present_mode.presentMode = mode;
+
+ VkPhysicalDeviceSurfaceInfo2KHR surface_info{};
+ surface_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR;
+ surface_info.surface = surface.surface_extension.surface;
+ surface_info.pNext = &present_mode;
+
+ VkSurfacePresentModeCompatibilityKHR SurfacePresentModeCompatibilityKHR{};
+ SurfacePresentModeCompatibilityKHR.sType = VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_KHR;
+
+ VkSurfacePresentScalingCapabilitiesKHR SurfacePresentScalingCapabilitiesKHR{};
+ SurfacePresentScalingCapabilitiesKHR.sType = VK_STRUCTURE_TYPE_SURFACE_PRESENT_SCALING_CAPABILITIES_EXT;
+ SurfacePresentScalingCapabilitiesKHR.pNext = &SurfacePresentModeCompatibilityKHR;
+
+ VkSurfaceCapabilities2KHR surface_caps2{};
+ surface_caps2.sType = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
+ surface_caps2.pNext = &SurfacePresentScalingCapabilitiesKHR;
+
+ VkResult err = vkGetPhysicalDeviceSurfaceCapabilities2KHR(gpu.phys_device, &surface_info, &surface_caps2);
+ if (err != VK_SUCCESS) {
+ continue;
+ }
+
+ std::vector<VkPresentModeKHR> compatible_present_modes{SurfacePresentModeCompatibilityKHR.presentModeCount};
+ SurfacePresentModeCompatibilityKHR.pPresentModes = compatible_present_modes.data();
+
+ err = vkGetPhysicalDeviceSurfaceCapabilities2KHR(gpu.phys_device, &surface_info, &surface_caps2);
+
+ if (err == VK_SUCCESS) {
+ ObjectWrapper present_mode_obj(p, VkPresentModeKHRString(mode));
+
+ p.PrintKeyValue("minImageCount", surface_caps2.surfaceCapabilities.minImageCount);
+ p.PrintKeyValue("maxImageCount", surface_caps2.surfaceCapabilities.maxImageCount);
+
+ DumpVkSurfacePresentScalingCapabilitiesKHR(p, "VkSurfacePresentScalingCapabilitiesKHR",
+ SurfacePresentScalingCapabilitiesKHR);
+ DumpVkSurfacePresentModeCompatibilityKHR(p, "VkSurfacePresentModeCompatibilityKHR",
+ SurfacePresentModeCompatibilityKHR);
+ }
+ }
+ }
+}
+
+void DumpSurface(Printer &p, AppInstance &inst, AppGpu &gpu, AppSurface &surface, std::set<std::string> surface_types) {
+ std::string surface_type_list_str = "";
+ if (surface_types.size() > 0) {
+ surface_type_list_str = " [";
+ bool is_first = true;
+ for (auto &name : surface_types) {
+ if (!is_first) {
+ surface_type_list_str += ", ";
+ } else {
+ is_first = false;
+ }
+ surface_type_list_str += name;
+ }
+ surface_type_list_str += "]";
+ }
+ ObjectWrapper obj(p, std::string("GPU id : ") + p.DecorateAsValue(std::to_string(gpu.id)) + " (" + gpu.props.deviceName + ")" +
+ surface_type_list_str);
+
+ if (surface_types.size() == 0) {
+ p.SetAsType().PrintKeyString("Surface type", "No type found");
+ } else if (surface_types.size() == 1) {
+ p.SetAsType().PrintKeyString("Surface type", surface.surface_extension.name);
+ } else {
+ ArrayWrapper arr(p, "Surface types", surface_types.size());
+ for (auto &name : surface_types) {
+ p.PrintString(name);
+ }
+ }
+
+ DumpSurfaceFormats(p, inst, surface);
+ DumpPresentModes(p, surface);
+ DumpSurfaceCapabilities(p, inst, gpu, surface);
+
+ p.AddNewline();
+}
+
+struct SurfaceTypeGroup {
+ AppSurface *surface;
+ AppGpu *gpu;
+ std::set<std::string> surface_types;
+};
+
+bool operator==(AppSurface const &a, AppSurface const &b) {
+ return a.phys_device == b.phys_device && a.surf_present_modes == b.surf_present_modes && a.surf_formats == b.surf_formats &&
+ a.surf_formats2 == b.surf_formats2 && a.surface_capabilities == b.surface_capabilities &&
+ a.surface_capabilities2_khr == b.surface_capabilities2_khr && a.surface_capabilities2_ext == b.surface_capabilities2_ext;
+}
+
+#if defined(VULKANINFO_WSI_ENABLED)
+void DumpPresentableSurfaces(Printer &p, AppInstance &inst, const std::vector<std::unique_ptr<AppGpu>> &gpus,
+ const std::vector<std::unique_ptr<AppSurface>> &surfaces) {
+ // Don't print anything if no surfaces are found
+ if (surfaces.size() == 0) return;
+ p.SetHeader();
+ ObjectWrapper obj(p, "Presentable Surfaces");
+ IndentWrapper indent(p);
+
+ std::vector<SurfaceTypeGroup> surface_list;
+
+ for (auto &surface : surfaces) {
+ auto exists = surface_list.end();
+ for (auto it = surface_list.begin(); it != surface_list.end(); it++) {
+ // check for duplicate surfaces that differ only by the surface extension
+ if (*(it->surface) == *(surface.get())) {
+ exists = it;
+ break;
+ }
+ }
+ if (exists != surface_list.end()) {
+ exists->surface_types.insert(surface.get()->surface_extension.name);
+ } else {
+ // find surface.phys_device's corresponding AppGpu
+ AppGpu *corresponding_gpu = nullptr;
+ for (auto &gpu : gpus) {
+ if (gpu->phys_device == surface->phys_device) corresponding_gpu = gpu.get();
+ }
+ if (corresponding_gpu != nullptr)
+ surface_list.push_back({surface.get(), corresponding_gpu, {surface.get()->surface_extension.name}});
+ }
+ }
+ for (auto &group : surface_list) {
+ DumpSurface(p, inst, *group.gpu, *group.surface, group.surface_types);
+ }
+ p.AddNewline();
+}
+#endif // defined(VULKANINFO_WSI_ENABLED)
+
+void DumpGroups(Printer &p, AppInstance &inst) {
+ if (inst.CheckExtensionEnabled(VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME)) {
+ auto groups = GetGroups(inst);
+ if (groups.size() == 0) {
+ p.SetHeader();
+ ObjectWrapper obj(p, "Groups");
+ p.PrintString("No Device Groups Found");
+ p.AddNewline();
+ return;
+ }
+
+ p.SetHeader();
+ ObjectWrapper obj_device_groups(p, "Device Groups");
+ IndentWrapper indent(p);
+
+ int group_id = 0;
+ for (auto &group : groups) {
+ ObjectWrapper obj_group(p, "Group " + std::to_string(group_id));
+ auto group_props = GetGroupProps(inst, group);
+ {
+ ObjectWrapper obj_properties(p, "Properties");
+ {
+ ArrayWrapper arr(p, "physicalDevices", group.physicalDeviceCount);
+ int id = 0;
+ for (auto &prop : group_props) {
+ p.PrintString(std::string(prop.deviceName) + " (ID: " + p.DecorateAsValue(std::to_string(id++)) + ")");
+ }
+ }
+ p.PrintKeyValue("subsetAllocation", group.subsetAllocation);
+ }
+ p.AddNewline();
+
+ auto group_capabilities = GetGroupCapabilities(inst, group);
+ if (!group_capabilities) {
+ p.PrintKeyString("Present Capabilities",
+ "Group does not support VK_KHR_device_group, skipping printing present capabilities");
+ } else {
+ ObjectWrapper obj_caps(p, "Present Capabilities");
+ for (uint32_t i = 0; i < group.physicalDeviceCount; i++) {
+ ObjectWrapper obj_device(
+ p, std::string(group_props[i].deviceName) + " (ID: " + p.DecorateAsValue(std::to_string(i)) + ")");
+ ArrayWrapper arr(p, "Can present images from the following devices", group.physicalDeviceCount);
+
+ for (uint32_t j = 0; j < group.physicalDeviceCount; j++) {
+ uint32_t mask = 1 << j;
+ if (group_capabilities->presentMask[i] & mask) {
+ p.PrintString(std::string(group_props[j].deviceName) + " (ID: " + p.DecorateAsValue(std::to_string(j)) +
+ ")");
+ }
+ }
+ }
+ DumpVkDeviceGroupPresentModeFlagsKHR(p, "Present modes", group_capabilities->modes);
+ }
+ p.AddNewline();
+ group_id++;
+ }
+ p.AddNewline();
+ }
+}
+
+void GpuDumpProps(Printer &p, AppGpu &gpu, bool show_promoted_structs) {
+ auto props = gpu.GetDeviceProperties();
+ p.SetSubHeader();
+ {
+ ObjectWrapper obj(p, "VkPhysicalDeviceProperties");
+ p.SetMinKeyWidth(17);
+ if (p.Type() == OutputType::json) {
+ p.PrintKeyValue("apiVersion", props.apiVersion);
+ p.PrintKeyValue("driverVersion", props.driverVersion);
+ } else {
+ p.SetValueDescription(std::to_string(props.apiVersion)).PrintKeyString("apiVersion", APIVersion(props.apiVersion));
+ p.SetValueDescription(std::to_string(props.driverVersion))
+ .PrintKeyString("driverVersion", gpu.GetDriverVersionString());
+ }
+ p.PrintKeyString("vendorID", to_hex_str(props.vendorID));
+ p.PrintKeyString("deviceID", to_hex_str(props.deviceID));
+ p.PrintKeyString("deviceType", VkPhysicalDeviceTypeString(props.deviceType));
+ p.PrintKeyString("deviceName", props.deviceName);
+ p.PrintKeyValue("pipelineCacheUUID", props.pipelineCacheUUID);
+ }
+ p.AddNewline();
+ DumpVkPhysicalDeviceLimits(p, "VkPhysicalDeviceLimits", gpu.props.limits);
+ p.AddNewline();
+ DumpVkPhysicalDeviceSparseProperties(p, "VkPhysicalDeviceSparseProperties", gpu.props.sparseProperties);
+ p.AddNewline();
+ if (gpu.inst.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
+ void *place = gpu.props2.pNext;
+ chain_iterator_phys_device_props2(p, gpu.inst, gpu, show_promoted_structs, place);
+ }
+}
+
+void GpuDumpQueueProps(Printer &p, AppGpu &gpu, const AppQueueFamilyProperties &queue) {
+ VkQueueFamilyProperties props = queue.props;
+ p.SetSubHeader().SetElementIndex(static_cast<int>(queue.queue_index));
+ ObjectWrapper obj_queue_props(p, "queueProperties");
+ p.SetMinKeyWidth(27);
+ if (p.Type() == OutputType::vkconfig_output) {
+ DumpVkExtent3D(p, "minImageTransferGranularity", props.minImageTransferGranularity);
+ } else {
+ p.PrintKeyValue("minImageTransferGranularity", props.minImageTransferGranularity);
+ }
+ p.PrintKeyValue("queueCount", props.queueCount);
+ p.PrintKeyString("queueFlags", VkQueueFlagsString(props.queueFlags));
+ p.PrintKeyValue("timestampValidBits", props.timestampValidBits);
+
+ if (!queue.can_present) {
+ p.PrintKeyString("present support", "false");
+ } else if (queue.can_always_present) {
+ p.PrintKeyString("present support", "true");
+ } else {
+ size_t width = 0;
+ for (const auto &support : queue.present_support) {
+ if (support.first.size() > width) width = support.first.size();
+ }
+ ObjectWrapper obj_present_support(p, "present support");
+ p.SetMinKeyWidth(width);
+ for (const auto &support : queue.present_support) {
+ p.PrintKeyString(support.first, support.second ? "true" : "false");
+ }
+ }
+ chain_iterator_queue_properties2(p, gpu, queue.pNext);
+
+ p.AddNewline();
+}
+
+// This prints a number of bytes in a human-readable format according to prefixes of the International System of Quantities (ISQ),
+// defined in ISO/IEC 80000. The prefixes used here are not SI prefixes, but rather the binary prefixes based on powers of 1024
+// (kibi-, mebi-, gibi- etc.).
+#define kBufferSize 32
+
+std::string NumToNiceStr(const size_t sz) {
+ const char prefixes[] = "KMGTPEZY";
+ char buf[kBufferSize];
+ int which = -1;
+ double result = (double)sz;
+ while (result > 1024 && which < 7) {
+ result /= 1024;
+ ++which;
+ }
+
+ char unit[] = "\0i";
+ if (which >= 0) {
+ unit[0] = prefixes[which];
+ }
+#ifdef _WIN32
+ _snprintf_s(buf, kBufferSize * sizeof(char), kBufferSize, "%.2f %sB", result, unit);
+#else
+ snprintf(buf, kBufferSize, "%.2f %sB", result, unit);
+#endif
+ return std::string(buf);
+}
+
+std::string append_human_readable(VkDeviceSize memory) {
+ return std::to_string(memory) + " (" + to_hex_str(memory) + ") (" + NumToNiceStr(static_cast<size_t>(memory)) + ")";
+}
+
+void GpuDumpMemoryProps(Printer &p, AppGpu &gpu) {
+ p.SetHeader();
+ ObjectWrapper obj_mem_props(p, "VkPhysicalDeviceMemoryProperties");
+ IndentWrapper indent(p);
+ {
+ ObjectWrapper obj_mem_heaps(p, "memoryHeaps", gpu.memory_props.memoryHeapCount);
+
+ for (uint32_t i = 0; i < gpu.memory_props.memoryHeapCount; ++i) {
+ p.SetElementIndex(static_cast<int>(i));
+ ObjectWrapper obj_mem_heap(p, "memoryHeaps");
+ p.SetMinKeyWidth(6);
+ p.PrintKeyString("size", append_human_readable(gpu.memory_props.memoryHeaps[i].size));
+ if (gpu.CheckPhysicalDeviceExtensionIncluded(VK_EXT_MEMORY_BUDGET_EXTENSION_NAME)) {
+ p.PrintKeyString("budget", append_human_readable(gpu.heapBudget[i]));
+ p.PrintKeyString("usage", append_human_readable(gpu.heapUsage[i]));
+ }
+ DumpVkMemoryHeapFlags(p, "flags", gpu.memory_props.memoryHeaps[i].flags);
+ }
+ }
+ {
+ ObjectWrapper obj_mem_types(p, "memoryTypes", gpu.memory_props.memoryTypeCount);
+ for (uint32_t i = 0; i < gpu.memory_props.memoryTypeCount; ++i) {
+ p.SetElementIndex(static_cast<int>(i));
+ ObjectWrapper obj_mem_type(p, "memoryTypes");
+ p.SetMinKeyWidth(13);
+ p.PrintKeyValue("heapIndex", gpu.memory_props.memoryTypes[i].heapIndex);
+
+ auto flags = gpu.memory_props.memoryTypes[i].propertyFlags;
+ DumpVkMemoryPropertyFlags(p, "propertyFlags = " + to_hex_str(flags), flags);
+
+ ObjectWrapper usable_for(p, "usable for");
+ const uint32_t memtype_bit = 1U << i;
+
+ // only linear and optimal tiling considered
+ for (auto &image_tiling : gpu.memory_image_support_types) {
+ p.SetOpenDetails();
+ ArrayWrapper arr(p, VkImageTilingString(VkImageTiling(image_tiling.tiling)));
+ bool has_any_support_types = false;
+ bool regular = false;
+ bool transient = false;
+ bool sparse = false;
+ for (auto &image_format : image_tiling.formats) {
+ if (image_format.type_support.size() > 0) {
+ bool has_a_support_type = false;
+ for (auto &img_type : image_format.type_support) {
+ if (img_type.Compatible(memtype_bit)) {
+ has_a_support_type = true;
+ has_any_support_types = true;
+ if (img_type.type == ImageTypeSupport::Type::regular) regular = true;
+ if (img_type.type == ImageTypeSupport::Type::transient) transient = true;
+ if (img_type.type == ImageTypeSupport::Type::sparse) sparse = true;
+ }
+ }
+ if (has_a_support_type) {
+ if (image_format.format == color_format) {
+ p.PrintString("color images");
+ } else {
+ p.PrintString(VkFormatString(image_format.format));
+ }
+ }
+ }
+ }
+ if (!has_any_support_types) {
+ p.PrintString("None");
+ } else {
+ if (regular && !transient && sparse) p.PrintString("(non-transient)");
+ if (regular && transient && !sparse) p.PrintString("(non-sparse)");
+ if (regular && !transient && !sparse) p.PrintString("(non-sparse, non-transient)");
+ if (!regular && transient && sparse) p.PrintString("(sparse and transient only)");
+ if (!regular && !transient && sparse) p.PrintString("(sparse only)");
+ if (!regular && transient && !sparse) p.PrintString("(transient only)");
+ }
+ }
+ }
+ }
+ p.AddNewline();
+}
+
+void GpuDumpFeatures(Printer &p, AppGpu &gpu, bool show_promoted_structs) {
+ p.SetHeader();
+ DumpVkPhysicalDeviceFeatures(p, "VkPhysicalDeviceFeatures", gpu.features);
+ p.AddNewline();
+ if (gpu.inst.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
+ void *place = gpu.features2.pNext;
+ chain_iterator_phys_device_features2(p, gpu, show_promoted_structs, place);
+ }
+}
+
+void GpuDumpTextFormatProperty(Printer &p, const AppGpu &gpu, PropFlags formats, const std::set<VkFormat> &format_list,
+ uint32_t counter) {
+ p.SetElementIndex(counter);
+ ObjectWrapper obj_common_group(p, "Common Format Group");
+ IndentWrapper indent_inner(p);
+ {
+ ArrayWrapper arr_formats(p, "Formats", format_list.size());
+ for (auto &fmt : format_list) {
+ p.SetAsType().PrintString(VkFormatString(fmt));
+ }
+ }
+ ObjectWrapper obj(p, "Properties");
+ if (gpu.CheckPhysicalDeviceExtensionIncluded(VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME)) {
+ DumpVkFormatFeatureFlags2(p, "linearTilingFeatures", formats.props3.linearTilingFeatures);
+ DumpVkFormatFeatureFlags2(p, "optimalTilingFeatures", formats.props3.optimalTilingFeatures);
+ DumpVkFormatFeatureFlags2(p, "bufferFeatures", formats.props3.bufferFeatures);
+ } else {
+ DumpVkFormatFeatureFlags(p, "linearTilingFeatures", formats.props.linearTilingFeatures);
+ DumpVkFormatFeatureFlags(p, "optimalTilingFeatures", formats.props.optimalTilingFeatures);
+ DumpVkFormatFeatureFlags(p, "bufferFeatures", formats.props.bufferFeatures);
+ }
+ p.AddNewline();
+}
+
+void GpuDumpToolingInfo(Printer &p, AppGpu &gpu) {
+ auto tools = GetToolingInfo(gpu);
+ if (tools.size() > 0) {
+ p.SetSubHeader();
+ ObjectWrapper obj(p, "Tooling Info");
+ for (auto tool : tools) {
+ DumpVkPhysicalDeviceToolProperties(p, tool.name, tool);
+ p.AddNewline();
+ }
+ }
+}
+
+void GpuDumpCooperativeMatrix(Printer &p, AppGpu &gpu) {
+ auto props = GetCooperativeMatrixInfo(gpu);
+ if (props.size() > 0) {
+ p.SetSubHeader();
+ ObjectWrapper obj(p, "vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR");
+ for (const auto prop : props) {
+ DumpVkCooperativeMatrixPropertiesKHR(p, "VkCooperativeMatrixPropertiesKHR", prop);
+ p.AddNewline();
+ }
+ }
+}
+
+void GpuDumpCalibrateableTimeDomain(Printer &p, AppGpu &gpu) {
+ auto props = GetTimeDomainInfo(gpu);
+ if (props.size() > 0) {
+ p.SetSubHeader();
+ ObjectWrapper obj_mem_props(p, "vkGetPhysicalDeviceCalibrateableTimeDomainsKHR");
+ {
+ for (uint32_t i = 0; i < props.size(); ++i) {
+ p.SetElementIndex(static_cast<int>(i));
+ DumpVkTimeDomainKHR(p, "pTimeDomains", props[i]);
+ p.AddNewline();
+ }
+ }
+ }
+}
+
+void GpuDumpFragmentShadingRate(Printer &p, AppGpu &gpu) {
+ auto props = GetFragmentShadingRateInfo(gpu);
+ if (props.size() > 0) {
+ p.SetSubHeader();
+ ObjectWrapper obj(p, "vkGetPhysicalDeviceFragmentShadingRatesKHR");
+ for (const auto prop : props) {
+ DumpVkPhysicalDeviceFragmentShadingRateKHR(p, "VkPhysicalDeviceFragmentShadingRateKHR", prop);
+ p.AddNewline();
+ }
+ }
+}
+
+// VK_EXT_sample_locations ('Multisample Properties' is too ambiguous of a name)
+void GpuDumpSampleLocations(Printer &p, AppGpu &gpu) {
+ auto props = GetSampleLocationInfo(gpu);
+ if (props.size() > 0) {
+ p.SetSubHeader();
+ ObjectWrapper obj(p, "vkGetPhysicalDeviceMultisamplePropertiesEXT");
+ for (uint32_t i = 0; i < props.size(); i++) {
+ const VkSampleCountFlagBits sample_count = (VkSampleCountFlagBits)(1 << i);
+ DumpVkSampleCountFlagBits(p, "samples", sample_count);
+ DumpVkMultisamplePropertiesEXT(p, "VkMultisamplePropertiesEXT", props[i]);
+ p.AddNewline();
+ }
+ }
+}
+
+void GpuDevDump(Printer &p, AppGpu &gpu) {
+ p.SetHeader();
+ ObjectWrapper obj_format_props(p, "Format Properties");
+ IndentWrapper indent_outer(p);
+
+ if (p.Type() == OutputType::text) {
+ auto fmtPropMap = FormatPropMap(gpu);
+ int counter = 0;
+ std::set<VkFormat> unsupported_formats;
+ for (auto &prop : fmtPropMap) {
+ VkFormatProperties props = prop.first.props;
+ VkFormatProperties3 props3 = prop.first.props3;
+ if (props.linearTilingFeatures == 0 && props.optimalTilingFeatures == 0 && props.bufferFeatures == 0 &&
+ props3.linearTilingFeatures == 0 && props3.optimalTilingFeatures == 0 && props3.bufferFeatures == 0) {
+ unsupported_formats = prop.second;
+ continue;
+ }
+ GpuDumpTextFormatProperty(p, gpu, prop.first, prop.second, counter++);
+ }
+
+ ArrayWrapper arr_unsupported_formats(p, "Unsupported Formats", unsupported_formats.size());
+ for (auto &fmt : unsupported_formats) {
+ p.SetAsType().PrintString(VkFormatString(fmt));
+ }
+ } else {
+ std::set<VkFormat> formats_to_print;
+ for (auto &format_range : format_ranges) {
+ if (gpu.FormatRangeSupported(format_range)) {
+ for (int32_t fmt_counter = format_range.first_format; fmt_counter <= format_range.last_format; ++fmt_counter) {
+ formats_to_print.insert(static_cast<VkFormat>(fmt_counter));
+ }
+ }
+ }
+ for (const auto &fmt : formats_to_print) {
+ auto formats = get_format_properties(gpu, fmt);
+ p.SetTitleAsType();
+ if (gpu.CheckPhysicalDeviceExtensionIncluded(VK_KHR_FORMAT_FEATURE_FLAGS_2_EXTENSION_NAME)) {
+ DumpVkFormatProperties3(p, VkFormatString(fmt), formats.props3);
+ } else {
+ DumpVkFormatProperties(p, VkFormatString(fmt), formats.props);
+ }
+ }
+ }
+
+ p.AddNewline();
+}
+
+void DumpVkVideoProfileInfoKHRCustom(Printer &p, std::string name, const VkVideoProfileInfoKHR &obj) {
+ // We use custom dumping here because we do not want to output ignored fields
+ // e.g. for monochrome chromaBitDepth is ignored
+ ObjectWrapper object{p, name};
+ DumpVkVideoCodecOperationFlagBitsKHR(p, "videoCodecOperation", obj.videoCodecOperation);
+ DumpVkVideoChromaSubsamplingFlagsKHR(p, "chromaSubsampling", obj.chromaSubsampling);
+ DumpVkVideoComponentBitDepthFlagsKHR(p, "lumaBitDepth", obj.lumaBitDepth);
+ if (obj.chromaSubsampling != VK_VIDEO_CHROMA_SUBSAMPLING_MONOCHROME_BIT_KHR) {
+ DumpVkVideoComponentBitDepthFlagsKHR(p, "chromaBitDepth", obj.chromaBitDepth);
+ } else {
+ DumpVkVideoComponentBitDepthFlagsKHR(p, "chromaBitDepth", 0);
+ }
+}
+
+void GpuDumpVideoProfiles(Printer &p, AppGpu &gpu, bool show_video_props) {
+ p.SetHeader();
+ ObjectWrapper video_profiles_obj(p, "Video Profiles", gpu.video_profiles.size());
+ IndentWrapper indent_outer(p);
+
+ if (p.Type() != OutputType::text || show_video_props) {
+ // Video profile details per profile
+ for (const auto &video_profile : gpu.video_profiles) {
+ p.SetSubHeader();
+ ObjectWrapper video_profile_obj(p, video_profile->name);
+ IndentWrapper indent_inner(p);
+ {
+ p.SetSubHeader();
+ ObjectWrapper profile_info_obj(p, "Video Profile Definition");
+ p.SetSubHeader();
+ DumpVkVideoProfileInfoKHRCustom(p, "VkVideoProfileInfoKHR", video_profile->profile_info);
+ chain_iterator_video_profile_info(p, gpu, video_profile->profile_info.pNext);
+ }
+ {
+ p.SetSubHeader();
+ ObjectWrapper capabilities_obj(p, "Video Profile Capabilities");
+ p.SetSubHeader();
+ DumpVkVideoCapabilitiesKHR(p, "VkVideoCapabilitiesKHR", video_profile->capabilities);
+ chain_iterator_video_capabilities(p, gpu, video_profile->capabilities.pNext);
+ }
+ {
+ p.SetSubHeader();
+ ObjectWrapper video_formats_obj(p, "Video Formats");
+ for (const auto &video_formats_it : video_profile->formats_by_category) {
+ const auto &video_format_category_name = video_formats_it.first;
+ const auto &video_format_props = video_formats_it.second;
+ ObjectWrapper video_format_category(p, video_format_category_name, video_format_props.size());
+ for (size_t i = 0; i < video_format_props.size(); ++i) {
+ ObjectWrapper video_format_obj(p, video_format_category_name + " Format #" + std::to_string(i + 1));
+ p.SetSubHeader();
+ DumpVkVideoFormatPropertiesKHR(p, "VkVideoFormatPropertiesKHR", video_format_props[i]);
+ chain_iterator_video_format_properties(p, gpu, video_format_props[i].pNext);
+ }
+ }
+ }
+
+ p.AddNewline();
+ }
+ } else {
+ // Video profile list only
+ for (const auto &video_profile : gpu.video_profiles) {
+ p.PrintString(video_profile->name);
+ }
+ }
+
+ p.AddNewline();
+}
+
+AppDisplayPlane::AppDisplayPlane(AppGpu &gpu, uint32_t index, const VkDisplayPlanePropertiesKHR &in_prop)
+ : global_index(index), properties(in_prop) {
+ std::ostringstream display_name;
+
+ supported_displays = GetVector<VkDisplayKHR>("vkGetDisplayPlaneSupportedDisplaysKHR", vkGetDisplayPlaneSupportedDisplaysKHR,
+ gpu.phys_device, global_index);
+}
+
+std::vector<AppDisplayPlane> enumerate_display_planes(AppGpu &gpu) {
+ std::vector<AppDisplayPlane> result;
+ if (vkGetPhysicalDeviceDisplayPlanePropertiesKHR) {
+ auto planes = GetVector<VkDisplayPlanePropertiesKHR>("vkGetPhysicalDeviceDisplayPlanePropertiesKHR",
+ vkGetPhysicalDeviceDisplayPlanePropertiesKHR, gpu.phys_device);
+ for (uint32_t i = 0; i < planes.size(); i++) {
+ result.emplace_back(gpu, i, planes[i]);
+ }
+ }
+ return result;
+}
+
+AppDisplayMode::AppDisplayMode(AppGpu &gpu, const VkDisplayModePropertiesKHR &in_properties,
+ const std::set<uint32_t> &supported_planes)
+ : properties(in_properties) {
+ for (auto plane : supported_planes) {
+ VkDisplayPlaneCapabilitiesKHR cap;
+
+ vkGetDisplayPlaneCapabilitiesKHR(gpu.phys_device, properties.displayMode, plane, &cap);
+ capabilities[plane] = cap;
+ }
+}
+
+static std::string MakeName(uint32_t index, const VkDisplayPropertiesKHR &prop) {
+ std::stringstream name;
+ name << "Display id : " << index << " (" << prop.displayName << ")";
+ return name.str();
+}
+
+AppDisplay::AppDisplay(AppGpu &gpu, uint32_t index, const VkDisplayPropertiesKHR &in_properties,
+ const std::vector<AppDisplayPlane> &all_planes)
+ : global_index(index), name(MakeName(index, in_properties)), properties(in_properties) {
+ auto mode_props = GetVector<VkDisplayModePropertiesKHR>("vkGetDisplayModePropertiesKHR", vkGetDisplayModePropertiesKHR,
+ gpu.phys_device, properties.display);
+
+ std::set<uint32_t> supported_planes;
+ for (const auto &plane : all_planes) {
+ for (const auto &display : plane.supported_displays) {
+ if (display == properties.display) {
+ supported_planes.insert(plane.global_index);
+ }
+ }
+ }
+
+ for (const auto &prop : mode_props) {
+ modes.emplace_back(gpu, prop, supported_planes);
+ }
+}
+
+std::vector<AppDisplay> enumerate_displays(AppGpu &gpu, const std::vector<AppDisplayPlane> &all_planes) {
+ std::vector<AppDisplay> result;
+
+ if (vkGetPhysicalDeviceDisplayPropertiesKHR) {
+ auto properties = GetVector<VkDisplayPropertiesKHR>("vkGetPhysicalDeviceDisplayPropertiesKHR",
+ vkGetPhysicalDeviceDisplayPropertiesKHR, gpu.phys_device);
+
+ for (uint32_t i = 0; i < properties.size(); i++) {
+ result.emplace_back(gpu, i, properties[i], all_planes);
+ }
+ }
+ return result;
+}
+
+void GpuDumpDisplays(Printer &p, AppGpu &gpu) {
+ if (gpu.displays.size() == 0) {
+ return;
+ }
+
+ p.SetHeader();
+ ObjectWrapper display_props_obj(p, "Display Properties", gpu.displays.size());
+
+ for (const auto &display : gpu.displays) {
+ p.SetSubHeader();
+ ObjectWrapper display_obj(p, display.name);
+
+ DumpVkDisplayPropertiesKHR(p, "VkDisplayPropertiesKHR", display.properties);
+ ArrayWrapper arr(p, "Display Modes", display.modes.size());
+
+ for (uint32_t m = 0; m < display.modes.size(); m++) {
+ const auto &mode = display.modes[m];
+ std::ostringstream mode_name;
+ mode_name << "Display Mode : " << p.DecorateAsValue(std::to_string(m)) << " ("
+ << mode.properties.parameters.visibleRegion.width << " x " << mode.properties.parameters.visibleRegion.height
+ << ")";
+
+ ObjectWrapper mode_obj(p, mode_name.str());
+
+ DumpVkDisplayModeParametersKHR(p, "VkDisplayModeParametersKHR", mode.properties.parameters);
+
+ ArrayWrapper cap_arr(p, "Display Plane Capabilities", mode.capabilities.size());
+ for (const auto &cap : mode.capabilities) {
+ std::ostringstream cap_name;
+ cap_name << "Capabilities (Plane " << p.DecorateAsValue(std::to_string(cap.first)) << ")";
+
+ ObjectWrapper cap_obj(p, cap_name.str());
+
+ DumpVkDisplayPlaneCapabilitiesKHR(p, "VkDisplayPlaneCapabilitiesKHR", cap.second);
+ }
+ }
+ }
+}
+
+void GpuDumpDisplayPlanes(Printer &p, AppGpu &gpu) {
+ if (gpu.display_planes.size() == 0) {
+ return;
+ }
+
+ p.SetHeader();
+ ObjectWrapper display_props_obj(p, "Display Plane Properties", gpu.display_planes.size());
+
+ for (const auto &plane : gpu.display_planes) {
+ p.SetSubHeader();
+ ObjectWrapper display_obj(p, std::string("Display Plane id : ") + p.DecorateAsValue(std::to_string(plane.global_index)));
+
+ auto *current = gpu.FindDisplay(plane.properties.currentDisplay);
+
+ p.PrintKeyString("currentDisplay", current ? current->name.c_str() : "none");
+
+ DumpVkDisplayPlanePropertiesKHR(p, "VkDisplayPlanePropertiesKHR", plane.properties);
+
+ ArrayWrapper arr(p, "Supported Displays", plane.supported_displays.size());
+ for (auto handle : plane.supported_displays) {
+ auto *display = gpu.FindDisplay(handle);
+ p.SetAsType().PrintString(display ? display->name.c_str() : "UNKNOWN");
+ }
+ }
+}
+
+struct ShowSettings {
+ bool all = false;
+ bool tool_props = false;
+ bool formats = false;
+ bool promoted_structs = false;
+ bool video_props = false;
+};
+
+// Print gpu info for text, html, & vkconfig_output
+// Uses a separate function than schema-json for clarity
+void DumpGpu(Printer &p, AppGpu &gpu, const ShowSettings &show) {
+ ObjectWrapper obj_gpu(p, "GPU" + std::to_string(gpu.id));
+ IndentWrapper indent(p);
+
+ GpuDumpProps(p, gpu, show.promoted_structs);
+ DumpExtensions(p, "Device Extensions", gpu.device_extensions);
+ p.AddNewline();
+ {
+ p.SetHeader();
+ ObjectWrapper obj_family_props(p, "VkQueueFamilyProperties");
+ for (const auto &queue_prop : gpu.extended_queue_props) {
+ GpuDumpQueueProps(p, gpu, queue_prop);
+ }
+ }
+ GpuDumpMemoryProps(p, gpu);
+ GpuDumpFeatures(p, gpu, show.promoted_structs);
+ if (show.tool_props) {
+ GpuDumpToolingInfo(p, gpu);
+ }
+
+ if (show.all) {
+ GpuDumpCooperativeMatrix(p, gpu);
+ GpuDumpCalibrateableTimeDomain(p, gpu);
+ GpuDumpFragmentShadingRate(p, gpu);
+ GpuDumpSampleLocations(p, gpu);
+ }
+
+ if (p.Type() != OutputType::text || show.formats) {
+ GpuDevDump(p, gpu);
+ }
+
+ if (!gpu.video_profiles.empty()) {
+ GpuDumpVideoProfiles(p, gpu, show.video_props);
+ }
+
+ if (!gpu.displays.empty()) {
+ GpuDumpDisplays(p, gpu);
+ }
+
+ if (!gpu.display_planes.empty()) {
+ GpuDumpDisplayPlanes(p, gpu);
+ }
+
+ p.AddNewline();
+}
+
+// Print capabilities section of profiles schema
+void DumpGpuProfileCapabilities(Printer &p, AppGpu &gpu, bool show_promoted_structs) {
+ ObjectWrapper capabilities(p, "capabilities");
+ {
+ ObjectWrapper temp_name_obj(p, "device");
+ DumpExtensions(p, "extensions", gpu.device_extensions);
+ {
+ ObjectWrapper obj(p, "features");
+ GpuDumpFeatures(p, gpu, show_promoted_structs);
+ }
+ {
+ ObjectWrapper obj(p, "properties");
+ {
+ ObjectWrapper props_obj(p, "VkPhysicalDeviceProperties");
+ auto props = gpu.GetDeviceProperties();
+ p.PrintKeyValue("apiVersion", props.apiVersion);
+ p.PrintKeyValue("deviceID", props.deviceID);
+ p.PrintKeyString("deviceName", props.deviceName);
+ p.PrintKeyString("deviceType", std::string("VK_") + VkPhysicalDeviceTypeString(props.deviceType));
+ p.PrintKeyValue("driverVersion", props.driverVersion);
+
+ DumpVkPhysicalDeviceLimits(p, "VkPhysicalDeviceLimits", gpu.props.limits);
+ {
+ ArrayWrapper arr(p, "pipelineCacheUUID");
+ for (const auto &uuid : props.pipelineCacheUUID) p.PrintElement(static_cast<uint32_t>(uuid));
+ }
+ DumpVkPhysicalDeviceSparseProperties(p, "VkPhysicalDeviceSparseProperties", gpu.props.sparseProperties);
+ p.PrintKeyValue("vendorID", props.vendorID);
+ }
+ if (gpu.inst.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
+ void *place = gpu.props2.pNext;
+ chain_iterator_phys_device_props2(p, gpu.inst, gpu, show_promoted_structs, place);
+ }
+ }
+ {
+ ObjectWrapper obj(p, "formats");
+ std::set<VkFormat> already_printed_formats;
+ for (const auto &format : format_ranges) {
+ if (gpu.FormatRangeSupported(format)) {
+ for (int32_t fmt_counter = format.first_format; fmt_counter <= format.last_format; ++fmt_counter) {
+ VkFormat fmt = static_cast<VkFormat>(fmt_counter);
+ if (already_printed_formats.count(fmt) > 0) {
+ continue;
+ }
+ auto formats = get_format_properties(gpu, fmt);
+
+ // don't print format properties that are unsupported
+ if (formats.props.linearTilingFeatures == 0 && formats.props.optimalTilingFeatures == 0 &&
+ formats.props.bufferFeatures == 0 && formats.props3.linearTilingFeatures == 0 &&
+ formats.props3.optimalTilingFeatures == 0 && formats.props3.bufferFeatures == 0)
+ continue;
+
+ ObjectWrapper format_obj(p, std::string("VK_") + VkFormatString(fmt));
+ {
+ // Want to explicitly list VkFormatProperties in addition to VkFormatProperties3 if available
+ DumpVkFormatProperties(p, "VkFormatProperties", formats.props);
+ VkFormatProperties2 format_props2{};
+ format_props2.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2;
+ format_props2.formatProperties = formats.props;
+ std::unique_ptr<format_properties2_chain> chain_for_format_props2;
+ setup_format_properties2_chain(format_props2, chain_for_format_props2, gpu);
+ vkGetPhysicalDeviceFormatProperties2KHR(gpu.phys_device, fmt, &format_props2);
+ chain_iterator_format_properties2(p, gpu, format_props2.pNext);
+ }
+ already_printed_formats.insert(fmt);
+ }
+ }
+ }
+ }
+ {
+ ArrayWrapper arr(p, "queueFamiliesProperties");
+ for (const auto &extended_queue_prop : gpu.extended_queue_props) {
+ ObjectWrapper queue_obj(p, "");
+ {
+ ObjectWrapper obj_queue_props(p, "VkQueueFamilyProperties");
+ VkQueueFamilyProperties props = extended_queue_prop.props;
+ DumpVkExtent3D(p, "minImageTransferGranularity", props.minImageTransferGranularity);
+ p.PrintKeyValue("queueCount", props.queueCount);
+ DumpVkQueueFlags(p, "queueFlags", props.queueFlags);
+ p.PrintKeyValue("timestampValidBits", props.timestampValidBits);
+ }
+ chain_iterator_queue_properties2(p, gpu, extended_queue_prop.pNext);
+ }
+ }
+ if (!gpu.video_profiles.empty()) {
+ ArrayWrapper video_profiles(p, "videoProfiles");
+ for (const auto &video_profile : gpu.video_profiles) {
+ ObjectWrapper video_profile_obj(p, "");
+ {
+ ObjectWrapper profile_info_obj(p, "profile");
+ DumpVkVideoProfileInfoKHRCustom(p, "VkVideoProfileInfoKHR", video_profile->profile_info);
+ chain_iterator_video_profile_info(p, gpu, video_profile->profile_info.pNext);
+ }
+ {
+ ObjectWrapper capabilities_obj(p, "capabilities");
+ DumpVkVideoCapabilitiesKHR(p, "VkVideoCapabilitiesKHR", video_profile->capabilities);
+ chain_iterator_video_capabilities(p, gpu, video_profile->capabilities.pNext);
+ }
+ {
+ ArrayWrapper video_formats(p, "formats");
+ for (const auto &video_format : video_profile->formats) {
+ ObjectWrapper video_format_obj(p, "");
+ DumpVkVideoFormatPropertiesKHR(p, "VkVideoFormatPropertiesKHR", video_format.properties);
+ chain_iterator_video_format_properties(p, gpu, video_format.properties.pNext);
+ }
+ }
+ }
+ }
+ }
+#if defined(VK_ENABLE_BETA_EXTENSIONS)
+ // Print portability subset extension, features, and properties if available
+ if (gpu.CheckPhysicalDeviceExtensionIncluded(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME) &&
+ (gpu.inst.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) ||
+ gpu.inst.api_version >= VK_API_VERSION_1_1)) {
+ ObjectWrapper macos_obj(p, "macos-specific");
+ {
+ ObjectWrapper ext_obj(p, "extensions");
+ const std::string portability_ext_name = VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME;
+ for (const auto &ext : gpu.device_extensions) {
+ if (portability_ext_name == ext.extensionName) {
+ p.PrintExtension(ext.extensionName, ext.specVersion);
+ }
+ }
+ }
+ {
+ ObjectWrapper features_obj(p, "features");
+ void *feats_place = gpu.features2.pNext;
+ while (feats_place) {
+ VkBaseOutStructure *structure = static_cast<VkBaseOutStructure *>(feats_place);
+ if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR) {
+ auto *features = reinterpret_cast<VkPhysicalDevicePortabilitySubsetFeaturesKHR *>(structure);
+ DumpVkPhysicalDevicePortabilitySubsetFeaturesKHR(p, "VkPhysicalDevicePortabilitySubsetFeaturesKHR", *features);
+ break;
+ }
+ feats_place = structure->pNext;
+ }
+ }
+ {
+ ObjectWrapper property_obj(p, "properties");
+ void *props_place = gpu.props2.pNext;
+ while (props_place) {
+ VkBaseOutStructure *structure = static_cast<VkBaseOutStructure *>(props_place);
+ if (structure->sType == VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_PROPERTIES_KHR) {
+ auto *props = reinterpret_cast<VkPhysicalDevicePortabilitySubsetPropertiesKHR *>(structure);
+ DumpVkPhysicalDevicePortabilitySubsetPropertiesKHR(p, "VkPhysicalDevicePortabilitySubsetPropertiesKHR", *props);
+ break;
+ }
+ props_place = structure->pNext;
+ }
+ }
+ }
+#endif // defined(VK_ENABLE_BETA_EXTENSIONS)
+}
+void PrintProfileBaseInfo(Printer &p, const std::string &device_name, uint32_t apiVersion, const std::string &device_label,
+ const std::vector<std::string> &capabilities) {
+ ObjectWrapper vk_info(p, device_name);
+ p.PrintKeyValue("version", 1);
+ p.PrintKeyString("api-version", APIVersion(apiVersion).str());
+ p.PrintKeyString("label", device_label);
+ p.PrintKeyString("description", std::string("Exported from ") + APP_SHORT_NAME);
+ {
+ ObjectWrapper contributors(p, "contributors");
+ }
+ {
+ ArrayWrapper contributors(p, "history");
+ ObjectWrapper element(p, "");
+ p.PrintKeyValue("revision", 1);
+ std::time_t t = std::time(0); // get time now
+ std::tm *now = std::localtime(&t);
+ std::string date =
+ std::to_string(now->tm_year + 1900) + '-' + std::to_string(now->tm_mon + 1) + '-' + std::to_string(now->tm_mday);
+ p.PrintKeyString("date", date);
+ p.PrintKeyString("author", std::string("Automated export from ") + APP_SHORT_NAME);
+ p.PrintKeyString("comment", "");
+ }
+ ArrayWrapper contributors(p, "capabilities");
+ for (const auto &str : capabilities) p.PrintString(str);
+}
+
+// Prints profiles section of profiles schema
+void DumpGpuProfileInfo(Printer &p, AppGpu &gpu) {
+ ObjectWrapper profiles(p, "profiles");
+
+ std::string device_label = std::string(gpu.props.deviceName) + " driver " + gpu.GetDriverVersionString();
+ std::string device_name =
+ std::string("VP_" APP_UPPER_CASE_NAME "_") + std::string(gpu.props.deviceName) + "_" + gpu.GetDriverVersionString();
+ ;
+ for (auto &c : device_name) {
+ if (c == ' ' || c == '.') c = '_';
+ }
+ PrintProfileBaseInfo(p, device_name, gpu.props.apiVersion, device_label, {"device"});
+#if defined(VK_ENABLE_BETA_EXTENSIONS)
+ if (gpu.CheckPhysicalDeviceExtensionIncluded(VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME) &&
+ (gpu.inst.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) ||
+ gpu.inst.api_version >= VK_API_VERSION_1_1)) {
+ PrintProfileBaseInfo(p, device_name + "_portability_subset", gpu.props.apiVersion, device_label + " subset",
+ {"device", "macos-specific"});
+ }
+#endif // defined(VK_ENABLE_BETA_EXTENSIONS)
+}
+
+// Print summary of system
+void DumpSummaryInstance(Printer &p, AppInstance &inst) {
+ p.SetSubHeader();
+ DumpExtensions(p, "Instance Extensions", inst.global_extensions, true);
+ p.AddNewline();
+
+ p.SetSubHeader();
+ ArrayWrapper arr(p, "Instance Layers", inst.global_layers.size());
+ IndentWrapper indent(p);
+ std::sort(inst.global_layers.begin(), inst.global_layers.end(), [](LayerExtensionList &left, LayerExtensionList &right) -> int {
+ return std::strncmp(left.layer_properties.layerName, right.layer_properties.layerName, VK_MAX_DESCRIPTION_SIZE) < 0;
+ });
+ size_t layer_name_max = 0;
+ size_t layer_desc_max = 0;
+ size_t layer_version_max = 0;
+
+ // find max of each type to align everything in columns
+ for (auto &layer : inst.global_layers) {
+ auto props = layer.layer_properties;
+ layer_name_max = std::max(layer_name_max, strlen(props.layerName));
+ layer_desc_max = std::max(layer_desc_max, strlen(props.description));
+ layer_version_max = std::max(layer_version_max, APIVersion(layer.layer_properties.specVersion).str().size());
+ }
+ for (auto &layer : inst.global_layers) {
+ auto v_str = APIVersion(layer.layer_properties.specVersion).str();
+ auto props = layer.layer_properties;
+
+ auto name_padding = std::string(layer_name_max - strlen(props.layerName), ' ');
+ auto desc_padding = std::string(layer_desc_max - strlen(props.description), ' ');
+ auto version_padding = std::string(layer_version_max - v_str.size(), ' ');
+ p.PrintString(std::string(props.layerName) + name_padding + " " + props.description + desc_padding + " " + v_str + " " +
+ version_padding + " version " + std::to_string(props.implementationVersion));
+ }
+ p.AddNewline();
+}
+
+void DumpSummaryGPU(Printer &p, AppGpu &gpu) {
+ ObjectWrapper obj(p, "GPU" + std::to_string(gpu.id));
+ p.SetMinKeyWidth(18);
+ auto props = gpu.GetDeviceProperties();
+ p.PrintKeyValue("apiVersion", APIVersion(props.apiVersion));
+ if (gpu.found_driver_props) {
+ p.PrintKeyString("driverVersion", gpu.GetDriverVersionString());
+ } else {
+ p.PrintKeyValue("driverVersion", props.driverVersion);
+ }
+ p.PrintKeyString("vendorID", to_hex_str(props.vendorID));
+ p.PrintKeyString("deviceID", to_hex_str(props.deviceID));
+ p.PrintKeyString("deviceType", VkPhysicalDeviceTypeString(props.deviceType));
+ p.PrintKeyString("deviceName", props.deviceName);
+
+ if (gpu.found_driver_props) {
+ DumpVkDriverId(p, "driverID", gpu.driverID);
+ p.PrintKeyString("driverName", gpu.driverName);
+ p.PrintKeyString("driverInfo", gpu.driverInfo);
+ p.PrintKeyValue("conformanceVersion", gpu.conformanceVersion);
+ }
+ if (gpu.found_device_id_props) {
+ p.PrintKeyValue("deviceUUID", gpu.deviceUUID);
+ p.PrintKeyValue("driverUUID", gpu.driverUUID);
+ }
+}
+
+// ============ Printing Logic ============= //
+
+#ifdef _WIN32
+// Enlarges the console window to have a large scrollback size.
+static void ConsoleEnlarge() {
+ const HANDLE console_handle = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ // make the console window bigger
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+ COORD buffer_size;
+ if (GetConsoleScreenBufferInfo(console_handle, &csbi)) {
+ buffer_size.X = csbi.dwSize.X + 30;
+ buffer_size.Y = 20000;
+ SetConsoleScreenBufferSize(console_handle, buffer_size);
+ }
+
+ SMALL_RECT r;
+ r.Left = r.Top = 0;
+ r.Right = csbi.dwSize.X - 1 + 30;
+ r.Bottom = 50;
+ SetConsoleWindowInfo(console_handle, true, &r);
+
+ // change the console window title
+ SetConsoleTitle(TEXT(APP_SHORT_NAME));
+}
+#endif
+
+// Global configuration
+enum class OutputCategory { text, html, profile_json, vkconfig_output, summary };
+const char *help_message_body =
+ "OPTIONS:\n"
+ "[-h, --help] Print this help.\n"
+ "[--summary] Show a summary of the instance and GPU's on a system.\n"
+ "[-o <filename>, --output <filename>]\n"
+ " Print output to a new file whose name is specified by filename.\n"
+ " File will be written to the current working directory.\n"
+ "[--text] Produce a text version of " APP_SHORT_NAME
+ " output to stdout. This is\n"
+ " the default output.\n"
+ "[--html] Produce an html version of " APP_SHORT_NAME
+ " output, saved as\n"
+ " \"" APP_SHORT_NAME
+ ".html\" in the directory in which the command\n"
+ " is run.\n"
+ "[-j, --json] Produce a json version of " APP_SHORT_NAME
+ " output conforming to the Vulkan\n"
+ " Profiles schema, saved as \n"
+ " \"VP_" APP_UPPER_CASE_NAME
+ "_[DEVICE_NAME]_[DRIVER_VERSION].json\"\n"
+ " of the first gpu in the system.\n"
+ "[-j=<gpu-number>, --json=<gpu-number>]\n"
+ " For a multi-gpu system, a single gpu can be targeted by\n"
+ " specifying the gpu-number associated with the gpu of \n"
+ " interest. This number can be determined by running\n"
+ " " APP_SHORT_NAME
+ " without any options specified.\n"
+ "[--show-all] Show everything (includes all the below options)\n"
+ "[--show-tool-props] Show the active VkPhysicalDeviceToolPropertiesEXT that " APP_SHORT_NAME
+ " finds.\n"
+ "[--show-formats] Display the format properties of each physical device.\n"
+ " Note: This only affects text output.\n"
+ "[--show-promoted-structs] Include structs promoted to core in pNext Chains.\n"
+ "[--show-video-props]\n"
+ " Display the video profile info, video capabilities and\n"
+ " video format properties of each video profile supported\n"
+ " by each physical device.\n"
+ " Note: This only affects text output which by default\n"
+ " only contains the list of supported video profile names.\n";
+
+void print_usage(const std::string &executable_name) {
+ std::cout << "\n" APP_SHORT_NAME " - Summarize " API_NAME " information in relation to the current environment.\n\n";
+ std::cout << "USAGE: \n";
+ std::cout << " " << executable_name << " --summary\n";
+ std::cout << " " << executable_name << " -o <filename> | --output <filename>\n";
+ std::cout << " " << executable_name << " -j | -j=<gpu-number> | --json | --json=<gpu-number>\n";
+ std::cout << " " << executable_name << " --text\n";
+ std::cout << " " << executable_name << " --html\n";
+ std::cout << " " << executable_name << " --show-all\n";
+ std::cout << " " << executable_name << " --show-formats\n";
+ std::cout << " " << executable_name << " --show-tool-props\n";
+ std::cout << " " << executable_name << " --show-promoted-structs\n";
+ std::cout << " " << executable_name << " --show-video-props\n";
+ std::cout << "\n" << help_message_body << std::endl;
+}
+
+struct ParsedResults {
+ OutputCategory output_category = OutputCategory::text;
+ uint32_t selected_gpu = 0;
+ bool has_selected_gpu = false; // differentiate between selecting the 0th gpu and using the default 0th value
+ ShowSettings show;
+ bool print_to_file = false;
+ std::string filename; // set if explicitly given, or if vkconfig_output has a <path> argument
+ std::string default_filename;
+};
+
+util::vulkaninfo_optional<ParsedResults> parse_arguments(int argc, char **argv, std::string executable_name) {
+ ParsedResults results{};
+ results.default_filename = APP_SHORT_NAME ".txt";
+ for (int i = 1; i < argc; ++i) {
+ // A internal-use-only format for communication with the Vulkan Configurator tool
+ // Usage "--vkconfig_output <path>"
+ // -o can be used to specify the filename instead
+ if (0 == strcmp("--vkconfig_output", argv[i])) {
+ results.output_category = OutputCategory::vkconfig_output;
+ results.print_to_file = true;
+ results.default_filename = APP_SHORT_NAME ".json";
+ if (argc > (i + 1) && argv[i + 1][0] != '-') {
+#ifdef WIN32
+ results.filename = (std::string(argv[i + 1]) + "\\" APP_SHORT_NAME ".json");
+#else
+ results.filename = (std::string(argv[i + 1]) + "/" APP_SHORT_NAME ".json");
+#endif
+ ++i;
+ }
+ } else if (strncmp("--json", argv[i], 6) == 0 || strncmp(argv[i], "-j", 2) == 0) {
+ if (strlen(argv[i]) > 7 && strncmp("--json=", argv[i], 7) == 0) {
+ results.selected_gpu = static_cast<uint32_t>(strtol(argv[i] + 7, nullptr, 10));
+ results.has_selected_gpu = true;
+ }
+ if (strlen(argv[i]) > 3 && strncmp("-j=", argv[i], 3) == 0) {
+ results.selected_gpu = static_cast<uint32_t>(strtol(argv[i] + 3, nullptr, 10));
+ results.has_selected_gpu = true;
+ }
+ results.output_category = OutputCategory::profile_json;
+ results.default_filename = APP_SHORT_NAME ".json";
+ results.print_to_file = true;
+ } else if (strcmp(argv[i], "--summary") == 0) {
+ results.output_category = OutputCategory::summary;
+ } else if (strcmp(argv[i], "--text") == 0) {
+ results.output_category = OutputCategory::text;
+ results.default_filename = APP_SHORT_NAME ".txt";
+ } else if (strcmp(argv[i], "--html") == 0) {
+ results.output_category = OutputCategory::html;
+ results.print_to_file = true;
+ results.default_filename = APP_SHORT_NAME ".html";
+ } else if (strcmp(argv[i], "--show-all") == 0) {
+ results.show.all = true;
+ results.show.tool_props = true;
+ results.show.formats = true;
+ results.show.promoted_structs = true;
+ results.show.video_props = true;
+ } else if (strcmp(argv[i], "--show-tool-props") == 0) {
+ results.show.tool_props = true;
+ } else if (strcmp(argv[i], "--show-formats") == 0) {
+ results.show.formats = true;
+ } else if (strcmp(argv[i], "--show-promoted-structs") == 0) {
+ results.show.promoted_structs = true;
+ } else if (strcmp(argv[i], "--show-video-props") == 0) {
+ results.show.video_props = true;
+ } else if ((strcmp(argv[i], "--output") == 0 || strcmp(argv[i], "-o") == 0) && argc > (i + 1)) {
+ if (argv[i + 1][0] == '-') {
+ std::cout << "-o or --output must be followed by a filename\n";
+ return {};
+ }
+ results.print_to_file = true;
+ results.filename = argv[i + 1];
+ ++i;
+ } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
+ print_usage(executable_name);
+ return {};
+ } else {
+ print_usage(executable_name);
+ return {};
+ }
+ }
+ return results;
+}
+
+PrinterCreateDetails get_printer_create_details(ParsedResults &parse_data, AppInstance &inst, AppGpu &selected_gpu,
+ std::string const &executable_name) {
+ PrinterCreateDetails create{};
+ create.print_to_file = parse_data.print_to_file;
+ create.file_name = (!parse_data.filename.empty()) ? parse_data.filename : parse_data.default_filename;
+ switch (parse_data.output_category) {
+ default:
+ case (OutputCategory::text):
+ create.output_type = OutputType::text;
+ break;
+ case (OutputCategory::html):
+ create.output_type = OutputType::html;
+ break;
+ case (OutputCategory::profile_json):
+ create.output_type = OutputType::json;
+ create.start_string =
+ std::string("{\n\t\"$schema\": ") + "\"https://schema.khronos.org/vulkan/profiles-0.8-latest.json\"";
+ if (parse_data.filename.empty()) {
+ create.file_name = std::string("VP_" APP_UPPER_CASE_NAME "_") + std::string(selected_gpu.props.deviceName) + "_" +
+ selected_gpu.GetDriverVersionString();
+ for (auto &c : create.file_name) {
+ if (c == ' ' || c == '.') c = '_';
+ }
+ create.file_name += ".json";
+ }
+ break;
+ case (OutputCategory::vkconfig_output):
+ create.output_type = OutputType::vkconfig_output;
+ create.start_string = "{\n\t\"" API_NAME " Instance Version\": \"" + inst.api_version.str() + "\"";
+ break;
+ }
+ return create;
+}
+
+void RunPrinter(Printer &p, ParsedResults parse_data, AppInstance &instance, std::vector<std::unique_ptr<AppGpu>> &gpus,
+ std::vector<std::unique_ptr<AppSurface>> &surfaces) {
+#ifdef VK_USE_PLATFORM_IOS_MVK
+ p.SetAlwaysOpenDetails(true);
+#endif
+ if (parse_data.output_category == OutputCategory::summary) {
+ DumpSummaryInstance(p, instance);
+ p.SetHeader();
+ ObjectWrapper obj(p, "Devices");
+ IndentWrapper indent(p);
+ for (auto &gpu : gpus) {
+ DumpSummaryGPU(p, *(gpu.get()));
+ }
+ } else if (parse_data.output_category == OutputCategory::profile_json) {
+ DumpGpuProfileCapabilities(p, *(gpus.at(parse_data.selected_gpu).get()), parse_data.show.promoted_structs);
+ DumpGpuProfileInfo(p, *(gpus.at(parse_data.selected_gpu).get()));
+ } else {
+ // text, html, vkconfig_output
+ p.SetHeader();
+ DumpExtensions(p, "Instance Extensions", instance.global_extensions);
+ p.AddNewline();
+
+ DumpLayers(p, instance.global_layers, gpus);
+#if defined(VULKANINFO_WSI_ENABLED)
+ // Doesn't print anything if no surfaces are available
+ DumpPresentableSurfaces(p, instance, gpus, surfaces);
+#endif // defined(VULKANINFO_WSI_ENABLED)
+ DumpGroups(p, instance);
+
+ p.SetHeader();
+ ObjectWrapper obj(p, "Device Properties and Extensions");
+ IndentWrapper indent(p);
+
+ for (auto &gpu : gpus) {
+ DumpGpu(p, *(gpu.get()), parse_data.show);
+ }
+ }
+}
+
+#ifdef VK_USE_PLATFORM_IOS_MVK
+// On iOS, we'll call this ourselves from a parent routine in the GUI
+int vulkanInfoMain(int argc, char **argv) {
+#else
+int main(int argc, char **argv) {
+#endif
+
+ // Figure out the name of the executable, pull out the name if given a path
+ // Default is `vulkaninfo`
+ std::string executable_name = APP_SHORT_NAME;
+ if (argc >= 1) {
+ const auto argv_0 = std::string(argv[0]);
+ // don't include path separator
+ // Look for forward slash first, only look for backslash if that found nothing
+ auto last_occurrence = argv_0.rfind('/');
+ if (last_occurrence == std::string::npos) {
+ last_occurrence = argv_0.rfind('\\');
+ }
+ if (last_occurrence != std::string::npos && last_occurrence + 1 < argv_0.size()) {
+ executable_name = argv_0.substr(last_occurrence + 1);
+ }
+ }
+
+ auto parsing_return = parse_arguments(argc, argv, executable_name);
+ if (!parsing_return) return 1;
+ ParsedResults parse_data = parsing_return.value();
+
+#if defined(_MSC_VER)
+ _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
+ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
+ _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
+ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+
+ if (ConsoleIsExclusive()) ConsoleEnlarge();
+ User32Handles local_user32_handles;
+ user32_handles = &local_user32_handles;
+ if (!local_user32_handles.load()) {
+ fprintf(stderr, "Failed to load user32.dll library!\n");
+ if (parse_data.output_category == OutputCategory::text && !parse_data.print_to_file) wait_for_console_destroy();
+ return 1;
+ }
+#endif
+
+ int return_code = 0; // set in case of error
+ std::unique_ptr<Printer> printer;
+ std::ostream std_out(std::cout.rdbuf());
+ std::ofstream file_out;
+ std::ostream *out = &std_out;
+
+ // if any essential vulkan call fails, it throws an exception
+ try {
+ AppInstance instance = {};
+ SetupWindowExtensions(instance);
+
+ auto phys_devices = instance.FindPhysicalDevices();
+
+#if defined(VULKANINFO_WSI_ENABLED)
+ for (auto &surface_extension : instance.surface_extensions) {
+ surface_extension.create_window(instance);
+ surface_extension.surface = surface_extension.create_surface(instance);
+ }
+#endif // defined(VULKANINFO_WSI_ENABLED)
+
+ std::vector<std::unique_ptr<AppGpu>> gpus;
+
+ uint32_t gpu_counter = 0;
+ for (auto &phys_device : phys_devices) {
+ gpus.push_back(
+ std::unique_ptr<AppGpu>(new AppGpu(instance, gpu_counter++, phys_device, parse_data.show.promoted_structs)));
+ }
+
+ std::vector<std::unique_ptr<AppSurface>> surfaces;
+#if defined(VULKANINFO_WSI_ENABLED)
+ for (auto &surface_extension : instance.surface_extensions) {
+ for (auto &gpu : gpus) {
+ try {
+ // check if the surface is supported by the physical device before adding it to the list
+ VkBool32 supported = VK_FALSE;
+ VkResult err = vkGetPhysicalDeviceSurfaceSupportKHR(gpu->phys_device, 0, surface_extension.surface, &supported);
+ if (err != VK_SUCCESS || supported == VK_FALSE) continue;
+
+ surfaces.push_back(
+ std::unique_ptr<AppSurface>(new AppSurface(instance, *gpu.get(), gpu->phys_device, surface_extension)));
+ } catch (std::exception &e) {
+ std::cerr << "ERROR while creating surface for extension " << surface_extension.name << " : " << e.what()
+ << "\n";
+ }
+ }
+ }
+#endif // defined(VULKANINFO_WSI_ENABLED)
+
+ if (parse_data.selected_gpu >= gpus.size()) {
+ if (parse_data.has_selected_gpu) {
+ std::cout << "The selected gpu (" << parse_data.selected_gpu << ") is not a valid GPU index. ";
+ if (gpus.size() == 0) {
+ std::cout << APP_SHORT_NAME " could not find any GPU's.\n";
+ return 1;
+ } else {
+ if (gpus.size() == 1) {
+ std::cout << "The only available GPU selection is 0.\n";
+ } else {
+ std::cout << "The available GPUs are in the range of 0 to " << gpus.size() - 1 << ".\n";
+ }
+ return 1;
+ }
+ } else if (parse_data.output_category == OutputCategory::profile_json) {
+ std::cout << APP_SHORT_NAME " could not find any GPU's.\n";
+ }
+ }
+
+ auto printer_data = get_printer_create_details(parse_data, instance, *gpus.at(parse_data.selected_gpu), executable_name);
+ if (printer_data.print_to_file) {
+ file_out = std::ofstream(printer_data.file_name);
+ out = &file_out;
+ }
+ printer = std::unique_ptr<Printer>(new Printer(printer_data, *out, instance.api_version));
+
+ RunPrinter(*(printer.get()), parse_data, instance, gpus, surfaces);
+
+ // Call the printer's destructor before the file handle gets closed
+ printer.reset(nullptr);
+#if defined(VULKANINFO_WSI_ENABLED)
+ for (auto &surface_extension : instance.surface_extensions) {
+ AppDestroySurface(instance, surface_extension.surface);
+ surface_extension.destroy_window(instance);
+ }
+#endif // defined(VULKANINFO_WSI_ENABLED)
+ } catch (std::exception &e) {
+ // Print the error to stderr and leave all outputs in a valid state (mainly for json)
+ std::cerr << "ERROR at " << e.what() << "\n";
+ if (printer) {
+ printer->FinishOutput();
+ }
+ return_code = 1;
+
+ // Call the printer's destructor before the file handle gets closed
+ printer.reset(nullptr);
+ }
+
+#ifdef _WIN32
+ if (parse_data.output_category == OutputCategory::text && !parse_data.print_to_file) wait_for_console_destroy();
+#endif
+
+ return return_code;
+}