/* This file is part of Magnum. Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 Vladimír Vondruš Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include "Magnum/Vk/Extensions.h" #include "Magnum/Vk/ExtensionProperties.h" #include "Magnum/Vk/InstanceCreateInfo.h" #include "Magnum/Vk/LayerProperties.h" #include "Magnum/Vk/Memory.h" #include "Magnum/Vk/DeviceProperties.h" #include "Magnum/Vk/Version.h" namespace Magnum { /** @page magnum-vk-info Magnum Vulkan Info @brief Displays information about Magnum engine Vulkan capabilities @m_since_latest @m_footernavigation @m_keywords{magnum-vk-info vk-info} This utility is built if both `WITH_VK` and `WITH_VK_INFO` is enabled when building Magnum. To use this utility with CMake, you need to request the `vk-info` component of the `Magnum` package and use the `Magnum::vk-info` target for example in a custom command: @code{.cmake} find_package(Magnum REQUIRED vk-info) add_custom_command(OUTPUT ... COMMAND Magnum::vk-info ...) @endcode See @ref building, @ref cmake and the @ref Vk namespace for more information. */ } using namespace Magnum; int main(int argc, char** argv) { Utility::Arguments args; args.addBooleanOption("extension-strings").setHelp("extension-strings", "list all extension strings provided by the driver") .addBooleanOption("all-extensions").setHelp("all-extensions", "display extensions also for fully supported versions") .addSkippedPrefix("magnum", "engine-specific options") .setGlobalHelp("Displays information about Magnum engine and Vulkan capabilities.") .parse(argc, argv); /* Setup InstanceCreateInfo before printing anything so --magnum-help has uncluttered output */ /** @todo add a NoCreate InstanceInfo that just populates internal state without querying vulkan for anything? or that's stupid? */ Vk::LayerProperties layerProperties = Vk::enumerateLayerProperties(); Vk::InstanceExtensionProperties instanceExtensionProperties = Vk::enumerateInstanceExtensionProperties({layerProperties.names()}); Vk::InstanceCreateInfo instanceCreateInfo{argc, argv, &layerProperties, &instanceExtensionProperties}; Debug{} << ""; Debug{} << " +---------------------------------------------------------+"; Debug{} << " | Information about Magnum engine Vulkan capabilities |"; Debug{} << " +---------------------------------------------------------+"; Debug{} << ""; Debug{} << "Compilation flags:"; #ifdef CORRADE_BUILD_DEPRECATED Debug{} << " CORRADE_BUILD_DEPRECATED"; #endif #ifdef CORRADE_BUILD_STATIC Debug{} << " CORRADE_BUILD_STATIC"; #endif #ifdef CORRADE_BUILD_MULTITHREADED Debug{} << " CORRADE_BUILD_MULTITHREADED"; #endif #ifdef CORRADE_TARGET_UNIX Debug{} << " CORRADE_TARGET_UNIX"; #endif #ifdef CORRADE_TARGET_APPLE Debug{} << " CORRADE_TARGET_APPLE"; #endif #ifdef CORRADE_TARGET_IOS Debug{} << " CORRADE_TARGET_IOS"; #endif #ifdef CORRADE_TARGET_WINDOWS Debug{} << " CORRADE_TARGET_WINDOWS"; #endif #ifdef CORRADE_TARGET_WINDOWS_RT Debug{} << " CORRADE_TARGET_WINDOWS_RT"; #endif #ifdef CORRADE_TARGET_ANDROID Debug{} << " CORRADE_TARGET_ANDROID"; #endif #ifdef CORRADE_TARGET_X86 Debug{} << " CORRADE_TARGET_X86"; #endif #ifdef CORRADE_TARGET_ARM Debug{} << " CORRADE_TARGET_ARM"; #endif #ifdef CORRADE_TARGET_POWERPC Debug{} << " CORRADE_TARGET_POWERPC"; #endif #ifdef CORRADE_TARGET_BIG_ENDIAN Debug{} << " CORRADE_TARGET_BIG_ENDIAN"; #endif #ifdef CORRADE_TARGET_GCC Debug{} << " CORRADE_TARGET_GCC"; #endif #ifdef CORRADE_TARGET_CLANG Debug{} << " CORRADE_TARGET_CLANG"; #endif #ifdef CORRADE_TARGET_APPLE_CLANG Debug{} << " CORRADE_TARGET_APPLE_CLANG"; #endif #ifdef CORRADE_TARGET_CLANG_CL Debug{} << " CORRADE_TARGET_CLANG_CL"; #endif #ifdef CORRADE_TARGET_MSVC Debug{} << " CORRADE_TARGET_MSVC"; #endif #ifdef CORRADE_TARGET_MINGW Debug{} << " CORRADE_TARGET_MINGW"; #endif #ifdef CORRADE_TARGET_LIBCXX Debug{} << " CORRADE_TARGET_LIBCXX"; #endif #ifdef CORRADE_TARGET_LIBSTDCXX Debug{} << " CORRADE_TARGET_LIBSTDCXX"; #endif #ifdef CORRADE_TARGET_DINKUMWARE Debug{} << " CORRADE_TARGET_DINKUMWARE"; #endif #ifdef CORRADE_TARGET_SSE2 Debug{} << " CORRADE_TARGET_SSE2"; #endif #ifdef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT Debug{} << " CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT"; #endif #ifdef CORRADE_TESTSUITE_TARGET_XCTEST Debug{} << " CORRADE_TESTSUITE_TARGET_XCTEST"; #endif #ifdef CORRADE_UTILITY_USE_ANSI_COLORS Debug{} << " CORRADE_UTILITY_USE_ANSI_COLORS"; #endif #ifdef MAGNUM_BUILD_DEPRECATED Debug{} << " MAGNUM_BUILD_DEPRECATED"; #endif #ifdef MAGNUM_BUILD_STATIC Debug{} << " MAGNUM_BUILD_STATIC"; #endif Debug{} << ""; const Vk::Version instanceVersion = Vk::enumerateInstanceVersion(); Debug{} << "Reported instance version:" << instanceVersion; Debug{} << "Reported instance layers:"; for(UnsignedInt i = 0, max = layerProperties.count(); i != max; ++i) { Debug{} << " " << layerProperties.name(i) << "(r" << Debug::nospace << layerProperties.revision(i) << Debug::nospace << ", written against" << layerProperties.version(i) << Debug::nospace << ")"; Debug{} << " " << layerProperties.description(i); } constexpr Vk::Version versions[]{ Vk::Version::Vk11, Vk::Version::Vk12, Vk::Version::None }; std::size_t instanceFuture = 0; if(!args.isSet("all-extensions")) while(versions[instanceFuture] != Vk::Version::None && instanceVersion >= versions[instanceFuture]) ++instanceFuture; /** @todo do better once implemented in format() */ using namespace Containers::Literals; constexpr Containers::StringView sixtyfourSpaces = " "_s; if(args.isSet("extension-strings")) { Debug{} << "Reported instance extension strings:"; for(std::size_t i = 0, max = instanceExtensionProperties.count(); i != max; ++i) { Debug d; d << " " << instanceExtensionProperties.name(i) << "(r" << Debug::nospace << instanceExtensionProperties.revision(i) << Debug::nospace; const UnsignedInt layer = instanceExtensionProperties.layer(i); if(layer != 0) d << ", from" << layerProperties.names()[layer - 1] << Debug::nospace; d << ")"; } } else for(std::size_t i = instanceFuture; i != Containers::arraySize(versions); ++i) { Containers::ArrayView extensions = Vk::InstanceExtension::extensions(versions[i]); if(extensions.empty()) continue; if(versions[i] != Vk::Version::None) Debug{} << versions[i] << "instance extension support:"; else Debug{} << "Vendor instance extension support:"; for(const Vk::InstanceExtension& extension: extensions) { Debug d; d << " " << extension.string() << sixtyfourSpaces.prefix(64 - extension.string().size()); if(instanceExtensionProperties.isSupported(extension)) d << "REV." << Debug::nospace << instanceExtensionProperties.revision(extension); else if(instanceVersion >= extension.requiredVersion()) d << " -"; else d << " n/a"; } } Debug{} << ""; Vk::Instance instance{instanceCreateInfo}; { Containers::Array devices = Vk::enumerateDevices(instance); Debug{} << "Found" << devices.size() << "devices:"; for(Vk::DeviceProperties& device: devices) { Debug{} << " " << device.name() << Debug::nospace << "," << device.version() << Debug::newline << " " << device.type() << Debug::nospace << ", driver" << Debug::packed << device.driverVersion(); } if(devices.empty()) return 0; } Debug{} << ""; Vk::DeviceProperties device = Vk::pickDevice(instance); Debug{} << "Picked device" << device.name() << Debug::newline; const Vk::Version deviceVersion = device.version(); Debug{} << "Reported version:" << deviceVersion; /* Driver info. Print only if the device actually reports something, otherwise assume VK_KHR_driver_properties are not supported. Due to the mess that's VK_KHR_get_physical_device_properties2 and the interactions between instance and driver version it's not possible to easily check for extension presence. */ if(Int(device.driver())) { Debug{} << "Driver:" << device.driverName() << "(" << Debug::nospace << device.driver() << Debug::nospace << ")"; Debug{} << "Driver info:" << device.driverInfo() << "(version" << Debug::packed << device.driverVersion() << Debug::nospace << ")"; /* Otherwise just print an Unknown placeholder, indicating the extension is not supported */ } else Debug{} << "Driver:" << device.driver(); std::size_t deviceFuture = 0; if(!args.isSet("all-extensions")) while(versions[deviceFuture] != Vk::Version::None && deviceVersion >= versions[deviceFuture]) ++deviceFuture; Vk::ExtensionProperties extensionProperties = device.enumerateExtensionProperties(layerProperties.names()); if(args.isSet("extension-strings")) { Debug{} << "Reported extension strings:"; for(std::size_t i = 0, max = extensionProperties.count(); i != max; ++i) { Debug d; d << " " << extensionProperties.name(i) << "(r" << Debug::nospace << extensionProperties.revision(i) << Debug::nospace; const UnsignedInt layer = extensionProperties.layer(i); if(layer != 0) d << ", from" << layerProperties.names()[layer - 1] << Debug::nospace; d << ")"; } } else for(std::size_t i = deviceFuture; i != Containers::arraySize(versions); ++i) { Containers::ArrayView extensions = Vk::Extension::extensions(versions[i]); if(extensions.empty()) continue; if(versions[i] != Vk::Version::None) Debug{} << versions[i] << "extension support:"; else Debug{} << "Vendor extension support:"; for(const Vk::Extension& extension: extensions) { Debug d; d << " " << extension.string() << sixtyfourSpaces.prefix(64 - extension.string().size()); if(extensionProperties.isSupported(extension)) d << "REV." << Debug::nospace << extensionProperties.revision(extension); else if(deviceVersion >= extension.requiredVersion()) d << " -"; else d << " n/a"; } } /* If we wanted only extension strings, exit now */ if(args.isSet("extension-strings")) return 0; Debug{} << "Queue families:"; for(UnsignedInt i = 0; i != device.queueFamilyCount(); ++i) { Debug{} << " " << i << Debug::nospace << ":" << device.queueFamilyFlags(i); Debug{} << " " << device.queueFamilySize(i) << "queues"; } Debug{} << "Memory heaps:"; for(UnsignedInt i = 0; i != device.memoryHeapCount(); ++i) { Debug{} << " " << i << Debug::nospace << ":" << device.memoryHeapFlags(i); Debug{} << " size:" << device.memoryHeapSize(i)/1024/1024 << "MB"; } Debug{} << "Memory types:"; for(UnsignedInt i = 0; i != device.memoryCount(); ++i) { Debug{} << " " << i << Debug::nospace << ":" << device.memoryFlags(i); Debug{} << " heap index:" << device.memoryHeapIndex(i); } }