Started adding a server binary, and added common headers, for a modular

approach.
This commit is contained in:
Alexandre 2026-05-05 11:44:15 +02:00
parent 03a30c0096
commit 48a88078cd
10 changed files with 9 additions and 1256 deletions

View File

@ -6,3 +6,4 @@ CompileFlags:
- -DINITIALIZERS_IMPL - -DINITIALIZERS_IMPL
- -DPIPELINES_IMPL - -DPIPELINES_IMPL
- -DDESCRIPTORS_IMPL - -DDESCRIPTORS_IMPL
- -DTIMER_IMPL

View File

@ -53,6 +53,8 @@ function ( addBinary BINARY_NAME )
if (DEFINED BINARY_SOURCE) if (DEFINED BINARY_SOURCE)
add_executable ( ${BINARY_NAME} src/${BINARY_SOURCE}.cpp ) add_executable ( ${BINARY_NAME} src/${BINARY_SOURCE}.cpp )
endif() endif()
target_include_directories( ${BINARY_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/src )
# Sets the output dir to have clear separation between binaries # Sets the output dir to have clear separation between binaries
set_target_properties ( ${BINARY_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${BINARY_NAME} ) set_target_properties ( ${BINARY_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${BINARY_NAME} )
set_target_properties ( ${BINARY_NAME} PROPERTIES CXX_STANDARD 20 ) # Uses C++20 set_target_properties ( ${BINARY_NAME} PROPERTIES CXX_STANDARD 20 ) # Uses C++20
@ -112,7 +114,12 @@ endfunction()
addBinary ( addBinary (
engine engine
SOURCE main SOURCE Engine/main
LIBS glfw fmt vk-bootstrap vulkan LIBS glfw fmt vk-bootstrap vulkan
) )
addBinary (
server
SOURCE Server/main
)

View File

@ -1,25 +0,0 @@
#ifndef CALLBACK_H
#define CALLBACK_H
// Header
// Other includes
#include "types.h"
class Callback {
public:
static void keyboardCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
};
#endif
#ifdef CALLBACK_IMPL
#ifndef CALLBACK_IMPL_H
#define CALLBACK_IMPL_H
void Callback::keyboardCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
#ifdef DEBUG
fmt::println("Key pressed, key {}", key);
#endif
}
#endif
#endif

View File

@ -1,100 +0,0 @@
#ifndef DESCRIPTORS_H
#define DESCRIPTORS_H
// Header
// Other includes
#include "types.h"
#include <cstdint>
#include <vulkan/vulkan_core.h>
struct DescriptorLayoutBuilder {
std::vector<VkDescriptorSetLayoutBinding> bindings;
void addBinding(
uint32_t binding,
VkDescriptorType type
);
void clear();
VkDescriptorSetLayout build (
VkDevice device,
VkShaderStageFlags shaderStages,
void* pNext = nullptr,
VkDescriptorSetLayoutCreateFlags flags = 0
);
};
#endif
#ifdef DESCRIPTORS_IMPL
#ifndef DESCRIPTORS_IMPL_H
#define DESCRIPTORS_IMPL_H
// The actual implementation
void DescriptorLayoutBuilder::addBinding(
uint32_t binding,
VkDescriptorType type
){
#ifdef DEBUG
fmt::println("Adding a descriptor set binding...");
#endif
VkDescriptorSetLayoutBinding newBind {
.binding = binding,
.descriptorType = type,
.descriptorCount = 1
};
bindings.push_back(newBind);
}
void DescriptorLayoutBuilder::clear() {
#ifdef DEBUG
fmt::println("Clearing a descriptor set...");
#endif
bindings.clear();
}
VkDescriptorSetLayout DescriptorLayoutBuilder::build (
VkDevice device,
VkShaderStageFlags shaderStages,
void* pNext = nullptr,
VkDescriptorSetLayoutCreateFlags flags = 0
) {
#ifdef DEBUG
fmt::println("Building a descriptor set...");
#endif
for (auto& b : bindings) {
b.stageFlags |= shaderStages;
}
VkDescriptorSetLayoutCreateInfo info = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.pNext = pNext,
.flags = flags,
.bindingCount = (uint32_t)bindings.size(),
.pBindings = bindings.data(),
};
VkDescriptorSet set;
VK_CHECK(
vkCreateDescriptorSetLayout(
device,
&info,
nullptr,
&set
)
);
return set;
}
#endif
#endif

View File

@ -1,648 +0,0 @@
#ifndef ENGINE_H
#define ENGINE_H
// Normal header
#include "types.h"
#include <cstdint>
#include <vulkan/vulkan_core.h>
struct FrameData {
VkCommandPool _commandPool;
VkCommandBuffer _mainCommandBuffer;
VkSemaphore _swapchainSemaphore;
VkSemaphore _renderSemaphore;
VkFence _renderFence;
DeletionQueue _deletionQueue;
};
constexpr uint32_t FRAME_OVERLAP = 2;
class Engine {
public:
//========== Class Members ==========
bool _isInitialized { false };
int _frameNumber { 0 };
VkExtent2D _windowExtent { 1700, 900 };
GLFWwindow *window { nullptr };
// Vulkan specific class members
VkInstance _instance;
VkDebugUtilsMessengerEXT _debugMessenger;
VkPhysicalDevice _choosenGPU;
VkDevice _device;
VkSurfaceKHR _surface;
VkSwapchainKHR _swapchain;
VkFormat _swapchainImageFormat;
std::vector<VkImage> _swapchainImages;
std::vector<VkImageView> _swapchainImageViews;
VkExtent2D _swapchainExtent;
FrameData _frames[FRAME_OVERLAP];
FrameData& getCurrentFrame() { return _frames[_frameNumber % FRAME_OVERLAP]; };
VkQueue _graphicsQueue;
uint32_t _graphicsQueueFamily;
// Deletion queue
DeletionQueue _mainDeletionQueue;
VmaAllocator _allocator;
// Draw resources
AllocatedImage _drawImage;
VkExtent2D _drawExtent;
void init();
void cleanup();
void draw();
void run();
private:
void initRender();
void initVulkan();
void initSwapchain();
void initCommands();
void initSyncStructures();
void createSwapchain(
uint32_t width,
uint32_t height
);
void destroySwapchain();
void drawBackground(
VkCommandBuffer cmd
);
};
#endif
#ifdef ENGINE_IMPL
#ifndef ENGINE_IMPL_H
#define ENGINE_IMPL_H
//========== Implementation ==========
// Implementation defines
#define IMAGES_IMPL
#define INITIALIZERS_IMPL
#define CALLBACK_IMPL
#define VMA_IMPLEMENTATION
// Custom includes
#include "images.h"
#include "initializers.h"
#include "callbacks.h"
#include "VkBootstrap.h"
#include "vk_mem_alloc.h"
#ifndef DEBUG
constexpr bool bUseValidationLayers = false;
#else
constexpr bool bUseValidationLayers = true;
#endif
// Abort when there is an error
// Todo : Give an error message or crash dump
using namespace std;
#define VK_CHECK(x) \
do { \
VkResult err = x; \
if (err) { \
fmt::println("Vulkan error : {}", string_VkResult(err)); \
abort(); \
} \
} while (0) \
void Engine::init() {
#ifdef DEBUG
fmt::println("Initializing the engine...");
fmt::println("Current engine version {}", BUILD_ID);
#endif
glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
window = glfwCreateWindow(
static_cast<uint32_t>(_windowExtent.width),
static_cast<uint32_t>(_windowExtent.height),
"Engine",
nullptr,
nullptr
);
glfwSetKeyCallback(window, Callback::keyboardCallback);
_isInitialized = true;
initRender();
#ifdef DEBUG
fmt::println("Engine Initialized !");
#endif
}
void Engine::cleanup() {
#ifdef DEBUG
fmt::println("Cleaning up...");
#endif
if (_isInitialized) {
// Wait for the GPU to stop working
vkDeviceWaitIdle(_device);
for (int i = 0; i < FRAME_OVERLAP; i++) {
vkDestroyCommandPool(_device, _frames[i]._commandPool, nullptr);
// Destroy sync objects
vkDestroyFence(_device, _frames[i]._renderFence, nullptr);
vkDestroySemaphore(_device, _frames[i]._renderSemaphore, nullptr);
vkDestroySemaphore(_device, _frames[i]._swapchainSemaphore, nullptr);
// Uses the deletion queue to clear ressources
_frames[i]._deletionQueue.flush();
}
// Flush the global deletion queue
_mainDeletionQueue.flush();
destroySwapchain();
vkDestroySurfaceKHR(_instance, _surface, nullptr);
vkDestroyDevice(_device, nullptr);
vkb::destroy_debug_utils_messenger(_instance, _debugMessenger);
vkDestroyInstance(_instance, nullptr);
/*
vkDestroyCommandPool(_device, _commandPool, nullptr);
vkDestroySwapchainKHR(_device, _swapchain, nullptr);
// Change to use dynamic rendering
vkDestroyRenderPass(_device, _renderPass, nullptr);
// Destroy swapchain ressources
for (uint32_t i = 0; i < _framebuffers.size(); i++) {
vkDestroyFramebuffer(_device, _framebuffers[i], nullptr);
vkDestroyImageView(_device, _swapchainImageViews[i], nullptr);
}
*/
// Destroy the window (at the end)
glfwDestroyWindow(window);
glfwTerminate();
}
#ifdef DEBUG
fmt::println("Engine cleaned up !");
#endif
}
void Engine::draw() {
// wait until the gpu has finished rendering the last frame. Timeout of 1s
VK_CHECK(vkWaitForFences(_device, 1, &getCurrentFrame()._renderFence, true, UINT64_MAX));
// Flush frame data
getCurrentFrame()._deletionQueue.flush();
// Request image from the swapchain
uint32_t swapchainImageIndex;
VK_CHECK(vkAcquireNextImageKHR(_device, _swapchain, UINT64_MAX, getCurrentFrame()._swapchainSemaphore, nullptr, &swapchainImageIndex));
// Reset fences to redo sync
VK_CHECK(vkResetFences(_device, 1, &getCurrentFrame()._renderFence));
VkCommandBuffer cmd = getCurrentFrame()._mainCommandBuffer;
_drawExtent.width = _drawImage.imageExtent.width;
_drawExtent.height = _drawImage.imageExtent.height;
VK_CHECK(vkResetCommandBuffer(cmd, 0));
VkCommandBufferBeginInfo cmdBeginInfo = {
vkinit::commandBufferBeginInfo(
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT
)
};
VK_CHECK(vkBeginCommandBuffer(cmd, &cmdBeginInfo));
vkutil::transitionImage(
cmd,
_drawImage.image,
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_GENERAL
);
drawBackground(cmd);
// Transfer the draw image and swapchain image to the correct layouts
vkutil::transitionImage(
cmd,
_drawImage.image,
VK_IMAGE_LAYOUT_GENERAL,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL
);
vkutil::transitionImage(
cmd,
_swapchainImages[swapchainImageIndex],
VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL
);
// Copy image -> swapchain
vkutil::copyImageToImage(
cmd,
_drawImage.image,
_swapchainImages[swapchainImageIndex],
_drawExtent,
_swapchainExtent
);
// Uses the present layout to display into the screen
vkutil::transitionImage(
cmd,
_swapchainImages[swapchainImageIndex],
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR
);
// Locks the buffer, allowing it to be executed
VK_CHECK(vkEndCommandBuffer(cmd));
VkCommandBufferSubmitInfo cmdinfo = vkinit::commandBufferSubmitInfo(cmd);
VkSemaphoreSubmitInfo waitInfo = vkinit::semaphoreSubmitInfo(VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR, getCurrentFrame()._swapchainSemaphore);
VkSemaphoreSubmitInfo signalInfo = vkinit::semaphoreSubmitInfo(VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT, getCurrentFrame()._renderSemaphore);
VkSubmitInfo2 submit = vkinit::submitInfo(&cmdinfo, &signalInfo, &waitInfo);
VK_CHECK(vkQueueSubmit2(_graphicsQueue, 1, &submit, getCurrentFrame()._renderFence));
VkPresentInfoKHR presentInfo = {};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.pNext = nullptr;
presentInfo.pSwapchains = &_swapchain;
presentInfo.swapchainCount = 1;
presentInfo.pWaitSemaphores = &getCurrentFrame()._renderSemaphore;
presentInfo.waitSemaphoreCount = 1;
presentInfo.pImageIndices = &swapchainImageIndex;
VK_CHECK(vkQueuePresentKHR(_graphicsQueue, &presentInfo));
_frameNumber++;
}
void Engine::run() {
#ifdef DEBUG
fmt::println("Running...");
auto runTimeStart = std::chrono::system_clock::now();
#endif
bool stopRendering = false;
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
if (glfwGetWindowAttrib(window, GLFW_ICONIFIED)) {
stopRendering = true;
} else {
stopRendering = false;
}
if (stopRendering) {
// Minimized, pause
std::this_thread::sleep_for(std::chrono::milliseconds(100));
continue;
}
draw();
}
#ifdef DEBUG
auto runTimeEnd = std::chrono::system_clock::now();
auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(runTimeEnd - runTimeStart);
fmt::println("Engine has finished running after {} seconds!", elapsed.count());
#endif
}
void Engine::initRender() {
initVulkan();
initSwapchain();
//initDefaultRenderpass();
//initFramebuffers();
initCommands();
initSyncStructures();
}
void Engine::initVulkan() {
#ifdef DEBUG
fmt::println("Initializing Vulkan...");
#endif
vkb::InstanceBuilder builder;
// Create a basic VK instance, with debuging features
auto instRet = builder.set_app_name("Engine")
.request_validation_layers(bUseValidationLayers)
.use_default_debug_messenger()
.require_api_version(1, 3, 0)
.build();
vkb::Instance vkbInst = instRet.value();
// Grab the instance
_instance = vkbInst.instance;
_debugMessenger = vkbInst.debug_messenger;
// Create the surface
if (glfwCreateWindowSurface(_instance, window, nullptr, & _surface) != VK_SUCCESS) {
throw std::runtime_error("Failed to create window surface !\nAborting...");
}
// Features
// Vulkan 1.3
VkPhysicalDeviceVulkan13Features features13 {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES,
.synchronization2 = true,
.dynamicRendering = true
};
VkPhysicalDeviceVulkan12Features features12 {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES,
.descriptorIndexing = true,
.bufferDeviceAddress = true
};
// Use vkBootstrap to select the GPU
vkb::PhysicalDeviceSelector selector { vkbInst };
vkb::PhysicalDevice physicalDevice = selector
.set_minimum_version(1, 3)
.set_required_features_13(features13)
.set_required_features_12(features12)
.set_surface(_surface)
.select()
.value();
vkb::DeviceBuilder deviceBuilder { physicalDevice };
#ifdef DEBUG
fmt::println("Device {}", physicalDevice.name);
#endif
vkb::Device vkbDevice { deviceBuilder.build().value() };
_device = { vkbDevice.device };
_choosenGPU = { physicalDevice.physical_device };
_graphicsQueue = { vkbDevice.get_queue(vkb::QueueType::graphics).value() };
_graphicsQueueFamily = { vkbDevice.get_queue_index(vkb::QueueType::graphics).value() };
VmaAllocatorCreateInfo allocatorInfo = {};
allocatorInfo.physicalDevice = _choosenGPU;
allocatorInfo.device = _device;
allocatorInfo.instance = _instance;
allocatorInfo.flags = VMA_ALLOCATOR_CREATE_BUFFER_DEVICE_ADDRESS_BIT;
vmaCreateAllocator(&allocatorInfo, &_allocator);
_mainDeletionQueue.pushFunction([&]() {
vmaDestroyAllocator(_allocator);
});
#ifdef DEBUG
fmt::println("Vulkan initialized !");
#endif
}
void Engine::initSwapchain() {
#ifdef DEBUG
fmt::println("Initializing the swapchain...");
#endif
createSwapchain(_windowExtent.width, _windowExtent.height);
VkExtent3D drawImageExtent = {
_windowExtent.width,
_windowExtent.height,
1
};
// Hardcoding draw format to a 32 bit float
_drawImage.imageFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
_drawImage.imageExtent = drawImageExtent;
VkImageUsageFlags drawImageUsages {
VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_STORAGE_BIT |
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
};
VkImageCreateInfo rImgInfo = {
vkinit::imageCreateInfo(
_drawImage.imageFormat,
drawImageUsages,
drawImageExtent
)
};
// Use the GPU local memory for the draw image
VmaAllocationCreateInfo rImgAllocInfo = {
.usage = VMA_MEMORY_USAGE_GPU_ONLY,
.requiredFlags = VkMemoryPropertyFlags(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
};
vmaCreateImage(
_allocator,
&rImgInfo,
&rImgAllocInfo,
&_drawImage.image,
&_drawImage.allocation,
nullptr
);
VkImageViewCreateInfo rViewInfo = {
vkinit::imageViewCreateInfo(
_drawImage.imageFormat,
_drawImage.image,
VK_IMAGE_ASPECT_COLOR_BIT
)
};
VK_CHECK(
vkCreateImageView(
_device,
&rViewInfo,
nullptr,
&_drawImage.imageView
)
);
// Add to deletion queues
_mainDeletionQueue.pushFunction([this]() {
vkDestroyImageView(
_device,
_drawImage.imageView,
nullptr
);
vmaDestroyImage(
_allocator,
_drawImage.image,
_drawImage.allocation
);
});
#ifdef DEBUG
fmt::println("Swapchain initialized !");
#endif
}
void Engine::initCommands() {
#ifdef DEBUG
fmt::println("Initializing vulkan commands..");
#endif
VkCommandPoolCreateInfo commandPoolInfo = {
vkinit::commandPoolCreateInfo(
_graphicsQueueFamily,
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
)
};
for ( uint32_t i = 0; i < FRAME_OVERLAP; i++ ) {
VK_CHECK(
vkCreateCommandPool(
_device,
&commandPoolInfo,
nullptr,
&_frames[i]._commandPool
)
);
VkCommandBufferAllocateInfo cmdAllocInfo = vkinit::commandBufferAllocateInfo(_frames[i]._commandPool, 1);
VK_CHECK(
vkAllocateCommandBuffers(
_device,
&cmdAllocInfo,
&_frames[i]._mainCommandBuffer
)
);
}
#ifdef DEBUG
fmt::println("Vulan commands initialized !");
#endif
}
void Engine::initSyncStructures() {
#ifdef DEBUG
fmt::println("Creating sync structures...");
#endif
VkFenceCreateInfo fenceCreateInfo = vkinit::fenceCreateInfo(VK_FENCE_CREATE_SIGNALED_BIT);
VkSemaphoreCreateInfo semaphoreCreateInfo = vkinit::semaphoreCreateInfo();
for (int i = 0; i < FRAME_OVERLAP; i++) {
VK_CHECK(vkCreateFence(_device, &fenceCreateInfo, nullptr, &_frames[i]._renderFence));
VK_CHECK(vkCreateSemaphore(_device, &semaphoreCreateInfo, nullptr, &_frames[i]._swapchainSemaphore));
VK_CHECK(vkCreateSemaphore(_device, &semaphoreCreateInfo, nullptr, &_frames[i]._renderSemaphore));
}
#ifdef DEBUG
fmt::println("Sync structures created !");
#endif
}
void Engine::createSwapchain(
uint32_t width,
uint32_t height
) {
#ifdef DEBUG
fmt::println("Creating the Swapchain...");
#endif
vkb::SwapchainBuilder swapchainBuilder {
_choosenGPU,
_device,
_surface
};
_swapchainImageFormat = VK_FORMAT_B8G8R8A8_UNORM;
vkb::Swapchain vkbSwapchain = swapchainBuilder
.set_desired_format(
VkSurfaceFormatKHR {
.format = _swapchainImageFormat,
.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
}
)
.set_desired_present_mode(VK_PRESENT_MODE_FIFO_KHR) // VSync
.set_desired_extent(width, height)
.add_image_usage_flags(VK_IMAGE_USAGE_TRANSFER_DST_BIT)
.build()
.value();
_swapchainExtent = { vkbSwapchain.extent };
// Store swapchain and it's related images
_swapchain = { vkbSwapchain.swapchain };
_swapchainImages = { vkbSwapchain.get_images().value() };
_swapchainImageViews = { vkbSwapchain.get_image_views().value() };
#ifdef DEBUG
fmt::println("Swapchain created with dimentions {} by {}", vkbSwapchain.extent.width, vkbSwapchain.extent.height);
#endif
}
void Engine::destroySwapchain() {
#ifdef DEBUG
fmt::println("Destroying the swapchain...");
#endif
vkDestroySwapchainKHR(_device, _swapchain, nullptr);
for (uint32_t i = 0; i < _swapchainImageViews.size(); i++) {
vkDestroyImageView(_device, _swapchainImageViews[i], nullptr);
}
#ifdef DEBUG
fmt::println("Swapchain destroyed !");
#endif
}
void Engine::drawBackground(
VkCommandBuffer cmd
) {
VkClearColorValue clearValue;
float flash = { std::abs(std::sin(_frameNumber / 120.0f)) };
clearValue = { { 0.0f, 0.0f, flash, 1.0f } };
VkImageSubresourceRange clearRange = vkinit::imageSubresourceRange(VK_IMAGE_ASPECT_COLOR_BIT);
// Clear Image
vkCmdClearColorImage(
cmd,
_drawImage.image,
VK_IMAGE_LAYOUT_GENERAL,
&clearValue,
1,
&clearRange
);
}
#endif
#endif

View File

@ -1,131 +0,0 @@
#ifndef IMAGES_H
#define IMAGES_H
// Normal header
#include "types.h"
#include <cstdint>
#include <vulkan/vulkan_core.h>
namespace vkutil {
void transitionImage(
VkCommandBuffer cmd,
VkImage image,
VkImageLayout currentLayout,
VkImageLayout newLayout
);
void copyImageToImage(
VkCommandBuffer cmd,
VkImage source,
VkImage destination,
VkExtent2D srcSize,
VkExtent2D dstSize
);
}
#endif
#ifdef IMAGES_IMPL
#ifndef IMAGES_IMPL_H
#define IMAGES_IMPL_H
// Implementation
#include "initializers.h"
namespace vkutil {
// Todo :
// Switch structs to designated initializers
void transitionImage(
VkCommandBuffer cmd,
VkImage image,
VkImageLayout currentLayout,
VkImageLayout newLayout
) {
VkImageMemoryBarrier2 imageBarrier {.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER_2};
imageBarrier.pNext = nullptr;
imageBarrier.srcStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
imageBarrier.srcAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT;
imageBarrier.dstStageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT;
imageBarrier.dstAccessMask = VK_ACCESS_2_MEMORY_WRITE_BIT | VK_ACCESS_2_MEMORY_READ_BIT;
imageBarrier.oldLayout = currentLayout;
imageBarrier.newLayout = newLayout;
VkImageAspectFlags aspectMask = (newLayout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL) ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT;
imageBarrier.subresourceRange = vkinit::imageSubresourceRange(aspectMask);
imageBarrier.image = image;
VkDependencyInfo depInfo {};
depInfo.sType = VK_STRUCTURE_TYPE_DEPENDENCY_INFO;
depInfo.pNext = nullptr;
depInfo.imageMemoryBarrierCount = 1;
depInfo.pImageMemoryBarriers = &imageBarrier;
vkCmdPipelineBarrier2(cmd, &depInfo);
}
void copyImageToImage(
VkCommandBuffer cmd,
VkImage source,
VkImage destination,
VkExtent2D srcSize,
VkExtent2D dstSize
) {
VkImageBlit2 blitRegion {
.sType = VK_STRUCTURE_TYPE_IMAGE_BLIT_2,
.pNext = nullptr,
.srcSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1,
},
.srcOffsets = {
VkOffset3D { 0, 0, 0 },
VkOffset3D {
(int32_t)srcSize.width,
(int32_t)srcSize.height,
1
}
},
.dstSubresource = {
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.mipLevel = 0,
.baseArrayLayer = 0,
.layerCount = 1
},
.dstOffsets = {
VkOffset3D { 0, 0, 0 },
VkOffset3D {
(int32_t)dstSize.width,
(int32_t)dstSize.height,
1
}
},
};
VkBlitImageInfo2 blitInfo = {
.sType = VK_STRUCTURE_TYPE_BLIT_IMAGE_INFO_2,
.pNext = nullptr,
.srcImage = source,
.srcImageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
.dstImage = destination,
.dstImageLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
.regionCount = 1,
.pRegions = &blitRegion,
.filter = VK_FILTER_LINEAR,
};
vkCmdBlitImage2(cmd, &blitInfo);
}
}
#endif
#endif

View File

@ -1,248 +0,0 @@
#ifndef INITIALIZERS_H
#define INITIALIZERS_H
// Normal header
#include "types.h"
#include <vulkan/vulkan_core.h>
namespace vkinit {
VkCommandPoolCreateInfo commandPoolCreateInfo(
uint32_t queueFamilyIndex,
VkCommandPoolCreateFlags flags = 0
);
VkCommandBufferAllocateInfo commandBufferAllocateInfo(
VkCommandPool pool,
uint32_t count
);
VkFenceCreateInfo fenceCreateInfo(
VkFenceCreateFlags flags = 0
);
VkSemaphoreCreateInfo semaphoreCreateInfo (
VkSemaphoreCreateFlags flags = 0
);
VkCommandBufferBeginInfo commandBufferBeginInfo (
VkCommandBufferUsageFlags flags = 0
);
VkImageSubresourceRange imageSubresourceRange(
VkImageAspectFlags aspectMask
);
VkSemaphoreSubmitInfo semaphoreSubmitInfo(
VkPipelineStageFlags2 stageMask,
VkSemaphore semaphore
);
VkCommandBufferSubmitInfo commandBufferSubmitInfo (
VkCommandBuffer cmd
);
VkSubmitInfo2 submitInfo(
VkCommandBufferSubmitInfo* cmd,
VkSemaphoreSubmitInfo* signalSemaphoreInfo,
VkSemaphoreSubmitInfo* waitSemaphoreInfo
);
VkImageCreateInfo imageCreateInfo(
VkFormat format,
VkImageUsageFlags usageFlags,
VkExtent3D extent
);
VkImageViewCreateInfo imageViewCreateInfo(
VkFormat format,
VkImage image,
VkImageAspectFlags aspectFlags
);
}
#endif
#ifdef INITIALIZERS_IMPL
#ifndef INITIALIZERS_IMPL_H
#define INITIALIZERS_IMPL_H
// Implementation
namespace vkinit {
// Todo :
// Switch structs to designated initializers
VkCommandPoolCreateInfo commandPoolCreateInfo(
uint32_t queueFamilyIndex,
VkCommandPoolCreateFlags flags
) {
VkCommandPoolCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
info.pNext = nullptr;
info.queueFamilyIndex = queueFamilyIndex;
info.flags = flags;
return info;
}
VkCommandBufferAllocateInfo commandBufferAllocateInfo(
VkCommandPool pool,
uint32_t count
) {
VkCommandBufferAllocateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
info.pNext = nullptr;
info.commandPool = pool;
info.commandBufferCount = count;
info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
return info;
}
VkFenceCreateInfo fenceCreateInfo(
VkFenceCreateFlags flags /*= 0 */
) {
VkFenceCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
info.pNext = nullptr;
info.flags = flags;
return info;
}
VkSemaphoreCreateInfo semaphoreCreateInfo (
VkSemaphoreCreateFlags flags /*= 0*/
) {
VkSemaphoreCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
info.pNext = nullptr;
info.flags = flags;
return info;
}
VkCommandBufferBeginInfo commandBufferBeginInfo (
VkCommandBufferUsageFlags flags /*= 0*/
) {
VkCommandBufferBeginInfo info = {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
info.pNext = nullptr;
info.pInheritanceInfo = nullptr;
info.flags = flags;
return info;
}
VkImageSubresourceRange imageSubresourceRange(
VkImageAspectFlags aspectMask
) {
VkImageSubresourceRange subImage {};
subImage.aspectMask = aspectMask;
subImage.baseMipLevel = 0;
subImage.levelCount = VK_REMAINING_MIP_LEVELS;
subImage.baseArrayLayer = 0;
subImage.layerCount = VK_REMAINING_ARRAY_LAYERS;
return subImage;
}
VkSemaphoreSubmitInfo semaphoreSubmitInfo(
VkPipelineStageFlags2 stageMask,
VkSemaphore semaphore
) {
VkSemaphoreSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO;
submitInfo.pNext = nullptr;
submitInfo.semaphore = semaphore;
submitInfo.stageMask = stageMask;
submitInfo.deviceIndex = 0;
submitInfo.value = 1;
return submitInfo;
}
VkCommandBufferSubmitInfo commandBufferSubmitInfo (
VkCommandBuffer cmd
) {
VkCommandBufferSubmitInfo info {};
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_SUBMIT_INFO;
info.pNext = nullptr;
info.commandBuffer = cmd;
info.deviceMask = 0;
return info;
}
VkSubmitInfo2 submitInfo(
VkCommandBufferSubmitInfo* cmd,
VkSemaphoreSubmitInfo* signalSemaphoreInfo,
VkSemaphoreSubmitInfo* waitSemaphoreInfo
) {
VkSubmitInfo2 info = {};
info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO_2;
info.pNext = nullptr;
info.waitSemaphoreInfoCount = waitSemaphoreInfo == nullptr ? 0 : 1;
info.pWaitSemaphoreInfos = waitSemaphoreInfo;
info.signalSemaphoreInfoCount = signalSemaphoreInfo == nullptr ? 0 : 1;
info.pSignalSemaphoreInfos = signalSemaphoreInfo;
info.commandBufferInfoCount = 1;
info.pCommandBufferInfos = cmd;
return info;
}
VkImageCreateInfo imageCreateInfo(
VkFormat format,
VkImageUsageFlags usageFlags,
VkExtent3D extent
) {
VkImageCreateInfo info = {};
info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
info.pNext = nullptr;
info.imageType = VK_IMAGE_TYPE_2D;
info.format = format;
info.extent = extent;
info.mipLevels = 1;
info.arrayLayers = 1;
//for MSAA. I won't be using it, so only 1 sample per pixel
info.samples = VK_SAMPLE_COUNT_1_BIT;
info.tiling = VK_IMAGE_TILING_OPTIMAL;
info.usage = usageFlags;
return info;
}
// Switched to designated initializers,
// because it's more modern, and require less typing
VkImageViewCreateInfo imageViewCreateInfo(
VkFormat format,
VkImage image,
VkImageAspectFlags aspectFlags
) {
VkImageViewCreateInfo info = {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.pNext = nullptr,
.image = image,
.viewType = VK_IMAGE_VIEW_TYPE_2D,
.format = format,
.subresourceRange = {
.aspectMask = aspectFlags,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
}
};
return info;
}
}
#endif
#endif

View File

@ -1,13 +0,0 @@
#ifndef PIPELINES_H
#define PIPELINES_H
// Normal header
#endif
#ifdef PIPELINES_IMPL
#ifndef PIPELINES_IMPL_H
#define PIPELINES_IMPL_H
// Implementation
#endif
#endif

View File

@ -1,75 +0,0 @@
#ifndef TYPES_H
#define TYPES_H
// Normal header
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include <span>
#include <array>
#include <functional>
#include <deque>
#include <chrono>
#include <thread>
#include <fmt/base.h>
#include <stdexcept>
#include <cstdint>
#include <vulkan/vulkan.h>
#include <vulkan/vulkan_core.h>
#include <vulkan/vk_enum_string_helper.h>
#include <vk_mem_alloc.h>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <glm/mat4x4.hpp>
#include <glm/vec4.hpp>
// Custom headers
//#include "callbacks.h"
// Custom types
struct DeletionQueue {
std::deque<std::function<void()>> deletors;
void pushFunction(
std::function<void()>&& function
) {
deletors.push_back(function);
}
void flush() {
// Reverse iterate the deletion queue to destroy in order
for (
auto it = deletors.rbegin();
it != deletors.rend();
it++
) {
(*it)();
}
deletors.clear();
}
};
struct AllocatedImage {
VkImage image;
VkImageView imageView;
VmaAllocation allocation;
VkExtent3D imageExtent;
VkFormat imageFormat;
};
#endif
#ifdef TYPES_IMPL
#ifndef TYPES_IMPL_H
#define TYPES_IMPL_H
// Implementation
#endif
#endif

View File

@ -1,15 +0,0 @@
#define ENGINE_IMPL
#include "engine/engine.h"
int main(int argc, char* argv[]) {
Engine engine;
engine.init();
engine.run();
engine.cleanup();
return 0;
}