Refactored upto a swapchain.
This commit is contained in:
parent
14f4ac39be
commit
31809faa75
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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`.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>);
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
}
|
||||
};
|
||||
|
|
@ -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");
|
||||
}
|
||||
|
|
@ -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);
|
||||
};
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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();
|
||||
};
|
||||
|
|
@ -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;
|
||||
}
|
||||
Loading…
Reference in New Issue