diff --git a/include/xdg/gprt/vulkan_probe.h b/include/xdg/gprt/vulkan_probe.h new file mode 100644 index 00000000..8e0ff9cf --- /dev/null +++ b/include/xdg/gprt/vulkan_probe.h @@ -0,0 +1,94 @@ +#pragma once + +#ifdef XDG_ENABLE_GPRT +#include "xdg/error.h" + +#include +#include +#include +#include + +inline std::vector +get_vk_device_extensions(VkPhysicalDevice device) +{ + uint32_t count = 0; + if (vkEnumerateDeviceExtensionProperties(device, nullptr, &count, nullptr) != VK_SUCCESS) + return {}; + + std::vector extensions(count); + if (vkEnumerateDeviceExtensionProperties(device, nullptr, &count, extensions.data()) != VK_SUCCESS) + return {}; + + return extensions; +} + +inline bool check_if_extension_available(const std::vector& extensions, const char* name) +{ + for (const auto& extension : extensions) { + if (std::strcmp(extension.extensionName, name) == 0) return true; + } + return false; +} + +inline bool system_has_vk_device() +{ + VkApplicationInfo app{ VK_STRUCTURE_TYPE_APPLICATION_INFO }; + app.pApplicationName = "vk-probe"; + app.applicationVersion = 1; + app.pEngineName = "probe"; + app.engineVersion = 1; + app.apiVersion = VK_API_VERSION_1_1; + + VkInstanceCreateInfo ici{ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO }; + ici.pApplicationInfo = &app; + + VkInstance instance = VK_NULL_HANDLE; + if (vkCreateInstance(&ici, nullptr, &instance) != VK_SUCCESS || !instance) { + warning("Could not create Vulkan instance; GPRT ray tracer unavailable."); + return false; + } + + uint32_t devCount = 0; + if (vkEnumeratePhysicalDevices(instance, &devCount, nullptr) != VK_SUCCESS || devCount == 0) { + vkDestroyInstance(instance, nullptr); + warning("No Vulkan physical devices found; GPRT ray tracer unavailable."); + return false; + } + + std::vector devices(devCount); + if (vkEnumeratePhysicalDevices(instance, &devCount, devices.data()) != VK_SUCCESS) { + vkDestroyInstance(instance, nullptr); + warning("Could not enumerate Vulkan physical devices; GPRT ray tracer unavailable."); + return false; + } + + std::string missing; + for (auto device : devices) { + auto extensions = get_vk_device_extensions(device); + bool accel_ext = check_if_extension_available(extensions, VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME); + bool rt_pipeline_ext = check_if_extension_available(extensions, VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME); + + // these are the two main extensions we need for GPRT so if both are present we can stop checking other devices + if (accel_ext && rt_pipeline_ext) { + VkPhysicalDeviceProperties properties{}; + vkGetPhysicalDeviceProperties(device, &properties); + write_message("Found Vulkan ray tracing capable device '{}'.", properties.deviceName); + vkDestroyInstance(instance, nullptr); + return true; + } + + missing.clear(); + if (!accel_ext) missing += VK_KHR_ACCELERATION_STRUCTURE_EXTENSION_NAME; + if (!rt_pipeline_ext) { + if (!missing.empty()) missing += ", "; + missing += VK_KHR_RAY_TRACING_PIPELINE_EXTENSION_NAME; + } + } + + vkDestroyInstance(instance, nullptr); + warning("No Vulkan device with the required GPRT extensions found. Missing extensions: " + + missing); + return false; +} + +#endif diff --git a/src/gprt/ray_tracer.cpp b/src/gprt/ray_tracer.cpp index d1c169f8..15d21a7b 100644 --- a/src/gprt/ray_tracer.cpp +++ b/src/gprt/ray_tracer.cpp @@ -1,10 +1,15 @@ #include "xdg/gprt/ray_tracer.h" #include "gprt/gprt.h" +#include "xdg/gprt/vulkan_probe.h" namespace xdg { GPRTRayTracer::GPRTRayTracer() { + if (!system_has_vk_device()) { + fatal_error("No Vulkan ray tracing capable device found; cannot initialize GPRT ray tracer."); + } + gprtRequestRayTypeCount(numRayTypes_); // Set the number of shaders which can be set to the same geometry context_ = gprtContextCreate(); module_ = gprtModuleCreate(context_, dbl_deviceCode); diff --git a/tests/util.h b/tests/util.h index f6f6c8ea..a9841086 100644 --- a/tests/util.h +++ b/tests/util.h @@ -1,4 +1,5 @@ #include +#include #include #include @@ -7,7 +8,7 @@ #include "xdg/constants.h" #include "xdg/ray_tracers.h" #include "xdg/mesh_managers.h" -#include "vulkan_probe.h" +#include "xdg/gprt/vulkan_probe.h" namespace xdg::test { diff --git a/tests/vulkan_probe.h b/tests/vulkan_probe.h deleted file mode 100644 index cfc6ff44..00000000 --- a/tests/vulkan_probe.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#ifdef XDG_ENABLE_GPRT -#include -#include - -inline bool system_has_vk_device(uint32_t min_instance = VK_API_VERSION_1_1) { - uint32_t loaderVer = VK_API_VERSION_1_0; - vkEnumerateInstanceVersion(&loaderVer); - - // Create VK instance - VkApplicationInfo app{ VK_STRUCTURE_TYPE_APPLICATION_INFO }; - app.pApplicationName = "vk-probe"; - app.applicationVersion = 1; - app.pEngineName = "probe"; - app.engineVersion = 1; - app.apiVersion = VK_API_VERSION_1_0; - - VkInstanceCreateInfo ici{ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO }; - ici.pApplicationInfo = &app; - - VkInstance instance = VK_NULL_HANDLE; - if (vkCreateInstance(&ici, nullptr, &instance) != VK_SUCCESS || !instance) - return false; - - // Look for at least one physical device - uint32_t devCount = 0; - VkResult r = vkEnumeratePhysicalDevices(instance, &devCount, nullptr); - - // Clean up the instance before returning - vkDestroyInstance(instance, nullptr); - - // Check for errors and non-zero device count - if (r != VK_SUCCESS || devCount == 0) { - return false; - } - - return true; // VK device detected -} - -#endif