lsfg-vk/src/core/device.cpp
2025-07-01 08:21:41 +02:00

105 lines
3.8 KiB
C++

#include "core/device.hpp"
#include "lsfg.hpp"
#include <optional>
#include <vector>
using namespace LSFG::Core;
const std::vector<const char*> 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<VkPhysicalDevice> 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<VkPhysicalDevice> 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<VkQueueFamilyProperties> queueFamilies(familyCount);
vkGetPhysicalDeviceQueueFamilyProperties(*physicalDevice, &familyCount, queueFamilies.data());
std::optional<uint32_t> 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<uint32_t>(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<VkDevice>(
new VkDevice(deviceHandle),
[](VkDevice* device) {
vkDestroyDevice(*device, nullptr);
}
);
}