#include #include #include #include #include #include #include #include namespace { void check(VkResult result, const char* operation) { if (result != VK_SUCCESS) throw std::runtime_error(std::string(operation) + ": VkResult " + std::to_string(static_cast(result))); } template std::vector enumerate(Enumerate call) { // Enumeration can change between count and data calls. Bound retries. for (int attempt = 0; attempt != 8; ++attempt) { std::uint32_t count = 0; check(call(&count, static_cast(nullptr)), "enumeration count"); if (count > 65536) throw std::runtime_error("implausible enumeration count"); if (count == 0) return {}; std::vector values(count); const auto result = call(&count, values.data()); if (result == VK_INCOMPLETE) continue; check(result, "enumeration data"); values.resize(count); return values; } throw std::runtime_error("enumeration did not stabilize"); } struct Instance { VkInstance value = VK_NULL_HANDLE; explicit Instance(const VkInstanceCreateInfo& info) { check(vkCreateInstance(&info, nullptr, &value), "vkCreateInstance"); } ~Instance() { vkDestroyInstance(value, nullptr); } Instance(const Instance&) = delete; Instance& operator=(const Instance&) = delete; }; void version(std::uint32_t v) { std::cout << VK_API_VERSION_MAJOR(v) << '.' << VK_API_VERSION_MINOR(v) << '.' << VK_API_VERSION_PATCH(v); } } // namespace int main() try { std::uint32_t loader_version = VK_API_VERSION_1_0; const auto query_version = reinterpret_cast( vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkEnumerateInstanceVersion")); if (query_version) check(query_version(&loader_version), "loader version"); std::cout << "Loader API: "; version(loader_version); std::cout << '\n'; if (loader_version < VK_API_VERSION_1_3) throw std::runtime_error("this course probe requires a Vulkan 1.3 loader"); const auto layers = enumerate([](auto* n, auto* p) { return vkEnumerateInstanceLayerProperties(n, p); }); const char* validation = "VK_LAYER_KHRONOS_validation"; const bool have_validation = std::any_of(layers.begin(), layers.end(), [&](const auto& layer) { return std::strcmp(layer.layerName, validation) == 0; }); VkApplicationInfo app{}; app.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; app.pApplicationName = "Signal Garden capability report"; app.apiVersion = VK_API_VERSION_1_3; VkInstanceCreateInfo info{}; info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; info.pApplicationInfo = &app; info.enabledLayerCount = have_validation ? 1u : 0u; info.ppEnabledLayerNames = have_validation ? &validation : nullptr; Instance instance(info); std::cout << "Validation layer: " << (have_validation ? "enabled" : "absent") << '\n'; const auto devices = enumerate([&](auto* n, auto* p) { return vkEnumeratePhysicalDevices(instance.value, n, p); }); if (devices.empty()) throw std::runtime_error("no physical devices reported"); for (const auto device : devices) { VkPhysicalDeviceProperties properties{}; vkGetPhysicalDeviceProperties(device, &properties); std::cout << "\nDevice: " << properties.deviceName << "\nAPI: "; version(properties.apiVersion); std::cout << "\nvendorID: " << properties.vendorID << "\nminUniformBufferOffsetAlignment: " << properties.limits.minUniformBufferOffsetAlignment << "\nnonCoherentAtomSize: " << properties.limits.nonCoherentAtomSize << "\nmaxComputeWorkGroupInvocations: " << properties.limits.maxComputeWorkGroupInvocations << '\n'; if (properties.apiVersion >= VK_API_VERSION_1_3) { VkPhysicalDeviceVulkan13Features features13{}; features13.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES; VkPhysicalDeviceFeatures2 features{}; features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; features.pNext = &features13; vkGetPhysicalDeviceFeatures2(device, &features); std::cout << "synchronization2: " << features13.synchronization2 << "\ndynamicRendering: " << features13.dynamicRendering << '\n'; } else { std::cout << "Course Vulkan 1.3 feature query skipped: older device API\n"; } std::uint32_t queue_count = 0; vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_count, nullptr); std::vector queues(queue_count); vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_count, queues.data()); queues.resize(queue_count); for (std::size_t i = 0; i < queues.size(); ++i) std::cout << "queue family " << i << ": count=" << queues[i].queueCount << " flags=" << queues[i].queueFlags << '\n'; const auto extensions = enumerate([&](auto* n, auto* p) { return vkEnumerateDeviceExtensionProperties(device, nullptr, n, p); }); const bool swapchain = std::any_of(extensions.begin(), extensions.end(), [](const auto& extension) { return std::strcmp(extension.extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0; }); std::cout << "VK_KHR_swapchain: " << swapchain << '\n'; } std::cout << "\nNo surface created: presentation support is NOT established.\n" "No logical device created: queried features are NOT enabled.\n"; return 0; } catch (const std::exception& error) { std::cerr << "Signal Garden: " << error.what() << '\n'; return 1; }