Compare commits

..

1 Commits

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

1
.envrc
View File

@ -1 +0,0 @@
use flake

5
.gitignore vendored
View File

@ -1,7 +1,4 @@
.idea/ .idea/
.cache/ .cache/
build/ build/
.vs/ .vs/
.direnv/
.ccls-cache/
*.user

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

38
aster/context.h Normal file
View File

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

View File

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

View File

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

29
aster/global.cpp Normal file
View File

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

View File

@ -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>
@ -25,9 +25,7 @@
#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>
{ {

View File

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

View File

@ -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);
@ -122,16 +116,4 @@ inline u32
Image::GetMipLevels() const 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);
}

View File

@ -1,5 +0,0 @@
# CMakeList.txt ; CMake project for Aster Util Headers
cmake_minimum_required(VERSION 3.13)
add_subdirectory("aster")

View File

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

View File

@ -1,8 +0,0 @@
// =============================================
// Aster: aster.h
// Copyright (c) 2020-2024 Anish Bhobe
// =============================================
#pragma once
#include "core/global.h"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +0,0 @@
# CMakeList.txt ; CMake project for Aster Util Headers
cmake_minimum_required(VERSION 3.13)
add_subdirectory("aster")

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +0,0 @@
// =============================================
// Aster: manager.cpp
// Copyright (c) 2020-2025 Anish Bhobe
// =============================================
#include "systems/manager.h"

View File

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

View File

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

33
aster/surface.cpp Normal file
View File

@ -0,0 +1,33 @@
// =============================================
// Aster: surface.cpp
// Copyright (c) 2020-2024 Anish Bhobe
// =============================================
#include "surface.h"
#include "context.h"
#include "window.h"
void
Surface::Init(Context *context, const Window *window)
{
assert(!m_Surface);
VkSurfaceKHR surface;
auto result = Cast<vk::Result>(
glfwCreateWindowSurface(Cast<VkInstance>(context->m_Instance), window->m_Window, nullptr, &surface));
ERROR_IF(Failed(result), "Failed to create Surface with {}", result)
THEN_ABORT(result)
ELSE_DEBUG("Surface Created");
m_Surface = vk::SurfaceKHR(surface);
}
void
Surface::Destroy(const Context *context)
{
if (!m_Surface)
return;
context->m_Instance.destroy(Take(m_Surface), nullptr);
DEBUG("Surface Destroyed");
}

19
aster/surface.h Normal file
View File

@ -0,0 +1,19 @@
// =============================================
// Aster: surface.h
// Copyright (c) 2020-2024 Anish Bhobe
// =============================================
#pragma once
#include "global.h"
struct Context;
struct Window;
struct Surface
{
vk::SurfaceKHR m_Surface;
void Init(Context *context, const Window *window);
void Destroy(const Context *context);
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1 +0,0 @@
build/compile_commands.json

View File

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

View File

@ -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
View File

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

View File

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

View File

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

View File

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

View File

@ -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
@ -213,4 +213,4 @@ PopDisable()
PopStyleVar(); PopStyleVar();
PopItemFlag(); PopItemFlag();
} }
} // namespace ImGui } // namespace ImGui

View File

@ -5,7 +5,7 @@
#pragma once #pragma once
#include "aster/aster.h" #include "global.h"
#include <imgui.h> #include <imgui.h>

View File

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

View File

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

View File

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

View File

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

View File

@ -4,13 +4,11 @@ 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)
add_resource_dir(box image) add_resource_dir(box image)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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({
@ -1080,4 +1080,4 @@ AssetLoader::operator=(AssetLoader &&other) noexcept
m_TransferQueueIndex = other.m_TransferQueueIndex; m_TransferQueueIndex = other.m_TransferQueueIndex;
m_GraphicsQueueIndex = other.m_GraphicsQueueIndex; m_GraphicsQueueIndex = other.m_GraphicsQueueIndex;
return *this; return *this;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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