Compare commits
4 Commits
e541be389d
...
07f3a237b5
| Author | SHA1 | Date |
|---|---|---|
|
|
07f3a237b5 | |
|
|
ef6ca6a79e | |
|
|
52b3c671c6 | |
|
|
b48fb3168d |
|
|
@ -0,0 +1,4 @@
|
||||||
|
*.bin filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.png filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.glb filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.jpg filter=lfs diff=lfs merge=lfs -text
|
||||||
55
README.md
55
README.md
|
|
@ -6,42 +6,43 @@ A Vulkan based renderer created with Vulkan 1.3 in C++.
|
||||||
|
|
||||||
- [ ] Forward Rendering
|
- [ ] Forward Rendering
|
||||||
- [ ] glTF 2.0 Support
|
- [ ] glTF 2.0 Support
|
||||||
- [ ] Load Vertex Data
|
- [ ] Load Vertex Data
|
||||||
- [ ] Load Material Data
|
- [ ] Load Material Data
|
||||||
- [ ] Load Animation Data
|
- [ ] Load Animation Data
|
||||||
- [ ] Load Camera
|
- [ ] Load Camera
|
||||||
- [ ] Load Lights
|
- [ ] Load Lights
|
||||||
- [ ] Support Specular Materials
|
- [ ] Support Specular Materials
|
||||||
|
- [ ] Bindless Descriptors
|
||||||
- [ ] PBR
|
- [ ] PBR
|
||||||
- [ ] IBL
|
- [ ] IBL
|
||||||
- [ ] Shadows v1
|
- [ ] Shadows v1
|
||||||
- [ ] Omnidirectional Cubemap Shadows
|
- [ ] Omnidirectional Cubemap Shadows
|
||||||
- [ ] Spot Lights
|
- [ ] Spot Lights
|
||||||
- [ ] Directional Shadows
|
- [ ] Directional Shadows
|
||||||
- [ ] Cascaded Shadows
|
- [ ] Cascaded Shadows
|
||||||
- [ ] PCF
|
- [ ] PCF
|
||||||
- [ ] Simplified Descriptor Creation Pipeline
|
- [ ] Simplified Descriptor Creation Pipeline
|
||||||
- [ ] Deferred Rendering
|
- [ ] Deferred Rendering
|
||||||
- [ ] Ambient Occlusion
|
- [ ] Ambient Occlusion
|
||||||
- [ ] SSAO
|
- [ ] SSAO
|
||||||
- [ ] HBAO
|
- [ ] HBAO
|
||||||
- [ ] VXAO/SDFAO
|
- [ ] VXAO/SDFAO
|
||||||
- [ ] RTX AO
|
- [ ] RTX AO
|
||||||
- [ ] Reflection
|
- [ ] Reflection
|
||||||
- [ ] ScreenSpace Reflection (SSR)
|
- [ ] ScreenSpace Reflection (SSR)
|
||||||
- [ ] Cubemap/Probe Reflection
|
- [ ] Cubemap/Probe Reflection
|
||||||
- [ ] Forward+ Rendering
|
- [ ] Forward+ Rendering
|
||||||
- [ ] Global Illumination
|
- [ ] Global Illumination
|
||||||
- [ ] Precomputed Radiance Transfer
|
- [ ] Precomputed Radiance Transfer
|
||||||
- [ ] Voxel Cone Tracing
|
- [ ] Voxel Cone Tracing
|
||||||
- [ ] SDFGI
|
- [ ] SDFGI
|
||||||
- [ ] RTXGI
|
- [ ] RTXGI
|
||||||
- [ ] Shadows v2
|
- [ ] Shadows v2
|
||||||
- [ ] Omnidirectional Dual Paraboloid Shadows
|
- [ ] Omnidirectional Dual Paraboloid Shadows
|
||||||
- [ ] Perspective Shadow Mapping
|
- [ ] Perspective Shadow Mapping
|
||||||
- [ ] RTX Shadows
|
- [ ] RTX Shadows
|
||||||
- [ ] Animation
|
- [ ] Animation
|
||||||
- [ ] Skeletal Animation
|
- [ ] Skeletal Animation
|
||||||
- [ ] TBD
|
- [ ] TBD
|
||||||
- [ ] Particle Effects
|
- [ ] Particle Effects
|
||||||
- [ ] Full Path Tracing
|
- [ ] Full Path Tracing
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,9 @@ set(SOURCE_FILES
|
||||||
device.cpp
|
device.cpp
|
||||||
swapchain.cpp
|
swapchain.cpp
|
||||||
pipeline.cpp
|
pipeline.cpp
|
||||||
buffer.cpp)
|
buffer.cpp
|
||||||
|
image.cpp
|
||||||
|
image.h)
|
||||||
|
|
||||||
add_library(aster_core STATIC ${SOURCE_FILES} ${HEADER_FILES})
|
add_library(aster_core STATIC ${SOURCE_FILES} ${HEADER_FILES})
|
||||||
set_property(TARGET aster_core PROPERTY CXX_STANDARD 20)
|
set_property(TARGET aster_core PROPERTY CXX_STANDARD 20)
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "buffer.h"
|
#include "buffer.h"
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "device.h"
|
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
|
||||||
struct Device;
|
struct Device;
|
||||||
|
|
|
||||||
|
|
@ -122,3 +122,19 @@ Context::~Context()
|
||||||
|
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Context::Context(Context &&other) noexcept
|
||||||
|
: m_Instance(Take(other.m_Instance))
|
||||||
|
, m_DebugMessenger(Take(other.m_DebugMessenger))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,4 +23,10 @@ struct Context final
|
||||||
// Ctor/Dtor
|
// Ctor/Dtor
|
||||||
Context(cstr appName, Version version, bool enableValidation = true);
|
Context(cstr appName, Version version, bool enableValidation = true);
|
||||||
~Context();
|
~Context();
|
||||||
|
|
||||||
|
// Move
|
||||||
|
Context(Context &&other) noexcept;
|
||||||
|
Context &operator=(Context &&other) noexcept;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(Context);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -108,4 +108,24 @@ Device::GetQueue(const u32 familyIndex, const u32 queueIndex) const
|
||||||
vk::Queue queue;
|
vk::Queue queue;
|
||||||
m_Device.getQueue(familyIndex, queueIndex, &queue);
|
m_Device.getQueue(familyIndex, queueIndex, &queue);
|
||||||
return queue;
|
return queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
@ -28,13 +28,20 @@ struct Device final
|
||||||
vk::Device m_Device = nullptr;
|
vk::Device m_Device = nullptr;
|
||||||
VmaAllocator m_Allocator = nullptr;
|
VmaAllocator m_Allocator = nullptr;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
requires vk::isVulkanHandleType<T>::value void SetName(const T &object, cstr name) const;
|
||||||
|
[[nodiscard]] vk::Queue GetQueue(u32 familyIndex, u32 queueIndex) const;
|
||||||
|
|
||||||
|
// Ctor/Dtor
|
||||||
Device(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures,
|
Device(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures,
|
||||||
const eastl::vector<QueueAllocation> &queueAllocations, NameString &&name);
|
const eastl::vector<QueueAllocation> &queueAllocations, NameString &&name);
|
||||||
~Device();
|
~Device();
|
||||||
|
|
||||||
template <typename T>
|
// Move
|
||||||
requires vk::isVulkanHandleType<T>::value void SetName(const T &object, cstr name) const;
|
Device(Device &&other) noexcept;
|
||||||
[[nodiscard]] vk::Queue GetQueue(u32 familyIndex, u32 queueIndex) const;
|
Device &operator=(Device &&other) noexcept;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(Device);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,11 @@ constexpr u32 ASTER_API_VERSION = VK_API_VERSION_1_3;
|
||||||
|
|
||||||
#define CODE_LOC " @ " __FILE__ ":" VULKAN_HPP_STRINGIFY(__LINE__)
|
#define CODE_LOC " @ " __FILE__ ":" VULKAN_HPP_STRINGIFY(__LINE__)
|
||||||
|
|
||||||
#define FORCE_TODO static_assert(false)
|
#define DISALLOW_COPY_AND_ASSIGN(CLASS_NAME) \
|
||||||
|
CLASS_NAME(const CLASS_NAME &other) = delete; \
|
||||||
|
CLASS_NAME &operator=(const CLASS_NAME &other) = delete
|
||||||
|
|
||||||
|
#define Take(ELEMENT) eastl::exchange(ELEMENT, {})
|
||||||
|
|
||||||
[[nodiscard]] inline bool
|
[[nodiscard]] inline bool
|
||||||
Failed(const vk::Result result)
|
Failed(const vk::Result result)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: image.cpp
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#include "image.h"
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
Image::Destroy(const Device *device)
|
||||||
|
{
|
||||||
|
if (!m_Image)
|
||||||
|
return;
|
||||||
|
|
||||||
|
vmaDestroyImage(device->m_Allocator, m_Image, m_Allocation);
|
||||||
|
m_Image = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Texture::Init(const Device *device, const vk::Extent2D extent, const bool isMipmapped, const cstr name)
|
||||||
|
{
|
||||||
|
const u32 mipLevels = isMipmapped ? 1 + Cast<u32>(floor(log2(eastl::max(extent.width, extent.height)))) : 1;
|
||||||
|
vk::ImageCreateInfo imageCreateInfo = {
|
||||||
|
.imageType = vk::ImageType::e2D,
|
||||||
|
.format = vk::Format::eR8G8B8A8Srgb,
|
||||||
|
.extent = {.width = extent.width, .height = extent.height, .depth = 1},
|
||||||
|
.mipLevels = mipLevels,
|
||||||
|
.arrayLayers = 1,
|
||||||
|
.samples = vk::SampleCountFlagBits::e1,
|
||||||
|
.tiling = vk::ImageTiling::eOptimal,
|
||||||
|
.usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst,
|
||||||
|
.sharingMode = vk::SharingMode::eExclusive,
|
||||||
|
.initialLayout = vk::ImageLayout::eUndefined,
|
||||||
|
};
|
||||||
|
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||||
|
.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT,
|
||||||
|
.usage = VMA_MEMORY_USAGE_AUTO,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkImage image;
|
||||||
|
VmaAllocation allocation;
|
||||||
|
auto result = Cast<vk::Result>(vmaCreateImage(device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||||
|
&allocationCreateInfo, &image, &allocation, nullptr));
|
||||||
|
ERROR_IF(Failed(result), "Could not allocate buffer. Cause: {}", result) THEN_ABORT(result);
|
||||||
|
|
||||||
|
m_Image = image;
|
||||||
|
m_Allocation = allocation;
|
||||||
|
m_Extent = {extent.width, extent.height, 1};
|
||||||
|
|
||||||
|
device->SetName(m_Image, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
DepthImage::Init(const Device *device, vk::Extent2D extent, cstr name)
|
||||||
|
{
|
||||||
|
vk::ImageCreateInfo imageCreateInfo = {
|
||||||
|
.imageType = vk::ImageType::e2D,
|
||||||
|
.format = vk::Format::eD32Sfloat,
|
||||||
|
.extent = {.width = extent.width, .height = extent.height, .depth = 1},
|
||||||
|
.mipLevels = 1,
|
||||||
|
.arrayLayers = 1,
|
||||||
|
.samples = vk::SampleCountFlagBits::e1,
|
||||||
|
.tiling = vk::ImageTiling::eOptimal,
|
||||||
|
.usage = vk::ImageUsageFlagBits::eDepthStencilAttachment,
|
||||||
|
.sharingMode = vk::SharingMode::eExclusive,
|
||||||
|
.initialLayout = vk::ImageLayout::eUndefined,
|
||||||
|
};
|
||||||
|
constexpr VmaAllocationCreateInfo allocationCreateInfo = {
|
||||||
|
.flags = VMA_ALLOCATION_CREATE_DEDICATED_MEMORY_BIT,
|
||||||
|
.usage = VMA_MEMORY_USAGE_AUTO,
|
||||||
|
};
|
||||||
|
|
||||||
|
VkImage image;
|
||||||
|
VmaAllocation allocation;
|
||||||
|
auto result = Cast<vk::Result>(vmaCreateImage(device->m_Allocator, Recast<VkImageCreateInfo *>(&imageCreateInfo),
|
||||||
|
&allocationCreateInfo, &image, &allocation, nullptr));
|
||||||
|
ERROR_IF(Failed(result), "Could not allocate buffer. Cause: {}", result) THEN_ABORT(result);
|
||||||
|
|
||||||
|
m_Image = image;
|
||||||
|
m_Allocation = allocation;
|
||||||
|
m_Extent = {extent.width, extent.height, 1};
|
||||||
|
|
||||||
|
device->SetName(m_Image, name);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: image.h
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
|
||||||
|
struct Device;
|
||||||
|
|
||||||
|
struct Image
|
||||||
|
{
|
||||||
|
vk::Image m_Image = nullptr;
|
||||||
|
VmaAllocation m_Allocation = nullptr;
|
||||||
|
vk::Extent3D m_Extent;
|
||||||
|
usize m_Size = 0;
|
||||||
|
|
||||||
|
void Destroy(const Device *device);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Texture : Image
|
||||||
|
{
|
||||||
|
void Init(const Device *device, vk::Extent2D extent, bool isMipmapped, cstr name = nullptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DepthImage : Image
|
||||||
|
{
|
||||||
|
void Init(const Device *device, vk::Extent2D extent, cstr name = nullptr);
|
||||||
|
};
|
||||||
|
|
@ -37,7 +37,7 @@ GetSurfaceFormats(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface);
|
||||||
[[nodiscard]] eastl::vector<vk::PresentModeKHR>
|
[[nodiscard]] eastl::vector<vk::PresentModeKHR>
|
||||||
GetSurfacePresentModes(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface);
|
GetSurfacePresentModes(vk::PhysicalDevice physicalDevice, vk::SurfaceKHR surface);
|
||||||
|
|
||||||
struct PhysicalDevice
|
struct PhysicalDevice final
|
||||||
{
|
{
|
||||||
vk::PhysicalDevice m_PhysicalDevice;
|
vk::PhysicalDevice m_PhysicalDevice;
|
||||||
vk::PhysicalDeviceProperties m_DeviceProperties;
|
vk::PhysicalDeviceProperties m_DeviceProperties;
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
Swapchain::Swapchain(const Window *window, const Device *device, NameString &&name)
|
Swapchain::Swapchain(const Window *window, const Device *device, NameString &&name)
|
||||||
: m_Device(device)
|
: m_Device(device)
|
||||||
, m_Name(std::move(name))
|
, m_Name(std::move(name))
|
||||||
|
, m_Format(vk::Format::eUndefined)
|
||||||
{
|
{
|
||||||
this->Create(window);
|
this->Create(window);
|
||||||
}
|
}
|
||||||
|
|
@ -21,6 +22,32 @@ Swapchain::~Swapchain()
|
||||||
this->Cleanup();
|
this->Cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Swapchain::Swapchain(Swapchain &&other) noexcept
|
||||||
|
: m_Device(other.m_Device)
|
||||||
|
, m_Swapchain(Take(other.m_Swapchain))
|
||||||
|
, m_Name(std::move(other.m_Name))
|
||||||
|
, m_Extent(other.m_Extent)
|
||||||
|
, m_Format(other.m_Format)
|
||||||
|
, m_Images(std::move(other.m_Images))
|
||||||
|
, m_ImageViews(std::move(other.m_ImageViews))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Swapchain &
|
||||||
|
Swapchain::operator=(Swapchain &&other) noexcept
|
||||||
|
{
|
||||||
|
if (this == &other)
|
||||||
|
return *this;
|
||||||
|
m_Device = other.m_Device;
|
||||||
|
m_Swapchain = Take(other.m_Swapchain);
|
||||||
|
m_Name = std::move(other.m_Name);
|
||||||
|
m_Extent = other.m_Extent;
|
||||||
|
m_Format = other.m_Format;
|
||||||
|
m_Images = std::move(other.m_Images);
|
||||||
|
m_ImageViews = std::move(other.m_ImageViews);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Swapchain::Create(const Window *window)
|
Swapchain::Create(const Window *window)
|
||||||
{
|
{
|
||||||
|
|
@ -150,6 +177,17 @@ Swapchain::Create(const Window *window)
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG("Swapchain {} Image Views created.", m_Name);
|
DEBUG("Swapchain {} Image Views created.", m_Name);
|
||||||
|
|
||||||
|
for (auto &callback : m_ResizeCallbacks)
|
||||||
|
{
|
||||||
|
callback(m_Extent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Swapchain::RegisterResizeCallback(FnResizeCallback &&callback)
|
||||||
|
{
|
||||||
|
m_ResizeCallbacks.emplace_back(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ struct Device;
|
||||||
|
|
||||||
struct Swapchain final
|
struct Swapchain final
|
||||||
{
|
{
|
||||||
|
using FnResizeCallback = eastl::function<void(vk::Extent2D)>;
|
||||||
|
|
||||||
const Device *m_Device;
|
const Device *m_Device;
|
||||||
vk::SwapchainKHR m_Swapchain;
|
vk::SwapchainKHR m_Swapchain;
|
||||||
NameString m_Name;
|
NameString m_Name;
|
||||||
|
|
@ -23,9 +25,20 @@ struct Swapchain final
|
||||||
eastl::fixed_vector<vk::Image, 4> m_Images;
|
eastl::fixed_vector<vk::Image, 4> m_Images;
|
||||||
eastl::fixed_vector<vk::ImageView, 4> m_ImageViews;
|
eastl::fixed_vector<vk::ImageView, 4> m_ImageViews;
|
||||||
|
|
||||||
|
eastl::vector<FnResizeCallback> m_ResizeCallbacks;
|
||||||
|
|
||||||
|
void Create(const Window *window);
|
||||||
|
void RegisterResizeCallback(FnResizeCallback &&callback);
|
||||||
|
|
||||||
|
// Ctor/Dtor
|
||||||
Swapchain(const Window *window, const Device *device, NameString &&name);
|
Swapchain(const Window *window, const Device *device, NameString &&name);
|
||||||
~Swapchain();
|
~Swapchain();
|
||||||
void Create(const Window *window);
|
|
||||||
|
// Move
|
||||||
|
Swapchain(Swapchain &&other) noexcept;
|
||||||
|
Swapchain &operator=(Swapchain &&other) noexcept;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(Swapchain);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Cleanup();
|
void Cleanup();
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ Window::~Window()
|
||||||
DEBUG("Surface Destroyed");
|
DEBUG("Surface Destroyed");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_Window != nullptr)
|
if (m_Window)
|
||||||
{
|
{
|
||||||
glfwDestroyWindow(m_Window);
|
glfwDestroyWindow(m_Window);
|
||||||
m_Window = nullptr;
|
m_Window = nullptr;
|
||||||
|
|
@ -87,3 +87,23 @@ Window::~Window()
|
||||||
|
|
||||||
DEBUG("Window '{}' Destroyed", m_Name);
|
DEBUG("Window '{}' Destroyed", m_Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Window::Window(Window &&other) noexcept
|
||||||
|
: m_Context(other.m_Context)
|
||||||
|
, m_Window(Take(other.m_Window))
|
||||||
|
, m_Surface(Take(other.m_Surface))
|
||||||
|
, m_Name(Take(other.m_Name))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Window &
|
||||||
|
Window::operator=(Window &&other) noexcept
|
||||||
|
{
|
||||||
|
if (this == &other)
|
||||||
|
return *this;
|
||||||
|
m_Context = other.m_Context;
|
||||||
|
m_Window = Take(other.m_Window);
|
||||||
|
m_Surface = Take(other.m_Surface);
|
||||||
|
m_Name = Take(other.m_Name);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,4 +34,10 @@ struct Window final
|
||||||
// Ctor/Dtor
|
// Ctor/Dtor
|
||||||
Window(cstr title, Context *context, vk::Extent2D extent, b8 isFullScreen = false);
|
Window(cstr title, Context *context, vk::Extent2D extent, b8 isFullScreen = false);
|
||||||
~Window();
|
~Window();
|
||||||
|
|
||||||
|
// Move
|
||||||
|
Window(Window &&other) noexcept;
|
||||||
|
Window &operator=(Window &&other) noexcept;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(Window);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,11 @@
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
add_library(util_helper STATIC helpers.h helpers.cpp)
|
add_library(util_helper STATIC
|
||||||
|
helpers.h
|
||||||
|
helpers.cpp
|
||||||
|
frame.cpp
|
||||||
|
frame.h)
|
||||||
|
|
||||||
target_link_libraries(util_helper PRIVATE aster_core)
|
target_link_libraries(util_helper PRIVATE aster_core)
|
||||||
target_include_directories(util_helper PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(util_helper PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,137 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: frame.cpp
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#include "frame.h"
|
||||||
|
|
||||||
|
#include "device.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
#include "swapchain.h"
|
||||||
|
|
||||||
|
Frame::Frame(const Device *device, const u32 queueFamilyIndex, const u32 frameCount)
|
||||||
|
: m_FrameIdx(0)
|
||||||
|
, m_ImageIdx(0)
|
||||||
|
{
|
||||||
|
m_Device = device;
|
||||||
|
|
||||||
|
const vk::CommandPoolCreateInfo commandPoolCreateInfo = {
|
||||||
|
.flags = vk::CommandPoolCreateFlagBits::eTransient,
|
||||||
|
.queueFamilyIndex = queueFamilyIndex,
|
||||||
|
};
|
||||||
|
AbortIfFailedMV(device->m_Device.createCommandPool(&commandPoolCreateInfo, nullptr, &m_Pool),
|
||||||
|
"Could not command pool for frame {}", frameCount);
|
||||||
|
|
||||||
|
constexpr vk::FenceCreateInfo fenceCreateInfo = {.flags = vk::FenceCreateFlagBits::eSignaled};
|
||||||
|
AbortIfFailedMV(device->m_Device.createFence(&fenceCreateInfo, nullptr, &m_FrameAvailableFence),
|
||||||
|
"Could not create a fence for frame {}", frameCount);
|
||||||
|
|
||||||
|
constexpr vk::SemaphoreCreateInfo semaphoreCreateInfo = {};
|
||||||
|
AbortIfFailedMV(device->m_Device.createSemaphore(&semaphoreCreateInfo, nullptr, &m_ImageAcquireSem),
|
||||||
|
"Could not create IA semaphore for frame {}.", frameCount);
|
||||||
|
AbortIfFailedMV(device->m_Device.createSemaphore(&semaphoreCreateInfo, nullptr, &m_RenderFinishSem),
|
||||||
|
"Could not create RF semaphore for frame {}.", frameCount);
|
||||||
|
|
||||||
|
const vk::CommandBufferAllocateInfo allocateInfo = {
|
||||||
|
.commandPool = m_Pool,
|
||||||
|
.level = vk::CommandBufferLevel::ePrimary,
|
||||||
|
.commandBufferCount = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
AbortIfFailed(m_Device->m_Device.allocateCommandBuffers(&allocateInfo, &m_CommandBuffer));
|
||||||
|
|
||||||
|
DEBUG("Frame {} created successfully.", frameCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Frame::Present(const vk::Queue commandQueue, Swapchain *swapchain, const Window *window)
|
||||||
|
{
|
||||||
|
|
||||||
|
vk::PresentInfoKHR presentInfo = {
|
||||||
|
.waitSemaphoreCount = 1,
|
||||||
|
.pWaitSemaphores = &m_RenderFinishSem,
|
||||||
|
.swapchainCount = 1,
|
||||||
|
.pSwapchains = &swapchain->m_Swapchain,
|
||||||
|
.pImageIndices = &m_ImageIdx,
|
||||||
|
.pResults = nullptr,
|
||||||
|
};
|
||||||
|
switch (auto result = commandQueue.presentKHR(&presentInfo))
|
||||||
|
{
|
||||||
|
case vk::Result::eSuccess:
|
||||||
|
break;
|
||||||
|
case vk::Result::eErrorOutOfDateKHR:
|
||||||
|
case vk::Result::eSuboptimalKHR:
|
||||||
|
INFO("Recreating Swapchain. Cause: {}", result);
|
||||||
|
swapchain->Create(window);
|
||||||
|
break; // Present failed. We do nothing. Frame is skipped.
|
||||||
|
default:
|
||||||
|
AbortIfFailedM(result, "Swapchain Present failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Frame::~Frame()
|
||||||
|
{
|
||||||
|
m_Device->m_Device.destroy(m_RenderFinishSem, nullptr);
|
||||||
|
m_Device->m_Device.destroy(m_ImageAcquireSem, nullptr);
|
||||||
|
m_Device->m_Device.destroy(m_FrameAvailableFence, nullptr);
|
||||||
|
m_Device->m_Device.destroy(m_Pool, nullptr);
|
||||||
|
|
||||||
|
DEBUG("Destoryed Frame");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Frame Manager
|
||||||
|
|
||||||
|
FrameManager::FrameManager(const Device *device, u32 queueFamilyIndex, u32 framesInFlight)
|
||||||
|
: m_Device(device)
|
||||||
|
, m_FramesInFlight(framesInFlight)
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < framesInFlight; ++i)
|
||||||
|
{
|
||||||
|
m_Frames.emplace_back(device, queueFamilyIndex, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Frame *
|
||||||
|
FrameManager::GetNextFrame(Swapchain *swapchain, const Window *window)
|
||||||
|
{
|
||||||
|
|
||||||
|
Frame *currentFrame = &m_Frames[m_CurrentFrameIdx];
|
||||||
|
u32 frameIndex = m_CurrentFrameIdx;
|
||||||
|
|
||||||
|
m_CurrentFrameIdx = (m_CurrentFrameIdx + 1) % m_FramesInFlight;
|
||||||
|
|
||||||
|
AbortIfFailedMV(m_Device->m_Device.waitForFences(1, ¤tFrame->m_FrameAvailableFence, true, MaxValue<u64>),
|
||||||
|
"Waiting for fence {} failed.", frameIndex);
|
||||||
|
|
||||||
|
u32 imageIndex;
|
||||||
|
bool imageAcquired = false;
|
||||||
|
while (!imageAcquired)
|
||||||
|
{
|
||||||
|
auto result = m_Device->m_Device.acquireNextImageKHR(swapchain->m_Swapchain, MaxValue<u64>,
|
||||||
|
currentFrame->m_ImageAcquireSem, nullptr, &imageIndex);
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case vk::Result::eSuccess:
|
||||||
|
case vk::Result::eSuboptimalKHR: // Suboptimal can still render. Better to let this go for semaphores etc.
|
||||||
|
imageAcquired = true;
|
||||||
|
break; // Image acquired. Break out of loop.
|
||||||
|
case vk::Result::eErrorOutOfDateKHR:
|
||||||
|
INFO("Recreating Swapchain. Cause: {}", result);
|
||||||
|
swapchain->Create(window);
|
||||||
|
break; // Image acquire has failed. We move to the next frame.
|
||||||
|
default:
|
||||||
|
AbortIfFailedMV(result, "Waiting for swapchain image {} failed.", frameIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset fences here. In case swapchain was out of date, we leave the fences signalled.
|
||||||
|
AbortIfFailedMV(m_Device->m_Device.resetFences(1, ¤tFrame->m_FrameAvailableFence), "Fence {} reset failed.",
|
||||||
|
frameIndex);
|
||||||
|
|
||||||
|
AbortIfFailedMV(m_Device->m_Device.resetCommandPool(currentFrame->m_Pool, {}), "Command pool {} reset failed.",
|
||||||
|
frameIndex);
|
||||||
|
|
||||||
|
currentFrame->m_ImageIdx = imageIndex;
|
||||||
|
|
||||||
|
return currentFrame;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
// =============================================
|
||||||
|
// Aster: frame.h
|
||||||
|
// Copyright (c) 2020-2024 Anish Bhobe
|
||||||
|
// =============================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "global.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
|
||||||
|
#include <EASTL/fixed_vector.h>
|
||||||
|
|
||||||
|
struct Device;
|
||||||
|
struct Window;
|
||||||
|
struct Swapchain;
|
||||||
|
|
||||||
|
struct Frame
|
||||||
|
{
|
||||||
|
// Persistent
|
||||||
|
const Device *m_Device;
|
||||||
|
vk::CommandPool m_Pool;
|
||||||
|
vk::CommandBuffer m_CommandBuffer;
|
||||||
|
vk::Fence m_FrameAvailableFence;
|
||||||
|
vk::Semaphore m_ImageAcquireSem;
|
||||||
|
vk::Semaphore m_RenderFinishSem;
|
||||||
|
u32 m_FrameIdx;
|
||||||
|
|
||||||
|
// Transient
|
||||||
|
u32 m_ImageIdx;
|
||||||
|
|
||||||
|
void Present(vk::Queue commandQueue, Swapchain *swapchain, const Window *window);
|
||||||
|
|
||||||
|
Frame(const Device *device, u32 queueFamilyIndex, u32 frameCount);
|
||||||
|
~Frame();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FrameManager
|
||||||
|
{
|
||||||
|
const Device *m_Device;
|
||||||
|
eastl::fixed_vector<Frame, 4> m_Frames{};
|
||||||
|
u32 m_CurrentFrameIdx = 0;
|
||||||
|
u32 m_FramesInFlight = 0;
|
||||||
|
|
||||||
|
FrameManager(const Device *device, u32 queueFamilyIndex, u32 framesInFlight);
|
||||||
|
|
||||||
|
Frame *GetNextFrame(Swapchain *swapchain, const Window *window);
|
||||||
|
};
|
||||||
|
|
@ -16,4 +16,27 @@ class PhysicalDevices;
|
||||||
|
|
||||||
PhysicalDevice FindSuitableDevice(const PhysicalDevices &physicalDevices);
|
PhysicalDevice FindSuitableDevice(const PhysicalDevices &physicalDevices);
|
||||||
QueueAllocation FindAppropriateQueueAllocation(const PhysicalDevice *physicalDevice);
|
QueueAllocation FindAppropriateQueueAllocation(const PhysicalDevice *physicalDevice);
|
||||||
eastl::vector<u32> ReadFile(cstr fileName);
|
eastl::vector<u32> ReadFile(cstr fileName);
|
||||||
|
|
||||||
|
#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)
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,13 @@ cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fsanitize=address")
|
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fsanitize=address")
|
||||||
|
|
||||||
add_executable(box box.cpp)
|
add_executable(box box.cpp stb_image.h)
|
||||||
add_shader(box shader/box.vert.glsl)
|
add_shader(box shader/box.vert.glsl)
|
||||||
add_shader(box shader/box.frag.glsl)
|
add_shader(box shader/box.frag.glsl)
|
||||||
|
|
||||||
target_link_libraries(box PRIVATE aster_core)
|
target_link_libraries(box PRIVATE aster_core)
|
||||||
target_link_libraries(box PRIVATE util_helper)
|
target_link_libraries(box PRIVATE util_helper)
|
||||||
|
|
||||||
|
add_custom_target(copy-resource-files ALL
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/image/ ${CMAKE_CURRENT_BINARY_DIR}/
|
||||||
|
DEPENDS box)
|
||||||
|
|
@ -7,43 +7,67 @@
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "context.h"
|
#include "context.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "physical_device.h"
|
|
||||||
#include "window.h"
|
|
||||||
|
|
||||||
#include "global.h"
|
#include "global.h"
|
||||||
|
#include "physical_device.h"
|
||||||
#include "pipeline.h"
|
#include "pipeline.h"
|
||||||
#include "swapchain.h"
|
#include "swapchain.h"
|
||||||
|
#include "window.h"
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#include "frame.h"
|
||||||
|
#include "image.h"
|
||||||
|
#include "stb_image.h"
|
||||||
|
|
||||||
#include <EASTL/array.h>
|
#include <EASTL/array.h>
|
||||||
|
|
||||||
constexpr u32 MAX_FRAMES_IN_FLIGHT = 3;
|
constexpr u32 MAX_FRAMES_IN_FLIGHT = 3;
|
||||||
constexpr auto VERTEX_SHADER_FILE = "shader/box.vert.glsl.spv";
|
constexpr auto VERTEX_SHADER_FILE = "shader/box.vert.glsl.spv";
|
||||||
constexpr auto FRAGMENT_SHADER_FILE = "shader/box.frag.glsl.spv";
|
constexpr auto FRAGMENT_SHADER_FILE = "shader/box.frag.glsl.spv";
|
||||||
|
|
||||||
#define AbortIfFailed(RESULT) \
|
struct ImageFile
|
||||||
do \
|
{
|
||||||
{ \
|
void *m_Data = nullptr;
|
||||||
vk::Result _checkResultValue_; \
|
u32 m_Width = 0;
|
||||||
ERROR_IF(Failed(_checkResultValue_ = Cast<vk::Result>(RESULT)), "Cause: {}", _checkResultValue_) \
|
u32 m_Height = 0;
|
||||||
THEN_ABORT(_checkResultValue_); \
|
u32 m_NumChannels = 0;
|
||||||
} while (false)
|
|
||||||
|
|
||||||
#define AbortIfFailedMV(RESULT, MSG, EXTRA) \
|
bool Load(cstr fileName);
|
||||||
do \
|
[[nodiscard]] usize GetSize() const;
|
||||||
{ \
|
~ImageFile();
|
||||||
vk::Result _checkResultValue_; \
|
};
|
||||||
ERROR_IF(Failed(_checkResultValue_ = Cast<vk::Result>(RESULT)), MSG " Cause: {}", EXTRA, _checkResultValue_) \
|
|
||||||
THEN_ABORT(_checkResultValue_); \
|
|
||||||
} while (false)
|
|
||||||
|
|
||||||
#define AbortIfFailedM(RESULT, MSG) \
|
bool
|
||||||
do \
|
ImageFile::Load(cstr fileName)
|
||||||
{ \
|
{
|
||||||
auto _checkResultValue_ = Cast<vk::Result>(RESULT); \
|
int width, height, nrChannels;
|
||||||
ERROR_IF(Failed(_checkResultValue_), MSG " Cause: {}", _checkResultValue_) THEN_ABORT(_checkResultValue_); \
|
m_Data = stbi_load(fileName, &width, &height, &nrChannels, 4);
|
||||||
} while (false)
|
ERROR_IF(!m_Data, "Could not load {}", fileName);
|
||||||
|
|
||||||
|
if (!m_Data)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Width = width;
|
||||||
|
m_Height = height;
|
||||||
|
m_NumChannels = 4;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
usize
|
||||||
|
ImageFile::GetSize() const
|
||||||
|
{
|
||||||
|
return m_Width * m_Height * m_NumChannels;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImageFile::~ImageFile()
|
||||||
|
{
|
||||||
|
stbi_image_free(m_Data);
|
||||||
|
m_Data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
vk::ShaderModule CreateShader(const Device *device, cstr shaderFile);
|
vk::ShaderModule CreateShader(const Device *device, cstr shaderFile);
|
||||||
Pipeline CreatePipeline(const Device *device, const Swapchain *swapchain);
|
Pipeline CreatePipeline(const Device *device, const Swapchain *swapchain);
|
||||||
|
|
@ -51,6 +75,7 @@ Pipeline CreatePipeline(const Device *device, const Swapchain *swapchain);
|
||||||
struct Vertex
|
struct Vertex
|
||||||
{
|
{
|
||||||
vec3 m_Position;
|
vec3 m_Position;
|
||||||
|
vec2 m_UV0;
|
||||||
|
|
||||||
constexpr static vk::VertexInputBindingDescription
|
constexpr static vk::VertexInputBindingDescription
|
||||||
GetBinding(const u32 binding)
|
GetBinding(const u32 binding)
|
||||||
|
|
@ -58,7 +83,7 @@ struct Vertex
|
||||||
return {.binding = binding, .stride = sizeof(Vertex), .inputRate = vk::VertexInputRate::eVertex};
|
return {.binding = binding, .stride = sizeof(Vertex), .inputRate = vk::VertexInputRate::eVertex};
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr static eastl::array<vk::VertexInputAttributeDescription, 1>
|
constexpr static eastl::array<vk::VertexInputAttributeDescription, 2>
|
||||||
GetAttributes(const u32 binding)
|
GetAttributes(const u32 binding)
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
|
|
@ -68,6 +93,12 @@ struct Vertex
|
||||||
.format = vk::Format::eR32G32B32Sfloat,
|
.format = vk::Format::eR32G32B32Sfloat,
|
||||||
.offset = offsetof(Vertex, m_Position),
|
.offset = offsetof(Vertex, m_Position),
|
||||||
},
|
},
|
||||||
|
vk::VertexInputAttributeDescription{
|
||||||
|
.location = 1,
|
||||||
|
.binding = binding,
|
||||||
|
.format = vk::Format::eR32G32Sfloat,
|
||||||
|
.offset = offsetof(Vertex, m_UV0),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -79,19 +110,6 @@ struct Camera
|
||||||
mat4 m_Perspective;
|
mat4 m_Perspective;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Frame
|
|
||||||
{
|
|
||||||
const Device *m_Device;
|
|
||||||
vk::CommandPool m_Pool;
|
|
||||||
vk::CommandBuffer m_CommandBuffer;
|
|
||||||
vk::Fence m_FrameAvailableFence;
|
|
||||||
vk::Semaphore m_ImageAcquireSem;
|
|
||||||
vk::Semaphore m_RenderFinishSem;
|
|
||||||
|
|
||||||
Frame(const Device *device, u32 queueFamilyIndex, u32 frameCount);
|
|
||||||
~Frame();
|
|
||||||
};
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int, char **)
|
main(int, char **)
|
||||||
{
|
{
|
||||||
|
|
@ -105,7 +123,10 @@ main(int, char **)
|
||||||
|
|
||||||
INFO("Using {} as the primary device.", deviceToUse.m_DeviceProperties.deviceName.data());
|
INFO("Using {} as the primary device.", deviceToUse.m_DeviceProperties.deviceName.data());
|
||||||
|
|
||||||
Features enabledDeviceFeatures = {.m_Vulkan13Features = {.dynamicRendering = true}};
|
Features enabledDeviceFeatures = {
|
||||||
|
.m_Vulkan10Features = {.samplerAnisotropy = true},
|
||||||
|
.m_Vulkan13Features = {.dynamicRendering = true},
|
||||||
|
};
|
||||||
QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse);
|
QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse);
|
||||||
Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"};
|
Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"};
|
||||||
vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0);
|
||||||
|
|
@ -123,12 +144,18 @@ main(int, char **)
|
||||||
vk::DescriptorSet descriptorSet;
|
vk::DescriptorSet descriptorSet;
|
||||||
{
|
{
|
||||||
vk::DescriptorSetLayout descriptorSetLayout = pipeline.m_SetLayouts.front();
|
vk::DescriptorSetLayout descriptorSetLayout = pipeline.m_SetLayouts.front();
|
||||||
vk::DescriptorPoolSize poolSize = {
|
eastl::array poolSizes = {
|
||||||
.type = vk::DescriptorType::eUniformBuffer,
|
vk::DescriptorPoolSize{
|
||||||
.descriptorCount = 1,
|
.type = vk::DescriptorType::eUniformBuffer,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
},
|
||||||
|
vk::DescriptorPoolSize{
|
||||||
|
.type = vk::DescriptorType::eCombinedImageSampler,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo = {
|
vk::DescriptorPoolCreateInfo descriptorPoolCreateInfo = {
|
||||||
.maxSets = 1, .poolSizeCount = 1, .pPoolSizes = &poolSize};
|
.maxSets = 1, .poolSizeCount = Cast<u32>(poolSizes.size()), .pPoolSizes = poolSizes.data()};
|
||||||
AbortIfFailed(device.m_Device.createDescriptorPool(&descriptorPoolCreateInfo, nullptr, &descriptorPool));
|
AbortIfFailed(device.m_Device.createDescriptorPool(&descriptorPoolCreateInfo, nullptr, &descriptorPool));
|
||||||
|
|
||||||
vk::DescriptorSetAllocateInfo descriptorSetAllocateInfo = {
|
vk::DescriptorSetAllocateInfo descriptorSetAllocateInfo = {
|
||||||
|
|
@ -157,25 +184,99 @@ main(int, char **)
|
||||||
"Copy command buffer allocation failed.");
|
"Copy command buffer allocation failed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// eastl::array<Vertex, 3> vertices{};
|
|
||||||
eastl::array vertices = {
|
eastl::array vertices = {
|
||||||
vec3(-0.5f, -0.5f, -0.5f), vec3(0.5f, -0.5f, -0.5f), vec3(0.5f, 0.5f, -0.5f), vec3(0.5f, 0.5f, -0.5f),
|
Vertex{.m_Position = vec3(0.5f, 0.5f, -0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
vec3(-0.5f, 0.5f, -0.5f), vec3(-0.5f, -0.5f, -0.5f), vec3(-0.5f, -0.5f, 0.5f), vec3(0.5f, -0.5f, 0.5f),
|
Vertex{.m_Position = vec3(0.5f, -0.5f, -0.5f), .m_UV0 = vec2(1.0f, 0.0f)},
|
||||||
vec3(0.5f, 0.5f, 0.5f), vec3(0.5f, 0.5f, 0.5f), vec3(-0.5f, 0.5f, 0.5f), vec3(-0.5f, -0.5f, 0.5f),
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
vec3(-0.5f, 0.5f, 0.5f), vec3(-0.5f, 0.5f, -0.5f), vec3(-0.5f, -0.5f, -0.5f), vec3(-0.5f, -0.5f, -0.5f),
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
vec3(-0.5f, -0.5f, 0.5f), vec3(-0.5f, 0.5f, 0.5f), vec3(0.5f, 0.5f, 0.5f), vec3(0.5f, 0.5f, -0.5f),
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, -0.5f), .m_UV0 = vec2(0.0f, 1.0f)},
|
||||||
vec3(0.5f, -0.5f, -0.5f), vec3(0.5f, -0.5f, -0.5f), vec3(0.5f, -0.5f, 0.5f), vec3(0.5f, 0.5f, 0.5f),
|
Vertex{.m_Position = vec3(0.5f, 0.5f, -0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
vec3(-0.5f, -0.5f, -0.5f), vec3(0.5f, -0.5f, -0.5f), vec3(0.5f, -0.5f, 0.5f), vec3(0.5f, -0.5f, 0.5f),
|
|
||||||
vec3(-0.5f, -0.5f, 0.5f), vec3(-0.5f, -0.5f, -0.5f), vec3(-0.5f, 0.5f, -0.5f), vec3(0.5f, 0.5f, -0.5f),
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, 0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
vec3(0.5f, 0.5f, 0.5f), vec3(0.5f, 0.5f, 0.5f), vec3(-0.5f, 0.5f, 0.5f), vec3(-0.5f, 0.5f, -0.5f),
|
Vertex{.m_Position = vec3(0.5f, -0.5f, 0.5f), .m_UV0 = vec2(1.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, 0.5f), .m_UV0 = vec2(0.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, 0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
|
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, 0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, -0.5f), .m_UV0 = vec2(1.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, 0.5f), .m_UV0 = vec2(0.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, 0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
|
|
||||||
|
Vertex{.m_Position = vec3(0.5f, -0.5f, -0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, 0.5f, -0.5f), .m_UV0 = vec2(1.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, -0.5f, 0.5f), .m_UV0 = vec2(0.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, -0.5f, -0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
|
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, -0.5f, -0.5f), .m_UV0 = vec2(1.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, -0.5f, 0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, -0.5f, 0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, 0.5f), .m_UV0 = vec2(0.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, -0.5f, -0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
|
|
||||||
|
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, 0.5f, -0.5f), .m_UV0 = vec2(1.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, -0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, -0.5f), .m_UV0 = vec2(0.0f, 0.0f)},
|
||||||
|
Vertex{.m_Position = vec3(-0.5f, 0.5f, 0.5f), .m_UV0 = vec2(0.0f, 1.0f)},
|
||||||
|
Vertex{.m_Position = vec3(0.5f, 0.5f, 0.5f), .m_UV0 = vec2(1.0f, 1.0f)},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ImageFile imageFile;
|
||||||
|
bool loaded = imageFile.Load("image/container.jpg");
|
||||||
|
assert(loaded);
|
||||||
|
INFO("Image {}x{} : {} channels", imageFile.m_Width, imageFile.m_Height, imageFile.m_NumChannels);
|
||||||
|
|
||||||
VertexBuffer vbo;
|
VertexBuffer vbo;
|
||||||
|
Texture crate;
|
||||||
vbo.Init(&device, vertices.size() * sizeof vertices[0], "VBO");
|
vbo.Init(&device, vertices.size() * sizeof vertices[0], "VBO");
|
||||||
|
crate.Init(&device, {imageFile.m_Width, imageFile.m_Height}, false, "Crate Texture");
|
||||||
{
|
{
|
||||||
StagingBuffer staging;
|
StagingBuffer vertexStaging, imageStaging;
|
||||||
staging.Init(&device, vertices.size() * sizeof vertices[0], "Staging");
|
vertexStaging.Init(&device, vertices.size() * sizeof vertices[0], "Vertex Staging");
|
||||||
staging.Write(&device, 0, vertices.size() * sizeof vertices[0], vertices.data());
|
vertexStaging.Write(&device, 0, vertices.size() * sizeof vertices[0], vertices.data());
|
||||||
|
|
||||||
|
imageStaging.Init(&device, imageFile.GetSize(), "Image Staging");
|
||||||
|
INFO("fine {}", imageFile.GetSize());
|
||||||
|
imageStaging.Write(&device, 0, imageFile.GetSize(), imageFile.m_Data);
|
||||||
|
|
||||||
|
vk::ImageMemoryBarrier imageReadyToWrite = {
|
||||||
|
.oldLayout = vk::ImageLayout::eUndefined,
|
||||||
|
.newLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||||
|
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
|
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
|
.image = crate.m_Image,
|
||||||
|
.subresourceRange =
|
||||||
|
{
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::ImageMemoryBarrier imageReadyToRead = {
|
||||||
|
.oldLayout = vk::ImageLayout::eTransferDstOptimal,
|
||||||
|
.newLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||||
|
.srcQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
|
.dstQueueFamilyIndex = queueAllocation.m_Family,
|
||||||
|
.image = crate.m_Image,
|
||||||
|
.subresourceRange =
|
||||||
|
{
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
vk::Fence fence;
|
vk::Fence fence;
|
||||||
vk::FenceCreateInfo fenceCreateInfo = {};
|
vk::FenceCreateInfo fenceCreateInfo = {};
|
||||||
|
|
@ -183,9 +284,31 @@ main(int, char **)
|
||||||
|
|
||||||
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
vk::CommandBufferBeginInfo beginInfo = {.flags = vk::CommandBufferUsageFlagBits::eOneTimeSubmit};
|
||||||
AbortIfFailed(copyBuffer.begin(&beginInfo));
|
AbortIfFailed(copyBuffer.begin(&beginInfo));
|
||||||
|
copyBuffer.pipelineBarrier(vk::PipelineStageFlagBits::eHost, vk::PipelineStageFlagBits::eTransfer, {}, 0,
|
||||||
|
nullptr, 0, nullptr, 1, &imageReadyToWrite);
|
||||||
|
|
||||||
vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = staging.GetSize()};
|
vk::BufferCopy bufferCopy = {.srcOffset = 0, .dstOffset = 0, .size = vertexStaging.GetSize()};
|
||||||
copyBuffer.copyBuffer(staging.m_Buffer, vbo.m_Buffer, 1, &bufferCopy);
|
copyBuffer.copyBuffer(vertexStaging.m_Buffer, vbo.m_Buffer, 1, &bufferCopy);
|
||||||
|
|
||||||
|
vk::BufferImageCopy imageCopy = {
|
||||||
|
.bufferOffset = 0,
|
||||||
|
.bufferRowLength = imageFile.m_Width,
|
||||||
|
.bufferImageHeight = imageFile.m_Height,
|
||||||
|
.imageSubresource =
|
||||||
|
{
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.mipLevel = 0,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
},
|
||||||
|
.imageOffset = {},
|
||||||
|
.imageExtent = {imageFile.m_Width, imageFile.m_Height, 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);
|
||||||
|
|
||||||
AbortIfFailed(copyBuffer.end());
|
AbortIfFailed(copyBuffer.end());
|
||||||
|
|
||||||
|
|
@ -203,7 +326,50 @@ main(int, char **)
|
||||||
AbortIfFailedM(device.m_Device.resetCommandPool(copyPool, {}), "Couldn't reset command pool.");
|
AbortIfFailedM(device.m_Device.resetCommandPool(copyPool, {}), "Couldn't reset command pool.");
|
||||||
|
|
||||||
device.m_Device.destroy(fence, nullptr);
|
device.m_Device.destroy(fence, nullptr);
|
||||||
staging.Destroy(&device);
|
vertexStaging.Destroy(&device);
|
||||||
|
imageStaging.Destroy(&device);
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::ImageView imageView;
|
||||||
|
vk::Sampler sampler;
|
||||||
|
{
|
||||||
|
vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||||
|
.image = crate.m_Image,
|
||||||
|
.viewType = vk::ImageViewType::e2D,
|
||||||
|
.format = vk::Format::eR8G8B8A8Srgb,
|
||||||
|
.components =
|
||||||
|
vk::ComponentMapping{
|
||||||
|
.r = vk::ComponentSwizzle::eIdentity,
|
||||||
|
.g = vk::ComponentSwizzle::eIdentity,
|
||||||
|
.b = vk::ComponentSwizzle::eIdentity,
|
||||||
|
.a = vk::ComponentSwizzle::eIdentity,
|
||||||
|
},
|
||||||
|
.subresourceRange =
|
||||||
|
{
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
AbortIfFailed(device.m_Device.createImageView(&imageViewCreateInfo, nullptr, &imageView));
|
||||||
|
vk::SamplerCreateInfo samplerCreateInfo = {
|
||||||
|
.magFilter = vk::Filter::eLinear,
|
||||||
|
.minFilter = vk::Filter::eLinear,
|
||||||
|
.mipmapMode = vk::SamplerMipmapMode::eLinear,
|
||||||
|
.addressModeU = vk::SamplerAddressMode::eRepeat,
|
||||||
|
.addressModeV = vk::SamplerAddressMode::eRepeat,
|
||||||
|
.addressModeW = vk::SamplerAddressMode::eRepeat,
|
||||||
|
.mipLodBias = 0.2,
|
||||||
|
.anisotropyEnable = true,
|
||||||
|
.maxAnisotropy = 1.0f,
|
||||||
|
.compareEnable = false,
|
||||||
|
.minLod = 0,
|
||||||
|
.maxLod = 4,
|
||||||
|
.unnormalizedCoordinates = false,
|
||||||
|
};
|
||||||
|
AbortIfFailed(device.m_Device.createSampler(&samplerCreateInfo, nullptr, &sampler));
|
||||||
}
|
}
|
||||||
|
|
||||||
UniformBuffer ubo;
|
UniformBuffer ubo;
|
||||||
|
|
@ -214,15 +380,30 @@ main(int, char **)
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
.range = ubo.GetSize(),
|
.range = ubo.GetSize(),
|
||||||
};
|
};
|
||||||
vk::WriteDescriptorSet writeDescriptors = {
|
vk::DescriptorImageInfo descriptorImageInfo = {
|
||||||
.dstSet = descriptorSet,
|
.sampler = sampler,
|
||||||
.dstBinding = 0,
|
.imageView = imageView,
|
||||||
.dstArrayElement = 0,
|
.imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal,
|
||||||
.descriptorCount = 1,
|
|
||||||
.descriptorType = vk::DescriptorType::eUniformBuffer,
|
|
||||||
.pBufferInfo = &descriptorBufferInfo,
|
|
||||||
};
|
};
|
||||||
device.m_Device.updateDescriptorSets(1, &writeDescriptors, 0, nullptr);
|
eastl::array writeDescriptors = {
|
||||||
|
vk::WriteDescriptorSet{
|
||||||
|
.dstSet = descriptorSet,
|
||||||
|
.dstBinding = 0,
|
||||||
|
.dstArrayElement = 0,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = vk::DescriptorType::eUniformBuffer,
|
||||||
|
.pBufferInfo = &descriptorBufferInfo,
|
||||||
|
},
|
||||||
|
vk::WriteDescriptorSet{
|
||||||
|
.dstSet = descriptorSet,
|
||||||
|
.dstBinding = 1,
|
||||||
|
.dstArrayElement = 0,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||||
|
.pImageInfo = &descriptorImageInfo,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
device.m_Device.updateDescriptorSets(Cast<u32>(writeDescriptors.size()), writeDescriptors.data(), 0, nullptr);
|
||||||
|
|
||||||
// Persistent variables
|
// Persistent variables
|
||||||
vk::Viewport viewport = {
|
vk::Viewport viewport = {
|
||||||
|
|
@ -239,6 +420,14 @@ main(int, char **)
|
||||||
.extent = swapchain.m_Extent,
|
.extent = swapchain.m_Extent,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
auto ResizeViewportScissor = [&viewport, &scissor](vk::Extent2D extent) {
|
||||||
|
viewport.y = Cast<f32>(extent.height);
|
||||||
|
viewport.width = Cast<f32>(extent.width);
|
||||||
|
viewport.height = -Cast<f32>(extent.height);
|
||||||
|
scissor.extent = extent;
|
||||||
|
};
|
||||||
|
swapchain.RegisterResizeCallback(ResizeViewportScissor);
|
||||||
|
|
||||||
vk::ImageSubresourceRange subresourceRange = {
|
vk::ImageSubresourceRange subresourceRange = {
|
||||||
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
.aspectMask = vk::ImageAspectFlagBits::eColor,
|
||||||
.baseMipLevel = 0,
|
.baseMipLevel = 0,
|
||||||
|
|
@ -261,58 +450,75 @@ main(int, char **)
|
||||||
.subresourceRange = subresourceRange,
|
.subresourceRange = subresourceRange,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Frames
|
FrameManager frameManager = {&device, queueAllocation.m_Family, MAX_FRAMES_IN_FLIGHT};
|
||||||
eastl::fixed_vector<Frame, MAX_FRAMES_IN_FLIGHT> frames;
|
eastl::fixed_vector<DepthImage, MAX_FRAMES_IN_FLIGHT> depthImages(frameManager.m_FramesInFlight);
|
||||||
for (int i = 0; i < MAX_FRAMES_IN_FLIGHT; ++i)
|
eastl::fixed_vector<vk::ImageView, MAX_FRAMES_IN_FLIGHT> depthViews(frameManager.m_FramesInFlight);
|
||||||
|
|
||||||
|
vk::ImageSubresourceRange depthSubresourceRange = {
|
||||||
|
.aspectMask = vk::ImageAspectFlagBits::eDepth,
|
||||||
|
.baseMipLevel = 0,
|
||||||
|
.levelCount = 1,
|
||||||
|
.baseArrayLayer = 0,
|
||||||
|
.layerCount = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
u32 index = 0;
|
||||||
|
for (auto &depthImage : depthImages)
|
||||||
{
|
{
|
||||||
frames.emplace_back(&device, queueAllocation.m_Family, i);
|
auto name = fmt::format("Depth image {}", index);
|
||||||
|
depthImage.Init(&device, swapchain.m_Extent, name.c_str());
|
||||||
|
vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||||
|
.image = depthImage.m_Image,
|
||||||
|
.viewType = vk::ImageViewType::e2D,
|
||||||
|
.format = vk::Format::eD32Sfloat,
|
||||||
|
.components = vk::ComponentMapping{.r = vk::ComponentSwizzle::eIdentity},
|
||||||
|
.subresourceRange = depthSubresourceRange,
|
||||||
|
};
|
||||||
|
AbortIfFailed(device.m_Device.createImageView(&imageViewCreateInfo, nullptr, &depthViews[index]));
|
||||||
|
|
||||||
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto RecreateDepthBuffers = [&device, &depthImages, &depthViews, depthSubresourceRange](vk::Extent2D extent) {
|
||||||
|
for (auto &depthView : depthViews)
|
||||||
|
{
|
||||||
|
device.m_Device.destroy(depthView, nullptr);
|
||||||
|
}
|
||||||
|
u32 index = 0;
|
||||||
|
for (auto &depthImage : depthImages)
|
||||||
|
{
|
||||||
|
depthImage.Destroy(&device);
|
||||||
|
depthImage.Init(&device, extent, "Depth");
|
||||||
|
vk::ImageViewCreateInfo imageViewCreateInfo = {
|
||||||
|
.image = depthImage.m_Image,
|
||||||
|
.viewType = vk::ImageViewType::e2D,
|
||||||
|
.format = vk::Format::eD32Sfloat,
|
||||||
|
.components = vk::ComponentMapping{.r = vk::ComponentSwizzle::eIdentity},
|
||||||
|
.subresourceRange = depthSubresourceRange,
|
||||||
|
};
|
||||||
|
AbortIfFailed(device.m_Device.createImageView(&imageViewCreateInfo, nullptr, &depthViews[index]));
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
swapchain.RegisterResizeCallback(RecreateDepthBuffers);
|
||||||
|
|
||||||
Time::Init();
|
Time::Init();
|
||||||
|
|
||||||
INFO("Starting loop");
|
INFO("Starting loop");
|
||||||
u32 frameIndex = 0;
|
|
||||||
while (window.Poll())
|
while (window.Poll())
|
||||||
{
|
{
|
||||||
Frame *currentFrame = &frames[frameIndex];
|
|
||||||
Time::Update();
|
Time::Update();
|
||||||
|
|
||||||
camera.m_Model *= rotate(mat4{1.0f}, Cast<f32>(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f));
|
camera.m_Model *= rotate(mat4{1.0f}, Cast<f32>(45.0_deg * Time::m_Delta), vec3(0.0f, 1.0f, 0.0f));
|
||||||
ubo.Write(&device, 0, sizeof camera, &camera);
|
ubo.Write(&device, 0, sizeof camera, &camera);
|
||||||
|
|
||||||
AbortIfFailedMV(device.m_Device.waitForFences(1, ¤tFrame->m_FrameAvailableFence, true, MaxValue<u64>),
|
Frame *currentFrame = frameManager.GetNextFrame(&swapchain, &window);
|
||||||
"Waiting for fence {} failed.", frameIndex);
|
|
||||||
|
|
||||||
u32 imageIndex;
|
|
||||||
auto result = device.m_Device.acquireNextImageKHR(swapchain.m_Swapchain, MaxValue<u64>,
|
|
||||||
currentFrame->m_ImageAcquireSem, nullptr, &imageIndex);
|
|
||||||
if (Failed(result))
|
|
||||||
{
|
|
||||||
switch (result)
|
|
||||||
{
|
|
||||||
case vk::Result::eErrorOutOfDateKHR:
|
|
||||||
case vk::Result::eSuboptimalKHR:
|
|
||||||
INFO("Recreating Swapchain. Cause: {}", result);
|
|
||||||
swapchain.Create(&window);
|
|
||||||
viewport.y = Cast<f32>(swapchain.m_Extent.height);
|
|
||||||
viewport.width = Cast<f32>(swapchain.m_Extent.width);
|
|
||||||
viewport.height = -Cast<f32>(swapchain.m_Extent.height);
|
|
||||||
scissor.extent = swapchain.m_Extent;
|
|
||||||
continue; // Image acquire has failed. We move to the next frame.
|
|
||||||
default:
|
|
||||||
AbortIfFailedMV(result, "Waiting for swapchain image {} failed.", frameIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Reset fences here. In case swapchain was out of date, we leave the fences signalled.
|
|
||||||
AbortIfFailedMV(device.m_Device.resetFences(1, ¤tFrame->m_FrameAvailableFence), "Fence {} reset failed.",
|
|
||||||
frameIndex);
|
|
||||||
|
|
||||||
AbortIfFailedMV(device.m_Device.resetCommandPool(currentFrame->m_Pool, {}), "Command pool {} reset failed.",
|
|
||||||
frameIndex);
|
|
||||||
|
|
||||||
|
u32 imageIndex = currentFrame->m_ImageIdx;
|
||||||
vk::ImageView currentImageView = swapchain.m_ImageViews[imageIndex];
|
vk::ImageView currentImageView = swapchain.m_ImageViews[imageIndex];
|
||||||
vk::Image currentImage = swapchain.m_Images[imageIndex];
|
vk::Image currentImage = swapchain.m_Images[imageIndex];
|
||||||
vk::CommandBuffer cmd = currentFrame->m_CommandBuffer;
|
vk::CommandBuffer cmd = currentFrame->m_CommandBuffer;
|
||||||
|
vk::ImageView currentDepthImageView = depthViews[currentFrame->m_FrameIdx];
|
||||||
|
|
||||||
topOfThePipeBarrier.image = currentImage;
|
topOfThePipeBarrier.image = currentImage;
|
||||||
renderToPresentBarrier.image = currentImage;
|
renderToPresentBarrier.image = currentImage;
|
||||||
|
|
@ -324,20 +530,32 @@ main(int, char **)
|
||||||
{}, 0, nullptr, 0, nullptr, 1, &topOfThePipeBarrier);
|
{}, 0, nullptr, 0, nullptr, 1, &topOfThePipeBarrier);
|
||||||
|
|
||||||
// Render
|
// Render
|
||||||
vk::RenderingAttachmentInfo attachmentInfo = {
|
eastl::array attachmentInfos = {
|
||||||
.imageView = currentImageView,
|
vk::RenderingAttachmentInfo{
|
||||||
.imageLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
.imageView = currentImageView,
|
||||||
|
.imageLayout = vk::ImageLayout::eColorAttachmentOptimal,
|
||||||
|
.resolveMode = vk::ResolveModeFlagBits::eNone,
|
||||||
|
.loadOp = vk::AttachmentLoadOp::eClear,
|
||||||
|
.storeOp = vk::AttachmentStoreOp::eStore,
|
||||||
|
.clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 1.0f},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
vk::RenderingAttachmentInfo depthAttachment = {
|
||||||
|
.imageView = currentDepthImageView,
|
||||||
|
.imageLayout = vk::ImageLayout::eDepthAttachmentOptimal,
|
||||||
.resolveMode = vk::ResolveModeFlagBits::eNone,
|
.resolveMode = vk::ResolveModeFlagBits::eNone,
|
||||||
.loadOp = vk::AttachmentLoadOp::eClear,
|
.loadOp = vk::AttachmentLoadOp::eClear,
|
||||||
.storeOp = vk::AttachmentStoreOp::eStore,
|
.storeOp = vk::AttachmentStoreOp::eDontCare,
|
||||||
.clearValue = vk::ClearColorValue{0.0f, 0.0f, 0.0f, 1.0f},
|
.clearValue = vk::ClearDepthStencilValue{.depth = 1.0f, .stencil = 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::RenderingInfo renderingInfo = {
|
vk::RenderingInfo renderingInfo = {
|
||||||
.renderArea = {.extent = swapchain.m_Extent},
|
.renderArea = {.extent = swapchain.m_Extent},
|
||||||
.layerCount = 1,
|
.layerCount = 1,
|
||||||
.colorAttachmentCount = 1,
|
.colorAttachmentCount = Cast<u32>(attachmentInfos.size()),
|
||||||
.pColorAttachments = &attachmentInfo,
|
.pColorAttachments = attachmentInfos.data(),
|
||||||
|
.pDepthAttachment = &depthAttachment,
|
||||||
};
|
};
|
||||||
|
|
||||||
cmd.beginRendering(&renderingInfo);
|
cmd.beginRendering(&renderingInfo);
|
||||||
|
|
@ -369,77 +587,30 @@ main(int, char **)
|
||||||
};
|
};
|
||||||
AbortIfFailed(commandQueue.submit(1, &submitInfo, currentFrame->m_FrameAvailableFence));
|
AbortIfFailed(commandQueue.submit(1, &submitInfo, currentFrame->m_FrameAvailableFence));
|
||||||
|
|
||||||
vk::PresentInfoKHR presentInfo = {
|
currentFrame->Present(commandQueue, &swapchain, &window);
|
||||||
.waitSemaphoreCount = 1,
|
|
||||||
.pWaitSemaphores = ¤tFrame->m_RenderFinishSem,
|
|
||||||
.swapchainCount = 1,
|
|
||||||
.pSwapchains = &swapchain.m_Swapchain,
|
|
||||||
.pImageIndices = &imageIndex,
|
|
||||||
.pResults = nullptr,
|
|
||||||
};
|
|
||||||
result = commandQueue.presentKHR(&presentInfo);
|
|
||||||
if (Failed(result))
|
|
||||||
{
|
|
||||||
switch (result)
|
|
||||||
{
|
|
||||||
case vk::Result::eErrorOutOfDateKHR:
|
|
||||||
case vk::Result::eSuboptimalKHR:
|
|
||||||
INFO("Recreating Swapchain. Cause: {}", result);
|
|
||||||
swapchain.Create(&window);
|
|
||||||
viewport.y = Cast<f32>(swapchain.m_Extent.height);
|
|
||||||
viewport.width = Cast<f32>(swapchain.m_Extent.width);
|
|
||||||
viewport.height = -Cast<f32>(swapchain.m_Extent.height);
|
|
||||||
scissor.extent = swapchain.m_Extent;
|
|
||||||
break; // Present failed. We redo the frame.
|
|
||||||
default:
|
|
||||||
AbortIfFailedM(result, "Swapchain Present failed.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AbortIfFailed(device.m_Device.waitIdle());
|
AbortIfFailed(device.m_Device.waitIdle());
|
||||||
|
|
||||||
|
for (auto &depthView : depthViews)
|
||||||
|
{
|
||||||
|
device.m_Device.destroy(depthView, nullptr);
|
||||||
|
}
|
||||||
|
for (auto &depthImage : depthImages)
|
||||||
|
{
|
||||||
|
depthImage.Destroy(&device);
|
||||||
|
}
|
||||||
|
device.m_Device.destroy(sampler, nullptr);
|
||||||
|
device.m_Device.destroy(imageView, nullptr);
|
||||||
ubo.Destroy(&device);
|
ubo.Destroy(&device);
|
||||||
device.m_Device.destroy(descriptorPool, nullptr);
|
device.m_Device.destroy(descriptorPool, nullptr);
|
||||||
device.m_Device.destroy(copyPool, nullptr);
|
device.m_Device.destroy(copyPool, nullptr);
|
||||||
|
crate.Destroy(&device);
|
||||||
vbo.Destroy(&device);
|
vbo.Destroy(&device);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Frame::Frame(const Device *device, const u32 queueFamilyIndex, const u32 frameCount)
|
|
||||||
{
|
|
||||||
m_Device = device;
|
|
||||||
|
|
||||||
const vk::CommandPoolCreateInfo commandPoolCreateInfo = {
|
|
||||||
.flags = vk::CommandPoolCreateFlagBits::eTransient,
|
|
||||||
.queueFamilyIndex = queueFamilyIndex,
|
|
||||||
};
|
|
||||||
AbortIfFailedMV(device->m_Device.createCommandPool(&commandPoolCreateInfo, nullptr, &m_Pool),
|
|
||||||
"Could not command pool for frame {}", frameCount);
|
|
||||||
|
|
||||||
constexpr vk::FenceCreateInfo fenceCreateInfo = {.flags = vk::FenceCreateFlagBits::eSignaled};
|
|
||||||
AbortIfFailedMV(device->m_Device.createFence(&fenceCreateInfo, nullptr, &m_FrameAvailableFence),
|
|
||||||
"Could not create a fence for frame {}", frameCount);
|
|
||||||
|
|
||||||
constexpr vk::SemaphoreCreateInfo semaphoreCreateInfo = {};
|
|
||||||
AbortIfFailedMV(device->m_Device.createSemaphore(&semaphoreCreateInfo, nullptr, &m_ImageAcquireSem),
|
|
||||||
"Could not create IA semaphore for frame {}.", frameCount);
|
|
||||||
AbortIfFailedMV(device->m_Device.createSemaphore(&semaphoreCreateInfo, nullptr, &m_RenderFinishSem),
|
|
||||||
"Could not create RF semaphore for frame {}.", frameCount);
|
|
||||||
|
|
||||||
const vk::CommandBufferAllocateInfo allocateInfo = {
|
|
||||||
.commandPool = m_Pool,
|
|
||||||
.level = vk::CommandBufferLevel::ePrimary,
|
|
||||||
.commandBufferCount = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
AbortIfFailed(m_Device->m_Device.allocateCommandBuffers(&allocateInfo, &m_CommandBuffer));
|
|
||||||
|
|
||||||
DEBUG("Frame {} created successfully.", frameCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
Pipeline
|
Pipeline
|
||||||
CreatePipeline(const Device *device, const Swapchain *swapchain)
|
CreatePipeline(const Device *device, const Swapchain *swapchain)
|
||||||
{
|
{
|
||||||
|
|
@ -460,15 +631,23 @@ CreatePipeline(const Device *device, const Swapchain *swapchain)
|
||||||
},
|
},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
vk::DescriptorSetLayoutBinding descriptorSetLayoutBinding = {
|
eastl::array descriptorSetLayoutBinding = {
|
||||||
.binding = 0,
|
vk::DescriptorSetLayoutBinding{
|
||||||
.descriptorType = vk::DescriptorType::eUniformBuffer,
|
.binding = 0,
|
||||||
.descriptorCount = 1,
|
.descriptorType = vk::DescriptorType::eUniformBuffer,
|
||||||
.stageFlags = vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment,
|
.descriptorCount = 1,
|
||||||
|
.stageFlags = vk::ShaderStageFlagBits::eVertex,
|
||||||
|
},
|
||||||
|
vk::DescriptorSetLayoutBinding{
|
||||||
|
.binding = 1,
|
||||||
|
.descriptorType = vk::DescriptorType::eCombinedImageSampler,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.stageFlags = vk::ShaderStageFlagBits::eFragment,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
|
vk::DescriptorSetLayoutCreateInfo descriptorSetLayoutCreateInfo = {
|
||||||
.bindingCount = 1,
|
.bindingCount = Cast<u32>(descriptorSetLayoutBinding.size()),
|
||||||
.pBindings = &descriptorSetLayoutBinding,
|
.pBindings = descriptorSetLayoutBinding.data(),
|
||||||
};
|
};
|
||||||
vk::DescriptorSetLayout descriptorSetLayout;
|
vk::DescriptorSetLayout descriptorSetLayout;
|
||||||
AbortIfFailed(
|
AbortIfFailed(
|
||||||
|
|
@ -517,8 +696,9 @@ CreatePipeline(const Device *device, const Swapchain *swapchain)
|
||||||
.sampleShadingEnable = false,
|
.sampleShadingEnable = false,
|
||||||
};
|
};
|
||||||
vk::PipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = {
|
vk::PipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = {
|
||||||
.depthTestEnable = false,
|
.depthTestEnable = true,
|
||||||
.depthWriteEnable = false,
|
.depthWriteEnable = true,
|
||||||
|
.depthCompareOp = vk::CompareOp::eLess,
|
||||||
};
|
};
|
||||||
vk::PipelineColorBlendAttachmentState colorBlendAttachmentState = {
|
vk::PipelineColorBlendAttachmentState colorBlendAttachmentState = {
|
||||||
.blendEnable = false,
|
.blendEnable = false,
|
||||||
|
|
@ -551,6 +731,7 @@ CreatePipeline(const Device *device, const Swapchain *swapchain)
|
||||||
.viewMask = 0,
|
.viewMask = 0,
|
||||||
.colorAttachmentCount = 1,
|
.colorAttachmentCount = 1,
|
||||||
.pColorAttachmentFormats = &swapchain->m_Format,
|
.pColorAttachmentFormats = &swapchain->m_Format,
|
||||||
|
.depthAttachmentFormat = vk::Format::eD32Sfloat,
|
||||||
};
|
};
|
||||||
|
|
||||||
vk::GraphicsPipelineCreateInfo pipelineCreateInfo = {
|
vk::GraphicsPipelineCreateInfo pipelineCreateInfo = {
|
||||||
|
|
@ -591,14 +772,4 @@ CreateShader(const Device *device, cstr shaderFile)
|
||||||
AbortIfFailedMV(device->m_Device.createShaderModule(&shaderModuleCreateInfo, nullptr, &shaderModule),
|
AbortIfFailedMV(device->m_Device.createShaderModule(&shaderModuleCreateInfo, nullptr, &shaderModule),
|
||||||
"Shader {} could not be created.", shaderFile);
|
"Shader {} could not be created.", shaderFile);
|
||||||
return shaderModule;
|
return shaderModule;
|
||||||
}
|
|
||||||
|
|
||||||
Frame::~Frame()
|
|
||||||
{
|
|
||||||
m_Device->m_Device.destroy(m_RenderFinishSem, nullptr);
|
|
||||||
m_Device->m_Device.destroy(m_ImageAcquireSem, nullptr);
|
|
||||||
m_Device->m_Device.destroy(m_FrameAvailableFence, nullptr);
|
|
||||||
m_Device->m_Device.destroy(m_Pool, nullptr);
|
|
||||||
|
|
||||||
DEBUG("Destoryed Frame");
|
|
||||||
}
|
}
|
||||||
Binary file not shown.
|
|
@ -1,9 +1,11 @@
|
||||||
#version 450
|
#version 450
|
||||||
#pragma shader_stage(fragment)
|
#pragma shader_stage(fragment)
|
||||||
|
|
||||||
layout (location = 0) in vec3 inColor;
|
layout (location = 0) in vec2 inUV;
|
||||||
layout (location = 0) out vec4 outColor;
|
layout (location = 0) out vec4 outColor;
|
||||||
|
|
||||||
|
layout(binding = 1) uniform sampler2D tex;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
outColor = vec4(inColor, 1.0);
|
outColor = vec4(texture(tex, inUV).rgb, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
@ -2,8 +2,9 @@
|
||||||
#pragma shader_stage(vertex)
|
#pragma shader_stage(vertex)
|
||||||
|
|
||||||
layout(location=0) in vec4 position;
|
layout(location=0) in vec4 position;
|
||||||
|
layout(location=1) in vec2 uv0;
|
||||||
|
|
||||||
layout(location=0) out vec3 outColor;
|
layout(location=0) out vec2 outUV;
|
||||||
|
|
||||||
layout(binding=0) uniform Camera {
|
layout(binding=0) uniform Camera {
|
||||||
mat4 model;
|
mat4 model;
|
||||||
|
|
@ -12,6 +13,7 @@ layout(binding=0) uniform Camera {
|
||||||
} ubo;
|
} ubo;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
outUV = uv0;
|
||||||
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(position.xyz, 1.0f);
|
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(position.xyz, 1.0f);
|
||||||
outColor = vec3(0.5f, 0.3f, 0.1f);
|
// outColor = vec3(0.5f, 0.3f, 0.1f);
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue