aboutsummaryrefslogtreecommitdiff
path: root/vulkaninfo/vulkaninfo.cpp
diff options
context:
space:
mode:
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;
+}