light/modules/renderer/private/vk/context/device.cpp

156 lines
4.2 KiB
C++

#include <renderer/vk/context/device.hpp>
#include <renderer/vk/context/instance.hpp>
#include <renderer/vk/context/surface.hpp>
#include <renderer/vk/debug/validation.hpp>
namespace lt::renderer::vk {
Device::Device(const Surface &surface)
{
ensure(surface.vk(), "Failed to initialize vk::Device: null vulkan surface");
initialize_physical_device();
initialize_logical_device();
Instance::load_device_functions(m_device);
initialize_queue(surface);
}
Device::~Device()
{
if (m_device)
{
vkc(vk_device_wait_idle(m_device));
vk_destroy_device(m_device, nullptr);
}
}
void Device::initialize_physical_device()
{
auto count = 0u;
vkc(vk_enumerate_physical_devices(Instance::get(), &count, nullptr));
ensure(count != 0u, "Failed to find any physical devices with Vulkan support");
auto devices = std::vector<VkPhysicalDevice>(count);
vkc(vk_enumerate_physical_devices(Instance::get(), &count, devices.data()));
for (auto &device : devices)
{
auto properties = VkPhysicalDeviceProperties {};
auto features = VkPhysicalDeviceFeatures {};
vk_get_physical_device_properties(device, &properties);
vk_get_physical_device_features(device, &features);
if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
&& features.geometryShader)
{
m_physical_device = device;
}
}
ensure(m_physical_device, "Failed to find any suitable Vulkan physical device");
}
void Device::initialize_logical_device()
{
const float priorities = .0f;
auto queue_info = VkDeviceQueueCreateInfo {
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
.queueFamilyIndex = find_suitable_queue_family(),
.queueCount = 1u,
.pQueuePriorities = &priorities,
};
auto physical_device_features = VkPhysicalDeviceFeatures {};
auto extensions = std::vector<const char *> {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
};
auto device_info = VkDeviceCreateInfo {
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
.queueCreateInfoCount = 1,
.pQueueCreateInfos = &queue_info,
.enabledExtensionCount = static_cast<uint32_t>(extensions.size()),
.ppEnabledExtensionNames = extensions.data(),
.pEnabledFeatures = &physical_device_features,
};
ensure(
!vk_create_device(m_physical_device, &device_info, nullptr, &m_device),
"Failed to create logical vulkan device"
);
}
[[nodiscard]] auto Device::find_suitable_queue_family() const -> uint32_t
{
auto count = 0u;
vk_get_physical_device_queue_family_properties(m_physical_device, &count, nullptr);
ensure(count != 0u, "Failed to find any physical devices with Vulkan support");
auto families = std::vector<VkQueueFamilyProperties>(count);
vk_get_physical_device_queue_family_properties(m_physical_device, &count, families.data());
const auto required_flags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
for (auto idx = 0u; auto &family : families)
{
if ((family.queueFlags & required_flags) == required_flags)
{
return idx;
}
}
ensure(false, "Failed to find a suitable Vulkan queue family");
return 0;
}
void Device::initialize_queue(const Surface &surface)
{
vk_get_device_queue(m_device, find_suitable_queue_family(), 0, &m_queue);
auto count = uint32_t { 0u };
vk_get_physical_device_queue_family_properties(m_physical_device, &count, nullptr);
auto properties = std::vector<VkQueueFamilyProperties>(count);
vk_get_physical_device_queue_family_properties(m_physical_device, &count, properties.data());
for (auto idx = uint32_t { 0u }; const auto &property : properties)
{
if (property.queueFlags & VK_QUEUE_GRAPHICS_BIT)
{
m_graphics_queue_family_index = idx;
}
auto has_presentation_support = VkBool32 { false };
vkc(vk_get_physical_device_surface_support(
m_physical_device,
idx,
surface.vk(),
&has_presentation_support
));
if (has_presentation_support)
{
m_present_queue_family_index = idx;
}
++idx;
if (m_graphics_queue_family_index != VK_QUEUE_FAMILY_IGNORED
&& m_present_queue_family_index != VK_QUEUE_FAMILY_IGNORED)
{
break;
}
}
ensure(
m_graphics_queue_family_index != VK_QUEUE_FAMILY_IGNORED,
"Failed to find graphics queue family"
);
ensure(
m_present_queue_family_index != VK_QUEUE_FAMILY_IGNORED,
"Failed to find presentation queue family"
);
}
} // namespace lt::renderer::vk