Compare commits
19 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
3a7bea902f | |
|
|
88d8a2acc2 | |
|
|
9ca5751a78 | |
|
|
15df13730d | |
|
|
dfdbd52087 | |
|
|
300fa7449c | |
|
|
058a6512ea | |
|
|
8d2c04ea19 | |
|
|
7d906e08f8 | |
|
|
ad6ee9a0e5 | |
|
|
12ab256a30 | |
|
|
ec1fc0570d | |
|
|
86326a4fa1 | |
|
|
0f868ef74e | |
|
|
564f6cc205 | |
|
|
466e4a4093 | |
|
|
91010a448e | |
|
|
0462dc33f0 | |
|
|
a3dcf22fa5 |
|
|
@ -1,4 +1,7 @@
|
|||
.idea/
|
||||
.cache/
|
||||
build/
|
||||
.vs/
|
||||
.vs/
|
||||
.direnv/
|
||||
.ccls-cache/
|
||||
*.user
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ set(CMAKE_CXX_EXTENSIONS OFF)
|
|||
|
||||
if (MSVC)
|
||||
set(CMAKE_CXX_FLAGS "/W4 /GR- ${MSVC_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "/O3")
|
||||
add_compile_definitions(_HAS_EXCEPTIONS=0)
|
||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
||||
add_compile_definitions(${MSVC_DEFINES})
|
||||
|
|
@ -21,5 +22,4 @@ include(add_shader.cmake)
|
|||
include(add_resource_dir.cmake)
|
||||
|
||||
add_subdirectory("aster")
|
||||
add_subdirectory("scratch")
|
||||
# add_subdirectory("samples")
|
||||
add_subdirectory("samples")
|
||||
|
|
|
|||
|
|
@ -18,6 +18,22 @@
|
|||
"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",
|
||||
"generator": "Ninja",
|
||||
|
|
|
|||
|
|
@ -10,42 +10,15 @@ find_package(fmt CONFIG REQUIRED)
|
|||
find_package(VulkanMemoryAllocator CONFIG REQUIRED)
|
||||
find_package(EASTL CONFIG REQUIRED)
|
||||
|
||||
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_library(aster_core STATIC)
|
||||
|
||||
set(SOURCE_FILES
|
||||
logger.cpp
|
||||
global.cpp
|
||||
context.cpp
|
||||
window.cpp
|
||||
physical_device.cpp
|
||||
device.cpp
|
||||
swapchain.cpp
|
||||
pipeline.cpp
|
||||
buffer.cpp
|
||||
image.cpp
|
||||
surface.cpp)
|
||||
add_subdirectory("include")
|
||||
add_subdirectory("src")
|
||||
|
||||
add_library(aster_core STATIC ${SOURCE_FILES} ${HEADER_FILES})
|
||||
set_property(TARGET aster_core PROPERTY CXX_STANDARD 20)
|
||||
|
||||
target_precompile_headers(aster_core PUBLIC global.h)
|
||||
|
||||
target_include_directories(aster_core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_include_directories(aster_core PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include/aster")
|
||||
target_include_directories(aster_core PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
|
||||
target_link_libraries(aster_core PUBLIC glm::glm-header-only)
|
||||
target_link_libraries(aster_core PRIVATE glfw)
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
// =============================================
|
||||
// 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>);
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
// =============================================
|
||||
// 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];
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
# CMakeList.txt ; CMake project for Aster Util Headers
|
||||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
add_subdirectory("aster")
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
# 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")
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
// =============================================
|
||||
// Aster: aster.h
|
||||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/global.h"
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# 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")
|
||||
|
|
@ -24,6 +24,8 @@ struct Buffer
|
|||
[[nodiscard]] bool IsValid() const;
|
||||
[[nodiscard]] bool IsMapped() const;
|
||||
[[nodiscard]] bool IsOwned() const;
|
||||
[[nodiscard]] bool IsCommitted() const;
|
||||
void SetCommitted(bool committed);
|
||||
|
||||
void Destroy(const Device *device);
|
||||
void Write(const Device *device, usize offset, usize size, const void *data);
|
||||
|
|
@ -32,7 +34,7 @@ struct Buffer
|
|||
VmaAllocationCreateFlags allocationFlags, VmaMemoryUsage memoryUsage, cstr name);
|
||||
|
||||
uptr
|
||||
GetDeviceAddress(const Device *device) const;
|
||||
GetDeviceAddress(const Device *device);
|
||||
|
||||
// Buffer.size is used for bookkeeping
|
||||
// If the buffer is Invalid, the remaining data in Buffer is used intrusively by `GpuResourceManager`.
|
||||
|
|
@ -40,9 +42,13 @@ struct Buffer
|
|||
|
||||
constexpr static usize VALID_BUFFER_BIT = Cast<usize>(1llu << 63);
|
||||
constexpr static usize OWNED_BIT = 1llu << 62;
|
||||
constexpr static usize SIZE_MASK = ~(VALID_BUFFER_BIT | OWNED_BIT);
|
||||
constexpr static usize COMMITTED_BIT = 1llu << 61;
|
||||
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.
|
||||
static_assert(offsetof(Buffer, m_Size_) > sizeof(usize));
|
||||
|
||||
|
|
@ -113,3 +119,15 @@ Buffer::IsOwned() const
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// =============================================
|
||||
// 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);
|
||||
};
|
||||
|
|
@ -24,6 +24,7 @@ struct Features
|
|||
|
||||
struct Device final
|
||||
{
|
||||
NameString m_Name;
|
||||
vk::PhysicalDevice m_PhysicalDevice = nullptr;
|
||||
vk::Device m_Device = nullptr;
|
||||
VmaAllocator m_Allocator = nullptr;
|
||||
|
|
@ -39,11 +40,17 @@ struct Device final
|
|||
void WaitIdle() const;
|
||||
|
||||
// Ctor/Dtor
|
||||
void Init(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures,
|
||||
const eastl::vector<QueueAllocation> &queueAllocations, cstr name);
|
||||
void Init(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures,
|
||||
const eastl::vector<QueueAllocation> &queueAllocations, const eastl::span<u8> &pipelineCacheData, cstr name);
|
||||
void Destroy();
|
||||
Device(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures,
|
||||
const eastl::vector<QueueAllocation> &queueAllocations, NameString &&name);
|
||||
Device(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures,
|
||||
const eastl::vector<QueueAllocation> &queueAllocations, eastl::span<u8> &&pipelineCacheData, NameString &&name);
|
||||
~Device();
|
||||
|
||||
// Move
|
||||
Device(Device &&other) noexcept;
|
||||
Device &operator=(Device &&other) noexcept;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Device);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#include "config.h"
|
||||
#include "constants.h"
|
||||
#include "logger.h"
|
||||
#include "util/logger.h"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
|
@ -25,7 +25,9 @@
|
|||
|
||||
#if !defined(NDEBUG)
|
||||
#define VULKAN_HPP_ASSERT(expr) DEBUG_IF(!(expr), "Vulkan assert failed")
|
||||
#endif
|
||||
#endif
|
||||
#include "type_traits.h"
|
||||
|
||||
#include <EASTL/fixed_string.h>
|
||||
#include <EASTL/string.h>
|
||||
#include <vk_mem_alloc.h>
|
||||
|
|
@ -40,6 +42,12 @@ constexpr u32 ASTER_API_VERSION = VK_API_VERSION_1_3;
|
|||
CLASS_NAME(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 TODO(MSG) assert(false && ("Unimplemented: " MSG))
|
||||
|
|
@ -169,6 +177,18 @@ ClosestPowerOfTwo(const u32 val)
|
|||
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 <>
|
||||
struct fmt::formatter<vk::Result> : nested_formatter<std::string>
|
||||
{
|
||||
|
|
@ -49,13 +49,19 @@ struct Image
|
|||
[[nodiscard]] bool IsValid() const;
|
||||
[[nodiscard]] bool IsOwned() const;
|
||||
[[nodiscard]] u32 GetMipLevels() const;
|
||||
[[nodiscard]] bool IsCommitted() const;
|
||||
void SetCommitted(bool committed);
|
||||
|
||||
void Destroy(const Device *device);
|
||||
|
||||
constexpr static u8 VALID_BIT = 1u << 7;
|
||||
constexpr static u8 OWNED_BIT = 1u << 6;
|
||||
constexpr static u8 COMMITTED_BIT = 1u << 5;
|
||||
};
|
||||
|
||||
template <>
|
||||
constexpr bool concepts::GpuResource<Image> = true;
|
||||
|
||||
struct Texture : Image
|
||||
{
|
||||
void Init(const Device *device, vk::Extent2D extent, vk::Format imageFormat, bool isMipMapped, cstr name = nullptr);
|
||||
|
|
@ -116,4 +122,16 @@ inline u32
|
|||
Image::GetMipLevels() const
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
|
@ -6,10 +6,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "global.h"
|
||||
#include "surface.h"
|
||||
|
||||
#include <EASTL/fixed_vector.h>
|
||||
|
||||
struct QueueAllocation;
|
||||
struct Surface;
|
||||
struct Window;
|
||||
struct Context;
|
||||
|
||||
|
|
@ -49,22 +49,10 @@ struct PhysicalDevice final
|
|||
eastl::vector<QueueFamilyInfo> m_QueueFamilies;
|
||||
|
||||
PhysicalDevice(vk::SurfaceKHR surface, vk::PhysicalDevice physicalDevice);
|
||||
QueueAllocation FindAppropriateQueueAllocation();
|
||||
};
|
||||
|
||||
class PhysicalDevices : public eastl::vector<PhysicalDevice>
|
||||
class PhysicalDevices : public eastl::fixed_vector<PhysicalDevice, 4>
|
||||
{
|
||||
public:
|
||||
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);
|
||||
};
|
||||
|
|
@ -7,19 +7,14 @@
|
|||
|
||||
#include "global.h"
|
||||
|
||||
struct Size
|
||||
struct Size2D
|
||||
{
|
||||
u32 m_Width;
|
||||
u32 m_Height;
|
||||
|
||||
explicit
|
||||
operator vk::Extent2D() const
|
||||
{
|
||||
return {m_Width, m_Height};
|
||||
}
|
||||
|
||||
glm::vec<2, u32>
|
||||
ToVec()
|
||||
{
|
||||
return {m_Width, m_Height};
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// =============================================
|
||||
// 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);
|
||||
};
|
||||
|
|
@ -11,16 +11,17 @@
|
|||
|
||||
#include <EASTL/fixed_vector.h>
|
||||
|
||||
struct Surface;
|
||||
struct PhysicalDevice;
|
||||
struct Window;
|
||||
struct Surface;
|
||||
struct Device;
|
||||
|
||||
struct Swapchain final
|
||||
{
|
||||
using FnResizeCallback = eastl::function<void(vk::Extent2D)>;
|
||||
|
||||
const Device *m_Device;
|
||||
vk::SwapchainKHR m_Swapchain;
|
||||
NameString m_Name;
|
||||
vk::Extent2D m_Extent;
|
||||
vk::Format m_Format;
|
||||
eastl::fixed_vector<vk::Image, 4> m_Images;
|
||||
|
|
@ -28,10 +29,19 @@ struct Swapchain final
|
|||
|
||||
eastl::vector<FnResizeCallback> m_ResizeCallbacks;
|
||||
|
||||
void Create(const Surface *surface, const Device *device, Size size, cstr name);
|
||||
void Create(const Surface *window, Size2D size);
|
||||
void RegisterResizeCallback(FnResizeCallback &&callback);
|
||||
|
||||
// Ctor/Dtor
|
||||
void Init(const Surface *surface, const Device *device, Size size, cstr name);
|
||||
void Destroy(const Device *device);
|
||||
Swapchain(const Surface *window, const Device *device, Size2D size, NameString &&name);
|
||||
~Swapchain();
|
||||
|
||||
// Move
|
||||
Swapchain(Swapchain &&other) noexcept;
|
||||
Swapchain &operator=(Swapchain &&other) noexcept;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Swapchain);
|
||||
|
||||
private:
|
||||
void Cleanup();
|
||||
};
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// =============================================
|
||||
// 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
|
||||
|
|
@ -7,11 +7,19 @@
|
|||
|
||||
#include "global.h"
|
||||
|
||||
struct Context;
|
||||
#include "size.h"
|
||||
|
||||
#include <EASTL/fixed_string.h>
|
||||
#include <atomic>
|
||||
|
||||
struct Window final
|
||||
{
|
||||
// fields
|
||||
GLFWwindow *m_Window = nullptr;
|
||||
NameString m_Name;
|
||||
|
||||
static std::atomic_uint64_t m_WindowCount;
|
||||
static std::atomic_bool m_IsGlfwInit;
|
||||
|
||||
// Methods
|
||||
[[nodiscard]] bool
|
||||
|
|
@ -25,9 +33,15 @@ struct Window final
|
|||
void SetWindowSize(const vk::Extent2D &extent) const noexcept;
|
||||
void SetWindowSize(u32 width, u32 height) const noexcept;
|
||||
/// Actual size of the framebuffer being used for the window render.
|
||||
[[nodiscard]] vk::Extent2D GetSize() const;
|
||||
[[nodiscard]] Size2D GetSize() const;
|
||||
|
||||
// Ctor/Dtor
|
||||
void Init(cstr title, vk::Extent2D extent, b8 isFullScreen = false);
|
||||
void Destroy();
|
||||
Window(cstr title, Size2D extent, b8 isFullScreen = false);
|
||||
~Window();
|
||||
|
||||
// Move
|
||||
Window(Window &&other) noexcept;
|
||||
Window &operator=(Window &&other) noexcept;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Window);
|
||||
};
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
# 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")
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
// =============================================
|
||||
// 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
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
// =============================================
|
||||
// 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
|
||||
|
|
@ -0,0 +1,361 @@
|
|||
// =============================================
|
||||
// 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());
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
// =============================================
|
||||
// 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
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
# CMakeList.txt ; CMake project for Aster Util Headers
|
||||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
target_sources(aster_core
|
||||
INTERFACE "logger.h")
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "constants.h"
|
||||
#include "aster/core/constants.h"
|
||||
#include <debugbreak.h>
|
||||
#include <fmt/core.h>
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
# CMakeList.txt ; CMake project for Aster Util Headers
|
||||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
add_subdirectory("aster")
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
# CMakeList.txt ; CMake project for Aster Util Headers
|
||||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
add_subdirectory("core")
|
||||
add_subdirectory("systems")
|
||||
add_subdirectory("util")
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
# 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")
|
||||
|
|
@ -3,9 +3,9 @@
|
|||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "buffer.h"
|
||||
#include "core/buffer.h"
|
||||
|
||||
#include "device.h"
|
||||
#include "core/device.h"
|
||||
|
||||
void
|
||||
Buffer::Destroy(const Device *device)
|
||||
|
|
@ -44,18 +44,19 @@ Buffer::Allocate(const Device *device, usize size, vk::BufferUsageFlags bufferUs
|
|||
vk::MemoryPropertyFlags memoryPropertyFlags;
|
||||
vmaGetAllocationMemoryProperties(device->m_Allocator, allocation,
|
||||
Recast<VkMemoryPropertyFlags *>(&memoryPropertyFlags));
|
||||
bool hostAccessible = Cast<bool>(memoryPropertyFlags & vk::MemoryPropertyFlagBits::eHostVisible);
|
||||
// TODO: Actually track Host Access
|
||||
// bool hostAccessible = Cast<bool>(memoryPropertyFlags & vk::MemoryPropertyFlagBits::eHostVisible);
|
||||
|
||||
m_Buffer = buffer;
|
||||
m_Size_ = size | VALID_BUFFER_BIT | OWNED_BIT;
|
||||
m_Allocation = allocation;
|
||||
m_Mapped = hostAccessible ? Cast<u8 *>(allocationInfo.pMappedData) : nullptr;
|
||||
m_Mapped = Cast<u8 *>(allocationInfo.pMappedData);
|
||||
|
||||
device->SetName(m_Buffer, name);
|
||||
}
|
||||
|
||||
uptr
|
||||
Buffer::GetDeviceAddress(const Device *device) const
|
||||
Buffer::GetDeviceAddress(const Device *device)
|
||||
{
|
||||
vk::BufferDeviceAddressInfo addressInfo = {.buffer = m_Buffer};
|
||||
return device->m_Device.getBufferAddress(&addressInfo);
|
||||
|
|
@ -3,14 +3,11 @@
|
|||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "context.h"
|
||||
#include "core/context.h"
|
||||
|
||||
#include <EASTL/array.h>
|
||||
#include <EASTL/fixed_vector.h>
|
||||
|
||||
constexpr eastl::array VALIDATION_LAYERS = {
|
||||
"VK_LAYER_KHRONOS_validation",
|
||||
};
|
||||
|
||||
VKAPI_ATTR b32 VKAPI_CALL
|
||||
DebugCallback(const VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||
const VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
|
|
@ -38,8 +35,7 @@ DebugCallback(const VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
|||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
Context::Init(const cstr appName, const Version version, bool enableValidation)
|
||||
Context::Context(const cstr appName, const Version version, bool enableValidation)
|
||||
{
|
||||
INFO_IF(enableValidation, "Validation Layers enabled");
|
||||
|
||||
|
|
@ -81,8 +77,6 @@ Context::Init(const cstr appName, const Version version, bool enableValidation)
|
|||
const auto instanceCreateInfo = vk::InstanceCreateInfo{
|
||||
.pNext = enableValidation ? &debugUtilsMessengerCreateInfo : nullptr,
|
||||
.pApplicationInfo = &appInfo,
|
||||
.enabledLayerCount = enableValidation ? Cast<u32>(VALIDATION_LAYERS.size()) : 0,
|
||||
.ppEnabledLayerNames = enableValidation ? VALIDATION_LAYERS.data() : nullptr,
|
||||
.enabledExtensionCount = Cast<u32>(instanceExtensions.size()),
|
||||
.ppEnabledExtensionNames = instanceExtensions.data(),
|
||||
};
|
||||
|
|
@ -103,12 +97,8 @@ Context::Init(const cstr appName, const Version version, bool enableValidation)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
Context::Destroy()
|
||||
Context::~Context()
|
||||
{
|
||||
if (!m_Instance)
|
||||
return;
|
||||
|
||||
if (m_DebugMessenger)
|
||||
{
|
||||
m_Instance.destroy(m_DebugMessenger, nullptr);
|
||||
|
|
@ -116,13 +106,20 @@ Context::Destroy()
|
|||
}
|
||||
m_Instance.destroy(nullptr);
|
||||
DEBUG("Instance destroyed");
|
||||
|
||||
m_DebugMessenger = nullptr;
|
||||
m_Instance = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
Context::IsInDebugMode() const
|
||||
Context::Context(Context &&other) noexcept
|
||||
: m_Instance(Take(other.m_Instance))
|
||||
, 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;
|
||||
}
|
||||
|
|
@ -3,11 +3,11 @@
|
|||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "device.h"
|
||||
#include "core/device.h"
|
||||
|
||||
#include "context.h"
|
||||
#include "physical_device.h"
|
||||
#include "queue_allocation.h"
|
||||
#include "core/context.h"
|
||||
#include "core/physical_device.h"
|
||||
#include "core/queue_allocation.h"
|
||||
|
||||
#include <EASTL/array.h>
|
||||
#include <EASTL/fixed_vector.h>
|
||||
|
|
@ -17,22 +17,19 @@ constexpr eastl::array DEVICE_EXTENSIONS = {
|
|||
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
|
||||
};
|
||||
|
||||
void
|
||||
Device::Init(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures,
|
||||
const eastl::vector<QueueAllocation> &queueAllocations, cstr name)
|
||||
Device::Device(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures,
|
||||
const eastl::vector<QueueAllocation> &queueAllocations, NameString &&name)
|
||||
: Device(context, physicalDevice, enabledFeatures, queueAllocations, {}, std::move(name))
|
||||
{
|
||||
this->Init(context, physicalDevice, enabledFeatures, queueAllocations, {}, name);
|
||||
}
|
||||
|
||||
void
|
||||
Device::Init(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures,
|
||||
const eastl::vector<QueueAllocation> &queueAllocations, const eastl::span<u8> &pipelineCacheData,
|
||||
cstr name)
|
||||
Device::Device(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures,
|
||||
const eastl::vector<QueueAllocation> &queueAllocations, eastl::span<u8> &&pipelineCacheData,
|
||||
NameString &&name)
|
||||
: m_Name(std::move(name))
|
||||
, m_PhysicalDevice(physicalDevice->m_PhysicalDevice)
|
||||
, m_ValidationEnabled(context->m_DebugMessenger != nullptr)
|
||||
{
|
||||
assert(!m_Device);
|
||||
|
||||
m_PhysicalDevice = physicalDevice->m_PhysicalDevice;
|
||||
m_ValidationEnabled = context->IsInDebugMode();
|
||||
// Shouldn't have more than 4 deviceQueueFamilies in use anyway. Else we can heap
|
||||
eastl::fixed_vector<vk::DeviceQueueCreateInfo, 4> deviceQueueCreateInfos;
|
||||
deviceQueueCreateInfos.reserve(queueAllocations.size());
|
||||
|
|
@ -74,9 +71,9 @@ Device::Init(const Context *context, PhysicalDevice *physicalDevice, Features *e
|
|||
vk::Result result = m_PhysicalDevice.createDevice(&deviceCreateInfo, nullptr, &m_Device);
|
||||
ERROR_IF(Failed(result), "Could not initialize Vulkan Device. Cause: {}", result)
|
||||
THEN_ABORT(result)
|
||||
ELSE_DEBUG("{} ({}) Initialized.", name, physicalDevice->m_DeviceProperties.deviceName.data());
|
||||
ELSE_DEBUG("{} ({}) Initialized.", m_Name, physicalDevice->m_DeviceProperties.deviceName.data());
|
||||
|
||||
SetName(m_Device, name);
|
||||
SetName(m_Device, m_Name.data());
|
||||
|
||||
VmaVulkanFunctions vmaVulkanFunctions = {
|
||||
.vkGetInstanceProcAddr = vk::defaultDispatchLoaderDynamic.vkGetInstanceProcAddr,
|
||||
|
|
@ -108,15 +105,11 @@ Device::Init(const Context *context, PhysicalDevice *physicalDevice, Features *e
|
|||
THEN_ABORT(result)
|
||||
ELSE_VERBOSE("Pipeline Cache created.");
|
||||
|
||||
DEBUG("Created Device '{}' Successfully", name);
|
||||
DEBUG("Created Device '{}' Successfully", m_Name);
|
||||
}
|
||||
|
||||
void
|
||||
Device::Destroy()
|
||||
Device::~Device()
|
||||
{
|
||||
if (!m_Device)
|
||||
return;
|
||||
|
||||
m_Device.destroy(m_PipelineCache, nullptr);
|
||||
if (m_Allocator)
|
||||
{
|
||||
|
|
@ -125,11 +118,8 @@ Device::Destroy()
|
|||
DEBUG("Memory Allocator Destroyed");
|
||||
}
|
||||
m_Device.destroy(nullptr);
|
||||
DEBUG("Device Destroyed");
|
||||
|
||||
m_Allocator = nullptr;
|
||||
DEBUG("Device '{}' Destroyed", m_Name);
|
||||
m_PhysicalDevice = nullptr;
|
||||
m_Device = nullptr;
|
||||
}
|
||||
|
||||
vk::Queue
|
||||
|
|
@ -160,3 +150,23 @@ Device::WaitIdle() const
|
|||
ERROR_IF(Failed(deviceIdleResult), "Device Idling Failed. Cause: {}", deviceIdleResult)
|
||||
THEN_ABORT(deviceIdleResult);
|
||||
}
|
||||
|
||||
Device::Device(Device &&other) noexcept
|
||||
: m_Name(std::move(other.m_Name))
|
||||
, m_PhysicalDevice(Take(other.m_PhysicalDevice))
|
||||
, m_Device(Take(other.m_Device))
|
||||
, m_Allocator(Take(other.m_Allocator))
|
||||
{
|
||||
}
|
||||
|
||||
Device &
|
||||
Device::operator=(Device &&other) noexcept
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
m_Name = std::move(other.m_Name);
|
||||
m_PhysicalDevice = Take(other.m_PhysicalDevice);
|
||||
m_Device = Take(other.m_Device);
|
||||
m_Allocator = Take(other.m_Allocator);
|
||||
return *this;
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
// =============================================
|
||||
// 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];
|
||||
}
|
||||
|
|
@ -3,9 +3,9 @@
|
|||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "image.h"
|
||||
#include "core/image.h"
|
||||
|
||||
#include "device.h"
|
||||
#include "core/device.h"
|
||||
|
||||
void
|
||||
Image::Destroy(const Device *device)
|
||||
|
|
@ -109,7 +109,7 @@ Remember, we use upside down viewport.
|
|||
void
|
||||
TextureCube::Init(const Device *device, u32 cubeSide, vk::Format imageFormat, bool isMipMapped, cstr name)
|
||||
{
|
||||
WARN_IF(!IsPowerOfTwo(cubeSide), "Image {1} is {0}x{0} (Non Power of Two)", cubeSide, name ? name : "<unnamed>");
|
||||
WARN_IF(!IsPowerOfTwo(cubeSide), "Image Cube {1} has side {0}x{0} (Non Power of Two)", cubeSide, name ? name : "<unnamed>");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
vk::Extent3D extent = {.width = cubeSide, .height = cubeSide, .depth = 1};
|
||||
const vk::Extent3D extent = {.width = cubeSide, .height = cubeSide, .depth = 1};
|
||||
|
||||
vk::ImageCreateInfo imageCreateInfo = {
|
||||
.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);
|
||||
ERROR_IF(Failed(result), "Could not create depth image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||
ERROR_IF(Failed(result), "Could not create attachment image view {}. Cause: {}", name, result) THEN_ABORT(result);
|
||||
|
||||
m_Image = image;
|
||||
m_View = view;
|
||||
|
|
@ -3,11 +3,10 @@
|
|||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "physical_device.h"
|
||||
#include "core/physical_device.h"
|
||||
|
||||
#include "context.h"
|
||||
#include "queue_allocation.h"
|
||||
#include "surface.h"
|
||||
#include "core/context.h"
|
||||
#include "core/surface.h"
|
||||
|
||||
[[nodiscard]] vk::SurfaceCapabilitiesKHR
|
||||
GetSurfaceCapabilities(const vk::PhysicalDevice physicalDevice, const vk::SurfaceKHR surface)
|
||||
|
|
@ -139,24 +138,6 @@ PhysicalDevice::PhysicalDevice(const vk::SurfaceKHR surface, const vk::PhysicalD
|
|||
m_PhysicalDevice = physicalDevice;
|
||||
}
|
||||
|
||||
QueueAllocation
|
||||
PhysicalDevice::FindAppropriateQueueAllocation()
|
||||
{
|
||||
|
||||
for (auto &queueFamilyInfo : this->m_QueueFamilies)
|
||||
{
|
||||
if ((queueFamilyInfo.m_Support & REQUIRED_QUEUE_SUPPORT) == REQUIRED_QUEUE_SUPPORT)
|
||||
{
|
||||
return {
|
||||
.m_Family = queueFamilyInfo.m_Index,
|
||||
.m_Count = queueFamilyInfo.m_Count,
|
||||
};
|
||||
}
|
||||
}
|
||||
ERROR("No suitable queue family on the GPU.")
|
||||
THEN_ABORT(vk::Result::eErrorUnknown);
|
||||
}
|
||||
|
||||
eastl::fixed_vector<vk::PhysicalDevice, 8>
|
||||
EnumeratePhysicalDevices(const vk::Instance instance)
|
||||
{
|
||||
|
|
@ -175,42 +156,9 @@ EnumeratePhysicalDevices(const vk::Instance instance)
|
|||
|
||||
PhysicalDevices::PhysicalDevices(const Surface *surface, const Context *context)
|
||||
{
|
||||
auto surfaceImpl = surface->m_Surface;
|
||||
auto physicalDevices = EnumeratePhysicalDevices(context->m_Instance);
|
||||
for (auto physicalDevice : physicalDevices)
|
||||
{
|
||||
this->emplace_back(surfaceImpl, physicalDevice);
|
||||
this->emplace_back(surface->m_Surface, 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);
|
||||
}
|
||||
|
|
@ -3,9 +3,9 @@
|
|||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "pipeline.h"
|
||||
#include "core/pipeline.h"
|
||||
|
||||
#include "device.h"
|
||||
#include "core/device.h"
|
||||
|
||||
Pipeline::Pipeline(const Device *device, vk::PipelineLayout layout, vk::Pipeline pipeline,
|
||||
eastl::vector<vk::DescriptorSetLayout> &&setLayouts)
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
// =============================================
|
||||
// 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;
|
||||
}
|
||||
|
|
@ -3,36 +3,68 @@
|
|||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// ==============================================
|
||||
|
||||
#include "swapchain.h"
|
||||
#include "core/swapchain.h"
|
||||
|
||||
#include "device.h"
|
||||
#include "physical_device.h"
|
||||
#include "surface.h"
|
||||
#include "core/device.h"
|
||||
#include "core/physical_device.h"
|
||||
#include "core/surface.h"
|
||||
|
||||
[[nodiscard]] vk::Extent2D GetExtent(Size size, vk::SurfaceCapabilitiesKHR *surfaceCapabilities);
|
||||
[[nodiscard]] vk::Extent2D GetExtent(Size2D size, vk::SurfaceCapabilitiesKHR *surfaceCapabilities);
|
||||
|
||||
void
|
||||
Swapchain::Init(const Surface *surface, const Device *device, Size size, cstr name)
|
||||
Swapchain::Swapchain(const Surface *surface, const Device *device, Size2D size, NameString &&name)
|
||||
: m_Device(device)
|
||||
, m_Name(std::move(name))
|
||||
, m_Format(vk::Format::eUndefined)
|
||||
{
|
||||
assert(!m_Swapchain);
|
||||
this->Create(surface, device, size, name);
|
||||
this->Create(surface, size);
|
||||
}
|
||||
|
||||
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
|
||||
Swapchain::Create(const Surface *surface, const Device *device, Size size, cstr name)
|
||||
Swapchain::Create(const Surface *surface, Size2D size)
|
||||
{
|
||||
auto surfaceCapabilities = GetSurfaceCapabilities(device->m_PhysicalDevice, surface->m_Surface);
|
||||
auto surfaceCapabilities = GetSurfaceCapabilities(m_Device->m_PhysicalDevice, surface->m_Surface);
|
||||
m_Extent = GetExtent(size, &surfaceCapabilities);
|
||||
|
||||
while (m_Extent.width == 0 || m_Extent.height == 0)
|
||||
{
|
||||
glfwWaitEvents();
|
||||
surfaceCapabilities = GetSurfaceCapabilities(device->m_PhysicalDevice, surface->m_Surface);
|
||||
surfaceCapabilities = GetSurfaceCapabilities(m_Device->m_PhysicalDevice, surface->m_Surface);
|
||||
m_Extent = GetExtent(size, &surfaceCapabilities);
|
||||
}
|
||||
|
||||
auto surfaceFormats = GetSurfaceFormats(device->m_PhysicalDevice, surface->m_Surface);
|
||||
auto presentModes = GetSurfacePresentModes(device->m_PhysicalDevice, surface->m_Surface);
|
||||
auto surfaceFormats = GetSurfaceFormats(m_Device->m_PhysicalDevice, surface->m_Surface);
|
||||
auto presentModes = GetSurfacePresentModes(m_Device->m_PhysicalDevice, surface->m_Surface);
|
||||
|
||||
m_Format = vk::Format::eUndefined;
|
||||
vk::ColorSpaceKHR swapchainColorSpace = vk::ColorSpaceKHR::eSrgbNonlinear;
|
||||
|
|
@ -87,29 +119,29 @@ Swapchain::Create(const Surface *surface, const Device *device, Size size, cstr
|
|||
.oldSwapchain = m_Swapchain,
|
||||
};
|
||||
|
||||
vk::Device vkDevice = device->m_Device;
|
||||
vk::Device device = m_Device->m_Device;
|
||||
|
||||
vk::SwapchainKHR swapchain;
|
||||
vk::Result result = vkDevice.createSwapchainKHR(&swapchainCreateInfo, nullptr, &swapchain);
|
||||
ERROR_IF(Failed(result), "Swapchain {} creation failed. Cause {}", name, result)
|
||||
vk::Result result = device.createSwapchainKHR(&swapchainCreateInfo, nullptr, &swapchain);
|
||||
ERROR_IF(Failed(result), "Swapchain {} creation failed. Cause {}", m_Name, result)
|
||||
THEN_ABORT(result)
|
||||
ELSE_DEBUG("Created Swapchain '{}'", name);
|
||||
ELSE_DEBUG("Created Swapchain '{}'", m_Name);
|
||||
|
||||
// Irrelevant on the first run. Required for re-creation.
|
||||
Destroy(device);
|
||||
Cleanup();
|
||||
|
||||
m_Swapchain = swapchain;
|
||||
|
||||
device->SetName(m_Swapchain, name);
|
||||
m_Device->SetName(m_Swapchain, m_Name.data());
|
||||
|
||||
result = vkDevice.getSwapchainImagesKHR(m_Swapchain, &swapchainImageCount, nullptr);
|
||||
ERROR_IF(Failed(result), "Failed getting swapchain {}'s images. Cause {}", name, result)
|
||||
result = device.getSwapchainImagesKHR(m_Swapchain, &swapchainImageCount, nullptr);
|
||||
ERROR_IF(Failed(result), "Failed getting swapchain {}'s images. Cause {}", m_Name, result)
|
||||
THEN_ABORT(result);
|
||||
|
||||
// Managed by the Swapchain.
|
||||
m_Images.resize(swapchainImageCount);
|
||||
result = vkDevice.getSwapchainImagesKHR(m_Swapchain, &swapchainImageCount, m_Images.data());
|
||||
ERROR_IF(Failed(result), "Failed getting swapchain {}'s images. Cause {}", name, result)
|
||||
result = device.getSwapchainImagesKHR(m_Swapchain, &swapchainImageCount, m_Images.data());
|
||||
ERROR_IF(Failed(result), "Failed getting swapchain {}'s images. Cause {}", m_Name, result)
|
||||
THEN_ABORT(result);
|
||||
|
||||
vk::ImageViewCreateInfo viewCreateInfo = {
|
||||
|
|
@ -132,8 +164,8 @@ Swapchain::Create(const Surface *surface, const Device *device, Size size, cstr
|
|||
viewCreateInfo.image = image;
|
||||
|
||||
vk::ImageView imageView;
|
||||
result = vkDevice.createImageView(&viewCreateInfo, nullptr, &imageView);
|
||||
ERROR_IF(Failed(result), "Failed creating swapchain {}'s image view [{}]. Cause {}", name, index, result)
|
||||
result = device.createImageView(&viewCreateInfo, nullptr, &imageView);
|
||||
ERROR_IF(Failed(result), "Failed creating swapchain {}'s image view [{}]. Cause {}", m_Name, index, result)
|
||||
THEN_ABORT(result);
|
||||
|
||||
m_ImageViews.push_back(imageView);
|
||||
|
|
@ -141,7 +173,7 @@ Swapchain::Create(const Surface *surface, const Device *device, Size size, cstr
|
|||
++index;
|
||||
}
|
||||
|
||||
DEBUG("Swapchain {} Image Views created.", name);
|
||||
DEBUG("Swapchain {} Image Views created.", m_Name);
|
||||
|
||||
for (auto &callback : m_ResizeCallbacks)
|
||||
{
|
||||
|
|
@ -156,25 +188,25 @@ Swapchain::RegisterResizeCallback(FnResizeCallback &&callback)
|
|||
}
|
||||
|
||||
void
|
||||
Swapchain::Destroy(const Device *device)
|
||||
Swapchain::Cleanup()
|
||||
{
|
||||
if (!m_ImageViews.empty()) // Don't want the condition in the logs.
|
||||
DEBUG("Swapchain Image Views destroyed.");
|
||||
DEBUG("Swapchain {} Image Views destroyed.", m_Name);
|
||||
for (const auto imageView : m_ImageViews)
|
||||
{
|
||||
device->m_Device.destroy(imageView, nullptr);
|
||||
m_Device->m_Device.destroy(imageView, nullptr);
|
||||
}
|
||||
m_ImageViews.clear();
|
||||
if (m_Swapchain)
|
||||
{
|
||||
device->m_Device.destroy(m_Swapchain, nullptr);
|
||||
m_Device->m_Device.destroy(m_Swapchain, nullptr);
|
||||
m_Swapchain = nullptr;
|
||||
DEBUG("Swapchain destroyed.");
|
||||
DEBUG("Swapchain '{}' destroyed.", m_Name);
|
||||
}
|
||||
}
|
||||
|
||||
vk::Extent2D
|
||||
GetExtent(Size size, vk::SurfaceCapabilitiesKHR *surfaceCapabilities)
|
||||
GetExtent(Size2D size, vk::SurfaceCapabilitiesKHR *surfaceCapabilities)
|
||||
{
|
||||
if (surfaceCapabilities->currentExtent.width != MaxValue<u32>)
|
||||
{
|
||||
|
|
@ -3,10 +3,13 @@
|
|||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "window.h"
|
||||
#include "core/window.h"
|
||||
|
||||
#include "context.h"
|
||||
#include "logger.h"
|
||||
#include "core/context.h"
|
||||
#include "util/logger.h"
|
||||
|
||||
std::atomic_uint64_t Window::m_WindowCount = 0;
|
||||
std::atomic_bool Window::m_IsGlfwInit = false;
|
||||
|
||||
void
|
||||
Window::RequestExit() const noexcept
|
||||
|
|
@ -26,7 +29,7 @@ Window::SetWindowSize(const u32 width, const u32 height) const noexcept
|
|||
glfwSetWindowSize(m_Window, Cast<i32>(width), Cast<i32>(height));
|
||||
}
|
||||
|
||||
vk::Extent2D
|
||||
Size2D
|
||||
Window::GetSize() const
|
||||
{
|
||||
int width;
|
||||
|
|
@ -35,15 +38,21 @@ Window::GetSize() const
|
|||
return {Cast<u32>(width), Cast<u32>(height)};
|
||||
}
|
||||
|
||||
void
|
||||
Window::Init(cstr title, vk::Extent2D extent, b8 isFullScreen)
|
||||
Window::Window(const cstr title, Size2D extent, const b8 isFullScreen)
|
||||
{
|
||||
if (!glfwInit())
|
||||
m_Name = title;
|
||||
|
||||
if (!m_IsGlfwInit)
|
||||
{
|
||||
const char *error = nullptr;
|
||||
const auto code = glfwGetError(&error);
|
||||
ERROR("GLFW Init failed. Cause: ({}) {}", code, error)
|
||||
THEN_ABORT(code);
|
||||
if (!glfwInit())
|
||||
{
|
||||
const char *error = nullptr;
|
||||
const auto code = glfwGetError(&error);
|
||||
ERROR("GLFW Init failed. Cause: ({}) {}", code, error)
|
||||
THEN_ABORT(code);
|
||||
}
|
||||
m_WindowCount = 0;
|
||||
m_IsGlfwInit = true;
|
||||
}
|
||||
|
||||
GLFWmonitor *monitor = glfwGetPrimaryMonitor();
|
||||
|
|
@ -55,10 +64,10 @@ Window::Init(cstr title, vk::Extent2D extent, b8 isFullScreen)
|
|||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
glfwWindowHint(GLFW_CENTER_CURSOR, GLFW_TRUE);
|
||||
|
||||
m_Window = glfwCreateWindow(Cast<i32>(extent.width), Cast<i32>(extent.height), title,
|
||||
m_Window = glfwCreateWindow(Cast<i32>(extent.m_Width), Cast<i32>(extent.m_Height), m_Name.c_str(),
|
||||
isFullScreen ? monitor : nullptr, nullptr);
|
||||
ERROR_IF(m_Window == nullptr, "Window creation failed")
|
||||
ELSE_DEBUG("Window '{}' created with resolution '{}x{}'", title, extent.width, extent.height);
|
||||
ELSE_DEBUG("Window '{}' created with resolution '{}x{}'", m_Name, extent.m_Width, extent.m_Height);
|
||||
if (m_Window == nullptr)
|
||||
{
|
||||
const char *error = nullptr;
|
||||
|
|
@ -69,25 +78,45 @@ Window::Init(cstr title, vk::Extent2D extent, b8 isFullScreen)
|
|||
|
||||
if (isFullScreen == false)
|
||||
{
|
||||
glfwSetWindowPos(m_Window, Cast<i32>(windowWidth - extent.width) / 2,
|
||||
Cast<i32>(windowHeight - extent.height) / 2);
|
||||
glfwSetWindowPos(m_Window, Cast<i32>(windowWidth - extent.m_Width) / 2,
|
||||
Cast<i32>(windowHeight - extent.m_Height) / 2);
|
||||
}
|
||||
glfwSetInputMode(m_Window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
|
||||
|
||||
++m_WindowCount;
|
||||
}
|
||||
|
||||
void
|
||||
Window::Destroy()
|
||||
Window::~Window()
|
||||
{
|
||||
if (!m_Window)
|
||||
return;
|
||||
if (m_Window)
|
||||
{
|
||||
glfwDestroyWindow(m_Window);
|
||||
m_Window = nullptr;
|
||||
|
||||
const char *title = glfwGetWindowTitle(m_Window);
|
||||
--m_WindowCount;
|
||||
}
|
||||
|
||||
DEBUG("Window {} Destroyed", title);
|
||||
if (m_WindowCount== 0 && m_IsGlfwInit)
|
||||
{
|
||||
glfwTerminate();
|
||||
m_IsGlfwInit = false;
|
||||
}
|
||||
|
||||
glfwDestroyWindow(m_Window);
|
||||
m_Window = nullptr;
|
||||
|
||||
// Currently only one window is supported.
|
||||
glfwTerminate();
|
||||
DEBUG("Window '{}' Destroyed", m_Name);
|
||||
}
|
||||
|
||||
Window::Window(Window &&other) noexcept
|
||||
: m_Window(Take(other.m_Window))
|
||||
, 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;
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
# 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")
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
// =============================================
|
||||
// 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}
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,316 @@
|
|||
// =============================================
|
||||
// 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}
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
// =============================================
|
||||
// Aster: manager.cpp
|
||||
// Copyright (c) 2020-2025 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "systems/manager.h"
|
||||
|
|
@ -0,0 +1,195 @@
|
|||
// =============================================
|
||||
// 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}
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
# CMakeList.txt ; CMake project for Aster Util Headers
|
||||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
target_sources(aster_core PRIVATE "logger.cpp")
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "logger.h"
|
||||
#include "util/logger.h"
|
||||
|
||||
Logger g_Logger = Logger();
|
||||
// ReSharper disable once CppInconsistentNaming
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
// =============================================
|
||||
// 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");
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
// =============================================
|
||||
// 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);
|
||||
};
|
||||
9
build.sh
9
build.sh
|
|
@ -1,7 +1,12 @@
|
|||
#!/usr/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
echo "Running CMake"
|
||||
cmake --preset=default
|
||||
if grep 'NAME=NixOS' /etc/os-release
|
||||
then
|
||||
cmake --preset nixos
|
||||
else
|
||||
cmake --preset linux
|
||||
fi
|
||||
|
||||
echo "Running Ninja"
|
||||
if echo "$@" | grep -e "clean" -q
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
build/compile_commands.json
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
{
|
||||
"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
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
outputs = {self, nixpkgs, flake-utils }:
|
||||
flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
};
|
||||
eabase = pkgs.callPackage ./vendored-nix/eabase {};
|
||||
eastl = pkgs.callPackage ./vendored-nix/eastl { inherit eabase; };
|
||||
tinygltf = pkgs.callPackage ./vendored-nix/tinygltf {};
|
||||
debugbreak = pkgs.callPackage ./vendored-nix/scottt-debugbreak {};
|
||||
in
|
||||
with pkgs;
|
||||
{
|
||||
devShells.default = clangStdenv.mkDerivation {
|
||||
name = "BlazeEnv";
|
||||
|
||||
|
||||
nativeBuildInputs = [
|
||||
cmake
|
||||
ninja
|
||||
ccls
|
||||
clang-tools
|
||||
lldb
|
||||
(imgui.override {IMGUI_BUILD_VULKAN_BINDING = true; IMGUI_BUILD_GLFW_BINDING=true; })
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
sdl3
|
||||
glm
|
||||
glfw3
|
||||
eastl
|
||||
fmt
|
||||
eabase
|
||||
eastl
|
||||
entt
|
||||
tinygltf
|
||||
debugbreak
|
||||
stb
|
||||
|
||||
# vulkan
|
||||
vulkan-headers
|
||||
vulkan-loader
|
||||
vulkan-validation-layers
|
||||
vulkan-memory-allocator
|
||||
directx-shader-compiler
|
||||
glslang
|
||||
shaderc
|
||||
];
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
10
run.sh
10
run.sh
|
|
@ -1,14 +1,14 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
if [ -d "out" ]; then
|
||||
pushd ./build/ > /dev/null || exit
|
||||
if [ -d "build" ]; then
|
||||
pushd ./build/samples/04_scenes/ > /dev/null || exit
|
||||
if echo "$@" | grep -e "debug" -q
|
||||
then
|
||||
lldb aster-exe
|
||||
lldb ./scene_render
|
||||
else
|
||||
./aster-exe
|
||||
./scene_render
|
||||
fi
|
||||
popd > /dev/null || exit
|
||||
else
|
||||
echo "Build blaze first."
|
||||
echo "Build Aster first."
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@ cmake_minimum_required(VERSION 3.13)
|
|||
find_package(imgui CONFIG REQUIRED)
|
||||
|
||||
add_library(util_helper STATIC
|
||||
helpers.h
|
||||
helpers.cpp
|
||||
frame.cpp
|
||||
frame.h
|
||||
gui.cpp
|
||||
gui.h)
|
||||
"helpers.h"
|
||||
"helpers.cpp"
|
||||
"frame.cpp"
|
||||
"frame.h"
|
||||
"gui.cpp"
|
||||
"gui.h")
|
||||
|
||||
target_link_libraries(util_helper PRIVATE aster_core)
|
||||
target_link_libraries(util_helper PRIVATE imgui::imgui)
|
||||
|
|
|
|||
|
|
@ -5,9 +5,10 @@
|
|||
|
||||
#include "frame.h"
|
||||
|
||||
#include "device.h"
|
||||
#include "aster/core/device.h"
|
||||
#include "aster/core/swapchain.h"
|
||||
|
||||
#include "helpers.h"
|
||||
#include "swapchain.h"
|
||||
|
||||
Frame::Frame(const Device *device, const u32 queueFamilyIndex, const u32 frameCount)
|
||||
: m_FrameIdx(frameCount)
|
||||
|
|
@ -52,7 +53,7 @@ Frame::Frame(const Device *device, const u32 queueFamilyIndex, const u32 frameCo
|
|||
}
|
||||
|
||||
void
|
||||
Frame::Present(const vk::Queue commandQueue, Swapchain *swapchain, const Window *window)
|
||||
Frame::Present(const vk::Queue commandQueue, Swapchain *swapchain, const Surface *surface, Size2D size)
|
||||
{
|
||||
|
||||
vk::PresentInfoKHR presentInfo = {
|
||||
|
|
@ -70,7 +71,7 @@ Frame::Present(const vk::Queue commandQueue, Swapchain *swapchain, const Window
|
|||
case vk::Result::eErrorOutOfDateKHR:
|
||||
case vk::Result::eSuboptimalKHR:
|
||||
DEBUG("Recreating Swapchain. Cause: {}", result);
|
||||
swapchain->Create(window);
|
||||
swapchain->Create(surface, size);
|
||||
break; // Present failed. We do nothing. Frame is skipped.
|
||||
default:
|
||||
AbortIfFailedM(result, "Swapchain Present failed.");
|
||||
|
|
@ -128,7 +129,7 @@ FrameManager::FrameManager(const Device *device, u32 queueFamilyIndex, u32 frame
|
|||
}
|
||||
|
||||
Frame *
|
||||
FrameManager::GetNextFrame(Swapchain *swapchain, const Window *window)
|
||||
FrameManager::GetNextFrame(Swapchain *swapchain, const Surface *surface, Size2D size)
|
||||
{
|
||||
|
||||
Frame *currentFrame = &m_Frames[m_CurrentFrameIdx];
|
||||
|
|
@ -153,7 +154,7 @@ FrameManager::GetNextFrame(Swapchain *swapchain, const Window *window)
|
|||
break; // Image acquired. Break out of loop.
|
||||
case vk::Result::eErrorOutOfDateKHR:
|
||||
DEBUG("Recreating Swapchain. Cause: {}", result);
|
||||
swapchain->Create(window);
|
||||
swapchain->Create(surface, size);
|
||||
break; // Image acquire has failed. We move to the next frame.
|
||||
default:
|
||||
AbortIfFailedMV(result, "Waiting for swapchain image {} failed.", frameIndex);
|
||||
|
|
|
|||
|
|
@ -5,14 +5,17 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "global.h"
|
||||
#include "aster/aster.h"
|
||||
#include "helpers.h"
|
||||
|
||||
#include "aster/core/size.h"
|
||||
|
||||
#include <EASTL/fixed_vector.h>
|
||||
|
||||
struct Device;
|
||||
struct Window;
|
||||
struct Swapchain;
|
||||
struct Surface;
|
||||
|
||||
struct Frame
|
||||
{
|
||||
|
|
@ -28,7 +31,7 @@ struct Frame
|
|||
// Transient
|
||||
u32 m_ImageIdx;
|
||||
|
||||
void Present(vk::Queue commandQueue, Swapchain *swapchain, const Window *window);
|
||||
void Present(const vk::Queue commandQueue, Swapchain* swapchain, const Surface* surface, Size2D size);
|
||||
|
||||
Frame(const Device *device, u32 queueFamilyIndex, u32 frameCount);
|
||||
~Frame();
|
||||
|
|
@ -48,5 +51,5 @@ struct FrameManager
|
|||
|
||||
FrameManager(const Device *device, u32 queueFamilyIndex, u32 framesInFlight);
|
||||
|
||||
Frame *GetNextFrame(Swapchain *swapchain, const Window *window);
|
||||
Frame *GetNextFrame(Swapchain *swapchain, const Surface *surface, Size2D size);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@
|
|||
|
||||
#include "gui.h"
|
||||
|
||||
#include "context.h"
|
||||
#include "device.h"
|
||||
#include "aster/core/context.h"
|
||||
#include "aster/core/device.h"
|
||||
#include "aster/core/window.h"
|
||||
#include "helpers.h"
|
||||
#include "window.h"
|
||||
|
||||
#include <imgui_impl_glfw.h>
|
||||
#include <imgui_impl_vulkan.h>
|
||||
|
|
@ -58,7 +58,7 @@ Init(const Context *context, const Device *device, const Window *window, vk::For
|
|||
CreateContext();
|
||||
ImGuiIO &io = GetIO();
|
||||
(void)io;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
||||
// io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
||||
// io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Viewports bad
|
||||
|
||||
StyleColorsDark();
|
||||
|
|
@ -108,16 +108,16 @@ StartBuild()
|
|||
ImGui_ImplGlfw_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,
|
||||
// because it would be confusing to have two docking targets within each others.
|
||||
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoDocking;
|
||||
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_None | ImGuiWindowFlags_NoDocking;
|
||||
|
||||
const ImGuiViewport *viewport = GetMainViewport();
|
||||
SetNextWindowPos(viewport->WorkPos);
|
||||
SetNextWindowSize(viewport->WorkSize);
|
||||
SetNextWindowViewport(viewport->ID);
|
||||
// SetNextWindowViewport(viewport->ID);
|
||||
PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||
PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
||||
windowFlags |=
|
||||
|
|
@ -130,18 +130,18 @@ StartBuild()
|
|||
// 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
|
||||
// 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));
|
||||
Begin("DockSpace Demo", nullptr, windowFlags);
|
||||
PopStyleVar();
|
||||
PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
|
||||
Begin("DockSpace Demo", nullptr, windowFlags);
|
||||
PopStyleVar();
|
||||
|
||||
PopStyleVar(2);
|
||||
PopStyleVar(2);
|
||||
|
||||
// DockSpace
|
||||
if (GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable)
|
||||
{
|
||||
const ImGuiID dockspaceId = GetID("MyDockSpace");
|
||||
DockSpace(dockspaceId, ImVec2(0.0f, 0.0f), dockspaceFlags);
|
||||
}
|
||||
// DockSpace
|
||||
if (GetIO().ConfigFlags & ImGuiConfigFlags_DockingEnable)
|
||||
{
|
||||
const ImGuiID dockspaceId = GetID("MyDockSpace");
|
||||
DockSpace(dockspaceId, ImVec2(0.0f, 0.0f), dockspaceFlags);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -151,13 +151,13 @@ EndBuild()
|
|||
Render();
|
||||
|
||||
EndFrame();
|
||||
if (GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
{
|
||||
GLFWwindow *backupCurrentContext = glfwGetCurrentContext();
|
||||
UpdatePlatformWindows();
|
||||
RenderPlatformWindowsDefault();
|
||||
glfwMakeContextCurrent(backupCurrentContext);
|
||||
}
|
||||
// if (GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
|
||||
// {
|
||||
// GLFWwindow *backupCurrentContext = glfwGetCurrentContext();
|
||||
// UpdatePlatformWindows();
|
||||
// RenderPlatformWindowsDefault();
|
||||
// glfwMakeContextCurrent(backupCurrentContext);
|
||||
// }
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -213,4 +213,4 @@ PopDisable()
|
|||
PopStyleVar();
|
||||
PopItemFlag();
|
||||
}
|
||||
} // namespace ImGui
|
||||
} // namespace ImGui
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "global.h"
|
||||
#include "aster/aster.h"
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
#include "helpers.h"
|
||||
|
||||
#include "device.h"
|
||||
#include "physical_device.h"
|
||||
#include "aster/core/device.h"
|
||||
#include "aster/core/physical_device.h"
|
||||
|
||||
#include <EASTL/array.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "global.h"
|
||||
#include "aster/aster.h"
|
||||
|
||||
#include "queue_allocation.h"
|
||||
#include "aster/core/queue_allocation.h"
|
||||
|
||||
#include "EASTL/span.h"
|
||||
#include <EASTL/vector.h>
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
add_executable(triangle triangle.cpp)
|
||||
add_shader(triangle shader/triangle.vert.glsl)
|
||||
add_shader(triangle shader/triangle.frag.glsl)
|
||||
add_executable(triangle "triangle.cpp")
|
||||
add_shader(triangle "shader/triangle.vert.glsl")
|
||||
add_shader(triangle "shader/triangle.frag.glsl")
|
||||
|
||||
target_link_libraries(triangle PRIVATE aster_core)
|
||||
target_link_libraries(triangle PRIVATE util_helper)
|
||||
|
|
|
|||
|
|
@ -3,16 +3,16 @@
|
|||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "buffer.h"
|
||||
#include "constants.h"
|
||||
#include "context.h"
|
||||
#include "device.h"
|
||||
#include "physical_device.h"
|
||||
#include "window.h"
|
||||
#include "aster/aster.h"
|
||||
|
||||
#include "global.h"
|
||||
#include "pipeline.h"
|
||||
#include "swapchain.h"
|
||||
#include "aster/core/buffer.h"
|
||||
#include "aster/core/constants.h"
|
||||
#include "aster/core/context.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"
|
||||
|
||||
|
|
@ -74,19 +74,23 @@ main(int, char **)
|
|||
{
|
||||
MIN_LOG_LEVEL(Logger::LogType::eInfo);
|
||||
|
||||
Window window = {"Triangle (Aster)", {640, 480}};
|
||||
Context context = {"Triangle", VERSION};
|
||||
Window window = {"Triangle (Aster)", &context, {640, 480}};
|
||||
Surface surface = {&context, &window, "Primary"};
|
||||
|
||||
PhysicalDevices physicalDevices = {&window, &context};
|
||||
PhysicalDevices physicalDevices = {&surface, &context};
|
||||
PhysicalDevice deviceToUse = FindSuitableDevice(physicalDevices);
|
||||
|
||||
INFO("Using {} as the primary device.", deviceToUse.m_DeviceProperties.deviceName.data());
|
||||
|
||||
Features enabledDeviceFeatures = {.m_Vulkan13Features = {.dynamicRendering = true}};
|
||||
Features enabledDeviceFeatures = {
|
||||
.m_Vulkan12Features = {.bufferDeviceAddress = true},
|
||||
.m_Vulkan13Features = {.synchronization2 = true, .dynamicRendering = true},
|
||||
};
|
||||
QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse);
|
||||
Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"};
|
||||
vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
||||
Swapchain swapchain = {&window, &device, "Primary Chain"};
|
||||
Swapchain swapchain = {&surface, &device, window.GetSize(), "Primary Chain"};
|
||||
Pipeline pipeline = CreatePipeline(&device, &swapchain);
|
||||
|
||||
vk::CommandPool copyPool;
|
||||
|
|
@ -175,24 +179,40 @@ main(int, char **)
|
|||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
};
|
||||
vk::ImageMemoryBarrier topOfThePipeBarrier = {
|
||||
vk::ImageMemoryBarrier2 topOfThePipeBarrier = {
|
||||
.srcStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
||||
.srcAccessMask = vk::AccessFlagBits2::eNone,
|
||||
.dstStageMask = vk::PipelineStageFlagBits2::eColorAttachmentOutput,
|
||||
.dstAccessMask = vk::AccessFlagBits2::eColorAttachmentWrite,
|
||||
.oldLayout = vk::ImageLayout::eUndefined,
|
||||
.newLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
||||
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||
.subresourceRange = subresourceRange,
|
||||
};
|
||||
vk::ImageMemoryBarrier renderToPresentBarrier = {
|
||||
vk::DependencyInfo topOfThePipeDependency = {
|
||||
.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,
|
||||
.newLayout = vk::ImageLayout::ePresentSrcKHR,
|
||||
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||
.subresourceRange = subresourceRange,
|
||||
};
|
||||
vk::DependencyInfo renderToPresentDependency = {
|
||||
.imageMemoryBarrierCount = 1,
|
||||
.pImageMemoryBarriers = &renderToPresentBarrier,
|
||||
};
|
||||
|
||||
// Frames
|
||||
eastl::fixed_vector<Frame, MAX_FRAMES_IN_FLIGHT> frames;
|
||||
for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
|
||||
for (u32 i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
|
||||
{
|
||||
frames.emplace_back(&device, queueAllocation.m_Family, i);
|
||||
}
|
||||
|
|
@ -217,7 +237,7 @@ main(int, char **)
|
|||
case vk::Result::eErrorOutOfDateKHR:
|
||||
case vk::Result::eSuboptimalKHR:
|
||||
INFO("Recreating Swapchain. Cause: {}", result);
|
||||
swapchain.Create(&window);
|
||||
swapchain.Create(&surface, window.GetSize());
|
||||
viewport.y = Cast<f32>(swapchain.m_Extent.height);
|
||||
viewport.width = Cast<f32>(swapchain.m_Extent.width);
|
||||
viewport.height = -Cast<f32>(swapchain.m_Extent.height);
|
||||
|
|
@ -249,8 +269,7 @@ main(int, char **)
|
|||
ERROR_IF(Failed(result), "Command buffer begin failed. Cause: {}", result)
|
||||
THEN_ABORT(result);
|
||||
|
||||
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eColorAttachmentOutput,
|
||||
{}, 0, nullptr, 0, nullptr, 1, &topOfThePipeBarrier);
|
||||
cmd.pipelineBarrier2(&topOfThePipeDependency);
|
||||
|
||||
// Render
|
||||
vk::RenderingAttachmentInfo attachmentInfo = {
|
||||
|
|
@ -259,7 +278,7 @@ main(int, char **)
|
|||
.resolveMode = vk::ResolveModeFlagBits::eNone,
|
||||
.loadOp = vk::AttachmentLoadOp::eClear,
|
||||
.storeOp = vk::AttachmentStoreOp::eStore,
|
||||
.clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 1.0f},
|
||||
.clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 0.0f},
|
||||
};
|
||||
|
||||
vk::RenderingInfo renderingInfo = {
|
||||
|
|
@ -280,8 +299,7 @@ main(int, char **)
|
|||
|
||||
cmd.endRendering();
|
||||
|
||||
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eBottomOfPipe,
|
||||
{}, 0, nullptr, 0, nullptr, 1, &renderToPresentBarrier);
|
||||
cmd.pipelineBarrier2(&renderToPresentDependency);
|
||||
|
||||
result = cmd.end();
|
||||
ERROR_IF(Failed(result), "Command buffer end failed. Cause: {}", result)
|
||||
|
|
@ -317,7 +335,7 @@ main(int, char **)
|
|||
case vk::Result::eErrorOutOfDateKHR:
|
||||
case vk::Result::eSuboptimalKHR:
|
||||
INFO("Recreating Swapchain. Cause: {}", result);
|
||||
swapchain.Create(&window);
|
||||
swapchain.Create(&surface, window.GetSize());
|
||||
viewport.y = Cast<f32>(swapchain.m_Extent.height);
|
||||
viewport.width = Cast<f32>(swapchain.m_Extent.width);
|
||||
viewport.height = -Cast<f32>(swapchain.m_Extent.height);
|
||||
|
|
|
|||
|
|
@ -4,11 +4,13 @@ cmake_minimum_required(VERSION 3.13)
|
|||
|
||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fsanitize=address")
|
||||
|
||||
add_executable(box box.cpp stb_image.h)
|
||||
add_shader(box shader/box.vert.glsl)
|
||||
add_shader(box shader/box.frag.glsl)
|
||||
add_executable(box "box.cpp" "stb_image.h")
|
||||
add_shader(box "shader/box.vert.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 util_helper)
|
||||
|
||||
add_resource_dir(box image)
|
||||
add_resource_dir(box image)
|
||||
|
|
|
|||
|
|
@ -3,28 +3,31 @@
|
|||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "buffer.h"
|
||||
#include "constants.h"
|
||||
#include "context.h"
|
||||
#include "device.h"
|
||||
#include "global.h"
|
||||
#include "physical_device.h"
|
||||
#include "pipeline.h"
|
||||
#include "swapchain.h"
|
||||
#include "window.h"
|
||||
#include "aster/aster.h"
|
||||
|
||||
#include "aster/core/buffer.h"
|
||||
#include "aster/core/constants.h"
|
||||
#include "aster/core/context.h"
|
||||
#include "aster/core/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"
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "aster/systems/buffer_manager.h"
|
||||
#include "aster/systems/image_manager.h"
|
||||
#include "frame.h"
|
||||
#include "image.h"
|
||||
#include "stb_image.h"
|
||||
|
||||
#include <EASTL/array.h>
|
||||
|
||||
constexpr u32 MAX_FRAMES_IN_FLIGHT = 3;
|
||||
constexpr auto VERTEX_SHADER_FILE = "shader/box.vert.glsl.spv";
|
||||
constexpr auto FRAGMENT_SHADER_FILE = "shader/box.frag.glsl.spv";
|
||||
constexpr auto VERTEX_SHADER_FILE = "shader/box.vs.hlsl.spv";
|
||||
constexpr auto FRAGMENT_SHADER_FILE = "shader/box.ps.hlsl.spv";
|
||||
|
||||
struct ImageFile
|
||||
{
|
||||
|
|
@ -75,32 +78,9 @@ Pipeline CreatePipeline(const Device *device, const Swapchain *swapchain);
|
|||
struct Vertex
|
||||
{
|
||||
vec3 m_Position;
|
||||
f32 m_PositionW = 1.0;
|
||||
vec2 m_TexCoord0;
|
||||
|
||||
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),
|
||||
},
|
||||
};
|
||||
}
|
||||
vec2 m_Padding0_ = {0.0f, 0.0f};
|
||||
};
|
||||
|
||||
struct Camera
|
||||
|
|
@ -115,24 +95,29 @@ main(int, char **)
|
|||
{
|
||||
MIN_LOG_LEVEL(Logger::LogType::eInfo);
|
||||
|
||||
Window window = {"Box (Aster)", {640, 480}};
|
||||
Context context = {"Box", VERSION};
|
||||
Window window = {"Box (Aster)", &context, {640, 480}};
|
||||
Surface surface = {&context, &window, "Primary"};
|
||||
|
||||
PhysicalDevices physicalDevices = {&window, &context};
|
||||
PhysicalDevices physicalDevices = {&surface, &context};
|
||||
PhysicalDevice deviceToUse = FindSuitableDevice(physicalDevices);
|
||||
|
||||
INFO("Using {} as the primary device.", deviceToUse.m_DeviceProperties.deviceName.data());
|
||||
|
||||
Features enabledDeviceFeatures = {
|
||||
.m_Vulkan10Features = {.samplerAnisotropy = true},
|
||||
.m_Vulkan13Features = {.dynamicRendering = true},
|
||||
.m_Vulkan12Features = {.bufferDeviceAddress = true},
|
||||
.m_Vulkan13Features = {.synchronization2 = true, .dynamicRendering = true},
|
||||
};
|
||||
QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse);
|
||||
Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"};
|
||||
vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
||||
Swapchain swapchain = {&window, &device, "Primary Chain"};
|
||||
Swapchain swapchain = {&surface, &device, window.GetSize(), "Primary Chain"};
|
||||
Pipeline pipeline = CreatePipeline(&device, &swapchain);
|
||||
|
||||
systems::BufferManager bufferManager{&device, 12, 0};
|
||||
systems::ImageManager imageManager{&device, 12, 1};
|
||||
|
||||
Camera camera = {
|
||||
.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)),
|
||||
|
|
@ -153,6 +138,10 @@ main(int, char **)
|
|||
.type = vk::DescriptorType::eCombinedImageSampler,
|
||||
.descriptorCount = 1,
|
||||
},
|
||||
vk::DescriptorPoolSize{
|
||||
.type = vk::DescriptorType::eStorageBuffer,
|
||||
.descriptorCount = 1,
|
||||
},
|
||||
};
|
||||
vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo = {
|
||||
.maxSets = 1, .poolSizeCount = Cast<u32>(poolSizes.size()), .pPoolSizes = poolSizes.data()};
|
||||
|
|
@ -233,24 +222,32 @@ main(int, char **)
|
|||
assert(loaded);
|
||||
INFO("Image {}x{} : {} channels", imageFile.m_Width, imageFile.m_Height, imageFile.m_NumChannels);
|
||||
|
||||
VertexBuffer vbo;
|
||||
Texture crate;
|
||||
vbo.Init(&device, vertices.size() * sizeof vertices[0], "VBO");
|
||||
crate.Init(&device, {imageFile.m_Width, imageFile.m_Height}, vk::Format::eR8G8B8A8Srgb, false, "Crate Texture");
|
||||
auto vbo = bufferManager.CreateStorageBuffer(vertices.size() * sizeof vertices[0], "Vertex Buffer").ToPointer();
|
||||
auto crate = imageManager
|
||||
.CreateTexture2D({
|
||||
.m_Format = vk::Format::eR8G8B8A8Srgb,
|
||||
.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 vertexStaging, imageStaging;
|
||||
vertexStaging.Init(&device, vertices.size() * sizeof vertices[0], "Vertex Staging");
|
||||
vertexStaging.Write(&device, 0, vertices.size() * sizeof vertices[0], vertices.data());
|
||||
StagingBuffer imageStaging;
|
||||
|
||||
imageStaging.Init(&device, imageFile.GetSize(), "Image Staging");
|
||||
imageStaging.Write(&device, 0, imageFile.GetSize(), imageFile.m_Data);
|
||||
|
||||
vk::ImageMemoryBarrier imageReadyToWrite = {
|
||||
vk::ImageMemoryBarrier2 imageReadyToWrite = {
|
||||
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
||||
.srcAccessMask = vk::AccessFlagBits2::eNone,
|
||||
.dstStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
||||
.dstAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
||||
.oldLayout = vk::ImageLayout::eUndefined,
|
||||
.newLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||
.image = crate.m_Image,
|
||||
.image = crate->m_Image,
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
|
|
@ -260,13 +257,21 @@ main(int, char **)
|
|||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
vk::DependencyInfo imageReadyToWriteDependency = {
|
||||
.imageMemoryBarrierCount = 1,
|
||||
.pImageMemoryBarriers = &imageReadyToWrite,
|
||||
};
|
||||
|
||||
vk::ImageMemoryBarrier imageReadyToRead = {
|
||||
vk::ImageMemoryBarrier2 imageReadyToRead = {
|
||||
.srcStageMask = vk::PipelineStageFlagBits2::eTransfer,
|
||||
.srcAccessMask = vk::AccessFlagBits2::eTransferWrite,
|
||||
.dstStageMask = vk::PipelineStageFlagBits2::eFragmentShader,
|
||||
.dstAccessMask = vk::AccessFlagBits2::eShaderRead,
|
||||
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||
.image = crate.m_Image,
|
||||
.image = crate->m_Image,
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||
|
|
@ -276,6 +281,10 @@ main(int, char **)
|
|||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
vk::DependencyInfo imageReadyToReadDependency = {
|
||||
.imageMemoryBarrierCount = 1,
|
||||
.pImageMemoryBarriers = &imageReadyToRead,
|
||||
};
|
||||
|
||||
vk::Fence fence;
|
||||
vk::FenceCreateInfo fenceCreateInfo = {};
|
||||
|
|
@ -283,11 +292,8 @@ main(int, char **)
|
|||
|
||||
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
||||
AbortIfFailed(copyBuffer.begin(&beginInfo));
|
||||
copyBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eHost, vk::PipelineStageFlagBits::eTransfer, {}, 0,
|
||||
nullptr, 0, nullptr, 1, &imageReadyToWrite);
|
||||
|
||||
vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = vertexStaging.GetSize()};
|
||||
copyBuffer.copyBuffer(vertexStaging.m_Buffer, vbo.m_Buffer, 1, &bufferCopy);
|
||||
copyBuffer.pipelineBarrier2(&imageReadyToWriteDependency);
|
||||
|
||||
vk::BufferImageCopy imageCopy = {
|
||||
.bufferOffset = 0,
|
||||
|
|
@ -303,11 +309,10 @@ main(int, char **)
|
|||
.imageOffset = {},
|
||||
.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);
|
||||
|
||||
copyBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eFragmentShader, {},
|
||||
0, nullptr, 0, nullptr, 1, &imageReadyToRead);
|
||||
copyBuffer.pipelineBarrier2(&imageReadyToReadDependency);
|
||||
|
||||
AbortIfFailed(copyBuffer.end());
|
||||
|
||||
|
|
@ -325,7 +330,6 @@ main(int, char **)
|
|||
AbortIfFailedM(device.m_Device.resetCommandPool(copyPool, {}), "Couldn't reset command pool.");
|
||||
|
||||
device.m_Device.destroy(fence, nullptr);
|
||||
vertexStaging.Destroy(&device);
|
||||
imageStaging.Destroy(&device);
|
||||
}
|
||||
|
||||
|
|
@ -349,19 +353,23 @@ main(int, char **)
|
|||
AbortIfFailed(device.m_Device.createSampler(&samplerCreateInfo, nullptr, &sampler));
|
||||
}
|
||||
|
||||
UniformBuffer ubo;
|
||||
ubo.Init(&device, sizeof camera, "Camera UBO");
|
||||
ubo.Write(&device, 0, sizeof camera, &camera);
|
||||
auto ubo = bufferManager.CreateUniformBuffer(sizeof camera, "Camera UBO").ToPointer();
|
||||
ubo->Write(&device, 0, sizeof camera, &camera);
|
||||
vk::DescriptorBufferInfo descriptorBufferInfo = {
|
||||
.buffer = ubo.m_Buffer,
|
||||
.buffer = ubo->m_Buffer,
|
||||
.offset = 0,
|
||||
.range = ubo.GetSize(),
|
||||
.range = ubo->GetSize(),
|
||||
};
|
||||
vk::DescriptorImageInfo descriptorImageInfo = {
|
||||
.sampler = sampler,
|
||||
.imageView = crate.m_View,
|
||||
.imageView = crate->m_View,
|
||||
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||
};
|
||||
vk::DescriptorBufferInfo descriptorStorageBufferInfo = {
|
||||
.buffer = vbo->m_Buffer,
|
||||
.offset = 0,
|
||||
.range = vbo->GetSize(),
|
||||
};
|
||||
eastl::array writeDescriptors = {
|
||||
vk::WriteDescriptorSet{
|
||||
.dstSet = descriptorSet,
|
||||
|
|
@ -379,6 +387,14 @@ main(int, char **)
|
|||
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||
.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);
|
||||
|
||||
|
|
@ -412,35 +428,56 @@ main(int, char **)
|
|||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
};
|
||||
vk::ImageMemoryBarrier topOfThePipeBarrier = {
|
||||
vk::ImageMemoryBarrier2 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,
|
||||
.newLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
||||
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||
.subresourceRange = subresourceRange,
|
||||
};
|
||||
vk::ImageMemoryBarrier renderToPresentBarrier = {
|
||||
vk::DependencyInfo topOfThePipeDependency = {
|
||||
.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,
|
||||
.newLayout = vk::ImageLayout::ePresentSrcKHR,
|
||||
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||
.subresourceRange = subresourceRange,
|
||||
};
|
||||
vk::DependencyInfo renderToPresentDependency = {
|
||||
.imageMemoryBarrierCount = 1,
|
||||
.pImageMemoryBarriers = &renderToPresentBarrier,
|
||||
};
|
||||
|
||||
FrameManager frameManager = {&device, queueAllocation.m_Family, MAX_FRAMES_IN_FLIGHT};
|
||||
eastl::fixed_vector<DepthImage, MAX_FRAMES_IN_FLIGHT> depthImages(frameManager.m_FramesInFlight);
|
||||
for (auto &depthImage : depthImages)
|
||||
{
|
||||
depthImage.Init(&device, swapchain.m_Extent, "Depth");
|
||||
}
|
||||
eastl::fixed_vector<Ref<Image>, MAX_FRAMES_IN_FLIGHT> depthImages;
|
||||
|
||||
auto recreateDepthBuffers = [&device, &depthImages](vk::Extent2D extent) {
|
||||
for (auto &depthImage : depthImages)
|
||||
auto initDepthImages = [&imageManager, &depthImages, &frameManager] (const vk::Extent2D extent) {
|
||||
for (u32 i = 0; i < frameManager.m_FramesInFlight; ++i)
|
||||
{
|
||||
depthImage.Destroy(&device);
|
||||
depthImage.Init(&device, extent, "Depth");
|
||||
depthImages.push_back(
|
||||
imageManager.CreateDepthStencilImage({.m_Extent = extent, .m_Name = "Depth"}).ToPointer());
|
||||
}
|
||||
};
|
||||
|
||||
initDepthImages(swapchain.m_Extent);
|
||||
|
||||
auto recreateDepthBuffers = [&depthImages, &initDepthImages](const vk::Extent2D extent) {
|
||||
depthImages.clear();
|
||||
initDepthImages(extent);
|
||||
};
|
||||
swapchain.RegisterResizeCallback(recreateDepthBuffers);
|
||||
|
||||
Time::Init();
|
||||
|
|
@ -451,15 +488,15 @@ main(int, char **)
|
|||
Time::Update();
|
||||
|
||||
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, &window);
|
||||
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &surface, window.GetSize());
|
||||
|
||||
u32 imageIndex = currentFrame->m_ImageIdx;
|
||||
vk::ImageView currentImageView = swapchain.m_ImageViews[imageIndex];
|
||||
vk::Image currentImage = swapchain.m_Images[imageIndex];
|
||||
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;
|
||||
renderToPresentBarrier.image = currentImage;
|
||||
|
|
@ -467,8 +504,7 @@ main(int, char **)
|
|||
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
||||
AbortIfFailed(cmd.begin(&beginInfo));
|
||||
|
||||
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eTopOfPipe, vk::PipelineStageFlagBits::eColorAttachmentOutput,
|
||||
{}, 0, nullptr, 0, nullptr, 1, &topOfThePipeBarrier);
|
||||
cmd.pipelineBarrier2(&topOfThePipeDependency);
|
||||
|
||||
// Render
|
||||
eastl::array attachmentInfos = {
|
||||
|
|
@ -478,7 +514,7 @@ main(int, char **)
|
|||
.resolveMode = vk::ResolveModeFlagBits::eNone,
|
||||
.loadOp = vk::AttachmentLoadOp::eClear,
|
||||
.storeOp = vk::AttachmentStoreOp::eStore,
|
||||
.clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 1.0f},
|
||||
.clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 0.0f},
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -505,14 +541,11 @@ main(int, char **)
|
|||
cmd.setScissor(0, 1, &scissor);
|
||||
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics, pipeline.m_Pipeline);
|
||||
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.endRendering();
|
||||
|
||||
cmd.pipelineBarrier(vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eBottomOfPipe,
|
||||
{}, 0, nullptr, 0, nullptr, 1, &renderToPresentBarrier);
|
||||
cmd.pipelineBarrier2(&renderToPresentDependency);
|
||||
|
||||
AbortIfFailed(cmd.end());
|
||||
|
||||
|
|
@ -528,21 +561,13 @@ main(int, char **)
|
|||
};
|
||||
AbortIfFailed(commandQueue.submit(1, &submitInfo, currentFrame->m_FrameAvailableFence));
|
||||
|
||||
currentFrame->Present(commandQueue, &swapchain, &window);
|
||||
currentFrame->Present(commandQueue, &swapchain, &surface, window.GetSize());
|
||||
}
|
||||
|
||||
device.WaitIdle();
|
||||
|
||||
for (auto &depthImage : depthImages)
|
||||
{
|
||||
depthImage.Destroy(&device);
|
||||
}
|
||||
device.m_Device.destroy(sampler, nullptr);
|
||||
ubo.Destroy(&device);
|
||||
device.m_Device.destroy(descriptorPool, nullptr);
|
||||
device.m_Device.destroy(copyPool, nullptr);
|
||||
crate.Destroy(&device);
|
||||
vbo.Destroy(&device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -580,6 +605,12 @@ CreatePipeline(const Device *device, const Swapchain *swapchain)
|
|||
.descriptorCount = 1,
|
||||
.stageFlags = vk::ShaderStageFlagBits::eFragment,
|
||||
},
|
||||
vk::DescriptorSetLayoutBinding{
|
||||
.binding = 2,
|
||||
.descriptorType = vk::DescriptorType::eStorageBuffer,
|
||||
.descriptorCount = 1,
|
||||
.stageFlags = vk::ShaderStageFlagBits::eVertex,
|
||||
},
|
||||
};
|
||||
vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
|
||||
.bindingCount = Cast<u32>(descriptorSetLayoutBinding.size()),
|
||||
|
|
@ -599,15 +630,7 @@ CreatePipeline(const Device *device, const Swapchain *swapchain)
|
|||
AbortIfFailed(device->m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &pipelineLayout));
|
||||
device->SetName(pipelineLayout, "Box Layout");
|
||||
|
||||
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::PipelineVertexInputStateCreateInfo vertexInputStateCreateInfo = {};
|
||||
vk::PipelineInputAssemblyStateCreateInfo inputAssemblyStateCreateInfo = {
|
||||
.topology = vk::PrimitiveTopology::eTriangleList,
|
||||
.primitiveRestartEnable = false,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
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;
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
struct VS_Input
|
||||
{
|
||||
uint VertexIndex : SV_VertexID;
|
||||
};
|
||||
|
||||
struct VS_Output
|
||||
{
|
||||
float2 UV0 : TEXCOORD0;
|
||||
float4 VertexPosition : SV_Position;
|
||||
};
|
||||
|
||||
struct CameraData {
|
||||
float4x4 Model;
|
||||
float4x4 View;
|
||||
float4x4 Projection;
|
||||
};
|
||||
|
||||
struct VertexData {
|
||||
float4 Position;
|
||||
float2 UV0;
|
||||
};
|
||||
|
||||
[[vk::binding(0, 0)]] ConstantBuffer<CameraData> Camera;
|
||||
[[vk::binding(2, 0)]] StructuredBuffer<VertexData> Vertices;
|
||||
|
||||
VS_Output main(VS_Input StageInput) {
|
||||
VS_Output output;
|
||||
|
||||
output.UV0 = Vertices[StageInput.VertexIndex].UV0;
|
||||
|
||||
float4 position = Vertices[StageInput.VertexIndex].Position;
|
||||
|
||||
output.VertexPosition = mul(Camera.Projection, mul(Camera.View, mul(Camera.Model, position)));
|
||||
|
||||
return output;
|
||||
}
|
||||
|
|
@ -5,28 +5,28 @@ cmake_minimum_required(VERSION 3.13)
|
|||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fsanitize=address")
|
||||
find_path(TINYGLTF_INCLUDE_DIRS "tiny_gltf.h")
|
||||
|
||||
add_executable(model_render model_render.cpp
|
||||
pipeline_utils.cpp
|
||||
pipeline_utils.h
|
||||
asset_loader.cpp
|
||||
asset_loader.h
|
||||
light_manager.cpp
|
||||
light_manager.h
|
||||
gpu_resource_manager.cpp
|
||||
gpu_resource_manager.h
|
||||
nodes.cpp
|
||||
nodes.h
|
||||
ibl_helpers.cpp
|
||||
ibl_helpers.h)
|
||||
add_executable(model_render "model_render.cpp"
|
||||
"pipeline_utils.cpp"
|
||||
"pipeline_utils.h"
|
||||
"asset_loader.cpp"
|
||||
"asset_loader.h"
|
||||
"light_manager.cpp"
|
||||
"light_manager.h"
|
||||
"gpu_resource_manager.cpp"
|
||||
"gpu_resource_manager.h"
|
||||
"nodes.cpp"
|
||||
"nodes.h"
|
||||
"ibl_helpers.cpp"
|
||||
"ibl_helpers.h")
|
||||
|
||||
add_shader(model_render shader/model.vs.hlsl)
|
||||
add_shader(model_render shader/model.ps.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.ps.hlsl)
|
||||
add_shader(model_render shader/diffuse_irradiance.cs.hlsl)
|
||||
add_shader(model_render shader/prefilter.cs.hlsl)
|
||||
add_shader(model_render shader/brdf_lut.cs.hlsl)
|
||||
add_shader(model_render "shader/model.vs.hlsl")
|
||||
add_shader(model_render "shader/model.ps.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.ps.hlsl")
|
||||
add_shader(model_render "shader/diffuse_irradiance.cs.hlsl")
|
||||
add_shader(model_render "shader/prefilter.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 util_helper)
|
||||
|
|
|
|||
|
|
@ -10,15 +10,15 @@
|
|||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
|
||||
#include "asset_loader.h"
|
||||
#include "aster/core/buffer.h"
|
||||
#include "aster/core/device.h"
|
||||
#include "aster/core/image.h"
|
||||
|
||||
#include "EASTL/fixed_vector.h"
|
||||
#include "buffer.h"
|
||||
#include "device.h"
|
||||
#include "gpu_resource_manager.h"
|
||||
#include "helpers.h"
|
||||
#include "image.h"
|
||||
#include "asset_loader.h"
|
||||
|
||||
#include <EASTL/fixed_vector.h>
|
||||
#include <EASTL/hash_map.h>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "buffer.h"
|
||||
#include "global.h"
|
||||
#include "aster/aster.h"
|
||||
|
||||
#include "aster/core/buffer.h"
|
||||
|
||||
#include "gpu_resource_manager.h"
|
||||
#include "nodes.h"
|
||||
|
|
|
|||
|
|
@ -5,10 +5,11 @@
|
|||
|
||||
#include "gpu_resource_manager.h"
|
||||
|
||||
#include "buffer.h"
|
||||
#include "device.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>
|
||||
|
||||
|
|
@ -22,7 +23,7 @@ TextureManager::Init(const u32 maxCapacity)
|
|||
TextureHandle
|
||||
TextureManager::Commit(Texture *texture)
|
||||
{
|
||||
ERROR_IF(!texture || !texture->IsValid(), "Texture must be valid for commital")
|
||||
ERROR_IF(!texture || !texture->IsValid(), "Texture must be valid for committal")
|
||||
THEN_ABORT(-1);
|
||||
|
||||
if (m_FreeHead != GpuResourceHandle::INVALID_HANDLE)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "global.h"
|
||||
#include "aster/aster.h"
|
||||
|
||||
#include <EASTL/deque.h>
|
||||
#include <EASTL/vector_map.h>
|
||||
|
|
|
|||
|
|
@ -5,15 +5,17 @@
|
|||
|
||||
#include "ibl_helpers.h"
|
||||
|
||||
#include "EASTL/fixed_vector.h"
|
||||
#include "EASTL/tuple.h"
|
||||
#include "aster/core/device.h"
|
||||
#include "aster/core/image.h"
|
||||
|
||||
#include "asset_loader.h"
|
||||
#include "device.h"
|
||||
#include "gpu_resource_manager.h"
|
||||
#include "helpers.h"
|
||||
#include "image.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 DIFFUSE_IRRADIANCE_SHADER_FILE = "shader/diffuse_irradiance.cs.hlsl.spv";
|
||||
constexpr cstr PREFILTER_SHADER_FILE = "shader/prefilter.cs.hlsl.spv";
|
||||
|
|
@ -195,8 +197,8 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
|||
vk::PushConstantRange pcr = {
|
||||
.stageFlags = vk::ShaderStageFlagBits::eCompute,
|
||||
.offset = 0,
|
||||
.size = eastl::max(eastl::max(sizeof(SkyboxPushConstants), sizeof(BrdfLutPushConstants)),
|
||||
eastl::max(sizeof(DiffuseIrradiancePushConstants), sizeof(PrefilterPushConstants))),
|
||||
.size = Cast<u32>(eastl::max(eastl::max(sizeof(SkyboxPushConstants), sizeof(BrdfLutPushConstants)),
|
||||
eastl::max(sizeof(DiffuseIrradiancePushConstants), sizeof(PrefilterPushConstants)))),
|
||||
};
|
||||
|
||||
vk::PipelineLayout pipelineLayout;
|
||||
|
|
@ -252,7 +254,7 @@ CreateCubeFromHdrEnv(AssetLoader *assetLoader, vk::Queue computeQueue, const u32
|
|||
};
|
||||
|
||||
eastl::array<vk::Pipeline, computePipelineCreateInfo.size()> pipelines;
|
||||
AbortIfFailed(pDevice->m_Device.createComputePipelines(pDevice->m_PipelineCache, computePipelineCreateInfo.size(),
|
||||
AbortIfFailed(pDevice->m_Device.createComputePipelines(pDevice->m_PipelineCache, Cast<u32>(computePipelineCreateInfo.size()),
|
||||
computePipelineCreateInfo.data(), nullptr,
|
||||
pipelines.data()));
|
||||
|
||||
|
|
|
|||
|
|
@ -5,11 +5,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "global.h"
|
||||
#include "aster/aster.h"
|
||||
#include "gpu_resource_manager.h"
|
||||
|
||||
#include <EASTL/tuple.h>
|
||||
|
||||
struct Pipeline;
|
||||
struct Texture;
|
||||
struct TextureCube;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include "light_manager.h"
|
||||
|
||||
#include "buffer.h"
|
||||
#include "aster/core/buffer.h"
|
||||
#include "glm/ext/matrix_transform.hpp"
|
||||
|
||||
struct Light
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "global.h"
|
||||
#include "aster/aster.h"
|
||||
|
||||
// TODO: Separate files so you only import handles.
|
||||
#include "gpu_resource_manager.h"
|
||||
|
|
@ -66,7 +66,7 @@ struct LightManager
|
|||
// Using lower bit. Capacity can be directly a multiple of 2
|
||||
// Thus, range is up to MaxValue<u16>
|
||||
constexpr static u16 UPDATE_REQUIRED_BIT = 1;
|
||||
constexpr static u16 CAPACITY_MASK = ~(UPDATE_REQUIRED_BIT);
|
||||
constexpr static u16 CAPACITY_MASK = Cast<u16>(~UPDATE_REQUIRED_BIT);
|
||||
|
||||
LightHandle AddDirectional(const vec3 &direction, const vec3 &color, f32 intensity);
|
||||
LightHandle AddPoint(const vec3 &position, const vec3 &color, f32 radius, f32 intensity);
|
||||
|
|
|
|||
|
|
@ -3,16 +3,17 @@
|
|||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "buffer.h"
|
||||
#include "constants.h"
|
||||
#include "context.h"
|
||||
#include "device.h"
|
||||
#include "global.h"
|
||||
#include "image.h"
|
||||
#include "physical_device.h"
|
||||
#include "pipeline.h"
|
||||
#include "swapchain.h"
|
||||
#include "window.h"
|
||||
#include "aster/aster.h"
|
||||
|
||||
#include "aster/core/buffer.h"
|
||||
#include "aster/core/constants.h"
|
||||
#include "aster/core/context.h"
|
||||
#include "aster/core/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 "frame.h"
|
||||
#include "helpers.h"
|
||||
|
|
@ -133,10 +134,11 @@ main(int, char **)
|
|||
{
|
||||
MIN_LOG_LEVEL(Logger::LogType::eInfo);
|
||||
|
||||
Window window = {"ModelRender (Aster)", {INIT_WIDTH, INIT_HEIGHT}};
|
||||
Context context = {"ModelRender", VERSION};
|
||||
Window window = {"ModelRender (Aster)", &context, {INIT_WIDTH, INIT_HEIGHT}};
|
||||
Surface surface = {&context, &window, "Primary Surface"};
|
||||
|
||||
PhysicalDevices physicalDevices = {&window, &context};
|
||||
PhysicalDevices physicalDevices = {&surface, &context};
|
||||
PhysicalDevice deviceToUse = FindSuitableDevice(physicalDevices);
|
||||
|
||||
usize physicalDeviceOffsetAlignment = deviceToUse.m_DeviceProperties.limits.minUniformBufferOffsetAlignment;
|
||||
|
|
@ -173,7 +175,7 @@ main(int, char **)
|
|||
Device device = {&context, &deviceToUse, &enabledDeviceFeatures,
|
||||
{queueAllocation}, pipelineCacheData, "Primary Device"};
|
||||
vk::Queue graphicsQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
||||
Swapchain swapchain = {&window, &device, "Primary Chain"};
|
||||
Swapchain swapchain = {&surface, &device, window.GetSize(), "Primary Chain"};
|
||||
GpuResourceManager resourceManager = {&device, 1000};
|
||||
|
||||
AssetLoader assetLoader = {&resourceManager, graphicsQueue, queueAllocation.m_Family, queueAllocation.m_Family};
|
||||
|
|
@ -513,7 +515,7 @@ main(int, char **)
|
|||
cameraController.m_Camera.CalculateInverses();
|
||||
ubo.Write(&device, 0, sizeof cameraController.m_Camera, &cameraController.m_Camera);
|
||||
|
||||
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &window);
|
||||
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &surface, window.GetSize());
|
||||
|
||||
u32 imageIndex = currentFrame->m_ImageIdx;
|
||||
vk::Image currentSwapchainImage = swapchain.m_Images[imageIndex];
|
||||
|
|
@ -686,7 +688,7 @@ main(int, char **)
|
|||
};
|
||||
AbortIfFailed(graphicsQueue.submit(1, &submitInfo, currentFrame->m_FrameAvailableFence));
|
||||
|
||||
currentFrame->Present(graphicsQueue, &swapchain, &window);
|
||||
currentFrame->Present(graphicsQueue, &swapchain, &surface, window.GetSize());
|
||||
}
|
||||
|
||||
device.WaitIdle();
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "global.h"
|
||||
#include "aster/aster.h"
|
||||
|
||||
#include "EASTL/vector.h"
|
||||
#include <EASTL/vector.h>
|
||||
|
||||
struct Nodes
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@
|
|||
|
||||
#include "pipeline_utils.h"
|
||||
|
||||
#include "device.h"
|
||||
#include "aster/core/device.h"
|
||||
#include "aster/core/pipeline.h"
|
||||
|
||||
#include "gpu_resource_manager.h"
|
||||
#include "helpers.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -5,12 +5,12 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "global.h"
|
||||
#include "pipeline.h"
|
||||
#include "aster/aster.h"
|
||||
|
||||
struct GpuResourceManager;
|
||||
struct Swapchain;
|
||||
struct Device;
|
||||
struct Pipeline;
|
||||
|
||||
constexpr auto VERTEX_SHADER_FILE = "shader/model.vs.hlsl.spv";
|
||||
constexpr auto FRAGMENT_SHADER_FILE = "shader/model.ps.hlsl.spv";
|
||||
|
|
|
|||
|
|
@ -7,24 +7,24 @@ find_path(TINYGLTF_INCLUDE_DIRS "tiny_gltf.h")
|
|||
|
||||
find_package(EnTT REQUIRED CONFIG)
|
||||
|
||||
add_executable(scene_render main.cpp
|
||||
render_resource_manager.cpp render_resource_manager.h
|
||||
asset_loader.cpp asset_loader.h
|
||||
pipeline_utils.cpp pipeline_utils.h
|
||||
core_components.h
|
||||
ecs_adapter.h
|
||||
camera.h
|
||||
ibl_helpers.cpp ibl_helpers.h
|
||||
light_manager.cpp light_manager.h)
|
||||
add_executable(scene_render "main.cpp"
|
||||
"render_resource_manager.cpp" "render_resource_manager.h"
|
||||
"asset_loader.cpp" "asset_loader.h"
|
||||
"pipeline_utils.cpp" "pipeline_utils.h"
|
||||
"core_components.h"
|
||||
"ecs_adapter.h"
|
||||
"camera.h"
|
||||
"ibl_helpers.cpp" "ibl_helpers.h"
|
||||
"light_manager.cpp" "light_manager.h")
|
||||
|
||||
add_shader(scene_render shader/model.frag.glsl)
|
||||
add_shader(scene_render shader/model.vert.glsl)
|
||||
add_shader(scene_render shader/eqrect_to_cube.cs.hlsl)
|
||||
add_shader(scene_render shader/diffuse_irradiance.cs.hlsl)
|
||||
add_shader(scene_render shader/prefilter.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.frag.glsl)
|
||||
add_shader(scene_render "shader/model.frag.glsl")
|
||||
add_shader(scene_render "shader/model.vert.glsl")
|
||||
add_shader(scene_render "shader/eqrect_to_cube.cs.hlsl")
|
||||
add_shader(scene_render "shader/diffuse_irradiance.cs.hlsl")
|
||||
add_shader(scene_render "shader/prefilter.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.frag.glsl")
|
||||
|
||||
target_link_libraries(scene_render PRIVATE aster_core)
|
||||
target_link_libraries(scene_render PRIVATE util_helper)
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@
|
|||
|
||||
#include "asset_loader.h"
|
||||
|
||||
#include "buffer.h"
|
||||
#include "device.h"
|
||||
#include "image.h"
|
||||
#include "aster/core/buffer.h"
|
||||
#include "aster/core/device.h"
|
||||
#include "aster/core/image.h"
|
||||
|
||||
#include "core_components.h"
|
||||
#include "helpers.h"
|
||||
|
|
@ -753,8 +753,8 @@ AssetLoader::ProcessNode(tinygltf::Model *model, eastl::vector<vec4> *vertexPosi
|
|||
entities->push_back(entity);
|
||||
|
||||
m_Registry->emplace<CMesh>(entity, CMesh{
|
||||
.m_VertexPositionPtr = vertexOffset * sizeof vec4,
|
||||
.m_VertexDataPtr = vertexOffset * sizeof VertexData,
|
||||
.m_VertexPositionPtr = vertexOffset * sizeof(vec4),
|
||||
.m_VertexDataPtr = vertexOffset * sizeof(VertexData),
|
||||
.m_FirstIndex = indexOffset,
|
||||
.m_IndexCount = indexCount,
|
||||
});
|
||||
|
|
@ -764,7 +764,7 @@ AssetLoader::ProcessNode(tinygltf::Model *model, eastl::vector<vec4> *vertexPosi
|
|||
m_Registry->emplace<CParent<CDynamicTransform>>(entity, nodeRoot);
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -870,7 +870,7 @@ AssetLoader::LoadModelToGpu(cstr path, cstr name)
|
|||
}
|
||||
else if (material->alphaMode == "MASK")
|
||||
{
|
||||
alphaBlendValue = material->alphaCutoff;
|
||||
alphaBlendValue = Cast<f32>(material->alphaCutoff);
|
||||
}
|
||||
|
||||
materials.push_back({
|
||||
|
|
@ -1080,4 +1080,4 @@ AssetLoader::operator=(AssetLoader &&other) noexcept
|
|||
m_TransferQueueIndex = other.m_TransferQueueIndex;
|
||||
m_GraphicsQueueIndex = other.m_GraphicsQueueIndex;
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "global.h"
|
||||
#include "aster/aster.h"
|
||||
|
||||
#include "buffer.h"
|
||||
#include "aster/core/buffer.h"
|
||||
#include "render_resource_manager.h"
|
||||
|
||||
#include "ecs_adapter.h"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "global.h"
|
||||
#include "aster/aster.h"
|
||||
|
||||
struct Camera
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "global.h"
|
||||
#include "aster/aster.h"
|
||||
|
||||
template <typename TComponent>
|
||||
struct CDirty
|
||||
|
|
|
|||
|
|
@ -5,15 +5,17 @@
|
|||
|
||||
#include "ibl_helpers.h"
|
||||
|
||||
#include "EASTL/fixed_vector.h"
|
||||
#include "EASTL/tuple.h"
|
||||
#include "aster/core/device.h"
|
||||
#include "aster/core/image.h"
|
||||
|
||||
#include "asset_loader.h"
|
||||
#include "device.h"
|
||||
#include "render_resource_manager.h"
|
||||
#include "helpers.h"
|
||||
#include "image.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 DIFFUSE_IRRADIANCE_SHADER_FILE = "shader/diffuse_irradiance.cs.hlsl.spv";
|
||||
constexpr cstr PREFILTER_SHADER_FILE = "shader/prefilter.cs.hlsl.spv";
|
||||
|
|
@ -195,8 +197,8 @@ CreateEnvironment(AssetLoader *assetLoader, vk::Queue computeQueue, const u32 cu
|
|||
vk::PushConstantRange pcr = {
|
||||
.stageFlags = vk::ShaderStageFlagBits::eCompute,
|
||||
.offset = 0,
|
||||
.size = eastl::max(eastl::max(sizeof(SkyboxPushConstants), sizeof(BrdfLutPushConstants)),
|
||||
eastl::max(sizeof(DiffuseIrradiancePushConstants), sizeof(PrefilterPushConstants))),
|
||||
.size = Cast<u32>(eastl::max(eastl::max(sizeof(SkyboxPushConstants), sizeof(BrdfLutPushConstants)),
|
||||
eastl::max(sizeof(DiffuseIrradiancePushConstants), sizeof(PrefilterPushConstants)))),
|
||||
};
|
||||
|
||||
vk::PipelineLayout pipelineLayout;
|
||||
|
|
@ -252,7 +254,7 @@ CreateEnvironment(AssetLoader *assetLoader, vk::Queue computeQueue, const u32 cu
|
|||
};
|
||||
|
||||
eastl::array<vk::Pipeline, computePipelineCreateInfo.size()> pipelines;
|
||||
AbortIfFailed(pDevice->m_Device.createComputePipelines(pDevice->m_PipelineCache, computePipelineCreateInfo.size(),
|
||||
AbortIfFailed(pDevice->m_Device.createComputePipelines(pDevice->m_PipelineCache, Cast<u32>(computePipelineCreateInfo.size()),
|
||||
computePipelineCreateInfo.data(), nullptr,
|
||||
pipelines.data()));
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "global.h"
|
||||
#include "aster/aster.h"
|
||||
#include "render_resource_manager.h"
|
||||
|
||||
struct Pipeline;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include "light_manager.h"
|
||||
|
||||
#include "buffer.h"
|
||||
#include "aster/core/buffer.h"
|
||||
#include "ibl_helpers.h"
|
||||
#include "glm/ext/matrix_transform.hpp"
|
||||
|
||||
|
|
@ -239,12 +239,11 @@ LightManager::Update()
|
|||
const u16 requiredBufferCapacity = eastl::min(Cast<u16>(m_Lights.capacity()), MAX_LIGHTS);
|
||||
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_ResourceManager->Release(m_MetaInfo.m_LightBuffer);
|
||||
m_MetaInfo.m_LightBuffer = m_ResourceManager->Commit(&newBuffer);
|
||||
m_MetaInfo.m_LightBuffer =
|
||||
m_ResourceManager->CreateStorageBuffer(requiredBufferCapacity * sizeof m_Lights[0], "Light Buffer");
|
||||
}
|
||||
if (m_GpuBufferCapacity_ & UPDATE_REQUIRED_BIT)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "global.h"
|
||||
#include "aster/aster.h"
|
||||
|
||||
// TODO: Separate files so you only import handles.
|
||||
#include "render_resource_manager.h"
|
||||
|
|
@ -73,7 +73,7 @@ struct LightManager
|
|||
// Using lower bit. Capacity can be directly a multiple of 2
|
||||
// Thus, range is up to MaxValue<u16>
|
||||
constexpr static u16 UPDATE_REQUIRED_BIT = 1;
|
||||
constexpr static u16 CAPACITY_MASK = ~(UPDATE_REQUIRED_BIT);
|
||||
constexpr static u16 CAPACITY_MASK = Cast<u16>(~UPDATE_REQUIRED_BIT);
|
||||
|
||||
LightHandle AddDirectional(const vec3 &direction, const vec3 &color, f32 intensity);
|
||||
LightHandle AddPoint(const vec3 &position, const vec3 &color, f32 radius, f32 intensity);
|
||||
|
|
|
|||
|
|
@ -3,13 +3,16 @@
|
|||
// Copyright (c) 2020-2024 Anish Bhobe
|
||||
// =============================================
|
||||
|
||||
#include "context.h"
|
||||
#include "device.h"
|
||||
#include "aster/core/context.h"
|
||||
#include "aster/core/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 "physical_device.h"
|
||||
#include "render_resource_manager.h"
|
||||
#include "swapchain.h"
|
||||
#include "window.h"
|
||||
|
||||
#include "asset_loader.h"
|
||||
#include "camera.h"
|
||||
|
|
@ -19,8 +22,6 @@
|
|||
#include "ecs_adapter.h"
|
||||
#include "frame.h"
|
||||
#include "ibl_helpers.h"
|
||||
#include "image.h"
|
||||
#include "pipeline.h"
|
||||
|
||||
#include "pipeline_utils.h"
|
||||
|
||||
|
|
@ -37,10 +38,11 @@ main(int, char *[])
|
|||
{
|
||||
MIN_LOG_LEVEL(Logger::LogType::eInfo);
|
||||
|
||||
Window window = {"Scene Render [WIP] (Aster)", {INIT_WIDTH, INIT_HEIGHT}};
|
||||
Context context = {"Scene Render [WIP]", VERSION};
|
||||
Window window = {"Scene Render [WIP] (Aster)", &context, {INIT_WIDTH, INIT_HEIGHT}};
|
||||
Surface surface = {&context, &window, "Primary Surface"};
|
||||
|
||||
PhysicalDevices physicalDevices = {&window, &context};
|
||||
PhysicalDevices physicalDevices = {&surface, &context};
|
||||
PhysicalDevice deviceToUse = FindSuitableDevice(physicalDevices);
|
||||
|
||||
vk::Extent2D internalResolution = {1920, 1080};
|
||||
|
|
@ -91,7 +93,7 @@ main(int, char *[])
|
|||
Device device = {&context, &deviceToUse, &enabledDeviceFeatures,
|
||||
{queueAllocation}, pipelineCacheData, "Primary Device"};
|
||||
vk::Queue graphicsQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
||||
Swapchain swapchain = {&window, &device, "Primary Chain"};
|
||||
Swapchain swapchain = {&surface, &device, window.GetSize(), "Primary Chain"};
|
||||
|
||||
RenderResourceManager resourceManager = {&device, 1024};
|
||||
EcsRegistry registry;
|
||||
|
|
@ -112,7 +114,7 @@ main(int, char *[])
|
|||
|
||||
eastl::vector<Model> models;
|
||||
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;
|
||||
constexpr usize uboLightManagerOffset = sizeof cameraController.m_Camera;
|
||||
|
|
@ -348,14 +350,15 @@ main(int, char *[])
|
|||
{
|
||||
Time::Update();
|
||||
|
||||
//u32 index = 0;
|
||||
//for (auto [entity, dynTrans] : rootModel.each())
|
||||
// u32 index = 0;
|
||||
// for (auto [entity, dynTrans] : rootModel.each())
|
||||
//{
|
||||
// dynTrans.m_Rotation =
|
||||
// glm::rotate(dynTrans.m_Rotation, Cast<f32>(30_deg * (++index) * Time::m_Delta), vec3{0.0f, 1.0f, 0.0f});
|
||||
//}
|
||||
// dynTrans.m_Rotation =
|
||||
// glm::rotate(dynTrans.m_Rotation, Cast<f32>(30_deg * (++index) * Time::m_Delta), vec3{0.0f, 1.0f,
|
||||
// 0.0f});
|
||||
// }
|
||||
|
||||
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &window);
|
||||
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &surface, window.GetSize());
|
||||
|
||||
u32 imageIndex = currentFrame->m_ImageIdx;
|
||||
vk::Image currentSwapchainImage = swapchain.m_Images[imageIndex];
|
||||
|
|
@ -552,7 +555,7 @@ main(int, char *[])
|
|||
};
|
||||
AbortIfFailed(graphicsQueue.submit(1, &submitInfo, currentFrame->m_FrameAvailableFence));
|
||||
|
||||
currentFrame->Present(graphicsQueue, &swapchain, &window);
|
||||
currentFrame->Present(graphicsQueue, &swapchain, &surface, window.GetSize());
|
||||
}
|
||||
|
||||
device.WaitIdle();
|
||||
|
|
|
|||
|
|
@ -5,7 +5,8 @@
|
|||
|
||||
#include "pipeline_utils.h"
|
||||
|
||||
#include "device.h"
|
||||
#include "aster/core/device.h"
|
||||
|
||||
#include "render_resource_manager.h"
|
||||
#include "helpers.h"
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "global.h"
|
||||
#include "pipeline.h"
|
||||
#include "aster/aster.h"
|
||||
#include "aster/core/pipeline.h"
|
||||
|
||||
struct RenderResourceManager;
|
||||
struct Swapchain;
|
||||
|
|
|
|||
|
|
@ -5,10 +5,11 @@
|
|||
|
||||
#include "render_resource_manager.h"
|
||||
|
||||
#include "buffer.h"
|
||||
#include "device.h"
|
||||
#include "aster/core/buffer.h"
|
||||
#include "aster/core/device.h"
|
||||
#include "aster/core/image.h"
|
||||
|
||||
#include "helpers.h"
|
||||
#include "image.h"
|
||||
|
||||
#include <EASTL/array.h>
|
||||
|
||||
|
|
@ -96,49 +97,51 @@ void
|
|||
BufferManager::Init(const u32 maxCapacity)
|
||||
{
|
||||
m_MaxCapacity = maxCapacity;
|
||||
m_FreeHead = GpuResourceHandle::INVALID_HANDLE;
|
||||
m_FreeHead = 0;
|
||||
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
|
||||
BufferManager::Commit(StorageBuffer *buffer)
|
||||
BufferManager::Allocate(const Device *device, const u32 bufferSize, const cstr name)
|
||||
{
|
||||
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")
|
||||
THEN_ABORT(-1);
|
||||
|
||||
if (m_FreeHead != GpuResourceHandle::INVALID_HANDLE)
|
||||
{
|
||||
const u32 index = m_FreeHead;
|
||||
ERROR_IF(m_FreeHead == GpuResourceHandle::INVALID_HANDLE, "Out of buffers")
|
||||
THEN_ABORT(-1);
|
||||
|
||||
StorageBuffer *allocatedBuffer = &m_Buffers[index];
|
||||
const u32 index = m_FreeHead;
|
||||
|
||||
assert(!allocatedBuffer->IsValid());
|
||||
m_FreeHead = *Recast<u32 *>(allocatedBuffer);
|
||||
Buffer *allocatedBuffer = &m_Buffers[index];
|
||||
|
||||
// Ensure it is copyable.
|
||||
static_assert(std::is_trivially_copyable_v<StorageBuffer>);
|
||||
*allocatedBuffer = *buffer;
|
||||
assert(!allocatedBuffer->IsValid());
|
||||
m_FreeHead = *Recast<u32 *>(allocatedBuffer);
|
||||
|
||||
// Take ownership of the buffer.
|
||||
buffer->m_Size_ &= ~StorageBuffer::OWNED_BIT;
|
||||
// Ensure it is copyable.
|
||||
static_assert(std::is_trivially_copyable_v<StorageBuffer>);
|
||||
*allocatedBuffer = *buffer;
|
||||
|
||||
return {index};
|
||||
}
|
||||
// Take ownership of the buffer.
|
||||
buffer->m_Size_ &= ~StorageBuffer::OWNED_BIT;
|
||||
|
||||
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);
|
||||
return {index};
|
||||
}
|
||||
|
||||
StorageBuffer *
|
||||
|
|
@ -146,7 +149,7 @@ BufferManager::Fetch(const BufferHandle handle)
|
|||
{
|
||||
assert(!handle.IsInvalid());
|
||||
|
||||
return &m_Buffers[handle.m_Index];
|
||||
return Recast<StorageBuffer *>(&m_Buffers[handle.m_Index]);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -154,7 +157,7 @@ BufferManager::Release(const Device *device, const BufferHandle handle)
|
|||
{
|
||||
assert(!handle.IsInvalid());
|
||||
|
||||
StorageBuffer *allocatedBuffer = &m_Buffers[handle.m_Index];
|
||||
Buffer *allocatedBuffer = &m_Buffers[handle.m_Index];
|
||||
allocatedBuffer->Destroy(device);
|
||||
|
||||
assert(!allocatedBuffer->IsValid());
|
||||
|
|
@ -166,10 +169,19 @@ BufferManager::Release(const Device *device, const BufferHandle handle)
|
|||
void
|
||||
BufferManager::Destroy(const Device *device)
|
||||
{
|
||||
for (auto &buffer : m_Buffers)
|
||||
if (!m_Buffers)
|
||||
{
|
||||
buffer.Destroy(device);
|
||||
WARN("Double Deletion");
|
||||
return;
|
||||
}
|
||||
|
||||
Buffer *pBegin = m_Buffers;
|
||||
const Buffer *pEnd = m_Buffers + m_MaxCapacity;
|
||||
while (pBegin != pEnd)
|
||||
{
|
||||
(pBegin++)->Destroy(device);
|
||||
}
|
||||
delete[] Take(m_Buffers);
|
||||
}
|
||||
|
||||
StorageTextureHandle
|
||||
|
|
@ -303,7 +315,7 @@ VirtualizedBufferPool::InitIndex(const Device *device, usize bufferMaxSize)
|
|||
}
|
||||
|
||||
void
|
||||
VirtualizedBufferPool::UpdateToGpu(const Device *device)
|
||||
VirtualizedBufferPool::UpdateToGpu(const Device *)
|
||||
{
|
||||
// Unrequired until adding the non-ReBAR support.
|
||||
}
|
||||
|
|
@ -405,9 +417,39 @@ RenderResourceManager::WriteInfo::WriteInfo(vk::BufferView info)
|
|||
}
|
||||
|
||||
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{
|
||||
.buffer = storageBuffer->m_Buffer,
|
||||
|
|
@ -748,7 +790,7 @@ RenderResourceManager::RenderResourceManager(Device *device, u16 maxSize, bool u
|
|||
m_Device->SetName(m_DescriptorSet, "Bindless Set");
|
||||
|
||||
// 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()
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "global.h"
|
||||
#include "aster/aster.h"
|
||||
|
||||
#include <EASTL/deque.h>
|
||||
#include <EASTL/vector_map.h>
|
||||
|
|
@ -75,12 +75,13 @@ struct TextureManager
|
|||
|
||||
struct BufferManager
|
||||
{
|
||||
eastl::vector<StorageBuffer> m_Buffers;
|
||||
Buffer* m_Buffers;
|
||||
u32 m_MaxCapacity;
|
||||
u32 m_FreeHead;
|
||||
|
||||
void Init(u32 maxCapacity);
|
||||
BufferHandle Commit(StorageBuffer *buffer);
|
||||
BufferHandle Allocate(const Device *device, u32 bufferSize, cstr name);
|
||||
BufferHandle Commit_(StorageBuffer *buffer);
|
||||
StorageBuffer *Fetch(BufferHandle handle);
|
||||
void Release(const Device *device, BufferHandle handle);
|
||||
void Destroy(const Device *device);
|
||||
|
|
@ -178,6 +179,7 @@ struct RenderResourceManager
|
|||
SamplerManager m_SamplerManager;
|
||||
|
||||
void EraseWrites(u32 handleIndex, HandleType handleType);
|
||||
BufferHandle Commit_(StorageBuffer *storageBuffer); // Commit to GPU and take Ownership
|
||||
|
||||
public:
|
||||
Device *m_Device;
|
||||
|
|
@ -198,7 +200,7 @@ struct RenderResourceManager
|
|||
|
||||
bool m_UseBufferAddr;
|
||||
|
||||
BufferHandle Commit(StorageBuffer *storageBuffer); // Commit to GPU and take Ownership
|
||||
BufferHandle CreateStorageBuffer(u32 bufferSize, cstr name); // Allocate a new buffer and commit to GPU.
|
||||
void Write(BufferHandle handle, usize offset, usize size, const void *data); // Write to buffer
|
||||
void Release(BufferHandle handle); // Release and Destroy
|
||||
void Release(StorageBuffer *storageBuffer, BufferHandle handle); // Release and Return
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue