From f9ec49e20e84dc1a73b64460bbf2d8fab4de71a0 Mon Sep 17 00:00:00 2001 From: Artur Wasmut <awasmut@uni-koblenz.de> Date: Sun, 16 May 2021 14:13:55 +0200 Subject: [PATCH] add pass manager. --- config/Sources.cmake | 7 +- include/vkcv/Core.hpp | 16 +- include/vkcv/Handles.hpp | 2 +- .../vkcv/{Renderpass.hpp => PassConfig.hpp} | 5 +- include/vkcv/Pipeline.hpp | 4 +- projects/first_triangle/src/main.cpp | 9 +- src/vkcv/Core.cpp | 140 ++---------------- src/vkcv/{Renderpass.cpp => PassConfig.cpp} | 8 +- src/vkcv/PassManager.cpp | 139 +++++++++++++++++ src/vkcv/PassManager.hpp | 32 ++++ src/vkcv/Pipeline.cpp | 2 +- 11 files changed, 214 insertions(+), 150 deletions(-) rename include/vkcv/{Renderpass.hpp => PassConfig.hpp} (88%) rename src/vkcv/{Renderpass.cpp => PassConfig.cpp} (75%) create mode 100644 src/vkcv/PassManager.cpp create mode 100644 src/vkcv/PassManager.hpp diff --git a/config/Sources.cmake b/config/Sources.cmake index 1814f581..0a612e7f 100644 --- a/config/Sources.cmake +++ b/config/Sources.cmake @@ -7,8 +7,11 @@ set(vkcv_sources ${vkcv_include}/vkcv/Core.hpp ${vkcv_source}/vkcv/Core.cpp - ${vkcv_include}/vkcv/Renderpass.hpp - ${vkcv_source}/vkcv/Renderpass.cpp + ${vkcv_include}/vkcv/PassConfig.hpp + ${vkcv_source}/vkcv/PassConfig.cpp + + ${vkcv_source}/vkcv/PassManager.hpp + ${vkcv_source}/vkcv/PassManager.cpp ${vkcv_include}/vkcv/Handles.hpp ${vkcv_source}/vkcv/Handles.cpp diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index f27ca4cc..048b1ad5 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -4,11 +4,13 @@ * @brief Handling of global states regarding dependencies */ +#include <memory> + #include <vulkan/vulkan.hpp> #include "vkcv/Context.hpp" #include "vkcv/SwapChain.hpp" #include "vkcv/Window.hpp" -#include "vkcv/Renderpass.hpp" +#include "vkcv/PassConfig.hpp" #include "vkcv/Handles.hpp" #include "vkcv/Pipeline.hpp" @@ -16,7 +18,9 @@ namespace vkcv { // TODO: class Buffer; - class Renderpass; + + // forward declarations + class PassManager; class Core final { @@ -41,11 +45,7 @@ namespace vkcv std::vector<vk::Pipeline> m_Pipelines; std::vector<vk::PipelineLayout> m_PipelineLayouts; - uint64_t m_NextRenderpassId; - - uint64_t m_NextPassId; - std::vector<vk::RenderPass> m_Renderpasses; - + std::unique_ptr<PassManager> m_PassManager; public: /** * Destructor of #Core destroys the Vulkan objects contained in the core's context. @@ -121,6 +121,6 @@ namespace vkcv BufferHandle createBuffer(const Buffer &buf); [[nodiscard]] - bool createRenderpass(const Renderpass &pass, RenderpassHandle &handle); + PassHandle createPass(const PassConfig &config); }; } diff --git a/include/vkcv/Handles.hpp b/include/vkcv/Handles.hpp index 52bc5dce..4ec2bc05 100644 --- a/include/vkcv/Handles.hpp +++ b/include/vkcv/Handles.hpp @@ -11,6 +11,6 @@ namespace vkcv { // Handle returned for any buffer created with the core/context objects struct BufferHandle {uint64_t id;}; - struct RenderpassHandle {uint64_t id;}; + struct PassHandle {uint64_t id;}; struct PipelineHandle {uint64_t id;}; } diff --git a/include/vkcv/Renderpass.hpp b/include/vkcv/PassConfig.hpp similarity index 88% rename from include/vkcv/Renderpass.hpp rename to include/vkcv/PassConfig.hpp index 7f2ad91c..b0ded8f5 100644 --- a/include/vkcv/Renderpass.hpp +++ b/include/vkcv/PassConfig.hpp @@ -46,9 +46,10 @@ namespace vkcv AttachmentOperation load_operation; }; - struct Renderpass + struct PassConfig { - Renderpass() noexcept = default; + PassConfig() = delete; + explicit PassConfig(std::vector<AttachmentDescription> attachments) noexcept; std::vector<AttachmentDescription> attachments{}; }; } \ No newline at end of file diff --git a/include/vkcv/Pipeline.hpp b/include/vkcv/Pipeline.hpp index 83dd6e4f..06380d0a 100644 --- a/include/vkcv/Pipeline.hpp +++ b/include/vkcv/Pipeline.hpp @@ -31,12 +31,12 @@ namespace vkcv { * @param width width of the application window * @param passHandle handle for Render Pass */ - Pipeline(const ShaderProgram& shaderProgram, uint32_t width, uint32_t height, RenderpassHandle &passHandle); + Pipeline(const ShaderProgram& shaderProgram, uint32_t width, uint32_t height, PassHandle &passHandle); ShaderProgram m_shaderProgram; uint32_t m_height; uint32_t m_width; - RenderpassHandle m_passHandle; + PassHandle m_passHandle; }; } diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp index b1a68c7f..e39e19c3 100644 --- a/projects/first_triangle/src/main.cpp +++ b/projects/first_triangle/src/main.cpp @@ -48,11 +48,10 @@ int main(int argc, const char** argv) { vkcv::AttachmentOperation::STORE, vkcv::AttachmentOperation::CLEAR); - vkcv::Renderpass trianglePassDefinition; - trianglePassDefinition.attachments.push_back(present_color_attachment); - vkcv::RenderpassHandle trianglePass; + vkcv::PassConfig trianglePassDefinition({present_color_attachment}); + vkcv::PassHandle trianglePass = core.createPass(trianglePassDefinition); - if (!core.createRenderpass(trianglePassDefinition, trianglePass)) + if (trianglePass.id == 0) { std::cout << "Error. Could not create renderpass. Exiting." << std::endl; return EXIT_FAILURE; @@ -63,7 +62,7 @@ int main(int argc, const char** argv) { triangleShaderProgram.addShader(vkcv::ShaderProgram::ShaderStage::FRAGMENT, "shaders/frag.spv"); const vkcv::Pipeline trianglePipelineDefinition(triangleShaderProgram, windowWidth, windowHeight, trianglePass); - vkcv::PipelineHandle trianglePipeline; + vkcv::PipelineHandle trianglePipeline{}; if (!core.createGraphicsPipeline(trianglePipelineDefinition, trianglePipeline)) { std::cout << "Error. Could not create graphics pipeline. Exiting." << std::endl; return EXIT_FAILURE; diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index 166ac3e5..6015363c 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -5,53 +5,10 @@ */ #include "vkcv/Core.hpp" +#include "PassManager.hpp" namespace vkcv { - static vk::ImageLayout getVkLayoutFromAttachLayout(AttachmentLayout layout) - { - switch(layout) - { - case AttachmentLayout::GENERAL: - return vk::ImageLayout::eGeneral; - case AttachmentLayout::COLOR_ATTACHMENT: - return vk::ImageLayout::eColorAttachmentOptimal; - case AttachmentLayout::SHADER_READ_ONLY: - return vk::ImageLayout::eShaderReadOnlyOptimal; - case AttachmentLayout::DEPTH_STENCIL_ATTACHMENT: - return vk::ImageLayout::eDepthStencilAttachmentOptimal; - case AttachmentLayout::DEPTH_STENCIL_READ_ONLY: - return vk::ImageLayout::eDepthStencilReadOnlyOptimal; - case AttachmentLayout::PRESENTATION: - return vk::ImageLayout::ePresentSrcKHR; - default: - return vk::ImageLayout::eUndefined; - } - } - - static vk::AttachmentStoreOp getVkStoreOpFromAttachOp(AttachmentOperation op) - { - switch(op) - { - case AttachmentOperation::STORE: - return vk::AttachmentStoreOp::eStore; - default: - return vk::AttachmentStoreOp::eDontCare; - } - } - - static vk::AttachmentLoadOp getVKLoadOpFromAttachOp(AttachmentOperation op) - { - switch(op) - { - case AttachmentOperation::LOAD: - return vk::AttachmentLoadOp::eLoad; - case AttachmentOperation::CLEAR: - return vk::AttachmentLoadOp::eClear; - default: - return vk::AttachmentLoadOp::eDontCare; - } - } /** * @brief The physical device is evaluated by three categories: @@ -508,12 +465,10 @@ namespace vkcv m_NextPipelineId(0), m_Pipelines{}, m_PipelineLayouts{}, - m_NextRenderpassId(0), - m_NextPassId(0), - m_Renderpasses{} + m_PassManager{std::make_unique<PassManager>(m_Context.m_Device)} {} - Core::~Core() { + Core::~Core() noexcept { std::cout << " Core " << std::endl; for(const auto &layout : m_PipelineLayouts) @@ -531,19 +486,14 @@ namespace vkcv m_NextPipelineId = 0; for (auto image : m_swapchainImageViews) { - m_Context.getDevice().destroyImageView(image); + m_Context.m_Device.destroyImageView(image); } - for (const auto& pass : m_Renderpasses) - m_Context.m_Device.destroy(pass); - m_Renderpasses.clear(); - m_NextPassId = 0; - - m_Context.getDevice().destroySwapchainKHR(m_swapchain.getSwapchain()); - m_Context.getInstance().destroySurfaceKHR(m_swapchain.getSurface()); + m_Context.m_Device.destroySwapchainKHR(m_swapchain.getSwapchain()); + m_Context.m_Instance.destroySurfaceKHR(m_swapchain.getSurface()); } - bool Core::createGraphicsPipeline(const Pipeline& pipeline, PipelineHandle& handle) { + bool Core::createGraphicsPipeline(const Pipeline &pipeline, PipelineHandle &handle) { // TODO: this search could be avoided if ShaderProgram could be queried for a specific stage const auto shaderStageFlags = pipeline.m_shaderProgram.getShaderStages(); @@ -559,8 +509,8 @@ namespace vkcv } } - const bool foundVertexCode = vertexCode.empty(); - const bool foundFragCode = fragCode.empty(); + const bool foundVertexCode = !vertexCode.empty(); + const bool foundFragCode = !fragCode.empty(); const bool foundRequiredShaderCode = foundVertexCode && foundFragCode; if (!foundRequiredShaderCode) { std::cout << "Core::createGraphicsPipeline requires vertex and fragment shader code" << std::endl; @@ -705,7 +655,7 @@ namespace vkcv &pipelineColorBlendStateCreateInfo, nullptr, vkPipelineLayout, - m_Renderpasses[pipeline.m_passHandle.id], + m_PassManager->getVkPass(pipeline.m_passHandle), 0, {}, 0 @@ -729,74 +679,8 @@ namespace vkcv return true; } - bool Core::createRenderpass(const Renderpass &pass, RenderpassHandle &handle) + PassHandle Core::createPass(const PassConfig &config) { - // description of all {color, input, depth/stencil} attachments of the render pass - std::vector<vk::AttachmentDescription> attachmentDescriptions{}; - - // individual references to color attachments (of a subpass) - std::vector<vk::AttachmentReference> colorAttachmentReferences{}; - // individual reference to depth attachment (of a subpass) - vk::AttachmentReference depthAttachmentReference{}; - vk::AttachmentReference *pDepthAttachment = nullptr; //stays nullptr if no depth attachment used - - for (uint32_t i = 0; i < pass.attachments.size(); i++) - { - // TODO: Renderpass struct should hold proper format information - vk::Format format; - - if (pass.attachments[i].layout_in_pass == AttachmentLayout::DEPTH_STENCIL_ATTACHMENT) - { - format = vk::Format::eD16Unorm; // depth attachments; - - depthAttachmentReference.attachment = i; - depthAttachmentReference.layout = getVkLayoutFromAttachLayout(pass.attachments[i].layout_in_pass); - pDepthAttachment = &depthAttachmentReference; - } - else - { - format = vk::Format::eB8G8R8A8Srgb; // color attachments, compatible with swapchain - vk::AttachmentReference attachmentRef(i, getVkLayoutFromAttachLayout(pass.attachments[i].layout_in_pass)); - colorAttachmentReferences.push_back(attachmentRef); - } - - vk::AttachmentDescription attachmentDesc({}, - format, - vk::SampleCountFlagBits::e1, - getVKLoadOpFromAttachOp(pass.attachments[i].load_operation), - getVkStoreOpFromAttachOp(pass.attachments[i].load_operation), - vk::AttachmentLoadOp::eDontCare, - vk::AttachmentStoreOp::eDontCare, - getVkLayoutFromAttachLayout(pass.attachments[i].layout_initial), - getVkLayoutFromAttachLayout(pass.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, - {}); - - vk::RenderPass vkObject{nullptr}; - if(m_Context.m_Device.createRenderPass(&passInfo, nullptr, &vkObject) != vk::Result::eSuccess) - return false; - - m_Renderpasses.push_back(vkObject); - handle.id = m_NextPassId++; - - return true; + return m_PassManager->createPass(config); } } diff --git a/src/vkcv/Renderpass.cpp b/src/vkcv/PassConfig.cpp similarity index 75% rename from src/vkcv/Renderpass.cpp rename to src/vkcv/PassConfig.cpp index e9f2459b..a0c22896 100644 --- a/src/vkcv/Renderpass.cpp +++ b/src/vkcv/PassConfig.cpp @@ -1,4 +1,6 @@ -#include "vkcv/Renderpass.hpp" +#include "vkcv/PassConfig.hpp" + +#include <utility> namespace vkcv { @@ -13,4 +15,8 @@ namespace vkcv store_operation{store_op}, load_operation{load_op} {}; + + PassConfig::PassConfig(std::vector<AttachmentDescription> attachments) noexcept : + attachments{std::move(attachments)} + {} } \ No newline at end of file diff --git a/src/vkcv/PassManager.cpp b/src/vkcv/PassManager.cpp new file mode 100644 index 00000000..43674620 --- /dev/null +++ b/src/vkcv/PassManager.cpp @@ -0,0 +1,139 @@ +#include "PassManager.hpp" + +namespace vkcv +{ + static vk::ImageLayout getVkLayoutFromAttachLayout(AttachmentLayout layout) + { + switch(layout) + { + case AttachmentLayout::GENERAL: + return vk::ImageLayout::eGeneral; + case AttachmentLayout::COLOR_ATTACHMENT: + return vk::ImageLayout::eColorAttachmentOptimal; + case AttachmentLayout::SHADER_READ_ONLY: + return vk::ImageLayout::eShaderReadOnlyOptimal; + case AttachmentLayout::DEPTH_STENCIL_ATTACHMENT: + return vk::ImageLayout::eDepthStencilAttachmentOptimal; + case AttachmentLayout::DEPTH_STENCIL_READ_ONLY: + return vk::ImageLayout::eDepthStencilReadOnlyOptimal; + case AttachmentLayout::PRESENTATION: + return vk::ImageLayout::ePresentSrcKHR; + default: + return vk::ImageLayout::eUndefined; + } + } + + static vk::AttachmentStoreOp getVkStoreOpFromAttachOp(AttachmentOperation op) + { + switch(op) + { + case AttachmentOperation::STORE: + return vk::AttachmentStoreOp::eStore; + default: + return vk::AttachmentStoreOp::eDontCare; + } + } + + static vk::AttachmentLoadOp getVKLoadOpFromAttachOp(AttachmentOperation op) + { + switch(op) + { + case AttachmentOperation::LOAD: + return vk::AttachmentLoadOp::eLoad; + case AttachmentOperation::CLEAR: + return vk::AttachmentLoadOp::eClear; + default: + return vk::AttachmentLoadOp::eDontCare; + } + } + + PassManager::PassManager(vk::Device device) noexcept : + m_Device{device}, + m_RenderPasses{}, + m_NextPassId{1} + {} + + PassManager::~PassManager() noexcept + { + for(const auto &pass : m_RenderPasses) + { + m_Device.destroy(pass); + } + m_RenderPasses.clear(); + m_NextPassId = 1; + } + + PassHandle PassManager::createPass(const PassConfig &config) + { + // description of all {color, input, depth/stencil} attachments of the render pass + std::vector<vk::AttachmentDescription> attachmentDescriptions{}; + + // individual references to color attachments (of a subpass) + std::vector<vk::AttachmentReference> colorAttachmentReferences{}; + // individual reference to depth attachment (of a subpass) + vk::AttachmentReference depthAttachmentReference{}; + vk::AttachmentReference *pDepthAttachment = nullptr; //stays nullptr if no depth attachment used + + for (uint32_t i = 0; i < config.attachments.size(); i++) + { + // TODO: Renderpass struct should hold proper format information + vk::Format format; + + if (config.attachments[i].layout_in_pass == AttachmentLayout::DEPTH_STENCIL_ATTACHMENT) + { + format = vk::Format::eD16Unorm; // depth attachments; + + depthAttachmentReference.attachment = i; + depthAttachmentReference.layout = getVkLayoutFromAttachLayout(config.attachments[i].layout_in_pass); + pDepthAttachment = &depthAttachmentReference; + } + else + { + format = vk::Format::eB8G8R8A8Srgb; // color attachments, compatible with swapchain + vk::AttachmentReference attachmentRef(i, getVkLayoutFromAttachLayout(config.attachments[i].layout_in_pass)); + colorAttachmentReferences.push_back(attachmentRef); + } + + vk::AttachmentDescription attachmentDesc({}, + format, + vk::SampleCountFlagBits::e1, + getVKLoadOpFromAttachOp(config.attachments[i].load_operation), + getVkStoreOpFromAttachOp(config.attachments[i].load_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, + {}); + + vk::RenderPass vkObject{nullptr}; + if(m_Device.createRenderPass(&passInfo, nullptr, &vkObject) != vk::Result::eSuccess) + return PassHandle{0}; + + m_RenderPasses.push_back(vkObject); + return PassHandle{m_NextPassId++}; + } + + vk::RenderPass PassManager::getVkPass(const PassHandle &handle) const + { + return m_RenderPasses[handle.id - 1]; + } +} diff --git a/src/vkcv/PassManager.hpp b/src/vkcv/PassManager.hpp new file mode 100644 index 00000000..b6be2cb1 --- /dev/null +++ b/src/vkcv/PassManager.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include <vulkan/vulkan.hpp> +#include <vector> +#include "vkcv/Handles.hpp" +#include "vkcv/PassConfig.hpp" + +namespace vkcv +{ + class PassManager + { + private: + vk::Device m_Device; + std::vector<vk::RenderPass> m_RenderPasses; + uint64_t m_NextPassId; + public: + PassManager() = delete; // no default ctor + explicit PassManager(vk::Device device) noexcept; // ctor + ~PassManager() noexcept; // dtor + + PassManager(const PassManager &other) = delete; // copy-ctor + PassManager(PassManager &&other) = delete; // move-ctor; + + PassManager & operator=(const PassManager &other) = delete; // copy-assign op + PassManager & operator=(PassManager &&other) = delete; // move-assign op + + PassHandle createPass(const PassConfig &config); + + [[nodiscard]] + vk::RenderPass getVkPass(const PassHandle &handle) const; + }; +} diff --git a/src/vkcv/Pipeline.cpp b/src/vkcv/Pipeline.cpp index 42a6b963..df3e6041 100644 --- a/src/vkcv/Pipeline.cpp +++ b/src/vkcv/Pipeline.cpp @@ -8,6 +8,6 @@ namespace vkcv { - Pipeline::Pipeline(const ShaderProgram& shaderProgram, uint32_t width, uint32_t height, RenderpassHandle &passHandle): + Pipeline::Pipeline(const ShaderProgram& shaderProgram, uint32_t width, uint32_t height, PassHandle &passHandle): m_shaderProgram(shaderProgram), m_height(height), m_width(width), m_passHandle(passHandle) {} } -- GitLab