#include "core/device.hpp" #include "lsfg.hpp" #include #include using namespace LSFG::Core; const std::vector requiredExtensions = { "VK_KHR_external_memory_fd", "VK_EXT_robustness2", }; Device::Device(const Instance& instance) { // get all physical devices uint32_t deviceCount{}; auto res = vkEnumeratePhysicalDevices(instance.handle(), &deviceCount, nullptr); if (res != VK_SUCCESS || deviceCount == 0) throw LSFG::vulkan_error(res, "Failed to enumerate physical devices"); std::vector devices(deviceCount); res = vkEnumeratePhysicalDevices(instance.handle(), &deviceCount, devices.data()); if (res != VK_SUCCESS) throw LSFG::vulkan_error(res, "Failed to get physical devices"); // find first discrete GPU std::optional physicalDevice; for (const auto& device : devices) { VkPhysicalDeviceProperties properties; vkGetPhysicalDeviceProperties(device, &properties); if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) { physicalDevice = device; break; } } if (!physicalDevice) throw LSFG::vulkan_error(VK_ERROR_INITIALIZATION_FAILED, "No discrete GPU found"); // find queue family indices uint32_t familyCount{}; vkGetPhysicalDeviceQueueFamilyProperties(*physicalDevice, &familyCount, nullptr); std::vector queueFamilies(familyCount); vkGetPhysicalDeviceQueueFamilyProperties(*physicalDevice, &familyCount, queueFamilies.data()); std::optional computeFamilyIdx; for (uint32_t i = 0; i < familyCount; ++i) { if (queueFamilies[i].queueFlags & VK_QUEUE_COMPUTE_BIT) computeFamilyIdx = i; } if (!computeFamilyIdx) throw LSFG::vulkan_error(VK_ERROR_INITIALIZATION_FAILED, "No compute queue family found"); // create logical device const float queuePriority{1.0F}; // highest priority VkPhysicalDeviceRobustness2FeaturesEXT robustness2{ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT, .nullDescriptor = VK_TRUE, }; VkPhysicalDeviceVulkan13Features features13{ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, .pNext = &robustness2, .synchronization2 = VK_TRUE }; const VkPhysicalDeviceVulkan12Features features12{ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, .pNext = &features13, .timelineSemaphore = VK_TRUE, .vulkanMemoryModel = VK_TRUE }; const VkDeviceQueueCreateInfo computeQueueDesc{ .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, .queueFamilyIndex = *computeFamilyIdx, .queueCount = 1, .pQueuePriorities = &queuePriority }; const VkDeviceCreateInfo deviceCreateInfo{ .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .pNext = &features12, .queueCreateInfoCount = 1, .pQueueCreateInfos = &computeQueueDesc, .enabledExtensionCount = static_cast(requiredExtensions.size()), .ppEnabledExtensionNames = requiredExtensions.data() }; VkDevice deviceHandle{}; res = vkCreateDevice(*physicalDevice, &deviceCreateInfo, nullptr, &deviceHandle); if (res != VK_SUCCESS | deviceHandle == VK_NULL_HANDLE) throw LSFG::vulkan_error(res, "Failed to create logical device"); // get compute queue VkQueue queueHandle{}; vkGetDeviceQueue(deviceHandle, *computeFamilyIdx, 0, &queueHandle); // store in shared ptr this->computeQueue = queueHandle; this->computeFamilyIdx = *computeFamilyIdx; this->physicalDevice = *physicalDevice; this->device = std::shared_ptr( new VkDevice(deviceHandle), [](VkDevice* device) { vkDestroyDevice(*device, nullptr); } ); }