diff --git a/aster/CMakeLists.txt b/aster/CMakeLists.txt index 0b5d17c..361cc18 100644 --- a/aster/CMakeLists.txt +++ b/aster/CMakeLists.txt @@ -10,10 +10,23 @@ find_package(Vulkan REQUIRED) find_package(fmt CONFIG REQUIRED) find_package(VulkanMemoryAllocator CONFIG REQUIRED) -set(HEADER_FILES constants.h config.h logger.h global.h context.h window.h - physical_device.h) -set(SOURCE_FILES logger.cpp global.cpp context.cpp window.cpp - physical_device.cpp) +set(HEADER_FILES + constants.h + config.h + 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}) set_property(TARGET aster_core PROPERTY CXX_STANDARD 20) diff --git a/aster/config.h b/aster/config.h index 4b14c88..f4493ad 100644 --- a/aster/config.h +++ b/aster/config.h @@ -12,6 +12,9 @@ #define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 #define VULKAN_HPP_NO_STRUCT_CONSTRUCTORS +#define VMA_STATIC_VULKAN_FUNCTIONS 0 +#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 + #if defined(NDEBUG) #define USE_OPTICK (0) #else diff --git a/aster/context.cpp b/aster/context.cpp index 2ca598c..809f925 100644 --- a/aster/context.cpp +++ b/aster/context.cpp @@ -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), .pEngineName = PROJECT_NAME, .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 = { diff --git a/aster/device.cpp b/aster/device.cpp new file mode 100644 index 0000000..a9c5e98 --- /dev/null +++ b/aster/device.cpp @@ -0,0 +1,80 @@ +// ============================================= +// Aster: device.cpp +// 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 &_queue_allocation, std::optional _name) : + physical_device{ std::move(_physical_device) }, + name{ std::move(_name) } { + std::vector 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(queue_create_infos.size()), + .pQueueCreateInfos = queue_create_infos.data(), + .enabledLayerCount = _context->enable_validation_layers ? cast(_context->validation_layers.size()) : 0, + .ppEnabledLayerNames = _context->enable_validation_layers ? _context->validation_layers.data() : nullptr, + .enabledExtensionCount = cast(_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(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; +} \ No newline at end of file diff --git a/aster/device.h b/aster/device.h new file mode 100644 index 0000000..e48941c --- /dev/null +++ b/aster/device.h @@ -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 = ""; + +struct QueueAllocation { + u32 family; + u32 count; +}; + +struct Device final { + vk::Device device; + PhysicalDevice physical_device; + VmaAllocator allocator{ nullptr }; + std::optional name{ nullptr }; + + Device(const Context *_context, PhysicalDevice &&_physical_device, const vk::PhysicalDeviceFeatures *_enabled_features, const std::vector &_queue_allocation, std::optional _name = std::nullopt); + + ~Device(); +}; diff --git a/aster/global.h b/aster/global.h index 3649cd8..4e6092d 100644 --- a/aster/global.h +++ b/aster/global.h @@ -18,6 +18,8 @@ #include #include +constexpr u32 ASTER_API_VERSION = vk::ApiVersion13; + #define CODE_LOC " @ " __FILE__ ":" VULKAN_HPP_STRINGIFY(__LINE__) [[nodiscard]] inline bool failed(const vk::Result _result) { return _result != vk::Result::eSuccess; diff --git a/aster/logger.h b/aster/logger.h index 8675c9a..2a2c53a 100644 --- a/aster/logger.h +++ b/aster/logger.h @@ -59,7 +59,7 @@ struct Logger { template void log(const std::string_view &_message, const char *_loc, u32 _line) const { if (cast(LogLevel) <= minimum_logging_level) { - fmt::println("{}{} {}{}| at {}:{}{}", to_color_cstr(), to_cstr(), _message.data(), ANSI_Black, _loc, _line, ANSI_Reset); + fmt::println("{}{} {} {} at {}:{}{}", to_color_cstr(), to_cstr(), _message.data(), ANSI_Black, _loc, _line, ANSI_Reset); } #if !defined(NDEBUG) if constexpr (LogLevel == LogType::eError) { @@ -71,7 +71,7 @@ struct Logger { template void log_cond(const char *_expr_str, const std::string_view &_message, const char *_loc, u32 _line) const { if (cast(LogLevel) <= minimum_logging_level) { - fmt::println("{}{} ({}) {}{}| at {}:{}{}", to_color_cstr(), to_cstr(), _expr_str, _message.data(), ANSI_Black, _loc, _line, ANSI_Reset); + fmt::println("{}{} ({}) {} {} at {}:{}{}", to_color_cstr(), to_cstr(), _expr_str, _message.data(), ANSI_Black, _loc, _line, ANSI_Reset); } #if !defined(NDEBUG) if constexpr (LogLevel == LogType::eError) { diff --git a/triangle/aster.cpp b/triangle/aster.cpp index 026da1b..96b38fd 100644 --- a/triangle/aster.cpp +++ b/triangle/aster.cpp @@ -1,9 +1,10 @@ #include "aster/constants.h" +#include "aster/device.h" #include "aster/glfw_context.h" #include "aster/physical_device.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) { 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."); } -int main(int, char **) { - const auto *glfw = new GlfwContext(); - auto *context = new Context("Aster", VERSION); - auto *window = new Window("Aster1", context, { 640, 480 }); +QueueAllocation find_appropriate_queue_allocation(const PhysicalDevice* _physical_device) { + for (auto &_queue_info: _physical_device->queue_families) { + if ((_queue_info.support & required_queue_support) == required_queue_support) { + 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); 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; - delete context; - delete glfw; + Device device = { &context, std::move(device_to_use), &features, {queue_allocation}, "Primary Device" }; + + while (window.poll()) { + } return 0; }