diff --git a/config/Sources.cmake b/config/Sources.cmake index 80fa3a09d163edf3277eb69f91e7b10e57b72c5d..d98c51c1bfd3372e2b1767e01626fcfe84dd2081 100644 --- a/config/Sources.cmake +++ b/config/Sources.cmake @@ -7,6 +7,9 @@ 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/Handles.hpp ${vkcv_source}/vkcv/Handles.cpp diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp index 7a7f3be7d61995462da1f65bd58af098b1dd1f4e..475099ab68b18556065698579dc13b5d5d7682d4 100644 --- a/include/vkcv/Core.hpp +++ b/include/vkcv/Core.hpp @@ -6,6 +6,7 @@ #include <vulkan/vulkan.hpp> #include "vkcv/Context.hpp" +#include "vkcv/Renderpass.hpp" #include "vkcv/Handles.hpp" namespace vkcv @@ -29,11 +30,15 @@ namespace vkcv Core() = delete; Context m_Context; + + uint64_t m_NextPassId; + std::vector<vk::RenderPass> m_Renderpasses; + public: /** * Destructor of #Core destroys the Vulkan objects contained in the core's context. */ - ~Core() noexcept = default; + ~Core() noexcept; /** * Copy-constructor of #Core is deleted! @@ -93,7 +98,11 @@ namespace vkcv // TODO: BufferHandle createBuffer(const Buffer &buf); - PassHandle createRenderPass(const Renderpass &pass) ; + + [[nodiscard]] + bool createRenderpass(const Renderpass &pass, RenderpassHandle &handle); + + // TODO: PipelineHandle createPipeline(const Pipeline &pipeline); }; diff --git a/include/vkcv/Handles.hpp b/include/vkcv/Handles.hpp index 4ec2bc058409e9119695700b2b727be9426c2bcd..0d8e4a89124c82d986a51e3175e311dd7b10c21e 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 PassHandle {uint64_t id;}; + struct RenderpassHandle {uint64_t id;}; struct PipelineHandle {uint64_t id;}; } diff --git a/include/vkcv/Renderpass.hpp b/include/vkcv/Renderpass.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7f2ad91caca9468b32f19b5e4cebebcaa7807364 --- /dev/null +++ b/include/vkcv/Renderpass.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include <vector> + +namespace vkcv +{ + enum class AttachmentLayout + { + UNDEFINED, + GENERAL, + + COLOR_ATTACHMENT, + SHADER_READ_ONLY, + + DEPTH_STENCIL_ATTACHMENT, + DEPTH_STENCIL_READ_ONLY, + + TRANSFER_SRC, + TRANSFER_DST, + + PRESENTATION + }; + + enum class AttachmentOperation + { + LOAD, + CLEAR, + STORE, + DONT_CARE + }; + + struct AttachmentDescription + { + AttachmentDescription() = delete; + AttachmentDescription(AttachmentLayout initial, + AttachmentLayout in_pass, + AttachmentLayout final, + AttachmentOperation store_op, + AttachmentOperation load_op) noexcept; + + AttachmentLayout layout_initial; + AttachmentLayout layout_in_pass; + AttachmentLayout layout_final; + + AttachmentOperation store_operation; + AttachmentOperation load_operation; + }; + + struct Renderpass + { + Renderpass() noexcept = default; + std::vector<AttachmentDescription> attachments{}; + }; +} \ No newline at end of file diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp index 0c981a25dc52db4363d2bc7835df3c3c9d7c49fa..87a7d11e5e05e0c367d46fe36db1a161ee8398bd 100644 --- a/projects/first_triangle/src/main.cpp +++ b/projects/first_triangle/src/main.cpp @@ -33,6 +33,38 @@ int main(int argc, const char** argv) { default: std::cout << "Unknown GPU vendor?! Either you're on an exotic system or your driver is broken..." << std::endl; } + // an example attachment for passes that output to the window + vkcv::AttachmentDescription present_color_attachment(vkcv::AttachmentLayout::UNDEFINED, + vkcv::AttachmentLayout::COLOR_ATTACHMENT, + vkcv::AttachmentLayout::PRESENTATION, + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR); + // an example attachment for passes that output to a depth buffer + vkcv::AttachmentDescription present_depth_attachment(vkcv::AttachmentLayout::UNDEFINED, + vkcv::AttachmentLayout::DEPTH_STENCIL_ATTACHMENT, + vkcv::AttachmentLayout::DEPTH_STENCIL_READ_ONLY, + vkcv::AttachmentOperation::STORE, + vkcv::AttachmentOperation::CLEAR); + + // this pass will output to the window, and produce a depth buffer + vkcv::Renderpass test_pass{}; + test_pass.attachments.push_back(present_color_attachment); + test_pass.attachments.push_back(present_depth_attachment); + + std::vector<vkcv::RenderpassHandle> test_handles{}; + // render pass creation test + for(uint32_t i = 0; i < 1000; i++) + { + vkcv::RenderpassHandle tmp_handle{}; + if(!core.createRenderpass(test_pass, tmp_handle)) + { + std::cout << "Oops. Something went wrong in the renderpass creation. Exiting." << std::endl; + return EXIT_FAILURE; + } + test_handles.push_back(tmp_handle); + } + std::cout << "Wow. You just made 1000 render passes. (That are all identical, though...)" << std::endl; + /* * BufferHandle triangleVertices = core.createBuffer(vertices); * BufferHandle triangleIndices = core.createBuffer(indices); diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp index 0c32f4e42d1a232a9b66d42e6a16f0c1eda06bbb..4ba377d953366c0b49f2f97d7b7fd4268e97abb2 100644 --- a/src/vkcv/Core.cpp +++ b/src/vkcv/Core.cpp @@ -8,6 +8,51 @@ 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: * discrete GPU vs. integrated GPU, amount of queues and its abilities, and VRAM.physicalDevice. @@ -268,6 +313,85 @@ namespace vkcv } Core::Core(Context &&context) noexcept : - m_Context(std::move(context)) + m_Context(std::move(context)), + m_NextPassId(0), + m_Renderpasses{} {} + + Core::~Core() noexcept + { + for(const auto &pass : m_Renderpasses) + m_Context.m_Device.destroy(pass); + m_Renderpasses.clear(); + m_NextPassId = 0; + } + + bool Core::createRenderpass(const Renderpass &pass, RenderpassHandle &handle) + { + // 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{}; + + 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); + } + 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(), + {}, + &depthAttachmentReference, + 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; + } } diff --git a/src/vkcv/Renderpass.cpp b/src/vkcv/Renderpass.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e9f2459b241d43c69b131ff93eb61bd94fd6e6c7 --- /dev/null +++ b/src/vkcv/Renderpass.cpp @@ -0,0 +1,16 @@ +#include "vkcv/Renderpass.hpp" + +namespace vkcv +{ + AttachmentDescription::AttachmentDescription(AttachmentLayout initial, + AttachmentLayout in_pass, + AttachmentLayout final, + AttachmentOperation store_op, + AttachmentOperation load_op) noexcept : + layout_initial{initial}, + layout_in_pass{in_pass}, + layout_final{final}, + store_operation{store_op}, + load_operation{load_op} + {}; +} \ No newline at end of file