Compare commits

..

4 Commits

Author SHA1 Message Date
Anish Bhobe 8769215437 Removed duplication. 2024-06-27 01:36:17 +02:00
Anish Bhobe e120b38066 Cleaned up result formatting. 2024-06-26 20:25:24 +02:00
Anish Bhobe e55f30e7e7 Swapchain added. 2024-06-26 19:49:55 +02:00
Anish Bhobe c16456c610 Refactored Device and Cleaned up includes. 2024-06-26 19:49:46 +02:00
12 changed files with 231 additions and 42 deletions

View File

@ -18,7 +18,8 @@ set(HEADER_FILES
context.h
window.h
physical_device.h
device.h)
device.h
swapchain.h)
set(SOURCE_FILES
logger.cpp
@ -26,11 +27,14 @@ set(SOURCE_FILES
context.cpp
window.cpp
physical_device.cpp
device.cpp)
device.cpp
swapchain.cpp)
add_library(aster_core STATIC ${SOURCE_FILES} ${HEADER_FILES})
set_property(TARGET aster_core PROPERTY CXX_STANDARD 20)
target_precompile_headers(aster_core PUBLIC global.h)
target_include_directories(aster_core PUBLIC ${CMAKE_SOURCE_DIR})
target_link_libraries(aster_core PUBLIC glm::glm-header-only)

View File

@ -12,7 +12,7 @@ constexpr eastl::array VALIDATION_LAYERS = {
};
VKAPI_ATTR b32 VKAPI_CALL
debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType,
DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT *callbackData, [[maybe_unused]] void *userData)
{
using Severity = vk::DebugUtilsMessageSeverityFlagsEXT;
@ -57,7 +57,7 @@ Context::Context(cstr appName, Version version, bool enableValidation)
.messageType = vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance |
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation,
.pfnUserCallback = debugCallback,
.pfnUserCallback = DebugCallback,
.pUserData = nullptr,
};
@ -85,7 +85,7 @@ Context::Context(cstr appName, Version version, bool enableValidation)
// May throw. Irrecoverable.
vk::Result result = vk::createInstance(&instanceCreateInfo, nullptr, &m_Instance);
ERROR_IF(result, "Instance creation failed. Cause: {}", to_string(result))
ERROR_IF(result, "Instance creation failed. Cause: {}", result)
THEN_ABORT(result)
ELSE_DEBUG("Instance Created.");
VULKAN_HPP_DEFAULT_DISPATCHER.init(m_Instance);
@ -94,7 +94,7 @@ Context::Context(cstr appName, Version version, bool enableValidation)
if (enableValidation)
{
result = m_Instance.createDebugUtilsMessengerEXT(&debugUtilsMessengerCreateInfo, nullptr, &m_DebugMessenger);
ERROR_IF(result, "Debug Messenger creation failed. Cause: {}", to_string(result)) // Non-critical. Continue.
ERROR_IF(result, "Debug Messenger creation failed. Cause: {}", result) // Non-critical. Continue.
ELSE_DEBUG("Debug Messenger Created.");
}
}

View File

@ -5,14 +5,19 @@
#include "device.h"
#include "context.h"
#include "physical_device.h"
#include <EASTL/array.h>
#include <EASTL/fixed_vector.h>
constexpr eastl::array DEVICE_EXTENSIONS = {VK_KHR_SWAPCHAIN_EXTENSION_NAME};
Device::Device(const Context *context, PhysicalDevice *physicalDevice,
const vk::PhysicalDeviceFeatures *enabledFeatures,
const eastl::vector<QueueAllocation> &queueAllocations, NameString name)
const eastl::vector<QueueAllocation> &queueAllocations, NameString &&name)
: m_Name(std::move(name))
, m_PhysicalDevice(physicalDevice->m_PhysicalDevice)
{
// Shouldn't have more than 4 deviceQueueFamilies in use anyway. Else we can heap
eastl::fixed_vector<vk::DeviceQueueCreateInfo, 4> deviceQueueCreateInfos;
@ -43,7 +48,7 @@ Device::Device(const Context *context, PhysicalDevice *physicalDevice,
.pEnabledFeatures = enabledFeatures,
};
vk::Result result = physicalDevice->m_PhysicalDevice.createDevice(&deviceCreateInfo, nullptr, &m_Device);
vk::Result result = m_PhysicalDevice.createDevice(&deviceCreateInfo, nullptr, &m_Device);
ERROR_IF(failed(result), "Could not initialize Vulkan Device. Cause: {}", result)
THEN_ABORT(result)
ELSE_DEBUG("{} ({}) Initialized.", m_Name, physicalDevice->m_DeviceProperties.deviceName.data());
@ -54,8 +59,7 @@ Device::Device(const Context *context, PhysicalDevice *physicalDevice,
};
const VmaAllocatorCreateInfo allocatorCreateInfo = {
.flags = 0,
.physicalDevice = physicalDevice->m_PhysicalDevice,
.physicalDevice = m_PhysicalDevice,
.device = m_Device,
.pVulkanFunctions = &vmaVulkanFunctions,
.instance = context->m_Instance,
@ -63,7 +67,7 @@ Device::Device(const Context *context, PhysicalDevice *physicalDevice,
};
result = cast<vk::Result>(vmaCreateAllocator(&allocatorCreateInfo, &m_Allocator));
ERROR_IF(failed(result), "Memory allocator creation failed. Cause: {}", to_string(result))
ERROR_IF(failed(result), "Memory allocator creation failed. Cause: {}", result)
DO(m_Device.destroy(nullptr))
THEN_ABORT(result)
ELSE_VERBOSE("Memory Allocator Created");
@ -81,4 +85,5 @@ Device::~Device()
}
m_Device.destroy(nullptr);
DEBUG("Device '{}' Destroyed", m_Name);
m_PhysicalDevice = nullptr;
}

View File

@ -6,7 +6,11 @@
#pragma once
#include "global.h"
#include "physical_device.h"
#include <EASTL/vector.h>
struct Context;
struct PhysicalDevice;
struct QueueAllocation
{
@ -16,14 +20,12 @@ struct QueueAllocation
struct Device final
{
using NameString = eastl::fixed_string<char, 32, false>;
NameString m_Name;
vk::PhysicalDevice m_PhysicalDevice = nullptr;
vk::Device m_Device = nullptr;
VmaAllocator m_Allocator = nullptr;
Device(const Context *context, PhysicalDevice *physicalDevice, const vk::PhysicalDeviceFeatures *enabledFeatures,
const eastl::vector<QueueAllocation> &queueAllocations, NameString name);
const eastl::vector<QueueAllocation> &queueAllocations, NameString &&name);
~Device();
};

View File

@ -60,6 +60,8 @@ toCstr(const T &val)
return buffer.c_str();
}
using NameString = eastl::fixed_string<char, 32, false>;
// TODO: Check why inline namespaces aren't working in MSVC 19.27.29110
using namespace std::literals::string_literals;
using namespace std::literals::string_view_literals;

View File

@ -5,53 +5,68 @@
#include "physical_device.h"
#include "context.h"
#include "window.h"
[[nodiscard]] vk::SurfaceCapabilitiesKHR
GetSurfaceCapabilities(const vk::PhysicalDevice physicalDevice, const vk::SurfaceKHR surface)
{
vk::SurfaceCapabilitiesKHR surfaceCapabilities;
vk::Result result = physicalDevice.getSurfaceCapabilitiesKHR(surface, &surfaceCapabilities);
ERROR_IF(failed(result), "Fetching surface capabilities failed. Cause: {}", result)
THEN_ABORT(result);
return surfaceCapabilities;
}
[[nodiscard]] eastl::vector<vk::SurfaceFormatKHR>
getSurfaceFormats(const vk::SurfaceKHR surface, const vk::PhysicalDevice physicalDevice)
GetSurfaceFormats(const vk::PhysicalDevice physicalDevice, const vk::SurfaceKHR surface)
{
// vk::Result::eIncomplete should not occur in this function. The rest are errors. Thus, abort is allowed.
u32 count = 0;
vk::Result result = physicalDevice.getSurfaceFormatsKHR(surface, &count, nullptr);
ERROR_IF(failed(result), "Could not get surface formats. Cause: {}", to_string(result))
ERROR_IF(failed(result), "Could not get surface formats. Cause: {}", result)
THEN_ABORT(result);
eastl::vector<vk::SurfaceFormatKHR> surfaceFormats(count);
result = physicalDevice.getSurfaceFormatsKHR(surface, &count, surfaceFormats.data());
ERROR_IF(failed(result), "Could not get surface formats. Cause: {}", to_string(result))
ERROR_IF(failed(result), "Could not get surface formats. Cause: {}", result)
THEN_ABORT(result);
return surfaceFormats;
}
[[nodiscard]] eastl::vector<vk::PresentModeKHR>
getSurfacePresentModes(const vk::SurfaceKHR surface, const vk::PhysicalDevice physicalDevice)
GetSurfacePresentModes(const vk::PhysicalDevice physicalDevice, const vk::SurfaceKHR surface)
{
// vk::Result::eIncomplete should not occur in this function. The rest are errors. Thus, abort is allowed.
u32 count = 0;
vk::Result result = physicalDevice.getSurfacePresentModesKHR(surface, &count, nullptr);
ERROR_IF(failed(result), "Could not get present modes. Cause: {}", to_string(result))
ERROR_IF(failed(result), "Could not get present modes. Cause: {}", result)
THEN_ABORT(result);
eastl::vector<vk::PresentModeKHR> presentModes(count);
result = physicalDevice.getSurfacePresentModesKHR(surface, &count, presentModes.data());
ERROR_IF(failed(result), "Could not get present modes. Cause: {}", to_string(result))
ERROR_IF(failed(result), "Could not get present modes. Cause: {}", result)
THEN_ABORT(result);
return presentModes;
}
[[nodiscard]] bool
getQueuePresentSupport(const u32 queueFamilyIndex, vk::SurfaceKHR surface, const vk::PhysicalDevice physicalDevice)
GetQueuePresentSupport(const u32 queueFamilyIndex, vk::SurfaceKHR surface, const vk::PhysicalDevice physicalDevice)
{
b32 supported = false;
const vk::Result result = physicalDevice.getSurfaceSupportKHR(queueFamilyIndex, surface, &supported);
ERROR_IF(failed(result), "Could not get queue family surface support. Cause: {}", to_string(result))
ERROR_IF(failed(result), "Could not get queue family surface support. Cause: {}", result)
THEN_ABORT(result);
return supported;
}
[[nodiscard]] eastl::fixed_vector<vk::QueueFamilyProperties, 32>
getQueueFamilyProperties(const vk::PhysicalDevice physicalDevice)
GetQueueFamilyProperties(const vk::PhysicalDevice physicalDevice)
{
// Devices rarely have more than 32 queue families. Thus fixed vector
u32 count = 0;
@ -65,10 +80,10 @@ getQueueFamilyProperties(const vk::PhysicalDevice physicalDevice)
// Size 384 return.
[[nodiscard]] eastl::vector<QueueFamilyInfo>
getQueueFamilies(const vk::SurfaceKHR surface, const vk::PhysicalDevice physicalDevice)
GetQueueFamilies(const vk::SurfaceKHR surface, const vk::PhysicalDevice physicalDevice)
{
auto queueFamilyProperties = getQueueFamilyProperties(physicalDevice);
auto queueFamilyProperties = GetQueueFamilyProperties(physicalDevice);
eastl::vector<QueueFamilyInfo> queueFamilyInfos;
queueFamilyInfos.reserve(queueFamilyProperties.size());
@ -93,7 +108,7 @@ getQueueFamilies(const vk::SurfaceKHR surface, const vk::PhysicalDevice physical
support |= QueueSupportFlagBits::eCompute;
}
if (getQueuePresentSupport(familyIndex, surface, physicalDevice))
if (GetQueuePresentSupport(familyIndex, surface, physicalDevice))
{
support |= QueueSupportFlagBits::ePresent;
}
@ -115,24 +130,24 @@ PhysicalDevice::PhysicalDevice(const vk::SurfaceKHR surface, const vk::PhysicalD
physicalDevice.getProperties(&m_DeviceProperties);
physicalDevice.getFeatures(&m_DeviceFeatures);
m_SurfaceFormats = getSurfaceFormats(surface, physicalDevice);
m_PresentModes = getSurfacePresentModes(surface, physicalDevice);
m_QueueFamilies = getQueueFamilies(surface, physicalDevice);
m_SurfaceFormats = GetSurfaceFormats(physicalDevice, surface);
m_PresentModes = GetSurfacePresentModes(physicalDevice, surface);
m_QueueFamilies = GetQueueFamilies(surface, physicalDevice);
m_PhysicalDevice = physicalDevice;
}
eastl::fixed_vector<vk::PhysicalDevice, 8>
enumeratePhysicalDevices(const vk::Instance instance)
EnumeratePhysicalDevices(const vk::Instance instance)
{
u32 count = 0;
vk::Result result = instance.enumeratePhysicalDevices(&count, nullptr);
ERROR_IF(failed(result), "Could not fetch vulkan devices. Cause: {}", to_string(result))
ERROR_IF(failed(result), "Could not fetch vulkan devices. Cause: {}", result)
THEN_ABORT(result);
eastl::fixed_vector<vk::PhysicalDevice, 8> physicalDevices(count);
result = instance.enumeratePhysicalDevices(&count, physicalDevices.data());
ERROR_IF(failed(result), "Could not fetch vulkan devices. Cause: {}", to_string(result))
ERROR_IF(failed(result), "Could not fetch vulkan devices. Cause: {}", result)
THEN_ABORT(result);
return physicalDevices;
@ -141,7 +156,7 @@ enumeratePhysicalDevices(const vk::Instance instance)
PhysicalDevices::PhysicalDevices(const Window *window, const Context *context)
{
auto surface = window->m_Surface;
auto physicalDevices = enumeratePhysicalDevices(context->m_Instance);
auto physicalDevices = EnumeratePhysicalDevices(context->m_Instance);
for (auto physicalDevice : physicalDevices)
{
this->emplace_back(surface, physicalDevice);

View File

@ -6,9 +6,11 @@
#pragma once
#include "global.h"
#include "window.h"
#include <EASTL/fixed_vector.h>
struct Window;
struct Context;
enum class QueueSupportFlagBits
{
eGraphics = 0b0001,
@ -26,6 +28,15 @@ struct QueueFamilyInfo
QueueSupportFlags m_Support;
};
[[nodiscard]] vk::SurfaceCapabilitiesKHR
GetSurfaceCapabilities(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface);
[[nodiscard]] eastl::vector<vk::SurfaceFormatKHR>
GetSurfaceFormats(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface);
[[nodiscard]] eastl::vector<vk::PresentModeKHR>
GetSurfacePresentModes(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface);
struct PhysicalDevice
{
vk::PhysicalDevice m_PhysicalDevice;

111
aster/swapchain.cpp Normal file
View File

@ -0,0 +1,111 @@
/// =============================================
// Aster: swapchain.cpp
// Copyright (c) 2020-2024 Anish Bhobe
// ==============================================
#include "swapchain.h"
#include "device.h"
#include "physical_device.h"
#include "window.h"
Swapchain::Swapchain(const Window *window, const Device *device, NameString &&name)
: m_Device(device)
, m_Name(std::move(name))
{
this->Create(window);
}
Swapchain::~Swapchain()
{
if (m_Swapchain)
{
m_Device->m_Device.destroy(m_Swapchain, nullptr);
m_Swapchain = nullptr;
DEBUG("Swapchain '{}' destroyed.", m_Name);
}
}
void
Swapchain::Create(const Window *window)
{
auto surfaceCapabilities = GetSurfaceCapabilities(m_Device->m_PhysicalDevice, window->m_Surface);
auto surfaceFormats = GetSurfaceFormats(m_Device->m_PhysicalDevice, window->m_Surface);
auto presentModes = GetSurfacePresentModes(m_Device->m_PhysicalDevice, window->m_Surface);
vk::Format swapchainFormat = vk::Format::eUndefined;
vk::ColorSpaceKHR swapchainColorSpace = vk::ColorSpaceKHR::eSrgbNonlinear;
for (auto [format, colorSpace] : surfaceFormats)
{
if (format == vk::Format::eB8G8R8A8Srgb && colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear)
{
swapchainFormat = format;
swapchainColorSpace = colorSpace;
}
}
if (swapchainFormat == vk::Format::eUndefined)
{
WARN("Preferred Swapchain format not found. Falling back.");
auto surfaceFormat = surfaceFormats.front();
swapchainFormat = surfaceFormat.format;
swapchainColorSpace = surfaceFormat.colorSpace;
}
vk::PresentModeKHR swapchainPresentMode = vk::PresentModeKHR::eFifo;
for (auto presentMode : presentModes)
{
if (presentMode == vk::PresentModeKHR::eMailbox)
{
swapchainPresentMode = presentMode;
break;
}
}
vk::Extent2D swapchainExtent;
if (surfaceCapabilities.currentExtent.width != MaxValue<u32>)
{
swapchainExtent = surfaceCapabilities.currentExtent;
}
else
{
vk::Extent2D extent = window->GetSize();
vk::Extent2D minExtent = surfaceCapabilities.minImageExtent;
vk::Extent2D maxExtent = surfaceCapabilities.maxImageExtent;
swapchainExtent.width = glm::clamp(extent.width, minExtent.width, maxExtent.width);
swapchainExtent.height = glm::clamp(extent.height, minExtent.height, maxExtent.height);
}
u32 swapchainImageCount = 3;
if (surfaceCapabilities.maxImageCount > 0)
{
swapchainImageCount =
glm::clamp(swapchainImageCount, surfaceCapabilities.minImageCount, surfaceCapabilities.maxImageCount);
}
// TODO: Note that different queues might need the images to be shared.
const vk::SwapchainCreateInfoKHR swapchainCreateInfo = {
.surface = window->m_Surface,
.minImageCount = swapchainImageCount,
.imageFormat = swapchainFormat,
.imageColorSpace = swapchainColorSpace,
.imageExtent = swapchainExtent,
.imageArrayLayers = 1,
.imageUsage = vk::ImageUsageFlagBits::eColorAttachment,
.imageSharingMode = vk::SharingMode::eExclusive,
.preTransform = surfaceCapabilities.currentTransform,
.compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque,
.presentMode = swapchainPresentMode,
.clipped = true,
.oldSwapchain = m_Swapchain,
};
vk::SwapchainKHR swapchain;
vk::Result result = m_Device->m_Device.createSwapchainKHR(&swapchainCreateInfo, nullptr, &swapchain);
ERROR_IF(failed(result), "Swapchain {} creation failed. Cause {}", m_Name, result)
THEN_ABORT(result)
ELSE_DEBUG("Created Swapchain '{}'", m_Name);
m_Swapchain = swapchain;
}

23
aster/swapchain.h Normal file
View File

@ -0,0 +1,23 @@
/// =============================================
// Aster: swapchain.h
// Copyright (c) 2020-2024 Anish Bhobe
// ==============================================
#pragma once
#include "global.h"
struct PhysicalDevice;
struct Window;
struct Device;
struct Swapchain final
{
const Device *m_Device;
vk::SwapchainKHR m_Swapchain;
NameString m_Name;
Swapchain(const Window *window, const Device *device, NameString &&name);
~Swapchain();
void Create(const Window *window);
};

View File

@ -4,6 +4,7 @@
// =============================================
#include "window.h"
#include "context.h"
#include "glfw_context.h"
#include "logger.h"
@ -20,6 +21,15 @@ Window::SetWindowSize(const u32 width, const u32 height) const noexcept
glfwSetWindowSize(m_Window, cast<i32>(width), cast<i32>(height));
}
vk::Extent2D
Window::GetSize() const
{
int width;
int height;
glfwGetWindowSize(m_Window, &width, &height);
return {cast<u32>(width), cast<u32>(height)};
}
Window::Window(cstr title, Context *context, vk::Extent2D extent, b8 isFullScreen)
{
m_Context = context;
@ -37,7 +47,7 @@ Window::Window(cstr title, Context *context, vk::Extent2D extent, b8 isFullScree
m_Window = glfwCreateWindow(cast<i32>(extent.width), cast<i32>(extent.height), m_Name.c_str(),
isFullScreen ? monitor : nullptr, nullptr);
ERROR_IF(m_Window == nullptr, "Window creation failed")
ELSE_DEBUG("Window '{}' created with resolution '{}x{}'", m_Name.c_str(), extent.width, extent.height);
ELSE_DEBUG("Window '{}' created with resolution '{}x{}'", m_Name, extent.width, extent.height);
if (m_Window == nullptr)
{
auto code = GlfwContext::PostError();
@ -55,9 +65,9 @@ Window::Window(cstr title, Context *context, vk::Extent2D extent, b8 isFullScree
VkSurfaceKHR surface;
auto result =
cast<vk::Result>(glfwCreateWindowSurface(cast<VkInstance>(m_Context->m_Instance), m_Window, nullptr, &surface));
ERROR_IF(failed(result), "Failed to create Surface with {}", to_string(result))
ERROR_IF(failed(result), "Failed to create Surface with {}", result)
THEN_ABORT(result)
ELSE_DEBUG("Surface {} Created", m_Name.c_str());
ELSE_DEBUG("Surface {} Created", m_Name);
m_Surface = vk::SurfaceKHR(surface);
}
@ -75,5 +85,5 @@ Window::~Window()
m_Window = nullptr;
}
DEBUG("Window '{}' Destroyed", m_Name.c_str());
DEBUG("Window '{}' Destroyed", m_Name);
}

View File

@ -5,10 +5,11 @@
#pragma once
#include "context.h"
#include "global.h"
#include <EASTL/fixed_string.h>
struct Context;
struct Window final
{
// fields
@ -28,6 +29,7 @@ struct Window final
void SetWindowSize(const vk::Extent2D &extent) const noexcept;
void SetWindowSize(u32 width, u32 height) const noexcept;
[[nodiscard]] vk::Extent2D GetSize() const;
// Ctor/Dtor
Window(cstr title, Context *context, vk::Extent2D extent, b8 isFullScreen = false);

View File

@ -1,10 +1,12 @@
#include "aster/constants.h"
#include "aster/context.h"
#include "aster/device.h"
#include "aster/glfw_context.h"
#include "aster/physical_device.h"
#include "aster/window.h"
#include "aster/global.h"
#include "aster/swapchain.h"
constexpr QueueSupportFlags REQUIRED_QUEUE_SUPPORT = QueueSupportFlags{} | QueueSupportFlagBits::eGraphics |
QueueSupportFlagBits::eCompute | QueueSupportFlagBits::ePresent |
@ -62,7 +64,7 @@ findAppropriateQueueAllocation(const PhysicalDevice *physicalDevice)
int
main(int, char **)
{
MIN_LOG_LEVEL(Logger::LogType::eInfo);
MIN_LOG_LEVEL(Logger::LogType::eDebug);
GlfwContext glfwContext = {};
Context context = {"Aster", VERSION};
@ -78,6 +80,8 @@ main(int, char **)
Device device = {&context, &deviceToUse, &features, {queueAllocation}, "Primary Device"};
Swapchain swapchain = {&window, &device, "Primary Chain"};
while (window.Poll())
{
}