aboutsummaryrefslogtreecommitdiff
path: root/vulkaninfo/vulkaninfo.cpp
diff options
context:
space:
mode:
authorCharles Giessen <charles@lunarg.com>2019-08-13 11:16:59 -0600
committerCharles Giessen <46324611+charles-lunarg@users.noreply.github.com>2019-10-04 09:14:44 -0600
commit623d1cc06173a7e209affe6030311abc464beb74 (patch)
tree68c33ef0491ab8d5515e5a9a3019bb1680f53124 /vulkaninfo/vulkaninfo.cpp
parent7513420a385869903b907d2d42e3ee93f93fa551 (diff)
downloadusermoji-623d1cc06173a7e209affe6030311abc464beb74.tar.xz
vulkaninfo: Major Refactor
Rewrote vulkan info to use C++ and include autogen capabilities Properties and Features are now populated based on the xml spec Improved readability and robustness by seperating vulkan info gathering, formatting, and printing into seperate files Files Added: - scripts/generate_vulkaninfo.py - vulkaninfo/vulkaninfo.h - vulkaninfo/vulkaninfo.cpp - vulkaninfo/outputprinter.h - vulkaninfo/generated/vulkaninfo.hpp - vulkaninfo/generated/.clang-format Files Modified: - scripts/kvt_genvk.py - vulkaninfo/CMakeLists.txt - vulkaninfo/macOS/vulkaninfo.cmake Files Removed: - vulkaninfo/vulkaninfo.c Change-Id: I8042a6a7949595b75f03d1f3ba48e221d2cc0e8a
Diffstat (limited to 'vulkaninfo/vulkaninfo.cpp')
-rw-r--r--vulkaninfo/vulkaninfo.cpp751
1 files changed, 751 insertions, 0 deletions
diff --git a/vulkaninfo/vulkaninfo.cpp b/vulkaninfo/vulkaninfo.cpp
new file mode 100644
index 00000000..f51a59e3
--- /dev/null
+++ b/vulkaninfo/vulkaninfo.cpp
@@ -0,0 +1,751 @@
+/*
+ * Copyright (c) 2015-2019 The Khronos Group Inc.
+ * Copyright (c) 2015-2019 Valve Corporation
+ * Copyright (c) 2015-2019 LunarG, Inc.
+ *
+ * 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: Charles Giessen <charles@lunarg.com>
+ *
+ */
+
+#include "vulkaninfo.hpp"
+
+// =========== Dump Functions ========= //
+
+void DumpExtensions(Printer &p, std::string layer_name, std::vector<VkExtensionProperties> extensions) {
+ std::sort(extensions.begin(), extensions.end(), [](VkExtensionProperties &a, VkExtensionProperties &b) -> int {
+ return std::string(a.extensionName) < std::string(b.extensionName);
+ });
+
+ if (p.Type() == OutputType::json) return;
+
+ int max_length = 0;
+ if (extensions.size() > 0) {
+ max_length = strlen(extensions.at(0).extensionName);
+ for (auto &ext : extensions) {
+ int len = strlen(ext.extensionName);
+ if (len > max_length) max_length = len;
+ }
+ }
+
+ p.ArrayStart(layer_name + " Extensions", extensions.size());
+ for (auto &ext : extensions) {
+ p.PrintExtension(ext.extensionName, ext.specVersion, max_length);
+ }
+ p.ArrayEnd();
+}
+
+void DumpLayers(Printer &p, std::vector<LayerExtensionList> layers, std::vector<AppGpu *> gpus) {
+ std::sort(layers.begin(), layers.end(), [](LayerExtensionList &left, LayerExtensionList &right) -> int {
+ const char *a = left.layer_properties.layerName;
+ const char *b = right.layer_properties.layerName;
+ return a && (!b || std::strcmp(a, b) < 0);
+ });
+
+ if (p.Type() == OutputType::text || p.Type() == OutputType::html) {
+ p.SetHeader().ArrayStart("Layers", layers.size());
+ p.IndentDecrease();
+ for (auto &layer : layers) {
+ auto v_str = VkVersionString(layer.layer_properties.specVersion);
+ auto props = layer.layer_properties;
+
+ std::string header;
+ if (p.Type() == OutputType::text)
+ header = std::string(props.layerName) + " (" + props.description + ") Vulkan version " + v_str +
+ ", layer version " + std::to_string(props.implementationVersion);
+ else if (p.Type() == OutputType::html)
+ header = std::string("<span class='type'>") + props.layerName + "</span> (" + props.description +
+ ") Vulkan version <span class='val'>" + v_str + "</span>, layer version <span class='val'>" +
+ std::to_string(props.implementationVersion) + "</span>";
+
+ p.ObjectStart(header);
+ DumpExtensions(p, "Layer", layer.extension_properties);
+
+ p.ArrayStart("Devices", gpus.size());
+ for (auto &gpu : gpus) {
+ p.PrintElement(std::string("GPU id \t: ") + std::to_string(gpu->id), gpu->props.deviceName);
+ auto exts = gpu->AppGetPhysicalDeviceLayerExtensions(props.layerName);
+ DumpExtensions(p, "Layer-Device", exts);
+ p.AddNewline();
+ }
+ p.ArrayEnd();
+ p.ObjectEnd();
+ }
+ p.IndentIncrease();
+ p.ArrayEnd();
+ } else if (p.Type() == OutputType::json) {
+ p.ArrayStart("ArrayOfVkLayerProperties", layers.size());
+ int i = 0;
+ for (auto &layer : layers) {
+ p.SetElementIndex(i++);
+ DumpVkLayerProperties(p, "layerProperty", layer.layer_properties);
+ }
+ p.ArrayEnd();
+ }
+}
+
+void DumpSurfaceFormats(Printer &p, AppInstance &inst, AppSurface &surface) {
+ p.ArrayStart("Formats", surface.surf_formats2.size());
+ int i = 0;
+ if (inst.CheckExtensionEnabled(VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME)) {
+ for (auto &format : surface.surf_formats2) {
+ p.SetElementIndex(i++);
+ DumpVkSurfaceFormatKHR(p, "SurfaceFormat", format.surfaceFormat);
+ }
+ } else {
+ for (auto &format : surface.surf_formats) {
+ p.SetElementIndex(i++);
+ DumpVkSurfaceFormatKHR(p, "SurfaceFormat", format);
+ }
+ }
+ p.ArrayEnd();
+}
+
+void DumpPresentModes(Printer &p, AppInstance &inst, AppSurface &surface) {
+ p.ArrayStart("Present Modes", surface.surf_present_modes.size());
+ for (auto &mode : surface.surf_present_modes) {
+ p.SetAsType().PrintElement(VkPresentModeKHRString(mode));
+ }
+ p.ArrayEnd();
+}
+
+void DumpSurfaceCapabilities(Printer &p, AppInstance &inst, AppGpu &gpu, AppSurface &surface) {
+ auto &surf_cap = surface.surface_capabilities;
+ p.SetSubHeader();
+ DumpVkSurfaceCapabilitiesKHR(p, "VkSurfaceCapabilitiesKHR", surf_cap);
+
+ p.SetSubHeader().ObjectStart("VkSurfaceCapabilities2EXT");
+ {
+ p.ObjectStart("supportedSurfaceCounters");
+ if (surface.surface_capabilities2_ext.supportedSurfaceCounters == 0) p.PrintElement("None");
+ if (surface.surface_capabilities2_ext.supportedSurfaceCounters & VK_SURFACE_COUNTER_VBLANK_EXT) {
+ p.SetAsType().PrintElement("VK_SURFACE_COUNTER_VBLANK_EXT");
+ }
+ p.ObjectEnd();
+ }
+ p.ObjectEnd(); // VkSurfaceCapabilities2EXT
+
+ chain_iterator_surface_capabilities2(p, inst, gpu, surface.surface_capabilities2_khr.pNext);
+}
+
+void DumpSurface(Printer &p, AppInstance &inst, AppGpu &gpu, AppSurface &surface) {
+ std::string header;
+ if (p.Type() == OutputType::text)
+ header = std::string("GPU id : ") + std::to_string(gpu.id) + " (" + gpu.props.deviceName + ")";
+ else if (p.Type() == OutputType::html)
+ header = std::string("GPU id : <span class='val'>") + std::to_string(gpu.id) + "</span> (" + gpu.props.deviceName + ")";
+ p.ObjectStart(header);
+
+ p.SetAsType().PrintKeyValue("Surface type", surface.surface_extension.name);
+
+ DumpSurfaceFormats(p, inst, surface);
+
+ DumpPresentModes(p, inst, surface);
+
+ DumpSurfaceCapabilities(p, inst, gpu, surface);
+
+ p.ObjectEnd();
+ p.AddNewline();
+}
+
+void DumpPresentableSurfaces(Printer &p, AppInstance &inst, std::vector<AppGpu *> &gpus, std::vector<AppSurface *> &surfaces) {
+ p.SetHeader().ObjectStart("Presentable Surfaces");
+ p.IndentDecrease();
+ for (auto &surface : surfaces) {
+ for (auto &gpu : gpus) {
+ DumpSurface(p, inst, *gpu, *surface);
+ }
+ }
+ p.ObjectEnd();
+ p.IndentIncrease();
+ p.AddNewline();
+}
+
+void DumpGroups(Printer &p, AppInstance &inst) {
+ if (inst.CheckExtensionEnabled(VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME)) {
+ p.SetHeader().ObjectStart("Groups");
+ auto groups = GetGroups(inst);
+ int group_id = 0;
+ for (auto &group : groups) {
+ p.ObjectStart("Device Group Properties (Group " + std::to_string(group_id) + ")");
+ auto group_props = GetGroupProps(group);
+ p.ArrayStart("physicalDeviceCount", group.physicalDeviceCount);
+ int id = 0;
+ for (auto &prop : group_props) {
+ std::string device_out;
+ if (p.Type() == OutputType::text) {
+ device_out = std::string(prop.deviceName) + " (ID: " + std::to_string(id++) + ")";
+ } else if (p.Type() == OutputType::html) {
+ device_out = std::string(prop.deviceName) + " (ID: <span class='val'>" + std::to_string(id++) + "</span>)";
+ }
+ p.PrintElement(device_out);
+ }
+ p.ArrayEnd();
+ p.PrintKeyValue("subsetAllocation", group.subsetAllocation);
+ p.ObjectEnd();
+ p.AddNewline();
+
+ p.ObjectStart("Device Group Present Capabilities (Group " + std::to_string(group_id) + ")");
+
+ auto group_capabilities = GetGroupCapabilities(inst, group);
+ for (uint32_t i = 0; i < group.physicalDeviceCount; i++) {
+ std::string device_out;
+ if (p.Type() == OutputType::text) {
+ device_out = std::string(group_props[i].deviceName) + " (ID: " + std::to_string(i) + ")";
+ } else if (p.Type() == OutputType::html) {
+ device_out =
+ std::string(group_props[i].deviceName) + " (ID: <span class='val'>" + std::to_string(i) + "</span>)";
+ }
+ p.PrintElement(device_out);
+ p.ObjectStart("Can present images from the following devices");
+ for (uint32_t j = 0; j < group.physicalDeviceCount; j++) {
+ uint32_t mask = 1 << j;
+ if (group_capabilities.presentMask[i] & mask) {
+ if (p.Type() == OutputType::text)
+ p.PrintElement(std::string(group_props[j].deviceName) + " (ID: " + std::to_string(j) + ")");
+ if (p.Type() == OutputType::html)
+ p.PrintElement(std::string(group_props[j].deviceName) + " (ID: <span class='val'>" + std::to_string(j) +
+ "</span>)");
+ }
+ }
+ p.ObjectEnd();
+ }
+ DumpVkDeviceGroupPresentModeFlagsKHR(p, "Present modes", group_capabilities.modes);
+ p.ObjectEnd();
+ p.AddNewline();
+ group_id++;
+ }
+ p.ObjectEnd();
+ p.AddNewline();
+ }
+}
+
+void GpuDumpProps(Printer &p, AppGpu &gpu) {
+ auto props = gpu.GetDeviceProperties();
+ p.SetSubHeader().ObjectStart("VkPhysicalDeviceProperties");
+ p.PrintKeyValue("apiVersion", props.apiVersion, 14, VkVersionString(props.apiVersion));
+ p.PrintKeyValue("driverVersion", props.driverVersion, 14, to_hex_str(props.driverVersion));
+ if (p.Type() == OutputType::json) {
+ p.PrintKeyValue("vendorID", props.vendorID, 14);
+ p.PrintKeyValue("deviceID", props.deviceID, 14);
+ p.PrintKeyValue("deviceType", props.deviceType, 14);
+ } else {
+ p.PrintKeyValue("vendorID", to_hex_str(props.vendorID), 14);
+ p.PrintKeyValue("deviceID", to_hex_str(props.deviceID), 14);
+ p.PrintKeyString("deviceType", VkPhysicalDeviceTypeString(props.deviceType), 14);
+ }
+ p.PrintKeyString("deviceName", props.deviceName, 14);
+ if (p.Type() == OutputType::json) {
+ p.ArrayStart("pipelineCacheUUID");
+ for (uint32_t i = 0; i < VK_UUID_SIZE; ++i) {
+ p.PrintElement(static_cast<uint32_t>(props.pipelineCacheUUID[i]));
+ }
+ p.ArrayEnd();
+ }
+ p.AddNewline();
+ if (p.Type() != OutputType::json) {
+ p.ObjectEnd(); // limits and sparse props are not sub objects in the text and html output
+ }
+
+ if (gpu.inst.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
+ DumpVkPhysicalDeviceLimits(p, "VkPhysicalDeviceLimits", gpu.props2.properties.limits);
+ } else {
+ DumpVkPhysicalDeviceLimits(p, "VkPhysicalDeviceLimits", gpu.props.limits);
+ }
+ p.AddNewline();
+ if (gpu.inst.CheckExtensionEnabled(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME)) {
+ DumpVkPhysicalDeviceSparseProperties(p, "VkPhysicalDeviceSparseProperties", gpu.props2.properties.sparseProperties);
+ } else {
+ DumpVkPhysicalDeviceSparseProperties(p, "VkPhysicalDeviceSparseProperties", gpu.props.sparseProperties);
+ }
+ p.AddNewline();
+ if (p.Type() == OutputType::json) {
+ p.ObjectEnd(); // limits and sparse props are sub objects in the json output
+ }
+
+ if (p.Type() != OutputType::json) {
+ 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, place);
+ }
+ }
+ p.AddNewline();
+}
+void GpuDumpQueueProps(Printer &p, std::vector<SurfaceExtension> &surfaces, AppQueueFamilyProperties &queue) {
+ p.SetHeader().SetElementIndex(queue.queue_index).ObjectStart("VkQueueFamilyProperties");
+ if (p.Type() == OutputType::json) {
+ DumpVkExtent3D(p, "minImageTransferGranularity", queue.props.minImageTransferGranularity);
+ } else {
+ p.PrintKeyString("minImageTransferGranularity", VkExtent3DString(queue.props.minImageTransferGranularity), 27);
+ }
+ p.PrintKeyValue("queueCount", queue.props.queueCount, 27);
+ if (p.Type() == OutputType::json) {
+ p.PrintKeyValue("queueFlags", queue.props.queueFlags, 27);
+ } else {
+ p.PrintKeyValue("queueFlags", VkQueueFlagsString(queue.props.queueFlags), 27);
+ }
+
+ p.PrintKeyValue("timestampValidBits", queue.props.timestampValidBits, 27);
+
+ if (p.Type() != OutputType::json) {
+ if (queue.is_present_platform_agnostic) {
+ p.PrintKeyString("present support", queue.platforms_support_present ? "true" : "false");
+ } else {
+ p.ObjectStart("present support");
+ for (auto &surface : surfaces) {
+ p.PrintKeyString(surface.name, surface.supports_present ? "true" : "false", 19);
+ }
+ p.ObjectEnd();
+ }
+ }
+ p.ObjectEnd();
+ 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
+
+static char *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 strndup(buf, kBufferSize);
+}
+
+void GpuDumpMemoryProps(Printer &p, AppGpu &gpu) {
+ p.SetHeader().ObjectStart("VkPhysicalDeviceMemoryProperties");
+ p.IndentDecrease();
+ p.ArrayStart("memoryHeaps", gpu.memory_props.memoryHeapCount);
+ for (uint32_t i = 0; i < gpu.memory_props.memoryHeapCount; ++i) {
+ const VkDeviceSize memSize = gpu.memory_props.memoryHeaps[i].size;
+ std::string mem_size_human_readable = std::string(NumToNiceStr(static_cast<size_t>(memSize)));
+
+ std::string mem_size_str = std::to_string(memSize) + " (" + to_hex_str(memSize) + ") (" + mem_size_human_readable + ")";
+
+ p.SetElementIndex(i).ObjectStart("memoryHeaps");
+ if (p.Type() != OutputType::json) {
+ p.PrintKeyValue("size", mem_size_str, 6);
+ p.PrintKeyValue("budget", gpu.heapBudget[i], 6);
+ p.PrintKeyValue("usage", gpu.heapUsage[i], 6);
+ DumpVkMemoryHeapFlags(p, "flags", gpu.memory_props.memoryHeaps[i].flags, 6);
+ } else {
+ p.PrintKeyValue("flags", gpu.memory_props.memoryHeaps[i].flags);
+ p.PrintKeyValue("size", memSize);
+ }
+ p.ObjectEnd();
+ }
+ p.ArrayEnd();
+
+ p.ArrayStart("memoryTypes", gpu.memory_props.memoryTypeCount);
+ for (uint32_t i = 0; i < gpu.memory_props.memoryTypeCount; ++i) {
+ p.SetElementIndex(i).ObjectStart("memoryTypes");
+ p.PrintKeyValue("heapIndex", gpu.memory_props.memoryTypes[i].heapIndex, 13);
+ if (p.Type() == OutputType::json) {
+ p.PrintKeyValue("propertyFlags", gpu.memory_props.memoryTypes[i].propertyFlags, 13);
+ } else {
+ auto flags = gpu.memory_props.memoryTypes[i].propertyFlags;
+ DumpVkMemoryPropertyFlags(p, "propertyFlags = " + to_hex_str(flags), flags);
+
+ p.ObjectStart("usable for");
+ const uint32_t memtype_bit = 1 << i;
+
+ // only linear and optimal tiling considered
+ for (uint32_t tiling = VK_IMAGE_TILING_OPTIMAL; tiling < gpu.mem_type_res_support.image.size(); ++tiling) {
+ std::string usable;
+ usable += std::string(VkImageTilingString(VkImageTiling(tiling))) + ": ";
+ size_t orig_usable_str_size = usable.size();
+ bool first = true;
+ for (size_t fmt_i = 0; fmt_i < gpu.mem_type_res_support.image[tiling].size(); ++fmt_i) {
+ const MemImageSupport *image_support = &gpu.mem_type_res_support.image[tiling][fmt_i];
+ const bool regular_compatible =
+ image_support->regular_supported && (image_support->regular_memtypes & memtype_bit);
+ const bool sparse_compatible =
+ image_support->sparse_supported && (image_support->sparse_memtypes & memtype_bit);
+ const bool transient_compatible =
+ image_support->transient_supported && (image_support->transient_memtypes & memtype_bit);
+
+ if (regular_compatible || sparse_compatible || transient_compatible) {
+ if (!first) usable += ", ";
+ first = false;
+
+ if (fmt_i == 0) {
+ usable += "color images";
+ } else {
+ usable += VkFormatString(gpu.mem_type_res_support.image[tiling][fmt_i].format);
+ }
+
+ if (regular_compatible && !sparse_compatible && !transient_compatible && image_support->sparse_supported &&
+ image_support->transient_supported) {
+ usable += "(non-sparse, non-transient)";
+ } else if (regular_compatible && !sparse_compatible && image_support->sparse_supported) {
+ if (image_support->sparse_supported) usable += "(non-sparse)";
+ } else if (regular_compatible && !transient_compatible && image_support->transient_supported) {
+ if (image_support->transient_supported) usable += "(non-transient)";
+ } else if (!regular_compatible && sparse_compatible && !transient_compatible &&
+ image_support->sparse_supported) {
+ if (image_support->sparse_supported) usable += "(sparse only)";
+ } else if (!regular_compatible && !sparse_compatible && transient_compatible &&
+ image_support->transient_supported) {
+ if (image_support->transient_supported) usable += "(transient only)";
+ } else if (!regular_compatible && sparse_compatible && transient_compatible &&
+ image_support->sparse_supported && image_support->transient_supported) {
+ usable += "(sparse and transient only)";
+ }
+ }
+ }
+ if (usable.size() == orig_usable_str_size) // not usable for anything
+ {
+ usable += "None";
+ }
+ p.PrintElement(usable);
+ }
+ p.ObjectEnd();
+ }
+
+ p.ObjectEnd();
+ }
+ p.ArrayEnd();
+ p.IndentIncrease();
+ p.ObjectEnd();
+ p.AddNewline();
+}
+
+void GpuDumpFeatures(Printer &p, AppGpu &gpu) {
+ p.SetHeader();
+ DumpVkPhysicalDeviceFeatures(p, "VkPhysicalDeviceFeatures", gpu.features);
+ p.AddNewline();
+ if (p.Type() != OutputType::json) {
+ 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, place);
+ }
+ }
+}
+
+void GpuDumpFormatProperty(Printer &p, VkFormatProperties prop) {
+ p.SetOpenDetails();
+ DumpVkFormatFeatureFlags(p, "linearTiling", prop.linearTilingFeatures);
+ p.SetOpenDetails();
+ DumpVkFormatFeatureFlags(p, "optimalTiling", prop.optimalTilingFeatures);
+ p.SetOpenDetails();
+ DumpVkFormatFeatureFlags(p, "bufferFeatures", prop.bufferFeatures);
+}
+
+void GpuDevDump(Printer &p, AppGpu &gpu, pNextChainInfos &chainInfos) {
+ if (p.Type() == OutputType::json) {
+ p.ArrayStart("ArrayOfVkFormatProperties");
+ } else {
+ p.SetHeader().ObjectStart("Format Properties");
+ p.IndentDecrease();
+ }
+
+ if (p.Type() == OutputType::text) {
+ auto fmtPropMap = FormatPropMap(gpu);
+
+ int counter = 0;
+ std::vector<VkFormat> unsupported_formats;
+ for (auto &prop : fmtPropMap) {
+ VkFormatProperties props;
+ props.linearTilingFeatures = prop.first.linear;
+ props.optimalTilingFeatures = prop.first.optimal;
+ props.bufferFeatures = prop.first.buffer;
+ if (props.linearTilingFeatures == 0 && props.optimalTilingFeatures == 0 && props.bufferFeatures == 0) {
+ unsupported_formats = prop.second;
+ continue;
+ }
+
+ p.SetElementIndex(counter++).ObjectStart("Common Format Group");
+ p.IndentDecrease();
+ p.ObjectStart("Formats");
+ for (auto &fmt : prop.second) {
+ p.SetAsType().PrintElement(VkFormatString(fmt));
+ }
+ p.ObjectEnd();
+
+ p.ObjectStart("Properies");
+ GpuDumpFormatProperty(p, props);
+ p.ObjectEnd();
+
+ p.IndentIncrease();
+ p.ObjectEnd();
+ p.AddNewline();
+ }
+
+ p.ObjectStart("Unsupported Formats");
+ for (auto &fmt : unsupported_formats) {
+ p.SetAsType().PrintElement(VkFormatString(fmt));
+ }
+ p.ObjectEnd();
+
+ } else {
+ for (auto &format : gpu.supported_format_ranges) {
+ if (gpu.FormatRangeSupported(format)) {
+ for (uint32_t fmt_counter = format.first_format; fmt_counter <= format.last_format; ++fmt_counter) {
+ VkFormat fmt = static_cast<VkFormat>(fmt_counter);
+
+ VkFormatProperties props;
+ vkGetPhysicalDeviceFormatProperties(gpu.phys_device, fmt, &props);
+
+ if (p.Type() == OutputType::html) {
+ p.SetTitleAsType().ObjectStart(VkFormatString(fmt));
+ GpuDumpFormatProperty(p, props);
+ p.ObjectEnd();
+ } else if (p.Type() == OutputType::json &&
+ (props.linearTilingFeatures || props.optimalTilingFeatures || props.bufferFeatures)) {
+ p.SetTitleAsType().ObjectStart("");
+ p.PrintKeyValue("formatID", fmt);
+ p.PrintKeyValue("linearTilingFeatures", props.linearTilingFeatures);
+ p.PrintKeyValue("optimalTilingFeatures", props.optimalTilingFeatures);
+ p.PrintKeyValue("bufferFeatures", props.bufferFeatures);
+ p.ObjectEnd();
+ }
+ }
+ }
+ }
+ }
+
+ if (p.Type() == OutputType::json) {
+ p.ArrayEnd();
+ } else {
+ p.ObjectEnd();
+ p.IndentIncrease();
+ }
+
+ p.AddNewline();
+}
+
+void DumpGpu(Printer &p, AppGpu &gpu, bool show_formats, pNextChainInfos &chainInfos) {
+ if (p.Type() != OutputType::json) {
+ p.ObjectStart("GPU" + std::to_string(gpu.id));
+ p.IndentDecrease();
+ }
+ GpuDumpProps(p, gpu);
+
+ if (p.Type() != OutputType::json) {
+ DumpExtensions(p, "Device", gpu.device_extensions);
+ p.AddNewline();
+ }
+
+ if (p.Type() == OutputType::json) p.ArrayStart("ArrayOfVkQueueFamilyProperties");
+ for (uint32_t i = 0; i < gpu.queue_count; i++) {
+ AppQueueFamilyProperties queue_props = AppQueueFamilyProperties(gpu, i);
+ GpuDumpQueueProps(p, gpu.inst.surface_extensions, queue_props);
+ }
+ if (p.Type() == OutputType::json) p.ArrayEnd();
+
+ GpuDumpMemoryProps(p, gpu);
+ GpuDumpFeatures(p, gpu);
+ if (p.Type() != OutputType::text || show_formats) {
+ GpuDevDump(p, gpu, chainInfos);
+ }
+
+ if (p.Type() != OutputType::json) {
+ p.ObjectEnd();
+ p.IndentIncrease();
+ }
+ p.AddNewline();
+}
+
+// ============ 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
+
+void print_usage(const char *argv0) {
+ std::cout << "\nvulkaninfo - Summarize Vulkan information in relation to the current environment.\n\n";
+ std::cout << "USAGE: " << argv0 << " [options]\n\n";
+ std::cout << "OPTIONS:\n";
+ std::cout << "-h, --help Print this help.\n";
+ std::cout << "--html Produce an html version of vulkaninfo output, saved as\n";
+ std::cout << " \"vulkaninfo.html\" in the directory in which the command is\n";
+ std::cout << " run.\n";
+ std::cout << "-j, --json Produce a json version of vulkaninfo output to standard\n";
+ std::cout << " output.\n";
+ std::cout << "--json=<gpu-number> For a multi-gpu system, a single gpu can be targetted by\n";
+ std::cout << " specifying the gpu-number associated with the gpu of \n";
+ std::cout << " interest. This number can be determined by running\n";
+ std::cout << " vulkaninfo without any options specified.\n\n";
+}
+
+int main(int argc, char **argv) {
+#ifdef _WIN32
+ if (ConsoleIsExclusive()) ConsoleEnlarge();
+#endif
+
+ bool human_readable_output = true;
+ bool html_output = false;
+ bool json_output = false;
+ uint32_t selected_gpu = 0;
+ bool show_formats = false;
+
+ // Combinations of output: html only, html AND json, json only, human readable only
+ for (int i = 1; i < argc; ++i) {
+ if (strncmp("--json", argv[i], 6) == 0 || strcmp(argv[i], "-j") == 0) {
+ if (strlen(argv[i]) > 7 && strncmp("--json=", argv[i], 7) == 0) {
+ selected_gpu = strtol(argv[i] + 7, nullptr, 10);
+ }
+ human_readable_output = false;
+ json_output = true;
+ } else if (strcmp(argv[i], "--html") == 0) {
+ human_readable_output = false;
+ html_output = true;
+ } else if (strcmp(argv[i], "--show-formats") == 0) {
+ show_formats = true;
+ } else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
+ print_usage(argv[0]);
+ return 1;
+ } else {
+ print_usage(argv[0]);
+ return 1;
+ }
+ }
+
+ AppInstance instance = {};
+ SetupWindowExtensions(instance);
+
+ auto pNext_chains = get_chain_infos();
+
+ auto gpu_holder = FindGpus(instance, pNext_chains);
+
+ std::vector<AppGpu *> gpus;
+ for (auto &gpu : gpu_holder) {
+ gpus.push_back(gpu.get());
+ }
+
+ if (selected_gpu >= gpus.size()) {
+ selected_gpu = 0;
+ }
+
+ std::vector<std::unique_ptr<AppSurface>> surfaces_holder;
+#if defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || \
+ defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_WAYLAND_KHR)
+ for (auto &surface_extension : instance.surface_extensions) {
+ surface_extension.create_window(instance);
+ surface_extension.surface = surface_extension.create_surface(instance);
+ for (auto &gpu : gpus) {
+ surfaces_holder.push_back(
+ std::unique_ptr<AppSurface>(new AppSurface(instance, gpu, surface_extension, pNext_chains.surface_capabilities2)));
+ }
+ }
+
+ std::vector<AppSurface *> surfaces;
+ for (auto &surface : surfaces_holder) {
+ surfaces.push_back(surface.get());
+ }
+#endif
+
+ std::vector<std::unique_ptr<Printer>> printers;
+
+ std::streambuf *buf;
+ buf = std::cout.rdbuf();
+ std::ostream out(buf);
+ std::ofstream html_out;
+
+ if (human_readable_output) {
+ printers.push_back(std::unique_ptr<Printer>(new Printer(OutputType::text, out, selected_gpu, instance.vk_version)));
+ }
+ if (html_output) {
+ html_out = std::ofstream("vulkaninfo.html");
+ printers.push_back(std::unique_ptr<Printer>(new Printer(OutputType::html, html_out, selected_gpu, instance.vk_version)));
+ }
+ if (json_output) {
+ printers.push_back(std::unique_ptr<Printer>(new Printer(OutputType::json, out, selected_gpu, instance.vk_version)));
+ }
+
+ for (auto &p : printers) {
+ p->SetHeader();
+ DumpExtensions(*p.get(), "Instance", instance.global_extensions);
+ p->AddNewline();
+
+ DumpLayers(*p.get(), instance.global_layers, gpus);
+
+ if (p->Type() != OutputType::json) {
+#if defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || \
+ defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_WAYLAND_KHR)
+ DumpPresentableSurfaces(*p.get(), instance, gpus, surfaces);
+#endif
+ DumpGroups(*p.get(), instance);
+
+ p->SetHeader().ObjectStart("Device Properties and Extensions");
+ p->IndentDecrease();
+ }
+ for (auto &gpu : gpus) {
+ if ((p->Type() == OutputType::json && gpu->id == selected_gpu) || p->Type() == OutputType::text ||
+ p->Type() == OutputType::html) {
+ DumpGpu(*p.get(), *gpu, show_formats, pNext_chains);
+ }
+ }
+ if (p->Type() != OutputType::json) {
+ p->ObjectEnd();
+ p->IndentIncrease();
+ }
+ }
+
+#if defined(VK_USE_PLATFORM_XCB_KHR) || defined(VK_USE_PLATFORM_XLIB_KHR) || defined(VK_USE_PLATFORM_WIN32_KHR) || \
+ defined(VK_USE_PLATFORM_MACOS_MVK) || defined(VK_USE_PLATFORM_WAYLAND_KHR)
+
+ for (auto &surface_extension : instance.surface_extensions) {
+ AppDestroySurface(instance, surface_extension.surface);
+ surface_extension.destroy_window(instance);
+ }
+#endif
+
+ return 0;
+}