Add proper queue init and fetch functionality to RenderDriver

This commit is contained in:
2025-05-04 02:54:06 +10:00
parent 7039fdf93e
commit 49a0a4b78a
4 changed files with 99 additions and 18 deletions

View File

@@ -30,7 +30,9 @@ namespace Nova {
[[nodiscard]] virtual bool get_device_supports_surface(u32 index, SurfaceID surface) const = 0;
virtual void select_device(u32 index) = 0;
[[nodiscard]] virtual QueueID get_queue() = 0;
[[nodiscard]] virtual u32 choose_queue_family(QueueType type, SurfaceID surface) = 0;
[[nodiscard]] virtual QueueID get_queue(u32 queue_family) = 0;
virtual void free_queue(QueueID queue) = 0;
[[nodiscard]] virtual SurfaceID create_surface(WindowID window) = 0;
virtual void destroy_surface(SurfaceID surface) = 0;

View File

@@ -12,6 +12,7 @@ namespace Nova {
enum class InputRate { VERTEX, INSTANCE };
enum class PipelineType { GRAPHICS, COMPUTE };
enum class PrimitiveTopology { POINT_LIST, LINE_LIST, LINE_STRIP, TRIANGLE_LIST, TRIANGLE_STRIP };
enum class QueueType { UNDEFINED, GRAPHICS, COMPUTE, TRANSFER };
enum class RenderAPI { DX12, VULKAN };
enum class ShaderStage { VERTEX, FRAGMENT, GEOMETRY, TESS_CONTROL, TESS_EVAL, COMPUTE, MESH, TASK };

View File

@@ -16,11 +16,12 @@
#include <vulkan/vulkan.h>
#include <algorithm>
#include <bit>
#include <format>
#include <limits>
#include <unordered_map>
#define VALIDATION_LAYER "VK_LAYER_KHRONOS_validation"
#define MAX_QUEUES_PER_FAMILY 2U
using namespace Nova;
@@ -61,6 +62,13 @@ static constexpr VkVertexInputRate VK_VERTEX_INPUT_RATE_MAP[] = {
VK_VERTEX_INPUT_RATE_INSTANCE
};
static constexpr VkQueueFlagBits VK_QUEUE_FLAGS_MAP[] = {
static_cast<VkQueueFlagBits>(0),
VK_QUEUE_GRAPHICS_BIT,
VK_QUEUE_COMPUTE_BIT,
VK_QUEUE_TRANSFER_BIT
};
// clang-format on
static constexpr VkFormat VK_FORMAT_MAP[] = {
@@ -375,13 +383,64 @@ void VulkanRenderDriver::select_device(const u32 p_index) {
_init_device(queues);
}
QueueID VulkanRenderDriver::get_queue() {
u32 VulkanRenderDriver::choose_queue_family(QueueType p_type, SurfaceID p_surface) {
NOVA_AUTO_TRACE();
NOVA_ASSERT(m_device);
// TODO: Actually create/get a queue
Queue* queue = new Queue();
queue->family_index = 0;
return queue;
NOVA_ASSERT(!m_queue_families.empty());
const VkQueueFlags mask = VK_QUEUE_FLAGS_MAP[static_cast<int>(p_type)];
u32 best_index = std::numeric_limits<u32>::max();
u32 best_score = std::numeric_limits<u32>::max();
for (const auto [index, flags] : m_queue_families) {
if ((flags & mask) != mask) {
continue;
}
if (p_surface) {
VkBool32 supports_surface;
vkGetPhysicalDeviceSurfaceSupportKHR(m_physical_device, index, p_surface->handle, &supports_surface);
if (!supports_surface) {
continue;
}
}
u32 score = std::popcount(flags);
if (score < best_score) {
best_index = index;
best_score = score;
}
}
return best_index;
}
QueueID VulkanRenderDriver::get_queue(u32 p_queue_family) {
NOVA_AUTO_TRACE();
NOVA_ASSERT(m_queue_families.contains(p_queue_family));
QueueID best_queue = nullptr;
u32 best_usage = std::numeric_limits<u32>::max();
for (Queue& queue : m_queues) {
if (queue.family_index != p_queue_family) {
continue;
}
if (queue.usage_count < best_usage) {
best_queue = &queue;
best_usage = queue.usage_count;
}
}
if (best_queue) {
best_queue->usage_count++;
}
return best_queue;
}
void VulkanRenderDriver::free_queue(QueueID p_queue) {
NOVA_AUTO_TRACE();
NOVA_ASSERT(p_queue);
p_queue->usage_count--;
}
SurfaceID VulkanRenderDriver::create_surface(WindowID p_window) {
@@ -1113,7 +1172,7 @@ void VulkanRenderDriver::_check_device_capabilities() {
// TODO: Check device capabilities
}
void VulkanRenderDriver::_init_queues(std::vector<VkDeviceQueueCreateInfo>& p_queues) const {
void VulkanRenderDriver::_init_queues(std::vector<VkDeviceQueueCreateInfo>& p_queues) {
NOVA_AUTO_TRACE();
u32 count;
@@ -1136,13 +1195,21 @@ void VulkanRenderDriver::_init_queues(std::vector<VkDeviceQueueCreateInfo>& p_qu
NOVA_LOG("Using queue family: {}", i);
found |= available[i].queueFlags;
VkDeviceQueueCreateInfo queue {};
queue.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue.queueFamilyIndex = i;
queue.queueCount = 1;
queue.pQueuePriorities = &s_priority;
VkDeviceQueueCreateInfo create {};
create.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
create.queueFamilyIndex = i;
create.queueCount = std::min(MAX_QUEUES_PER_FAMILY, available[i].queueCount);
create.pQueuePriorities = &s_priority;
p_queues.push_back(queue);
p_queues.push_back(create);
m_queue_families[i] = available[i].queueFlags;
for (u32 j = 0; j < create.queueCount; j++) {
Queue queue;
queue.family_index = i;
queue.queue_index = j;
m_queues.push_back(queue);
}
}
if ((found & QUEUE_MASK) != QUEUE_MASK) {
@@ -1162,12 +1229,15 @@ void VulkanRenderDriver::_init_device(const std::vector<VkDeviceQueueCreateInfo>
create.queueCreateInfoCount = static_cast<u32>(p_queues.size());
create.pQueueCreateInfos = p_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");
}
for (Queue& queue : m_queues) {
vkGetDeviceQueue(m_device, queue.family_index, queue.queue_index, &queue.handle);
}
NOVA_LOG("VkDevice created");
}

View File

@@ -11,6 +11,7 @@
#include <nova/render/render_driver.h>
#include <vulkan/vulkan.h>
#include <unordered_map>
#include <vector>
namespace Nova {
@@ -30,7 +31,10 @@ namespace Nova {
};
struct Queue {
VkQueue handle = VK_NULL_HANDLE;
u32 family_index;
u32 queue_index;
u32 usage_count = 0;
};
struct RenderPass {
@@ -76,7 +80,9 @@ namespace Nova {
[[nodiscard]] bool get_device_supports_surface(u32 index, SurfaceID surface) const override;
void select_device(u32 index) override;
[[nodiscard]] QueueID get_queue() override;
[[nodiscard]] u32 choose_queue_family(QueueType type, SurfaceID surface) override;
[[nodiscard]] QueueID get_queue(u32 queue_family) override;
void free_queue(QueueID queue) override;
[[nodiscard]] SurfaceID create_surface(WindowID window) override;
void destroy_surface(SurfaceID surface) override;
@@ -117,6 +123,8 @@ namespace Nova {
std::vector<const char*> m_layers;
std::vector<const char*> m_device_extensions;
std::vector<RenderDevice> m_devices;
std::vector<Queue> m_queues;
std::unordered_map<u32, VkQueueFlags> m_queue_families;
void _check_version() const;
void _check_extensions();
@@ -127,7 +135,7 @@ namespace Nova {
void _check_device_extensions();
void _check_device_features();
void _check_device_capabilities();
void _init_queues(std::vector<VkDeviceQueueCreateInfo>& queues) const;
void _init_queues(std::vector<VkDeviceQueueCreateInfo>& queues);
void _init_device(const std::vector<VkDeviceQueueCreateInfo>& queues);
};
} // namespace Nova