diff --git a/CMakeLists.txt b/CMakeLists.txt index 6bf0029..9cffe4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,7 +91,7 @@ endfunction() # A function to automate executables aditions 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) add_executable ( ${BINARY_NAME} src/${BINARY_SOURCE}.cpp ) endif() @@ -134,31 +134,43 @@ function ( addBinary BINARY_NAME ) ) endif() + if(BINARY_LICENSE) + file(COPY ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION ${CMAKE_BINARY_DIR}/${BINARY_NAME}) + endif() + + if(DEFINED BINARY_SHADERS) set(SHADER_OUTPUT_DIR ${CMAKE_BINARY_DIR}/${BINARY_NAME}/shaders) 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}) set(SHADER_SRC ${CMAKE_CURRENT_SOURCE_DIR}/${SHADER_SRC}) endif() - addGlslShader(${SHADER_SRC} ${SHADER_OUTPUT_DIR}) - list(APPEND ALL_SPV_FILES ${SPV_FILE}) + 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}) + list(APPEND ALL_SPV_FILES ${SPV_FILE}) + endif() endforeach() add_custom_target(shaders_${BINARY_NAME} DEPENDS ${ALL_SPV_FILES}) add_dependencies(${BINARY_NAME} shaders_${BINARY_NAME}) 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) target_link_libraries ( ${BINARY_NAME} ${BINARY_LIBS} ) endif() @@ -192,17 +204,21 @@ function ( addBinary BINARY_NAME ) endif () endfunction() + +# Scan the shader folder +file(GLOB SHADER_SOURCES CONFIGURE_DEPENDS "shaders/*") + # Adds the main binary addBinary ( engine SOURCE Engine/main - SHADERS shaders/gradient.comp - SHADERS shaders/gradient_color.comp - SHADERS shaders/sky.comp + SHADERS ${SHADER_SOURCES} + SHADERS LIBS glfw fmt vk-bootstrap vulkan IMGUI + LICENSE ) addBinary ( diff --git a/shaders/colored_triangle.slang b/shaders/colored_triangle.slang new file mode 100644 index 0000000..d61c968 --- /dev/null +++ b/shaders/colored_triangle.slang @@ -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); +} diff --git a/src/Engine/engine/engine.h b/src/Engine/engine/engine.h index 9c02978..0b5a09b 100644 --- a/src/Engine/engine/engine.h +++ b/src/Engine/engine/engine.h @@ -3,7 +3,7 @@ // Normal header // 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 "Common/Types.h" @@ -18,7 +18,6 @@ struct FrameData { VkCommandPool _commandPool; VkCommandBuffer _mainCommandBuffer; VkSemaphore _swapchainSemaphore; - VkSemaphore _renderSemaphore; VkFence _renderFence; DeletionQueue _deletionQueue; }; @@ -68,11 +67,15 @@ class Engine { FrameData& getCurrentFrame() { return _frames[_frameNumber % FRAME_OVERLAP]; }; + // Sync + std::vector _renderSemaphores; // It's size should be the number of swapchain images + VkQueue _graphicsQueue; uint32_t _graphicsQueueFamily; // Deletion queue DeletionQueue _mainDeletionQueue; + DeletionQueue _syncDeletionQueue; VmaAllocator _allocator; // Draw resources @@ -204,9 +207,15 @@ constexpr bool bUseValidationLayers = true; void Engine::init() { #ifdef DEBUG + std::ifstream infile("LICENSE"); fmt::println("[Engine:Init] Initializing the engine..."); fmt::println("[Engine:Info] Current engine version {}", BUILD_ID); 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 glfwInit(); @@ -241,12 +250,11 @@ void Engine::cleanup() { // Wait for the GPU to stop working vkDeviceWaitIdle(_device); + _syncDeletionQueue.flush(); + 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); + // Sync objects // Uses the deletion queue to clear ressources _frames[i]._deletionQueue.flush(); @@ -302,6 +310,8 @@ void Engine::draw() { uint32_t 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) { // Recreate swapchain _requestResize = true; @@ -388,7 +398,7 @@ void Engine::draw() { 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); + VkSemaphoreSubmitInfo signalInfo = vkinit::semaphoreSubmitInfo(VK_PIPELINE_STAGE_2_ALL_GRAPHICS_BIT, renderSemaphore); VkSubmitInfo2 submit = vkinit::submitInfo(&cmdinfo, &signalInfo, &waitInfo); @@ -400,7 +410,7 @@ void Engine::draw() { presentInfo.pSwapchains = &_swapchain; presentInfo.swapchainCount = 1; - presentInfo.pWaitSemaphores = &getCurrentFrame()._renderSemaphore; + presentInfo.pWaitSemaphores = &renderSemaphore; presentInfo.waitSemaphoreCount = 1; presentInfo.pImageIndices = &swapchainImageIndex; @@ -703,15 +713,32 @@ void Engine::initSyncStructures() { fmt::println("[Engine:Init] Creating sync structures..."); #endif - VkFenceCreateInfo fenceCreateInfo = vkinit::fenceCreateInfo(VK_FENCE_CREATE_SIGNALED_BIT); + // Render semaphores, depends on swapchain + _renderSemaphores.resize(_swapchainImages.size()); 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++) { 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)); - } + VK_CHECK(vkCreateSemaphore(_device, &semaphoreCreateInfo, nullptr, &_frames[i]._swapchainSemaphore)); + + _syncDeletionQueue.pushFunction([this, i]() { + vkDestroyFence(_device, _frames[i]._renderFence, nullptr); + vkDestroySemaphore(_device, _frames[i]._swapchainSemaphore, nullptr); + }); + } + // Immediate sync objects VK_CHECK( @@ -723,7 +750,7 @@ void Engine::initSyncStructures() { ); ); - _mainDeletionQueue.pushFunction([this]() { + _syncDeletionQueue.pushFunction([this]() { vkDestroyFence( _device, _immFence, @@ -1331,8 +1358,12 @@ void Engine::resizeSwapchain() { _windowExtent.width = w; _windowExtent.height = h; + + _syncDeletionQueue.flush(); createSwapchain(_windowExtent.width, _windowExtent.height); + initSyncStructures(); + _requestResize = false; #ifdef DEBUG diff --git a/src/Engine/engine/pipelines.h b/src/Engine/engine/pipelines.h index fe0e901..d9d8c69 100644 --- a/src/Engine/engine/pipelines.h +++ b/src/Engine/engine/pipelines.h @@ -45,6 +45,29 @@ class PipelineBuilder { void setInputTopology( 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 @@ -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 diff --git a/src/Engine/main.cpp b/src/Engine/main.cpp index 544c0b6..bd0db34 100644 --- a/src/Engine/main.cpp +++ b/src/Engine/main.cpp @@ -5,6 +5,9 @@ int main(int argc, char* argv[]) { Engine engine; + // Exemple of overwriting a class value + //engine._windowExtent = { 67, 67 }; + engine.init(); engine.run();