diff --git a/config/Sources.cmake b/config/Sources.cmake index fefdb6d8c8400d50424fdb3c95d732c6c4ce08e2..1b35d798597d0c781d5c4e90679679a83fcedcb2 100644 --- a/config/Sources.cmake +++ b/config/Sources.cmake @@ -56,9 +56,6 @@ set(vkcv_sources ${vkcv_source}/vkcv/ImageLayoutTransitions.hpp ${vkcv_source}/vkcv/ImageLayoutTransitions.cpp - - ${vkcv_source}/vkcv/Framebuffer.hpp - ${vkcv_source}/vkcv/Framebuffer.cpp ${vkcv_include}/vkcv/VertexLayout.hpp ${vkcv_source}/vkcv/VertexLayout.cpp diff --git a/include/vkcv/PassConfig.hpp b/include/vkcv/PassConfig.hpp index b8e80c67c2b70e3a0e6e2732b950ccaed38da3bf..d9a5bcd83acca5f5ba86b4e6ce6973acbed89de6 100644 --- a/include/vkcv/PassConfig.hpp +++ b/include/vkcv/PassConfig.hpp @@ -53,7 +53,6 @@ namespace vkcv struct PassConfig { - PassConfig() = delete; explicit PassConfig(std::vector<AttachmentDescription> attachments) noexcept; std::vector<AttachmentDescription> attachments{}; }; diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp index ced7867ee26e4b3d9d700eb3a7a46ec326b966e2..6ba3656f6c02077a868c5d99b1331fab5be0abe6 100644 --- a/projects/first_mesh/src/main.cpp +++ b/projects/first_mesh/src/main.cpp @@ -60,9 +60,19 @@ int main(int argc, const char** argv) { vkcv::AttachmentLayout::PRESENTATION, vkcv::AttachmentOperation::STORE, vkcv::AttachmentOperation::CLEAR, - core.getSwapchainImageFormat()); + core.getSwapchainImageFormat() + ); + + const vkcv::AttachmentDescription depth_attachment( + vkcv::AttachmentLayout::UNDEFINED, + vkcv::AttachmentLayout::DEPTH_STENCIL_ATTACHMENT, + vkcv::AttachmentLayout::DEPTH_STENCIL_ATTACHMENT, + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR, + vk::Format::eD32Sfloat + ); - vkcv::PassConfig trianglePassDefinition({ present_color_attachment }); + vkcv::PassConfig trianglePassDefinition({ present_color_attachment, depth_attachment }); vkcv::PassHandle trianglePass = core.createPass(trianglePassDefinition); if (!trianglePass) { @@ -98,7 +108,18 @@ int main(int argc, const char** argv) { cameraManager.getCamera().updateView(std::chrono::duration<double>(deltatime).count()); const glm::mat4 mvp = cameraManager.getCamera().getProjection() * cameraManager.getCamera().getView(); - core.renderMesh(trianglePass, trianglePipeline, windowWidth, windowHeight, sizeof(mvp), &mvp, vertexBuffer.getHandle(), indexBuffer.getHandle(), mesh.vertexGroups[0].numIndices); + core.renderMesh( + trianglePass, + trianglePipeline, + windowWidth, + windowHeight, + sizeof(mvp), + &mvp, + vertexBuffer.getHandle(), + indexBuffer.getHandle(), + mesh.vertexGroups[0].numIndices + ); + core.endFrame(); } diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index 5c924743c95f67f00095264f9d99308b1403b017..d24282f194e79c36096677b7f13d4b218911c3a1 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -14,7 +14,6 @@ #include "DescriptorManager.hpp" #include "Surface.hpp" #include "ImageLayoutTransitions.hpp" -#include "Framebuffer.hpp" namespace vkcv { @@ -122,8 +121,7 @@ namespace vkcv PipelineHandle Core::createGraphicsPipeline(const PipelineConfig &config) { - const vk::RenderPass &pass = m_PassManager->getVkPass(config.m_PassHandle); - return m_PipelineManager->createPipeline(config, pass); + return m_PipelineManager->createPipeline(config, *m_PassManager); } @@ -165,6 +163,13 @@ namespace vkcv m_Context.getDevice().waitIdle(); // FIMXE: this is a sin against graphics programming, but its getting late - Alex destroyTemporaryFramebuffers(); } + + vk::Framebuffer createFramebuffer(const vk::Device device, const vk::RenderPass& renderpass, + const int width, const int height, const std::vector<vk::ImageView>& attachments) { + const vk::FramebufferCreateFlags flags = {}; + const vk::FramebufferCreateInfo createInfo(flags, renderpass, attachments.size(), attachments.data(), width, height, 1); + return device.createFramebuffer(createInfo); + } void Core::renderMesh(const PassHandle renderpassHandle, const PipelineHandle pipelineHandle, const int width, const int height, const size_t pushConstantSize, const void *pushConstantData, @@ -175,6 +180,17 @@ namespace vkcv } const vk::RenderPass renderpass = m_PassManager->getVkPass(renderpassHandle); + const PassConfig passConfig = m_PassManager->getPassConfig(renderpassHandle); + + ImageHandle depthImage; + + for (const auto& attachment : passConfig.attachments) { + if (attachment.layout_final == AttachmentLayout::DEPTH_STENCIL_ATTACHMENT) { + depthImage = m_ImageManager->createImage(width, height, 1, attachment.format); + break; + } + } + const vk::ImageView imageView = m_swapchainImageViews[m_currentSwapchainImageIndex]; const vk::Pipeline pipeline = m_PipelineManager->getVkPipeline(pipelineHandle); const vk::PipelineLayout pipelineLayout = m_PipelineManager->getVkPipelineLayout(pipelineHandle); @@ -182,19 +198,47 @@ namespace vkcv const vk::Buffer vulkanVertexBuffer = m_BufferManager->getBuffer(vertexBuffer); const vk::Buffer vulkanIndexBuffer = m_BufferManager->getBuffer(indexBuffer); - const vk::Framebuffer framebuffer = createFramebuffer(m_Context.getDevice(), renderpass, width, height, imageView); + std::vector<vk::ImageView> attachments; + attachments.push_back(imageView); + + if (depthImage) { + attachments.push_back(m_ImageManager->getVulkanImageView(depthImage)); + } + + const vk::Framebuffer framebuffer = createFramebuffer( + m_Context.getDevice(), + renderpass, + width, + height, + attachments + ); + m_TemporaryFramebuffers.push_back(framebuffer); SubmitInfo submitInfo; submitInfo.queueType = QueueType::Graphics; submitInfo.signalSemaphores = { m_SyncResources.renderFinished }; - submitCommands(submitInfo, [renderpass, renderArea, imageView, framebuffer, pipeline, pipelineLayout, - pushConstantSize, pushConstantData, vulkanVertexBuffer, indexCount, vulkanIndexBuffer](const vk::CommandBuffer& cmdBuffer) { - - const std::array<float, 4> clearColor = { 0.f, 0.f, 0.f, 1.f }; - const vk::ClearValue clearValues(clearColor); - - const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, 1, &clearValues); + submitCommands(submitInfo, [&](const vk::CommandBuffer& cmdBuffer) { + std::vector<vk::ClearValue> clearValues; + + for (const auto& attachment : passConfig.attachments) { + if (attachment.load_operation == AttachmentOperation::CLEAR) { + float clear = 0.0f; + + if (attachment.layout_final == AttachmentLayout::DEPTH_STENCIL_ATTACHMENT) { + clear = 1.0f; + } + + clearValues.emplace_back(std::array<float, 4>{ + clear, + clear, + clear, + 1.f + }); + } + } + + const vk::RenderPassBeginInfo beginInfo(renderpass, framebuffer, renderArea, clearValues.size(), clearValues.data()); const vk::SubpassContents subpassContents = {}; cmdBuffer.beginRenderPass(beginInfo, subpassContents, {}); @@ -205,7 +249,9 @@ namespace vkcv cmdBuffer.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eAll, 0, pushConstantSize, pushConstantData); cmdBuffer.drawIndexed(indexCount, 1, 0, 0, {}); cmdBuffer.endRenderPass(); - }, nullptr); + }, [&]() { + m_ImageManager->destroyImage(depthImage); + }); } void Core::endFrame() { diff --git a/src/vkcv/Framebuffer.cpp b/src/vkcv/Framebuffer.cpp deleted file mode 100644 index 3b3e8000668e460d476b211984e9e12249f066c0..0000000000000000000000000000000000000000 --- a/src/vkcv/Framebuffer.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "Framebuffer.hpp" - -namespace vkcv { - vk::Framebuffer createFramebuffer(const vk::Device device, const vk::RenderPass renderpass, - const int width, const int height, const vk::ImageView imageView) { - const vk::FramebufferCreateFlags flags = {}; - const uint32_t attachmentCount = 1; // TODO: proper value - const vk::FramebufferCreateInfo createInfo(flags, renderpass, attachmentCount, &imageView, width, height, 1); - return device.createFramebuffer(createInfo, nullptr, {}); - } -} \ No newline at end of file diff --git a/src/vkcv/Framebuffer.hpp b/src/vkcv/Framebuffer.hpp deleted file mode 100644 index 7d5d718adbde0c3f8eb8d97c539fb73f7771987f..0000000000000000000000000000000000000000 --- a/src/vkcv/Framebuffer.hpp +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once -#include <vulkan/vulkan.hpp> - -namespace vkcv{ - vk::Framebuffer createFramebuffer(const vk::Device device, const vk::RenderPass renderpass, - const int width, const int height, const vk::ImageView imageView); -} \ No newline at end of file diff --git a/src/vkcv/ImageManager.cpp b/src/vkcv/ImageManager.cpp index 6716024e25071db1ca41247179278d342d62c3cd..3896d6bc4abdd24264ad5d468b49ebf08bd20be7 100644 --- a/src/vkcv/ImageManager.cpp +++ b/src/vkcv/ImageManager.cpp @@ -67,6 +67,12 @@ namespace vkcv { vk::ImageUsageFlags imageUsageFlags = ( vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eTransferDst ); + + const bool isDepthFormat = isDepthImageFormat(format); + + if (isDepthFormat) { + imageUsageFlags |= vk::ImageUsageFlagBits::eDepthStencilAttachment; + } const vk::Device& device = m_core->getContext().getDevice(); @@ -131,7 +137,7 @@ namespace vkcv { vk::ImageAspectFlags aspectFlags; - if (isDepthImageFormat(format)) { + if (isDepthFormat) { aspectFlags = vk::ImageAspectFlagBits::eDepth; } else { aspectFlags = vk::ImageAspectFlagBits::eColor; diff --git a/src/vkcv/PassManager.cpp b/src/vkcv/PassManager.cpp index d69024a805f45cda549365c7cc97fc57f59ef926..26e5f290d04ebaf16940cd99386253b5ab3622cc 100644 --- a/src/vkcv/PassManager.cpp +++ b/src/vkcv/PassManager.cpp @@ -49,16 +49,16 @@ namespace vkcv PassManager::PassManager(vk::Device device) noexcept : m_Device{device}, - m_RenderPasses{}, + m_Passes{}, m_NextPassId(0) {} PassManager::~PassManager() noexcept { - for(const auto &pass : m_RenderPasses) - m_Device.destroy(pass); - - m_RenderPasses.clear(); + for(const auto &pass : m_Passes) + m_Device.destroy(pass.m_Handle); + + m_Passes.clear(); m_NextPassId = 0; } @@ -90,46 +90,74 @@ namespace vkcv colorAttachmentReferences.push_back(attachmentRef); } - vk::AttachmentDescription attachmentDesc({}, - format, - vk::SampleCountFlagBits::e1, - getVKLoadOpFromAttachOp(config.attachments[i].load_operation), - getVkStoreOpFromAttachOp(config.attachments[i].store_operation), - vk::AttachmentLoadOp::eDontCare, - vk::AttachmentStoreOp::eDontCare, - getVkLayoutFromAttachLayout(config.attachments[i].layout_initial), - getVkLayoutFromAttachLayout(config.attachments[i].layout_final)); + vk::AttachmentDescription attachmentDesc( + {}, + format, + vk::SampleCountFlagBits::e1, + getVKLoadOpFromAttachOp(config.attachments[i].load_operation), + getVkStoreOpFromAttachOp(config.attachments[i].store_operation), + vk::AttachmentLoadOp::eDontCare, + vk::AttachmentStoreOp::eDontCare, + getVkLayoutFromAttachLayout(config.attachments[i].layout_initial), + getVkLayoutFromAttachLayout(config.attachments[i].layout_final) + ); + attachmentDescriptions.push_back(attachmentDesc); } - vk::SubpassDescription subpassDescription({}, - vk::PipelineBindPoint::eGraphics, - 0, - {}, - static_cast<uint32_t>(colorAttachmentReferences.size()), - colorAttachmentReferences.data(), - {}, - pDepthAttachment, - 0, - {}); - - vk::RenderPassCreateInfo passInfo({}, - static_cast<uint32_t>(attachmentDescriptions.size()), - attachmentDescriptions.data(), - 1, - &subpassDescription, - 0, - {}); + + const vk::SubpassDescription subpassDescription( + {}, + vk::PipelineBindPoint::eGraphics, + 0, + {}, + static_cast<uint32_t>(colorAttachmentReferences.size()), + colorAttachmentReferences.data(), + {}, + pDepthAttachment, + 0, + {} + ); - vk::RenderPass vkObject{nullptr}; - if(m_Device.createRenderPass(&passInfo, nullptr, &vkObject) != vk::Result::eSuccess) - return PassHandle(); + const vk::RenderPassCreateInfo passInfo( + {}, + static_cast<uint32_t>(attachmentDescriptions.size()), + attachmentDescriptions.data(), + 1, + &subpassDescription, + 0, + {} + ); - m_RenderPasses.push_back(vkObject); + vk::RenderPass renderPass = m_Device.createRenderPass(passInfo); + + m_Passes.push_back({ renderPass, config }); return PassHandle(m_NextPassId++); } vk::RenderPass PassManager::getVkPass(const PassHandle &handle) const { - return m_RenderPasses[handle.getId()]; + const uint64_t id = handle.getId(); + + if (id >= m_Passes.size()) { + return nullptr; + } + + auto& pass = m_Passes[id]; + + return pass.m_Handle; + } + + const PassConfig& PassManager::getPassConfig(const PassHandle &handle) const { + const uint64_t id = handle.getId(); + + if (id >= m_Passes.size()) { + static PassConfig emptyConfig = PassConfig({}); + return emptyConfig; + } + + auto& pass = m_Passes[id]; + + return pass.m_Config; } + } diff --git a/src/vkcv/PassManager.hpp b/src/vkcv/PassManager.hpp index b6be2cb13d8d24bdb9759f8878917f99e31afbec..bfc20fe25ace95bd8d94832b953b6b14ab9cadee 100644 --- a/src/vkcv/PassManager.hpp +++ b/src/vkcv/PassManager.hpp @@ -10,8 +10,13 @@ namespace vkcv class PassManager { private: + struct Pass { + vk::RenderPass m_Handle; + PassConfig m_Config; + }; + vk::Device m_Device; - std::vector<vk::RenderPass> m_RenderPasses; + std::vector<Pass> m_Passes; uint64_t m_NextPassId; public: PassManager() = delete; // no default ctor @@ -28,5 +33,9 @@ namespace vkcv [[nodiscard]] vk::RenderPass getVkPass(const PassHandle &handle) const; + + [[nodiscard]] + const PassConfig& getPassConfig(const PassHandle &handle) const; + }; } diff --git a/src/vkcv/PipelineManager.cpp b/src/vkcv/PipelineManager.cpp index 8b6202eb901f26c84585597e327c297902e54b03..f9c56b41fb60841f19edf294bd9adb739dd19691 100644 --- a/src/vkcv/PipelineManager.cpp +++ b/src/vkcv/PipelineManager.cpp @@ -23,8 +23,10 @@ namespace vkcv m_NextPipelineId = 0; } - PipelineHandle PipelineManager::createPipeline(const PipelineConfig &config, const vk::RenderPass &pass) + PipelineHandle PipelineManager::createPipeline(const PipelineConfig &config, PassManager& passManager) { + const vk::RenderPass &pass = passManager.getVkPass(config.m_PassHandle); + const bool existsVertexShader = config.m_ShaderProgram.existsShader(ShaderStage::VERTEX); const bool existsFragmentShader = config.m_ShaderProgram.existsShader(ShaderStage::FRAGMENT); if (!(existsVertexShader && existsFragmentShader)) @@ -170,10 +172,34 @@ namespace vkcv m_Device.destroy(fragmentModule); return PipelineHandle(); } - - // graphics pipeline create + + const vk::PipelineDepthStencilStateCreateInfo depthStencilCreateInfo( + vk::PipelineDepthStencilStateCreateFlags(), + true, + true, + vk::CompareOp::eLessOrEqual, + false, + false, + {}, + {}, + 0.0f, + 1.0f + ); + + const vk::PipelineDepthStencilStateCreateInfo* p_depthStencilCreateInfo = nullptr; + + const PassConfig& passConfig = passManager.getPassConfig(config.m_PassHandle); + + for (const auto& attachment : passConfig.attachments) { + if (attachment.layout_final == AttachmentLayout::DEPTH_STENCIL_ATTACHMENT) { + p_depthStencilCreateInfo = &depthStencilCreateInfo; + break; + } + } + + // graphics pipeline create std::vector<vk::PipelineShaderStageCreateInfo> shaderStages = { pipelineVertexShaderStageInfo, pipelineFragmentShaderStageInfo }; - vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo( + const vk::GraphicsPipelineCreateInfo graphicsPipelineCreateInfo( {}, static_cast<uint32_t>(shaderStages.size()), shaderStages.data(), @@ -183,7 +209,7 @@ namespace vkcv &pipelineViewportStateCreateInfo, &pipelineRasterizationStateCreateInfo, &pipelineMultisampleStateCreateInfo, - nullptr, + p_depthStencilCreateInfo, &pipelineColorBlendStateCreateInfo, nullptr, vkPipelineLayout, diff --git a/src/vkcv/PipelineManager.hpp b/src/vkcv/PipelineManager.hpp index b5c0948efa13a4021f424cc576f1403a1ec26ebe..896d0df1ce10f56d291ef1accf93f9783cdd9db4 100644 --- a/src/vkcv/PipelineManager.hpp +++ b/src/vkcv/PipelineManager.hpp @@ -4,6 +4,7 @@ #include <vector> #include "vkcv/Handles.hpp" #include "vkcv/PipelineConfig.hpp" +#include "PassManager.hpp" namespace vkcv { @@ -25,7 +26,7 @@ namespace vkcv PipelineManager & operator=(const PipelineManager &other) = delete; // copy-assign op PipelineManager & operator=(PipelineManager &&other) = delete; // move-assign op - PipelineHandle createPipeline(const PipelineConfig &config, const vk::RenderPass &pass); + PipelineHandle createPipeline(const PipelineConfig &config, PassManager& passManager); [[nodiscard]] vk::Pipeline getVkPipeline(const PipelineHandle &handle) const;