Compare commits
1 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
31809faa75 |
|
|
@ -2,6 +2,3 @@
|
||||||
.cache/
|
.cache/
|
||||||
build/
|
build/
|
||||||
.vs/
|
.vs/
|
||||||
.direnv/
|
|
||||||
.ccls-cache/
|
|
||||||
*.user
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ set(CMAKE_CXX_EXTENSIONS OFF)
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
set(CMAKE_CXX_FLAGS "/W4 /GR- ${MSVC_FLAGS}")
|
set(CMAKE_CXX_FLAGS "/W4 /GR- ${MSVC_FLAGS}")
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "/O3")
|
|
||||||
add_compile_definitions(_HAS_EXCEPTIONS=0)
|
add_compile_definitions(_HAS_EXCEPTIONS=0)
|
||||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
||||||
add_compile_definitions(${MSVC_DEFINES})
|
add_compile_definitions(${MSVC_DEFINES})
|
||||||
|
|
@ -22,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")
|
||||||
|
|
|
||||||
|
|
@ -18,22 +18,6 @@
|
||||||
"rhs": "Linux"
|
"rhs": "Linux"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "nixos",
|
|
||||||
"generator": "Ninja",
|
|
||||||
"binaryDir": "${sourceDir}/build",
|
|
||||||
"cacheVariables": {
|
|
||||||
"CMAKE_EXPORT_COMPILE_COMMANDS": true,
|
|
||||||
"CMAKE_MAKE_PROGRAM": "ninja",
|
|
||||||
"CMAKE_C_COMPILER": "$env{CC}",
|
|
||||||
"CMAKE_CXX_COMPILER": "$env{CXX}"
|
|
||||||
},
|
|
||||||
"condition": {
|
|
||||||
"type": "equals",
|
|
||||||
"lhs": "${hostSystemName}",
|
|
||||||
"rhs": "Linux"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "windows-debug",
|
"name": "windows-debug",
|
||||||
"generator": "Ninja",
|
"generator": "Ninja",
|
||||||
|
|
|
||||||
|
|
@ -10,15 +10,42 @@ find_package(fmt CONFIG REQUIRED)
|
||||||
find_package(VulkanMemoryAllocator CONFIG REQUIRED)
|
find_package(VulkanMemoryAllocator CONFIG REQUIRED)
|
||||||
find_package(EASTL CONFIG REQUIRED)
|
find_package(EASTL CONFIG REQUIRED)
|
||||||
|
|
||||||
add_library(aster_core STATIC)
|
set(HEADER_FILES
|
||||||
|
constants.h
|
||||||
|
config.h
|
||||||
|
logger.h
|
||||||
|
global.h
|
||||||
|
context.h
|
||||||
|
window.h
|
||||||
|
physical_device.h
|
||||||
|
device.h
|
||||||
|
swapchain.h
|
||||||
|
pipeline.h
|
||||||
|
queue_allocation.h
|
||||||
|
buffer.h
|
||||||
|
size.h
|
||||||
|
image.h
|
||||||
|
surface.h)
|
||||||
|
|
||||||
add_subdirectory("include")
|
set(SOURCE_FILES
|
||||||
add_subdirectory("src")
|
logger.cpp
|
||||||
|
global.cpp
|
||||||
|
context.cpp
|
||||||
|
window.cpp
|
||||||
|
physical_device.cpp
|
||||||
|
device.cpp
|
||||||
|
swapchain.cpp
|
||||||
|
pipeline.cpp
|
||||||
|
buffer.cpp
|
||||||
|
image.cpp
|
||||||
|
surface.cpp)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
target_include_directories(aster_core PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include/aster")
|
target_precompile_headers(aster_core PUBLIC global.h)
|
||||||
target_include_directories(aster_core PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
|
||||||
|
target_include_directories(aster_core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
target_link_libraries(aster_core PUBLIC glm::glm-header-only)
|
target_link_libraries(aster_core PUBLIC glm::glm-header-only)
|
||||||
target_link_libraries(aster_core PRIVATE glfw)
|
target_link_libraries(aster_core PRIVATE glfw)
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,9 @@
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
// =============================================
|
// =============================================
|
||||||
|
|
||||||
#include "core/buffer.h"
|
#include "buffer.h"
|
||||||
|
|
||||||
#include "core/device.h"
|
#include "device.h"
|
||||||
|
|
||||||
void
|
void
|
||||||
Buffer::Destroy(const Device *device)
|
Buffer::Destroy(const Device *device)
|
||||||
|
|
@ -44,19 +44,18 @@ Buffer::Allocate(const Device *device, usize size, vk::BufferUsageFlags bufferUs
|
||||||
vk::MemoryPropertyFlags memoryPropertyFlags;
|
vk::MemoryPropertyFlags memoryPropertyFlags;
|
||||||
vmaGetAllocationMemoryProperties(device->m_Allocator, allocation,
|
vmaGetAllocationMemoryProperties(device->m_Allocator, allocation,
|
||||||
Recast<VkMemoryPropertyFlags *>(&memoryPropertyFlags));
|
Recast<VkMemoryPropertyFlags *>(&memoryPropertyFlags));
|
||||||
// TODO: Actually track Host Access
|
bool hostAccessible = Cast<bool>(memoryPropertyFlags & vk::MemoryPropertyFlagBits::eHostVisible);
|
||||||
// bool hostAccessible = Cast<bool>(memoryPropertyFlags & vk::MemoryPropertyFlagBits::eHostVisible);
|
|
||||||
|
|
||||||
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);
|
||||||
|
|
@ -24,8 +24,6 @@ struct Buffer
|
||||||
[[nodiscard]] bool IsValid() const;
|
[[nodiscard]] bool IsValid() const;
|
||||||
[[nodiscard]] bool IsMapped() const;
|
[[nodiscard]] bool IsMapped() const;
|
||||||
[[nodiscard]] bool IsOwned() const;
|
[[nodiscard]] bool IsOwned() const;
|
||||||
[[nodiscard]] bool IsCommitted() const;
|
|
||||||
void SetCommitted(bool committed);
|
|
||||||
|
|
||||||
void Destroy(const Device *device);
|
void Destroy(const Device *device);
|
||||||
void Write(const Device *device, usize offset, usize size, const void *data);
|
void Write(const Device *device, usize offset, usize size, const void *data);
|
||||||
|
|
@ -34,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`.
|
||||||
|
|
@ -42,13 +40,9 @@ struct Buffer
|
||||||
|
|
||||||
constexpr static usize VALID_BUFFER_BIT = Cast<usize>(1llu << 63);
|
constexpr static usize VALID_BUFFER_BIT = Cast<usize>(1llu << 63);
|
||||||
constexpr static usize OWNED_BIT = 1llu << 62;
|
constexpr static usize OWNED_BIT = 1llu << 62;
|
||||||
constexpr static usize COMMITTED_BIT = 1llu << 61;
|
constexpr static usize SIZE_MASK = ~(VALID_BUFFER_BIT | OWNED_BIT);
|
||||||
constexpr static usize SIZE_MASK = ~(VALID_BUFFER_BIT | OWNED_BIT | COMMITTED_BIT);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
|
||||||
constexpr bool concepts::GpuResource<Buffer> = true;
|
|
||||||
|
|
||||||
// Ensure that m_Size doesn't get used intrusively since it manages the state.
|
// Ensure that m_Size doesn't get used intrusively since it manages the state.
|
||||||
static_assert(offsetof(Buffer, m_Size_) > sizeof(usize));
|
static_assert(offsetof(Buffer, m_Size_) > sizeof(usize));
|
||||||
|
|
||||||
|
|
@ -119,15 +113,3 @@ Buffer::IsOwned() const
|
||||||
{
|
{
|
||||||
return m_Size_ & OWNED_BIT;
|
return m_Size_ & OWNED_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
|
||||||
Buffer::IsCommitted() const
|
|
||||||
{
|
|
||||||
return m_Size_ & COMMITTED_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
Buffer::SetCommitted(const bool committed)
|
|
||||||
{
|
|
||||||
m_Size_ = committed ? (m_Size_ | COMMITTED_BIT) : (m_Size_ & ~COMMITTED_BIT);
|
|
||||||
}
|
|
||||||
|
|
@ -3,11 +3,14 @@
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
// =============================================
|
// =============================================
|
||||||
|
|
||||||
#include "core/context.h"
|
#include "context.h"
|
||||||
|
|
||||||
#include <EASTL/array.h>
|
#include <EASTL/array.h>
|
||||||
#include <EASTL/fixed_vector.h>
|
#include <EASTL/fixed_vector.h>
|
||||||
|
|
||||||
|
constexpr eastl::array VALIDATION_LAYERS = {
|
||||||
|
"VK_LAYER_KHRONOS_validation",
|
||||||
|
};
|
||||||
|
|
||||||
VKAPI_ATTR b32 VKAPI_CALL
|
VKAPI_ATTR b32 VKAPI_CALL
|
||||||
DebugCallback(const VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
DebugCallback(const VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
const VkDebugUtilsMessageTypeFlagsEXT messageType,
|
const VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||||
|
|
@ -35,7 +38,8 @@ 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");
|
||||||
|
|
||||||
|
|
@ -77,6 +81,8 @@ Context::Context(const cstr appName, const Version version, bool enableValidatio
|
||||||
const auto instanceCreateInfo = vk::InstanceCreateInfo{
|
const auto instanceCreateInfo = vk::InstanceCreateInfo{
|
||||||
.pNext = enableValidation ? &debugUtilsMessengerCreateInfo : nullptr,
|
.pNext = enableValidation ? &debugUtilsMessengerCreateInfo : nullptr,
|
||||||
.pApplicationInfo = &appInfo,
|
.pApplicationInfo = &appInfo,
|
||||||
|
.enabledLayerCount = enableValidation ? Cast<u32>(VALIDATION_LAYERS.size()) : 0,
|
||||||
|
.ppEnabledLayerNames = enableValidation ? VALIDATION_LAYERS.data() : nullptr,
|
||||||
.enabledExtensionCount = Cast<u32>(instanceExtensions.size()),
|
.enabledExtensionCount = Cast<u32>(instanceExtensions.size()),
|
||||||
.ppEnabledExtensionNames = instanceExtensions.data(),
|
.ppEnabledExtensionNames = instanceExtensions.data(),
|
||||||
};
|
};
|
||||||
|
|
@ -97,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);
|
||||||
|
|
@ -106,20 +116,13 @@ Context::~Context()
|
||||||
}
|
}
|
||||||
m_Instance.destroy(nullptr);
|
m_Instance.destroy(nullptr);
|
||||||
DEBUG("Instance destroyed");
|
DEBUG("Instance destroyed");
|
||||||
|
|
||||||
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: context.h
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class Context
|
||||||
|
*
|
||||||
|
* @brief Vulkan context to handle device initialization logic.
|
||||||
|
*
|
||||||
|
* Handles the required hardware interactions.
|
||||||
|
*/
|
||||||
|
struct Context final
|
||||||
|
{
|
||||||
|
// Members
|
||||||
|
vk::Instance m_Instance;
|
||||||
|
vk::DebugUtilsMessengerEXT m_DebugMessenger;
|
||||||
|
|
||||||
|
// Ctor/Dtor
|
||||||
|
void Init(cstr appName, Version version, bool enableValidation = ENABLE_VALIDATION_DEFAULT_VALUE);
|
||||||
|
void Destroy();
|
||||||
|
|
||||||
|
[[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
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(std::is_trivially_copyable_v<Context>);
|
||||||
|
static_assert(std::is_trivially_copy_assignable_v<Context>);
|
||||||
|
|
@ -3,11 +3,11 @@
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
// =============================================
|
// =============================================
|
||||||
|
|
||||||
#include "core/device.h"
|
#include "device.h"
|
||||||
|
|
||||||
#include "core/context.h"
|
#include "context.h"
|
||||||
#include "core/physical_device.h"
|
#include "physical_device.h"
|
||||||
#include "core/queue_allocation.h"
|
#include "queue_allocation.h"
|
||||||
|
|
||||||
#include <EASTL/array.h>
|
#include <EASTL/array.h>
|
||||||
#include <EASTL/fixed_vector.h>
|
#include <EASTL/fixed_vector.h>
|
||||||
|
|
@ -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>
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: global.cpp
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#define VMA_IMPLEMENTATION
|
||||||
|
#include <vk_mem_alloc.h>
|
||||||
|
|
||||||
|
// NOTE: Vulkan Dispatch Loader Storage - Should only appear once.
|
||||||
|
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
||||||
|
|
||||||
|
void *
|
||||||
|
operator new[](size_t size, const char * /*pName*/, int /*flags*/, unsigned /*debugFlags*/, const char * /*file*/,
|
||||||
|
int /*line*/)
|
||||||
|
{
|
||||||
|
return new u8[size];
|
||||||
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
operator new[](size_t size, size_t /*alignment*/, size_t /*alignmentOffset*/, const char * /*pName*/, int /*flags*/,
|
||||||
|
unsigned /*debugFlags*/, const char * /*file*/, int /*line*/)
|
||||||
|
{
|
||||||
|
return new u8[size];
|
||||||
|
}
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "util/logger.h"
|
#include "logger.h"
|
||||||
|
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
|
|
@ -26,8 +26,6 @@
|
||||||
#if !defined(NDEBUG)
|
#if !defined(NDEBUG)
|
||||||
#define VULKAN_HPP_ASSERT(expr) DEBUG_IF(!(expr), "Vulkan assert failed")
|
#define VULKAN_HPP_ASSERT(expr) DEBUG_IF(!(expr), "Vulkan assert failed")
|
||||||
#endif
|
#endif
|
||||||
#include "type_traits.h"
|
|
||||||
|
|
||||||
#include <EASTL/fixed_string.h>
|
#include <EASTL/fixed_string.h>
|
||||||
#include <EASTL/string.h>
|
#include <EASTL/string.h>
|
||||||
#include <vk_mem_alloc.h>
|
#include <vk_mem_alloc.h>
|
||||||
|
|
@ -42,12 +40,6 @@ constexpr u32 ASTER_API_VERSION = VK_API_VERSION_1_3;
|
||||||
CLASS_NAME(const CLASS_NAME &other) = delete; \
|
CLASS_NAME(const CLASS_NAME &other) = delete; \
|
||||||
CLASS_NAME &operator=(const CLASS_NAME &other) = delete
|
CLASS_NAME &operator=(const CLASS_NAME &other) = delete
|
||||||
|
|
||||||
#define PIN_MEMORY(CLASS_NAME) \
|
|
||||||
CLASS_NAME(const CLASS_NAME &other) = delete; \
|
|
||||||
CLASS_NAME(CLASS_NAME &&other) noexcept = delete; \
|
|
||||||
CLASS_NAME &operator=(const CLASS_NAME &other) = delete; \
|
|
||||||
CLASS_NAME &operator=(CLASS_NAME &&other) noexcept = delete
|
|
||||||
|
|
||||||
#define Take(ELEMENT) eastl::exchange(ELEMENT, {})
|
#define Take(ELEMENT) eastl::exchange(ELEMENT, {})
|
||||||
|
|
||||||
#define TODO(MSG) assert(false && ("Unimplemented: " MSG))
|
#define TODO(MSG) assert(false && ("Unimplemented: " MSG))
|
||||||
|
|
@ -177,18 +169,6 @@ ClosestPowerOfTwo(const u32 val)
|
||||||
return (smallerPo2 + largerPo2 <= (val << 1)) ? largerPo2 : smallerPo2;
|
return (smallerPo2 + largerPo2 <= (val << 1)) ? largerPo2 : smallerPo2;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] constexpr u32
|
|
||||||
GetMaskOffset(u32 val)
|
|
||||||
{
|
|
||||||
u32 count = 0;
|
|
||||||
while ((val & 1) == 0)
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
val = val >> 1;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct fmt::formatter<vk::Result> : nested_formatter<std::string>
|
struct fmt::formatter<vk::Result> : nested_formatter<std::string>
|
||||||
{
|
{
|
||||||
|
|
@ -3,9 +3,9 @@
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
// =============================================
|
// =============================================
|
||||||
|
|
||||||
#include "core/image.h"
|
#include "image.h"
|
||||||
|
|
||||||
#include "core/device.h"
|
#include "device.h"
|
||||||
|
|
||||||
void
|
void
|
||||||
Image::Destroy(const Device *device)
|
Image::Destroy(const Device *device)
|
||||||
|
|
@ -109,7 +109,7 @@ Remember, we use upside down viewport.
|
||||||
void
|
void
|
||||||
TextureCube::Init(const Device *device, u32 cubeSide, vk::Format imageFormat, bool isMipMapped, cstr name)
|
TextureCube::Init(const Device *device, u32 cubeSide, vk::Format imageFormat, bool isMipMapped, cstr name)
|
||||||
{
|
{
|
||||||
WARN_IF(!IsPowerOfTwo(cubeSide), "Image Cube {1} has side {0}x{0} (Non Power of Two)", cubeSide, name ? name : "<unnamed>");
|
WARN_IF(!IsPowerOfTwo(cubeSide), "Image {1} is {0}x{0} (Non Power of Two)", cubeSide, name ? name : "<unnamed>");
|
||||||
|
|
||||||
const u8 mipLevels = isMipMapped ? 1 + Cast<u8>(floor(log2(cubeSide))) : 1;
|
const u8 mipLevels = isMipMapped ? 1 + Cast<u8>(floor(log2(cubeSide))) : 1;
|
||||||
|
|
||||||
|
|
@ -119,7 +119,7 @@ TextureCube::Init(const Device *device, u32 cubeSide, vk::Format imageFormat, bo
|
||||||
usage |= vk::ImageUsageFlagBits::eTransferSrc;
|
usage |= vk::ImageUsageFlagBits::eTransferSrc;
|
||||||
}
|
}
|
||||||
|
|
||||||
const vk::Extent3D extent = {.width = cubeSide, .height = cubeSide, .depth = 1};
|
vk::Extent3D extent = {.width = cubeSide, .height = cubeSide, .depth = 1};
|
||||||
|
|
||||||
vk::ImageCreateInfo imageCreateInfo = {
|
vk::ImageCreateInfo imageCreateInfo = {
|
||||||
.flags = vk::ImageCreateFlagBits::eCubeCompatible,
|
.flags = vk::ImageCreateFlagBits::eCubeCompatible,
|
||||||
|
|
@ -216,7 +216,7 @@ AttachmentImage::Init(const Device *device, vk::Extent2D extent, vk::Format imag
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
result = device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
||||||
ERROR_IF(Failed(result), "Could not create attachment image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
ERROR_IF(Failed(result), "Could not create depth image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||||
|
|
||||||
m_Image = image;
|
m_Image = image;
|
||||||
m_View = view;
|
m_View = view;
|
||||||
|
|
@ -49,19 +49,13 @@ struct Image
|
||||||
[[nodiscard]] bool IsValid() const;
|
[[nodiscard]] bool IsValid() const;
|
||||||
[[nodiscard]] bool IsOwned() const;
|
[[nodiscard]] bool IsOwned() const;
|
||||||
[[nodiscard]] u32 GetMipLevels() const;
|
[[nodiscard]] u32 GetMipLevels() const;
|
||||||
[[nodiscard]] bool IsCommitted() const;
|
|
||||||
void SetCommitted(bool committed);
|
|
||||||
|
|
||||||
void Destroy(const Device *device);
|
void Destroy(const Device *device);
|
||||||
|
|
||||||
constexpr static u8 VALID_BIT = 1u << 7;
|
constexpr static u8 VALID_BIT = 1u << 7;
|
||||||
constexpr static u8 OWNED_BIT = 1u << 6;
|
constexpr static u8 OWNED_BIT = 1u << 6;
|
||||||
constexpr static u8 COMMITTED_BIT = 1u << 5;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
|
||||||
constexpr bool concepts::GpuResource<Image> = true;
|
|
||||||
|
|
||||||
struct Texture : Image
|
struct Texture : Image
|
||||||
{
|
{
|
||||||
void Init(const Device *device, vk::Extent2D extent, vk::Format imageFormat, bool isMipMapped, cstr name = nullptr);
|
void Init(const Device *device, vk::Extent2D extent, vk::Format imageFormat, bool isMipMapped, cstr name = nullptr);
|
||||||
|
|
@ -123,15 +117,3 @@ Image::GetMipLevels() const
|
||||||
{
|
{
|
||||||
return m_MipLevels;
|
return m_MipLevels;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool
|
|
||||||
Image::IsCommitted() const
|
|
||||||
{
|
|
||||||
return m_Flags_ & COMMITTED_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void
|
|
||||||
Image::SetCommitted(const bool committed)
|
|
||||||
{
|
|
||||||
m_Flags_ = committed ? (m_Flags_ | COMMITTED_BIT) : (m_Flags_ & ~COMMITTED_BIT);
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
# CMakeList.txt ; CMake project for Aster Util Headers
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
|
|
||||||
add_subdirectory("aster")
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
# CMakeList.txt ; CMake project for Aster Util Headers
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
|
|
||||||
add_subdirectory("core")
|
|
||||||
add_subdirectory("systems")
|
|
||||||
add_subdirectory("util")
|
|
||||||
|
|
||||||
target_sources(aster_core
|
|
||||||
PUBLIC "aster.h")
|
|
||||||
|
|
||||||
target_precompile_headers(aster_core PUBLIC "aster.h")
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
// =============================================
|
|
||||||
// Aster: aster.h
|
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
|
||||||
// =============================================
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "core/global.h"
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
# CMakeList.txt ; CMake project for Aster Core Headers
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
|
|
||||||
target_sources(aster_core
|
|
||||||
INTERFACE
|
|
||||||
"global.h"
|
|
||||||
"constants.h"
|
|
||||||
"config.h"
|
|
||||||
"context.h"
|
|
||||||
"physical_device.h"
|
|
||||||
"device.h"
|
|
||||||
"swapchain.h"
|
|
||||||
"pipeline.h"
|
|
||||||
"queue_allocation.h"
|
|
||||||
"buffer.h"
|
|
||||||
"image.h"
|
|
||||||
"surface.h"
|
|
||||||
"size.h"
|
|
||||||
"type_traits.h"
|
|
||||||
"window.h")
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
// =============================================
|
|
||||||
// Aster: context.h
|
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
|
||||||
// =============================================
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "global.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @class Context
|
|
||||||
*
|
|
||||||
* @brief Vulkan context to handle device initialization logic.
|
|
||||||
*
|
|
||||||
* Handles the required hardware interactions.
|
|
||||||
*/
|
|
||||||
struct Context final
|
|
||||||
{
|
|
||||||
// Members
|
|
||||||
vk::Instance m_Instance = nullptr;
|
|
||||||
vk::DebugUtilsMessengerEXT m_DebugMessenger = nullptr;
|
|
||||||
|
|
||||||
// Ctor/Dtor
|
|
||||||
Context(cstr appName, Version version, bool enableValidation = ENABLE_LAYER_MESSAGES_DEFAULT_VALUE);
|
|
||||||
~Context();
|
|
||||||
|
|
||||||
// Move
|
|
||||||
Context(Context &&other) noexcept;
|
|
||||||
Context &operator=(Context &&other) noexcept;
|
|
||||||
|
|
||||||
#if !defined(ASTER_NDEBUG)
|
|
||||||
constexpr static bool ENABLE_LAYER_MESSAGES_DEFAULT_VALUE = true;
|
|
||||||
#else
|
|
||||||
constexpr static bool ENABLE_LAYER_MESSAGES_DEFAULT_VALUE = false;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(Context);
|
|
||||||
};
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
// =============================================
|
|
||||||
// Aster: surface.h
|
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
|
||||||
// =============================================
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "global.h"
|
|
||||||
|
|
||||||
struct Context;
|
|
||||||
struct Window;
|
|
||||||
|
|
||||||
struct Surface
|
|
||||||
{
|
|
||||||
Context *m_Context;
|
|
||||||
vk::SurfaceKHR m_Surface;
|
|
||||||
NameString m_Name;
|
|
||||||
|
|
||||||
// Ctor Dtor
|
|
||||||
Surface(Context *context, const Window *window, cstr name);
|
|
||||||
~Surface();
|
|
||||||
|
|
||||||
// Move
|
|
||||||
Surface(Surface &&other) noexcept;
|
|
||||||
Surface &operator=(Surface &&other) noexcept;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(Surface);
|
|
||||||
};
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
// =============================================
|
|
||||||
// Aster: type_traits.h
|
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
|
||||||
// =============================================
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
struct Device;
|
|
||||||
|
|
||||||
namespace concepts
|
|
||||||
{
|
|
||||||
template <typename T>
|
|
||||||
concept DeviceDestructible = requires(T a, Device *p) {
|
|
||||||
{ a.Destroy(p) } -> std::convertible_to<void>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
concept Committable = requires(T a, bool v) {
|
|
||||||
{ a.IsCommitted() } -> std::convertible_to<bool>;
|
|
||||||
{ a.SetCommitted(v) } -> std::convertible_to<void>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
constexpr bool GpuResource = false;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
concept RenderResource = GpuResource<T> and std::is_default_constructible_v<T> and std::is_trivially_copyable_v<T> and
|
|
||||||
DeviceDestructible<T> and Committable<T>;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
constexpr bool IsHandle = false;
|
|
||||||
|
|
||||||
template <typename THandle>
|
|
||||||
concept HandleType = IsHandle<THandle> and RenderResource<typename THandle::Type>;
|
|
||||||
|
|
||||||
} // namespace concepts
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
# CMakeList.txt ; CMake project for Aster Util Headers
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
|
|
||||||
target_sources(aster_core
|
|
||||||
INTERFACE
|
|
||||||
"manager.h"
|
|
||||||
"buffer_manager.h"
|
|
||||||
"image_manager.h"
|
|
||||||
"render_resource_manager.h")
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
// =============================================
|
|
||||||
// Aster: buffer_manager.h
|
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
|
||||||
// =============================================
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "aster/aster.h"
|
|
||||||
#include "aster/core/buffer.h"
|
|
||||||
#include "manager.h"
|
|
||||||
|
|
||||||
namespace systems
|
|
||||||
{
|
|
||||||
using BufferHandle = Handle<Buffer>;
|
|
||||||
|
|
||||||
class BufferManager final : public Manager<Buffer>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
BufferManager(const Device *device, const u32 maxCount, const u8 binding);
|
|
||||||
|
|
||||||
[[nodiscard]] Handle CreateStorageBuffer(usize size, cstr name = nullptr);
|
|
||||||
[[nodiscard]] Handle CreateUniformBuffer(usize size, cstr name = nullptr);
|
|
||||||
};
|
|
||||||
} // namespace systems
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
// =============================================
|
|
||||||
// Aster: image_manager.h
|
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
|
||||||
// =============================================
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "aster/aster.h"
|
|
||||||
#include "aster/core/image.h"
|
|
||||||
#include "manager.h"
|
|
||||||
|
|
||||||
namespace systems
|
|
||||||
{
|
|
||||||
|
|
||||||
struct Texture2DCreateInfo
|
|
||||||
{
|
|
||||||
vk::Format m_Format = vk::Format::eUndefined;
|
|
||||||
vk::Extent2D m_Extent = {};
|
|
||||||
cstr m_Name = nullptr;
|
|
||||||
bool m_IsSampled = true;
|
|
||||||
bool m_IsMipMapped = false;
|
|
||||||
bool m_IsStorage = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TextureCubeCreateInfo
|
|
||||||
{
|
|
||||||
vk::Format m_Format = vk::Format::eUndefined;
|
|
||||||
u32 m_Side = 0;
|
|
||||||
cstr m_Name = nullptr;
|
|
||||||
bool m_IsSampled = true;
|
|
||||||
bool m_IsMipMapped = false;
|
|
||||||
bool m_IsStorage = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AttachmentCreateInfo
|
|
||||||
{
|
|
||||||
vk::Format m_Format = vk::Format::eUndefined;
|
|
||||||
vk::Extent2D m_Extent = {};
|
|
||||||
cstr m_Name = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DepthStencilImageCreateInfo
|
|
||||||
{
|
|
||||||
vk::Extent2D m_Extent = {};
|
|
||||||
cstr m_Name = nullptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
using ImageHandle = Handle<Image>;
|
|
||||||
|
|
||||||
class ImageManager final : public Manager<Image>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ImageManager(const Device *device, const u32 maxCount, const u8 binding);
|
|
||||||
|
|
||||||
[[nodiscard]] Handle CreateTexture2D(const Texture2DCreateInfo &createInfo);
|
|
||||||
[[nodiscard]] Handle CreateTextureCube(const TextureCubeCreateInfo &createInfo);
|
|
||||||
[[nodiscard]] Handle CreateAttachment(const AttachmentCreateInfo &createInfo);
|
|
||||||
[[nodiscard]] Handle CreateDepthStencilImage(const DepthStencilImageCreateInfo &createInfo);
|
|
||||||
};
|
|
||||||
} // namespace systems
|
|
||||||
|
|
@ -1,361 +0,0 @@
|
||||||
// =============================================
|
|
||||||
// Aster: manager.h
|
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
|
||||||
// =============================================
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "aster/aster.h"
|
|
||||||
#include "aster/core/type_traits.h"
|
|
||||||
|
|
||||||
struct Device;
|
|
||||||
|
|
||||||
template <concepts::RenderResource T>
|
|
||||||
class Handle;
|
|
||||||
|
|
||||||
template <concepts::RenderResource T>
|
|
||||||
class Manager
|
|
||||||
{
|
|
||||||
friend Handle<T>;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using Type = T;
|
|
||||||
using Handle = Handle<Type>;
|
|
||||||
static_assert(sizeof(Handle) == sizeof(u32));
|
|
||||||
constexpr static u32 MAX_HANDLES = Handle::INDEX_MASK + 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for the Manager class template.
|
|
||||||
* @param device Device with which resources are created.
|
|
||||||
* @param maxCount Max number of resources that can be created (maxCount <= Handle::INDEX_MASK)
|
|
||||||
* @param binding The shader binding at which this manager will bind its resources.
|
|
||||||
*/
|
|
||||||
explicit Manager(const Device *device, const u32 maxCount, const u8 binding)
|
|
||||||
: m_MaxCount{maxCount}
|
|
||||||
, m_Binding{binding}
|
|
||||||
, m_Device{device}
|
|
||||||
{
|
|
||||||
assert(!m_Instance);
|
|
||||||
assert(maxCount <= MAX_HANDLES);
|
|
||||||
|
|
||||||
m_Data = new Type[m_MaxCount];
|
|
||||||
m_RefCount = new std::atomic<u32>[m_MaxCount];
|
|
||||||
|
|
||||||
for (u32 i = 0; i < m_MaxCount; ++i)
|
|
||||||
{
|
|
||||||
*Recast<u32 *>(&m_Data[i]) = (i + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Instance = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~Manager()
|
|
||||||
{
|
|
||||||
if (!m_Data)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (u32 i = 0; i < m_MaxCount; ++i)
|
|
||||||
{
|
|
||||||
m_Data[i].Destroy(m_Device);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] m_Data;
|
|
||||||
delete[] m_RefCount;
|
|
||||||
m_Data = nullptr;
|
|
||||||
m_RefCount = nullptr;
|
|
||||||
m_MaxCount = 0;
|
|
||||||
m_FreeHead = 0;
|
|
||||||
m_Device = nullptr;
|
|
||||||
|
|
||||||
m_Instance = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @warning only to be used internally.
|
|
||||||
* @return The only constructed instance of this manager.
|
|
||||||
*/
|
|
||||||
static Manager *
|
|
||||||
Instance()
|
|
||||||
{
|
|
||||||
assert(m_Instance);
|
|
||||||
return m_Instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
PIN_MEMORY(Manager);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Type *m_Data = nullptr; // Data also keeps the freelist during 'not use'.
|
|
||||||
std::atomic<u32> *m_RefCount = nullptr; // Associated reference count for each of the instances in Data.
|
|
||||||
u32 m_MaxCount = 0; // Max number of resources supported.
|
|
||||||
u32 m_FreeHead = 0;
|
|
||||||
u8 m_Binding = 0;
|
|
||||||
|
|
||||||
static Manager *m_Instance;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User is expected to type-check.
|
|
||||||
* @param index Actual index of the resource in the m_Data array. Not type checked.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
AddRef(const u32 index)
|
|
||||||
{
|
|
||||||
assert(index < m_MaxCount);
|
|
||||||
++m_RefCount[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User is expected to type-check.
|
|
||||||
* @param index Actual index of the resource in the m_Data array. Not type checked.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
Release(const u32 index)
|
|
||||||
{
|
|
||||||
assert(index < m_MaxCount);
|
|
||||||
const u32 rc = --m_RefCount[index];
|
|
||||||
assert(rc != MaxValue<u32>);
|
|
||||||
if (rc == 0)
|
|
||||||
{
|
|
||||||
// TODO: Don't destroy here. Separate out to a cleanup routine.
|
|
||||||
m_Data[index].Destroy(m_Device);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User is expected to type-check.
|
|
||||||
* @param index Actual index of the resource in the m_Data array. Not type checked.
|
|
||||||
* @return Pointer to the resource at the index.
|
|
||||||
*/
|
|
||||||
Type *
|
|
||||||
Fetch(const u32 index)
|
|
||||||
{
|
|
||||||
assert(index < m_MaxCount);
|
|
||||||
return &m_Data[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
const Device *m_Device;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal Method to Allocate a resource on the manager.
|
|
||||||
* @return [Handle, Type*] Where Type* is available to initialize the resource.
|
|
||||||
*/
|
|
||||||
[[nodiscard]] std::pair<Handle, Type *>
|
|
||||||
Alloc()
|
|
||||||
{
|
|
||||||
ERROR_IF(m_FreeHead >= m_MaxCount, "Max buffers allocated.") THEN_ABORT(-1);
|
|
||||||
|
|
||||||
const auto index = m_FreeHead;
|
|
||||||
Type *pAlloc = &m_Data[index];
|
|
||||||
m_FreeHead = *Recast<u32 *>(pAlloc);
|
|
||||||
return {Handle{index, m_Binding}, pAlloc};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <concepts::RenderResource T>
|
|
||||||
class Ref
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using Type = T;
|
|
||||||
using Handle = Handle<Type>;
|
|
||||||
using Manager = Manager<Type>;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
Handle m_Handle;
|
|
||||||
Type *m_Pointer = nullptr;
|
|
||||||
|
|
||||||
friend Handle;
|
|
||||||
|
|
||||||
void
|
|
||||||
InitPtr()
|
|
||||||
{
|
|
||||||
m_Pointer = m_Handle.Fetch();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
Type *
|
|
||||||
Get()
|
|
||||||
{
|
|
||||||
assert(m_Pointer);
|
|
||||||
return m_Pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Type *
|
|
||||||
Get() const
|
|
||||||
{
|
|
||||||
assert(m_Pointer);
|
|
||||||
return m_Pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
Type *
|
|
||||||
operator->()
|
|
||||||
{
|
|
||||||
return Get();
|
|
||||||
}
|
|
||||||
|
|
||||||
const Type *
|
|
||||||
operator->() const
|
|
||||||
{
|
|
||||||
return Get();
|
|
||||||
}
|
|
||||||
|
|
||||||
Type &
|
|
||||||
operator*()
|
|
||||||
{
|
|
||||||
return *Get();
|
|
||||||
}
|
|
||||||
|
|
||||||
const Type &
|
|
||||||
operator*() const
|
|
||||||
{
|
|
||||||
return Get();
|
|
||||||
}
|
|
||||||
|
|
||||||
// The only constructor requires a valid construction.
|
|
||||||
explicit Ref(Handle &&handle)
|
|
||||||
: m_Handle{std::forward<Handle>(handle)}
|
|
||||||
{
|
|
||||||
InitPtr();
|
|
||||||
}
|
|
||||||
|
|
||||||
// The only constructor requires a valid construction.
|
|
||||||
explicit Ref(const Handle &&handle)
|
|
||||||
: m_Handle{handle}
|
|
||||||
{
|
|
||||||
InitPtr();
|
|
||||||
}
|
|
||||||
|
|
||||||
Ref(const Ref &other) = default;
|
|
||||||
Ref(Ref &&other) noexcept = default;
|
|
||||||
Ref &operator=(const Ref &other) = default;
|
|
||||||
Ref &operator=(Ref &&other) noexcept = default;
|
|
||||||
~Ref() = default;
|
|
||||||
};
|
|
||||||
|
|
||||||
class RawHandle
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
constexpr static u32 INVALID_HANDLE = MaxValue<u32>;
|
|
||||||
constexpr static u32 INDEX_MASK = 0x0FFFFFFF;
|
|
||||||
constexpr static u32 TYPE_MASK = ~INDEX_MASK;
|
|
||||||
constexpr static u32 TYPE_OFFSET = GetMaskOffset(TYPE_MASK);
|
|
||||||
u32 m_Internal = INVALID_HANDLE;
|
|
||||||
|
|
||||||
RawHandle(const u32 index, const u8 typeId)
|
|
||||||
: m_Internal{(index & INDEX_MASK) | (typeId & TYPE_MASK)}
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit RawHandle(const u32 internal)
|
|
||||||
: m_Internal{internal}
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
[[nodiscard]] bool
|
|
||||||
IsValid() const
|
|
||||||
{
|
|
||||||
return m_Internal != INVALID_HANDLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] u32
|
|
||||||
GetIndex() const
|
|
||||||
{
|
|
||||||
return m_Internal & INDEX_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] u32
|
|
||||||
GetType() const
|
|
||||||
{
|
|
||||||
return (m_Internal & TYPE_MASK) >> TYPE_OFFSET;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
operator==(const RawHandle &other) const
|
|
||||||
{
|
|
||||||
return m_Internal == other.m_Internal;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <concepts::RenderResource T>
|
|
||||||
class Handle : public RawHandle
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using Type = T;
|
|
||||||
using Manager = Manager<Type>;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// The only constructor requires a valid construction.
|
|
||||||
Handle(const u32 index, const u8 typeId)
|
|
||||||
: RawHandle{index, typeId}
|
|
||||||
{
|
|
||||||
AddRef();
|
|
||||||
}
|
|
||||||
|
|
||||||
friend Manager;
|
|
||||||
friend Ref<T>;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Handle(const Handle &other)
|
|
||||||
: RawHandle{other}
|
|
||||||
{
|
|
||||||
AddRef();
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle(Handle &&other) noexcept
|
|
||||||
: RawHandle{std::exchange(other.m_Internal, m_Internal)}
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] Ref<T>
|
|
||||||
ToPointer()
|
|
||||||
{
|
|
||||||
return Ref{std::move(*this)};
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] Type *
|
|
||||||
Fetch() const
|
|
||||||
{
|
|
||||||
return Manager::Instance()->Fetch(m_Internal);
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle &
|
|
||||||
operator=(const Handle &other)
|
|
||||||
{
|
|
||||||
if (this == &other)
|
|
||||||
return *this;
|
|
||||||
m_Internal = other.m_Internal;
|
|
||||||
AddRef();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
Handle &
|
|
||||||
operator=(Handle &&other) noexcept
|
|
||||||
{
|
|
||||||
if (this == &other)
|
|
||||||
return *this;
|
|
||||||
std::swap(m_Internal, other.m_Internal);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Handle()
|
|
||||||
{
|
|
||||||
if (m_Internal != INVALID_HANDLE)
|
|
||||||
{
|
|
||||||
Release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void
|
|
||||||
AddRef()
|
|
||||||
{
|
|
||||||
Manager::Instance()->AddRef(GetIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
Release()
|
|
||||||
{
|
|
||||||
Manager::Instance()->Release(GetIndex());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
@ -1,157 +0,0 @@
|
||||||
// =============================================
|
|
||||||
// Aster: render_resource_manager.h
|
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
|
||||||
// =============================================
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "aster/aster.h"
|
|
||||||
#include "buffer_manager.h"
|
|
||||||
#include "image_manager.h"
|
|
||||||
|
|
||||||
#include "EASTL/deque.h"
|
|
||||||
#include "EASTL/vector.h"
|
|
||||||
|
|
||||||
namespace systems
|
|
||||||
{
|
|
||||||
|
|
||||||
class RenderResourceManager
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
union WriteInfo {
|
|
||||||
vk::DescriptorBufferInfo uBufferInfo;
|
|
||||||
vk::DescriptorImageInfo uImageInfo;
|
|
||||||
vk::BufferView uBufferView;
|
|
||||||
|
|
||||||
explicit WriteInfo(const vk::DescriptorBufferInfo &info);
|
|
||||||
explicit WriteInfo(const vk::DescriptorImageInfo &info);
|
|
||||||
explicit WriteInfo(const vk::BufferView &info);
|
|
||||||
};
|
|
||||||
|
|
||||||
using WriteCommand = vk::WriteDescriptorSet;
|
|
||||||
|
|
||||||
union WriteOwner {
|
|
||||||
Handle<Buffer> uBufferHandle;
|
|
||||||
Handle<Image> uImageHandle;
|
|
||||||
|
|
||||||
explicit WriteOwner(const Handle<Buffer> &handle);
|
|
||||||
explicit WriteOwner(const Handle<Image> &handle);
|
|
||||||
|
|
||||||
WriteOwner(const WriteOwner &other)
|
|
||||||
{
|
|
||||||
switch (uRawHandle.GetType())
|
|
||||||
{
|
|
||||||
case BUFFER_BINDING_INDEX:
|
|
||||||
uBufferHandle = other.uBufferHandle;
|
|
||||||
break;
|
|
||||||
case IMAGE_BINDING_INDEX:
|
|
||||||
uImageHandle = other.uImageHandle;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ERROR("Invalid Handle type.") THEN_ABORT(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteOwner(WriteOwner &&other) noexcept
|
|
||||||
{
|
|
||||||
switch (uRawHandle.GetType())
|
|
||||||
{
|
|
||||||
case BUFFER_BINDING_INDEX:
|
|
||||||
uBufferHandle = std::move(other.uBufferHandle);
|
|
||||||
break;
|
|
||||||
case IMAGE_BINDING_INDEX:
|
|
||||||
uImageHandle = std::move(other.uImageHandle);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ERROR("Invalid Handle type.") THEN_ABORT(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteOwner &
|
|
||||||
operator=(const WriteOwner &other)
|
|
||||||
{
|
|
||||||
if (this == &other)
|
|
||||||
return *this;
|
|
||||||
|
|
||||||
switch (uRawHandle.GetType())
|
|
||||||
{
|
|
||||||
case BUFFER_BINDING_INDEX:
|
|
||||||
uBufferHandle = other.uBufferHandle;
|
|
||||||
break;
|
|
||||||
case IMAGE_BINDING_INDEX:
|
|
||||||
uImageHandle = other.uImageHandle;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ERROR("Invalid Handle type.") THEN_ABORT(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
WriteOwner &
|
|
||||||
operator=(WriteOwner &&other) noexcept
|
|
||||||
{
|
|
||||||
if (this == &other)
|
|
||||||
return *this;
|
|
||||||
|
|
||||||
switch (uRawHandle.GetType())
|
|
||||||
{
|
|
||||||
case BUFFER_BINDING_INDEX:
|
|
||||||
uBufferHandle = std::move(other.uBufferHandle);
|
|
||||||
break;
|
|
||||||
case IMAGE_BINDING_INDEX:
|
|
||||||
uImageHandle = std::move(other.uImageHandle);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ERROR("Invalid Handle type.") THEN_ABORT(-1);
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
~WriteOwner()
|
|
||||||
{
|
|
||||||
switch (uRawHandle.GetType())
|
|
||||||
{
|
|
||||||
case BUFFER_BINDING_INDEX:
|
|
||||||
uBufferHandle.~Handle();
|
|
||||||
return;
|
|
||||||
case IMAGE_BINDING_INDEX:
|
|
||||||
uImageHandle.~Handle();
|
|
||||||
return;
|
|
||||||
default:
|
|
||||||
ERROR("Invalid Handle type.") THEN_ABORT(-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
RawHandle uRawHandle;
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
|
||||||
RenderResourceManager(const Device *device, u32 maxBuffers, u32 maxImages);
|
|
||||||
|
|
||||||
void Commit(concepts::HandleType auto &handle);
|
|
||||||
|
|
||||||
private:
|
|
||||||
BufferManager m_BufferManager;
|
|
||||||
ImageManager m_ImageManager;
|
|
||||||
|
|
||||||
vk::DescriptorPool m_DescriptorPool;
|
|
||||||
vk::DescriptorSetLayout m_SetLayout;
|
|
||||||
vk::DescriptorSet m_DescriptorSet;
|
|
||||||
|
|
||||||
constexpr static u8 BUFFER_BINDING_INDEX = 0;
|
|
||||||
constexpr static u8 IMAGE_BINDING_INDEX = 1;
|
|
||||||
|
|
||||||
eastl::vector<vk::WriteDescriptorSet> m_Writes;
|
|
||||||
eastl::deque<WriteInfo> m_WriteInfos;
|
|
||||||
eastl::vector<WriteOwner> m_WriteOwner;
|
|
||||||
|
|
||||||
#if !defined(ASTER_NDEBUG)
|
|
||||||
usize m_CommitedBufferCount = 0;
|
|
||||||
usize m_CommitedTextureCount = 0;
|
|
||||||
usize m_CommitedStorageTextureCount = 0;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace systems
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
# CMakeList.txt ; CMake project for Aster Util Headers
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
|
|
||||||
target_sources(aster_core
|
|
||||||
INTERFACE "logger.h")
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
// =============================================
|
// =============================================
|
||||||
|
|
||||||
#include "util/logger.h"
|
#include "logger.h"
|
||||||
|
|
||||||
Logger g_Logger = Logger();
|
Logger g_Logger = Logger();
|
||||||
// ReSharper disable once CppInconsistentNaming
|
// ReSharper disable once CppInconsistentNaming
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "aster/core/constants.h"
|
#include "constants.h"
|
||||||
#include <debugbreak.h>
|
#include <debugbreak.h>
|
||||||
#include <fmt/core.h>
|
#include <fmt/core.h>
|
||||||
|
|
||||||
|
|
@ -3,10 +3,11 @@
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
// =============================================
|
// =============================================
|
||||||
|
|
||||||
#include "core/physical_device.h"
|
#include "physical_device.h"
|
||||||
|
|
||||||
#include "core/context.h"
|
#include "context.h"
|
||||||
#include "core/surface.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)
|
||||||
{
|
{
|
||||||
|
|
@ -156,9 +175,42 @@ EnumeratePhysicalDevices(const vk::Instance instance)
|
||||||
|
|
||||||
PhysicalDevices::PhysicalDevices(const Surface *surface, const Context *context)
|
PhysicalDevices::PhysicalDevices(const Surface *surface, const Context *context)
|
||||||
{
|
{
|
||||||
|
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->m_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);
|
||||||
|
}
|
||||||
|
|
@ -6,10 +6,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "surface.h"
|
|
||||||
|
|
||||||
#include <EASTL/fixed_vector.h>
|
#include <EASTL/fixed_vector.h>
|
||||||
|
|
||||||
|
struct QueueAllocation;
|
||||||
|
struct Surface;
|
||||||
struct Window;
|
struct Window;
|
||||||
struct Context;
|
struct Context;
|
||||||
|
|
||||||
|
|
@ -49,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 Surface *surface, 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);
|
||||||
|
|
@ -3,9 +3,9 @@
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
// =============================================
|
// =============================================
|
||||||
|
|
||||||
#include "core/pipeline.h"
|
#include "pipeline.h"
|
||||||
|
|
||||||
#include "core/device.h"
|
#include "device.h"
|
||||||
|
|
||||||
Pipeline::Pipeline(const Device *device, vk::PipelineLayout layout, vk::Pipeline pipeline,
|
Pipeline::Pipeline(const Device *device, vk::PipelineLayout layout, vk::Pipeline pipeline,
|
||||||
eastl::vector<vk::DescriptorSetLayout> &&setLayouts)
|
eastl::vector<vk::DescriptorSetLayout> &&setLayouts)
|
||||||
|
|
@ -7,14 +7,19 @@
|
||||||
|
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
|
||||||
struct Size2D
|
struct Size
|
||||||
{
|
{
|
||||||
u32 m_Width;
|
u32 m_Width;
|
||||||
u32 m_Height;
|
u32 m_Height;
|
||||||
|
|
||||||
explicit
|
|
||||||
operator vk::Extent2D() const
|
operator vk::Extent2D() const
|
||||||
{
|
{
|
||||||
return {m_Width, m_Height};
|
return {m_Width, m_Height};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec<2, u32>
|
||||||
|
ToVec()
|
||||||
|
{
|
||||||
|
return {m_Width, m_Height};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
# CMakeList.txt ; CMake project for Aster Util Headers
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
|
|
||||||
add_subdirectory("aster")
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
# CMakeList.txt ; CMake project for Aster Util Headers
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
|
|
||||||
add_subdirectory("core")
|
|
||||||
add_subdirectory("systems")
|
|
||||||
add_subdirectory("util")
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
# CMakeList.txt ; CMake project for Aster Util Headers
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
|
|
||||||
target_sources(aster_core
|
|
||||||
PRIVATE
|
|
||||||
"global.cpp"
|
|
||||||
"context.cpp"
|
|
||||||
"physical_device.cpp"
|
|
||||||
"device.cpp"
|
|
||||||
"swapchain.cpp"
|
|
||||||
"pipeline.cpp"
|
|
||||||
"buffer.cpp"
|
|
||||||
"image.cpp"
|
|
||||||
"surface.cpp"
|
|
||||||
"window.cpp")
|
|
||||||
|
|
@ -1,92 +0,0 @@
|
||||||
// =============================================
|
|
||||||
// Aster: global.cpp
|
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
|
||||||
// =============================================
|
|
||||||
|
|
||||||
#include "core/global.h"
|
|
||||||
|
|
||||||
#include <cstdarg>
|
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
#define VMA_IMPLEMENTATION
|
|
||||||
#include <vk_mem_alloc.h>
|
|
||||||
|
|
||||||
// NOTE: Vulkan Dispatch Loader Storage - Should only appear once.
|
|
||||||
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
|
|
||||||
|
|
||||||
struct MemorySize
|
|
||||||
{
|
|
||||||
u16 m_Gigabytes;
|
|
||||||
u16 m_Megabytes;
|
|
||||||
u16 m_Kilobytes;
|
|
||||||
u16 m_Bytes;
|
|
||||||
|
|
||||||
MemorySize &
|
|
||||||
operator+=(usize bytes)
|
|
||||||
{
|
|
||||||
usize totalBytes = bytes + m_Bytes;
|
|
||||||
m_Bytes = totalBytes % 1024;
|
|
||||||
const usize totalKb = m_Kilobytes + totalBytes / 1024;
|
|
||||||
m_Kilobytes = totalKb % 1024;
|
|
||||||
const usize totalMb = m_Megabytes + totalKb / 1024;
|
|
||||||
m_Megabytes = totalMb % 1024;
|
|
||||||
m_Gigabytes += Cast<u16>(totalMb / 1024);
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
MemorySize g_TotalAlloc = {};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct fmt::formatter<MemorySize>
|
|
||||||
{
|
|
||||||
// ReSharper disable once CppInconsistentNaming
|
|
||||||
constexpr auto
|
|
||||||
parse(format_parse_context &ctx)
|
|
||||||
{
|
|
||||||
return ctx.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Context>
|
|
||||||
// ReSharper disable once CppInconsistentNaming
|
|
||||||
constexpr auto
|
|
||||||
format(MemorySize const &mem, Context &ctx) const
|
|
||||||
{
|
|
||||||
// return format_to(ctx.out(), "({}, {})", foo.a, foo.b); // --== KEY LINE ==--
|
|
||||||
if (mem.m_Gigabytes > 0)
|
|
||||||
{
|
|
||||||
return v10::format_to(ctx.out(), "{}.{} GB", mem.m_Gigabytes, Cast<u16>(mem.m_Megabytes / 1024.0));
|
|
||||||
}
|
|
||||||
if (mem.m_Megabytes > 0)
|
|
||||||
{
|
|
||||||
return v10::format_to(ctx.out(), "{}.{} MB", mem.m_Megabytes, Cast<u16>(mem.m_Kilobytes / 1024.0));
|
|
||||||
}
|
|
||||||
if (mem.m_Kilobytes > 0)
|
|
||||||
{
|
|
||||||
return v10::format_to(ctx.out(), "{}.{} KB", mem.m_Kilobytes, Cast<u16>(mem.m_Bytes / 1024.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
return v10::format_to(ctx.out(), "{} Bytes", mem.m_Bytes);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void *
|
|
||||||
operator new[](size_t size, const char * /*pName*/, int flags, unsigned /*debugFlags*/, const char * /*file*/,
|
|
||||||
int /*line*/)
|
|
||||||
{
|
|
||||||
g_TotalAlloc += size;
|
|
||||||
|
|
||||||
VERBOSE("Total: {} - Allocated {} bytes. ({})", g_TotalAlloc, size, (flags & eastl::MEM_TEMP) ? "temp" : "perm");
|
|
||||||
return new u8[size];
|
|
||||||
}
|
|
||||||
|
|
||||||
void *
|
|
||||||
operator new[](size_t size, size_t /*alignment*/, size_t /*alignmentOffset*/, const char * /*pName*/, int flags,
|
|
||||||
unsigned /*debugFlags*/, const char * /*file*/, int /*line*/)
|
|
||||||
{
|
|
||||||
g_TotalAlloc += size;
|
|
||||||
|
|
||||||
VERBOSE("Total: {} - Allocated {} bytes. ({})", g_TotalAlloc, size, (flags & eastl::MEM_TEMP) ? "temp" : "perm");
|
|
||||||
return new u8[size];
|
|
||||||
}
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
// =============================================
|
|
||||||
// Aster: surface.cpp
|
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
|
||||||
// =============================================
|
|
||||||
|
|
||||||
#include "core/surface.h"
|
|
||||||
|
|
||||||
#include "core/context.h"
|
|
||||||
#include "core/window.h"
|
|
||||||
|
|
||||||
Surface::Surface(Context *context, const Window *window, cstr name)
|
|
||||||
: m_Context(context)
|
|
||||||
, m_Name(name)
|
|
||||||
{
|
|
||||||
VkSurfaceKHR surface;
|
|
||||||
auto result = Cast<vk::Result>(
|
|
||||||
glfwCreateWindowSurface(Cast<VkInstance>(m_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_Name);
|
|
||||||
m_Surface = vk::SurfaceKHR(surface);
|
|
||||||
}
|
|
||||||
|
|
||||||
Surface::~Surface()
|
|
||||||
{
|
|
||||||
if (m_Context && m_Surface)
|
|
||||||
{
|
|
||||||
m_Context->m_Instance.destroy(m_Surface, nullptr);
|
|
||||||
DEBUG("Surface Destroyed");
|
|
||||||
|
|
||||||
m_Surface = nullptr;
|
|
||||||
m_Context = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Surface::Surface(Surface &&other) noexcept
|
|
||||||
: m_Context(Take(other.m_Context))
|
|
||||||
, m_Surface(Take(other.m_Surface))
|
|
||||||
, m_Name(std::move(other.m_Name))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Surface &
|
|
||||||
Surface::operator=(Surface &&other) noexcept
|
|
||||||
{
|
|
||||||
if (this == &other)
|
|
||||||
return *this;
|
|
||||||
m_Context = Take(other.m_Context);
|
|
||||||
m_Surface = Take(other.m_Surface);
|
|
||||||
m_Name = std::move(other.m_Name);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
# CMakeList.txt ; CMake project for Aster Util Headers
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
|
|
||||||
target_sources(aster_core
|
|
||||||
PRIVATE
|
|
||||||
"manager.cpp"
|
|
||||||
"buffer_manager.cpp"
|
|
||||||
"image_manager.cpp"
|
|
||||||
"render_resource_manager.cpp")
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
// =============================================
|
|
||||||
// Aster: buffer_manager.cpp
|
|
||||||
// Copyright (c) 2020-2025 Anish Bhobe
|
|
||||||
// =============================================
|
|
||||||
|
|
||||||
#include "systems/buffer_manager.h"
|
|
||||||
|
|
||||||
Manager<Buffer> *Manager<Buffer>::m_Instance = nullptr;
|
|
||||||
|
|
||||||
using namespace systems;
|
|
||||||
|
|
||||||
BufferHandle
|
|
||||||
BufferManager::CreateStorageBuffer(const usize size, const cstr name)
|
|
||||||
{
|
|
||||||
auto [handle, object] = Alloc();
|
|
||||||
|
|
||||||
// TODO: Storage and Index buffer are set.
|
|
||||||
// This is hacky and should be improved.
|
|
||||||
constexpr vk::BufferUsageFlags usage = vk::BufferUsageFlagBits::eStorageBuffer | vk::BufferUsageFlagBits::eIndexBuffer |
|
|
||||||
vk::BufferUsageFlagBits::eShaderDeviceAddress;
|
|
||||||
constexpr VmaAllocationCreateFlags createFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT |
|
|
||||||
VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT |
|
|
||||||
VMA_ALLOCATION_CREATE_MAPPED_BIT;
|
|
||||||
constexpr VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO;
|
|
||||||
object->Allocate(m_Device, size, usage, createFlags, memoryUsage, name);
|
|
||||||
|
|
||||||
return std::move(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
Manager<Buffer>::Handle
|
|
||||||
BufferManager::CreateUniformBuffer(const usize size, const cstr name)
|
|
||||||
{
|
|
||||||
auto [handle, object] = Alloc();
|
|
||||||
|
|
||||||
constexpr vk::BufferUsageFlags usage = vk::BufferUsageFlagBits::eUniformBuffer;
|
|
||||||
constexpr VmaAllocationCreateFlags createFlags = VMA_ALLOCATION_CREATE_HOST_ACCESS_SEQUENTIAL_WRITE_BIT |
|
|
||||||
VMA_ALLOCATION_CREATE_HOST_ACCESS_ALLOW_TRANSFER_INSTEAD_BIT |
|
|
||||||
VMA_ALLOCATION_CREATE_MAPPED_BIT;
|
|
||||||
constexpr VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO;
|
|
||||||
object->Allocate(m_Device, size, usage, createFlags, memoryUsage, name);
|
|
||||||
|
|
||||||
return std::move(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
BufferManager::BufferManager(const Device *device, const u32 maxCount, const u8 binding)
|
|
||||||
: Manager{device, maxCount, binding}
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
@ -1,316 +0,0 @@
|
||||||
// =============================================
|
|
||||||
// Aster: buffer_manager.cpp
|
|
||||||
// Copyright (c) 2020-2025 Anish Bhobe
|
|
||||||
// =============================================
|
|
||||||
|
|
||||||
#include "systems/image_manager.h"
|
|
||||||
|
|
||||||
#include "core/device.h"
|
|
||||||
|
|
||||||
Manager<Image> *Manager<Image>::m_Instance = nullptr;
|
|
||||||
|
|
||||||
using namespace systems;
|
|
||||||
|
|
||||||
vk::ImageCreateInfo ToImageCreateInfo(const Texture2DCreateInfo &createInfo);
|
|
||||||
vk::ImageCreateInfo ToImageCreateInfo(const TextureCubeCreateInfo &createInfo);
|
|
||||||
vk::ImageCreateInfo ToImageCreateInfo(const AttachmentCreateInfo &createInfo);
|
|
||||||
vk::ImageCreateInfo ToImageCreateInfo(const DepthStencilImageCreateInfo &createInfo);
|
|
||||||
|
|
||||||
namespace usage_flags
|
|
||||||
{
|
|
||||||
constexpr vk::ImageUsageFlags MIPMAP = vk::ImageUsageFlagBits::eTransferSrc | vk::ImageUsageFlagBits::eTransferDst;
|
|
||||||
constexpr vk::ImageUsageFlags SAMPLE = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst;
|
|
||||||
constexpr vk::ImageUsageFlags STORAGE =
|
|
||||||
vk::ImageUsageFlagBits::eStorage | vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eTransferSrc;
|
|
||||||
constexpr vk::ImageUsageFlags COLOR_ATTACHMENT =
|
|
||||||
vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eTransferSrc;
|
|
||||||
constexpr vk::ImageUsageFlags DEPTH_STENCIL_ATTACHMENT = vk::ImageUsageFlagBits::eDepthStencilAttachment;
|
|
||||||
} // namespace usage_flags
|
|
||||||
|
|
||||||
ImageHandle
|
|
||||||
ImageManager::CreateTexture2D(const Texture2DCreateInfo &createInfo)
|
|
||||||
{
|
|
||||||
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
|
||||||
.flags = {},
|
|
||||||
.usage = VMA_MEMORY_USAGE_AUTO,
|
|
||||||
};
|
|
||||||
|
|
||||||
VkImage image;
|
|
||||||
VmaAllocation allocation;
|
|
||||||
vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo);
|
|
||||||
auto result = Cast<vk::Result>(vmaCreateImage(m_Device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
|
||||||
&allocationCreateInfo, &image, &allocation, nullptr));
|
|
||||||
ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result);
|
|
||||||
|
|
||||||
vk::ImageView view;
|
|
||||||
const vk::ImageViewCreateInfo imageViewCreateInfo = {
|
|
||||||
.image = image,
|
|
||||||
.viewType = vk::ImageViewType::e2D,
|
|
||||||
.format = imageCreateInfo.format,
|
|
||||||
.components = {},
|
|
||||||
.subresourceRange =
|
|
||||||
{
|
|
||||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
|
||||||
.baseMipLevel = 0,
|
|
||||||
.levelCount = imageCreateInfo.mipLevels,
|
|
||||||
.baseArrayLayer = 0,
|
|
||||||
.layerCount = imageCreateInfo.arrayLayers,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
result = m_Device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
|
||||||
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result)
|
|
||||||
THEN_ABORT(result);
|
|
||||||
|
|
||||||
auto [handle, object] = Alloc();
|
|
||||||
object->m_Image = image;
|
|
||||||
object->m_View = view;
|
|
||||||
object->m_Allocation = allocation;
|
|
||||||
object->m_Extent = imageCreateInfo.extent;
|
|
||||||
object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT;
|
|
||||||
object->m_LayerCount = Cast<u8>(imageCreateInfo.arrayLayers);
|
|
||||||
object->m_MipLevels = Cast<u8>(imageCreateInfo.mipLevels);
|
|
||||||
|
|
||||||
m_Device->SetName(object->m_Image, createInfo.m_Name);
|
|
||||||
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageHandle
|
|
||||||
ImageManager::CreateTextureCube(const TextureCubeCreateInfo &createInfo)
|
|
||||||
{
|
|
||||||
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
|
||||||
.flags = {},
|
|
||||||
.usage = VMA_MEMORY_USAGE_AUTO,
|
|
||||||
};
|
|
||||||
|
|
||||||
VkImage image;
|
|
||||||
VmaAllocation allocation;
|
|
||||||
vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo);
|
|
||||||
auto result = Cast<vk::Result>(vmaCreateImage(m_Device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
|
||||||
&allocationCreateInfo, &image, &allocation, nullptr));
|
|
||||||
ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result);
|
|
||||||
|
|
||||||
vk::ImageView view;
|
|
||||||
const vk::ImageViewCreateInfo imageViewCreateInfo = {
|
|
||||||
.image = image,
|
|
||||||
.viewType = vk::ImageViewType::eCube,
|
|
||||||
.format = imageCreateInfo.format,
|
|
||||||
.components = {},
|
|
||||||
.subresourceRange =
|
|
||||||
{
|
|
||||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
|
||||||
.baseMipLevel = 0,
|
|
||||||
.levelCount = imageCreateInfo.mipLevels,
|
|
||||||
.baseArrayLayer = 0,
|
|
||||||
.layerCount = imageCreateInfo.arrayLayers,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
result = m_Device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
|
||||||
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result)
|
|
||||||
THEN_ABORT(result);
|
|
||||||
|
|
||||||
auto [handle, object] = Alloc();
|
|
||||||
object->m_Image = image;
|
|
||||||
object->m_View = view;
|
|
||||||
object->m_Allocation = allocation;
|
|
||||||
object->m_Extent = imageCreateInfo.extent;
|
|
||||||
object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT;
|
|
||||||
object->m_LayerCount = Cast<u8>(imageCreateInfo.arrayLayers);
|
|
||||||
object->m_MipLevels = Cast<u8>(imageCreateInfo.mipLevels);
|
|
||||||
|
|
||||||
m_Device->SetName(object->m_Image, createInfo.m_Name);
|
|
||||||
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageHandle
|
|
||||||
ImageManager::CreateAttachment(const AttachmentCreateInfo &createInfo)
|
|
||||||
{
|
|
||||||
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
|
||||||
.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT,
|
|
||||||
.usage = VMA_MEMORY_USAGE_AUTO,
|
|
||||||
};
|
|
||||||
|
|
||||||
VkImage image;
|
|
||||||
VmaAllocation allocation;
|
|
||||||
vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo);
|
|
||||||
auto result = Cast<vk::Result>(vmaCreateImage(m_Device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
|
||||||
&allocationCreateInfo, &image, &allocation, nullptr));
|
|
||||||
ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result);
|
|
||||||
|
|
||||||
vk::ImageView view;
|
|
||||||
const vk::ImageViewCreateInfo imageViewCreateInfo = {
|
|
||||||
.image = image,
|
|
||||||
.viewType = vk::ImageViewType::e2D,
|
|
||||||
.format = imageCreateInfo.format,
|
|
||||||
.components = {},
|
|
||||||
.subresourceRange =
|
|
||||||
{
|
|
||||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
|
||||||
.baseMipLevel = 0,
|
|
||||||
.levelCount = imageCreateInfo.mipLevels,
|
|
||||||
.baseArrayLayer = 0,
|
|
||||||
.layerCount = imageCreateInfo.arrayLayers,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
result = m_Device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
|
||||||
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result)
|
|
||||||
THEN_ABORT(result);
|
|
||||||
|
|
||||||
auto [handle, object] = Alloc();
|
|
||||||
object->m_Image = image;
|
|
||||||
object->m_View = view;
|
|
||||||
object->m_Allocation = allocation;
|
|
||||||
object->m_Extent = imageCreateInfo.extent;
|
|
||||||
object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT;
|
|
||||||
object->m_LayerCount = Cast<u8>(imageCreateInfo.arrayLayers);
|
|
||||||
object->m_MipLevels = Cast<u8>(imageCreateInfo.mipLevels);
|
|
||||||
|
|
||||||
m_Device->SetName(object->m_Image, createInfo.m_Name);
|
|
||||||
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageHandle
|
|
||||||
ImageManager::CreateDepthStencilImage(const DepthStencilImageCreateInfo &createInfo)
|
|
||||||
{
|
|
||||||
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
|
||||||
.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT,
|
|
||||||
.usage = VMA_MEMORY_USAGE_AUTO,
|
|
||||||
};
|
|
||||||
|
|
||||||
VkImage image;
|
|
||||||
VmaAllocation allocation;
|
|
||||||
vk::ImageCreateInfo imageCreateInfo = ToImageCreateInfo(createInfo);
|
|
||||||
auto result = Cast<vk::Result>(vmaCreateImage(m_Device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
|
||||||
&allocationCreateInfo, &image, &allocation, nullptr));
|
|
||||||
ERROR_IF(Failed(result), "Could not allocate image {}. Cause: {}", createInfo.m_Name, result) THEN_ABORT(result);
|
|
||||||
|
|
||||||
vk::ImageView view;
|
|
||||||
const vk::ImageViewCreateInfo imageViewCreateInfo = {
|
|
||||||
.image = image,
|
|
||||||
.viewType = vk::ImageViewType::e2D,
|
|
||||||
.format = imageCreateInfo.format,
|
|
||||||
.components = {},
|
|
||||||
.subresourceRange =
|
|
||||||
{
|
|
||||||
.aspectMask = vk::ImageAspectFlagBits::eDepth | vk::ImageAspectFlagBits::eStencil,
|
|
||||||
.baseMipLevel = 0,
|
|
||||||
.levelCount = imageCreateInfo.mipLevels,
|
|
||||||
.baseArrayLayer = 0,
|
|
||||||
.layerCount = imageCreateInfo.arrayLayers,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
result = m_Device->m_Device.createImageView(&imageViewCreateInfo, nullptr, &view);
|
|
||||||
ERROR_IF(Failed(result), "Could not create image view {}. Cause: {}", createInfo.m_Name, result)
|
|
||||||
THEN_ABORT(result);
|
|
||||||
|
|
||||||
auto [handle, object] = Alloc();
|
|
||||||
object->m_Image = image;
|
|
||||||
object->m_View = view;
|
|
||||||
object->m_Allocation = allocation;
|
|
||||||
object->m_Extent = imageCreateInfo.extent;
|
|
||||||
object->m_Flags_ = Image::OWNED_BIT | Image::VALID_BIT;
|
|
||||||
object->m_LayerCount = Cast<u8>(imageCreateInfo.arrayLayers);
|
|
||||||
object->m_MipLevels = Cast<u8>(imageCreateInfo.mipLevels);
|
|
||||||
|
|
||||||
m_Device->SetName(object->m_Image, createInfo.m_Name);
|
|
||||||
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
vk::ImageCreateInfo
|
|
||||||
ToImageCreateInfo(const Texture2DCreateInfo &createInfo)
|
|
||||||
{
|
|
||||||
auto &[format, extent, name, isSampled, isMipMapped, isStorage] = createInfo;
|
|
||||||
|
|
||||||
WARN_IF(!IsPowerOfTwo(extent.width) || !IsPowerOfTwo(extent.width), "Image {2} is {0}x{1} (Non Power of Two)",
|
|
||||||
extent.width, extent.height, name ? name : "<unnamed>");
|
|
||||||
|
|
||||||
const u8 mipLevels = isMipMapped ? 1 + Cast<u8>(floor(log2(eastl::max(extent.width, extent.height)))) : 1;
|
|
||||||
|
|
||||||
auto usage = vk::ImageUsageFlags{};
|
|
||||||
if (isSampled)
|
|
||||||
usage |= usage_flags::SAMPLE;
|
|
||||||
if (isMipMapped)
|
|
||||||
usage |= usage_flags::MIPMAP;
|
|
||||||
if (isStorage)
|
|
||||||
usage |= usage_flags::STORAGE;
|
|
||||||
|
|
||||||
return {
|
|
||||||
.imageType = vk::ImageType::e2D,
|
|
||||||
.format = format,
|
|
||||||
.extent = ToExtent3D(extent, 1),
|
|
||||||
.mipLevels = mipLevels,
|
|
||||||
.arrayLayers = 1,
|
|
||||||
.usage = usage,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
vk::ImageCreateInfo
|
|
||||||
ToImageCreateInfo(const TextureCubeCreateInfo &createInfo)
|
|
||||||
{
|
|
||||||
auto &[format, side, name, isSampled, isMipMapped, isStorage] = createInfo;
|
|
||||||
|
|
||||||
WARN_IF(!IsPowerOfTwo(side), "ImageCube {1} is {0}x{0} (Non Power of Two)", side, name ? name : "<unnamed>");
|
|
||||||
|
|
||||||
const u8 mipLevels = isMipMapped ? 1 + Cast<u8>(floor(log2(side))) : 1;
|
|
||||||
|
|
||||||
auto usage = vk::ImageUsageFlags{};
|
|
||||||
if (isSampled)
|
|
||||||
usage |= usage_flags::SAMPLE;
|
|
||||||
if (isMipMapped)
|
|
||||||
usage |= usage_flags::MIPMAP;
|
|
||||||
if (isStorage)
|
|
||||||
usage |= usage_flags::STORAGE;
|
|
||||||
|
|
||||||
return {
|
|
||||||
.flags = vk::ImageCreateFlagBits::eCubeCompatible,
|
|
||||||
.imageType = vk::ImageType::e2D,
|
|
||||||
.format = format,
|
|
||||||
.extent = {side, side, 1},
|
|
||||||
.mipLevels = mipLevels,
|
|
||||||
.arrayLayers = 6,
|
|
||||||
.usage = usage,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
vk::ImageCreateInfo
|
|
||||||
ToImageCreateInfo(const AttachmentCreateInfo &createInfo)
|
|
||||||
{
|
|
||||||
auto &[format, extent, name] = createInfo;
|
|
||||||
|
|
||||||
constexpr auto usage = usage_flags::COLOR_ATTACHMENT;
|
|
||||||
|
|
||||||
return {
|
|
||||||
.imageType = vk::ImageType::e2D,
|
|
||||||
.format = format,
|
|
||||||
.extent = ToExtent3D(extent, 1),
|
|
||||||
.mipLevels = 1,
|
|
||||||
.arrayLayers = 1,
|
|
||||||
.usage = usage,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
vk::ImageCreateInfo
|
|
||||||
ToImageCreateInfo(const DepthStencilImageCreateInfo &createInfo)
|
|
||||||
{
|
|
||||||
auto &[extent, name] = createInfo;
|
|
||||||
|
|
||||||
constexpr vk::Format format = vk::Format::eD24UnormS8Uint;
|
|
||||||
constexpr auto usage = usage_flags::DEPTH_STENCIL_ATTACHMENT;
|
|
||||||
|
|
||||||
return {
|
|
||||||
.imageType = vk::ImageType::e2D,
|
|
||||||
.format = format,
|
|
||||||
.extent = ToExtent3D(extent, 1),
|
|
||||||
.mipLevels = 1,
|
|
||||||
.arrayLayers = 1,
|
|
||||||
.usage = usage,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
ImageManager::ImageManager(const Device *device, const u32 maxCount, const u8 binding)
|
|
||||||
: Manager{device, maxCount, binding}
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
// =============================================
|
|
||||||
// Aster: manager.cpp
|
|
||||||
// Copyright (c) 2020-2025 Anish Bhobe
|
|
||||||
// =============================================
|
|
||||||
|
|
||||||
#include "systems/manager.h"
|
|
||||||
|
|
@ -1,195 +0,0 @@
|
||||||
// =============================================
|
|
||||||
// Aster: render_resource_manager.cpp
|
|
||||||
// Copyright (c) 2020-2025 Anish Bhobe
|
|
||||||
// =============================================
|
|
||||||
|
|
||||||
#include "systems/render_resource_manager.h"
|
|
||||||
|
|
||||||
#include "EASTL/array.h"
|
|
||||||
#include "core/device.h"
|
|
||||||
|
|
||||||
#define AbortIfFailed(RESULT) \
|
|
||||||
do \
|
|
||||||
{ \
|
|
||||||
vk::Result _checkResultValue_; \
|
|
||||||
ERROR_IF(Failed(_checkResultValue_ = Cast<vk::Result>(RESULT)), "Cause: {}", _checkResultValue_) \
|
|
||||||
THEN_ABORT(_checkResultValue_); \
|
|
||||||
} while (false)
|
|
||||||
|
|
||||||
#define AbortIfFailedMV(RESULT, MSG, EXTRA) \
|
|
||||||
do \
|
|
||||||
{ \
|
|
||||||
vk::Result _checkResultValue_; \
|
|
||||||
ERROR_IF(Failed(_checkResultValue_ = Cast<vk::Result>(RESULT)), MSG " Cause: {}", EXTRA, _checkResultValue_) \
|
|
||||||
THEN_ABORT(_checkResultValue_); \
|
|
||||||
} while (false)
|
|
||||||
|
|
||||||
#define AbortIfFailedM(RESULT, MSG) \
|
|
||||||
do \
|
|
||||||
{ \
|
|
||||||
auto _checkResultValue_ = Cast<vk::Result>(RESULT); \
|
|
||||||
ERROR_IF(Failed(_checkResultValue_), MSG " Cause: {}", _checkResultValue_) THEN_ABORT(_checkResultValue_); \
|
|
||||||
} while (false)
|
|
||||||
|
|
||||||
|
|
||||||
using namespace systems;
|
|
||||||
|
|
||||||
u32
|
|
||||||
GetHandleInternal(concepts::HandleType auto &handle)
|
|
||||||
{
|
|
||||||
return *Recast<u32 *>(&handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderResourceManager::WriteOwner::WriteOwner(const Handle<Buffer> &handle)
|
|
||||||
: uBufferHandle(handle)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderResourceManager::WriteOwner::WriteOwner(const Handle<Image> &handle)
|
|
||||||
: uImageHandle(handle)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderResourceManager::RenderResourceManager(const Device *device, u32 const maxBuffers, const u32 maxImages)
|
|
||||||
: m_BufferManager{device, maxBuffers, BUFFER_BINDING_INDEX}
|
|
||||||
, m_ImageManager{device, maxImages, IMAGE_BINDING_INDEX}
|
|
||||||
{
|
|
||||||
eastl::array poolSizes = {
|
|
||||||
vk::DescriptorPoolSize{
|
|
||||||
.type = vk::DescriptorType::eStorageBuffer,
|
|
||||||
.descriptorCount = maxBuffers,
|
|
||||||
},
|
|
||||||
vk::DescriptorPoolSize{
|
|
||||||
.type = vk::DescriptorType::eCombinedImageSampler,
|
|
||||||
.descriptorCount = maxImages,
|
|
||||||
},
|
|
||||||
//vk::DescriptorPoolSize{
|
|
||||||
// .type = vk::DescriptorType::eStorageImage,
|
|
||||||
// .descriptorCount = storageTexturesCount,
|
|
||||||
//},
|
|
||||||
};
|
|
||||||
|
|
||||||
const vk::DescriptorPoolCreateInfo poolCreateInfo = {
|
|
||||||
.flags = vk::DescriptorPoolCreateFlagBits::eUpdateAfterBind,
|
|
||||||
.maxSets = 1,
|
|
||||||
.poolSizeCount = Cast<u32>(poolSizes.size()),
|
|
||||||
.pPoolSizes = poolSizes.data(),
|
|
||||||
};
|
|
||||||
AbortIfFailed(device->m_Device.createDescriptorPool(&poolCreateInfo, nullptr, &m_DescriptorPool));
|
|
||||||
|
|
||||||
eastl::array descriptorLayoutBindings = {
|
|
||||||
vk::DescriptorSetLayoutBinding{
|
|
||||||
.binding = BUFFER_BINDING_INDEX,
|
|
||||||
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
|
||||||
.descriptorCount = Cast<u32>(maxBuffers),
|
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
|
||||||
},
|
|
||||||
vk::DescriptorSetLayoutBinding{
|
|
||||||
.binding = IMAGE_BINDING_INDEX,
|
|
||||||
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
|
||||||
.descriptorCount = Cast<u32>(maxImages),
|
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eAll,
|
|
||||||
},
|
|
||||||
//vk::DescriptorSetLayoutBinding{
|
|
||||||
// .binding = STORAGE_TEXTURE_BINDING_INDEX,
|
|
||||||
// .descriptorType = vk::DescriptorType::eStorageImage,
|
|
||||||
// .descriptorCount = Cast<u32>(storageTexturesCount),
|
|
||||||
// .stageFlags = vk::ShaderStageFlagBits::eAll,
|
|
||||||
//},
|
|
||||||
};
|
|
||||||
|
|
||||||
vk::DescriptorBindingFlags bindingFlags =
|
|
||||||
vk::DescriptorBindingFlagBits::ePartiallyBound | vk::DescriptorBindingFlagBits::eUpdateAfterBind;
|
|
||||||
|
|
||||||
eastl::array<vk::DescriptorBindingFlags, decltype(descriptorLayoutBindings)::count> layoutBindingFlags;
|
|
||||||
layoutBindingFlags.fill(bindingFlags);
|
|
||||||
|
|
||||||
vk::DescriptorSetLayoutBindingFlagsCreateInfo bindingFlagsCreateInfo = {
|
|
||||||
.bindingCount = Cast<u32>(layoutBindingFlags.size()),
|
|
||||||
.pBindingFlags = layoutBindingFlags.data(),
|
|
||||||
};
|
|
||||||
|
|
||||||
static_assert(layoutBindingFlags.size() == descriptorLayoutBindings.size());
|
|
||||||
const vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
|
|
||||||
.pNext = &bindingFlagsCreateInfo,
|
|
||||||
.flags = vk::DescriptorSetLayoutCreateFlagBits::eUpdateAfterBindPool,
|
|
||||||
.bindingCount = Cast<u32>(descriptorLayoutBindings.size()),
|
|
||||||
.pBindings = descriptorLayoutBindings.data(),
|
|
||||||
};
|
|
||||||
AbortIfFailed(device->m_Device.createDescriptorSetLayout(&descriptorSetLayoutCreateInfo, nullptr, &m_SetLayout));
|
|
||||||
|
|
||||||
// One descriptor is enough. Updating it at any time is safe. (Update until submit, data held when pending)
|
|
||||||
// https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_descriptor_indexing.html
|
|
||||||
// https://github.com/KhronosGroup/Vulkan-Guide/blob/main/chapters/extensions/VK_EXT_descriptor_indexing.adoc
|
|
||||||
const vk::DescriptorSetAllocateInfo descriptorSetAllocateInfo = {
|
|
||||||
.descriptorPool = m_DescriptorPool,
|
|
||||||
.descriptorSetCount = 1,
|
|
||||||
.pSetLayouts = &m_SetLayout,
|
|
||||||
};
|
|
||||||
AbortIfFailed(device->m_Device.allocateDescriptorSets(&descriptorSetAllocateInfo, &m_DescriptorSet));
|
|
||||||
|
|
||||||
device->SetName(m_SetLayout, "Bindless Layout");
|
|
||||||
device->SetName(m_DescriptorPool, "Bindless Pool");
|
|
||||||
device->SetName(m_DescriptorSet, "Bindless Set");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
systems::RenderResourceManager::Commit(concepts::HandleType auto &handle)
|
|
||||||
{
|
|
||||||
using HandleType = decltype(handle)::Type;
|
|
||||||
if constexpr (std::is_same_v<HandleType, Buffer>)
|
|
||||||
{
|
|
||||||
const Buffer *buffer = handle.Fetch();
|
|
||||||
|
|
||||||
m_WriteInfos.emplace_back(vk::DescriptorBufferInfo{
|
|
||||||
.buffer = buffer->m_Buffer,
|
|
||||||
.offset = 0,
|
|
||||||
.range = buffer->GetSize(),
|
|
||||||
});
|
|
||||||
m_Writes.push_back({
|
|
||||||
.dstSet = m_DescriptorSet,
|
|
||||||
.dstBinding = BUFFER_BINDING_INDEX,
|
|
||||||
.dstArrayElement = handle.GetIndex(),
|
|
||||||
.descriptorCount = 1,
|
|
||||||
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
|
||||||
.pBufferInfo = &m_WriteInfos.back().uBufferInfo,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if constexpr (std::is_same_v<HandleType, Image>)
|
|
||||||
{
|
|
||||||
const Image *image = handle.Fetch();
|
|
||||||
|
|
||||||
m_WriteInfos.emplace_back(vk::DescriptorImageInfo{
|
|
||||||
.sampler = nullptr /* TODO Sampler */,
|
|
||||||
.imageView = image->m_View,
|
|
||||||
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
|
||||||
});
|
|
||||||
m_Writes.push_back({
|
|
||||||
.dstSet = m_DescriptorSet,
|
|
||||||
.dstBinding = IMAGE_BINDING_INDEX,
|
|
||||||
.dstArrayElement = handle.GetIndex(),
|
|
||||||
.descriptorCount = 1,
|
|
||||||
.descriptorType = vk::DescriptorType::eSampledImage,
|
|
||||||
.pImageInfo = &m_WriteInfos.back().uImageInfo,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
static_assert(false && "Type is currently unsupported");
|
|
||||||
}
|
|
||||||
|
|
||||||
m_WriteOwner.emplace_back(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderResourceManager::WriteInfo::WriteInfo(const vk::DescriptorBufferInfo &info)
|
|
||||||
: uBufferInfo{info}
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderResourceManager::WriteInfo::WriteInfo(const vk::DescriptorImageInfo &info)
|
|
||||||
: uImageInfo{info}
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderResourceManager::WriteInfo::WriteInfo(const vk::BufferView &info)
|
|
||||||
: uBufferView{info}
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
# CMakeList.txt ; CMake project for Aster Util Headers
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.13)
|
|
||||||
|
|
||||||
target_sources(aster_core PRIVATE "logger.cpp")
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: surface.cpp
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#include "surface.h"
|
||||||
|
|
||||||
|
#include "context.h"
|
||||||
|
#include "window.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
Surface::Init(Context *context, const Window *window)
|
||||||
|
{
|
||||||
|
assert(!m_Surface);
|
||||||
|
|
||||||
|
VkSurfaceKHR surface;
|
||||||
|
auto result = Cast<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);
|
||||||
|
};
|
||||||
|
|
@ -3,68 +3,36 @@
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
// ==============================================
|
// ==============================================
|
||||||
|
|
||||||
#include "core/swapchain.h"
|
#include "swapchain.h"
|
||||||
|
|
||||||
#include "core/device.h"
|
#include "device.h"
|
||||||
#include "core/physical_device.h"
|
#include "physical_device.h"
|
||||||
#include "core/surface.h"
|
#include "surface.h"
|
||||||
|
|
||||||
[[nodiscard]] vk::Extent2D GetExtent(Size2D size, vk::SurfaceCapabilitiesKHR *surfaceCapabilities);
|
[[nodiscard]] vk::Extent2D GetExtent(Size size, vk::SurfaceCapabilitiesKHR *surfaceCapabilities);
|
||||||
|
|
||||||
Swapchain::Swapchain(const Surface *surface, const Device *device, Size2D size, 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(surface, size);
|
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 Surface *surface, Size2D size)
|
Swapchain::Create(const Surface *surface, const Device *device, Size size, cstr name)
|
||||||
{
|
{
|
||||||
auto surfaceCapabilities = GetSurfaceCapabilities(m_Device->m_PhysicalDevice, surface->m_Surface);
|
auto surfaceCapabilities = GetSurfaceCapabilities(device->m_PhysicalDevice, surface->m_Surface);
|
||||||
m_Extent = GetExtent(size, &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, surface->m_Surface);
|
surfaceCapabilities = GetSurfaceCapabilities(device->m_PhysicalDevice, surface->m_Surface);
|
||||||
m_Extent = GetExtent(size, &surfaceCapabilities);
|
m_Extent = GetExtent(size, &surfaceCapabilities);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto surfaceFormats = GetSurfaceFormats(m_Device->m_PhysicalDevice, surface->m_Surface);
|
auto surfaceFormats = GetSurfaceFormats(device->m_PhysicalDevice, surface->m_Surface);
|
||||||
auto presentModes = GetSurfacePresentModes(m_Device->m_PhysicalDevice, surface->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;
|
||||||
|
|
@ -119,29 +87,29 @@ Swapchain::Create(const Surface *surface, Size2D size)
|
||||||
.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 Surface *surface, Size2D size)
|
||||||
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 Surface *surface, Size2D size)
|
||||||
++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,25 +156,25 @@ 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(Size2D size, vk::SurfaceCapabilitiesKHR *surfaceCapabilities)
|
GetExtent(Size size, vk::SurfaceCapabilitiesKHR *surfaceCapabilities)
|
||||||
{
|
{
|
||||||
if (surfaceCapabilities->currentExtent.width != MaxValue<u32>)
|
if (surfaceCapabilities->currentExtent.width != MaxValue<u32>)
|
||||||
{
|
{
|
||||||
|
|
@ -11,17 +11,16 @@
|
||||||
|
|
||||||
#include <EASTL/fixed_vector.h>
|
#include <EASTL/fixed_vector.h>
|
||||||
|
|
||||||
struct PhysicalDevice;
|
|
||||||
struct Surface;
|
struct Surface;
|
||||||
|
struct PhysicalDevice;
|
||||||
|
struct Window;
|
||||||
struct Device;
|
struct Device;
|
||||||
|
|
||||||
struct Swapchain final
|
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;
|
||||||
|
|
@ -29,19 +28,10 @@ struct Swapchain final
|
||||||
|
|
||||||
eastl::vector<FnResizeCallback> m_ResizeCallbacks;
|
eastl::vector<FnResizeCallback> m_ResizeCallbacks;
|
||||||
|
|
||||||
void Create(const Surface *window, Size2D size);
|
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 Surface *window, const Device *device, Size2D size, 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();
|
|
||||||
};
|
};
|
||||||
|
|
@ -3,13 +3,10 @@
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
// =============================================
|
// =============================================
|
||||||
|
|
||||||
#include "core/window.h"
|
#include "window.h"
|
||||||
|
|
||||||
#include "core/context.h"
|
#include "context.h"
|
||||||
#include "util/logger.h"
|
#include "logger.h"
|
||||||
|
|
||||||
std::atomic_uint64_t Window::m_WindowCount = 0;
|
|
||||||
std::atomic_bool Window::m_IsGlfwInit = false;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
Window::RequestExit() const noexcept
|
Window::RequestExit() const noexcept
|
||||||
|
|
@ -29,7 +26,7 @@ Window::SetWindowSize(const u32 width, const u32 height) const noexcept
|
||||||
glfwSetWindowSize(m_Window, Cast<i32>(width), Cast<i32>(height));
|
glfwSetWindowSize(m_Window, Cast<i32>(width), Cast<i32>(height));
|
||||||
}
|
}
|
||||||
|
|
||||||
Size2D
|
vk::Extent2D
|
||||||
Window::GetSize() const
|
Window::GetSize() const
|
||||||
{
|
{
|
||||||
int width;
|
int width;
|
||||||
|
|
@ -38,21 +35,15 @@ Window::GetSize() const
|
||||||
return {Cast<u32>(width), Cast<u32>(height)};
|
return {Cast<u32>(width), Cast<u32>(height)};
|
||||||
}
|
}
|
||||||
|
|
||||||
Window::Window(const cstr title, Size2D extent, const b8 isFullScreen)
|
void
|
||||||
|
Window::Init(cstr title, vk::Extent2D extent, b8 isFullScreen)
|
||||||
{
|
{
|
||||||
m_Name = title;
|
if (!glfwInit())
|
||||||
|
|
||||||
if (!m_IsGlfwInit)
|
|
||||||
{
|
{
|
||||||
if (!glfwInit())
|
const char *error = nullptr;
|
||||||
{
|
const auto code = glfwGetError(&error);
|
||||||
const char *error = nullptr;
|
ERROR("GLFW Init failed. Cause: ({}) {}", code, error)
|
||||||
const auto code = glfwGetError(&error);
|
THEN_ABORT(code);
|
||||||
ERROR("GLFW Init failed. Cause: ({}) {}", code, error)
|
|
||||||
THEN_ABORT(code);
|
|
||||||
}
|
|
||||||
m_WindowCount = 0;
|
|
||||||
m_IsGlfwInit = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GLFWmonitor *monitor = glfwGetPrimaryMonitor();
|
GLFWmonitor *monitor = glfwGetPrimaryMonitor();
|
||||||
|
|
@ -64,10 +55,10 @@ Window::Window(const cstr title, Size2D extent, const b8 isFullScreen)
|
||||||
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.m_Width), Cast<i32>(extent.m_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.m_Width, extent.m_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;
|
||||||
|
|
@ -78,45 +69,25 @@ Window::Window(const cstr title, Size2D extent, const b8 isFullScreen)
|
||||||
|
|
||||||
if (isFullScreen == false)
|
if (isFullScreen == false)
|
||||||
{
|
{
|
||||||
glfwSetWindowPos(m_Window, Cast<i32>(windowWidth - extent.m_Width) / 2,
|
glfwSetWindowPos(m_Window, Cast<i32>(windowWidth - extent.width) / 2,
|
||||||
Cast<i32>(windowHeight - extent.m_Height) / 2);
|
Cast<i32>(windowHeight - extent.height) / 2);
|
||||||
}
|
}
|
||||||
glfwSetInputMode(m_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
glfwSetInputMode(m_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||||
|
|
||||||
++m_WindowCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Window::~Window()
|
void
|
||||||
|
Window::Destroy()
|
||||||
{
|
{
|
||||||
if (m_Window)
|
if (!m_Window)
|
||||||
{
|
return;
|
||||||
glfwDestroyWindow(m_Window);
|
|
||||||
m_Window = nullptr;
|
|
||||||
|
|
||||||
--m_WindowCount;
|
const char *title = glfwGetWindowTitle(m_Window);
|
||||||
}
|
|
||||||
|
|
||||||
if (m_WindowCount== 0 && m_IsGlfwInit)
|
DEBUG("Window {} Destroyed", title);
|
||||||
{
|
|
||||||
glfwTerminate();
|
|
||||||
m_IsGlfwInit = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG("Window '{}' Destroyed", m_Name);
|
glfwDestroyWindow(m_Window);
|
||||||
}
|
m_Window = nullptr;
|
||||||
|
|
||||||
Window::Window(Window &&other) noexcept
|
// Currently only one window is supported.
|
||||||
: m_Window(Take(other.m_Window))
|
glfwTerminate();
|
||||||
, m_Name(Take(other.m_Name))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Window &
|
|
||||||
Window::operator=(Window &&other) noexcept
|
|
||||||
{
|
|
||||||
if (this == &other)
|
|
||||||
return *this;
|
|
||||||
m_Window = Take(other.m_Window);
|
|
||||||
m_Name = Take(other.m_Name);
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
|
|
@ -7,19 +7,11 @@
|
||||||
|
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
|
||||||
#include "size.h"
|
struct Context;
|
||||||
|
|
||||||
#include <EASTL/fixed_string.h>
|
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
struct Window final
|
struct Window final
|
||||||
{
|
{
|
||||||
// fields
|
|
||||||
GLFWwindow *m_Window = nullptr;
|
GLFWwindow *m_Window = nullptr;
|
||||||
NameString m_Name;
|
|
||||||
|
|
||||||
static std::atomic_uint64_t m_WindowCount;
|
|
||||||
static std::atomic_bool m_IsGlfwInit;
|
|
||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
[[nodiscard]] bool
|
[[nodiscard]] bool
|
||||||
|
|
@ -33,15 +25,9 @@ struct Window final
|
||||||
void SetWindowSize(const vk::Extent2D &extent) const noexcept;
|
void SetWindowSize(const vk::Extent2D &extent) const noexcept;
|
||||||
void SetWindowSize(u32 width, u32 height) const noexcept;
|
void SetWindowSize(u32 width, u32 height) const noexcept;
|
||||||
/// Actual size of the framebuffer being used for the window render.
|
/// Actual size of the framebuffer being used for the window render.
|
||||||
[[nodiscard]] Size2D GetSize() const;
|
[[nodiscard]] vk::Extent2D GetSize() const;
|
||||||
|
|
||||||
// Ctor/Dtor
|
// Ctor/Dtor
|
||||||
Window(cstr title, Size2D 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);
|
|
||||||
};
|
};
|
||||||
9
build.sh
9
build.sh
|
|
@ -1,12 +1,7 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/bash
|
||||||
|
|
||||||
echo "Running CMake"
|
echo "Running CMake"
|
||||||
if grep 'NAME=NixOS' /etc/os-release
|
cmake --preset=default
|
||||||
then
|
|
||||||
cmake --preset nixos
|
|
||||||
else
|
|
||||||
cmake --preset linux
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Running Ninja"
|
echo "Running Ninja"
|
||||||
if echo "$@" | grep -e "clean" -q
|
if echo "$@" | grep -e "clean" -q
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
build/compile_commands.json
|
|
||||||
61
flake.lock
61
flake.lock
|
|
@ -1,61 +0,0 @@
|
||||||
{
|
|
||||||
"nodes": {
|
|
||||||
"flake-utils": {
|
|
||||||
"inputs": {
|
|
||||||
"systems": "systems"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1731533236,
|
|
||||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1738734093,
|
|
||||||
"narHash": "sha256-UEYOKfXXKU49fR7dGB05As0s2pGbLK4xDo48Qtdm7xs=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "5b2753b0356d1c951d7a3ef1d086ba5a71fff43c",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixpkgs-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": "flake-utils",
|
|
||||||
"nixpkgs": "nixpkgs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"systems": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1681028828,
|
|
||||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": "root",
|
|
||||||
"version": 7
|
|
||||||
}
|
|
||||||
57
flake.nix
57
flake.nix
|
|
@ -1,57 +0,0 @@
|
||||||
{
|
|
||||||
inputs = {
|
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
|
||||||
flake-utils.url = "github:numtide/flake-utils";
|
|
||||||
};
|
|
||||||
outputs = {self, nixpkgs, flake-utils }:
|
|
||||||
flake-utils.lib.eachDefaultSystem (system:
|
|
||||||
let
|
|
||||||
pkgs = import nixpkgs {
|
|
||||||
inherit system;
|
|
||||||
};
|
|
||||||
eabase = pkgs.callPackage ./vendored-nix/eabase {};
|
|
||||||
eastl = pkgs.callPackage ./vendored-nix/eastl { inherit eabase; };
|
|
||||||
tinygltf = pkgs.callPackage ./vendored-nix/tinygltf {};
|
|
||||||
debugbreak = pkgs.callPackage ./vendored-nix/scottt-debugbreak {};
|
|
||||||
in
|
|
||||||
with pkgs;
|
|
||||||
{
|
|
||||||
devShells.default = clangStdenv.mkDerivation {
|
|
||||||
name = "BlazeEnv";
|
|
||||||
|
|
||||||
|
|
||||||
nativeBuildInputs = [
|
|
||||||
cmake
|
|
||||||
ninja
|
|
||||||
ccls
|
|
||||||
clang-tools
|
|
||||||
lldb
|
|
||||||
(imgui.override {IMGUI_BUILD_VULKAN_BINDING = true; IMGUI_BUILD_GLFW_BINDING=true; })
|
|
||||||
];
|
|
||||||
|
|
||||||
buildInputs = [
|
|
||||||
sdl3
|
|
||||||
glm
|
|
||||||
glfw3
|
|
||||||
eastl
|
|
||||||
fmt
|
|
||||||
eabase
|
|
||||||
eastl
|
|
||||||
entt
|
|
||||||
tinygltf
|
|
||||||
debugbreak
|
|
||||||
stb
|
|
||||||
|
|
||||||
# vulkan
|
|
||||||
vulkan-headers
|
|
||||||
vulkan-loader
|
|
||||||
vulkan-validation-layers
|
|
||||||
vulkan-memory-allocator
|
|
||||||
directx-shader-compiler
|
|
||||||
glslang
|
|
||||||
shaderc
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
10
run.sh
10
run.sh
|
|
@ -1,14 +1,14 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
if [ -d "build" ]; then
|
if [ -d "out" ]; then
|
||||||
pushd ./build/samples/04_scenes/ > /dev/null || exit
|
pushd ./build/ > /dev/null || exit
|
||||||
if echo "$@" | grep -e "debug" -q
|
if echo "$@" | grep -e "debug" -q
|
||||||
then
|
then
|
||||||
lldb ./scene_render
|
lldb aster-exe
|
||||||
else
|
else
|
||||||
./scene_render
|
./aster-exe
|
||||||
fi
|
fi
|
||||||
popd > /dev/null || exit
|
popd > /dev/null || exit
|
||||||
else
|
else
|
||||||
echo "Build Aster first."
|
echo "Build blaze first."
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,12 @@ cmake_minimum_required(VERSION 3.13)
|
||||||
find_package(imgui CONFIG REQUIRED)
|
find_package(imgui CONFIG REQUIRED)
|
||||||
|
|
||||||
add_library(util_helper STATIC
|
add_library(util_helper STATIC
|
||||||
"helpers.h"
|
helpers.h
|
||||||
"helpers.cpp"
|
helpers.cpp
|
||||||
"frame.cpp"
|
frame.cpp
|
||||||
"frame.h"
|
frame.h
|
||||||
"gui.cpp"
|
gui.cpp
|
||||||
"gui.h")
|
gui.h)
|
||||||
|
|
||||||
target_link_libraries(util_helper PRIVATE aster_core)
|
target_link_libraries(util_helper PRIVATE aster_core)
|
||||||
target_link_libraries(util_helper PRIVATE imgui::imgui)
|
target_link_libraries(util_helper PRIVATE imgui::imgui)
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,9 @@
|
||||||
|
|
||||||
#include "frame.h"
|
#include "frame.h"
|
||||||
|
|
||||||
#include "aster/core/device.h"
|
#include "device.h"
|
||||||
#include "aster/core/swapchain.h"
|
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
#include "swapchain.h"
|
||||||
|
|
||||||
Frame::Frame(const Device *device, const u32 queueFamilyIndex, const u32 frameCount)
|
Frame::Frame(const Device *device, const u32 queueFamilyIndex, const u32 frameCount)
|
||||||
: m_FrameIdx(frameCount)
|
: m_FrameIdx(frameCount)
|
||||||
|
|
@ -53,7 +52,7 @@ Frame::Frame(const Device *device, const u32 queueFamilyIndex, const u32 frameCo
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Frame::Present(const vk::Queue commandQueue, Swapchain *swapchain, const Surface *surface, Size2D size)
|
Frame::Present(const vk::Queue commandQueue, Swapchain *swapchain, const Window *window)
|
||||||
{
|
{
|
||||||
|
|
||||||
vk::PresentInfoKHR presentInfo = {
|
vk::PresentInfoKHR presentInfo = {
|
||||||
|
|
@ -71,7 +70,7 @@ Frame::Present(const vk::Queue commandQueue, Swapchain *swapchain, const Surface
|
||||||
case vk::Result::eErrorOutOfDateKHR:
|
case vk::Result::eErrorOutOfDateKHR:
|
||||||
case vk::Result::eSuboptimalKHR:
|
case vk::Result::eSuboptimalKHR:
|
||||||
DEBUG("Recreating Swapchain. Cause: {}", result);
|
DEBUG("Recreating Swapchain. Cause: {}", result);
|
||||||
swapchain->Create(surface, size);
|
swapchain->Create(window);
|
||||||
break; // Present failed. We do nothing. Frame is skipped.
|
break; // Present failed. We do nothing. Frame is skipped.
|
||||||
default:
|
default:
|
||||||
AbortIfFailedM(result, "Swapchain Present failed.");
|
AbortIfFailedM(result, "Swapchain Present failed.");
|
||||||
|
|
@ -129,7 +128,7 @@ FrameManager::FrameManager(const Device *device, u32 queueFamilyIndex, u32 frame
|
||||||
}
|
}
|
||||||
|
|
||||||
Frame *
|
Frame *
|
||||||
FrameManager::GetNextFrame(Swapchain *swapchain, const Surface *surface, Size2D size)
|
FrameManager::GetNextFrame(Swapchain *swapchain, const Window *window)
|
||||||
{
|
{
|
||||||
|
|
||||||
Frame *currentFrame = &m_Frames[m_CurrentFrameIdx];
|
Frame *currentFrame = &m_Frames[m_CurrentFrameIdx];
|
||||||
|
|
@ -154,7 +153,7 @@ FrameManager::GetNextFrame(Swapchain *swapchain, const Surface *surface, Size2D
|
||||||
break; // Image acquired. Break out of loop.
|
break; // Image acquired. Break out of loop.
|
||||||
case vk::Result::eErrorOutOfDateKHR:
|
case vk::Result::eErrorOutOfDateKHR:
|
||||||
DEBUG("Recreating Swapchain. Cause: {}", result);
|
DEBUG("Recreating Swapchain. Cause: {}", result);
|
||||||
swapchain->Create(surface, size);
|
swapchain->Create(window);
|
||||||
break; // Image acquire has failed. We move to the next frame.
|
break; // Image acquire has failed. We move to the next frame.
|
||||||
default:
|
default:
|
||||||
AbortIfFailedMV(result, "Waiting for swapchain image {} failed.", frameIndex);
|
AbortIfFailedMV(result, "Waiting for swapchain image {} failed.", frameIndex);
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,14 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "aster/aster.h"
|
#include "global.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
#include "aster/core/size.h"
|
|
||||||
|
|
||||||
#include <EASTL/fixed_vector.h>
|
#include <EASTL/fixed_vector.h>
|
||||||
|
|
||||||
struct Device;
|
struct Device;
|
||||||
struct Window;
|
struct Window;
|
||||||
struct Swapchain;
|
struct Swapchain;
|
||||||
struct Surface;
|
|
||||||
|
|
||||||
struct Frame
|
struct Frame
|
||||||
{
|
{
|
||||||
|
|
@ -31,7 +28,7 @@ struct Frame
|
||||||
// Transient
|
// Transient
|
||||||
u32 m_ImageIdx;
|
u32 m_ImageIdx;
|
||||||
|
|
||||||
void Present(const vk::Queue commandQueue, Swapchain* swapchain, const Surface* surface, Size2D size);
|
void Present(vk::Queue commandQueue, Swapchain *swapchain, const Window *window);
|
||||||
|
|
||||||
Frame(const Device *device, u32 queueFamilyIndex, u32 frameCount);
|
Frame(const Device *device, u32 queueFamilyIndex, u32 frameCount);
|
||||||
~Frame();
|
~Frame();
|
||||||
|
|
@ -51,5 +48,5 @@ struct FrameManager
|
||||||
|
|
||||||
FrameManager(const Device *device, u32 queueFamilyIndex, u32 framesInFlight);
|
FrameManager(const Device *device, u32 queueFamilyIndex, u32 framesInFlight);
|
||||||
|
|
||||||
Frame *GetNextFrame(Swapchain *swapchain, const Surface *surface, Size2D size);
|
Frame *GetNextFrame(Swapchain *swapchain, const Window *window);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@
|
||||||
|
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
|
|
||||||
#include "aster/core/context.h"
|
#include "context.h"
|
||||||
#include "aster/core/device.h"
|
#include "device.h"
|
||||||
#include "aster/core/window.h"
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
#include "window.h"
|
||||||
|
|
||||||
#include <imgui_impl_glfw.h>
|
#include <imgui_impl_glfw.h>
|
||||||
#include <imgui_impl_vulkan.h>
|
#include <imgui_impl_vulkan.h>
|
||||||
|
|
@ -58,7 +58,7 @@ Init(const Context *context, const Device *device, const Window *window, vk::For
|
||||||
CreateContext();
|
CreateContext();
|
||||||
ImGuiIO &io = GetIO();
|
ImGuiIO &io = GetIO();
|
||||||
(void)io;
|
(void)io;
|
||||||
// io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
||||||
// io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Viewports bad
|
// io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Viewports bad
|
||||||
|
|
||||||
StyleColorsDark();
|
StyleColorsDark();
|
||||||
|
|
@ -108,16 +108,16 @@ StartBuild()
|
||||||
ImGui_ImplGlfw_NewFrame();
|
ImGui_ImplGlfw_NewFrame();
|
||||||
NewFrame();
|
NewFrame();
|
||||||
|
|
||||||
static ImGuiDockNodeFlags dockspaceFlags = ImGuiDockNodeFlags_None | ImGuiDockNodeFlags_PassthruCentralNode;
|
static ImGuiDockNodeFlags dockspaceFlags = ImGuiDockNodeFlags_None | ImGuiDockNodeFlags_PassthruCentralNode;
|
||||||
|
|
||||||
// We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into,
|
// We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into,
|
||||||
// because it would be confusing to have two docking targets within each others.
|
// because it would be confusing to have two docking targets within each others.
|
||||||
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_None | ImGuiWindowFlags_NoDocking;
|
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoDocking;
|
||||||
|
|
||||||
const ImGuiViewport *viewport = GetMainViewport();
|
const ImGuiViewport *viewport = GetMainViewport();
|
||||||
SetNextWindowPos(viewport->WorkPos);
|
SetNextWindowPos(viewport->WorkPos);
|
||||||
SetNextWindowSize(viewport->WorkSize);
|
SetNextWindowSize(viewport->WorkSize);
|
||||||
// SetNextWindowViewport(viewport->ID);
|
SetNextWindowViewport(viewport->ID);
|
||||||
PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||||
PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
||||||
windowFlags |=
|
windowFlags |=
|
||||||
|
|
@ -130,18 +130,18 @@ StartBuild()
|
||||||
// all active windows docked into it will lose their parent and become undocked.
|
// all active windows docked into it will lose their parent and become undocked.
|
||||||
// We cannot preserve the docking relationship between an active window and an inactive docking, otherwise
|
// We cannot preserve the docking relationship between an active window and an inactive docking, otherwise
|
||||||
// any change of dockspace/settings would lead to windows being stuck in limbo and never being visible.
|
// any change of dockspace/settings would lead to windows being stuck in limbo and never being visible.
|
||||||
PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
|
PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
|
||||||
Begin("DockSpace Demo", nullptr, windowFlags);
|
Begin("DockSpace Demo", nullptr, windowFlags);
|
||||||
PopStyleVar();
|
PopStyleVar();
|
||||||
|
|
||||||
PopStyleVar(2);
|
PopStyleVar(2);
|
||||||
|
|
||||||
// DockSpace
|
// DockSpace
|
||||||
if (GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable)
|
if (GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable)
|
||||||
{
|
{
|
||||||
const ImGuiID dockspaceId = GetID("MyDockSpace");
|
const ImGuiID dockspaceId = GetID("MyDockSpace");
|
||||||
DockSpace(dockspaceId, ImVec2(0.0f, 0.0f), dockspaceFlags);
|
DockSpace(dockspaceId, ImVec2(0.0f, 0.0f), dockspaceFlags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -151,13 +151,13 @@ EndBuild()
|
||||||
Render();
|
Render();
|
||||||
|
|
||||||
EndFrame();
|
EndFrame();
|
||||||
// if (GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
if (GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||||
// {
|
{
|
||||||
// GLFWwindow *backupCurrentContext = glfwGetCurrentContext();
|
GLFWwindow *backupCurrentContext = glfwGetCurrentContext();
|
||||||
// UpdatePlatformWindows();
|
UpdatePlatformWindows();
|
||||||
// RenderPlatformWindowsDefault();
|
RenderPlatformWindowsDefault();
|
||||||
// glfwMakeContextCurrent(backupCurrentContext);
|
glfwMakeContextCurrent(backupCurrentContext);
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "aster/aster.h"
|
#include "global.h"
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
#include "aster/core/device.h"
|
#include "device.h"
|
||||||
#include "aster/core/physical_device.h"
|
#include "physical_device.h"
|
||||||
|
|
||||||
#include <EASTL/array.h>
|
#include <EASTL/array.h>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "aster/aster.h"
|
#include "global.h"
|
||||||
|
|
||||||
#include "aster/core/queue_allocation.h"
|
#include "queue_allocation.h"
|
||||||
|
|
||||||
#include "EASTL/span.h"
|
#include "EASTL/span.h"
|
||||||
#include <EASTL/vector.h>
|
#include <EASTL/vector.h>
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
add_executable(triangle "triangle.cpp")
|
add_executable(triangle triangle.cpp)
|
||||||
add_shader(triangle "shader/triangle.vert.glsl")
|
add_shader(triangle shader/triangle.vert.glsl)
|
||||||
add_shader(triangle "shader/triangle.frag.glsl")
|
add_shader(triangle shader/triangle.frag.glsl)
|
||||||
|
|
||||||
target_link_libraries(triangle PRIVATE aster_core)
|
target_link_libraries(triangle PRIVATE aster_core)
|
||||||
target_link_libraries(triangle PRIVATE util_helper)
|
target_link_libraries(triangle PRIVATE util_helper)
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,16 @@
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
// =============================================
|
// =============================================
|
||||||
|
|
||||||
#include "aster/aster.h"
|
#include "buffer.h"
|
||||||
|
#include "constants.h"
|
||||||
|
#include "context.h"
|
||||||
|
#include "device.h"
|
||||||
|
#include "physical_device.h"
|
||||||
|
#include "window.h"
|
||||||
|
|
||||||
#include "aster/core/buffer.h"
|
#include "global.h"
|
||||||
#include "aster/core/constants.h"
|
#include "pipeline.h"
|
||||||
#include "aster/core/context.h"
|
#include "swapchain.h"
|
||||||
#include "aster/core/device.h"
|
|
||||||
#include "aster/core/physical_device.h"
|
|
||||||
#include "aster/core/pipeline.h"
|
|
||||||
#include "aster/core/swapchain.h"
|
|
||||||
#include "aster/core/window.h"
|
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
|
|
@ -74,23 +74,19 @@ main(int, char **)
|
||||||
{
|
{
|
||||||
MIN_LOG_LEVEL(Logger::LogType::eInfo);
|
MIN_LOG_LEVEL(Logger::LogType::eInfo);
|
||||||
|
|
||||||
Window window = {"Triangle (Aster)", {640, 480}};
|
|
||||||
Context context = {"Triangle", VERSION};
|
Context context = {"Triangle", VERSION};
|
||||||
Surface surface = {&context, &window, "Primary"};
|
Window window = {"Triangle (Aster)", &context, {640, 480}};
|
||||||
|
|
||||||
PhysicalDevices physicalDevices = {&surface, &context};
|
PhysicalDevices physicalDevices = {&window, &context};
|
||||||
PhysicalDevice deviceToUse = FindSuitableDevice(physicalDevices);
|
PhysicalDevice deviceToUse = FindSuitableDevice(physicalDevices);
|
||||||
|
|
||||||
INFO("Using {} as the primary device.", deviceToUse.m_DeviceProperties.deviceName.data());
|
INFO("Using {} as the primary device.", deviceToUse.m_DeviceProperties.deviceName.data());
|
||||||
|
|
||||||
Features enabledDeviceFeatures = {
|
Features enabledDeviceFeatures = {.m_Vulkan13Features = {.dynamicRendering = true}};
|
||||||
.m_Vulkan12Features = {.bufferDeviceAddress = true},
|
|
||||||
.m_Vulkan13Features = {.synchronization2 = true, .dynamicRendering = true},
|
|
||||||
};
|
|
||||||
QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse);
|
QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse);
|
||||||
Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"};
|
Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"};
|
||||||
vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
||||||
Swapchain swapchain = {&surface, &device, window.GetSize(), "Primary Chain"};
|
Swapchain swapchain = {&window, &device, "Primary Chain"};
|
||||||
Pipeline pipeline = CreatePipeline(&device, &swapchain);
|
Pipeline pipeline = CreatePipeline(&device, &swapchain);
|
||||||
|
|
||||||
vk::CommandPool copyPool;
|
vk::CommandPool copyPool;
|
||||||
|
|
@ -179,40 +175,24 @@ main(int, char **)
|
||||||
.baseArrayLayer = 0,
|
.baseArrayLayer = 0,
|
||||||
.layerCount = 1,
|
.layerCount = 1,
|
||||||
};
|
};
|
||||||
vk::ImageMemoryBarrier2 topOfThePipeBarrier = {
|
vk::ImageMemoryBarrier topOfThePipeBarrier = {
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
|
||||||
.srcAccessMask = vk::AccessFlagBits2::eNone,
|
|
||||||
.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
|
||||||
.dstAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
|
|
||||||
.oldLayout = vk::ImageLayout::eUndefined,
|
.oldLayout = vk::ImageLayout::eUndefined,
|
||||||
.newLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
.newLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
||||||
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.subresourceRange = subresourceRange,
|
.subresourceRange = subresourceRange,
|
||||||
};
|
};
|
||||||
vk::DependencyInfo topOfThePipeDependency = {
|
vk::ImageMemoryBarrier renderToPresentBarrier = {
|
||||||
.imageMemoryBarrierCount = 1,
|
|
||||||
.pImageMemoryBarriers = &topOfThePipeBarrier,
|
|
||||||
};
|
|
||||||
vk::ImageMemoryBarrier2 renderToPresentBarrier = {
|
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
|
||||||
.srcAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
|
|
||||||
.dstStageMask = vk::PipelineStageFlagBits2::eBottomOfPipe,
|
|
||||||
.dstAccessMask = vk::AccessFlagBits2::eNone,
|
|
||||||
.oldLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
.oldLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
||||||
.newLayout = vk::ImageLayout::ePresentSrcKHR,
|
.newLayout = vk::ImageLayout::ePresentSrcKHR,
|
||||||
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.subresourceRange = subresourceRange,
|
.subresourceRange = subresourceRange,
|
||||||
};
|
};
|
||||||
vk::DependencyInfo renderToPresentDependency = {
|
|
||||||
.imageMemoryBarrierCount = 1,
|
|
||||||
.pImageMemoryBarriers = &renderToPresentBarrier,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Frames
|
// Frames
|
||||||
eastl::fixed_vector<Frame, MAX_FRAMES_IN_FLIGHT> frames;
|
eastl::fixed_vector<Frame, MAX_FRAMES_IN_FLIGHT> frames;
|
||||||
for (u32 i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
|
for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
|
||||||
{
|
{
|
||||||
frames.emplace_back(&device, queueAllocation.m_Family, i);
|
frames.emplace_back(&device, queueAllocation.m_Family, i);
|
||||||
}
|
}
|
||||||
|
|
@ -237,7 +217,7 @@ main(int, char **)
|
||||||
case vk::Result::eErrorOutOfDateKHR:
|
case vk::Result::eErrorOutOfDateKHR:
|
||||||
case vk::Result::eSuboptimalKHR:
|
case vk::Result::eSuboptimalKHR:
|
||||||
INFO("Recreating Swapchain. Cause: {}", result);
|
INFO("Recreating Swapchain. Cause: {}", result);
|
||||||
swapchain.Create(&surface, window.GetSize());
|
swapchain.Create(&window);
|
||||||
viewport.y = Cast<f32>(swapchain.m_Extent.height);
|
viewport.y = Cast<f32>(swapchain.m_Extent.height);
|
||||||
viewport.width = Cast<f32>(swapchain.m_Extent.width);
|
viewport.width = Cast<f32>(swapchain.m_Extent.width);
|
||||||
viewport.height = -Cast<f32>(swapchain.m_Extent.height);
|
viewport.height = -Cast<f32>(swapchain.m_Extent.height);
|
||||||
|
|
@ -269,7 +249,8 @@ main(int, char **)
|
||||||
ERROR_IF(Failed(result), "Command buffer begin failed. Cause: {}", result)
|
ERROR_IF(Failed(result), "Command buffer begin failed. Cause: {}", result)
|
||||||
THEN_ABORT(result);
|
THEN_ABORT(result);
|
||||||
|
|
||||||
cmd.pipelineBarrier2(&topOfThePipeDependency);
|
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eColorAttachmentOutput,
|
||||||
|
{}, 0, nullptr, 0, nullptr, 1, &topOfThePipeBarrier);
|
||||||
|
|
||||||
// Render
|
// Render
|
||||||
vk::RenderingAttachmentInfo attachmentInfo = {
|
vk::RenderingAttachmentInfo attachmentInfo = {
|
||||||
|
|
@ -278,7 +259,7 @@ main(int, char **)
|
||||||
.resolveMode = vk::ResolveModeFlagBits::eNone,
|
.resolveMode = vk::ResolveModeFlagBits::eNone,
|
||||||
.loadOp = vk::AttachmentLoadOp::eClear,
|
.loadOp = vk::AttachmentLoadOp::eClear,
|
||||||
.storeOp = vk::AttachmentStoreOp::eStore,
|
.storeOp = vk::AttachmentStoreOp::eStore,
|
||||||
.clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 0.0f},
|
.clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 1.0f},
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::RenderingInfo renderingInfo = {
|
vk::RenderingInfo renderingInfo = {
|
||||||
|
|
@ -299,7 +280,8 @@ main(int, char **)
|
||||||
|
|
||||||
cmd.endRendering();
|
cmd.endRendering();
|
||||||
|
|
||||||
cmd.pipelineBarrier2(&renderToPresentDependency);
|
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eBottomOfPipe,
|
||||||
|
{}, 0, nullptr, 0, nullptr, 1, &renderToPresentBarrier);
|
||||||
|
|
||||||
result = cmd.end();
|
result = cmd.end();
|
||||||
ERROR_IF(Failed(result), "Command buffer end failed. Cause: {}", result)
|
ERROR_IF(Failed(result), "Command buffer end failed. Cause: {}", result)
|
||||||
|
|
@ -335,7 +317,7 @@ main(int, char **)
|
||||||
case vk::Result::eErrorOutOfDateKHR:
|
case vk::Result::eErrorOutOfDateKHR:
|
||||||
case vk::Result::eSuboptimalKHR:
|
case vk::Result::eSuboptimalKHR:
|
||||||
INFO("Recreating Swapchain. Cause: {}", result);
|
INFO("Recreating Swapchain. Cause: {}", result);
|
||||||
swapchain.Create(&surface, window.GetSize());
|
swapchain.Create(&window);
|
||||||
viewport.y = Cast<f32>(swapchain.m_Extent.height);
|
viewport.y = Cast<f32>(swapchain.m_Extent.height);
|
||||||
viewport.width = Cast<f32>(swapchain.m_Extent.width);
|
viewport.width = Cast<f32>(swapchain.m_Extent.width);
|
||||||
viewport.height = -Cast<f32>(swapchain.m_Extent.height);
|
viewport.height = -Cast<f32>(swapchain.m_Extent.height);
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,9 @@ cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fsanitize=address")
|
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fsanitize=address")
|
||||||
|
|
||||||
add_executable(box "box.cpp" "stb_image.h")
|
add_executable(box box.cpp stb_image.h)
|
||||||
add_shader(box "shader/box.vert.glsl")
|
add_shader(box shader/box.vert.glsl)
|
||||||
add_shader(box "shader/box.frag.glsl")
|
add_shader(box shader/box.frag.glsl)
|
||||||
add_shader(box "shader/box.vs.hlsl")
|
|
||||||
add_shader(box "shader/box.ps.hlsl")
|
|
||||||
|
|
||||||
target_link_libraries(box PRIVATE aster_core)
|
target_link_libraries(box PRIVATE aster_core)
|
||||||
target_link_libraries(box PRIVATE util_helper)
|
target_link_libraries(box PRIVATE util_helper)
|
||||||
|
|
|
||||||
|
|
@ -3,31 +3,28 @@
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
// =============================================
|
// =============================================
|
||||||
|
|
||||||
#include "aster/aster.h"
|
#include "buffer.h"
|
||||||
|
#include "constants.h"
|
||||||
#include "aster/core/buffer.h"
|
#include "context.h"
|
||||||
#include "aster/core/constants.h"
|
#include "device.h"
|
||||||
#include "aster/core/context.h"
|
#include "global.h"
|
||||||
#include "aster/core/device.h"
|
#include "physical_device.h"
|
||||||
#include "aster/core/image.h"
|
#include "pipeline.h"
|
||||||
#include "aster/core/physical_device.h"
|
#include "swapchain.h"
|
||||||
#include "aster/core/pipeline.h"
|
#include "window.h"
|
||||||
#include "aster/core/swapchain.h"
|
|
||||||
#include "aster/core/window.h"
|
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include "aster/systems/buffer_manager.h"
|
|
||||||
#include "aster/systems/image_manager.h"
|
|
||||||
#include "frame.h"
|
#include "frame.h"
|
||||||
|
#include "image.h"
|
||||||
#include "stb_image.h"
|
#include "stb_image.h"
|
||||||
|
|
||||||
#include <EASTL/array.h>
|
#include <EASTL/array.h>
|
||||||
|
|
||||||
constexpr u32 MAX_FRAMES_IN_FLIGHT = 3;
|
constexpr u32 MAX_FRAMES_IN_FLIGHT = 3;
|
||||||
constexpr auto VERTEX_SHADER_FILE = "shader/box.vs.hlsl.spv";
|
constexpr auto VERTEX_SHADER_FILE = "shader/box.vert.glsl.spv";
|
||||||
constexpr auto FRAGMENT_SHADER_FILE = "shader/box.ps.hlsl.spv";
|
constexpr auto FRAGMENT_SHADER_FILE = "shader/box.frag.glsl.spv";
|
||||||
|
|
||||||
struct ImageFile
|
struct ImageFile
|
||||||
{
|
{
|
||||||
|
|
@ -78,9 +75,32 @@ Pipeline CreatePipeline(const Device *device, const Swapchain *swapchain);
|
||||||
struct Vertex
|
struct Vertex
|
||||||
{
|
{
|
||||||
vec3 m_Position;
|
vec3 m_Position;
|
||||||
f32 m_PositionW = 1.0;
|
|
||||||
vec2 m_TexCoord0;
|
vec2 m_TexCoord0;
|
||||||
vec2 m_Padding0_ = {0.0f, 0.0f};
|
|
||||||
|
constexpr static vk::VertexInputBindingDescription
|
||||||
|
GetBinding(const u32 binding)
|
||||||
|
{
|
||||||
|
return {.binding = binding, .stride = sizeof(Vertex), .inputRate = vk::VertexInputRate::eVertex};
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr static eastl::array<vk::VertexInputAttributeDescription, 2>
|
||||||
|
GetAttributes(const u32 binding)
|
||||||
|
{
|
||||||
|
return {
|
||||||
|
vk::VertexInputAttributeDescription{
|
||||||
|
.location = 0,
|
||||||
|
.binding = binding,
|
||||||
|
.format = vk::Format::eR32G32B32Sfloat,
|
||||||
|
.offset = offsetof(Vertex, m_Position),
|
||||||
|
},
|
||||||
|
vk::VertexInputAttributeDescription{
|
||||||
|
.location = 1,
|
||||||
|
.binding = binding,
|
||||||
|
.format = vk::Format::eR32G32Sfloat,
|
||||||
|
.offset = offsetof(Vertex, m_TexCoord0),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Camera
|
struct Camera
|
||||||
|
|
@ -95,29 +115,24 @@ main(int, char **)
|
||||||
{
|
{
|
||||||
MIN_LOG_LEVEL(Logger::LogType::eInfo);
|
MIN_LOG_LEVEL(Logger::LogType::eInfo);
|
||||||
|
|
||||||
Window window = {"Box (Aster)", {640, 480}};
|
|
||||||
Context context = {"Box", VERSION};
|
Context context = {"Box", VERSION};
|
||||||
Surface surface = {&context, &window, "Primary"};
|
Window window = {"Box (Aster)", &context, {640, 480}};
|
||||||
|
|
||||||
PhysicalDevices physicalDevices = {&surface, &context};
|
PhysicalDevices physicalDevices = {&window, &context};
|
||||||
PhysicalDevice deviceToUse = FindSuitableDevice(physicalDevices);
|
PhysicalDevice deviceToUse = FindSuitableDevice(physicalDevices);
|
||||||
|
|
||||||
INFO("Using {} as the primary device.", deviceToUse.m_DeviceProperties.deviceName.data());
|
INFO("Using {} as the primary device.", deviceToUse.m_DeviceProperties.deviceName.data());
|
||||||
|
|
||||||
Features enabledDeviceFeatures = {
|
Features enabledDeviceFeatures = {
|
||||||
.m_Vulkan10Features = {.samplerAnisotropy = true},
|
.m_Vulkan10Features = {.samplerAnisotropy = true},
|
||||||
.m_Vulkan12Features = {.bufferDeviceAddress = true},
|
.m_Vulkan13Features = {.dynamicRendering = true},
|
||||||
.m_Vulkan13Features = {.synchronization2 = true, .dynamicRendering = true},
|
|
||||||
};
|
};
|
||||||
QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse);
|
QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse);
|
||||||
Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"};
|
Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"};
|
||||||
vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
||||||
Swapchain swapchain = {&surface, &device, window.GetSize(), "Primary Chain"};
|
Swapchain swapchain = {&window, &device, "Primary Chain"};
|
||||||
Pipeline pipeline = CreatePipeline(&device, &swapchain);
|
Pipeline pipeline = CreatePipeline(&device, &swapchain);
|
||||||
|
|
||||||
systems::BufferManager bufferManager{&device, 12, 0};
|
|
||||||
systems::ImageManager imageManager{&device, 12, 1};
|
|
||||||
|
|
||||||
Camera camera = {
|
Camera camera = {
|
||||||
.m_Model = {1.0f},
|
.m_Model = {1.0f},
|
||||||
.m_View = glm::lookAt(vec3(0.0f, 2.0f, 2.0f), vec3(0.0f), vec3(0.0f, 1.0f, 0.0f)),
|
.m_View = glm::lookAt(vec3(0.0f, 2.0f, 2.0f), vec3(0.0f), vec3(0.0f, 1.0f, 0.0f)),
|
||||||
|
|
@ -138,10 +153,6 @@ main(int, char **)
|
||||||
.type = vk::DescriptorType::eCombinedImageSampler,
|
.type = vk::DescriptorType::eCombinedImageSampler,
|
||||||
.descriptorCount = 1,
|
.descriptorCount = 1,
|
||||||
},
|
},
|
||||||
vk::DescriptorPoolSize{
|
|
||||||
.type = vk::DescriptorType::eStorageBuffer,
|
|
||||||
.descriptorCount = 1,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo = {
|
vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo = {
|
||||||
.maxSets = 1, .poolSizeCount = Cast<u32>(poolSizes.size()), .pPoolSizes = poolSizes.data()};
|
.maxSets = 1, .poolSizeCount = Cast<u32>(poolSizes.size()), .pPoolSizes = poolSizes.data()};
|
||||||
|
|
@ -222,32 +233,24 @@ main(int, char **)
|
||||||
assert(loaded);
|
assert(loaded);
|
||||||
INFO("Image {}x{} : {} channels", imageFile.m_Width, imageFile.m_Height, imageFile.m_NumChannels);
|
INFO("Image {}x{} : {} channels", imageFile.m_Width, imageFile.m_Height, imageFile.m_NumChannels);
|
||||||
|
|
||||||
auto vbo = bufferManager.CreateStorageBuffer(vertices.size() * sizeof vertices[0], "Vertex Buffer").ToPointer();
|
VertexBuffer vbo;
|
||||||
auto crate = imageManager
|
Texture crate;
|
||||||
.CreateTexture2D({
|
vbo.Init(&device, vertices.size() * sizeof vertices[0], "VBO");
|
||||||
.m_Format = vk::Format::eR8G8B8A8Srgb,
|
crate.Init(&device, {imageFile.m_Width, imageFile.m_Height}, vk::Format::eR8G8B8A8Srgb, false, "Crate Texture");
|
||||||
.m_Extent = {imageFile.m_Width, imageFile.m_Height},
|
|
||||||
.m_Name = "Crate Texture",
|
|
||||||
})
|
|
||||||
.ToPointer();
|
|
||||||
vbo->Write(&device, 0, vertices.size() * sizeof vertices[0], vertices.data());
|
|
||||||
|
|
||||||
{
|
{
|
||||||
StagingBuffer imageStaging;
|
StagingBuffer vertexStaging, imageStaging;
|
||||||
|
vertexStaging.Init(&device, vertices.size() * sizeof vertices[0], "Vertex Staging");
|
||||||
|
vertexStaging.Write(&device, 0, vertices.size() * sizeof vertices[0], vertices.data());
|
||||||
|
|
||||||
imageStaging.Init(&device, imageFile.GetSize(), "Image Staging");
|
imageStaging.Init(&device, imageFile.GetSize(), "Image Staging");
|
||||||
imageStaging.Write(&device, 0, imageFile.GetSize(), imageFile.m_Data);
|
imageStaging.Write(&device, 0, imageFile.GetSize(), imageFile.m_Data);
|
||||||
|
|
||||||
vk::ImageMemoryBarrier2 imageReadyToWrite = {
|
vk::ImageMemoryBarrier imageReadyToWrite = {
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
|
||||||
.srcAccessMask = vk::AccessFlagBits2::eNone,
|
|
||||||
.dstStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
|
||||||
.dstAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
|
||||||
.oldLayout = vk::ImageLayout::eUndefined,
|
.oldLayout = vk::ImageLayout::eUndefined,
|
||||||
.newLayout = vk::ImageLayout::eTransferDstOptimal,
|
.newLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||||
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.image = crate->m_Image,
|
.image = crate.m_Image,
|
||||||
.subresourceRange =
|
.subresourceRange =
|
||||||
{
|
{
|
||||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
|
@ -257,21 +260,13 @@ main(int, char **)
|
||||||
.layerCount = 1,
|
.layerCount = 1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
vk::DependencyInfo imageReadyToWriteDependency = {
|
|
||||||
.imageMemoryBarrierCount = 1,
|
|
||||||
.pImageMemoryBarriers = &imageReadyToWrite,
|
|
||||||
};
|
|
||||||
|
|
||||||
vk::ImageMemoryBarrier2 imageReadyToRead = {
|
vk::ImageMemoryBarrier imageReadyToRead = {
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
|
||||||
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
|
||||||
.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader,
|
|
||||||
.dstAccessMask = vk::AccessFlagBits2::eShaderRead,
|
|
||||||
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||||
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||||
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.image = crate->m_Image,
|
.image = crate.m_Image,
|
||||||
.subresourceRange =
|
.subresourceRange =
|
||||||
{
|
{
|
||||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
|
@ -281,10 +276,6 @@ main(int, char **)
|
||||||
.layerCount = 1,
|
.layerCount = 1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
vk::DependencyInfo imageReadyToReadDependency = {
|
|
||||||
.imageMemoryBarrierCount = 1,
|
|
||||||
.pImageMemoryBarriers = &imageReadyToRead,
|
|
||||||
};
|
|
||||||
|
|
||||||
vk::Fence fence;
|
vk::Fence fence;
|
||||||
vk::FenceCreateInfo fenceCreateInfo = {};
|
vk::FenceCreateInfo fenceCreateInfo = {};
|
||||||
|
|
@ -292,8 +283,11 @@ main(int, char **)
|
||||||
|
|
||||||
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
||||||
AbortIfFailed(copyBuffer.begin(&beginInfo));
|
AbortIfFailed(copyBuffer.begin(&beginInfo));
|
||||||
|
copyBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eHost, vk::PipelineStageFlagBits::eTransfer, {}, 0,
|
||||||
|
nullptr, 0, nullptr, 1, &imageReadyToWrite);
|
||||||
|
|
||||||
copyBuffer.pipelineBarrier2(&imageReadyToWriteDependency);
|
vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = vertexStaging.GetSize()};
|
||||||
|
copyBuffer.copyBuffer(vertexStaging.m_Buffer, vbo.m_Buffer, 1, &bufferCopy);
|
||||||
|
|
||||||
vk::BufferImageCopy imageCopy = {
|
vk::BufferImageCopy imageCopy = {
|
||||||
.bufferOffset = 0,
|
.bufferOffset = 0,
|
||||||
|
|
@ -309,10 +303,11 @@ main(int, char **)
|
||||||
.imageOffset = {},
|
.imageOffset = {},
|
||||||
.imageExtent = {imageFile.m_Width, imageFile.m_Height, 1},
|
.imageExtent = {imageFile.m_Width, imageFile.m_Height, 1},
|
||||||
};
|
};
|
||||||
copyBuffer.copyBufferToImage(imageStaging.m_Buffer, crate->m_Image, vk::ImageLayout::eTransferDstOptimal, 1,
|
copyBuffer.copyBufferToImage(imageStaging.m_Buffer, crate.m_Image, vk::ImageLayout::eTransferDstOptimal, 1,
|
||||||
&imageCopy);
|
&imageCopy);
|
||||||
|
|
||||||
copyBuffer.pipelineBarrier2(&imageReadyToReadDependency);
|
copyBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {},
|
||||||
|
0, nullptr, 0, nullptr, 1, &imageReadyToRead);
|
||||||
|
|
||||||
AbortIfFailed(copyBuffer.end());
|
AbortIfFailed(copyBuffer.end());
|
||||||
|
|
||||||
|
|
@ -330,6 +325,7 @@ main(int, char **)
|
||||||
AbortIfFailedM(device.m_Device.resetCommandPool(copyPool, {}), "Couldn't reset command pool.");
|
AbortIfFailedM(device.m_Device.resetCommandPool(copyPool, {}), "Couldn't reset command pool.");
|
||||||
|
|
||||||
device.m_Device.destroy(fence, nullptr);
|
device.m_Device.destroy(fence, nullptr);
|
||||||
|
vertexStaging.Destroy(&device);
|
||||||
imageStaging.Destroy(&device);
|
imageStaging.Destroy(&device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -353,23 +349,19 @@ main(int, char **)
|
||||||
AbortIfFailed(device.m_Device.createSampler(&samplerCreateInfo, nullptr, &sampler));
|
AbortIfFailed(device.m_Device.createSampler(&samplerCreateInfo, nullptr, &sampler));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ubo = bufferManager.CreateUniformBuffer(sizeof camera, "Camera UBO").ToPointer();
|
UniformBuffer ubo;
|
||||||
ubo->Write(&device, 0, sizeof camera, &camera);
|
ubo.Init(&device, sizeof camera, "Camera UBO");
|
||||||
|
ubo.Write(&device, 0, sizeof camera, &camera);
|
||||||
vk::DescriptorBufferInfo descriptorBufferInfo = {
|
vk::DescriptorBufferInfo descriptorBufferInfo = {
|
||||||
.buffer = ubo->m_Buffer,
|
.buffer = ubo.m_Buffer,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
.range = ubo->GetSize(),
|
.range = ubo.GetSize(),
|
||||||
};
|
};
|
||||||
vk::DescriptorImageInfo descriptorImageInfo = {
|
vk::DescriptorImageInfo descriptorImageInfo = {
|
||||||
.sampler = sampler,
|
.sampler = sampler,
|
||||||
.imageView = crate->m_View,
|
.imageView = crate.m_View,
|
||||||
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||||
};
|
};
|
||||||
vk::DescriptorBufferInfo descriptorStorageBufferInfo = {
|
|
||||||
.buffer = vbo->m_Buffer,
|
|
||||||
.offset = 0,
|
|
||||||
.range = vbo->GetSize(),
|
|
||||||
};
|
|
||||||
eastl::array writeDescriptors = {
|
eastl::array writeDescriptors = {
|
||||||
vk::WriteDescriptorSet{
|
vk::WriteDescriptorSet{
|
||||||
.dstSet = descriptorSet,
|
.dstSet = descriptorSet,
|
||||||
|
|
@ -387,14 +379,6 @@ main(int, char **)
|
||||||
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||||
.pImageInfo = &descriptorImageInfo,
|
.pImageInfo = &descriptorImageInfo,
|
||||||
},
|
},
|
||||||
vk::WriteDescriptorSet{
|
|
||||||
.dstSet = descriptorSet,
|
|
||||||
.dstBinding = 2,
|
|
||||||
.dstArrayElement = 0,
|
|
||||||
.descriptorCount = 1,
|
|
||||||
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
|
||||||
.pBufferInfo = &descriptorStorageBufferInfo,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
device.m_Device.updateDescriptorSets(Cast<u32>(writeDescriptors.size()), writeDescriptors.data(), 0, nullptr);
|
device.m_Device.updateDescriptorSets(Cast<u32>(writeDescriptors.size()), writeDescriptors.data(), 0, nullptr);
|
||||||
|
|
||||||
|
|
@ -428,56 +412,35 @@ main(int, char **)
|
||||||
.baseArrayLayer = 0,
|
.baseArrayLayer = 0,
|
||||||
.layerCount = 1,
|
.layerCount = 1,
|
||||||
};
|
};
|
||||||
vk::ImageMemoryBarrier2 topOfThePipeBarrier = {
|
vk::ImageMemoryBarrier topOfThePipeBarrier = {
|
||||||
// For Color Attachment output ref:
|
|
||||||
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/7193#issuecomment-1875960974
|
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
|
||||||
.srcAccessMask = vk::AccessFlagBits2::eNone,
|
|
||||||
.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
|
||||||
.dstAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
|
|
||||||
.oldLayout = vk::ImageLayout::eUndefined,
|
.oldLayout = vk::ImageLayout::eUndefined,
|
||||||
.newLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
.newLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
||||||
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.subresourceRange = subresourceRange,
|
.subresourceRange = subresourceRange,
|
||||||
};
|
};
|
||||||
vk::DependencyInfo topOfThePipeDependency = {
|
vk::ImageMemoryBarrier renderToPresentBarrier = {
|
||||||
.imageMemoryBarrierCount = 1,
|
|
||||||
.pImageMemoryBarriers = &topOfThePipeBarrier,
|
|
||||||
};
|
|
||||||
vk::ImageMemoryBarrier2 renderToPresentBarrier = {
|
|
||||||
.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
|
||||||
.srcAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
|
|
||||||
.dstStageMask = vk::PipelineStageFlagBits2::eBottomOfPipe,
|
|
||||||
.dstAccessMask = vk::AccessFlagBits2::eNone,
|
|
||||||
.oldLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
.oldLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
||||||
.newLayout = vk::ImageLayout::ePresentSrcKHR,
|
.newLayout = vk::ImageLayout::ePresentSrcKHR,
|
||||||
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
.subresourceRange = subresourceRange,
|
.subresourceRange = subresourceRange,
|
||||||
};
|
};
|
||||||
vk::DependencyInfo renderToPresentDependency = {
|
|
||||||
.imageMemoryBarrierCount = 1,
|
|
||||||
.pImageMemoryBarriers = &renderToPresentBarrier,
|
|
||||||
};
|
|
||||||
|
|
||||||
FrameManager frameManager = {&device, queueAllocation.m_Family, MAX_FRAMES_IN_FLIGHT};
|
FrameManager frameManager = {&device, queueAllocation.m_Family, MAX_FRAMES_IN_FLIGHT};
|
||||||
eastl::fixed_vector<Ref<Image>, MAX_FRAMES_IN_FLIGHT> depthImages;
|
eastl::fixed_vector<DepthImage, MAX_FRAMES_IN_FLIGHT> depthImages(frameManager.m_FramesInFlight);
|
||||||
|
for (auto &depthImage : depthImages)
|
||||||
|
{
|
||||||
|
depthImage.Init(&device, swapchain.m_Extent, "Depth");
|
||||||
|
}
|
||||||
|
|
||||||
auto initDepthImages = [&imageManager, &depthImages, &frameManager] (const vk::Extent2D extent) {
|
auto recreateDepthBuffers = [&device, &depthImages](vk::Extent2D extent) {
|
||||||
for (u32 i = 0; i < frameManager.m_FramesInFlight; ++i)
|
for (auto &depthImage : depthImages)
|
||||||
{
|
{
|
||||||
depthImages.push_back(
|
depthImage.Destroy(&device);
|
||||||
imageManager.CreateDepthStencilImage({.m_Extent = extent, .m_Name = "Depth"}).ToPointer());
|
depthImage.Init(&device, extent, "Depth");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
initDepthImages(swapchain.m_Extent);
|
|
||||||
|
|
||||||
auto recreateDepthBuffers = [&depthImages, &initDepthImages](const vk::Extent2D extent) {
|
|
||||||
depthImages.clear();
|
|
||||||
initDepthImages(extent);
|
|
||||||
};
|
|
||||||
swapchain.RegisterResizeCallback(recreateDepthBuffers);
|
swapchain.RegisterResizeCallback(recreateDepthBuffers);
|
||||||
|
|
||||||
Time::Init();
|
Time::Init();
|
||||||
|
|
@ -488,15 +451,15 @@ main(int, char **)
|
||||||
Time::Update();
|
Time::Update();
|
||||||
|
|
||||||
camera.m_Model *= rotate(mat4{1.0f}, Cast<f32>(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f));
|
camera.m_Model *= rotate(mat4{1.0f}, Cast<f32>(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f));
|
||||||
ubo->Write(&device, 0, sizeof camera, &camera);
|
ubo.Write(&device, 0, sizeof camera, &camera);
|
||||||
|
|
||||||
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &surface, window.GetSize());
|
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &window);
|
||||||
|
|
||||||
u32 imageIndex = currentFrame->m_ImageIdx;
|
u32 imageIndex = currentFrame->m_ImageIdx;
|
||||||
vk::ImageView currentImageView = swapchain.m_ImageViews[imageIndex];
|
vk::ImageView currentImageView = swapchain.m_ImageViews[imageIndex];
|
||||||
vk::Image currentImage = swapchain.m_Images[imageIndex];
|
vk::Image currentImage = swapchain.m_Images[imageIndex];
|
||||||
vk::CommandBuffer cmd = currentFrame->m_CommandBuffer;
|
vk::CommandBuffer cmd = currentFrame->m_CommandBuffer;
|
||||||
vk::ImageView currentDepthImageView = depthImages[currentFrame->m_FrameIdx]->m_View;
|
vk::ImageView currentDepthImageView = depthImages[currentFrame->m_FrameIdx].m_View;
|
||||||
|
|
||||||
topOfThePipeBarrier.image = currentImage;
|
topOfThePipeBarrier.image = currentImage;
|
||||||
renderToPresentBarrier.image = currentImage;
|
renderToPresentBarrier.image = currentImage;
|
||||||
|
|
@ -504,7 +467,8 @@ main(int, char **)
|
||||||
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
||||||
AbortIfFailed(cmd.begin(&beginInfo));
|
AbortIfFailed(cmd.begin(&beginInfo));
|
||||||
|
|
||||||
cmd.pipelineBarrier2(&topOfThePipeDependency);
|
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eColorAttachmentOutput,
|
||||||
|
{}, 0, nullptr, 0, nullptr, 1, &topOfThePipeBarrier);
|
||||||
|
|
||||||
// Render
|
// Render
|
||||||
eastl::array attachmentInfos = {
|
eastl::array attachmentInfos = {
|
||||||
|
|
@ -514,7 +478,7 @@ main(int, char **)
|
||||||
.resolveMode = vk::ResolveModeFlagBits::eNone,
|
.resolveMode = vk::ResolveModeFlagBits::eNone,
|
||||||
.loadOp = vk::AttachmentLoadOp::eClear,
|
.loadOp = vk::AttachmentLoadOp::eClear,
|
||||||
.storeOp = vk::AttachmentStoreOp::eStore,
|
.storeOp = vk::AttachmentStoreOp::eStore,
|
||||||
.clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 0.0f},
|
.clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 1.0f},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -541,11 +505,14 @@ main(int, char **)
|
||||||
cmd.setScissor(0, 1, &scissor);
|
cmd.setScissor(0, 1, &scissor);
|
||||||
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline);
|
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline);
|
||||||
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 0, 1, &descriptorSet, 0, nullptr);
|
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipeline.m_Layout, 0, 1, &descriptorSet, 0, nullptr);
|
||||||
|
usize offsets = 0;
|
||||||
|
cmd.bindVertexBuffers(0, 1, &vbo.m_Buffer, &offsets);
|
||||||
cmd.draw(Cast<u32>(vertices.size()), 1, 0, 0);
|
cmd.draw(Cast<u32>(vertices.size()), 1, 0, 0);
|
||||||
|
|
||||||
cmd.endRendering();
|
cmd.endRendering();
|
||||||
|
|
||||||
cmd.pipelineBarrier2(&renderToPresentDependency);
|
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eBottomOfPipe,
|
||||||
|
{}, 0, nullptr, 0, nullptr, 1, &renderToPresentBarrier);
|
||||||
|
|
||||||
AbortIfFailed(cmd.end());
|
AbortIfFailed(cmd.end());
|
||||||
|
|
||||||
|
|
@ -561,13 +528,21 @@ main(int, char **)
|
||||||
};
|
};
|
||||||
AbortIfFailed(commandQueue.submit(1, &submitInfo, currentFrame->m_FrameAvailableFence));
|
AbortIfFailed(commandQueue.submit(1, &submitInfo, currentFrame->m_FrameAvailableFence));
|
||||||
|
|
||||||
currentFrame->Present(commandQueue, &swapchain, &surface, window.GetSize());
|
currentFrame->Present(commandQueue, &swapchain, &window);
|
||||||
}
|
}
|
||||||
|
|
||||||
device.WaitIdle();
|
device.WaitIdle();
|
||||||
|
|
||||||
|
for (auto &depthImage : depthImages)
|
||||||
|
{
|
||||||
|
depthImage.Destroy(&device);
|
||||||
|
}
|
||||||
device.m_Device.destroy(sampler, nullptr);
|
device.m_Device.destroy(sampler, nullptr);
|
||||||
|
ubo.Destroy(&device);
|
||||||
device.m_Device.destroy(descriptorPool, nullptr);
|
device.m_Device.destroy(descriptorPool, nullptr);
|
||||||
device.m_Device.destroy(copyPool, nullptr);
|
device.m_Device.destroy(copyPool, nullptr);
|
||||||
|
crate.Destroy(&device);
|
||||||
|
vbo.Destroy(&device);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -605,12 +580,6 @@ CreatePipeline(const Device *device, const Swapchain *swapchain)
|
||||||
.descriptorCount = 1,
|
.descriptorCount = 1,
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eFragment,
|
.stageFlags = vk::ShaderStageFlagBits::eFragment,
|
||||||
},
|
},
|
||||||
vk::DescriptorSetLayoutBinding{
|
|
||||||
.binding = 2,
|
|
||||||
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
|
||||||
.descriptorCount = 1,
|
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eVertex,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
|
vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
|
||||||
.bindingCount = Cast<u32>(descriptorSetLayoutBinding.size()),
|
.bindingCount = Cast<u32>(descriptorSetLayoutBinding.size()),
|
||||||
|
|
@ -630,7 +599,15 @@ CreatePipeline(const Device *device, const Swapchain *swapchain)
|
||||||
AbortIfFailed(device->m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
|
AbortIfFailed(device->m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
|
||||||
device->SetName(pipelineLayout, "Box Layout");
|
device->SetName(pipelineLayout, "Box Layout");
|
||||||
|
|
||||||
vk::PipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {};
|
vk::VertexInputBindingDescription inputBindingDescription = Vertex::GetBinding(0);
|
||||||
|
auto inputAttributeDescription = Vertex::GetAttributes(0);
|
||||||
|
|
||||||
|
vk::PipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {
|
||||||
|
.vertexBindingDescriptionCount = 1,
|
||||||
|
.pVertexBindingDescriptions = &inputBindingDescription,
|
||||||
|
.vertexAttributeDescriptionCount = Cast<u32>(inputAttributeDescription.size()),
|
||||||
|
.pVertexAttributeDescriptions = inputAttributeDescription.data(),
|
||||||
|
};
|
||||||
vk::PipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = {
|
vk::PipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = {
|
||||||
.topology = vk::PrimitiveTopology::eTriangleList,
|
.topology = vk::PrimitiveTopology::eTriangleList,
|
||||||
.primitiveRestartEnable = false,
|
.primitiveRestartEnable = false,
|
||||||
|
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
struct FS_Input {
|
|
||||||
float2 UV0 : TEXCOORD0;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FS_Output
|
|
||||||
{
|
|
||||||
float4 ColorTarget : SV_Target0;
|
|
||||||
};
|
|
||||||
|
|
||||||
[[vk::binding(1, 0)]] Texture2D<float4> Texture;
|
|
||||||
[[vk::binding(1, 0)]] SamplerState Sampler;
|
|
||||||
|
|
||||||
FS_Output main(FS_Input StageInput) {
|
|
||||||
FS_Output output;
|
|
||||||
|
|
||||||
output.ColorTarget = float4(Texture.Sample(Sampler, StageInput.UV0).rgb, 1.0);
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
struct VS_Input
|
|
||||||
{
|
|
||||||
uint VertexIndex : SV_VertexID;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct VS_Output
|
|
||||||
{
|
|
||||||
float2 UV0 : TEXCOORD0;
|
|
||||||
float4 VertexPosition : SV_Position;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CameraData {
|
|
||||||
float4x4 Model;
|
|
||||||
float4x4 View;
|
|
||||||
float4x4 Projection;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct VertexData {
|
|
||||||
float4 Position;
|
|
||||||
float2 UV0;
|
|
||||||
};
|
|
||||||
|
|
||||||
[[vk::binding(0, 0)]] ConstantBuffer<CameraData> Camera;
|
|
||||||
[[vk::binding(2, 0)]] StructuredBuffer<VertexData> Vertices;
|
|
||||||
|
|
||||||
VS_Output main(VS_Input StageInput) {
|
|
||||||
VS_Output output;
|
|
||||||
|
|
||||||
output.UV0 = Vertices[StageInput.VertexIndex].UV0;
|
|
||||||
|
|
||||||
float4 position = Vertices[StageInput.VertexIndex].Position;
|
|
||||||
|
|
||||||
output.VertexPosition = mul(Camera.Projection, mul(Camera.View, mul(Camera.Model, position)));
|
|
||||||
|
|
||||||
return output;
|
|
||||||
}
|
|
||||||
|
|
@ -5,28 +5,28 @@ cmake_minimum_required(VERSION 3.13)
|
||||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fsanitize=address")
|
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fsanitize=address")
|
||||||
find_path(TINYGLTF_INCLUDE_DIRS "tiny_gltf.h")
|
find_path(TINYGLTF_INCLUDE_DIRS "tiny_gltf.h")
|
||||||
|
|
||||||
add_executable(model_render "model_render.cpp"
|
add_executable(model_render model_render.cpp
|
||||||
"pipeline_utils.cpp"
|
pipeline_utils.cpp
|
||||||
"pipeline_utils.h"
|
pipeline_utils.h
|
||||||
"asset_loader.cpp"
|
asset_loader.cpp
|
||||||
"asset_loader.h"
|
asset_loader.h
|
||||||
"light_manager.cpp"
|
light_manager.cpp
|
||||||
"light_manager.h"
|
light_manager.h
|
||||||
"gpu_resource_manager.cpp"
|
gpu_resource_manager.cpp
|
||||||
"gpu_resource_manager.h"
|
gpu_resource_manager.h
|
||||||
"nodes.cpp"
|
nodes.cpp
|
||||||
"nodes.h"
|
nodes.h
|
||||||
"ibl_helpers.cpp"
|
ibl_helpers.cpp
|
||||||
"ibl_helpers.h")
|
ibl_helpers.h)
|
||||||
|
|
||||||
add_shader(model_render "shader/model.vs.hlsl")
|
add_shader(model_render shader/model.vs.hlsl)
|
||||||
add_shader(model_render "shader/model.ps.hlsl")
|
add_shader(model_render shader/model.ps.hlsl)
|
||||||
add_shader(model_render "shader/eqrect_to_cube.cs.hlsl")
|
add_shader(model_render shader/eqrect_to_cube.cs.hlsl)
|
||||||
add_shader(model_render "shader/background.vs.hlsl")
|
add_shader(model_render shader/background.vs.hlsl)
|
||||||
add_shader(model_render "shader/background.ps.hlsl")
|
add_shader(model_render shader/background.ps.hlsl)
|
||||||
add_shader(model_render "shader/diffuse_irradiance.cs.hlsl")
|
add_shader(model_render shader/diffuse_irradiance.cs.hlsl)
|
||||||
add_shader(model_render "shader/prefilter.cs.hlsl")
|
add_shader(model_render shader/prefilter.cs.hlsl)
|
||||||
add_shader(model_render "shader/brdf_lut.cs.hlsl")
|
add_shader(model_render shader/brdf_lut.cs.hlsl)
|
||||||
|
|
||||||
target_link_libraries(model_render PRIVATE aster_core)
|
target_link_libraries(model_render PRIVATE aster_core)
|
||||||
target_link_libraries(model_render PRIVATE util_helper)
|
target_link_libraries(model_render PRIVATE util_helper)
|
||||||
|
|
|
||||||
|
|
@ -10,15 +10,15 @@
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
|
|
||||||
#include "aster/core/buffer.h"
|
|
||||||
#include "aster/core/device.h"
|
|
||||||
#include "aster/core/image.h"
|
|
||||||
|
|
||||||
#include "gpu_resource_manager.h"
|
|
||||||
#include "helpers.h"
|
|
||||||
#include "asset_loader.h"
|
#include "asset_loader.h"
|
||||||
|
|
||||||
#include <EASTL/fixed_vector.h>
|
#include "EASTL/fixed_vector.h"
|
||||||
|
#include "buffer.h"
|
||||||
|
#include "device.h"
|
||||||
|
#include "gpu_resource_manager.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
#include "image.h"
|
||||||
|
|
||||||
#include <EASTL/hash_map.h>
|
#include <EASTL/hash_map.h>
|
||||||
#include <glm/gtc/type_ptr.hpp>
|
#include <glm/gtc/type_ptr.hpp>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "aster/aster.h"
|
#include "buffer.h"
|
||||||
|
#include "global.h"
|
||||||
#include "aster/core/buffer.h"
|
|
||||||
|
|
||||||
#include "gpu_resource_manager.h"
|
#include "gpu_resource_manager.h"
|
||||||
#include "nodes.h"
|
#include "nodes.h"
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,10 @@
|
||||||
|
|
||||||
#include "gpu_resource_manager.h"
|
#include "gpu_resource_manager.h"
|
||||||
|
|
||||||
|
#include "buffer.h"
|
||||||
|
#include "device.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
#include "image.h"
|
||||||
#include "aster/core/buffer.h"
|
|
||||||
#include "aster/core/device.h"
|
|
||||||
#include "aster/core/image.h"
|
|
||||||
|
|
||||||
#include <EASTL/array.h>
|
#include <EASTL/array.h>
|
||||||
|
|
||||||
|
|
@ -23,7 +22,7 @@ TextureManager::Init(const u32 maxCapacity)
|
||||||
TextureHandle
|
TextureHandle
|
||||||
TextureManager::Commit(Texture *texture)
|
TextureManager::Commit(Texture *texture)
|
||||||
{
|
{
|
||||||
ERROR_IF(!texture || !texture->IsValid(), "Texture must be valid for committal")
|
ERROR_IF(!texture || !texture->IsValid(), "Texture must be valid for commital")
|
||||||
THEN_ABORT(-1);
|
THEN_ABORT(-1);
|
||||||
|
|
||||||
if (m_FreeHead != GpuResourceHandle::INVALID_HANDLE)
|
if (m_FreeHead != GpuResourceHandle::INVALID_HANDLE)
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "aster/aster.h"
|
#include "global.h"
|
||||||
|
|
||||||
#include <EASTL/deque.h>
|
#include <EASTL/deque.h>
|
||||||
#include <EASTL/vector_map.h>
|
#include <EASTL/vector_map.h>
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,15 @@
|
||||||
|
|
||||||
#include "ibl_helpers.h"
|
#include "ibl_helpers.h"
|
||||||
|
|
||||||
#include "aster/core/device.h"
|
#include "EASTL/fixed_vector.h"
|
||||||
#include "aster/core/image.h"
|
#include "EASTL/tuple.h"
|
||||||
|
|
||||||
#include "asset_loader.h"
|
#include "asset_loader.h"
|
||||||
|
#include "device.h"
|
||||||
#include "gpu_resource_manager.h"
|
#include "gpu_resource_manager.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
#include "image.h"
|
||||||
#include "pipeline_utils.h"
|
#include "pipeline_utils.h"
|
||||||
|
|
||||||
#include <EASTL/fixed_vector.h>
|
|
||||||
#include <EASTL/tuple.h>
|
|
||||||
|
|
||||||
constexpr cstr EQUIRECT_TO_CUBE_SHADER_FILE = "shader/eqrect_to_cube.cs.hlsl.spv";
|
constexpr cstr EQUIRECT_TO_CUBE_SHADER_FILE = "shader/eqrect_to_cube.cs.hlsl.spv";
|
||||||
constexpr cstr DIFFUSE_IRRADIANCE_SHADER_FILE = "shader/diffuse_irradiance.cs.hlsl.spv";
|
constexpr cstr DIFFUSE_IRRADIANCE_SHADER_FILE = "shader/diffuse_irradiance.cs.hlsl.spv";
|
||||||
constexpr cstr PREFILTER_SHADER_FILE = "shader/prefilter.cs.hlsl.spv";
|
constexpr cstr PREFILTER_SHADER_FILE = "shader/prefilter.cs.hlsl.spv";
|
||||||
|
|
@ -197,8 +195,8 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
vk::PushConstantRange pcr = {
|
vk::PushConstantRange pcr = {
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eCompute,
|
.stageFlags = vk::ShaderStageFlagBits::eCompute,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
.size = Cast<u32>(eastl::max(eastl::max(sizeof(SkyboxPushConstants), sizeof(BrdfLutPushConstants)),
|
.size = eastl::max(eastl::max(sizeof(SkyboxPushConstants), sizeof(BrdfLutPushConstants)),
|
||||||
eastl::max(sizeof(DiffuseIrradiancePushConstants), sizeof(PrefilterPushConstants)))),
|
eastl::max(sizeof(DiffuseIrradiancePushConstants), sizeof(PrefilterPushConstants))),
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::PipelineLayout pipelineLayout;
|
vk::PipelineLayout pipelineLayout;
|
||||||
|
|
@ -254,7 +252,7 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
||||||
};
|
};
|
||||||
|
|
||||||
eastl::array<vk::Pipeline, computePipelineCreateInfo.size()> pipelines;
|
eastl::array<vk::Pipeline, computePipelineCreateInfo.size()> pipelines;
|
||||||
AbortIfFailed(pDevice->m_Device.createComputePipelines(pDevice->m_PipelineCache, Cast<u32>(computePipelineCreateInfo.size()),
|
AbortIfFailed(pDevice->m_Device.createComputePipelines(pDevice->m_PipelineCache, computePipelineCreateInfo.size(),
|
||||||
computePipelineCreateInfo.data(), nullptr,
|
computePipelineCreateInfo.data(), nullptr,
|
||||||
pipelines.data()));
|
pipelines.data()));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "aster/aster.h"
|
#include "global.h"
|
||||||
#include "gpu_resource_manager.h"
|
#include "gpu_resource_manager.h"
|
||||||
|
|
||||||
|
#include <EASTL/tuple.h>
|
||||||
|
|
||||||
struct Pipeline;
|
struct Pipeline;
|
||||||
struct Texture;
|
struct Texture;
|
||||||
struct TextureCube;
|
struct TextureCube;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#include "light_manager.h"
|
#include "light_manager.h"
|
||||||
|
|
||||||
#include "aster/core/buffer.h"
|
#include "buffer.h"
|
||||||
#include "glm/ext/matrix_transform.hpp"
|
#include "glm/ext/matrix_transform.hpp"
|
||||||
|
|
||||||
struct Light
|
struct Light
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "aster/aster.h"
|
#include "global.h"
|
||||||
|
|
||||||
// TODO: Separate files so you only import handles.
|
// TODO: Separate files so you only import handles.
|
||||||
#include "gpu_resource_manager.h"
|
#include "gpu_resource_manager.h"
|
||||||
|
|
@ -66,7 +66,7 @@ struct LightManager
|
||||||
// Using lower bit. Capacity can be directly a multiple of 2
|
// Using lower bit. Capacity can be directly a multiple of 2
|
||||||
// Thus, range is up to MaxValue<u16>
|
// Thus, range is up to MaxValue<u16>
|
||||||
constexpr static u16 UPDATE_REQUIRED_BIT = 1;
|
constexpr static u16 UPDATE_REQUIRED_BIT = 1;
|
||||||
constexpr static u16 CAPACITY_MASK = Cast<u16>(~UPDATE_REQUIRED_BIT);
|
constexpr static u16 CAPACITY_MASK = ~(UPDATE_REQUIRED_BIT);
|
||||||
|
|
||||||
LightHandle AddDirectional(const vec3 &direction, const vec3 &color, f32 intensity);
|
LightHandle AddDirectional(const vec3 &direction, const vec3 &color, f32 intensity);
|
||||||
LightHandle AddPoint(const vec3 &position, const vec3 &color, f32 radius, f32 intensity);
|
LightHandle AddPoint(const vec3 &position, const vec3 &color, f32 radius, f32 intensity);
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,16 @@
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
// =============================================
|
// =============================================
|
||||||
|
|
||||||
#include "aster/aster.h"
|
#include "buffer.h"
|
||||||
|
#include "constants.h"
|
||||||
#include "aster/core/buffer.h"
|
#include "context.h"
|
||||||
#include "aster/core/constants.h"
|
#include "device.h"
|
||||||
#include "aster/core/context.h"
|
#include "global.h"
|
||||||
#include "aster/core/device.h"
|
#include "image.h"
|
||||||
#include "aster/core/image.h"
|
#include "physical_device.h"
|
||||||
#include "aster/core/physical_device.h"
|
#include "pipeline.h"
|
||||||
#include "aster/core/pipeline.h"
|
#include "swapchain.h"
|
||||||
#include "aster/core/swapchain.h"
|
#include "window.h"
|
||||||
#include "aster/core/window.h"
|
|
||||||
|
|
||||||
#include "frame.h"
|
#include "frame.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
@ -134,11 +133,10 @@ main(int, char **)
|
||||||
{
|
{
|
||||||
MIN_LOG_LEVEL(Logger::LogType::eInfo);
|
MIN_LOG_LEVEL(Logger::LogType::eInfo);
|
||||||
|
|
||||||
Window window = {"ModelRender (Aster)", {INIT_WIDTH, INIT_HEIGHT}};
|
|
||||||
Context context = {"ModelRender", VERSION};
|
Context context = {"ModelRender", VERSION};
|
||||||
Surface surface = {&context, &window, "Primary Surface"};
|
Window window = {"ModelRender (Aster)", &context, {INIT_WIDTH, INIT_HEIGHT}};
|
||||||
|
|
||||||
PhysicalDevices physicalDevices = {&surface, &context};
|
PhysicalDevices physicalDevices = {&window, &context};
|
||||||
PhysicalDevice deviceToUse = FindSuitableDevice(physicalDevices);
|
PhysicalDevice deviceToUse = FindSuitableDevice(physicalDevices);
|
||||||
|
|
||||||
usize physicalDeviceOffsetAlignment = deviceToUse.m_DeviceProperties.limits.minUniformBufferOffsetAlignment;
|
usize physicalDeviceOffsetAlignment = deviceToUse.m_DeviceProperties.limits.minUniformBufferOffsetAlignment;
|
||||||
|
|
@ -175,7 +173,7 @@ main(int, char **)
|
||||||
Device device = {&context, &deviceToUse, &enabledDeviceFeatures,
|
Device device = {&context, &deviceToUse, &enabledDeviceFeatures,
|
||||||
{queueAllocation}, pipelineCacheData, "Primary Device"};
|
{queueAllocation}, pipelineCacheData, "Primary Device"};
|
||||||
vk::Queue graphicsQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
vk::Queue graphicsQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
||||||
Swapchain swapchain = {&surface, &device, window.GetSize(), "Primary Chain"};
|
Swapchain swapchain = {&window, &device, "Primary Chain"};
|
||||||
GpuResourceManager resourceManager = {&device, 1000};
|
GpuResourceManager resourceManager = {&device, 1000};
|
||||||
|
|
||||||
AssetLoader assetLoader = {&resourceManager, graphicsQueue, queueAllocation.m_Family, queueAllocation.m_Family};
|
AssetLoader assetLoader = {&resourceManager, graphicsQueue, queueAllocation.m_Family, queueAllocation.m_Family};
|
||||||
|
|
@ -515,7 +513,7 @@ main(int, char **)
|
||||||
cameraController.m_Camera.CalculateInverses();
|
cameraController.m_Camera.CalculateInverses();
|
||||||
ubo.Write(&device, 0, sizeof cameraController.m_Camera, &cameraController.m_Camera);
|
ubo.Write(&device, 0, sizeof cameraController.m_Camera, &cameraController.m_Camera);
|
||||||
|
|
||||||
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &surface, window.GetSize());
|
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &window);
|
||||||
|
|
||||||
u32 imageIndex = currentFrame->m_ImageIdx;
|
u32 imageIndex = currentFrame->m_ImageIdx;
|
||||||
vk::Image currentSwapchainImage = swapchain.m_Images[imageIndex];
|
vk::Image currentSwapchainImage = swapchain.m_Images[imageIndex];
|
||||||
|
|
@ -688,7 +686,7 @@ main(int, char **)
|
||||||
};
|
};
|
||||||
AbortIfFailed(graphicsQueue.submit(1, &submitInfo, currentFrame->m_FrameAvailableFence));
|
AbortIfFailed(graphicsQueue.submit(1, &submitInfo, currentFrame->m_FrameAvailableFence));
|
||||||
|
|
||||||
currentFrame->Present(graphicsQueue, &swapchain, &surface, window.GetSize());
|
currentFrame->Present(graphicsQueue, &swapchain, &window);
|
||||||
}
|
}
|
||||||
|
|
||||||
device.WaitIdle();
|
device.WaitIdle();
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "aster/aster.h"
|
#include "global.h"
|
||||||
|
|
||||||
#include <EASTL/vector.h>
|
#include "EASTL/vector.h"
|
||||||
|
|
||||||
struct Nodes
|
struct Nodes
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,7 @@
|
||||||
|
|
||||||
#include "pipeline_utils.h"
|
#include "pipeline_utils.h"
|
||||||
|
|
||||||
#include "aster/core/device.h"
|
#include "device.h"
|
||||||
#include "aster/core/pipeline.h"
|
|
||||||
|
|
||||||
#include "gpu_resource_manager.h"
|
#include "gpu_resource_manager.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,12 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "aster/aster.h"
|
#include "global.h"
|
||||||
|
#include "pipeline.h"
|
||||||
|
|
||||||
struct GpuResourceManager;
|
struct GpuResourceManager;
|
||||||
struct Swapchain;
|
struct Swapchain;
|
||||||
struct Device;
|
struct Device;
|
||||||
struct Pipeline;
|
|
||||||
|
|
||||||
constexpr auto VERTEX_SHADER_FILE = "shader/model.vs.hlsl.spv";
|
constexpr auto VERTEX_SHADER_FILE = "shader/model.vs.hlsl.spv";
|
||||||
constexpr auto FRAGMENT_SHADER_FILE = "shader/model.ps.hlsl.spv";
|
constexpr auto FRAGMENT_SHADER_FILE = "shader/model.ps.hlsl.spv";
|
||||||
|
|
|
||||||
|
|
@ -7,24 +7,24 @@ find_path(TINYGLTF_INCLUDE_DIRS "tiny_gltf.h")
|
||||||
|
|
||||||
find_package(EnTT REQUIRED CONFIG)
|
find_package(EnTT REQUIRED CONFIG)
|
||||||
|
|
||||||
add_executable(scene_render "main.cpp"
|
add_executable(scene_render main.cpp
|
||||||
"render_resource_manager.cpp" "render_resource_manager.h"
|
render_resource_manager.cpp render_resource_manager.h
|
||||||
"asset_loader.cpp" "asset_loader.h"
|
asset_loader.cpp asset_loader.h
|
||||||
"pipeline_utils.cpp" "pipeline_utils.h"
|
pipeline_utils.cpp pipeline_utils.h
|
||||||
"core_components.h"
|
core_components.h
|
||||||
"ecs_adapter.h"
|
ecs_adapter.h
|
||||||
"camera.h"
|
camera.h
|
||||||
"ibl_helpers.cpp" "ibl_helpers.h"
|
ibl_helpers.cpp ibl_helpers.h
|
||||||
"light_manager.cpp" "light_manager.h")
|
light_manager.cpp light_manager.h)
|
||||||
|
|
||||||
add_shader(scene_render "shader/model.frag.glsl")
|
add_shader(scene_render shader/model.frag.glsl)
|
||||||
add_shader(scene_render "shader/model.vert.glsl")
|
add_shader(scene_render shader/model.vert.glsl)
|
||||||
add_shader(scene_render "shader/eqrect_to_cube.cs.hlsl")
|
add_shader(scene_render shader/eqrect_to_cube.cs.hlsl)
|
||||||
add_shader(scene_render "shader/diffuse_irradiance.cs.hlsl")
|
add_shader(scene_render shader/diffuse_irradiance.cs.hlsl)
|
||||||
add_shader(scene_render "shader/prefilter.cs.hlsl")
|
add_shader(scene_render shader/prefilter.cs.hlsl)
|
||||||
add_shader(scene_render "shader/brdf_lut.cs.hlsl")
|
add_shader(scene_render shader/brdf_lut.cs.hlsl)
|
||||||
add_shader(scene_render "shader/background.vert.glsl")
|
add_shader(scene_render shader/background.vert.glsl)
|
||||||
add_shader(scene_render "shader/background.frag.glsl")
|
add_shader(scene_render shader/background.frag.glsl)
|
||||||
|
|
||||||
target_link_libraries(scene_render PRIVATE aster_core)
|
target_link_libraries(scene_render PRIVATE aster_core)
|
||||||
target_link_libraries(scene_render PRIVATE util_helper)
|
target_link_libraries(scene_render PRIVATE util_helper)
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,9 @@
|
||||||
|
|
||||||
#include "asset_loader.h"
|
#include "asset_loader.h"
|
||||||
|
|
||||||
#include "aster/core/buffer.h"
|
#include "buffer.h"
|
||||||
#include "aster/core/device.h"
|
#include "device.h"
|
||||||
#include "aster/core/image.h"
|
#include "image.h"
|
||||||
|
|
||||||
#include "core_components.h"
|
#include "core_components.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
@ -753,8 +753,8 @@ AssetLoader::ProcessNode(tinygltf::Model *model, eastl::vector<vec4> *vertexPosi
|
||||||
entities->push_back(entity);
|
entities->push_back(entity);
|
||||||
|
|
||||||
m_Registry->emplace<CMesh>(entity, CMesh{
|
m_Registry->emplace<CMesh>(entity, CMesh{
|
||||||
.m_VertexPositionPtr = vertexOffset * sizeof(vec4),
|
.m_VertexPositionPtr = vertexOffset * sizeof vec4,
|
||||||
.m_VertexDataPtr = vertexOffset * sizeof(VertexData),
|
.m_VertexDataPtr = vertexOffset * sizeof VertexData,
|
||||||
.m_FirstIndex = indexOffset,
|
.m_FirstIndex = indexOffset,
|
||||||
.m_IndexCount = indexCount,
|
.m_IndexCount = indexCount,
|
||||||
});
|
});
|
||||||
|
|
@ -764,7 +764,7 @@ AssetLoader::ProcessNode(tinygltf::Model *model, eastl::vector<vec4> *vertexPosi
|
||||||
m_Registry->emplace<CParent<CDynamicTransform>>(entity, nodeRoot);
|
m_Registry->emplace<CParent<CDynamicTransform>>(entity, nodeRoot);
|
||||||
if (prim.material >= 0)
|
if (prim.material >= 0)
|
||||||
{
|
{
|
||||||
m_Registry->emplace<CMaterial>(entity, sizeof(Material) * loadMaterial(prim.material));
|
m_Registry->emplace<CMaterial>(entity, sizeof Material * loadMaterial(prim.material));
|
||||||
m_Registry->emplace<CRequiresPostLoadProcess<CMaterial>>(entity);
|
m_Registry->emplace<CRequiresPostLoadProcess<CMaterial>>(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -870,7 +870,7 @@ AssetLoader::LoadModelToGpu(cstr path, cstr name)
|
||||||
}
|
}
|
||||||
else if (material->alphaMode == "MASK")
|
else if (material->alphaMode == "MASK")
|
||||||
{
|
{
|
||||||
alphaBlendValue = Cast<f32>(material->alphaCutoff);
|
alphaBlendValue = material->alphaCutoff;
|
||||||
}
|
}
|
||||||
|
|
||||||
materials.push_back({
|
materials.push_back({
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "aster/aster.h"
|
#include "global.h"
|
||||||
|
|
||||||
#include "aster/core/buffer.h"
|
#include "buffer.h"
|
||||||
#include "render_resource_manager.h"
|
#include "render_resource_manager.h"
|
||||||
|
|
||||||
#include "ecs_adapter.h"
|
#include "ecs_adapter.h"
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
// =============================================
|
// =============================================
|
||||||
|
|
||||||
#include "aster/aster.h"
|
#include "global.h"
|
||||||
|
|
||||||
struct Camera
|
struct Camera
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "aster/aster.h"
|
#include "global.h"
|
||||||
|
|
||||||
template <typename TComponent>
|
template <typename TComponent>
|
||||||
struct CDirty
|
struct CDirty
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,15 @@
|
||||||
|
|
||||||
#include "ibl_helpers.h"
|
#include "ibl_helpers.h"
|
||||||
|
|
||||||
#include "aster/core/device.h"
|
#include "EASTL/fixed_vector.h"
|
||||||
#include "aster/core/image.h"
|
#include "EASTL/tuple.h"
|
||||||
|
|
||||||
#include "asset_loader.h"
|
#include "asset_loader.h"
|
||||||
|
#include "device.h"
|
||||||
#include "render_resource_manager.h"
|
#include "render_resource_manager.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
#include "image.h"
|
||||||
#include "pipeline_utils.h"
|
#include "pipeline_utils.h"
|
||||||
|
|
||||||
#include <EASTL/fixed_vector.h>
|
|
||||||
#include <EASTL/tuple.h>
|
|
||||||
|
|
||||||
constexpr cstr EQUIRECT_TO_CUBE_SHADER_FILE = "shader/eqrect_to_cube.cs.hlsl.spv";
|
constexpr cstr EQUIRECT_TO_CUBE_SHADER_FILE = "shader/eqrect_to_cube.cs.hlsl.spv";
|
||||||
constexpr cstr DIFFUSE_IRRADIANCE_SHADER_FILE = "shader/diffuse_irradiance.cs.hlsl.spv";
|
constexpr cstr DIFFUSE_IRRADIANCE_SHADER_FILE = "shader/diffuse_irradiance.cs.hlsl.spv";
|
||||||
constexpr cstr PREFILTER_SHADER_FILE = "shader/prefilter.cs.hlsl.spv";
|
constexpr cstr PREFILTER_SHADER_FILE = "shader/prefilter.cs.hlsl.spv";
|
||||||
|
|
@ -197,8 +195,8 @@ CreateEnvironment(AssetLoader *assetLoader, vk::Queue computeQueue, const u32 cu
|
||||||
vk::PushConstantRange pcr = {
|
vk::PushConstantRange pcr = {
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eCompute,
|
.stageFlags = vk::ShaderStageFlagBits::eCompute,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
.size = Cast<u32>(eastl::max(eastl::max(sizeof(SkyboxPushConstants), sizeof(BrdfLutPushConstants)),
|
.size = eastl::max(eastl::max(sizeof(SkyboxPushConstants), sizeof(BrdfLutPushConstants)),
|
||||||
eastl::max(sizeof(DiffuseIrradiancePushConstants), sizeof(PrefilterPushConstants)))),
|
eastl::max(sizeof(DiffuseIrradiancePushConstants), sizeof(PrefilterPushConstants))),
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::PipelineLayout pipelineLayout;
|
vk::PipelineLayout pipelineLayout;
|
||||||
|
|
@ -254,7 +252,7 @@ CreateEnvironment(AssetLoader *assetLoader, vk::Queue computeQueue, const u32 cu
|
||||||
};
|
};
|
||||||
|
|
||||||
eastl::array<vk::Pipeline, computePipelineCreateInfo.size()> pipelines;
|
eastl::array<vk::Pipeline, computePipelineCreateInfo.size()> pipelines;
|
||||||
AbortIfFailed(pDevice->m_Device.createComputePipelines(pDevice->m_PipelineCache, Cast<u32>(computePipelineCreateInfo.size()),
|
AbortIfFailed(pDevice->m_Device.createComputePipelines(pDevice->m_PipelineCache, computePipelineCreateInfo.size(),
|
||||||
computePipelineCreateInfo.data(), nullptr,
|
computePipelineCreateInfo.data(), nullptr,
|
||||||
pipelines.data()));
|
pipelines.data()));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "aster/aster.h"
|
#include "global.h"
|
||||||
#include "render_resource_manager.h"
|
#include "render_resource_manager.h"
|
||||||
|
|
||||||
struct Pipeline;
|
struct Pipeline;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#include "light_manager.h"
|
#include "light_manager.h"
|
||||||
|
|
||||||
#include "aster/core/buffer.h"
|
#include "buffer.h"
|
||||||
#include "ibl_helpers.h"
|
#include "ibl_helpers.h"
|
||||||
#include "glm/ext/matrix_transform.hpp"
|
#include "glm/ext/matrix_transform.hpp"
|
||||||
|
|
||||||
|
|
@ -239,11 +239,12 @@ LightManager::Update()
|
||||||
const u16 requiredBufferCapacity = eastl::min(Cast<u16>(m_Lights.capacity()), MAX_LIGHTS);
|
const u16 requiredBufferCapacity = eastl::min(Cast<u16>(m_Lights.capacity()), MAX_LIGHTS);
|
||||||
if ((m_GpuBufferCapacity_ & CAPACITY_MASK) < requiredBufferCapacity)
|
if ((m_GpuBufferCapacity_ & CAPACITY_MASK) < requiredBufferCapacity)
|
||||||
{
|
{
|
||||||
|
StorageBuffer newBuffer;
|
||||||
|
newBuffer.Init(m_ResourceManager->m_Device, requiredBufferCapacity * sizeof m_Lights[0], true, "Light Buffer");
|
||||||
m_GpuBufferCapacity_ = requiredBufferCapacity | UPDATE_REQUIRED_BIT;
|
m_GpuBufferCapacity_ = requiredBufferCapacity | UPDATE_REQUIRED_BIT;
|
||||||
|
|
||||||
m_ResourceManager->Release(m_MetaInfo.m_LightBuffer);
|
m_ResourceManager->Release(m_MetaInfo.m_LightBuffer);
|
||||||
m_MetaInfo.m_LightBuffer =
|
m_MetaInfo.m_LightBuffer = m_ResourceManager->Commit(&newBuffer);
|
||||||
m_ResourceManager->CreateStorageBuffer(requiredBufferCapacity * sizeof m_Lights[0], "Light Buffer");
|
|
||||||
}
|
}
|
||||||
if (m_GpuBufferCapacity_ & UPDATE_REQUIRED_BIT)
|
if (m_GpuBufferCapacity_ & UPDATE_REQUIRED_BIT)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "aster/aster.h"
|
#include "global.h"
|
||||||
|
|
||||||
// TODO: Separate files so you only import handles.
|
// TODO: Separate files so you only import handles.
|
||||||
#include "render_resource_manager.h"
|
#include "render_resource_manager.h"
|
||||||
|
|
@ -73,7 +73,7 @@ struct LightManager
|
||||||
// Using lower bit. Capacity can be directly a multiple of 2
|
// Using lower bit. Capacity can be directly a multiple of 2
|
||||||
// Thus, range is up to MaxValue<u16>
|
// Thus, range is up to MaxValue<u16>
|
||||||
constexpr static u16 UPDATE_REQUIRED_BIT = 1;
|
constexpr static u16 UPDATE_REQUIRED_BIT = 1;
|
||||||
constexpr static u16 CAPACITY_MASK = Cast<u16>(~UPDATE_REQUIRED_BIT);
|
constexpr static u16 CAPACITY_MASK = ~(UPDATE_REQUIRED_BIT);
|
||||||
|
|
||||||
LightHandle AddDirectional(const vec3 &direction, const vec3 &color, f32 intensity);
|
LightHandle AddDirectional(const vec3 &direction, const vec3 &color, f32 intensity);
|
||||||
LightHandle AddPoint(const vec3 &position, const vec3 &color, f32 radius, f32 intensity);
|
LightHandle AddPoint(const vec3 &position, const vec3 &color, f32 radius, f32 intensity);
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,13 @@
|
||||||
// Copyright (c) 2020-2024 Anish Bhobe
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
// =============================================
|
// =============================================
|
||||||
|
|
||||||
#include "aster/core/context.h"
|
#include "context.h"
|
||||||
#include "aster/core/device.h"
|
#include "device.h"
|
||||||
#include "aster/core/image.h"
|
|
||||||
#include "aster/core/physical_device.h"
|
|
||||||
#include "aster/core/pipeline.h"
|
|
||||||
#include "aster/core/swapchain.h"
|
|
||||||
#include "aster/core/window.h"
|
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
#include "physical_device.h"
|
||||||
#include "render_resource_manager.h"
|
#include "render_resource_manager.h"
|
||||||
|
#include "swapchain.h"
|
||||||
|
#include "window.h"
|
||||||
|
|
||||||
#include "asset_loader.h"
|
#include "asset_loader.h"
|
||||||
#include "camera.h"
|
#include "camera.h"
|
||||||
|
|
@ -22,6 +19,8 @@
|
||||||
#include "ecs_adapter.h"
|
#include "ecs_adapter.h"
|
||||||
#include "frame.h"
|
#include "frame.h"
|
||||||
#include "ibl_helpers.h"
|
#include "ibl_helpers.h"
|
||||||
|
#include "image.h"
|
||||||
|
#include "pipeline.h"
|
||||||
|
|
||||||
#include "pipeline_utils.h"
|
#include "pipeline_utils.h"
|
||||||
|
|
||||||
|
|
@ -38,11 +37,10 @@ main(int, char *[])
|
||||||
{
|
{
|
||||||
MIN_LOG_LEVEL(Logger::LogType::eInfo);
|
MIN_LOG_LEVEL(Logger::LogType::eInfo);
|
||||||
|
|
||||||
Window window = {"Scene Render [WIP] (Aster)", {INIT_WIDTH, INIT_HEIGHT}};
|
|
||||||
Context context = {"Scene Render [WIP]", VERSION};
|
Context context = {"Scene Render [WIP]", VERSION};
|
||||||
Surface surface = {&context, &window, "Primary Surface"};
|
Window window = {"Scene Render [WIP] (Aster)", &context, {INIT_WIDTH, INIT_HEIGHT}};
|
||||||
|
|
||||||
PhysicalDevices physicalDevices = {&surface, &context};
|
PhysicalDevices physicalDevices = {&window, &context};
|
||||||
PhysicalDevice deviceToUse = FindSuitableDevice(physicalDevices);
|
PhysicalDevice deviceToUse = FindSuitableDevice(physicalDevices);
|
||||||
|
|
||||||
vk::Extent2D internalResolution = {1920, 1080};
|
vk::Extent2D internalResolution = {1920, 1080};
|
||||||
|
|
@ -93,7 +91,7 @@ main(int, char *[])
|
||||||
Device device = {&context, &deviceToUse, &enabledDeviceFeatures,
|
Device device = {&context, &deviceToUse, &enabledDeviceFeatures,
|
||||||
{queueAllocation}, pipelineCacheData, "Primary Device"};
|
{queueAllocation}, pipelineCacheData, "Primary Device"};
|
||||||
vk::Queue graphicsQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
vk::Queue graphicsQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
||||||
Swapchain swapchain = {&surface, &device, window.GetSize(), "Primary Chain"};
|
Swapchain swapchain = {&window, &device, "Primary Chain"};
|
||||||
|
|
||||||
RenderResourceManager resourceManager = {&device, 1024};
|
RenderResourceManager resourceManager = {&device, 1024};
|
||||||
EcsRegistry registry;
|
EcsRegistry registry;
|
||||||
|
|
@ -114,7 +112,7 @@ main(int, char *[])
|
||||||
|
|
||||||
eastl::vector<Model> models;
|
eastl::vector<Model> models;
|
||||||
models.emplace_back(assetLoader.LoadModelToGpu(MODEL_FILE, "Main Model"));
|
models.emplace_back(assetLoader.LoadModelToGpu(MODEL_FILE, "Main Model"));
|
||||||
// registry.get<CDynamicTransform>(model.m_RootEntity).m_Position = vec3(2 * i, 0, 2 * j);
|
//registry.get<CDynamicTransform>(model.m_RootEntity).m_Position = vec3(2 * i, 0, 2 * j);
|
||||||
|
|
||||||
UniformBuffer ubo;
|
UniformBuffer ubo;
|
||||||
constexpr usize uboLightManagerOffset = sizeof cameraController.m_Camera;
|
constexpr usize uboLightManagerOffset = sizeof cameraController.m_Camera;
|
||||||
|
|
@ -350,15 +348,14 @@ main(int, char *[])
|
||||||
{
|
{
|
||||||
Time::Update();
|
Time::Update();
|
||||||
|
|
||||||
// u32 index = 0;
|
//u32 index = 0;
|
||||||
// for (auto [entity, dynTrans] : rootModel.each())
|
//for (auto [entity, dynTrans] : rootModel.each())
|
||||||
//{
|
//{
|
||||||
// dynTrans.m_Rotation =
|
// dynTrans.m_Rotation =
|
||||||
// glm::rotate(dynTrans.m_Rotation, Cast<f32>(30_deg * (++index) * Time::m_Delta), vec3{0.0f, 1.0f,
|
// glm::rotate(dynTrans.m_Rotation, Cast<f32>(30_deg * (++index) * Time::m_Delta), vec3{0.0f, 1.0f, 0.0f});
|
||||||
// 0.0f});
|
//}
|
||||||
// }
|
|
||||||
|
|
||||||
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &surface, window.GetSize());
|
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &window);
|
||||||
|
|
||||||
u32 imageIndex = currentFrame->m_ImageIdx;
|
u32 imageIndex = currentFrame->m_ImageIdx;
|
||||||
vk::Image currentSwapchainImage = swapchain.m_Images[imageIndex];
|
vk::Image currentSwapchainImage = swapchain.m_Images[imageIndex];
|
||||||
|
|
@ -555,7 +552,7 @@ main(int, char *[])
|
||||||
};
|
};
|
||||||
AbortIfFailed(graphicsQueue.submit(1, &submitInfo, currentFrame->m_FrameAvailableFence));
|
AbortIfFailed(graphicsQueue.submit(1, &submitInfo, currentFrame->m_FrameAvailableFence));
|
||||||
|
|
||||||
currentFrame->Present(graphicsQueue, &swapchain, &surface, window.GetSize());
|
currentFrame->Present(graphicsQueue, &swapchain, &window);
|
||||||
}
|
}
|
||||||
|
|
||||||
device.WaitIdle();
|
device.WaitIdle();
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,7 @@
|
||||||
|
|
||||||
#include "pipeline_utils.h"
|
#include "pipeline_utils.h"
|
||||||
|
|
||||||
#include "aster/core/device.h"
|
#include "device.h"
|
||||||
|
|
||||||
#include "render_resource_manager.h"
|
#include "render_resource_manager.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "aster/aster.h"
|
#include "global.h"
|
||||||
#include "aster/core/pipeline.h"
|
#include "pipeline.h"
|
||||||
|
|
||||||
struct RenderResourceManager;
|
struct RenderResourceManager;
|
||||||
struct Swapchain;
|
struct Swapchain;
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,10 @@
|
||||||
|
|
||||||
#include "render_resource_manager.h"
|
#include "render_resource_manager.h"
|
||||||
|
|
||||||
#include "aster/core/buffer.h"
|
#include "buffer.h"
|
||||||
#include "aster/core/device.h"
|
#include "device.h"
|
||||||
#include "aster/core/image.h"
|
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
#include "image.h"
|
||||||
|
|
||||||
#include <EASTL/array.h>
|
#include <EASTL/array.h>
|
||||||
|
|
||||||
|
|
@ -97,51 +96,49 @@ void
|
||||||
BufferManager::Init(const u32 maxCapacity)
|
BufferManager::Init(const u32 maxCapacity)
|
||||||
{
|
{
|
||||||
m_MaxCapacity = maxCapacity;
|
m_MaxCapacity = maxCapacity;
|
||||||
m_FreeHead = 0;
|
m_FreeHead = GpuResourceHandle::INVALID_HANDLE;
|
||||||
m_Buffers = new Buffer[maxCapacity];
|
|
||||||
|
|
||||||
// Chaining Freeheads
|
|
||||||
Buffer *pIter = m_Buffers;
|
|
||||||
for (u32 i = 1; i < m_MaxCapacity; ++i)
|
|
||||||
{
|
|
||||||
*Recast<u32 *>(pIter) = i;
|
|
||||||
++pIter;
|
|
||||||
}
|
|
||||||
*Recast<u32 *>(pIter) = GpuResourceHandle::INVALID_HANDLE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferHandle
|
BufferHandle
|
||||||
BufferManager::Allocate(const Device *device, const u32 bufferSize, const cstr name)
|
BufferManager::Commit(StorageBuffer *buffer)
|
||||||
{
|
|
||||||
StorageBuffer sb;
|
|
||||||
sb.Init(device, bufferSize, true, true, name);
|
|
||||||
return Commit_(&sb);
|
|
||||||
}
|
|
||||||
|
|
||||||
BufferHandle
|
|
||||||
BufferManager::Commit_(StorageBuffer *buffer)
|
|
||||||
{
|
{
|
||||||
ERROR_IF(!buffer || !buffer->IsValid() || !buffer->IsOwned(), "Buffer must be valid and owned for commital")
|
ERROR_IF(!buffer || !buffer->IsValid() || !buffer->IsOwned(), "Buffer must be valid and owned for commital")
|
||||||
THEN_ABORT(-1);
|
THEN_ABORT(-1);
|
||||||
|
|
||||||
ERROR_IF(m_FreeHead == GpuResourceHandle::INVALID_HANDLE, "Out of buffers")
|
if (m_FreeHead != GpuResourceHandle::INVALID_HANDLE)
|
||||||
THEN_ABORT(-1);
|
{
|
||||||
|
const u32 index = m_FreeHead;
|
||||||
|
|
||||||
const u32 index = m_FreeHead;
|
StorageBuffer *allocatedBuffer = &m_Buffers[index];
|
||||||
|
|
||||||
Buffer *allocatedBuffer = &m_Buffers[index];
|
assert(!allocatedBuffer->IsValid());
|
||||||
|
m_FreeHead = *Recast<u32 *>(allocatedBuffer);
|
||||||
|
|
||||||
assert(!allocatedBuffer->IsValid());
|
// Ensure it is copyable.
|
||||||
m_FreeHead = *Recast<u32 *>(allocatedBuffer);
|
static_assert(std::is_trivially_copyable_v<StorageBuffer>);
|
||||||
|
*allocatedBuffer = *buffer;
|
||||||
|
|
||||||
// Ensure it is copyable.
|
// Take ownership of the buffer.
|
||||||
static_assert(std::is_trivially_copyable_v<StorageBuffer>);
|
buffer->m_Size_ &= ~StorageBuffer::OWNED_BIT;
|
||||||
*allocatedBuffer = *buffer;
|
|
||||||
|
|
||||||
// Take ownership of the buffer.
|
return {index};
|
||||||
buffer->m_Size_ &= ~StorageBuffer::OWNED_BIT;
|
}
|
||||||
|
|
||||||
return {index};
|
const u32 index = Cast<u32>(m_Buffers.size());
|
||||||
|
if (index < m_MaxCapacity)
|
||||||
|
{
|
||||||
|
StorageBuffer *allocatedBuffer = &m_Buffers.push_back();
|
||||||
|
|
||||||
|
// Ensure it is copyable.
|
||||||
|
static_assert(std::is_trivially_copyable_v<StorageBuffer>);
|
||||||
|
*allocatedBuffer = *buffer;
|
||||||
|
|
||||||
|
buffer->m_Size_ &= ~StorageBuffer::OWNED_BIT;
|
||||||
|
|
||||||
|
return {index};
|
||||||
|
}
|
||||||
|
|
||||||
|
ERROR("Out of Buffers") THEN_ABORT(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
StorageBuffer *
|
StorageBuffer *
|
||||||
|
|
@ -149,7 +146,7 @@ BufferManager::Fetch(const BufferHandle handle)
|
||||||
{
|
{
|
||||||
assert(!handle.IsInvalid());
|
assert(!handle.IsInvalid());
|
||||||
|
|
||||||
return Recast<StorageBuffer *>(&m_Buffers[handle.m_Index]);
|
return &m_Buffers[handle.m_Index];
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -157,7 +154,7 @@ BufferManager::Release(const Device *device, const BufferHandle handle)
|
||||||
{
|
{
|
||||||
assert(!handle.IsInvalid());
|
assert(!handle.IsInvalid());
|
||||||
|
|
||||||
Buffer *allocatedBuffer = &m_Buffers[handle.m_Index];
|
StorageBuffer *allocatedBuffer = &m_Buffers[handle.m_Index];
|
||||||
allocatedBuffer->Destroy(device);
|
allocatedBuffer->Destroy(device);
|
||||||
|
|
||||||
assert(!allocatedBuffer->IsValid());
|
assert(!allocatedBuffer->IsValid());
|
||||||
|
|
@ -169,19 +166,10 @@ BufferManager::Release(const Device *device, const BufferHandle handle)
|
||||||
void
|
void
|
||||||
BufferManager::Destroy(const Device *device)
|
BufferManager::Destroy(const Device *device)
|
||||||
{
|
{
|
||||||
if (!m_Buffers)
|
for (auto &buffer : m_Buffers)
|
||||||
{
|
{
|
||||||
WARN("Double Deletion");
|
buffer.Destroy(device);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer *pBegin = m_Buffers;
|
|
||||||
const Buffer *pEnd = m_Buffers + m_MaxCapacity;
|
|
||||||
while (pBegin != pEnd)
|
|
||||||
{
|
|
||||||
(pBegin++)->Destroy(device);
|
|
||||||
}
|
|
||||||
delete[] Take(m_Buffers);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StorageTextureHandle
|
StorageTextureHandle
|
||||||
|
|
@ -315,7 +303,7 @@ VirtualizedBufferPool::InitIndex(const Device *device, usize bufferMaxSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
VirtualizedBufferPool::UpdateToGpu(const Device *)
|
VirtualizedBufferPool::UpdateToGpu(const Device *device)
|
||||||
{
|
{
|
||||||
// Unrequired until adding the non-ReBAR support.
|
// Unrequired until adding the non-ReBAR support.
|
||||||
}
|
}
|
||||||
|
|
@ -417,39 +405,9 @@ RenderResourceManager::WriteInfo::WriteInfo(vk::BufferView info)
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferHandle
|
BufferHandle
|
||||||
RenderResourceManager::Commit_(StorageBuffer *storageBuffer)
|
RenderResourceManager::Commit(StorageBuffer *storageBuffer)
|
||||||
{
|
{
|
||||||
const BufferHandle handle = m_BufferManager.Commit_(storageBuffer);
|
const BufferHandle handle = m_BufferManager.Commit(storageBuffer);
|
||||||
|
|
||||||
m_WriteInfos.emplace_back(vk::DescriptorBufferInfo{
|
|
||||||
.buffer = storageBuffer->m_Buffer,
|
|
||||||
.offset = 0,
|
|
||||||
.range = storageBuffer->GetSize(),
|
|
||||||
});
|
|
||||||
|
|
||||||
m_Writes.push_back({
|
|
||||||
.dstSet = m_DescriptorSet,
|
|
||||||
.dstBinding = BUFFER_BINDING_INDEX,
|
|
||||||
.dstArrayElement = handle.m_Index,
|
|
||||||
.descriptorCount = 1,
|
|
||||||
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
|
||||||
.pBufferInfo = &m_WriteInfos.back().uBufferInfo,
|
|
||||||
});
|
|
||||||
|
|
||||||
m_WriteOwner.emplace_back(HandleType::eBuffer, handle.m_Index);
|
|
||||||
|
|
||||||
#if !defined(ASTER_NDEBUG)
|
|
||||||
++m_CommitedBufferCount;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
BufferHandle
|
|
||||||
RenderResourceManager::CreateStorageBuffer(const u32 bufferSize, const cstr name)
|
|
||||||
{
|
|
||||||
auto handle = m_BufferManager.Allocate(m_Device, bufferSize, name);
|
|
||||||
const auto storageBuffer = m_BufferManager.Fetch(handle);
|
|
||||||
|
|
||||||
m_WriteInfos.emplace_back(vk::DescriptorBufferInfo{
|
m_WriteInfos.emplace_back(vk::DescriptorBufferInfo{
|
||||||
.buffer = storageBuffer->m_Buffer,
|
.buffer = storageBuffer->m_Buffer,
|
||||||
|
|
@ -790,7 +748,7 @@ RenderResourceManager::RenderResourceManager(Device *device, u16 maxSize, bool u
|
||||||
m_Device->SetName(m_DescriptorSet, "Bindless Set");
|
m_Device->SetName(m_DescriptorSet, "Bindless Set");
|
||||||
|
|
||||||
// NOTE: This needs to be synced with the destructor manually.
|
// NOTE: This needs to be synced with the destructor manually.
|
||||||
assert(Commit_(m_Geometry.m_BackingBuffer.get()).m_Index == UNIFIED_GEOMETRY_DATA_HANDLE_INDEX); // Making an assumption to avoid extra bindings.
|
assert(Commit(m_Geometry.m_BackingBuffer.get()).m_Index == UNIFIED_GEOMETRY_DATA_HANDLE_INDEX); // Making an assumption to avoid extra bindings.
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderResourceManager::~RenderResourceManager()
|
RenderResourceManager::~RenderResourceManager()
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "aster/aster.h"
|
#include "global.h"
|
||||||
|
|
||||||
#include <EASTL/deque.h>
|
#include <EASTL/deque.h>
|
||||||
#include <EASTL/vector_map.h>
|
#include <EASTL/vector_map.h>
|
||||||
|
|
@ -75,13 +75,12 @@ struct TextureManager
|
||||||
|
|
||||||
struct BufferManager
|
struct BufferManager
|
||||||
{
|
{
|
||||||
Buffer* m_Buffers;
|
eastl::vector<StorageBuffer> m_Buffers;
|
||||||
u32 m_MaxCapacity;
|
u32 m_MaxCapacity;
|
||||||
u32 m_FreeHead;
|
u32 m_FreeHead;
|
||||||
|
|
||||||
void Init(u32 maxCapacity);
|
void Init(u32 maxCapacity);
|
||||||
BufferHandle Allocate(const Device *device, u32 bufferSize, cstr name);
|
BufferHandle Commit(StorageBuffer *buffer);
|
||||||
BufferHandle Commit_(StorageBuffer *buffer);
|
|
||||||
StorageBuffer *Fetch(BufferHandle handle);
|
StorageBuffer *Fetch(BufferHandle handle);
|
||||||
void Release(const Device *device, BufferHandle handle);
|
void Release(const Device *device, BufferHandle handle);
|
||||||
void Destroy(const Device *device);
|
void Destroy(const Device *device);
|
||||||
|
|
@ -179,7 +178,6 @@ struct RenderResourceManager
|
||||||
SamplerManager m_SamplerManager;
|
SamplerManager m_SamplerManager;
|
||||||
|
|
||||||
void EraseWrites(u32 handleIndex, HandleType handleType);
|
void EraseWrites(u32 handleIndex, HandleType handleType);
|
||||||
BufferHandle Commit_(StorageBuffer *storageBuffer); // Commit to GPU and take Ownership
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Device *m_Device;
|
Device *m_Device;
|
||||||
|
|
@ -200,7 +198,7 @@ struct RenderResourceManager
|
||||||
|
|
||||||
bool m_UseBufferAddr;
|
bool m_UseBufferAddr;
|
||||||
|
|
||||||
BufferHandle CreateStorageBuffer(u32 bufferSize, cstr name); // Allocate a new buffer and commit to GPU.
|
BufferHandle Commit(StorageBuffer *storageBuffer); // Commit to GPU and take Ownership
|
||||||
void Write(BufferHandle handle, usize offset, usize size, const void *data); // Write to buffer
|
void Write(BufferHandle handle, usize offset, usize size, const void *data); // Write to buffer
|
||||||
void Release(BufferHandle handle); // Release and Destroy
|
void Release(BufferHandle handle); // Release and Destroy
|
||||||
void Release(StorageBuffer *storageBuffer, BufferHandle handle); // Release and Return
|
void Release(StorageBuffer *storageBuffer, BufferHandle handle); // Release and Return
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue