Add proper queue init and fetch functionality to RenderDriver
This commit is contained in:
@@ -30,7 +30,9 @@ namespace Nova {
|
|||||||
[[nodiscard]] virtual bool get_device_supports_surface(u32 index, SurfaceID surface) const = 0;
|
[[nodiscard]] virtual bool get_device_supports_surface(u32 index, SurfaceID surface) const = 0;
|
||||||
virtual void select_device(u32 index) = 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;
|
[[nodiscard]] virtual SurfaceID create_surface(WindowID window) = 0;
|
||||||
virtual void destroy_surface(SurfaceID surface) = 0;
|
virtual void destroy_surface(SurfaceID surface) = 0;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ namespace Nova {
|
|||||||
enum class InputRate { VERTEX, INSTANCE };
|
enum class InputRate { VERTEX, INSTANCE };
|
||||||
enum class PipelineType { GRAPHICS, COMPUTE };
|
enum class PipelineType { GRAPHICS, COMPUTE };
|
||||||
enum class PrimitiveTopology { POINT_LIST, LINE_LIST, LINE_STRIP, TRIANGLE_LIST, TRIANGLE_STRIP };
|
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 RenderAPI { DX12, VULKAN };
|
||||||
enum class ShaderStage { VERTEX, FRAGMENT, GEOMETRY, TESS_CONTROL, TESS_EVAL, COMPUTE, MESH, TASK };
|
enum class ShaderStage { VERTEX, FRAGMENT, GEOMETRY, TESS_CONTROL, TESS_EVAL, COMPUTE, MESH, TASK };
|
||||||
|
|
||||||
|
|||||||
@@ -16,11 +16,12 @@
|
|||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <bit>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
#define VALIDATION_LAYER "VK_LAYER_KHRONOS_validation"
|
#define VALIDATION_LAYER "VK_LAYER_KHRONOS_validation"
|
||||||
|
#define MAX_QUEUES_PER_FAMILY 2U
|
||||||
|
|
||||||
using namespace Nova;
|
using namespace Nova;
|
||||||
|
|
||||||
@@ -61,6 +62,13 @@ static constexpr VkVertexInputRate VK_VERTEX_INPUT_RATE_MAP[] = {
|
|||||||
VK_VERTEX_INPUT_RATE_INSTANCE
|
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
|
// clang-format on
|
||||||
|
|
||||||
static constexpr VkFormat VK_FORMAT_MAP[] = {
|
static constexpr VkFormat VK_FORMAT_MAP[] = {
|
||||||
@@ -375,13 +383,64 @@ void VulkanRenderDriver::select_device(const u32 p_index) {
|
|||||||
_init_device(queues);
|
_init_device(queues);
|
||||||
}
|
}
|
||||||
|
|
||||||
QueueID VulkanRenderDriver::get_queue() {
|
u32 VulkanRenderDriver::choose_queue_family(QueueType p_type, SurfaceID p_surface) {
|
||||||
NOVA_AUTO_TRACE();
|
NOVA_AUTO_TRACE();
|
||||||
NOVA_ASSERT(m_device);
|
NOVA_ASSERT(!m_queue_families.empty());
|
||||||
// TODO: Actually create/get a queue
|
|
||||||
Queue* queue = new Queue();
|
const VkQueueFlags mask = VK_QUEUE_FLAGS_MAP[static_cast<int>(p_type)];
|
||||||
queue->family_index = 0;
|
|
||||||
return queue;
|
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) {
|
SurfaceID VulkanRenderDriver::create_surface(WindowID p_window) {
|
||||||
@@ -1113,7 +1172,7 @@ void VulkanRenderDriver::_check_device_capabilities() {
|
|||||||
// TODO: 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();
|
NOVA_AUTO_TRACE();
|
||||||
|
|
||||||
u32 count;
|
u32 count;
|
||||||
@@ -1136,13 +1195,21 @@ void VulkanRenderDriver::_init_queues(std::vector<VkDeviceQueueCreateInfo>& p_qu
|
|||||||
NOVA_LOG("Using queue family: {}", i);
|
NOVA_LOG("Using queue family: {}", i);
|
||||||
found |= available[i].queueFlags;
|
found |= available[i].queueFlags;
|
||||||
|
|
||||||
VkDeviceQueueCreateInfo queue {};
|
VkDeviceQueueCreateInfo create {};
|
||||||
queue.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
create.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||||
queue.queueFamilyIndex = i;
|
create.queueFamilyIndex = i;
|
||||||
queue.queueCount = 1;
|
create.queueCount = std::min(MAX_QUEUES_PER_FAMILY, available[i].queueCount);
|
||||||
queue.pQueuePriorities = &s_priority;
|
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) {
|
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.queueCreateInfoCount = static_cast<u32>(p_queues.size());
|
||||||
create.pQueueCreateInfos = p_queues.data();
|
create.pQueueCreateInfos = p_queues.data();
|
||||||
create.pEnabledFeatures = &m_features;
|
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) {
|
if (vkCreateDevice(m_physical_device, &create, get_allocator(VK_OBJECT_TYPE_DEVICE), &m_device) != VK_SUCCESS) {
|
||||||
throw std::runtime_error("Failed to create VkDevice");
|
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");
|
NOVA_LOG("VkDevice created");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <nova/render/render_driver.h>
|
#include <nova/render/render_driver.h>
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace Nova {
|
namespace Nova {
|
||||||
@@ -30,7 +31,10 @@ namespace Nova {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Queue {
|
struct Queue {
|
||||||
|
VkQueue handle = VK_NULL_HANDLE;
|
||||||
u32 family_index;
|
u32 family_index;
|
||||||
|
u32 queue_index;
|
||||||
|
u32 usage_count = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RenderPass {
|
struct RenderPass {
|
||||||
@@ -76,7 +80,9 @@ namespace Nova {
|
|||||||
[[nodiscard]] bool get_device_supports_surface(u32 index, SurfaceID surface) const override;
|
[[nodiscard]] bool get_device_supports_surface(u32 index, SurfaceID surface) const override;
|
||||||
void select_device(u32 index) 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;
|
[[nodiscard]] SurfaceID create_surface(WindowID window) override;
|
||||||
void destroy_surface(SurfaceID surface) override;
|
void destroy_surface(SurfaceID surface) override;
|
||||||
@@ -117,6 +123,8 @@ namespace Nova {
|
|||||||
std::vector<const char*> m_layers;
|
std::vector<const char*> m_layers;
|
||||||
std::vector<const char*> m_device_extensions;
|
std::vector<const char*> m_device_extensions;
|
||||||
std::vector<RenderDevice> m_devices;
|
std::vector<RenderDevice> m_devices;
|
||||||
|
std::vector<Queue> m_queues;
|
||||||
|
std::unordered_map<u32, VkQueueFlags> m_queue_families;
|
||||||
|
|
||||||
void _check_version() const;
|
void _check_version() const;
|
||||||
void _check_extensions();
|
void _check_extensions();
|
||||||
@@ -127,7 +135,7 @@ namespace Nova {
|
|||||||
void _check_device_extensions();
|
void _check_device_extensions();
|
||||||
void _check_device_features();
|
void _check_device_features();
|
||||||
void _check_device_capabilities();
|
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);
|
void _init_device(const std::vector<VkDeviceQueueCreateInfo>& queues);
|
||||||
};
|
};
|
||||||
} // namespace Nova
|
} // namespace Nova
|
||||||
|
|||||||
Reference in New Issue
Block a user