Merge branch 'SP3-1-Rendering' of https://github.com/SHADE-DP/SHADE_Y3 into SP3-1-Rendering

This commit is contained in:
Kah Wei 2022-09-26 17:18:55 +08:00
commit 927944d55a
15 changed files with 863 additions and 664 deletions

View File

@ -39,8 +39,9 @@ namespace SHADE
std::vector<vk::DescriptorPoolSize> 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}
};
/// <summary>
/// Maximum number of descriptor sets allowed

View File

@ -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<Handle<SHVkDescriptorSetLayout>> SHVkPipelineLayout::GetDescriptorSetLayoutsPipeline(void) const noexcept
{
return descriptorSetLayoutsPipeline;
}
std::vector<Handle<SHVkDescriptorSetLayout>> SHVkPipelineLayout::GetDescriptorSetLayoutsAllocate(void) const noexcept
{
return descriptorSetLayoutsAllocate;
}
SHVkPipelineLayout& SHVkPipelineLayout::operator=(SHVkPipelineLayout&& rhs) noexcept
{
if (&rhs == this)

View File

@ -42,6 +42,9 @@ namespace SHADE
//! We want to store this also because we need to allocate later
std::vector<vk::DescriptorSetLayout> vkDescriptorSetLayoutsAllocate;
//! Store for descriptor set group creation
std::vector<Handle<SHVkDescriptorSetLayout>> descriptorSetLayoutsPipeline;
//! Store for pipeline layout recreation
std::vector<vk::DescriptorSetLayout> vkDescriptorSetLayoutsPipeline;
@ -71,10 +74,12 @@ namespace SHADE
/*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/
std::vector<Handle<SHVkShaderModule>> const& GetShaderModules (void) const noexcept;
vk::PipelineLayout GetVkPipelineLayout (void) const noexcept;
SHPushConstantInterface const& GetPushConstantInterface (void) const noexcept;
Handle<SHShaderBlockInterface> GetShaderBlockInterface (uint32_t set, uint32_t binding, vk::ShaderStageFlagBits shaderStage) const noexcept;
std::vector<Handle<SHVkShaderModule>> const& GetShaderModules (void) const noexcept;
vk::PipelineLayout GetVkPipelineLayout (void) const noexcept;
SHPushConstantInterface const& GetPushConstantInterface (void) const noexcept;
Handle<SHShaderBlockInterface> GetShaderBlockInterface (uint32_t set, uint32_t binding, vk::ShaderStageFlagBits shaderStage) const noexcept;
std::vector<Handle<SHVkDescriptorSetLayout>> GetDescriptorSetLayoutsPipeline(void) const noexcept;
std::vector<Handle<SHVkDescriptorSetLayout>> GetDescriptorSetLayoutsAllocate(void) const noexcept;
};
}

View File

@ -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<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> 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<SHRenderGraphNode> const& parent, uint32_t index, std::unordered_map<uint64_t, uint32_t> const* mapping, std::unordered_map<std::string, Handle<SHRenderGraphResource>> 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<SHVkCommandBuffer>& 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<void(Handle<SHVkCommandBuffer>&)> const& newDrawCall) noexcept
{
exteriorDrawCalls.push_back(newDrawCall);
}
void SHSubpass::Init(ResourceManager& resourceManager) noexcept
{
superBatch = resourceManager.Create<SHSuperBatch>(GetHandle());
}
/***************************************************************************/
/*!
\brief
Getter for parent renderpass.
\return
Returns the parent renderpass the subpass belongs to.
*/
/***************************************************************************/
Handle<SHRenderGraphNode> const& SHSubpass::GetParentNode(void) const noexcept
{
return parentNode;
}
SHADE::SHSubPassIndex SHSubpass::GetIndex() const noexcept
{
return subpassIndex;
}
Handle<SHSuperBatch> 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<Handle<SHVkImageView>> imageViews(attResources.size());
uint32_t fbWidth = std::numeric_limits<uint32_t>::max();
uint32_t fbHeight = std::numeric_limits<uint32_t>::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<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::vector<Handle<SHRenderGraphResource>> attRes, std::vector<Handle<SHRenderGraphNode>> predecessors, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* resources, Handle<SHGraphicsGlobalData> 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<SHSubpass> 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<SHSubpass>(resourceManager, GetHandle(), subpasses.size(), &resourceAttachmentMapping, ptrToResources));
subpassIndexing.try_emplace(subpassName, static_cast<uint32_t>(subpasses.size()) - 1u);
Handle<SHSubpass> subpass = subpasses.back();
subpass->Init(resourceManager);
// Register the SuperBatch
batcher.RegisterSuperBatch(subpass->GetSuperBatch());
return subpass;
}
void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer>& 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<SHVkPipeline> SHRenderGraphNode::GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> 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<SHVkPipeline> 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<SHVkRenderpass> SHRenderGraphNode::GetRenderpass(void) const noexcept
{
return renderpass;
}
Handle<SHSubpass> 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

View File

@ -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 <string>
#include <map>

View File

@ -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<Handle<SHVkImageView>> imageViews(attResources.size());
uint32_t fbWidth = std::numeric_limits<uint32_t>::max();
uint32_t fbHeight = std::numeric_limits<uint32_t>::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<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> const& swapchain, std::vector<Handle<SHRenderGraphResource>> attRes, std::vector<Handle<SHRenderGraphNode>> predecessors, std::unordered_map<std::string, Handle<SHRenderGraphResource>> const* resources, Handle<SHGraphicsGlobalData> 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<SHSubpass> 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<SHSubpass>(resourceManager, GetHandle(), subpasses.size(), &resourceAttachmentMapping, ptrToResources));
subpassIndexing.try_emplace(subpassName, static_cast<uint32_t>(subpasses.size()) - 1u);
Handle<SHSubpass> subpass = subpasses.back();
subpass->Init(resourceManager);
// Register the SuperBatch
batcher.RegisterSuperBatch(subpass->GetSuperBatch());
return subpass;
}
void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer>& 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<SHVkPipeline> SHRenderGraphNode::GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> 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<SHVkPipeline> 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<SHVkRenderpass> SHRenderGraphNode::GetRenderpass(void) const noexcept
{
return renderpass;
}
Handle<SHSubpass> SHRenderGraphNode::GetSubpass(std::string_view subpassName) const noexcept
{
return subpasses[subpassIndexing.at(subpassName.data())];
}
}

View File

@ -1,8 +1,22 @@
#pragma once
#include <string>
#include <unordered_map>
#include <map>
#include <vector>
#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<SHRenderGraphNode>
{

View File

@ -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<SHVkLogicalDevice> const& logicalDevice, Handle<SHVkSwapchain> 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
{
}
}

View File

@ -1,7 +1,19 @@
#pragma once
#include <string>
#include "SHAttachmentDescriptionType.h"
#include <vector>
#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:

View File

@ -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<SHRenderGraphNode> const& parent, uint32_t index, std::unordered_map<uint64_t, uint32_t> const* mapping, std::unordered_map<std::string, Handle<SHRenderGraphResource>> 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<SHVkCommandBuffer>& 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<void(Handle<SHVkCommandBuffer>&)> const& newDrawCall) noexcept
{
exteriorDrawCalls.push_back(newDrawCall);
}
void SHSubpass::Init(ResourceManager& resourceManager) noexcept
{
superBatch = resourceManager.Create<SHSuperBatch>(GetHandle());
}
/***************************************************************************/
/*!
\brief
Getter for parent renderpass.
\return
Returns the parent renderpass the subpass belongs to.
*/
/***************************************************************************/
Handle<SHRenderGraphNode> const& SHSubpass::GetParentNode(void) const noexcept
{
return parentNode;
}
SHADE::SHSubPassIndex SHSubpass::GetIndex() const noexcept
{
return subpassIndex;
}
Handle<SHSuperBatch> SHSubpass::GetSuperBatch(void) const noexcept
{
return superBatch;
}
}

View File

@ -1,6 +1,93 @@
#pragma once
#include "SHAttachmentDescriptionType.h"
#include <string>
#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<SHSubpass>
{
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<SHRenderGraphNode> parentNode;
//!
Handle<SHSuperBatch> superBatch;
//! Descriptor set layout to hold attachments
Handle<SHVkDescriptorSetLayout> descriptorSetLayout;
//! Color attachments
std::vector<vk::AttachmentReference> colorReferences;
//! Depth attachments
std::vector<vk::AttachmentReference> depthReferences;
//! Input attachments
std::vector<vk::AttachmentReference> inputReferences;
//! For getting attachment reference indices using handles
std::unordered_map<uint64_t, uint32_t> const* resourceAttachmentMapping;
//! Pointer to resources in the render graph (for getting handle IDs)
std::unordered_map<std::string, Handle<SHRenderGraphResource>> 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<std::function<void(Handle<SHVkCommandBuffer>&)>> exteriorDrawCalls;
public:
/*-----------------------------------------------------------------------*/
/* CTORS AND DTORS */
/*-----------------------------------------------------------------------*/
SHSubpass(ResourceManager& rm, Handle<SHRenderGraphNode> const& parent, uint32_t index, std::unordered_map<uint64_t, uint32_t> const* mapping, std::unordered_map<std::string, Handle<SHRenderGraphResource>> 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<SHVkCommandBuffer>& commandBuffer, uint32_t frameIndex) noexcept;
void AddExteriorDrawCalls(std::function<void(Handle<SHVkCommandBuffer>&)> const& newDrawCall) noexcept;
void Init(ResourceManager& resourceManager) noexcept;
/*-----------------------------------------------------------------------*/
/* GETTERS AND SETTERS */
/*-----------------------------------------------------------------------*/
Handle<SHRenderGraphNode> const& GetParentNode(void) const noexcept;
SHSubPassIndex GetIndex() const noexcept;
Handle<SHSuperBatch> GetSuperBatch(void) const noexcept;
friend class SHRenderGraphNode;
friend class SHRenderGraph;
};
}

View File

@ -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<SHVkPipeline> inPipeline, Handle<SHVkDescriptorPool> 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<uint32_t> variableCounts{static_cast<uint32_t>(layouts.size())};
std::fill (variableCounts.begin(), variableCounts.end(), 0);
// Allocate descriptor sets to hold the images for reading (STORAGE_IMAGE)
descPool->Allocate(layouts, variableCounts);
}
}

View File

@ -0,0 +1,25 @@
#pragma once
#include <Resource/Handle.h>
namespace SHADE
{
class SHVkPipeline;
class SHVkDescriptorSetGroup;
class SHVkDescriptorPool;
class SHSubpassCompute
{
private:
//! To run the dispatch command
Handle<SHVkPipeline> pipeline;
//! Descriptor set group
Handle<SHVkDescriptorSetGroup> descSetGroup;
public:
SHSubpassCompute (Handle<SHVkPipeline> inPipeline, Handle<SHVkDescriptorPool> descPool) noexcept;
};
}

View File

@ -10,10 +10,6 @@ namespace SHADE
{
class SHVkLogicalDevice;
class SHVkFramebuffer;
/*-----------------------------------------------------------------------*/
/* TYPE DEFINTIIONS */
/*-----------------------------------------------------------------------*/
using SHSubPassIndex = uint32_t;
class SHVkRenderpass
{

View File

@ -5,9 +5,13 @@
namespace SHADE
{
/*-----------------------------------------------------------------------*/
/* TYPE DEFINTIIONS */
/*-----------------------------------------------------------------------*/
using SHQueueFamilyIndex = uint32_t;
using BindingAndSetHash = uint64_t;
using SetIndex = uint32_t;
using SHSubPassIndex = uint32_t;
}