Compare commits

...

1 Commits

Author SHA1 Message Date
Anish Bhobe 31809faa75 Refactored upto a swapchain. 2025-01-15 13:36:25 +01:00
21 changed files with 417 additions and 231 deletions

View File

@ -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")

View File

@ -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)

View File

@ -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<u8 *>(allocationInfo.pMappedData);
m_Mapped = hostAccessible ? Cast<u8 *>(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);

View File

@ -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`.

View File

@ -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;
}

View File

@ -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<Context>);
static_assert(std::is_trivially_copy_assignable_v<Context>);

View File

@ -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<QueueAllocation> &queueAllocations, NameString &&name)
: Device(context, physicalDevice, enabledFeatures, queueAllocations, {}, std::move(name))
void
Device::Init(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures,
const eastl::vector<QueueAllocation> &queueAllocations, cstr name)
{
this->Init(context, physicalDevice, enabledFeatures, queueAllocations, {}, name);
}
Device::Device(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures,
const eastl::vector<QueueAllocation> &queueAllocations, eastl::span<u8> &&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<QueueAllocation> &queueAllocations, const eastl::span<u8> &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<vk::DeviceQueueCreateInfo, 4> 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;
}

View File

@ -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<QueueAllocation> &queueAllocations, NameString &&name);
Device(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures,
const eastl::vector<QueueAllocation> &queueAllocations, eastl::span<u8> &&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<QueueAllocation> &queueAllocations, cstr name);
void Init(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures,
const eastl::vector<QueueAllocation> &queueAllocations, const eastl::span<u8> &pipelineCacheData, cstr name);
void Destroy();
};
template <typename T>

View File

@ -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<vk::PhysicalDevice, 8>
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);
}

View File

@ -8,6 +8,8 @@
#include "global.h"
#include <EASTL/fixed_vector.h>
struct QueueAllocation;
struct Surface;
struct Window;
struct Context;
@ -47,10 +49,22 @@ struct PhysicalDevice final
eastl::vector<QueueFamilyInfo> m_QueueFamilies;
PhysicalDevice(vk::SurfaceKHR surface, vk::PhysicalDevice physicalDevice);
QueueAllocation FindAppropriateQueueAllocation();
};
class PhysicalDevices : public eastl::fixed_vector<PhysicalDevice, 4>
class PhysicalDevices : public eastl::vector<PhysicalDevice>
{
public:
PhysicalDevices(const Window *window, const Context *context);
};
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);

25
aster/size.h Normal file
View File

@ -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};
}
};

33
aster/surface.cpp Normal file
View File

@ -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<vk::Result>(
glfwCreateWindowSurface(Cast<VkInstance>(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");
}

19
aster/surface.h Normal file
View File

@ -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);
};

View File

@ -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<u32>)
{
return surfaceCapabilities->currentExtent;
}
auto [width, height] = window->GetSize();
auto [width, height] = size;
auto [minWidth, minHeight] = surfaceCapabilities->minImageExtent;
auto [maxWidth, maxHeight] = surfaceCapabilities->maxImageExtent;

View File

@ -7,8 +7,11 @@
#include "global.h"
#include "size.h"
#include <EASTL/fixed_vector.h>
struct Surface;
struct PhysicalDevice;
struct Window;
struct Device;
@ -17,9 +20,7 @@ struct Swapchain final
{
using FnResizeCallback = eastl::function<void(vk::Extent2D)>;
const Device *m_Device;
vk::SwapchainKHR m_Swapchain;
NameString m_Name;
vk::Extent2D m_Extent;
vk::Format m_Format;
eastl::fixed_vector<vk::Image, 4> m_Images;
@ -27,19 +28,10 @@ struct Swapchain final
eastl::vector<FnResizeCallback> 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);
};

View File

@ -35,10 +35,16 @@ Window::GetSize() const
return {Cast<u32>(width), Cast<u32>(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<i32>(extent.width), Cast<i32>(extent.height), m_Name.c_str(),
m_Window = glfwCreateWindow(Cast<i32>(extent.width), Cast<i32>(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<i32>(windowHeight - extent.height) / 2);
}
glfwSetInputMode(m_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
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 {}", 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();
}

View File

@ -6,18 +6,12 @@
#pragma once
#include "global.h"
#include <EASTL/fixed_string.h>
struct Context;
struct Window final
{
// fields
Context *m_Context{};
GLFWwindow *m_Window = nullptr;
vk::SurfaceKHR m_Surface;
eastl::fixed_string<char, 32> 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();
};

15
scratch/CMakeLists.txt Normal file
View File

@ -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)

25
scratch/graphics.cpp Normal file
View File

@ -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();
}

69
scratch/graphics.h Normal file
View File

@ -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 <typename T>
void MakePermanent(T* &val) requires std::is_default_constructible_v<T>
{
const usize alignment = alignof(T);
const usize size = sizeof(T);
const usize offset = (alignment - Recast<uptr>(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<T *>(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();
};

34
scratch/scratch_run.cpp Normal file
View File

@ -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;
}