diff --git a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.h b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.h index 91112496..e1bee300 100644 --- a/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.h +++ b/SHADE_Engine/src/Graphics/Descriptors/SHVkDescriptorPool.h @@ -39,8 +39,9 @@ namespace SHADE std::vector Limits = { { vk::DescriptorType::eCombinedImageSampler, 100 }, - { vk::DescriptorType::eUniformBuffer, 100 }, - { vk::DescriptorType::eUniformBufferDynamic, 100 } + { vk::DescriptorType::eUniformBuffer, 100 }, + { vk::DescriptorType::eUniformBufferDynamic, 100 }, + { vk::DescriptorType::eStorageImage, 100} }; /// /// Maximum number of descriptor sets allowed diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp index 25be112e..7a76447d 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.cpp @@ -216,10 +216,13 @@ namespace SHADE /***************************************************************************/ void SHVkPipelineLayout::PrepareVkDescriptorSetLayouts(void) noexcept { + descriptorSetLayoutsPipeline.reserve(descriptorSetLayoutsAllocate.size() + descriptorSetLayoutsGlobal.size()); + // Settle allocate layouts first vkDescriptorSetLayoutsAllocate.reserve(descriptorSetLayoutsAllocate.size()); for (auto const& layout : descriptorSetLayoutsAllocate) { + descriptorSetLayoutsPipeline.emplace_back(layout); vkDescriptorSetLayoutsAllocate.emplace_back(layout->GetVkHandle()); } @@ -228,7 +231,10 @@ namespace SHADE // First we insert the global layouts for (auto const& layout : descriptorSetLayoutsGlobal) + { + descriptorSetLayoutsPipeline.emplace_back(layout); vkDescriptorSetLayoutsPipeline.emplace_back(layout->GetVkHandle()); + } // Then we append layouts for allocation at the back of the vector std::copy(vkDescriptorSetLayoutsAllocate.begin(), vkDescriptorSetLayoutsAllocate.end(), std::back_inserter(vkDescriptorSetLayoutsPipeline)); @@ -435,6 +441,16 @@ namespace SHADE return {}; } + std::vector> SHVkPipelineLayout::GetDescriptorSetLayoutsPipeline(void) const noexcept + { + return descriptorSetLayoutsPipeline; + } + + std::vector> SHVkPipelineLayout::GetDescriptorSetLayoutsAllocate(void) const noexcept + { + return descriptorSetLayoutsAllocate; + } + SHVkPipelineLayout& SHVkPipelineLayout::operator=(SHVkPipelineLayout&& rhs) noexcept { if (&rhs == this) diff --git a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h index e43ceb73..f5d363fa 100644 --- a/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h +++ b/SHADE_Engine/src/Graphics/Pipeline/SHVkPipelineLayout.h @@ -42,6 +42,9 @@ namespace SHADE //! We want to store this also because we need to allocate later std::vector vkDescriptorSetLayoutsAllocate; + //! Store for descriptor set group creation + std::vector> descriptorSetLayoutsPipeline; + //! Store for pipeline layout recreation std::vector vkDescriptorSetLayoutsPipeline; @@ -71,10 +74,12 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */ /*-----------------------------------------------------------------------*/ - std::vector> const& GetShaderModules (void) const noexcept; - vk::PipelineLayout GetVkPipelineLayout (void) const noexcept; - SHPushConstantInterface const& GetPushConstantInterface (void) const noexcept; - Handle GetShaderBlockInterface (uint32_t set, uint32_t binding, vk::ShaderStageFlagBits shaderStage) const noexcept; + std::vector> const& GetShaderModules (void) const noexcept; + vk::PipelineLayout GetVkPipelineLayout (void) const noexcept; + SHPushConstantInterface const& GetPushConstantInterface (void) const noexcept; + Handle GetShaderBlockInterface (uint32_t set, uint32_t binding, vk::ShaderStageFlagBits shaderStage) const noexcept; + std::vector> GetDescriptorSetLayoutsPipeline(void) const noexcept; + std::vector> GetDescriptorSetLayoutsAllocate(void) const noexcept; }; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp index 3f5641c0..588e950e 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp @@ -11,655 +11,7 @@ namespace SHADE { - /***************************************************************************/ - /*! - - \brief - Non-default ctor for the resource. Using the type of the resource, we - decide whether or not we create a resource or link with a swapchain - resource (image). - - \param logicalDevice - Logical device required to create an image resource if the type is NOT - SH_ATT_DESC_TYPE::COLOR_PRESENT. - - \param swapchain - Swapchain required to get swapchain image if the type IS - SH_ATT_DESC_TYPE::COLOR_PRESENT. - - \param type - Type of the image resource. - - \param format - Format of the image resource. - - \param w - Width of the image resource. - - \param h - Height of the image resource. - - \param levels - Number of mipmap levels of the image resource. - - \param createFlags - Create flags used when an image resource needs to be created. - - */ - /***************************************************************************/ - SHRenderGraphResource::SHRenderGraphResource(Handle const& logicalDevice, Handle const& swapchain, std::string const& name, SH_ATT_DESC_TYPE type, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageCreateFlagBits createFlags) noexcept - : resourceType{ type } - , resourceFormat{ format } - , images{} - , imageViews{} - , width{ w } - , height{ h } - , mipLevels{ levels } - , resourceName{ name } - { - // If the resource type is an arbitrary image and not swapchain image - if (type != SH_ATT_DESC_TYPE::COLOR_PRESENT) - { - vk::ImageAspectFlags imageAspectFlags; - vk::ImageUsageFlags usage = {}; - - // Check the resource type and set image usage flags and image aspect flags accordingly - switch (resourceType) - { - case SH_ATT_DESC_TYPE::COLOR: - usage |= vk::ImageUsageFlagBits::eColorAttachment; - imageAspectFlags |= vk::ImageAspectFlagBits::eColor; - break; - case SH_ATT_DESC_TYPE::DEPTH: - usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; - imageAspectFlags |= vk::ImageAspectFlagBits::eDepth; - break; - case SH_ATT_DESC_TYPE::STENCIL: - usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; - imageAspectFlags |= vk::ImageAspectFlagBits::eStencil; - break; - case SH_ATT_DESC_TYPE::DEPTH_STENCIL: - usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; - imageAspectFlags |= vk::ImageAspectFlagBits::eStencil | vk::ImageAspectFlagBits::eDepth; - break; - } - - // The resource is not a swapchain image, just use the first slot of the vector - images.push_back(logicalDevice->CreateImage(width, height, mipLevels, resourceFormat, usage, createFlags)); - - // prepare image view details - SHImageViewDetails viewDetails - { - .viewType = vk::ImageViewType::e2D, - .format = images[0]->GetImageFormat(), - .imageAspectFlags = imageAspectFlags, - .baseMipLevel = 0, - .mipLevelCount = mipLevels, - .baseArrayLayer = 0, - .layerCount = 1, - }; - - // just 1 image view created - imageViews.push_back(images[0]->CreateImageView(logicalDevice, images[0], viewDetails)); - } - else // if swapchain image resource - { - // Prepare image view details - SHImageViewDetails viewDetails - { - .viewType = vk::ImageViewType::e2D, - .format = swapchain->GetSurfaceFormatKHR().format, - .imageAspectFlags = vk::ImageAspectFlagBits::eColor, - .baseMipLevel = 0, - .mipLevelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1, - }; - - // We want an image handle for every swapchain image - images.resize(swapchain->GetNumImages()); - imageViews.resize(swapchain->GetNumImages()); - - for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i) - { - images[i] = swapchain->GetSwapchainImage(i); - imageViews[i] = images[i]->CreateImageView(logicalDevice, images[i], viewDetails); - } - } - } - - /***************************************************************************/ - /*! - - \brief - Move ctor for resource. - - \param rhs - The other resource. - - */ - /***************************************************************************/ - SHRenderGraphResource::SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept - : resourceName{ std::move(rhs.resourceName) } - , resourceType{ std::move(rhs.resourceType) } - , images{ std::move(rhs.images) } - , imageViews{ std::move(rhs.imageViews) } - , resourceFormat{ std::move(rhs.resourceFormat) } - , width{ rhs.width } - , height{ rhs.height } - , mipLevels{ rhs.mipLevels } - { - - } - - /***************************************************************************/ - /*! - - \brief - Move assignment operator. - - \param rhs - The other resource. - - \return - - */ - /***************************************************************************/ - SHRenderGraphResource& SHRenderGraphResource::operator=(SHRenderGraphResource&& rhs) noexcept - { - if (this == &rhs) - return *this; - - resourceName = std::move(rhs.resourceName); - resourceType = std::move(rhs.resourceType); - images = std::move(rhs.images); - imageViews = std::move(rhs.imageViews); - resourceFormat = std::move(rhs.resourceFormat); - width = rhs.width; - height = rhs.height; - mipLevels = rhs.mipLevels; - - return *this; - } - - /***************************************************************************/ - /*! - - \brief - Destructor for resource. - - */ - /***************************************************************************/ - SHRenderGraphResource::~SHRenderGraphResource(void) noexcept - { - - } - - /***************************************************************************/ - /*! - - \brief - Subpass non-default constructor. Simply initializes variables. - - \param mapping - Mapping from a resource handle to an attachment reference referencing - the resource. - - \param resources - A mapping from string to render graph resource. - - */ - /***************************************************************************/ - SHSubpass::SHSubpass(ResourceManager& rm, Handle const& parent, uint32_t index, std::unordered_map const* mapping, std::unordered_map> const* resources) noexcept - : resourceAttachmentMapping{ mapping } - , ptrToResources{ resources } - , parentNode{ parent } - , subpassIndex{ index } - , superBatch{} - , colorReferences{} - , depthReferences{} - , inputReferences{} - { - } - - /***************************************************************************/ - /*! - - \brief - Move constructor for subpass. - - \param rhs - The subpass the move from. - - */ - /***************************************************************************/ - SHSubpass::SHSubpass(SHSubpass&& rhs) noexcept - : subpassIndex{ std::move(rhs.subpassIndex) } - , parentNode{ std::move(rhs.parentNode) } - , superBatch{ std::move(rhs.superBatch) } - , colorReferences{ std::move(rhs.colorReferences) } - , depthReferences{ std::move(rhs.depthReferences) } - , inputReferences{ std::move(rhs.inputReferences) } - , resourceAttachmentMapping{ rhs.resourceAttachmentMapping } - , ptrToResources{ rhs.ptrToResources } - { - - } - - /***************************************************************************/ - /*! - - \brief - Move assignment operator for subpass. - - \param rhs - subpass to move from. - - */ - /***************************************************************************/ - SHSubpass& SHSubpass::operator=(SHSubpass&& rhs) noexcept - { - if (this == &rhs) - return *this; - - subpassIndex = std::move(rhs.subpassIndex); - parentNode = std::move(rhs.parentNode); - superBatch = std::move(rhs.superBatch); - colorReferences = std::move(rhs.colorReferences); - depthReferences = std::move(rhs.depthReferences); - inputReferences = std::move(rhs.inputReferences); - resourceAttachmentMapping = rhs.resourceAttachmentMapping; - ptrToResources = rhs.ptrToResources; - - return *this; - } - - /***************************************************************************/ - /*! - - \brief - Adds a color output to a subpass. Takes in a string and finds the - attachment index to create the vk::SubpassReference. - - \param resourceToReference - Resource name to find resource to attach. - - */ - /***************************************************************************/ - void SHSubpass::AddColorOutput(std::string resourceToReference) noexcept - { - colorReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eColorAttachmentOptimal }); - } - - /***************************************************************************/ - /*! - - \brief - Adds a depth output to a subpass. Takes in a string and finds the - attachment index to create the vk::SubpassReference. - - \param resourceToReference - Resource name to find resource to attach. - - \param attachmentDescriptionType - Depending on the type of the resource, initialize the image layout - appropriately. - - */ - /***************************************************************************/ - void SHSubpass::AddDepthOutput(std::string resourceToReference, SH_ATT_DESC_TYPE attachmentDescriptionType) noexcept - { - vk::ImageLayout imageLayout; - switch (attachmentDescriptionType) - { - case SH_ATT_DESC_TYPE::DEPTH: - imageLayout = vk::ImageLayout::eDepthAttachmentOptimal; - break; - case SH_ATT_DESC_TYPE::STENCIL: - imageLayout = vk::ImageLayout::eStencilAttachmentOptimal; - break; - case SH_ATT_DESC_TYPE::DEPTH_STENCIL: - imageLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal; - break; - default: - //Invalid - return; - } - depthReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), imageLayout }); - } - - /***************************************************************************/ - /*! - - \brief - Adds a input output to a subpass. Takes in a string and finds the - attachment index to create the vk::SubpassReference. - - \param resourceToReference - Resource name to find resource to attach. - - */ - /***************************************************************************/ - void SHSubpass::AddInput(std::string resourceToReference) noexcept - { - inputReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal }); - } - - void SHSubpass::Execute(Handle& commandBuffer, uint32_t frameIndex) noexcept - { - // Ensure correct transforms are provided - superBatch->UpdateBuffers(frameIndex); - - // Draw all the batches - superBatch->Draw(commandBuffer, frameIndex); - - // Draw all the exterior draw calls - for (auto& drawCall : exteriorDrawCalls) - { - drawCall(commandBuffer); - } - } - - void SHSubpass::AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept - { - exteriorDrawCalls.push_back(newDrawCall); - } - - void SHSubpass::Init(ResourceManager& resourceManager) noexcept - { - superBatch = resourceManager.Create(GetHandle()); - - } - - /***************************************************************************/ - /*! - - \brief - Getter for parent renderpass. - - \return - Returns the parent renderpass the subpass belongs to. - - */ - /***************************************************************************/ - Handle const& SHSubpass::GetParentNode(void) const noexcept - { - return parentNode; - } - - SHADE::SHSubPassIndex SHSubpass::GetIndex() const noexcept - { - return subpassIndex; - } - - Handle SHSubpass::GetSuperBatch(void) const noexcept - { - return superBatch; - } - - /***************************************************************************/ - /*! - - \brief - Creates a renderpass for the node. Uses subpass and attachment - descriptions already configured beforehand in the render graph. - - */ - /***************************************************************************/ - void SHRenderGraphNode::CreateRenderpass(void) noexcept - { - renderpass = logicalDeviceHdl->CreateRenderpass(attachmentDescriptions, spDescs, spDeps); - } - - /***************************************************************************/ - /*! - - \brief - Creates a framebuffer from the images used in the renderpass. - - */ - /***************************************************************************/ - void SHRenderGraphNode::CreateFramebuffer(void) noexcept - { - for (uint32_t i = 0; i < framebuffers.size(); ++i) - { - std::vector> imageViews(attResources.size()); - uint32_t fbWidth = std::numeric_limits::max(); - uint32_t fbHeight = std::numeric_limits::max(); - - for (uint32_t j = 0; j < attResources.size(); ++j) - { - uint32_t imageViewIndex = (attResources[j]->resourceType == SH_ATT_DESC_TYPE::COLOR_PRESENT) ? i : 0; - imageViews[j] = attResources[j]->imageViews[imageViewIndex]; - - // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's - if (fbWidth > attResources[j]->width) - fbWidth = attResources[j]->width; - if (fbHeight > attResources[j]->height) - fbHeight = attResources[j]->height; - } - - - framebuffers[i] = logicalDeviceHdl->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight); - } - } - - /***************************************************************************/ - /*! - - \brief - Render Graph node constructor. Note that we do not create the renderpass - yet. This is because layouts of attachment descriptions facilitate image - transitions and we cannot know guarantee layouts until we've seen all - renderpasses and their subpasses in the graph. - - \param swapchain - Swapchain required to query number of images as parameters for number - of framebuffers to create. - - \param attachmentDescriptionTypes - - - \return - - */ - /***************************************************************************/ - SHRenderGraphNode::SHRenderGraphNode(ResourceManager& rm, Handle const& logicalDevice, Handle const& swapchain, std::vector> attRes, std::vector> predecessors, std::unordered_map> const* resources, Handle globalData) noexcept - : logicalDeviceHdl{ logicalDevice } - , renderpass{} - , framebuffers{} - , prereqNodes{ std::move(predecessors) } - , attachmentDescriptions{} - , resourceAttachmentMapping{} - , attResources{ std::move(attRes) } - , subpasses{} - , executed{ false } - , configured{ false } - , resourceManager{ rm } - , ptrToResources{ resources } - { - // pipeline library initialization - pipelineLibrary.Init(logicalDeviceHdl, globalData); - - attachmentDescriptions.resize(attResources.size()); - - bool containsSwapchainImage = false; - for (uint32_t i = 0; i < attResources.size(); ++i) - { - // As mentioned above we don't initialize much here because it's dependent on how other renderpasses are configured. - vk::AttachmentDescription& newDesc = attachmentDescriptions[i]; - newDesc.samples = vk::SampleCountFlagBits::e1; - - // We set this to clear first. If later we find out that some predecessor is writing to the same attachment, - // we set the pred's storeOp to eStore and "this" loadOp to eLoad. - newDesc.loadOp = vk::AttachmentLoadOp::eClear; - newDesc.storeOp = vk::AttachmentStoreOp::eStore; - - newDesc.stencilLoadOp = vk::AttachmentLoadOp::eClear; - newDesc.stencilStoreOp = vk::AttachmentStoreOp::eStore; - - newDesc.format = attResources[i]->resourceFormat; - - if (attResources[i]->resourceType == SH_ATT_DESC_TYPE::COLOR_PRESENT) - containsSwapchainImage = true; - - resourceAttachmentMapping.try_emplace(attResources[i].GetId().Raw, i); - } - - if (!containsSwapchainImage) - framebuffers.resize(1); - else - framebuffers.resize(swapchain->GetNumImages()); - - // At this point, we could configure framebuffers if we had the renderpass object but we don't so their creation has to be - // deferred to when renderpasses are also created. - } - - SHRenderGraphNode::SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept - : resourceManager{ rhs.resourceManager } - , logicalDeviceHdl{ rhs.logicalDeviceHdl } - , renderpass{ rhs.renderpass } - , framebuffers{ std::move(rhs.framebuffers) } - , prereqNodes{ std::move(rhs.prereqNodes) } - , attachmentDescriptions{ std::move(rhs.attachmentDescriptions) } - , attResources{ std::move(rhs.attResources) } - , subpasses{ std::move(rhs.subpasses) } - , resourceAttachmentMapping{ std::move(rhs.resourceAttachmentMapping) } - , subpassIndexing{ std::move(rhs.subpassIndexing) } - , configured{ rhs.configured } - , executed{ rhs.executed } - , ptrToResources{ rhs.ptrToResources } - , pipelineLibrary{ std::move(rhs.pipelineLibrary) } - , batcher { std::move(rhs.batcher) } - - { - rhs.renderpass = {}; - } - - SHRenderGraphNode& SHRenderGraphNode::operator=(SHRenderGraphNode&& rhs) noexcept - { - if (&rhs == this) - return *this; - - resourceManager = rhs.resourceManager; - logicalDeviceHdl = rhs.logicalDeviceHdl; - renderpass = rhs.renderpass; - framebuffers = std::move(rhs.framebuffers); - prereqNodes = std::move(rhs.prereqNodes); - attachmentDescriptions = std::move(rhs.attachmentDescriptions); - attResources = std::move(rhs.attResources); - subpasses = std::move(rhs.subpasses); - resourceAttachmentMapping = std::move(rhs.resourceAttachmentMapping); - subpassIndexing = std::move(rhs.subpassIndexing); - ptrToResources = std::move(rhs.ptrToResources); - pipelineLibrary = std::move(rhs.pipelineLibrary); - batcher = std::move(rhs.batcher); - - rhs.renderpass = {}; - - return *this; - } - - /***************************************************************************/ - /*! - - \brief - Add subpasses to the renderpass and returns a reference to it. - - \param subpassName - Name of the subpass. - - \return - Handle to the new subpass. - - */ - /***************************************************************************/ - Handle SHRenderGraphNode::AddSubpass(std::string subpassName) noexcept - { - // if subpass already exists, don't add. - if (subpassIndexing.contains(subpassName)) - { - SHLOG_ERROR("Subpass already exists."); - return{}; - } - - // Add subpass to container and create mapping for it - subpasses.emplace_back(resourceManager.Create(resourceManager, GetHandle(), subpasses.size(), &resourceAttachmentMapping, ptrToResources)); - subpassIndexing.try_emplace(subpassName, static_cast(subpasses.size()) - 1u); - Handle subpass = subpasses.back(); - subpass->Init(resourceManager); - - // Register the SuperBatch - batcher.RegisterSuperBatch(subpass->GetSuperBatch()); - - return subpass; - } - - void SHRenderGraphNode::Execute(Handle& commandBuffer, uint32_t frameIndex) noexcept - { - frameIndex = (framebuffers.size() > 1) ? frameIndex : 0; - commandBuffer->BeginRenderpass(renderpass, framebuffers[frameIndex]); - - for (uint32_t i = 0; i < subpasses.size(); ++i) - { - subpasses[i]->Execute(commandBuffer, frameIndex); - - // Go to next subpass if not last subpass - if (i != subpasses.size() - 1) - commandBuffer->NextSubpass(); - } - - commandBuffer->EndRenderpass(); - } - - Handle SHRenderGraphNode::GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept - { - // verify subpass exists - if (subpass->GetIndex() >= subpasses.size()) - { - SHLOG_ERROR("Subpass index passed in is not valid. RenderGraphNode does not have that many passes. "); - return {}; - } - - Handle pipeline = pipelineLibrary.GetDrawPipline(vsFsPair); - if (!pipeline) - { - pipeline = pipelineLibrary.CreateDrawPipeline - ( - vsFsPair, - renderpass, - subpass - ); - } - - return pipeline; - } - - void SHRenderGraphNode::FinaliseBatch(uint32_t frameIndex) - { - batcher.FinaliseBatches(logicalDeviceHdl, frameIndex); - } - - /***************************************************************************/ - /*! - - \brief - Get the renderpass from the node. - - \return - Handle to the renderpass. - - */ - /***************************************************************************/ - Handle SHRenderGraphNode::GetRenderpass(void) const noexcept - { - return renderpass; - } - - Handle SHRenderGraphNode::GetSubpass(std::string_view subpassName) const noexcept - { - return subpasses[subpassIndexing.at(subpassName.data())]; - } + /***************************************************************************/ /*! @@ -779,7 +131,7 @@ namespace SHADE attDesc.loadOp = vk::AttachmentLoadOp::eLoad; predAttDesc.storeOp = vk::AttachmentStoreOp::eStore; - // TODO: Stecil load and store + // TODO: Stencil load and store // When an image is done being used in a renderpass, the image layout will end up being the finalLayout // value of the attachment description. We want this to carry over to the next renderpass; specifically diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h index a5ff66d1..02868cce 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h @@ -9,6 +9,10 @@ #include "../MiddleEnd/Batching/SHBatcher.h" #include "SHRenderGraphNode.h" #include "SHSubpass.h" +#include "SHRenderGraphResource.h" +#include "SHRenderGraphNode.h" +#include "SHSubpass.h" +#include "SHAttachmentDescriptionType.h" #include #include diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp index 498ac8e4..4f99ea10 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -1,6 +1,276 @@ +#include "SHpch.h" #include "SHRenderGraphNode.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" +#include "Graphics/Images/SHVkImageView.h" +#include "Graphics/Swapchain/SHVkSwapchain.h" +#include "SHRenderGraphResource.h" +#include "SHSubpass.h" namespace SHADE { - + + /***************************************************************************/ + /*! + + \brief + Creates a renderpass for the node. Uses subpass and attachment + descriptions already configured beforehand in the render graph. + + */ + /***************************************************************************/ + void SHRenderGraphNode::CreateRenderpass(void) noexcept + { + renderpass = logicalDeviceHdl->CreateRenderpass(attachmentDescriptions, spDescs, spDeps); + } + + /***************************************************************************/ + /*! + + \brief + Creates a framebuffer from the images used in the renderpass. + + */ + /***************************************************************************/ + void SHRenderGraphNode::CreateFramebuffer(void) noexcept + { + for (uint32_t i = 0; i < framebuffers.size(); ++i) + { + std::vector> imageViews(attResources.size()); + uint32_t fbWidth = std::numeric_limits::max(); + uint32_t fbHeight = std::numeric_limits::max(); + + for (uint32_t j = 0; j < attResources.size(); ++j) + { + uint32_t imageViewIndex = (attResources[j]->resourceType == SH_ATT_DESC_TYPE::COLOR_PRESENT) ? i : 0; + imageViews[j] = attResources[j]->imageViews[imageViewIndex]; + + // We want the minimum dimensions for the framebuffer because the image attachments referenced cannot have dimensions smaller than the framebuffer's + if (fbWidth > attResources[j]->width) + fbWidth = attResources[j]->width; + if (fbHeight > attResources[j]->height) + fbHeight = attResources[j]->height; + } + + + framebuffers[i] = logicalDeviceHdl->CreateFramebuffer(renderpass, imageViews, fbWidth, fbHeight); + } + } + + /***************************************************************************/ + /*! + + \brief + Render Graph node constructor. Note that we do not create the renderpass + yet. This is because layouts of attachment descriptions facilitate image + transitions and we cannot know guarantee layouts until we've seen all + renderpasses and their subpasses in the graph. + + \param swapchain + Swapchain required to query number of images as parameters for number + of framebuffers to create. + + \param attachmentDescriptionTypes + + + \return + + */ + /***************************************************************************/ + SHRenderGraphNode::SHRenderGraphNode(ResourceManager& rm, Handle const& logicalDevice, Handle const& swapchain, std::vector> attRes, std::vector> predecessors, std::unordered_map> const* resources, Handle globalData) noexcept + : logicalDeviceHdl{ logicalDevice } + , renderpass{} + , framebuffers{} + , prereqNodes{ std::move(predecessors) } + , attachmentDescriptions{} + , resourceAttachmentMapping{} + , attResources{ std::move(attRes) } + , subpasses{} + , executed{ false } + , configured{ false } + , resourceManager{ rm } + , ptrToResources{ resources } + { + // pipeline library initialization + pipelineLibrary.Init(logicalDeviceHdl, globalData); + + attachmentDescriptions.resize(attResources.size()); + + bool containsSwapchainImage = false; + for (uint32_t i = 0; i < attResources.size(); ++i) + { + // As mentioned above we don't initialize much here because it's dependent on how other renderpasses are configured. + vk::AttachmentDescription& newDesc = attachmentDescriptions[i]; + newDesc.samples = vk::SampleCountFlagBits::e1; + + // We set this to clear first. If later we find out that some predecessor is writing to the same attachment, + // we set the pred's storeOp to eStore and "this" loadOp to eLoad. + newDesc.loadOp = vk::AttachmentLoadOp::eClear; + newDesc.storeOp = vk::AttachmentStoreOp::eStore; + + newDesc.stencilLoadOp = vk::AttachmentLoadOp::eClear; + newDesc.stencilStoreOp = vk::AttachmentStoreOp::eStore; + + newDesc.format = attResources[i]->resourceFormat; + + if (attResources[i]->resourceType == SH_ATT_DESC_TYPE::COLOR_PRESENT) + containsSwapchainImage = true; + + resourceAttachmentMapping.try_emplace(attResources[i].GetId().Raw, i); + } + + if (!containsSwapchainImage) + framebuffers.resize(1); + else + framebuffers.resize(swapchain->GetNumImages()); + + // At this point, we could configure framebuffers if we had the renderpass object but we don't so their creation has to be + // deferred to when renderpasses are also created. + } + + SHRenderGraphNode::SHRenderGraphNode(SHRenderGraphNode&& rhs) noexcept + : resourceManager{ rhs.resourceManager } + , logicalDeviceHdl{ rhs.logicalDeviceHdl } + , renderpass{ rhs.renderpass } + , framebuffers{ std::move(rhs.framebuffers) } + , prereqNodes{ std::move(rhs.prereqNodes) } + , attachmentDescriptions{ std::move(rhs.attachmentDescriptions) } + , attResources{ std::move(rhs.attResources) } + , subpasses{ std::move(rhs.subpasses) } + , resourceAttachmentMapping{ std::move(rhs.resourceAttachmentMapping) } + , subpassIndexing{ std::move(rhs.subpassIndexing) } + , configured{ rhs.configured } + , executed{ rhs.executed } + , ptrToResources{ rhs.ptrToResources } + , pipelineLibrary{ std::move(rhs.pipelineLibrary) } + , batcher{ std::move(rhs.batcher) } + + { + rhs.renderpass = {}; + } + + SHRenderGraphNode& SHRenderGraphNode::operator=(SHRenderGraphNode&& rhs) noexcept + { + if (&rhs == this) + return *this; + + resourceManager = rhs.resourceManager; + logicalDeviceHdl = rhs.logicalDeviceHdl; + renderpass = rhs.renderpass; + framebuffers = std::move(rhs.framebuffers); + prereqNodes = std::move(rhs.prereqNodes); + attachmentDescriptions = std::move(rhs.attachmentDescriptions); + attResources = std::move(rhs.attResources); + subpasses = std::move(rhs.subpasses); + resourceAttachmentMapping = std::move(rhs.resourceAttachmentMapping); + subpassIndexing = std::move(rhs.subpassIndexing); + ptrToResources = std::move(rhs.ptrToResources); + pipelineLibrary = std::move(rhs.pipelineLibrary); + batcher = std::move(rhs.batcher); + + rhs.renderpass = {}; + + return *this; + } + + /***************************************************************************/ + /*! + + \brief + Add subpasses to the renderpass and returns a reference to it. + + \param subpassName + Name of the subpass. + + \return + Handle to the new subpass. + + */ + /***************************************************************************/ + Handle SHRenderGraphNode::AddSubpass(std::string subpassName) noexcept + { + // if subpass already exists, don't add. + if (subpassIndexing.contains(subpassName)) + { + SHLOG_ERROR("Subpass already exists."); + return{}; + } + + // Add subpass to container and create mapping for it + subpasses.emplace_back(resourceManager.Create(resourceManager, GetHandle(), subpasses.size(), &resourceAttachmentMapping, ptrToResources)); + subpassIndexing.try_emplace(subpassName, static_cast(subpasses.size()) - 1u); + Handle subpass = subpasses.back(); + subpass->Init(resourceManager); + + // Register the SuperBatch + batcher.RegisterSuperBatch(subpass->GetSuperBatch()); + + return subpass; + } + + void SHRenderGraphNode::Execute(Handle& commandBuffer, uint32_t frameIndex) noexcept + { + frameIndex = (framebuffers.size() > 1) ? frameIndex : 0; + commandBuffer->BeginRenderpass(renderpass, framebuffers[frameIndex]); + + for (uint32_t i = 0; i < subpasses.size(); ++i) + { + subpasses[i]->Execute(commandBuffer, frameIndex); + + // Go to next subpass if not last subpass + if (i != subpasses.size() - 1) + commandBuffer->NextSubpass(); + } + + commandBuffer->EndRenderpass(); + } + + Handle SHRenderGraphNode::GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept + { + // verify subpass exists + if (subpass->GetIndex() >= subpasses.size()) + { + SHLOG_ERROR("Subpass index passed in is not valid. RenderGraphNode does not have that many passes. "); + return {}; + } + + Handle pipeline = pipelineLibrary.GetDrawPipline(vsFsPair); + if (!pipeline) + { + pipeline = pipelineLibrary.CreateDrawPipeline + ( + vsFsPair, + renderpass, + subpass + ); + } + + return pipeline; + } + + void SHRenderGraphNode::FinaliseBatch(uint32_t frameIndex) + { + batcher.FinaliseBatches(logicalDeviceHdl, frameIndex); + } + + /***************************************************************************/ + /*! + + \brief + Get the renderpass from the node. + + \return + Handle to the renderpass. + + */ + /***************************************************************************/ + Handle SHRenderGraphNode::GetRenderpass(void) const noexcept + { + return renderpass; + } + + Handle SHRenderGraphNode::GetSubpass(std::string_view subpassName) const noexcept + { + return subpasses[subpassIndexing.at(subpassName.data())]; + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h index 7cd31787..cdaddb8e 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h @@ -1,8 +1,22 @@ #pragma once +#include +#include +#include +#include +#include "SHAttachmentDescriptionType.h" +#include "Graphics/SHVulkanIncludes.h" +#include "SH_API.h" +#include "Graphics/MiddleEnd/Pipeline/SHPipelineLibrary.h" +#include "Graphics/MiddleEnd/Batching/SHBatcher.h" + namespace SHADE { - + class ResourceManager; + class SHVkFramebuffer; + class SHRenderGraphResource; + class SHVkLogicalDevice; + class SHVkRenderpass; class SH_API SHRenderGraphNode : public ISelfHandle { diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp index 6b0138d9..eb873b16 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.cpp @@ -1,6 +1,192 @@ +#include "SHpch.h" #include "SHRenderGraphResource.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" +#include "Graphics/Swapchain/SHVkSwapchain.h" namespace SHADE { - + /***************************************************************************/ + /*! + + \brief + Non-default ctor for the resource. Using the type of the resource, we + decide whether or not we create a resource or link with a swapchain + resource (image). + + \param logicalDevice + Logical device required to create an image resource if the type is NOT + SH_ATT_DESC_TYPE::COLOR_PRESENT. + + \param swapchain + Swapchain required to get swapchain image if the type IS + SH_ATT_DESC_TYPE::COLOR_PRESENT. + + \param type + Type of the image resource. + + \param format + Format of the image resource. + + \param w + Width of the image resource. + + \param h + Height of the image resource. + + \param levels + Number of mipmap levels of the image resource. + + \param createFlags + Create flags used when an image resource needs to be created. + + */ + /***************************************************************************/ + SHRenderGraphResource::SHRenderGraphResource(Handle const& logicalDevice, Handle const& swapchain, std::string const& name, SH_ATT_DESC_TYPE type, vk::Format format, uint32_t w, uint32_t h, uint8_t levels, vk::ImageCreateFlagBits createFlags) noexcept + : resourceType{ type } + , resourceFormat{ format } + , images{} + , imageViews{} + , width{ w } + , height{ h } + , mipLevels{ levels } + , resourceName{ name } + { + // If the resource type is an arbitrary image and not swapchain image + if (type != SH_ATT_DESC_TYPE::COLOR_PRESENT) + { + vk::ImageAspectFlags imageAspectFlags; + vk::ImageUsageFlags usage = {}; + + // Check the resource type and set image usage flags and image aspect flags accordingly + switch (resourceType) + { + case SH_ATT_DESC_TYPE::COLOR: + usage |= vk::ImageUsageFlagBits::eColorAttachment; + imageAspectFlags |= vk::ImageAspectFlagBits::eColor; + break; + case SH_ATT_DESC_TYPE::DEPTH: + usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; + imageAspectFlags |= vk::ImageAspectFlagBits::eDepth; + break; + case SH_ATT_DESC_TYPE::STENCIL: + usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; + imageAspectFlags |= vk::ImageAspectFlagBits::eStencil; + break; + case SH_ATT_DESC_TYPE::DEPTH_STENCIL: + usage |= vk::ImageUsageFlagBits::eDepthStencilAttachment; + imageAspectFlags |= vk::ImageAspectFlagBits::eStencil | vk::ImageAspectFlagBits::eDepth; + break; + } + + // The resource is not a swapchain image, just use the first slot of the vector + images.push_back(logicalDevice->CreateImage(width, height, mipLevels, resourceFormat, usage, createFlags)); + + // prepare image view details + SHImageViewDetails viewDetails + { + .viewType = vk::ImageViewType::e2D, + .format = images[0]->GetImageFormat(), + .imageAspectFlags = imageAspectFlags, + .baseMipLevel = 0, + .mipLevelCount = mipLevels, + .baseArrayLayer = 0, + .layerCount = 1, + }; + + // just 1 image view created + imageViews.push_back(images[0]->CreateImageView(logicalDevice, images[0], viewDetails)); + } + else // if swapchain image resource + { + // Prepare image view details + SHImageViewDetails viewDetails + { + .viewType = vk::ImageViewType::e2D, + .format = swapchain->GetSurfaceFormatKHR().format, + .imageAspectFlags = vk::ImageAspectFlagBits::eColor, + .baseMipLevel = 0, + .mipLevelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1, + }; + + // We want an image handle for every swapchain image + images.resize(swapchain->GetNumImages()); + imageViews.resize(swapchain->GetNumImages()); + + for (uint32_t i = 0; i < swapchain->GetNumImages(); ++i) + { + images[i] = swapchain->GetSwapchainImage(i); + imageViews[i] = images[i]->CreateImageView(logicalDevice, images[i], viewDetails); + } + } + } + + /***************************************************************************/ + /*! + + \brief + Move ctor for resource. + + \param rhs + The other resource. + + */ + /***************************************************************************/ + SHRenderGraphResource::SHRenderGraphResource(SHRenderGraphResource&& rhs) noexcept + : resourceName{ std::move(rhs.resourceName) } + , resourceType{ std::move(rhs.resourceType) } + , images{ std::move(rhs.images) } + , imageViews{ std::move(rhs.imageViews) } + , resourceFormat{ std::move(rhs.resourceFormat) } + , width{ rhs.width } + , height{ rhs.height } + , mipLevels{ rhs.mipLevels } + { + + } + + /***************************************************************************/ + /*! + + \brief + Move assignment operator. + + \param rhs + The other resource. + + \return + + */ + /***************************************************************************/ + SHRenderGraphResource& SHRenderGraphResource::operator=(SHRenderGraphResource&& rhs) noexcept + { + if (this == &rhs) + return *this; + + resourceName = std::move(rhs.resourceName); + resourceType = std::move(rhs.resourceType); + images = std::move(rhs.images); + imageViews = std::move(rhs.imageViews); + resourceFormat = std::move(rhs.resourceFormat); + width = rhs.width; + height = rhs.height; + mipLevels = rhs.mipLevels; + + return *this; + } + + /***************************************************************************/ + /*! + + \brief + Destructor for resource. + + */ + /***************************************************************************/ + SHRenderGraphResource::~SHRenderGraphResource(void) noexcept + { + + } + } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h index 78245763..fcb16601 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphResource.h @@ -1,7 +1,19 @@ #pragma once +#include +#include "SHAttachmentDescriptionType.h" +#include +#include "Resource/Handle.h" +#include "Graphics/SHVulkanIncludes.h" +#include "SH_API.h" + namespace SHADE { + class SHVkImage; + class SHVkImageView; + class SHVkLogicalDevice; + class SHVkSwapchain; + class SH_API SHRenderGraphResource { private: diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp index 329af7c3..2d79b764 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.cpp @@ -1,6 +1,210 @@ +#include "SHpch.h" #include "SHSubpass.h" +#include "Graphics/MiddleEnd/Batching/SHSuperBatch.h" +#include "Graphics/Devices/SHVkLogicalDevice.h" namespace SHADE { - + + /***************************************************************************/ + /*! + + \brief + Subpass non-default constructor. Simply initializes variables. + + \param mapping + Mapping from a resource handle to an attachment reference referencing + the resource. + + \param resources + A mapping from string to render graph resource. + + */ + /***************************************************************************/ + SHSubpass::SHSubpass(ResourceManager& rm, Handle const& parent, uint32_t index, std::unordered_map const* mapping, std::unordered_map> const* resources) noexcept + : resourceAttachmentMapping{ mapping } + , ptrToResources{ resources } + , parentNode{ parent } + , subpassIndex{ index } + , superBatch{} + , colorReferences{} + , depthReferences{} + , inputReferences{} + { + } + + /***************************************************************************/ + /*! + + \brief + Move constructor for subpass. + + \param rhs + The subpass the move from. + + */ + /***************************************************************************/ + SHSubpass::SHSubpass(SHSubpass&& rhs) noexcept + : subpassIndex{ std::move(rhs.subpassIndex) } + , parentNode{ std::move(rhs.parentNode) } + , superBatch{ std::move(rhs.superBatch) } + , colorReferences{ std::move(rhs.colorReferences) } + , depthReferences{ std::move(rhs.depthReferences) } + , inputReferences{ std::move(rhs.inputReferences) } + , resourceAttachmentMapping{ rhs.resourceAttachmentMapping } + , ptrToResources{ rhs.ptrToResources } + { + + } + + /***************************************************************************/ + /*! + + \brief + Move assignment operator for subpass. + + \param rhs + subpass to move from. + + */ + /***************************************************************************/ + SHSubpass& SHSubpass::operator=(SHSubpass&& rhs) noexcept + { + if (this == &rhs) + return *this; + + subpassIndex = std::move(rhs.subpassIndex); + parentNode = std::move(rhs.parentNode); + superBatch = std::move(rhs.superBatch); + colorReferences = std::move(rhs.colorReferences); + depthReferences = std::move(rhs.depthReferences); + inputReferences = std::move(rhs.inputReferences); + resourceAttachmentMapping = rhs.resourceAttachmentMapping; + ptrToResources = rhs.ptrToResources; + + return *this; + } + + /***************************************************************************/ + /*! + + \brief + Adds a color output to a subpass. Takes in a string and finds the + attachment index to create the vk::SubpassReference. + + \param resourceToReference + Resource name to find resource to attach. + + */ + /***************************************************************************/ + void SHSubpass::AddColorOutput(std::string resourceToReference) noexcept + { + colorReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eColorAttachmentOptimal }); + } + + /***************************************************************************/ + /*! + + \brief + Adds a depth output to a subpass. Takes in a string and finds the + attachment index to create the vk::SubpassReference. + + \param resourceToReference + Resource name to find resource to attach. + + \param attachmentDescriptionType + Depending on the type of the resource, initialize the image layout + appropriately. + + */ + /***************************************************************************/ + void SHSubpass::AddDepthOutput(std::string resourceToReference, SH_ATT_DESC_TYPE attachmentDescriptionType) noexcept + { + vk::ImageLayout imageLayout; + switch (attachmentDescriptionType) + { + case SH_ATT_DESC_TYPE::DEPTH: + imageLayout = vk::ImageLayout::eDepthAttachmentOptimal; + break; + case SH_ATT_DESC_TYPE::STENCIL: + imageLayout = vk::ImageLayout::eStencilAttachmentOptimal; + break; + case SH_ATT_DESC_TYPE::DEPTH_STENCIL: + imageLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal; + break; + default: + //Invalid + return; + } + depthReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), imageLayout }); + } + + /***************************************************************************/ + /*! + + \brief + Adds a input output to a subpass. Takes in a string and finds the + attachment index to create the vk::SubpassReference. + + \param resourceToReference + Resource name to find resource to attach. + + */ + /***************************************************************************/ + void SHSubpass::AddInput(std::string resourceToReference) noexcept + { + inputReferences.push_back({ resourceAttachmentMapping->at(ptrToResources->at(resourceToReference).GetId().Raw), vk::ImageLayout::eShaderReadOnlyOptimal }); + } + + void SHSubpass::Execute(Handle& commandBuffer, uint32_t frameIndex) noexcept + { + // Ensure correct transforms are provided + superBatch->UpdateBuffers(frameIndex); + + // Draw all the batches + superBatch->Draw(commandBuffer, frameIndex); + + // Draw all the exterior draw calls + for (auto& drawCall : exteriorDrawCalls) + { + drawCall(commandBuffer); + } + } + + void SHSubpass::AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept + { + exteriorDrawCalls.push_back(newDrawCall); + } + + void SHSubpass::Init(ResourceManager& resourceManager) noexcept + { + superBatch = resourceManager.Create(GetHandle()); + + } + + /***************************************************************************/ + /*! + + \brief + Getter for parent renderpass. + + \return + Returns the parent renderpass the subpass belongs to. + + */ + /***************************************************************************/ + Handle const& SHSubpass::GetParentNode(void) const noexcept + { + return parentNode; + } + + SHADE::SHSubPassIndex SHSubpass::GetIndex() const noexcept + { + return subpassIndex; + } + + Handle SHSubpass::GetSuperBatch(void) const noexcept + { + return superBatch; + } } \ No newline at end of file diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h index a1aa1500..da36fe46 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpass.h @@ -1,6 +1,93 @@ #pragma once +#include "SHAttachmentDescriptionType.h" +#include +#include "SH_API.h" +#include "Resource/Handle.h" +#include "Graphics/SHVulkanIncludes.h" + + namespace SHADE { + class SHRenderGraphNode; + class SHSuperBatch; + class SHRenderGraphResource; + class SHVkCommandBuffer; + class SHVkDescriptorSetLayout; + class SH_API SHSubpass : public ISelfHandle + { + private: + /*---------------------------------------------------------------------*/ + /* PRIVATE MEMBER VARIABLES */ + /*---------------------------------------------------------------------*/ + //! The index of the subpass in the render graph + uint32_t subpassIndex; + + //! The parent renderpass that this subpass belongs to + Handle parentNode; + + //! + Handle superBatch; + + //! Descriptor set layout to hold attachments + Handle descriptorSetLayout; + + //! Color attachments + std::vector colorReferences; + + //! Depth attachments + std::vector depthReferences; + + //! Input attachments + std::vector inputReferences; + + //! For getting attachment reference indices using handles + std::unordered_map const* resourceAttachmentMapping; + + //! Pointer to resources in the render graph (for getting handle IDs) + std::unordered_map> const* ptrToResources; + + //! Sometimes there exists entities that we want to render onto a render target + //! but don't want it to come from the batching system. An example would be ImGUI. + //! For these entities we want to link a function from the outside and draw them + //! after we draw everything from the batch. Because of this, these draw calls + //! are always the last things drawn, so DO NOT USE THIS FUNCTIONALITY FOR ANYTHING + //! COMPLEX. + std::vector&)>> exteriorDrawCalls; + + + public: + /*-----------------------------------------------------------------------*/ + /* CTORS AND DTORS */ + /*-----------------------------------------------------------------------*/ + SHSubpass(ResourceManager& rm, Handle const& parent, uint32_t index, std::unordered_map const* mapping, std::unordered_map> const* ptrToResources) noexcept; + SHSubpass(SHSubpass&& rhs) noexcept; + SHSubpass& operator=(SHSubpass&& rhs) noexcept; + + /*-----------------------------------------------------------------------*/ + /* PUBLIC MEMBER FUNCTIONS */ + /*-----------------------------------------------------------------------*/ + // Preparation functions + void AddColorOutput(std::string resourceToReference) noexcept; + void AddDepthOutput(std::string resourceToReference, SH_ATT_DESC_TYPE attachmentDescriptionType = SH_ATT_DESC_TYPE::DEPTH_STENCIL) noexcept; + void AddInput(std::string resourceToReference) noexcept; + + // Runtime functions + void Execute(Handle& commandBuffer, uint32_t frameIndex) noexcept; + void AddExteriorDrawCalls(std::function&)> const& newDrawCall) noexcept; + + void Init(ResourceManager& resourceManager) noexcept; + + /*-----------------------------------------------------------------------*/ + /* GETTERS AND SETTERS */ + /*-----------------------------------------------------------------------*/ + Handle const& GetParentNode(void) const noexcept; + SHSubPassIndex GetIndex() const noexcept; + Handle GetSuperBatch(void) const noexcept; + + + friend class SHRenderGraphNode; + friend class SHRenderGraph; + }; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp new file mode 100644 index 00000000..ccd0e6c3 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.cpp @@ -0,0 +1,23 @@ +#include "SHpch.h" +#include "SHSubpassCompute.h" +#include "Graphics/Pipeline/SHVkPipeline.h" +#include "Graphics/Descriptors/SHVkDescriptorSetGroup.h" +#include "Graphics/Descriptors/SHVkDescriptorPool.h" + +namespace SHADE +{ + SHSubpassCompute::SHSubpassCompute(Handle inPipeline, Handle descPool) noexcept + : pipeline {inPipeline} + { + // Get the descriptor set layouts required to allocate. we will bind a different pipeline layout, one that includes the layout for global. + auto const& layouts = pipeline->GetPipelineLayout()->GetDescriptorSetLayoutsAllocate(); + + // Variable counts for the descriptor sets (all should be 1). + std::vector variableCounts{static_cast(layouts.size())}; + std::fill (variableCounts.begin(), variableCounts.end(), 0); + + // Allocate descriptor sets to hold the images for reading (STORAGE_IMAGE) + descPool->Allocate(layouts, variableCounts); + } + +} diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.h b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.h new file mode 100644 index 00000000..3ebc5676 --- /dev/null +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHSubpassCompute.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +namespace SHADE +{ + class SHVkPipeline; + class SHVkDescriptorSetGroup; + class SHVkDescriptorPool; + + class SHSubpassCompute + { + private: + //! To run the dispatch command + Handle pipeline; + + //! Descriptor set group + Handle descSetGroup; + + public: + SHSubpassCompute (Handle inPipeline, Handle descPool) noexcept; + + }; +} + diff --git a/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h b/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h index afed0736..b0ae7445 100644 --- a/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h +++ b/SHADE_Engine/src/Graphics/Renderpass/SHVkRenderpass.h @@ -10,10 +10,6 @@ namespace SHADE { class SHVkLogicalDevice; class SHVkFramebuffer; - /*-----------------------------------------------------------------------*/ - /* TYPE DEFINTIIONS */ - /*-----------------------------------------------------------------------*/ - using SHSubPassIndex = uint32_t; class SHVkRenderpass { diff --git a/SHADE_Engine/src/Graphics/SHVulkanDefines.h b/SHADE_Engine/src/Graphics/SHVulkanDefines.h index 2f625f7e..1cbcae0f 100644 --- a/SHADE_Engine/src/Graphics/SHVulkanDefines.h +++ b/SHADE_Engine/src/Graphics/SHVulkanDefines.h @@ -5,9 +5,13 @@ namespace SHADE { + /*-----------------------------------------------------------------------*/ + /* TYPE DEFINTIIONS */ + /*-----------------------------------------------------------------------*/ using SHQueueFamilyIndex = uint32_t; using BindingAndSetHash = uint64_t; using SetIndex = uint32_t; + using SHSubPassIndex = uint32_t; }