Compare commits
1 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
31809faa75 |
|
|
@ -21,4 +21,5 @@ include(add_shader.cmake)
|
||||||
include(add_resource_dir.cmake)
|
include(add_resource_dir.cmake)
|
||||||
|
|
||||||
add_subdirectory("aster")
|
add_subdirectory("aster")
|
||||||
add_subdirectory("samples")
|
add_subdirectory("scratch")
|
||||||
|
# add_subdirectory("samples")
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,10 @@ set(HEADER_FILES
|
||||||
swapchain.h
|
swapchain.h
|
||||||
pipeline.h
|
pipeline.h
|
||||||
queue_allocation.h
|
queue_allocation.h
|
||||||
buffer.h)
|
buffer.h
|
||||||
|
size.h
|
||||||
|
image.h
|
||||||
|
surface.h)
|
||||||
|
|
||||||
set(SOURCE_FILES
|
set(SOURCE_FILES
|
||||||
logger.cpp
|
logger.cpp
|
||||||
|
|
@ -35,7 +38,7 @@ set(SOURCE_FILES
|
||||||
pipeline.cpp
|
pipeline.cpp
|
||||||
buffer.cpp
|
buffer.cpp
|
||||||
image.cpp
|
image.cpp
|
||||||
image.h)
|
surface.cpp)
|
||||||
|
|
||||||
add_library(aster_core STATIC ${SOURCE_FILES} ${HEADER_FILES})
|
add_library(aster_core STATIC ${SOURCE_FILES} ${HEADER_FILES})
|
||||||
set_property(TARGET aster_core PROPERTY CXX_STANDARD 20)
|
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_Buffer = buffer;
|
||||||
m_Size_ = size | VALID_BUFFER_BIT | OWNED_BIT;
|
m_Size_ = size | VALID_BUFFER_BIT | OWNED_BIT;
|
||||||
m_Allocation = allocation;
|
m_Allocation = allocation;
|
||||||
m_Mapped = Cast<u8 *>(allocationInfo.pMappedData);
|
m_Mapped = hostAccessible ? Cast<u8 *>(allocationInfo.pMappedData) : nullptr;
|
||||||
|
|
||||||
device->SetName(m_Buffer, name);
|
device->SetName(m_Buffer, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
uptr
|
uptr
|
||||||
Buffer::GetDeviceAddress(const Device *device)
|
Buffer::GetDeviceAddress(const Device *device) const
|
||||||
{
|
{
|
||||||
vk::BufferDeviceAddressInfo addressInfo = {.buffer = m_Buffer};
|
vk::BufferDeviceAddressInfo addressInfo = {.buffer = m_Buffer};
|
||||||
return device->m_Device.getBufferAddress(&addressInfo);
|
return device->m_Device.getBufferAddress(&addressInfo);
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ struct Buffer
|
||||||
VmaAllocationCreateFlags allocationFlags, VmaMemoryUsage memoryUsage, cstr name);
|
VmaAllocationCreateFlags allocationFlags, VmaMemoryUsage memoryUsage, cstr name);
|
||||||
|
|
||||||
uptr
|
uptr
|
||||||
GetDeviceAddress(const Device *device);
|
GetDeviceAddress(const Device *device) const;
|
||||||
|
|
||||||
// Buffer.size is used for bookkeeping
|
// Buffer.size is used for bookkeeping
|
||||||
// If the buffer is Invalid, the remaining data in Buffer is used intrusively by `GpuResourceManager`.
|
// 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;
|
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");
|
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
|
// TODO Get/Check API Version
|
||||||
|
|
||||||
// Creating Instance
|
// 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)
|
if (m_DebugMessenger)
|
||||||
{
|
{
|
||||||
m_Instance.destroy(m_DebugMessenger, nullptr);
|
m_Instance.destroy(m_DebugMessenger, nullptr);
|
||||||
|
|
@ -120,21 +117,12 @@ Context::~Context()
|
||||||
m_Instance.destroy(nullptr);
|
m_Instance.destroy(nullptr);
|
||||||
DEBUG("Instance destroyed");
|
DEBUG("Instance destroyed");
|
||||||
|
|
||||||
glfwTerminate();
|
m_DebugMessenger = nullptr;
|
||||||
|
m_Instance = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Context::Context(Context &&other) noexcept
|
bool
|
||||||
: m_Instance(Take(other.m_Instance))
|
Context::IsInDebugMode() const
|
||||||
, m_DebugMessenger(Take(other.m_DebugMessenger))
|
|
||||||
{
|
{
|
||||||
}
|
return m_DebugMessenger != nullptr;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -17,22 +18,21 @@
|
||||||
struct Context final
|
struct Context final
|
||||||
{
|
{
|
||||||
// Members
|
// Members
|
||||||
vk::Instance m_Instance = nullptr;
|
vk::Instance m_Instance;
|
||||||
vk::DebugUtilsMessengerEXT m_DebugMessenger = nullptr;
|
vk::DebugUtilsMessengerEXT m_DebugMessenger;
|
||||||
|
|
||||||
// Ctor/Dtor
|
// Ctor/Dtor
|
||||||
Context(cstr appName, Version version, bool enableValidation = ENABLE_VALIDATION_DEFAULT_VALUE);
|
void Init(cstr appName, Version version, bool enableValidation = ENABLE_VALIDATION_DEFAULT_VALUE);
|
||||||
~Context();
|
void Destroy();
|
||||||
|
|
||||||
// Move
|
[[nodiscard]] bool IsInDebugMode() const;
|
||||||
Context(Context &&other) noexcept;
|
|
||||||
Context &operator=(Context &&other) noexcept;
|
|
||||||
|
|
||||||
#if !defined(ASTER_NDEBUG)
|
#if !defined(ASTER_NDEBUG)
|
||||||
constexpr static bool ENABLE_VALIDATION_DEFAULT_VALUE = true;
|
constexpr static bool ENABLE_VALIDATION_DEFAULT_VALUE = true;
|
||||||
#else
|
#else
|
||||||
constexpr static bool ENABLE_VALIDATION_DEFAULT_VALUE = false;
|
constexpr static bool ENABLE_VALIDATION_DEFAULT_VALUE = false;
|
||||||
#endif
|
#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,
|
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||||
};
|
};
|
||||||
|
|
||||||
Device::Device(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures,
|
void
|
||||||
const eastl::vector<QueueAllocation> &queueAllocations, NameString &&name)
|
Device::Init(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures,
|
||||||
: Device(context, physicalDevice, enabledFeatures, queueAllocations, {}, std::move(name))
|
const eastl::vector<QueueAllocation> &queueAllocations, cstr name)
|
||||||
{
|
{
|
||||||
|
this->Init(context, physicalDevice, enabledFeatures, queueAllocations, {}, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
Device::Device(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures,
|
void
|
||||||
const eastl::vector<QueueAllocation> &queueAllocations, eastl::span<u8> &&pipelineCacheData,
|
Device::Init(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures,
|
||||||
NameString &&name)
|
const eastl::vector<QueueAllocation> &queueAllocations, const eastl::span<u8> &pipelineCacheData,
|
||||||
: m_Name(std::move(name))
|
cstr name)
|
||||||
, m_PhysicalDevice(physicalDevice->m_PhysicalDevice)
|
|
||||||
, m_ValidationEnabled(context->m_DebugMessenger != nullptr)
|
|
||||||
{
|
{
|
||||||
|
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
|
// Shouldn't have more than 4 deviceQueueFamilies in use anyway. Else we can heap
|
||||||
eastl::fixed_vector<vk::DeviceQueueCreateInfo, 4> deviceQueueCreateInfos;
|
eastl::fixed_vector<vk::DeviceQueueCreateInfo, 4> deviceQueueCreateInfos;
|
||||||
deviceQueueCreateInfos.reserve(queueAllocations.size());
|
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);
|
vk::Result result = m_PhysicalDevice.createDevice(&deviceCreateInfo, nullptr, &m_Device);
|
||||||
ERROR_IF(Failed(result), "Could not initialize Vulkan Device. Cause: {}", result)
|
ERROR_IF(Failed(result), "Could not initialize Vulkan Device. Cause: {}", result)
|
||||||
THEN_ABORT(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 = {
|
VmaVulkanFunctions vmaVulkanFunctions = {
|
||||||
.vkGetInstanceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetInstanceProcAddr,
|
.vkGetInstanceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetInstanceProcAddr,
|
||||||
|
|
@ -105,11 +108,15 @@ Device::Device(const Context *context, PhysicalDevice *physicalDevice, Features
|
||||||
THEN_ABORT(result)
|
THEN_ABORT(result)
|
||||||
ELSE_VERBOSE("Pipeline Cache created.");
|
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);
|
m_Device.destroy(m_PipelineCache, nullptr);
|
||||||
if (m_Allocator)
|
if (m_Allocator)
|
||||||
{
|
{
|
||||||
|
|
@ -118,8 +125,11 @@ Device::~Device()
|
||||||
DEBUG("Memory Allocator Destroyed");
|
DEBUG("Memory Allocator Destroyed");
|
||||||
}
|
}
|
||||||
m_Device.destroy(nullptr);
|
m_Device.destroy(nullptr);
|
||||||
DEBUG("Device '{}' Destroyed", m_Name);
|
DEBUG("Device Destroyed");
|
||||||
|
|
||||||
|
m_Allocator = nullptr;
|
||||||
m_PhysicalDevice = nullptr;
|
m_PhysicalDevice = nullptr;
|
||||||
|
m_Device = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::Queue
|
vk::Queue
|
||||||
|
|
@ -150,23 +160,3 @@ Device::WaitIdle() const
|
||||||
ERROR_IF(Failed(deviceIdleResult), "Device Idling Failed. Cause: {}", deviceIdleResult)
|
ERROR_IF(Failed(deviceIdleResult), "Device Idling Failed. Cause: {}", deviceIdleResult)
|
||||||
THEN_ABORT(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
|
struct Device final
|
||||||
{
|
{
|
||||||
NameString m_Name;
|
|
||||||
vk::PhysicalDevice m_PhysicalDevice = nullptr;
|
vk::PhysicalDevice m_PhysicalDevice = nullptr;
|
||||||
vk::Device m_Device = nullptr;
|
vk::Device m_Device = nullptr;
|
||||||
VmaAllocator m_Allocator = nullptr;
|
VmaAllocator m_Allocator = nullptr;
|
||||||
|
|
@ -40,17 +39,11 @@ struct Device final
|
||||||
void WaitIdle() const;
|
void WaitIdle() const;
|
||||||
|
|
||||||
// Ctor/Dtor
|
// Ctor/Dtor
|
||||||
Device(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures,
|
void Init(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures,
|
||||||
const eastl::vector<QueueAllocation> &queueAllocations, NameString &&name);
|
const eastl::vector<QueueAllocation> &queueAllocations, cstr name);
|
||||||
Device(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures,
|
void Init(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures,
|
||||||
const eastl::vector<QueueAllocation> &queueAllocations, eastl::span<u8> &&pipelineCacheData, NameString &&name);
|
const eastl::vector<QueueAllocation> &queueAllocations, const eastl::span<u8> &pipelineCacheData, cstr name);
|
||||||
~Device();
|
void Destroy();
|
||||||
|
|
||||||
// Move
|
|
||||||
Device(Device &&other) noexcept;
|
|
||||||
Device &operator=(Device &&other) noexcept;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(Device);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@
|
||||||
#include "physical_device.h"
|
#include "physical_device.h"
|
||||||
|
|
||||||
#include "context.h"
|
#include "context.h"
|
||||||
#include "window.h"
|
#include "queue_allocation.h"
|
||||||
|
#include "surface.h"
|
||||||
|
|
||||||
[[nodiscard]] vk::SurfaceCapabilitiesKHR
|
[[nodiscard]] vk::SurfaceCapabilitiesKHR
|
||||||
GetSurfaceCapabilities(const vk::PhysicalDevice physicalDevice, const vk::SurfaceKHR surface)
|
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;
|
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>
|
eastl::fixed_vector<vk::PhysicalDevice, 8>
|
||||||
EnumeratePhysicalDevices(const vk::Instance instance)
|
EnumeratePhysicalDevices(const vk::Instance instance)
|
||||||
{
|
{
|
||||||
|
|
@ -154,12 +173,44 @@ EnumeratePhysicalDevices(const vk::Instance instance)
|
||||||
return physicalDevices;
|
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);
|
auto physicalDevices = EnumeratePhysicalDevices(context->m_Instance);
|
||||||
for (auto physicalDevice : physicalDevices)
|
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 "global.h"
|
||||||
#include <EASTL/fixed_vector.h>
|
#include <EASTL/fixed_vector.h>
|
||||||
|
|
||||||
|
struct QueueAllocation;
|
||||||
|
struct Surface;
|
||||||
struct Window;
|
struct Window;
|
||||||
struct Context;
|
struct Context;
|
||||||
|
|
||||||
|
|
@ -47,10 +49,22 @@ struct PhysicalDevice final
|
||||||
eastl::vector<QueueFamilyInfo> m_QueueFamilies;
|
eastl::vector<QueueFamilyInfo> m_QueueFamilies;
|
||||||
|
|
||||||
PhysicalDevice(vk::SurfaceKHR surface, vk::PhysicalDevice physicalDevice);
|
PhysicalDevice(vk::SurfaceKHR surface, vk::PhysicalDevice physicalDevice);
|
||||||
|
QueueAllocation FindAppropriateQueueAllocation();
|
||||||
};
|
};
|
||||||
|
|
||||||
class PhysicalDevices : public eastl::fixed_vector<PhysicalDevice, 4>
|
class PhysicalDevices : public eastl::vector<PhysicalDevice>
|
||||||
{
|
{
|
||||||
public:
|
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 "device.h"
|
||||||
#include "physical_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)
|
void
|
||||||
: m_Device(device)
|
Swapchain::Init(const Surface *surface, const Device *device, Size size, cstr name)
|
||||||
, m_Name(std::move(name))
|
|
||||||
, m_Format(vk::Format::eUndefined)
|
|
||||||
{
|
{
|
||||||
this->Create(window);
|
assert(!m_Swapchain);
|
||||||
}
|
this->Create(surface, device, size, name);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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);
|
auto surfaceCapabilities = GetSurfaceCapabilities(device->m_PhysicalDevice, surface->m_Surface);
|
||||||
m_Extent = GetExtent(window, &surfaceCapabilities);
|
m_Extent = GetExtent(size, &surfaceCapabilities);
|
||||||
|
|
||||||
while (m_Extent.width == 0 || m_Extent.height == 0)
|
while (m_Extent.width == 0 || m_Extent.height == 0)
|
||||||
{
|
{
|
||||||
glfwWaitEvents();
|
glfwWaitEvents();
|
||||||
surfaceCapabilities = GetSurfaceCapabilities(m_Device->m_PhysicalDevice, window->m_Surface);
|
surfaceCapabilities = GetSurfaceCapabilities(device->m_PhysicalDevice, surface->m_Surface);
|
||||||
m_Extent = GetExtent(window, &surfaceCapabilities);
|
m_Extent = GetExtent(size, &surfaceCapabilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto surfaceFormats = GetSurfaceFormats(m_Device->m_PhysicalDevice, window->m_Surface);
|
auto surfaceFormats = GetSurfaceFormats(device->m_PhysicalDevice, surface->m_Surface);
|
||||||
auto presentModes = GetSurfacePresentModes(m_Device->m_PhysicalDevice, window->m_Surface);
|
auto presentModes = GetSurfacePresentModes(device->m_PhysicalDevice, surface->m_Surface);
|
||||||
|
|
||||||
m_Format = vk::Format::eUndefined;
|
m_Format = vk::Format::eUndefined;
|
||||||
vk::ColorSpaceKHR swapchainColorSpace = vk::ColorSpaceKHR::eSrgbNonlinear;
|
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.
|
// TODO: Note that different queues might need the images to be shared.
|
||||||
|
|
||||||
const vk::SwapchainCreateInfoKHR swapchainCreateInfo = {
|
const vk::SwapchainCreateInfoKHR swapchainCreateInfo = {
|
||||||
.surface = window->m_Surface,
|
.surface = surface->m_Surface,
|
||||||
.minImageCount = swapchainImageCount,
|
.minImageCount = swapchainImageCount,
|
||||||
.imageFormat = m_Format,
|
.imageFormat = m_Format,
|
||||||
.imageColorSpace = swapchainColorSpace,
|
.imageColorSpace = swapchainColorSpace,
|
||||||
|
|
@ -119,29 +87,29 @@ Swapchain::Create(const Window *window)
|
||||||
.oldSwapchain = m_Swapchain,
|
.oldSwapchain = m_Swapchain,
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::Device device = m_Device->m_Device;
|
vk::Device vkDevice = device->m_Device;
|
||||||
|
|
||||||
vk::SwapchainKHR swapchain;
|
vk::SwapchainKHR swapchain;
|
||||||
vk::Result result = device.createSwapchainKHR(&swapchainCreateInfo, nullptr, &swapchain);
|
vk::Result result = vkDevice.createSwapchainKHR(&swapchainCreateInfo, nullptr, &swapchain);
|
||||||
ERROR_IF(Failed(result), "Swapchain {} creation failed. Cause {}", m_Name, result)
|
ERROR_IF(Failed(result), "Swapchain {} creation failed. Cause {}", name, result)
|
||||||
THEN_ABORT(result)
|
THEN_ABORT(result)
|
||||||
ELSE_DEBUG("Created Swapchain '{}'", m_Name);
|
ELSE_DEBUG("Created Swapchain '{}'", name);
|
||||||
|
|
||||||
// Irrelevant on the first run. Required for re-creation.
|
// Irrelevant on the first run. Required for re-creation.
|
||||||
Cleanup();
|
Destroy(device);
|
||||||
|
|
||||||
m_Swapchain = swapchain;
|
m_Swapchain = swapchain;
|
||||||
|
|
||||||
m_Device->SetName(m_Swapchain, m_Name.data());
|
device->SetName(m_Swapchain, name);
|
||||||
|
|
||||||
result = device.getSwapchainImagesKHR(m_Swapchain, &swapchainImageCount, nullptr);
|
result = vkDevice.getSwapchainImagesKHR(m_Swapchain, &swapchainImageCount, nullptr);
|
||||||
ERROR_IF(Failed(result), "Failed getting swapchain {}'s images. Cause {}", m_Name, result)
|
ERROR_IF(Failed(result), "Failed getting swapchain {}'s images. Cause {}", name, result)
|
||||||
THEN_ABORT(result);
|
THEN_ABORT(result);
|
||||||
|
|
||||||
// Managed by the Swapchain.
|
// Managed by the Swapchain.
|
||||||
m_Images.resize(swapchainImageCount);
|
m_Images.resize(swapchainImageCount);
|
||||||
result = device.getSwapchainImagesKHR(m_Swapchain, &swapchainImageCount, m_Images.data());
|
result = vkDevice.getSwapchainImagesKHR(m_Swapchain, &swapchainImageCount, m_Images.data());
|
||||||
ERROR_IF(Failed(result), "Failed getting swapchain {}'s images. Cause {}", m_Name, result)
|
ERROR_IF(Failed(result), "Failed getting swapchain {}'s images. Cause {}", name, result)
|
||||||
THEN_ABORT(result);
|
THEN_ABORT(result);
|
||||||
|
|
||||||
vk::ImageViewCreateInfo viewCreateInfo = {
|
vk::ImageViewCreateInfo viewCreateInfo = {
|
||||||
|
|
@ -164,8 +132,8 @@ Swapchain::Create(const Window *window)
|
||||||
viewCreateInfo.image = image;
|
viewCreateInfo.image = image;
|
||||||
|
|
||||||
vk::ImageView imageView;
|
vk::ImageView imageView;
|
||||||
result = device.createImageView(&viewCreateInfo, nullptr, &imageView);
|
result = vkDevice.createImageView(&viewCreateInfo, nullptr, &imageView);
|
||||||
ERROR_IF(Failed(result), "Failed creating swapchain {}'s image view [{}]. Cause {}", m_Name, index, result)
|
ERROR_IF(Failed(result), "Failed creating swapchain {}'s image view [{}]. Cause {}", name, index, result)
|
||||||
THEN_ABORT(result);
|
THEN_ABORT(result);
|
||||||
|
|
||||||
m_ImageViews.push_back(imageView);
|
m_ImageViews.push_back(imageView);
|
||||||
|
|
@ -173,7 +141,7 @@ Swapchain::Create(const Window *window)
|
||||||
++index;
|
++index;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG("Swapchain {} Image Views created.", m_Name);
|
DEBUG("Swapchain {} Image Views created.", name);
|
||||||
|
|
||||||
for (auto &callback : m_ResizeCallbacks)
|
for (auto &callback : m_ResizeCallbacks)
|
||||||
{
|
{
|
||||||
|
|
@ -188,32 +156,32 @@ Swapchain::RegisterResizeCallback(FnResizeCallback &&callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Swapchain::Cleanup()
|
Swapchain::Destroy(const Device *device)
|
||||||
{
|
{
|
||||||
if (!m_ImageViews.empty()) // Don't want the condition in the logs.
|
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)
|
for (const auto imageView : m_ImageViews)
|
||||||
{
|
{
|
||||||
m_Device->m_Device.destroy(imageView, nullptr);
|
device->m_Device.destroy(imageView, nullptr);
|
||||||
}
|
}
|
||||||
m_ImageViews.clear();
|
m_ImageViews.clear();
|
||||||
if (m_Swapchain)
|
if (m_Swapchain)
|
||||||
{
|
{
|
||||||
m_Device->m_Device.destroy(m_Swapchain, nullptr);
|
device->m_Device.destroy(m_Swapchain, nullptr);
|
||||||
m_Swapchain = nullptr;
|
m_Swapchain = nullptr;
|
||||||
DEBUG("Swapchain '{}' destroyed.", m_Name);
|
DEBUG("Swapchain destroyed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vk::Extent2D
|
vk::Extent2D
|
||||||
GetExtent(const Window *window, vk::SurfaceCapabilitiesKHR *surfaceCapabilities)
|
GetExtent(Size size, vk::SurfaceCapabilitiesKHR *surfaceCapabilities)
|
||||||
{
|
{
|
||||||
if (surfaceCapabilities->currentExtent.width != MaxValue<u32>)
|
if (surfaceCapabilities->currentExtent.width != MaxValue<u32>)
|
||||||
{
|
{
|
||||||
return surfaceCapabilities->currentExtent;
|
return surfaceCapabilities->currentExtent;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto [width, height] = window->GetSize();
|
auto [width, height] = size;
|
||||||
auto [minWidth, minHeight] = surfaceCapabilities->minImageExtent;
|
auto [minWidth, minHeight] = surfaceCapabilities->minImageExtent;
|
||||||
auto [maxWidth, maxHeight] = surfaceCapabilities->maxImageExtent;
|
auto [maxWidth, maxHeight] = surfaceCapabilities->maxImageExtent;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,11 @@
|
||||||
|
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
|
||||||
|
#include "size.h"
|
||||||
|
|
||||||
#include <EASTL/fixed_vector.h>
|
#include <EASTL/fixed_vector.h>
|
||||||
|
|
||||||
|
struct Surface;
|
||||||
struct PhysicalDevice;
|
struct PhysicalDevice;
|
||||||
struct Window;
|
struct Window;
|
||||||
struct Device;
|
struct Device;
|
||||||
|
|
@ -17,9 +20,7 @@ struct Swapchain final
|
||||||
{
|
{
|
||||||
using FnResizeCallback = eastl::function<void(vk::Extent2D)>;
|
using FnResizeCallback = eastl::function<void(vk::Extent2D)>;
|
||||||
|
|
||||||
const Device *m_Device;
|
|
||||||
vk::SwapchainKHR m_Swapchain;
|
vk::SwapchainKHR m_Swapchain;
|
||||||
NameString m_Name;
|
|
||||||
vk::Extent2D m_Extent;
|
vk::Extent2D m_Extent;
|
||||||
vk::Format m_Format;
|
vk::Format m_Format;
|
||||||
eastl::fixed_vector<vk::Image, 4> m_Images;
|
eastl::fixed_vector<vk::Image, 4> m_Images;
|
||||||
|
|
@ -27,19 +28,10 @@ struct Swapchain final
|
||||||
|
|
||||||
eastl::vector<FnResizeCallback> m_ResizeCallbacks;
|
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);
|
void RegisterResizeCallback(FnResizeCallback &&callback);
|
||||||
|
|
||||||
// Ctor/Dtor
|
// Ctor/Dtor
|
||||||
Swapchain(const Window *window, const Device *device, NameString &&name);
|
void Init(const Surface *surface, const Device *device, Size size, cstr name);
|
||||||
~Swapchain();
|
void Destroy(const Device *device);
|
||||||
|
|
||||||
// Move
|
|
||||||
Swapchain(Swapchain &&other) noexcept;
|
|
||||||
Swapchain &operator=(Swapchain &&other) noexcept;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(Swapchain);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void Cleanup();
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -35,10 +35,16 @@ Window::GetSize() const
|
||||||
return {Cast<u32>(width), Cast<u32>(height)};
|
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;
|
if (!glfwInit())
|
||||||
m_Name = title;
|
{
|
||||||
|
const char *error = nullptr;
|
||||||
|
const auto code = glfwGetError(&error);
|
||||||
|
ERROR("GLFW Init failed. Cause: ({}) {}", code, error)
|
||||||
|
THEN_ABORT(code);
|
||||||
|
}
|
||||||
|
|
||||||
GLFWmonitor *monitor = glfwGetPrimaryMonitor();
|
GLFWmonitor *monitor = glfwGetPrimaryMonitor();
|
||||||
ERROR_IF(!monitor, "No monitor found");
|
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_CLIENT_API, GLFW_NO_API);
|
||||||
glfwWindowHint(GLFW_CENTER_CURSOR, GLFW_TRUE);
|
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);
|
isFullScreen ? monitor : nullptr, nullptr);
|
||||||
ERROR_IF(m_Window == nullptr, "Window creation failed")
|
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)
|
if (m_Window == nullptr)
|
||||||
{
|
{
|
||||||
const char *error = 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);
|
Cast<i32>(windowHeight - extent.height) / 2);
|
||||||
}
|
}
|
||||||
glfwSetInputMode(m_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
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)
|
if (!m_Window)
|
||||||
{
|
return;
|
||||||
m_Context->m_Instance.destroy(m_Surface, nullptr);
|
|
||||||
DEBUG("Surface Destroyed");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_Window)
|
const char *title = glfwGetWindowTitle(m_Window);
|
||||||
{
|
|
||||||
glfwDestroyWindow(m_Window);
|
|
||||||
m_Window = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG("Window '{}' Destroyed", m_Name);
|
DEBUG("Window {} Destroyed", title);
|
||||||
}
|
|
||||||
|
glfwDestroyWindow(m_Window);
|
||||||
Window::Window(Window &&other) noexcept
|
m_Window = nullptr;
|
||||||
: m_Context(other.m_Context)
|
|
||||||
, m_Window(Take(other.m_Window))
|
// Currently only one window is supported.
|
||||||
, m_Surface(Take(other.m_Surface))
|
glfwTerminate();
|
||||||
, 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;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,18 +6,12 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include <EASTL/fixed_string.h>
|
|
||||||
|
|
||||||
struct Context;
|
struct Context;
|
||||||
|
|
||||||
struct Window final
|
struct Window final
|
||||||
{
|
{
|
||||||
// fields
|
|
||||||
Context *m_Context{};
|
|
||||||
|
|
||||||
GLFWwindow *m_Window = nullptr;
|
GLFWwindow *m_Window = nullptr;
|
||||||
vk::SurfaceKHR m_Surface;
|
|
||||||
eastl::fixed_string<char, 32> m_Name;
|
|
||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
[[nodiscard]] bool
|
[[nodiscard]] bool
|
||||||
|
|
@ -34,12 +28,6 @@ struct Window final
|
||||||
[[nodiscard]] vk::Extent2D GetSize() const;
|
[[nodiscard]] vk::Extent2D GetSize() const;
|
||||||
|
|
||||||
// Ctor/Dtor
|
// Ctor/Dtor
|
||||||
Window(cstr title, Context *context, vk::Extent2D extent, b8 isFullScreen = false);
|
void Init(cstr title, vk::Extent2D extent, b8 isFullScreen = false);
|
||||||
~Window();
|
void Destroy();
|
||||||
|
|
||||||
// Move
|
|
||||||
Window(Window &&other) noexcept;
|
|
||||||
Window &operator=(Window &&other) noexcept;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(Window);
|
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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