diff --git a/CMakeLists.txt b/CMakeLists.txt index aeb8a3c..a616bc9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,4 +21,5 @@ include(add_shader.cmake) include(add_resource_dir.cmake) add_subdirectory("aster") -add_subdirectory("samples") +add_subdirectory("scratch") +# add_subdirectory("samples") diff --git a/aster/CMakeLists.txt b/aster/CMakeLists.txt index 9e95315..ccb8346 100644 --- a/aster/CMakeLists.txt +++ b/aster/CMakeLists.txt @@ -22,7 +22,10 @@ set(HEADER_FILES swapchain.h pipeline.h queue_allocation.h - buffer.h) + buffer.h + size.h + image.h + surface.h) set(SOURCE_FILES logger.cpp @@ -35,7 +38,7 @@ set(SOURCE_FILES pipeline.cpp buffer.cpp image.cpp - image.h) + surface.cpp) add_library(aster_core STATIC ${SOURCE_FILES} ${HEADER_FILES}) set_property(TARGET aster_core PROPERTY CXX_STANDARD 20) diff --git a/aster/buffer.cpp b/aster/buffer.cpp index d24b918..d3dcdfc 100644 --- a/aster/buffer.cpp +++ b/aster/buffer.cpp @@ -49,13 +49,13 @@ Buffer::Allocate(const Device *device, usize size, vk::BufferUsageFlags bufferUs m_Buffer = buffer; m_Size_ = size | VALID_BUFFER_BIT | OWNED_BIT; m_Allocation = allocation; - m_Mapped = Cast(allocationInfo.pMappedData); + m_Mapped = hostAccessible ? Cast(allocationInfo.pMappedData) : nullptr; device->SetName(m_Buffer, name); } uptr -Buffer::GetDeviceAddress(const Device *device) +Buffer::GetDeviceAddress(const Device *device) const { vk::BufferDeviceAddressInfo addressInfo = {.buffer = m_Buffer}; return device->m_Device.getBufferAddress(&addressInfo); diff --git a/aster/buffer.h b/aster/buffer.h index 45075d3..16685f2 100644 --- a/aster/buffer.h +++ b/aster/buffer.h @@ -32,7 +32,7 @@ struct Buffer VmaAllocationCreateFlags allocationFlags, VmaMemoryUsage memoryUsage, cstr name); uptr - GetDeviceAddress(const Device *device); + GetDeviceAddress(const Device *device) const; // Buffer.size is used for bookkeeping // If the buffer is Invalid, the remaining data in Buffer is used intrusively by `GpuResourceManager`. diff --git a/aster/context.cpp b/aster/context.cpp index 212ca52..8784279 100644 --- a/aster/context.cpp +++ b/aster/context.cpp @@ -38,18 +38,11 @@ DebugCallback(const VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, return false; } -Context::Context(const cstr appName, const Version version, bool enableValidation) +void +Context::Init(const cstr appName, const Version version, bool enableValidation) { INFO_IF(enableValidation, "Validation Layers enabled"); - if (!glfwInit()) - { - const char *error = nullptr; - const auto code = glfwGetError(&error); - ERROR("GLFW Init failed. Cause: ({}) {}", code, error) - THEN_ABORT(code); - } - // TODO Get/Check API Version // Creating Instance @@ -110,8 +103,12 @@ Context::Context(const cstr appName, const Version version, bool enableValidatio } } -Context::~Context() +void +Context::Destroy() { + if (!m_Instance) + return; + if (m_DebugMessenger) { m_Instance.destroy(m_DebugMessenger, nullptr); @@ -120,21 +117,12 @@ Context::~Context() m_Instance.destroy(nullptr); DEBUG("Instance destroyed"); - glfwTerminate(); + m_DebugMessenger = nullptr; + m_Instance = nullptr; } -Context::Context(Context &&other) noexcept - : m_Instance(Take(other.m_Instance)) - , m_DebugMessenger(Take(other.m_DebugMessenger)) +bool +Context::IsInDebugMode() const { -} - -Context & -Context::operator=(Context &&other) noexcept -{ - if (this == &other) - return *this; - m_Instance = Take(other.m_Instance); - m_DebugMessenger = Take(other.m_DebugMessenger); - return *this; + return m_DebugMessenger != nullptr; } diff --git a/aster/context.h b/aster/context.h index b17d00f..0b31e86 100644 --- a/aster/context.h +++ b/aster/context.h @@ -5,6 +5,7 @@ #pragma once +#include "device.h" #include "global.h" /** @@ -17,22 +18,21 @@ struct Context final { // Members - vk::Instance m_Instance = nullptr; - vk::DebugUtilsMessengerEXT m_DebugMessenger = nullptr; + vk::Instance m_Instance; + vk::DebugUtilsMessengerEXT m_DebugMessenger; // Ctor/Dtor - Context(cstr appName, Version version, bool enableValidation = ENABLE_VALIDATION_DEFAULT_VALUE); - ~Context(); + void Init(cstr appName, Version version, bool enableValidation = ENABLE_VALIDATION_DEFAULT_VALUE); + void Destroy(); - // Move - Context(Context &&other) noexcept; - Context &operator=(Context &&other) noexcept; + [[nodiscard]] bool IsInDebugMode() const; #if !defined(ASTER_NDEBUG) constexpr static bool ENABLE_VALIDATION_DEFAULT_VALUE = true; #else constexpr static bool ENABLE_VALIDATION_DEFAULT_VALUE = false; #endif - - DISALLOW_COPY_AND_ASSIGN(Context); }; + +static_assert(std::is_trivially_copyable_v); +static_assert(std::is_trivially_copy_assignable_v); \ No newline at end of file diff --git a/aster/device.cpp b/aster/device.cpp index e6157f0..1f3f537 100644 --- a/aster/device.cpp +++ b/aster/device.cpp @@ -17,19 +17,22 @@ constexpr eastl::array DEVICE_EXTENSIONS = { VK_KHR_SWAPCHAIN_EXTENSION_NAME, }; -Device::Device(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures, - const eastl::vector &queueAllocations, NameString &&name) - : Device(context, physicalDevice, enabledFeatures, queueAllocations, {}, std::move(name)) +void +Device::Init(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures, + const eastl::vector &queueAllocations, cstr name) { + this->Init(context, physicalDevice, enabledFeatures, queueAllocations, {}, name); } -Device::Device(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures, - const eastl::vector &queueAllocations, eastl::span &&pipelineCacheData, - NameString &&name) - : m_Name(std::move(name)) - , m_PhysicalDevice(physicalDevice->m_PhysicalDevice) - , m_ValidationEnabled(context->m_DebugMessenger != nullptr) +void +Device::Init(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures, + const eastl::vector &queueAllocations, const eastl::span &pipelineCacheData, + cstr name) { + assert(!m_Device); + + m_PhysicalDevice = physicalDevice->m_PhysicalDevice; + m_ValidationEnabled = context->IsInDebugMode(); // Shouldn't have more than 4 deviceQueueFamilies in use anyway. Else we can heap eastl::fixed_vector deviceQueueCreateInfos; deviceQueueCreateInfos.reserve(queueAllocations.size()); @@ -71,9 +74,9 @@ Device::Device(const Context *context, PhysicalDevice *physicalDevice, Features 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()); + ELSE_DEBUG("{} ({}) Initialized.", name, physicalDevice->m_DeviceProperties.deviceName.data()); - SetName(m_Device, m_Name.data()); + SetName(m_Device, name); VmaVulkanFunctions vmaVulkanFunctions = { .vkGetInstanceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetInstanceProcAddr, @@ -105,11 +108,15 @@ Device::Device(const Context *context, PhysicalDevice *physicalDevice, Features THEN_ABORT(result) ELSE_VERBOSE("Pipeline Cache created."); - DEBUG("Created Device '{}' Successfully", m_Name); + DEBUG("Created Device '{}' Successfully", name); } -Device::~Device() +void +Device::Destroy() { + if (!m_Device) + return; + m_Device.destroy(m_PipelineCache, nullptr); if (m_Allocator) { @@ -118,8 +125,11 @@ Device::~Device() DEBUG("Memory Allocator Destroyed"); } m_Device.destroy(nullptr); - DEBUG("Device '{}' Destroyed", m_Name); + DEBUG("Device Destroyed"); + + m_Allocator = nullptr; m_PhysicalDevice = nullptr; + m_Device = nullptr; } vk::Queue @@ -150,23 +160,3 @@ Device::WaitIdle() const ERROR_IF(Failed(deviceIdleResult), "Device Idling Failed. Cause: {}", deviceIdleResult) THEN_ABORT(deviceIdleResult); } - -Device::Device(Device &&other) noexcept - : m_Name(std::move(other.m_Name)) - , m_PhysicalDevice(Take(other.m_PhysicalDevice)) - , m_Device(Take(other.m_Device)) - , m_Allocator(Take(other.m_Allocator)) -{ -} - -Device & -Device::operator=(Device &&other) noexcept -{ - if (this == &other) - return *this; - m_Name = std::move(other.m_Name); - m_PhysicalDevice = Take(other.m_PhysicalDevice); - m_Device = Take(other.m_Device); - m_Allocator = Take(other.m_Allocator); - return *this; -} \ No newline at end of file diff --git a/aster/device.h b/aster/device.h index f3ad2d2..7499ab3 100644 --- a/aster/device.h +++ b/aster/device.h @@ -24,7 +24,6 @@ struct Features struct Device final { - NameString m_Name; vk::PhysicalDevice m_PhysicalDevice = nullptr; vk::Device m_Device = nullptr; VmaAllocator m_Allocator = nullptr; @@ -40,17 +39,11 @@ struct Device final void WaitIdle() const; // Ctor/Dtor - Device(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures, - const eastl::vector &queueAllocations, NameString &&name); - Device(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures, - const eastl::vector &queueAllocations, eastl::span &&pipelineCacheData, NameString &&name); - ~Device(); - - // Move - Device(Device &&other) noexcept; - Device &operator=(Device &&other) noexcept; - - DISALLOW_COPY_AND_ASSIGN(Device); + void Init(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures, + const eastl::vector &queueAllocations, cstr name); + void Init(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures, + const eastl::vector &queueAllocations, const eastl::span &pipelineCacheData, cstr name); + void Destroy(); }; template diff --git a/aster/physical_device.cpp b/aster/physical_device.cpp index 1c25af3..7bdce74 100644 --- a/aster/physical_device.cpp +++ b/aster/physical_device.cpp @@ -6,7 +6,8 @@ #include "physical_device.h" #include "context.h" -#include "window.h" +#include "queue_allocation.h" +#include "surface.h" [[nodiscard]] vk::SurfaceCapabilitiesKHR GetSurfaceCapabilities(const vk::PhysicalDevice physicalDevice, const vk::SurfaceKHR surface) @@ -138,6 +139,24 @@ PhysicalDevice::PhysicalDevice(const vk::SurfaceKHR surface, const vk::PhysicalD m_PhysicalDevice = physicalDevice; } +QueueAllocation +PhysicalDevice::FindAppropriateQueueAllocation() +{ + + for (auto &queueFamilyInfo : this->m_QueueFamilies) + { + if ((queueFamilyInfo.m_Support & REQUIRED_QUEUE_SUPPORT) == REQUIRED_QUEUE_SUPPORT) + { + return { + .m_Family = queueFamilyInfo.m_Index, + .m_Count = queueFamilyInfo.m_Count, + }; + } + } + ERROR("No suitable queue family on the GPU.") + THEN_ABORT(vk::Result::eErrorUnknown); +} + eastl::fixed_vector EnumeratePhysicalDevices(const vk::Instance instance) { @@ -154,12 +173,44 @@ EnumeratePhysicalDevices(const vk::Instance instance) return physicalDevices; } -PhysicalDevices::PhysicalDevices(const Window *window, const Context *context) +PhysicalDevices::PhysicalDevices(const Surface *surface, const Context *context) { - auto surface = window->m_Surface; + auto surfaceImpl = surface->m_Surface; auto physicalDevices = EnumeratePhysicalDevices(context->m_Instance); for (auto physicalDevice : physicalDevices) { - this->emplace_back(surface, physicalDevice); + this->emplace_back(surfaceImpl, physicalDevice); } } + +bool +IsSuitableDevice(const PhysicalDevice *physicalDevice) +{ + const bool hasAllRequiredQueues = + std::ranges::any_of(physicalDevice->m_QueueFamilies, [](const auto &queueFamilyProp) { + return (queueFamilyProp.m_Support & REQUIRED_QUEUE_SUPPORT) == REQUIRED_QUEUE_SUPPORT; + }); + + const bool isNotCpu = physicalDevice->m_DeviceProperties.deviceType != vk::PhysicalDeviceType::eCpu; + + const bool hasPresentMode = !physicalDevice->m_PresentModes.empty(); + + const bool hasSurfaceFormat = !physicalDevice->m_SurfaceFormats.empty(); + + return hasSurfaceFormat && hasPresentMode && isNotCpu && hasAllRequiredQueues; +} + +PhysicalDevice +PhysicalDevices::FindSuitableDevice() +{ + for (auto &physicalDevice : *this) + { + if (IsSuitableDevice(&physicalDevice)) + { + return physicalDevice; + } + } + + ERROR("No suitable GPU available on the system.") + THEN_ABORT(vk::Result::eErrorUnknown); +} \ No newline at end of file diff --git a/aster/physical_device.h b/aster/physical_device.h index 5f8e828..8642c6b 100644 --- a/aster/physical_device.h +++ b/aster/physical_device.h @@ -8,6 +8,8 @@ #include "global.h" #include +struct QueueAllocation; +struct Surface; struct Window; struct Context; @@ -47,10 +49,22 @@ struct PhysicalDevice final eastl::vector m_QueueFamilies; PhysicalDevice(vk::SurfaceKHR surface, vk::PhysicalDevice physicalDevice); + QueueAllocation FindAppropriateQueueAllocation(); }; -class PhysicalDevices : public eastl::fixed_vector +class PhysicalDevices : public eastl::vector { public: - PhysicalDevices(const Window *window, const Context *context); -}; \ No newline at end of file + PhysicalDevices(const Surface *surface, const Context *context); + PhysicalDevice FindSuitableDevice(); +}; + +constexpr QueueSupportFlags REQUIRED_QUEUE_SUPPORT = QueueSupportFlags{} | QueueSupportFlagBits::eGraphics | + QueueSupportFlagBits::eCompute | QueueSupportFlagBits::ePresent | + QueueSupportFlagBits::eTransfer; + +bool +IsSuitableDevice(const vk::PhysicalDevice physicalDevice); + +PhysicalDevice +FindSuitableDevice(const PhysicalDevices &physicalDevices); diff --git a/aster/size.h b/aster/size.h new file mode 100644 index 0000000..7ec5f5c --- /dev/null +++ b/aster/size.h @@ -0,0 +1,25 @@ +// ============================================= +// Aster: size.h +// Copyright (c) 2020-2024 Anish Bhobe +// ============================================= + +#pragma once + +#include "global.h" + +struct Size +{ + u32 m_Width; + u32 m_Height; + + operator vk::Extent2D() const + { + return {m_Width, m_Height}; + } + + glm::vec<2, u32> + ToVec() + { + return {m_Width, m_Height}; + } +}; \ No newline at end of file diff --git a/aster/surface.cpp b/aster/surface.cpp new file mode 100644 index 0000000..8994198 --- /dev/null +++ b/aster/surface.cpp @@ -0,0 +1,33 @@ +// ============================================= +// Aster: surface.cpp +// Copyright (c) 2020-2024 Anish Bhobe +// ============================================= + +#include "surface.h" + +#include "context.h" +#include "window.h" + +void +Surface::Init(Context *context, const Window *window) +{ + assert(!m_Surface); + + VkSurfaceKHR surface; + auto result = Cast( + glfwCreateWindowSurface(Cast(context->m_Instance), window->m_Window, nullptr, &surface)); + ERROR_IF(Failed(result), "Failed to create Surface with {}", result) + THEN_ABORT(result) + ELSE_DEBUG("Surface Created"); + m_Surface = vk::SurfaceKHR(surface); +} + +void +Surface::Destroy(const Context *context) +{ + if (!m_Surface) + return; + + context->m_Instance.destroy(Take(m_Surface), nullptr); + DEBUG("Surface Destroyed"); +} diff --git a/aster/surface.h b/aster/surface.h new file mode 100644 index 0000000..65b0b54 --- /dev/null +++ b/aster/surface.h @@ -0,0 +1,19 @@ +// ============================================= +// Aster: surface.h +// Copyright (c) 2020-2024 Anish Bhobe +// ============================================= + +#pragma once + +#include "global.h" + +struct Context; +struct Window; + +struct Surface +{ + vk::SurfaceKHR m_Surface; + + void Init(Context *context, const Window *window); + void Destroy(const Context *context); +}; \ No newline at end of file diff --git a/aster/swapchain.cpp b/aster/swapchain.cpp index 57ff233..82ed652 100644 --- a/aster/swapchain.cpp +++ b/aster/swapchain.cpp @@ -7,64 +7,32 @@ #include "device.h" #include "physical_device.h" -#include "window.h" +#include "surface.h" -[[nodiscard]] vk::Extent2D GetExtent(const Window *window, vk::SurfaceCapabilitiesKHR *surfaceCapabilities); +[[nodiscard]] vk::Extent2D GetExtent(Size size, vk::SurfaceCapabilitiesKHR *surfaceCapabilities); -Swapchain::Swapchain(const Window *window, const Device *device, NameString &&name) - : m_Device(device) - , m_Name(std::move(name)) - , m_Format(vk::Format::eUndefined) +void +Swapchain::Init(const Surface *surface, const Device *device, Size size, cstr name) { - this->Create(window); -} - -Swapchain::~Swapchain() -{ - this->Cleanup(); -} - -Swapchain::Swapchain(Swapchain &&other) noexcept - : m_Device(other.m_Device) - , m_Swapchain(Take(other.m_Swapchain)) - , m_Name(std::move(other.m_Name)) - , m_Extent(other.m_Extent) - , m_Format(other.m_Format) - , m_Images(std::move(other.m_Images)) - , m_ImageViews(std::move(other.m_ImageViews)) -{ -} - -Swapchain & -Swapchain::operator=(Swapchain &&other) noexcept -{ - if (this == &other) - return *this; - m_Device = other.m_Device; - m_Swapchain = Take(other.m_Swapchain); - m_Name = std::move(other.m_Name); - m_Extent = other.m_Extent; - m_Format = other.m_Format; - m_Images = std::move(other.m_Images); - m_ImageViews = std::move(other.m_ImageViews); - return *this; + assert(!m_Swapchain); + this->Create(surface, device, size, name); } void -Swapchain::Create(const Window *window) +Swapchain::Create(const Surface *surface, const Device *device, Size size, cstr name) { - auto surfaceCapabilities = GetSurfaceCapabilities(m_Device->m_PhysicalDevice, window->m_Surface); - m_Extent = GetExtent(window, &surfaceCapabilities); + auto surfaceCapabilities = GetSurfaceCapabilities(device->m_PhysicalDevice, surface->m_Surface); + m_Extent = GetExtent(size, &surfaceCapabilities); while (m_Extent.width == 0 || m_Extent.height == 0) { glfwWaitEvents(); - surfaceCapabilities = GetSurfaceCapabilities(m_Device->m_PhysicalDevice, window->m_Surface); - m_Extent = GetExtent(window, &surfaceCapabilities); + surfaceCapabilities = GetSurfaceCapabilities(device->m_PhysicalDevice, surface->m_Surface); + m_Extent = GetExtent(size, &surfaceCapabilities); } - auto surfaceFormats = GetSurfaceFormats(m_Device->m_PhysicalDevice, window->m_Surface); - auto presentModes = GetSurfacePresentModes(m_Device->m_PhysicalDevice, window->m_Surface); + auto surfaceFormats = GetSurfaceFormats(device->m_PhysicalDevice, surface->m_Surface); + auto presentModes = GetSurfacePresentModes(device->m_PhysicalDevice, surface->m_Surface); m_Format = vk::Format::eUndefined; vk::ColorSpaceKHR swapchainColorSpace = vk::ColorSpaceKHR::eSrgbNonlinear; @@ -104,7 +72,7 @@ Swapchain::Create(const Window *window) // TODO: Note that different queues might need the images to be shared. const vk::SwapchainCreateInfoKHR swapchainCreateInfo = { - .surface = window->m_Surface, + .surface = surface->m_Surface, .minImageCount = swapchainImageCount, .imageFormat = m_Format, .imageColorSpace = swapchainColorSpace, @@ -119,29 +87,29 @@ Swapchain::Create(const Window *window) .oldSwapchain = m_Swapchain, }; - vk::Device device = m_Device->m_Device; + vk::Device vkDevice = device->m_Device; vk::SwapchainKHR swapchain; - vk::Result result = device.createSwapchainKHR(&swapchainCreateInfo, nullptr, &swapchain); - ERROR_IF(Failed(result), "Swapchain {} creation failed. Cause {}", m_Name, result) + vk::Result result = vkDevice.createSwapchainKHR(&swapchainCreateInfo, nullptr, &swapchain); + ERROR_IF(Failed(result), "Swapchain {} creation failed. Cause {}", name, result) THEN_ABORT(result) - ELSE_DEBUG("Created Swapchain '{}'", m_Name); + ELSE_DEBUG("Created Swapchain '{}'", name); // Irrelevant on the first run. Required for re-creation. - Cleanup(); + Destroy(device); m_Swapchain = swapchain; - m_Device->SetName(m_Swapchain, m_Name.data()); + device->SetName(m_Swapchain, name); - result = device.getSwapchainImagesKHR(m_Swapchain, &swapchainImageCount, nullptr); - ERROR_IF(Failed(result), "Failed getting swapchain {}'s images. Cause {}", m_Name, result) + result = vkDevice.getSwapchainImagesKHR(m_Swapchain, &swapchainImageCount, nullptr); + ERROR_IF(Failed(result), "Failed getting swapchain {}'s images. Cause {}", name, result) THEN_ABORT(result); // Managed by the Swapchain. m_Images.resize(swapchainImageCount); - result = device.getSwapchainImagesKHR(m_Swapchain, &swapchainImageCount, m_Images.data()); - ERROR_IF(Failed(result), "Failed getting swapchain {}'s images. Cause {}", m_Name, result) + result = vkDevice.getSwapchainImagesKHR(m_Swapchain, &swapchainImageCount, m_Images.data()); + ERROR_IF(Failed(result), "Failed getting swapchain {}'s images. Cause {}", name, result) THEN_ABORT(result); vk::ImageViewCreateInfo viewCreateInfo = { @@ -164,8 +132,8 @@ Swapchain::Create(const Window *window) viewCreateInfo.image = image; vk::ImageView imageView; - result = device.createImageView(&viewCreateInfo, nullptr, &imageView); - ERROR_IF(Failed(result), "Failed creating swapchain {}'s image view [{}]. Cause {}", m_Name, index, result) + result = vkDevice.createImageView(&viewCreateInfo, nullptr, &imageView); + ERROR_IF(Failed(result), "Failed creating swapchain {}'s image view [{}]. Cause {}", name, index, result) THEN_ABORT(result); m_ImageViews.push_back(imageView); @@ -173,7 +141,7 @@ Swapchain::Create(const Window *window) ++index; } - DEBUG("Swapchain {} Image Views created.", m_Name); + DEBUG("Swapchain {} Image Views created.", name); for (auto &callback : m_ResizeCallbacks) { @@ -188,32 +156,32 @@ Swapchain::RegisterResizeCallback(FnResizeCallback &&callback) } void -Swapchain::Cleanup() +Swapchain::Destroy(const Device *device) { if (!m_ImageViews.empty()) // Don't want the condition in the logs. - DEBUG("Swapchain {} Image Views destroyed.", m_Name); + DEBUG("Swapchain Image Views destroyed."); for (const auto imageView : m_ImageViews) { - m_Device->m_Device.destroy(imageView, nullptr); + device->m_Device.destroy(imageView, nullptr); } m_ImageViews.clear(); if (m_Swapchain) { - m_Device->m_Device.destroy(m_Swapchain, nullptr); + device->m_Device.destroy(m_Swapchain, nullptr); m_Swapchain = nullptr; - DEBUG("Swapchain '{}' destroyed.", m_Name); + DEBUG("Swapchain destroyed."); } } vk::Extent2D -GetExtent(const Window *window, vk::SurfaceCapabilitiesKHR *surfaceCapabilities) +GetExtent(Size size, vk::SurfaceCapabilitiesKHR *surfaceCapabilities) { if (surfaceCapabilities->currentExtent.width != MaxValue) { return surfaceCapabilities->currentExtent; } - auto [width, height] = window->GetSize(); + auto [width, height] = size; auto [minWidth, minHeight] = surfaceCapabilities->minImageExtent; auto [maxWidth, maxHeight] = surfaceCapabilities->maxImageExtent; diff --git a/aster/swapchain.h b/aster/swapchain.h index 9ed2137..a2ab382 100644 --- a/aster/swapchain.h +++ b/aster/swapchain.h @@ -7,8 +7,11 @@ #include "global.h" +#include "size.h" + #include +struct Surface; struct PhysicalDevice; struct Window; struct Device; @@ -17,9 +20,7 @@ struct Swapchain final { using FnResizeCallback = eastl::function; - const Device *m_Device; vk::SwapchainKHR m_Swapchain; - NameString m_Name; vk::Extent2D m_Extent; vk::Format m_Format; eastl::fixed_vector m_Images; @@ -27,19 +28,10 @@ struct Swapchain final eastl::vector m_ResizeCallbacks; - void Create(const Window *window); + void Create(const Surface *surface, const Device *device, Size size, cstr name); void RegisterResizeCallback(FnResizeCallback &&callback); // Ctor/Dtor - Swapchain(const Window *window, const Device *device, NameString &&name); - ~Swapchain(); - - // Move - Swapchain(Swapchain &&other) noexcept; - Swapchain &operator=(Swapchain &&other) noexcept; - - DISALLOW_COPY_AND_ASSIGN(Swapchain); - - private: - void Cleanup(); + void Init(const Surface *surface, const Device *device, Size size, cstr name); + void Destroy(const Device *device); }; diff --git a/aster/window.cpp b/aster/window.cpp index 3198b5c..a01bc86 100644 --- a/aster/window.cpp +++ b/aster/window.cpp @@ -35,10 +35,16 @@ Window::GetSize() const return {Cast(width), Cast(height)}; } -Window::Window(const cstr title, Context *context, vk::Extent2D extent, const b8 isFullScreen) +void +Window::Init(cstr title, vk::Extent2D extent, b8 isFullScreen) { - m_Context = context; - m_Name = title; + if (!glfwInit()) + { + const char *error = nullptr; + const auto code = glfwGetError(&error); + ERROR("GLFW Init failed. Cause: ({}) {}", code, error) + THEN_ABORT(code); + } GLFWmonitor *monitor = glfwGetPrimaryMonitor(); ERROR_IF(!monitor, "No monitor found"); @@ -49,10 +55,10 @@ Window::Window(const cstr title, Context *context, vk::Extent2D extent, const b8 glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_CENTER_CURSOR, GLFW_TRUE); - m_Window = glfwCreateWindow(Cast(extent.width), Cast(extent.height), m_Name.c_str(), + m_Window = glfwCreateWindow(Cast(extent.width), Cast(extent.height), title, isFullScreen ? monitor : nullptr, nullptr); ERROR_IF(m_Window == nullptr, "Window creation failed") - ELSE_DEBUG("Window '{}' created with resolution '{}x{}'", m_Name, extent.width, extent.height); + ELSE_DEBUG("Window '{}' created with resolution '{}x{}'", title, extent.width, extent.height); if (m_Window == nullptr) { const char *error = nullptr; @@ -67,49 +73,21 @@ Window::Window(const cstr title, Context *context, vk::Extent2D extent, const b8 Cast(windowHeight - extent.height) / 2); } glfwSetInputMode(m_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - - VkSurfaceKHR surface; - auto result = - Cast(glfwCreateWindowSurface(Cast(m_Context->m_Instance), m_Window, nullptr, &surface)); - ERROR_IF(Failed(result), "Failed to create Surface with {}", result) - THEN_ABORT(result) - ELSE_DEBUG("Surface {} Created", m_Name); - m_Surface = vk::SurfaceKHR(surface); } -Window::~Window() +void +Window::Destroy() { - if (m_Context && m_Surface) - { - m_Context->m_Instance.destroy(m_Surface, nullptr); - DEBUG("Surface Destroyed"); - } + if (!m_Window) + return; - if (m_Window) - { - glfwDestroyWindow(m_Window); - m_Window = nullptr; - } + const char *title = glfwGetWindowTitle(m_Window); - DEBUG("Window '{}' Destroyed", m_Name); -} - -Window::Window(Window &&other) noexcept - : m_Context(other.m_Context) - , m_Window(Take(other.m_Window)) - , m_Surface(Take(other.m_Surface)) - , m_Name(Take(other.m_Name)) -{ -} - -Window & -Window::operator=(Window &&other) noexcept -{ - if (this == &other) - return *this; - m_Context = other.m_Context; - m_Window = Take(other.m_Window); - m_Surface = Take(other.m_Surface); - m_Name = Take(other.m_Name); - return *this; + DEBUG("Window {} Destroyed", title); + + glfwDestroyWindow(m_Window); + m_Window = nullptr; + + // Currently only one window is supported. + glfwTerminate(); } diff --git a/aster/window.h b/aster/window.h index 565b6d7..3aefe70 100644 --- a/aster/window.h +++ b/aster/window.h @@ -6,18 +6,12 @@ #pragma once #include "global.h" -#include struct Context; struct Window final { - // fields - Context *m_Context{}; - GLFWwindow *m_Window = nullptr; - vk::SurfaceKHR m_Surface; - eastl::fixed_string m_Name; // Methods [[nodiscard]] bool @@ -34,12 +28,6 @@ struct Window final [[nodiscard]] vk::Extent2D GetSize() const; // Ctor/Dtor - Window(cstr title, Context *context, vk::Extent2D extent, b8 isFullScreen = false); - ~Window(); - - // Move - Window(Window &&other) noexcept; - Window &operator=(Window &&other) noexcept; - - DISALLOW_COPY_AND_ASSIGN(Window); + void Init(cstr title, vk::Extent2D extent, b8 isFullScreen = false); + void Destroy(); }; diff --git a/scratch/CMakeLists.txt b/scratch/CMakeLists.txt new file mode 100644 index 0000000..ae6e8a7 --- /dev/null +++ b/scratch/CMakeLists.txt @@ -0,0 +1,15 @@ +# CMakeList.txt ; CMake project for Refactoring scratchwork + +cmake_minimum_required(VERSION 3.13) + +set(SOURCE_FILES "graphics.cpp") +set(HEADER_FILES "graphics.h") + +add_library(scratch STATIC ${SOURCE_FILES} ${HEADER_FILES}) + +add_executable(scratch_exe "scratch_run.cpp") + +target_link_libraries(scratch_exe PRIVATE scratch) + +target_link_libraries(scratch PRIVATE aster_core) +target_link_libraries(scratch_exe PRIVATE aster_core) diff --git a/scratch/graphics.cpp b/scratch/graphics.cpp new file mode 100644 index 0000000..46f35b7 --- /dev/null +++ b/scratch/graphics.cpp @@ -0,0 +1,25 @@ +#include "graphics.h" + +#include "physical_device.h" +#include "queue_allocation.h" + +void +Graphics::Init(const Window *window, const cstr appName, const Version version) +{ + m_Context.Init(appName, version); + m_Surface.Init(&m_Context, window); + + auto deviceToUse = PhysicalDevices(&m_Surface, &m_Context).FindSuitableDevice(); + + Features features = {}; + QueueAllocation qa = deviceToUse.FindAppropriateQueueAllocation(); + m_Device.Init(&m_Context, &deviceToUse, &features, {qa}, "Primary"); +} + +void +Graphics::Destroy() +{ + m_Device.Destroy(); + m_Surface.Destroy(&m_Context); + m_Context.Destroy(); +} \ No newline at end of file diff --git a/scratch/graphics.h b/scratch/graphics.h new file mode 100644 index 0000000..0d06590 --- /dev/null +++ b/scratch/graphics.h @@ -0,0 +1,69 @@ +// ============================================= +// Scratch: graphics.h +// Copyright (c) 2020-2024 Anish Bhobe +// ============================================= + +#pragma once + +#include "global.h" + +#include "context.h" +#include "device.h" +#include "surface.h" + +struct Window; + +struct Memory +{ + u8 *m_Data; + + u8 *m_TransientMemory; + usize m_TransientMemorySize; + + u8 *m_PermanentMemory; + usize m_PermanentMemoryRemaining; + + void Init(usize transientSize, usize permanentSize) + { + m_Data = new u8[permanentSize + transientSize]; + m_TransientMemory = m_Data + permanentSize; + m_TransientMemorySize = transientSize; + m_PermanentMemory = m_Data; + m_PermanentMemoryRemaining = permanentSize; + } + + void + Destroy() + { + delete[] Take(m_Data); + } + + template + void MakePermanent(T* &val) requires std::is_default_constructible_v + { + const usize alignment = alignof(T); + const usize size = sizeof(T); + + const usize offset = (alignment - Recast(val) % alignment) % alignment; + const usize totalSize = size + offset; + + assert(totalSize <= m_PermanentMemoryRemaining); + + u8 *block = m_PermanentMemory; + block += offset; + m_PermanentMemory += totalSize; + m_PermanentMemoryRemaining -= totalSize; + + val = Recast(block); + } +}; + +struct Graphics +{ + Context m_Context; + Surface m_Surface; + Device m_Device; + + void Init(const Window* window, const cstr appName, const Version version); + void Destroy(); +}; \ No newline at end of file diff --git a/scratch/scratch_run.cpp b/scratch/scratch_run.cpp new file mode 100644 index 0000000..4f286f5 --- /dev/null +++ b/scratch/scratch_run.cpp @@ -0,0 +1,34 @@ +// ============================================= +// Scratch: scratch_run.cpp +// Copyright (c) 2020-2024 Anish Bhobe +// ============================================= + +#include "global.h" + +#include "graphics.h" +#include "window.h" + +int +main(int argc, const char *argv[]) +{ + Memory memory; + + memory.Init(Gigabyte(4), Megabyte(128u)); + Window window; + Graphics graphics; + + window.Init("Scratch", {640, 480}); + graphics.Init(&window, "Scratch", VERSION); + + while (window.Poll()) + { + + } + + graphics.Destroy(); + window.Destroy(); + + memory.Destroy(); + + return 0; +} \ No newline at end of file