diff --git a/aster/CMakeLists.txt b/aster/CMakeLists.txt index 7eb0333..0b5d17c 100644 --- a/aster/CMakeLists.txt +++ b/aster/CMakeLists.txt @@ -10,8 +10,10 @@ 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) -set(SOURCE_FILES logger.cpp global.cpp context.cpp window.cpp) +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) 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 bb5f85b..4b14c88 100644 --- a/aster/config.h +++ b/aster/config.h @@ -11,7 +11,6 @@ #define GLFW_INCLUDE_VULKAN #define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 #define VULKAN_HPP_NO_STRUCT_CONSTRUCTORS -#define VULKAN_HPP_NO_EXCEPTIONS #if defined(NDEBUG) #define USE_OPTICK (0) diff --git a/aster/context.cpp b/aster/context.cpp index bf5777b..2ca598c 100644 --- a/aster/context.cpp +++ b/aster/context.cpp @@ -29,12 +29,10 @@ VKAPI_ATTR b32 VKAPI_CALL Context::debug_callback(VkDebugUtilsMessageSeverityFla } void Context::init(const std::string_view &_app_name, const Version &_app_version) { - vk::Result result; - INFO_IF(enable_validation_layers, "Validation Layers enabled"); // Creating Instance - vk::ApplicationInfo app_info = { + const vk::ApplicationInfo app_info = { .pApplicationName = _app_name.data(), .applicationVersion = VK_MAKE_VERSION(_app_version.major, _app_version.minor, _app_version.patch), .pEngineName = PROJECT_NAME, @@ -54,10 +52,8 @@ void Context::init(const std::string_view &_app_name, const Version &_app_versio }; u32 glfw_extension_count = 0; - const char **glfw_extensions = nullptr; - - glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extension_count); - std::vector vulkan_extensions(glfw_extensions, glfw_extensions + glfw_extension_count); + const char **glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extension_count); + std::vector vulkan_extensions(glfw_extensions, glfw_extensions + glfw_extension_count); if (enable_validation_layers) { vulkan_extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); } @@ -67,24 +63,29 @@ void Context::init(const std::string_view &_app_name, const Version &_app_versio const auto vkGetInstanceProcAddr = dl.getProcAddress("vkGetInstanceProcAddr"); VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr); - tie(result, instance) = vk::createInstance({ - .pNext = enable_validation_layers ? &debug_messenger_create_info : nullptr, - .pApplicationInfo = &app_info, - .enabledLayerCount = enable_validation_layers ? cast(validation_layers.size()) : 0, - .ppEnabledLayerNames = enable_validation_layers ? validation_layers.data() : nullptr, - .enabledExtensionCount = cast(vulkan_extensions.size()), - .ppEnabledExtensionNames = vulkan_extensions.data(), - }); - ERROR_IF(failed(result), "Failed to create Vulkan instance with {}", to_string(result)) - THEN_CRASH(result) - ELSE_INFO("Instance Created."); + const auto instance_create_info = vk::InstanceCreateInfo{ + .pNext = enable_validation_layers ? &debug_messenger_create_info : nullptr, + .pApplicationInfo = &app_info, + .enabledLayerCount = enable_validation_layers ? cast(validation_layers.size()) : 0, + .ppEnabledLayerNames = enable_validation_layers ? validation_layers.data() : nullptr, + .enabledExtensionCount = cast(vulkan_extensions.size()), + .ppEnabledExtensionNames = vulkan_extensions.data(), + }; + + // May throw. Irrecoverable. + instance = vk::createInstance(instance_create_info); + INFO("Instance Created."); VULKAN_HPP_DEFAULT_DISPATCHER.init(instance); // Debug Messenger if (enable_validation_layers) { - tie(result, debug_messenger) = instance.createDebugUtilsMessengerEXT(debug_messenger_create_info); - ERROR_IF(failed(result), "Debug Messenger creation failed with {}", to_string(result)) - ELSE_INFO("Debug Messenger Created."); + try { + debug_messenger = instance.createDebugUtilsMessengerEXT(debug_messenger_create_info); + } catch (const std::exception &_err) { + ERROR("Debug Messenger creation failed. Cause: {}", _err.what()); + // Non-critical. Continue. + } + INFO("Debug Messenger Created."); } } diff --git a/aster/physical_device.cpp b/aster/physical_device.cpp new file mode 100644 index 0000000..770876a --- /dev/null +++ b/aster/physical_device.cpp @@ -0,0 +1,99 @@ +// ============================================= +// Aster: physical_device.cpp +// Copyright (c) 2020-2024 Anish Bhobe +// ============================================= + +#include "physical_device.h" + +[[nodiscard]] std::vector get_surface_formats(const Window *_window, const vk::PhysicalDevice *_physical_device) { + try { + return _physical_device->getSurfaceFormatsKHR(_window->surface); + } catch (const std::exception &_err) { + ERROR("Could not get surface formats. Cause: {}", _err.what()); + throw; + } +} + +[[nodiscard]] std::vector get_present_modes(const Window *_window, const vk::PhysicalDevice *_physical_device) { + try { + return _physical_device->getSurfacePresentModesKHR(_window->surface); + } catch (const std::exception &_err) { + ERROR("Could not get present modes. Cause: {}", _err.what()); + throw; + } +} + +[[nodiscard]] bool get_present_support(const u32 _family_index, const Window *_window, const vk::PhysicalDevice *_device) { + try { + return _device->getSurfaceSupportKHR(_family_index, _window->surface); + } catch (const std::exception &_err) { + ERROR("Could not get queue family surface support. Cause: {}", _err.what()); + throw; + } +} + +[[nodiscard]] std::vector get_queue_families(const Window *_window, const vk::PhysicalDevice *_device) { + auto queue_family_props = _device->getQueueFamilyProperties(); + + std::vector queue_family_infos; + queue_family_infos.reserve(queue_family_props.size()); + + u32 family_index = 0; + for (auto qfp : queue_family_props) { + QueueSupportFlags support = {}; + + if (qfp.queueFlags | vk::QueueFlagBits::eGraphics) { + support |= QueueSupportFlagBits::eGraphics; + } + + if (qfp.queueFlags | vk::QueueFlagBits::eTransfer) { + support |= QueueSupportFlagBits::eTransfer; + } + + if (qfp.queueFlags | vk::QueueFlagBits::eCompute) { + support |= QueueSupportFlagBits::eCompute; + } + + if (get_present_support(family_index, _window, _device)) { + support |= QueueSupportFlagBits::ePresent; + } + + queue_family_infos.push_back({ + .index = family_index, + .count = qfp.queueCount, + .support = support, + }); + + family_index++; + } + + return queue_family_infos; +} + +PhysicalDevice::PhysicalDevice(const Window *_window, vk::PhysicalDevice _physical_device) { + _physical_device.getProperties(&properties); + _physical_device.getFeatures(&features); + + surface_formats = get_surface_formats(_window, &_physical_device); + present_modes = get_present_modes(_window, &_physical_device); + queue_families = get_queue_families(_window, &_physical_device); + + device = _physical_device; +} + +std::vector enumerate_physical_devices(const Context *_context) { + try { + return _context->instance.enumeratePhysicalDevices(); + } catch (const std::exception &_err) { + ERROR("Could not fetch vulkan devices. Cause: {}", _err.what()); + throw; + } +} + +PhysicalDevices::PhysicalDevices(const Window *_window, const Context *_context) { + auto physical_devices = enumerate_physical_devices(_context); + this->reserve(physical_devices.size()); + for (auto physical_device : physical_devices) { + this->emplace_back(_window, physical_device); + } +} diff --git a/aster/physical_device.h b/aster/physical_device.h new file mode 100644 index 0000000..de778d2 --- /dev/null +++ b/aster/physical_device.h @@ -0,0 +1,40 @@ +// ============================================= +// Aster: physical_device.h +// Copyright (c) 2020-2024 Anish Bhobe +// ============================================= + +#pragma once + +#include "global.h" +#include "window.h" + +enum class QueueSupportFlagBits { + eGraphics = 0b0001, + eTransfer = 0b0010, + eCompute = 0b0100, + ePresent = 0b1000, +}; + +using QueueSupportFlags = vk::Flags{}; + +struct QueueFamilyInfo { + u32 index; + u32 count; + QueueSupportFlags support; +}; + +struct PhysicalDevice { + vk::PhysicalDevice device; + vk::PhysicalDeviceProperties properties; + vk::PhysicalDeviceFeatures features; + std::vector surface_formats; + std::vector present_modes; + std::vector queue_families; + + PhysicalDevice(const Window *_window, vk::PhysicalDevice _physical_device); +}; + +class PhysicalDevices : public std::vector { +public: + PhysicalDevices(const Window *_window, const Context *_context); +}; \ No newline at end of file