Add RenderDriver::create_device()
This commit is contained in:
@@ -21,5 +21,6 @@ namespace Nova {
|
||||
|
||||
[[nodiscard]] virtual u32 get_device_count() const = 0;
|
||||
[[nodiscard]] virtual const RenderDevice& get_device(u32 index) const = 0;
|
||||
virtual void create_device(u32 index) = 0;
|
||||
};
|
||||
} // namespace Nova
|
||||
|
||||
@@ -25,12 +25,17 @@ VulkanRenderDriver::VulkanRenderDriver() {
|
||||
_check_extensions();
|
||||
_check_layers();
|
||||
_init_instance();
|
||||
_init_devices();
|
||||
_init_hardware();
|
||||
}
|
||||
|
||||
VulkanRenderDriver::~VulkanRenderDriver() {
|
||||
NOVA_AUTO_TRACE();
|
||||
if (m_device) {
|
||||
vkDestroyDevice(m_device, _get_allocator(VK_OBJECT_TYPE_DEVICE));
|
||||
}
|
||||
if (m_instance) {
|
||||
vkDestroyInstance(m_instance, _get_allocator(VK_OBJECT_TYPE_INSTANCE));
|
||||
}
|
||||
}
|
||||
|
||||
RenderAPI VulkanRenderDriver::get_api() const {
|
||||
@@ -51,6 +56,24 @@ const RenderDevice& VulkanRenderDriver::get_device(const u32 index) const {
|
||||
return m_devices[index];
|
||||
}
|
||||
|
||||
void VulkanRenderDriver::create_device(const u32 index) {
|
||||
NOVA_AUTO_TRACE();
|
||||
|
||||
if (m_device) {
|
||||
NOVA_ERROR("VkDevice already created");
|
||||
return;
|
||||
}
|
||||
|
||||
m_physical_device = static_cast<VkPhysicalDevice>(m_devices[index].handle);
|
||||
std::vector<VkDeviceQueueCreateInfo> queues;
|
||||
|
||||
_check_device_extensions();
|
||||
_check_device_features();
|
||||
// TODO: Check device capabilities
|
||||
_init_queues(queues);
|
||||
_init_device(queues);
|
||||
}
|
||||
|
||||
void VulkanRenderDriver::_check_version() const {
|
||||
NOVA_AUTO_TRACE();
|
||||
|
||||
@@ -169,7 +192,7 @@ void VulkanRenderDriver::_init_instance() {
|
||||
NOVA_LOG("VkInstance created");
|
||||
}
|
||||
|
||||
void VulkanRenderDriver::_init_devices() {
|
||||
void VulkanRenderDriver::_init_hardware() {
|
||||
NOVA_AUTO_TRACE();
|
||||
|
||||
u32 count;
|
||||
@@ -189,9 +212,114 @@ void VulkanRenderDriver::_init_devices() {
|
||||
m_devices.back().type = static_cast<RenderDevice::Type>(properties.deviceType);
|
||||
m_devices.back().deviceID = properties.deviceID;
|
||||
m_devices.back().handle = device;
|
||||
|
||||
NOVA_LOG("Found device: {}", properties.deviceName);
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanRenderDriver::_check_device_extensions() {
|
||||
NOVA_AUTO_TRACE();
|
||||
|
||||
std::unordered_map<std::string_view, bool> requested; // <extension, required>
|
||||
requested[VK_KHR_SWAPCHAIN_EXTENSION_NAME] = true;
|
||||
// TODO: Add other device extensions
|
||||
|
||||
// Get available extensions
|
||||
u32 count;
|
||||
vkEnumerateDeviceExtensionProperties(m_physical_device, nullptr, &count, nullptr); // TODO: Check result
|
||||
std::vector<VkExtensionProperties> available(count);
|
||||
vkEnumerateDeviceExtensionProperties(m_physical_device, nullptr, &count, available.data()); // TODO: Check result
|
||||
|
||||
// Check found extensions
|
||||
for (const auto& extension : available) {
|
||||
if (auto it = requested.find(extension.extensionName); it != requested.end()) {
|
||||
NOVA_LOG("Using device extension: {}", extension.extensionName);
|
||||
m_device_extensions.push_back(it->first.data());
|
||||
requested.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
// Check remaining extensions
|
||||
bool error = false;
|
||||
for (auto [name, required] : requested) {
|
||||
if (required) {
|
||||
NOVA_ERROR("Required device extension not found: {}", name);
|
||||
error = true;
|
||||
} else {
|
||||
NOVA_WARN("Optional device extension not found: {}", name);
|
||||
}
|
||||
}
|
||||
if (error) {
|
||||
throw std::runtime_error("Failed to find required device extensions");
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanRenderDriver::_check_device_features() {
|
||||
NOVA_AUTO_TRACE();
|
||||
|
||||
vkGetPhysicalDeviceFeatures(m_physical_device, &m_features);
|
||||
// TODO: Check required features
|
||||
// TODO: Disable unwanted features
|
||||
|
||||
NOVA_WARN("{}() not implemented", NOVA_FUNC_NAME);
|
||||
}
|
||||
|
||||
void VulkanRenderDriver::_init_queues(std::vector<VkDeviceQueueCreateInfo>& queues) const {
|
||||
NOVA_AUTO_TRACE();
|
||||
|
||||
u32 count;
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(m_physical_device, &count, nullptr);
|
||||
std::vector<VkQueueFamilyProperties> available(count);
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(m_physical_device, &count, available.data());
|
||||
|
||||
constexpr VkQueueFlags mask = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT;
|
||||
static float priority = 1.0f;
|
||||
VkQueueFlags found = 0;
|
||||
|
||||
for (u32 i = 0; i < count; i++) {
|
||||
if ((available[i].queueFlags & mask) == 0) {
|
||||
continue;
|
||||
}
|
||||
if (!available[i].queueCount) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NOVA_LOG("Using queue family: {}", i);
|
||||
found |= available[i].queueFlags;
|
||||
|
||||
queues.emplace_back();
|
||||
queues.back().sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queues.back().queueFamilyIndex = i;
|
||||
queues.back().queueCount = 1; // TODO: Does it make sense to have more than one queue?
|
||||
queues.back().pQueuePriorities = &priority;
|
||||
}
|
||||
|
||||
if ((found & mask) != mask) {
|
||||
throw std::runtime_error("Failed to find required queue family");
|
||||
}
|
||||
}
|
||||
|
||||
void VulkanRenderDriver::_init_device(const std::vector<VkDeviceQueueCreateInfo>& queues) {
|
||||
NOVA_AUTO_TRACE();
|
||||
|
||||
VkDeviceCreateInfo create {};
|
||||
create.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
create.enabledLayerCount = m_layers.size();
|
||||
create.ppEnabledLayerNames = m_layers.data();
|
||||
create.enabledExtensionCount = m_device_extensions.size();
|
||||
create.ppEnabledExtensionNames = m_device_extensions.data();
|
||||
create.queueCreateInfoCount = queues.size();
|
||||
create.pQueueCreateInfos = queues.data();
|
||||
create.pEnabledFeatures = &m_features;
|
||||
// TODO: pNext for additional features
|
||||
|
||||
if (vkCreateDevice(m_physical_device, &create, _get_allocator(VK_OBJECT_TYPE_DEVICE), &m_device) != VK_SUCCESS) {
|
||||
throw std::runtime_error("Failed to create VkDevice");
|
||||
}
|
||||
|
||||
NOVA_LOG("VkDevice created");
|
||||
}
|
||||
|
||||
VkAllocationCallbacks* VulkanRenderDriver::_get_allocator(const VkObjectType type) {
|
||||
// TODO: Add custom allocator
|
||||
(void)type;
|
||||
|
||||
@@ -22,19 +22,30 @@ namespace Nova {
|
||||
|
||||
[[nodiscard]] u32 get_device_count() const override;
|
||||
[[nodiscard]] const RenderDevice& get_device(u32 index) const override;
|
||||
void create_device(u32 index) override;
|
||||
|
||||
private:
|
||||
VkInstance m_instance = VK_NULL_HANDLE;
|
||||
VkPhysicalDevice m_physical_device = VK_NULL_HANDLE;
|
||||
VkDevice m_device = VK_NULL_HANDLE;
|
||||
VkPhysicalDeviceFeatures m_features = {};
|
||||
|
||||
std::vector<const char*> m_extensions;
|
||||
std::vector<const char*> m_layers;
|
||||
std::vector<const char*> m_device_extensions;
|
||||
std::vector<RenderDevice> m_devices;
|
||||
|
||||
void _check_version() const;
|
||||
void _check_extensions();
|
||||
void _check_layers();
|
||||
void _init_instance();
|
||||
void _init_devices();
|
||||
void _init_hardware();
|
||||
|
||||
// TODO: Other init functions for device
|
||||
void _check_device_extensions();
|
||||
void _check_device_features();
|
||||
void _init_queues(std::vector<VkDeviceQueueCreateInfo>& queues) const;
|
||||
void _init_device(const std::vector<VkDeviceQueueCreateInfo>& queues);
|
||||
|
||||
static VkAllocationCallbacks* _get_allocator(VkObjectType type);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user