Device creation + cleanup.
This commit is contained in:
parent
ce4dd9b096
commit
75bb1ca895
|
|
@ -10,10 +10,23 @@ find_package(Vulkan REQUIRED)
|
||||||
find_package(fmt CONFIG REQUIRED)
|
find_package(fmt CONFIG REQUIRED)
|
||||||
find_package(VulkanMemoryAllocator CONFIG REQUIRED)
|
find_package(VulkanMemoryAllocator CONFIG REQUIRED)
|
||||||
|
|
||||||
set(HEADER_FILES constants.h config.h logger.h global.h context.h window.h
|
set(HEADER_FILES
|
||||||
physical_device.h)
|
constants.h
|
||||||
set(SOURCE_FILES logger.cpp global.cpp context.cpp window.cpp
|
config.h
|
||||||
physical_device.cpp)
|
logger.h
|
||||||
|
global.h
|
||||||
|
context.h
|
||||||
|
window.h
|
||||||
|
physical_device.h
|
||||||
|
device.h)
|
||||||
|
|
||||||
|
set(SOURCE_FILES
|
||||||
|
logger.cpp
|
||||||
|
global.cpp
|
||||||
|
context.cpp
|
||||||
|
window.cpp
|
||||||
|
physical_device.cpp
|
||||||
|
device.cpp)
|
||||||
|
|
||||||
add_library(aster_core STATIC ${SOURCE_FILES} ${HEADER_FILES})
|
add_library(aster_core STATIC ${SOURCE_FILES} ${HEADER_FILES})
|
||||||
set_property(TARGET aster_core PROPERTY CXX_STANDARD 20)
|
set_property(TARGET aster_core PROPERTY CXX_STANDARD 20)
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,9 @@
|
||||||
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
|
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
|
||||||
#define VULKAN_HPP_NO_STRUCT_CONSTRUCTORS
|
#define VULKAN_HPP_NO_STRUCT_CONSTRUCTORS
|
||||||
|
|
||||||
|
#define VMA_STATIC_VULKAN_FUNCTIONS 0
|
||||||
|
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
|
||||||
|
|
||||||
#if defined(NDEBUG)
|
#if defined(NDEBUG)
|
||||||
#define USE_OPTICK (0)
|
#define USE_OPTICK (0)
|
||||||
#else
|
#else
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ void Context::init(const std::string_view &_app_name, const Version &_app_versio
|
||||||
.applicationVersion = VK_MAKE_VERSION(_app_version.major, _app_version.minor, _app_version.patch),
|
.applicationVersion = VK_MAKE_VERSION(_app_version.major, _app_version.minor, _app_version.patch),
|
||||||
.pEngineName = PROJECT_NAME,
|
.pEngineName = PROJECT_NAME,
|
||||||
.engineVersion = VK_MAKE_VERSION(VERSION.major, VERSION.minor, VERSION.patch),
|
.engineVersion = VK_MAKE_VERSION(VERSION.major, VERSION.minor, VERSION.patch),
|
||||||
.apiVersion = VK_API_VERSION_1_2,
|
.apiVersion = ASTER_API_VERSION,
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::DebugUtilsMessengerCreateInfoEXT debug_messenger_create_info = {
|
vk::DebugUtilsMessengerCreateInfoEXT debug_messenger_create_info = {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: device.h
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
|
Device::Device(const Context *_context, PhysicalDevice &&_physical_device, const vk::PhysicalDeviceFeatures *_enabled_features, const std::vector<QueueAllocation> &_queue_allocation, std::optional<std::string> _name) :
|
||||||
|
physical_device{ std::move(_physical_device) },
|
||||||
|
name{ std::move(_name) } {
|
||||||
|
std::vector<vk::DeviceQueueCreateInfo> queue_create_infos;
|
||||||
|
queue_create_infos.reserve(_queue_allocation.size());
|
||||||
|
|
||||||
|
u32 num_priorities = 0;
|
||||||
|
for (auto [_, count] : _queue_allocation) {
|
||||||
|
num_priorities = std::max(count, num_priorities);
|
||||||
|
}
|
||||||
|
std::vector priorities(num_priorities, 1.0f);
|
||||||
|
|
||||||
|
for (auto [family, count] : _queue_allocation) {
|
||||||
|
queue_create_infos.push_back({
|
||||||
|
.queueFamilyIndex = family,
|
||||||
|
.queueCount = count,
|
||||||
|
.pQueuePriorities = priorities.data(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
device = physical_device.device.createDevice({
|
||||||
|
.queueCreateInfoCount = cast<u32>(queue_create_infos.size()),
|
||||||
|
.pQueueCreateInfos = queue_create_infos.data(),
|
||||||
|
.enabledLayerCount = _context->enable_validation_layers ? cast<u32>(_context->validation_layers.size()) : 0,
|
||||||
|
.ppEnabledLayerNames = _context->enable_validation_layers ? _context->validation_layers.data() : nullptr,
|
||||||
|
.enabledExtensionCount = cast<u32>(_context->device_extensions.size()),
|
||||||
|
.ppEnabledExtensionNames = _context->device_extensions.data(),
|
||||||
|
.pEnabledFeatures = _enabled_features,
|
||||||
|
});
|
||||||
|
} catch (const std::exception &_err) {
|
||||||
|
ERROR("Could not initialize Vulkan Device. Cause: {}", _err.what());
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
INFO("{} ({}) Initialized!", name.value_or(DEFAULT_DEVICE_NAME), physical_device.properties.deviceName.data());
|
||||||
|
|
||||||
|
VmaVulkanFunctions vma_vulkan_functions = {
|
||||||
|
.vkGetInstanceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetInstanceProcAddr,
|
||||||
|
.vkGetDeviceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetDeviceProcAddr,
|
||||||
|
};
|
||||||
|
|
||||||
|
const VmaAllocatorCreateInfo vma_allocator_create_info = {
|
||||||
|
.flags = 0,
|
||||||
|
.physicalDevice = physical_device.device,
|
||||||
|
.device = device,
|
||||||
|
.pVulkanFunctions = &vma_vulkan_functions,
|
||||||
|
.instance = _context->instance,
|
||||||
|
.vulkanApiVersion = ASTER_API_VERSION,
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto result = cast<vk::Result>(vmaCreateAllocator(&vma_allocator_create_info, &allocator));
|
||||||
|
if (failed(result)) {
|
||||||
|
device.destroy();
|
||||||
|
auto _err = fmt::format("Memory allocator creation failed. Cause: {}", to_string(result));
|
||||||
|
ERROR("{}", _err);
|
||||||
|
throw std::runtime_error(_err);
|
||||||
|
}
|
||||||
|
VERBOSE("Memory Allocator Created");
|
||||||
|
|
||||||
|
INFO("Created '{}' Successfully", name.value_or(DEFAULT_DEVICE_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
Device::~Device() {
|
||||||
|
if (allocator) {
|
||||||
|
vmaDestroyAllocator(allocator);
|
||||||
|
allocator = nullptr;
|
||||||
|
VERBOSE("Memory Allocator Destroyed");
|
||||||
|
}
|
||||||
|
device.destroy();
|
||||||
|
INFO("Device '{}' Destroyed", name.value_or(DEFAULT_DEVICE_NAME));
|
||||||
|
name = std::nullopt;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: device.h
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
#include "physical_device.h"
|
||||||
|
|
||||||
|
constexpr std::string DEFAULT_DEVICE_NAME = "<Unnamed GPU>";
|
||||||
|
|
||||||
|
struct QueueAllocation {
|
||||||
|
u32 family;
|
||||||
|
u32 count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Device final {
|
||||||
|
vk::Device device;
|
||||||
|
PhysicalDevice physical_device;
|
||||||
|
VmaAllocator allocator { nullptr };
|
||||||
|
std::optional<std::string> name { nullptr };
|
||||||
|
|
||||||
|
Device(const Context *_context, PhysicalDevice &&_physical_device, const vk::PhysicalDeviceFeatures *_enabled_features, const std::vector<QueueAllocation> &_queue_allocation, std::optional<std::string> _name = std::nullopt);
|
||||||
|
|
||||||
|
~Device();
|
||||||
|
};
|
||||||
|
|
@ -18,6 +18,8 @@
|
||||||
#include <vk_mem_alloc.h>
|
#include <vk_mem_alloc.h>
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
|
constexpr u32 ASTER_API_VERSION = vk::ApiVersion13;
|
||||||
|
|
||||||
#define CODE_LOC " @ " __FILE__ ":" VULKAN_HPP_STRINGIFY(__LINE__)
|
#define CODE_LOC " @ " __FILE__ ":" VULKAN_HPP_STRINGIFY(__LINE__)
|
||||||
[[nodiscard]] inline bool failed(const vk::Result _result) {
|
[[nodiscard]] inline bool failed(const vk::Result _result) {
|
||||||
return _result != vk::Result::eSuccess;
|
return _result != vk::Result::eSuccess;
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ struct Logger {
|
||||||
template <LogType LogLevel>
|
template <LogType LogLevel>
|
||||||
void log(const std::string_view &_message, const char *_loc, u32 _line) const {
|
void log(const std::string_view &_message, const char *_loc, u32 _line) const {
|
||||||
if (cast<u32>(LogLevel) <= minimum_logging_level) {
|
if (cast<u32>(LogLevel) <= minimum_logging_level) {
|
||||||
fmt::println("{}{} {}{}| at {}:{}{}", to_color_cstr<LogLevel>(), to_cstr<LogLevel>(), _message.data(), ANSI_Black, _loc, _line, ANSI_Reset);
|
fmt::println("{}{} {} {} at {}:{}{}", to_color_cstr<LogLevel>(), to_cstr<LogLevel>(), _message.data(), ANSI_Black, _loc, _line, ANSI_Reset);
|
||||||
}
|
}
|
||||||
#if !defined(NDEBUG)
|
#if !defined(NDEBUG)
|
||||||
if constexpr (LogLevel == LogType::eError) {
|
if constexpr (LogLevel == LogType::eError) {
|
||||||
|
|
@ -71,7 +71,7 @@ struct Logger {
|
||||||
template <LogType LogLevel>
|
template <LogType LogLevel>
|
||||||
void log_cond(const char *_expr_str, const std::string_view &_message, const char *_loc, u32 _line) const {
|
void log_cond(const char *_expr_str, const std::string_view &_message, const char *_loc, u32 _line) const {
|
||||||
if (cast<u32>(LogLevel) <= minimum_logging_level) {
|
if (cast<u32>(LogLevel) <= minimum_logging_level) {
|
||||||
fmt::println("{}{} ({}) {}{}| at {}:{}{}", to_color_cstr<LogLevel>(), to_cstr<LogLevel>(), _expr_str, _message.data(), ANSI_Black, _loc, _line, ANSI_Reset);
|
fmt::println("{}{} ({}) {} {} at {}:{}{}", to_color_cstr<LogLevel>(), to_cstr<LogLevel>(), _expr_str, _message.data(), ANSI_Black, _loc, _line, ANSI_Reset);
|
||||||
}
|
}
|
||||||
#if !defined(NDEBUG)
|
#if !defined(NDEBUG)
|
||||||
if constexpr (LogLevel == LogType::eError) {
|
if constexpr (LogLevel == LogType::eError) {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
#include "aster/constants.h"
|
#include "aster/constants.h"
|
||||||
|
#include "aster/device.h"
|
||||||
#include "aster/glfw_context.h"
|
#include "aster/glfw_context.h"
|
||||||
#include "aster/physical_device.h"
|
#include "aster/physical_device.h"
|
||||||
#include "aster/window.h"
|
#include "aster/window.h"
|
||||||
|
|
||||||
constexpr QueueSupportFlags required_queue_support = QueueSupportFlags{} | QueueSupportFlagBits::eGraphics | QueueSupportFlagBits::eCompute | QueueSupportFlagBits::ePresent | QueueSupportFlagBits::eCompute;
|
constexpr QueueSupportFlags required_queue_support = QueueSupportFlags{} | QueueSupportFlagBits::eGraphics | QueueSupportFlagBits::eCompute | QueueSupportFlagBits::ePresent | QueueSupportFlagBits::eTransfer;
|
||||||
|
|
||||||
[[nodiscard]] bool is_suitable_device(const PhysicalDevice *_physical_device) {
|
[[nodiscard]] bool is_suitable_device(const PhysicalDevice *_physical_device) {
|
||||||
const bool all_required_queues = std::ranges::any_of(_physical_device->queue_families, [](const auto &_qfp) {
|
const bool all_required_queues = std::ranges::any_of(_physical_device->queue_families, [](const auto &_qfp) {
|
||||||
|
|
@ -28,22 +29,35 @@ PhysicalDevice find_suitable_device(const PhysicalDevices &_physical_devices) {
|
||||||
throw std::runtime_error("No suitable device found.");
|
throw std::runtime_error("No suitable device found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int, char **) {
|
QueueAllocation find_appropriate_queue_allocation(const PhysicalDevice* _physical_device) {
|
||||||
const auto *glfw = new GlfwContext();
|
for (auto &_queue_info: _physical_device->queue_families) {
|
||||||
auto *context = new Context("Aster", VERSION);
|
if ((_queue_info.support & required_queue_support) == required_queue_support) {
|
||||||
auto *window = new Window("Aster1", context, { 640, 480 });
|
return {
|
||||||
|
.family = _queue_info.index,
|
||||||
|
.count = _queue_info.count,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw std::runtime_error("No suitable queue family.");
|
||||||
|
}
|
||||||
|
|
||||||
PhysicalDevices physical_devices = { window, context };
|
int main(int, char **) {
|
||||||
|
GlfwContext glfw_context = {};
|
||||||
|
Context context = {"Aster", VERSION};
|
||||||
|
Window window = {"Aster1", &context, { 640, 480 }};
|
||||||
|
|
||||||
|
PhysicalDevices physical_devices = { &window, &context };
|
||||||
PhysicalDevice device_to_use = find_suitable_device(physical_devices);
|
PhysicalDevice device_to_use = find_suitable_device(physical_devices);
|
||||||
|
|
||||||
INFO("Using {} as the primary device.", device_to_use.properties.deviceName.data());
|
INFO("Using {} as the primary device.", device_to_use.properties.deviceName.data());
|
||||||
|
|
||||||
while (window->poll()) {
|
vk::PhysicalDeviceFeatures features = {};
|
||||||
}
|
QueueAllocation queue_allocation = find_appropriate_queue_allocation(&device_to_use);
|
||||||
|
|
||||||
delete window;
|
Device device = { &context, std::move(device_to_use), &features, {queue_allocation}, "Primary Device" };
|
||||||
delete context;
|
|
||||||
delete glfw;
|
while (window.poll()) {
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue