Added automatic shader inclusion.

Continued pipeline creation
This commit is contained in:
Alexandre 2026-07-25 21:33:53 +02:00
parent ec2955436d
commit 49963f3425
5 changed files with 193 additions and 30 deletions

View File

@ -91,7 +91,7 @@ endfunction()
# A function to automate executables aditions # A function to automate executables aditions
function ( addBinary BINARY_NAME ) function ( addBinary BINARY_NAME )
cmake_parse_arguments ( BINARY "IMGUI" "SOURCE" "SHADERS;SLANG_SHADERS;LIBS;TEXTURES;MODELS" ${ARGN} ) cmake_parse_arguments ( BINARY "IMGUI;LICENSE" "SOURCE" "SHADERS;SLANG_SHADERS;LIBS;TEXTURES;MODELS" ${ARGN} )
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()
@ -134,31 +134,43 @@ function ( addBinary BINARY_NAME )
) )
endif() endif()
if(BINARY_LICENSE)
file(COPY ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION ${CMAKE_BINARY_DIR}/${BINARY_NAME})
endif()
if(DEFINED BINARY_SHADERS) if(DEFINED BINARY_SHADERS)
set(SHADER_OUTPUT_DIR ${CMAKE_BINARY_DIR}/${BINARY_NAME}/shaders) set(SHADER_OUTPUT_DIR ${CMAKE_BINARY_DIR}/${BINARY_NAME}/shaders)
set(ALL_SPV_FILES "") set(ALL_SPV_FILES "")
foreach(SHADER_SRC ${BINARY_SHADERS}) set(EXPANDED_SHADERS "")
foreach(SHADER_PATTERN ${BINARY_SHADERS})
if(SHADER_PATTERN MATCHES "[*?]")
file(GLOB SHADER_FILES CONFIGURE_DEPENDS ${SHADER_PATTERN})
list(APPEND EXPANDED_SHADERS ${SHADER_FILES})
else()
list(APPEND EXPANDED_SHADERS ${SHADER_PATTERN})
endif()
endforeach()
foreach(SHADER_SRC ${EXPANDED_SHADERS})
if(NOT IS_ABSOLUTE ${SHADER_SRC}) if(NOT IS_ABSOLUTE ${SHADER_SRC})
set(SHADER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER_SRC}) set(SHADER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER_SRC})
endif() endif()
get_filename_component(EXT ${SHADER_SRC} EXT)
if(EXT STREQUAL ".slang")
addSlangShader(${SHADER_SRC} "${BINARY_SLANG_ENTRIES}" ${SHADER_OUTPUT_DIR})
list(APPEND ALL_SPV_FILES ${SPV_FILE})
else()
addGlslShader(${SHADER_SRC} ${SHADER_OUTPUT_DIR}) addGlslShader(${SHADER_SRC} ${SHADER_OUTPUT_DIR})
list(APPEND ALL_SPV_FILES ${SPV_FILE}) list(APPEND ALL_SPV_FILES ${SPV_FILE})
endif()
endforeach() endforeach()
add_custom_target(shaders_${BINARY_NAME} DEPENDS ${ALL_SPV_FILES}) add_custom_target(shaders_${BINARY_NAME} DEPENDS ${ALL_SPV_FILES})
add_dependencies(${BINARY_NAME} shaders_${BINARY_NAME}) add_dependencies(${BINARY_NAME} shaders_${BINARY_NAME})
endif() endif()
if(DEFINED BINARY_SLANG_SHADERS)
set(SLANG_OUTPUT_DIR ${CMAKE_BINARY_DIR}/${BINARY_NAME}/shaders)
if(NOT DEFINED BINARY_SLANG_ENTRIES)
message(FATAL_ERROR "addBinary: SLANG_SHADERS nécessite SLANG_ENTRIES")
endif()
addSlangShader("${BINARY_SLANG_SHADERS}" "${BINARY_SLANG_ENTRIES}" ${SLANG_OUTPUT_DIR})
add_custom_target(slang_shaders_${BINARY_NAME} DEPENDS ${SPV_FILE})
add_dependencies(${BINARY_NAME} slang_shaders_${BINARY_NAME})
endif()
if (DEFINED BINARY_LIBS) if (DEFINED BINARY_LIBS)
target_link_libraries ( ${BINARY_NAME} ${BINARY_LIBS} ) target_link_libraries ( ${BINARY_NAME} ${BINARY_LIBS} )
endif() endif()
@ -192,17 +204,21 @@ function ( addBinary BINARY_NAME )
endif () endif ()
endfunction() endfunction()
# Scan the shader folder
file(GLOB SHADER_SOURCES CONFIGURE_DEPENDS "shaders/*")
# Adds the main binary # Adds the main binary
addBinary ( addBinary (
engine engine
SOURCE Engine/main SOURCE Engine/main
SHADERS shaders/gradient.comp SHADERS ${SHADER_SOURCES}
SHADERS shaders/gradient_color.comp SHADERS
SHADERS shaders/sky.comp
LIBS glfw fmt vk-bootstrap vulkan LIBS glfw fmt vk-bootstrap vulkan
IMGUI IMGUI
LICENSE
) )
addBinary ( addBinary (

View File

@ -0,0 +1,30 @@
static float2 positions[3] = float2[](
float2(0.0, -0.5),
float2(0.5, 0.5),
float2(-0.5, 0.5)
);
static float3 colors[3] = float3[] (
float3(1.0, 0.0, 0.0),
float3(0.0, 1.0, 0.0),
float3(0.0, 0.0, 1.0)
);
struct VertexOutput {
float3 color;
float4 sv_position : SV_Position;
};
[shader("vertex")]
VertexOutput vertMain(uint vid : SV_VertexID) {
VertexOutput output;
output.sv_position = float4(positions[vid], 0.0, 1.0);
output.color = colors[vid];
return output;
}
[shader("fragment")]
float4 fragMain(VertexOutput inVert) : SV_Target {
float3 color = inVert.color;
return float4(color, 1.0);
}

View File

@ -3,7 +3,7 @@
// Normal header // Normal header
// Current progress // Current progress
// 3 - Graphics Pipeline - Setting up the render pipeline // 3 - Graphics Pipeline - Doing PipelineBuilder functions
#include "descriptors.h" // Required for public interface custom allocator #include "descriptors.h" // Required for public interface custom allocator
#include "Common/Types.h" #include "Common/Types.h"
@ -18,7 +18,6 @@ struct FrameData {
VkCommandPool _commandPool; VkCommandPool _commandPool;
VkCommandBuffer _mainCommandBuffer; VkCommandBuffer _mainCommandBuffer;
VkSemaphore _swapchainSemaphore; VkSemaphore _swapchainSemaphore;
VkSemaphore _renderSemaphore;
VkFence _renderFence; VkFence _renderFence;
DeletionQueue _deletionQueue; DeletionQueue _deletionQueue;
}; };
@ -68,11 +67,15 @@ class Engine {
FrameData& getCurrentFrame() { return _frames[_frameNumber % FRAME_OVERLAP]; }; FrameData& getCurrentFrame() { return _frames[_frameNumber % FRAME_OVERLAP]; };
// Sync
std::vector<VkSemaphore> _renderSemaphores; // It's size should be the number of swapchain images
VkQueue _graphicsQueue; VkQueue _graphicsQueue;
uint32_t _graphicsQueueFamily; uint32_t _graphicsQueueFamily;
// Deletion queue // Deletion queue
DeletionQueue _mainDeletionQueue; DeletionQueue _mainDeletionQueue;
DeletionQueue _syncDeletionQueue;
VmaAllocator _allocator; VmaAllocator _allocator;
// Draw resources // Draw resources
@ -204,9 +207,15 @@ constexpr bool bUseValidationLayers = true;
void Engine::init() { void Engine::init() {
#ifdef DEBUG #ifdef DEBUG
std::ifstream infile("LICENSE");
fmt::println("[Engine:Init] Initializing the engine..."); fmt::println("[Engine:Init] Initializing the engine...");
fmt::println("[Engine:Info] Current engine version {}", BUILD_ID); fmt::println("[Engine:Info] Current engine version {}", BUILD_ID);
fmt::println("[Engine:Info] Compiled on {} at {}", __DATE__ ,__TIME__); fmt::println("[Engine:Info] Compiled on {} at {}", __DATE__ ,__TIME__);
if (infile.good()) {
std::string sLine;
std::getline(infile, sLine);
fmt::println("[Engine:Info] Current Licence : {}", sLine);
}
#endif #endif
glfwInit(); glfwInit();
@ -241,12 +250,11 @@ void Engine::cleanup() {
// Wait for the GPU to stop working // Wait for the GPU to stop working
vkDeviceWaitIdle(_device); vkDeviceWaitIdle(_device);
_syncDeletionQueue.flush();
for (int i = 0; i < FRAME_OVERLAP; i++) { for (int i = 0; i < FRAME_OVERLAP; i++) {
vkDestroyCommandPool(_device, _frames[i]._commandPool, nullptr); vkDestroyCommandPool(_device, _frames[i]._commandPool, nullptr);
// Destroy sync objects // 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 // Uses the deletion queue to clear ressources
_frames[i]._deletionQueue.flush(); _frames[i]._deletionQueue.flush();
@ -302,6 +310,8 @@ void Engine::draw() {
uint32_t swapchainImageIndex; uint32_t swapchainImageIndex;
VkResult aquireResult {vkAcquireNextImageKHR(_device, _swapchain, UINT64_MAX, getCurrentFrame()._swapchainSemaphore, nullptr, &swapchainImageIndex)}; VkResult aquireResult {vkAcquireNextImageKHR(_device, _swapchain, UINT64_MAX, getCurrentFrame()._swapchainSemaphore, nullptr, &swapchainImageIndex)};
VkSemaphore renderSemaphore = _renderSemaphores[swapchainImageIndex];
if (aquireResult == VK_SUBOPTIMAL_KHR || aquireResult == VK_ERROR_OUT_OF_DATE_KHR) { if (aquireResult == VK_SUBOPTIMAL_KHR || aquireResult == VK_ERROR_OUT_OF_DATE_KHR) {
// Recreate swapchain // Recreate swapchain
_requestResize = true; _requestResize = true;
@ -388,7 +398,7 @@ void Engine::draw() {
VkCommandBufferSubmitInfo cmdinfo = vkinit::commandBufferSubmitInfo(cmd); VkCommandBufferSubmitInfo cmdinfo = vkinit::commandBufferSubmitInfo(cmd);
VkSemaphoreSubmitInfo waitInfo = vkinit::semaphoreSubmitInfo(VK_PIPELINE_STAGE_2_COLOR_ATTACHMENT_OUTPUT_BIT_KHR, getCurrentFrame()._swapchainSemaphore); 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); VkSemaphoreSubmitInfo signalInfo = vkinit::semaphoreSubmitInfo(VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT, renderSemaphore);
VkSubmitInfo2 submit = vkinit::submitInfo(&cmdinfo, &signalInfo, &waitInfo); VkSubmitInfo2 submit = vkinit::submitInfo(&cmdinfo, &signalInfo, &waitInfo);
@ -400,7 +410,7 @@ void Engine::draw() {
presentInfo.pSwapchains = &_swapchain; presentInfo.pSwapchains = &_swapchain;
presentInfo.swapchainCount = 1; presentInfo.swapchainCount = 1;
presentInfo.pWaitSemaphores = &getCurrentFrame()._renderSemaphore; presentInfo.pWaitSemaphores = &renderSemaphore;
presentInfo.waitSemaphoreCount = 1; presentInfo.waitSemaphoreCount = 1;
presentInfo.pImageIndices = &swapchainImageIndex; presentInfo.pImageIndices = &swapchainImageIndex;
@ -703,16 +713,33 @@ void Engine::initSyncStructures() {
fmt::println("[Engine:Init] Creating sync structures..."); fmt::println("[Engine:Init] Creating sync structures...");
#endif #endif
VkFenceCreateInfo fenceCreateInfo = vkinit::fenceCreateInfo(VK_FENCE_CREATE_SIGNALED_BIT); // Render semaphores, depends on swapchain
_renderSemaphores.resize(_swapchainImages.size());
VkSemaphoreCreateInfo semaphoreCreateInfo = vkinit::semaphoreCreateInfo(); VkSemaphoreCreateInfo semaphoreCreateInfo = vkinit::semaphoreCreateInfo();
for (size_t i = 0; i < _renderSemaphores.size(); ++i) {
VK_CHECK(vkCreateSemaphore(_device, &semaphoreCreateInfo, nullptr, &_renderSemaphores[i]));
_syncDeletionQueue.pushFunction([this, i]() {
vkDestroySemaphore(_device, _renderSemaphores[i], nullptr);
});
}
// Now, other sync objects, that depends on FRAME_OVERLAP
VkFenceCreateInfo fenceCreateInfo = vkinit::fenceCreateInfo(VK_FENCE_CREATE_SIGNALED_BIT);
for (int i = 0; i < FRAME_OVERLAP; i++) { for (int i = 0; i < FRAME_OVERLAP; i++) {
VK_CHECK(vkCreateFence(_device, &fenceCreateInfo, nullptr, &_frames[i]._renderFence)); 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]._swapchainSemaphore));
VK_CHECK(vkCreateSemaphore(_device, &semaphoreCreateInfo, nullptr, &_frames[i]._renderSemaphore));
_syncDeletionQueue.pushFunction([this, i]() {
vkDestroyFence(_device, _frames[i]._renderFence, nullptr);
vkDestroySemaphore(_device, _frames[i]._swapchainSemaphore, nullptr);
});
} }
// Immediate sync objects // Immediate sync objects
VK_CHECK( VK_CHECK(
vkCreateFence( vkCreateFence(
@ -723,7 +750,7 @@ void Engine::initSyncStructures() {
); );
); );
_mainDeletionQueue.pushFunction([this]() { _syncDeletionQueue.pushFunction([this]() {
vkDestroyFence( vkDestroyFence(
_device, _device,
_immFence, _immFence,
@ -1331,8 +1358,12 @@ void Engine::resizeSwapchain() {
_windowExtent.width = w; _windowExtent.width = w;
_windowExtent.height = h; _windowExtent.height = h;
_syncDeletionQueue.flush();
createSwapchain(_windowExtent.width, _windowExtent.height); createSwapchain(_windowExtent.width, _windowExtent.height);
initSyncStructures();
_requestResize = false; _requestResize = false;
#ifdef DEBUG #ifdef DEBUG

View File

@ -45,6 +45,29 @@ class PipelineBuilder {
void setInputTopology( void setInputTopology(
VkPrimitiveTopology topology VkPrimitiveTopology topology
); );
void setPolygonMode(
VkPolygonMode mode
);
void setCullMode(
VkCullModeFlags cullMode,
VkFrontFace frontFace
);
void setMultisamplingNone();
void disableBlending ();
void setColorAttachmentFormat(
VkFormat format
);
void setDepthFormat(
VkFormat format
);
void disableDepthtest();
}; };
#endif #endif
@ -265,5 +288,65 @@ void PipelineBuilder::setShaders(
); );
} }
void PipelineBuilder::setInputTopology(
VkPrimitiveTopology topology
) {
_inputAssembly.topology = topology;
// I am not going to use primitive restart rn
// so I leave it on false
_inputAssembly.primitiveRestartEnable = VK_FALSE;
}
void PipelineBuilder::setPolygonMode(
VkPolygonMode mode
) {
_rasterizer.polygonMode = mode;
_rasterizer.lineWidth = 1.0f;
}
void PipelineBuilder::setCullMode(
VkCullModeFlags cullMode,
VkFrontFace frontFace
) {
_rasterizer.cullMode = cullMode;
_rasterizer.frontFace = frontFace;
}
void PipelineBuilder::setMultisamplingNone() {
_multisampling.sampleShadingEnable = VK_FALSE;
// Multisampling defaulted to no multisampling (1 sample per pixel)
_multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
_multisampling.minSampleShading = 1.0f;
_multisampling.pSampleMask = nullptr;
// No alpha to coverage either
_multisampling.alphaToCoverageEnable = VK_FALSE;
_multisampling.alphaToOneEnable = VK_FALSE;
}
void PipelineBuilder::disableBlending() {
// Default write mask
_colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
// No blending
_colorBlendAttachment.blendEnable = VK_FALSE;
}
void PipelineBuilder::setDepthFormat(
VkFormat format
) {
_renderInfo.depthAttachmentFormat = format;
}
void PipelineBuilder::disableDepthtest() {
_depthStencil.depthTestEnable = VK_FALSE;
_depthStencil.depthWriteEnable = VK_FALSE;
_depthStencil.depthCompareOp = VK_COMPARE_OP_NEVER;
_depthStencil.depthBoundsTestEnable = VK_FALSE;
_depthStencil.stencilTestEnable = VK_FALSE;
_depthStencil.front = {};
_depthStencil.back = {};
_depthStencil.minDepthBounds = 0.0f;
_depthStencil.maxDepthBounds = 1.0f;
}
#endif #endif
#endif #endif

View File

@ -5,6 +5,9 @@
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
Engine engine; Engine engine;
// Exemple of overwriting a class value
//engine._windowExtent = { 67, 67 };
engine.init(); engine.init();
engine.run(); engine.run();