Wrote remove resource for render graph (untested)

This commit is contained in:
Brandon Mak 2023-01-01 12:02:51 +08:00
parent 118ad33109
commit d7754e125d
14 changed files with 535 additions and 236 deletions

View File

@ -22,4 +22,5 @@ constexpr SHEventIdentifier SH_SCENE_INIT_PRE { 13 };
constexpr SHEventIdentifier SH_SCENE_INIT_POST { 14 }; constexpr SHEventIdentifier SH_SCENE_INIT_POST { 14 };
constexpr SHEventIdentifier SH_SCENE_EXIT_PRE { 15 }; constexpr SHEventIdentifier SH_SCENE_EXIT_PRE { 15 };
constexpr SHEventIdentifier SH_SCENE_EXIT_POST { 16 }; constexpr SHEventIdentifier SH_SCENE_EXIT_POST { 16 };
constexpr SHEventIdentifier SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT { 17 };

View File

@ -0,0 +1,14 @@
#pragma once
#include <string>
#include <initializer_list>
#include "ECS_Base/SHECSMacros.h"
namespace SHADE
{
struct SHLightEnableShadowEvent
{
//! We need to get the light component and initialize the relevant variables.
EntityID lightEntity;
};
}

View File

@ -195,7 +195,6 @@ namespace SHADE
renderGraph->AddResource("SSAO Blur", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR8Unorm); renderGraph->AddResource("SSAO Blur", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE }, windowDims.first, windowDims.second, vk::Format::eR8Unorm);
renderGraph->AddResource("Present", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT }, windowDims.first, windowDims.second); renderGraph->AddResource("Present", { SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT }, windowDims.first, windowDims.second);
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* MAIN NODE */ /* MAIN NODE */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@ -207,7 +206,6 @@ namespace SHADE
"Normals", "Normals",
"Albedo", "Albedo",
"Depth Buffer", "Depth Buffer",
"Scene",
"SSAO", "SSAO",
"SSAO Blur" "SSAO Blur"
}, },
@ -251,23 +249,46 @@ namespace SHADE
auto viewSamplerLayout = ssaoStorage->GetViewSamplerLayout(); auto viewSamplerLayout = ssaoStorage->GetViewSamplerLayout();
ssaoPass->ModifyWriteDescImageComputeResource(SHSSAO::DESC_SET_IMAGE_BINDING, { &viewSamplerLayout, 1 }); ssaoPass->ModifyWriteDescImageComputeResource(SHSSAO::DESC_SET_IMAGE_BINDING, { &viewSamplerLayout, 1 });
ssaoPass->SetRenderer (worldRenderer); ssaoPass->SetRenderer(worldRenderer);
// Add another pass to blur SSAO // Add another pass to blur SSAO
Handle<SHRenderGraphNodeCompute> ssaoBlurPass = gBufferNode->AddNodeCompute("SSAO Blur Step", ssaoBlurShader, { "SSAO", "SSAO Blur" }); Handle<SHRenderGraphNodeCompute> ssaoBlurPass = gBufferNode->AddNodeCompute("SSAO Blur Step", ssaoBlurShader, { "SSAO", "SSAO Blur" });
/*-----------------------------------------------------------------------*/
/* SHADOW MAP PASS */
/*-----------------------------------------------------------------------*/
// Shadow map pass will have no resources bound at first. Lighting system will add resources to the node.
// It will initially also not have any subpasses since they will be added for each light that casts shadows.
//auto shadowMapPass = renderGraph->AddNode("Shadow Map Pass", {}, {});
/*-----------------------------------------------------------------------*/
/* DEFERRED COMPOSITE NODE */
/*-----------------------------------------------------------------------*/
// This pass will facilitate both lighting and shadows in 1 single pass.
auto deferredCompositeNode = renderGraph->AddNode("Deferred Comp Pass",
{
"Position",
"Light Layer Indices",
"Normals",
"Albedo",
"Scene",
"SSAO Blur"
},
{"G-Buffer"});
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* DEFERRED COMPOSITE SUBPASS INIT */ /* DEFERRED COMPOSITE SUBPASS INIT */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
gBufferNode->AddNodeCompute("Deferred Composite", deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Scene" }); deferredCompositeNode->AddNodeCompute("Deferred Composite", deferredCompositeShader, { "Position", "Normals", "Albedo", "Light Layer Indices", "SSAO Blur", "Scene" });
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* DEBUG DRAW PASS INIT */ /* DEBUG DRAW PASS INIT */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
// Set up Debug Draw Passes // Set up Debug Draw Passes
// - Depth Tested // - Depth Tested
auto debugDrawNodeDepth = renderGraph->AddNode("Debug Draw with Depth", { "Scene", "Depth Buffer" }, {"G-Buffer"}); auto debugDrawNodeDepth = renderGraph->AddNode("Debug Draw with Depth", { "Scene", "Depth Buffer" }, {"G-Buffer", "Deferred Comp Pass"});
auto debugDrawDepthSubpass = debugDrawNodeDepth->AddSubpass("Debug Draw with Depth", worldViewport, worldRenderer); auto debugDrawDepthSubpass = debugDrawNodeDepth->AddSubpass("Debug Draw with Depth", worldViewport, worldRenderer);
debugDrawDepthSubpass->AddColorOutput("Scene"); debugDrawDepthSubpass->AddColorOutput("Scene");
debugDrawDepthSubpass->AddDepthOutput("Depth Buffer"); debugDrawDepthSubpass->AddDepthOutput("Depth Buffer");
@ -279,7 +300,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* SCREEN SPACE PASS */ /* SCREEN SPACE PASS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
auto screenSpaceNode = renderGraph->AddNode("Screen Space Pass", { "Scene", "Entity ID" }, {"G-Buffer", "Debug Draw" }); auto screenSpaceNode = renderGraph->AddNode("Screen Space Pass", { "Scene", "Entity ID" }, {"Deferred Comp Pass", "G-Buffer", "Debug Draw" });
auto uiSubpass = screenSpaceNode->AddSubpass("UI", worldViewport, screenRenderer); auto uiSubpass = screenSpaceNode->AddSubpass("UI", worldViewport, screenRenderer);
uiSubpass->AddColorOutput("Scene"); uiSubpass->AddColorOutput("Scene");
uiSubpass->AddColorOutput("Entity ID"); uiSubpass->AddColorOutput("Entity ID");
@ -410,6 +431,16 @@ namespace SHADE
} }
void SHGraphicsSystem::InitEvents(void) noexcept
{
std::shared_ptr<SHEventReceiverSpec<SHGraphicsSystem>> thisReceiver
{
std::make_shared<SHEventReceiverSpec<SHGraphicsSystem>>(this, &SHGraphicsSystem::ReceiveLightEnableShadowEvent)
};
ReceiverPtr receiver = std::dynamic_pointer_cast<SHEventReceiver>(thisReceiver);
SHEventManager::SubscribeTo(SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT, receiver);
}
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
/* Constructor/Destructors */ /* Constructor/Destructors */
/*---------------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------------*/
@ -694,6 +725,18 @@ namespace SHADE
renderers.erase(iter); renderers.erase(iter);
} }
SHEventHandle SHGraphicsSystem::ReceiveLightEnableShadowEvent(SHEventPtr event) noexcept
{
// Add the shadow map resource to the graph
// link resource to node. This means linking the resource and regenerating the node's renderpass and framebuffer.
// Add a subpass to render to that shadow map
//renderGraph->GetNode ();
return event->handle;
}
Handle<SHMaterial> SHGraphicsSystem::AddMaterial(Handle<SHVkShaderModule> vertShader, Handle<SHVkShaderModule> fragShader, Handle<SHSubpass> subpass) Handle<SHMaterial> SHGraphicsSystem::AddMaterial(Handle<SHVkShaderModule> vertShader, Handle<SHVkShaderModule> fragShader, Handle<SHSubpass> subpass)
{ {
// Retrieve pipeline from pipeline storage or create if unavailable // Retrieve pipeline from pipeline storage or create if unavailable

View File

@ -35,6 +35,7 @@ of DigiPen Institute of Technology is prohibited.
#include "Camera/SHCameraDirector.h" #include "Camera/SHCameraDirector.h"
#include "Graphics/MiddleEnd/TextRendering/SHFontLibrary.h" #include "Graphics/MiddleEnd/TextRendering/SHFontLibrary.h"
#include "Graphics/MiddleEnd/Interface/SHRenderer.h" #include "Graphics/MiddleEnd/Interface/SHRenderer.h"
#include "Graphics/Events/SHGraphicsEvents.h"
namespace SHADE namespace SHADE
{ {
@ -102,10 +103,7 @@ namespace SHADE
void InitMiddleEnd (void) noexcept; void InitMiddleEnd (void) noexcept;
void InitSubsystems (void) noexcept; void InitSubsystems (void) noexcept;
void InitBuiltInResources (void); void InitBuiltInResources (void);
void InitEvents (void) noexcept;
#ifdef SHEDITOR
void InitEditorRenderGraph (void) noexcept;
#endif
public: public:
class SH_API BeginRoutine final : public SHSystemRoutine class SH_API BeginRoutine final : public SHSystemRoutine
@ -176,6 +174,10 @@ namespace SHADE
Handle<SHRenderer> AddRenderer(SHRenderer::PROJECTION_TYPE projectionType); Handle<SHRenderer> AddRenderer(SHRenderer::PROJECTION_TYPE projectionType);
void RemoveRenderer(Handle<SHRenderer> renderer); void RemoveRenderer(Handle<SHRenderer> renderer);
/*-----------------------------------------------------------------------*/
/* Light functions */
/*-----------------------------------------------------------------------*/
SHEventHandle ReceiveLightEnableShadowEvent (SHEventPtr event) noexcept;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Material Functions */ /* Material Functions */

View File

@ -1,5 +1,7 @@
#include "SHpch.h" #include "SHpch.h"
#include "SHLightComponent.h" #include "SHLightComponent.h"
#include "Graphics/Events/SHGraphicsEvents.h"
#include "Events/SHEventManager.hpp"
namespace SHADE namespace SHADE
{ {
@ -104,6 +106,21 @@ namespace SHADE
//MakeDirty(); //MakeDirty();
} }
void SHLightComponent::SetEnableShadow(bool flag) noexcept
{
lightData.castShadows = flag;
// If the flag is true
if (flag && lightData.shadowMapIndex == SHLightData::INVALID_SHADOW_MAP_INDEX)
{
// Create new event and broadcast it
SHLightEnableShadowEvent newEvent;
newEvent.lightEntity = GetEID();
SHEventManager::BroadcastEvent<SHLightEnableShadowEvent>(newEvent, SH_GRAPHICS_LIGHT_ENABLE_SHADOW_EVENT);
}
}
SHLightData const& SHLightComponent::GetLightData(void) const noexcept SHLightData const& SHLightComponent::GetLightData(void) const noexcept
{ {
return lightData; return lightData;

View File

@ -25,7 +25,6 @@ namespace SHADE
////! If the light's data is already in the buffers, this will be set to true. ////! If the light's data is already in the buffers, this will be set to true.
//bool bound; //bool bound;
public: public:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* LIFECYCLE FUNCTIONS */ /* LIFECYCLE FUNCTIONS */
@ -49,6 +48,7 @@ namespace SHADE
//void Unbind (void) noexcept; //void Unbind (void) noexcept;
//void SetBound (uint32_t inIndexInBuffer) noexcept; //void SetBound (uint32_t inIndexInBuffer) noexcept;
void SetStrength (float value) noexcept; // serialized void SetStrength (float value) noexcept; // serialized
void SetEnableShadow (bool flag) noexcept;
SHLightData const& GetLightData (void) const noexcept; SHLightData const& GetLightData (void) const noexcept;
@ -59,7 +59,7 @@ namespace SHADE
uint32_t const& GetCullingMask (void) const noexcept; // serialized uint32_t const& GetCullingMask (void) const noexcept; // serialized
//bool IsDirty (void) const noexcept; //bool IsDirty (void) const noexcept;
//bool GetBound (void) const noexcept; //bool GetBound (void) const noexcept;
uint32_t GetIndexInBuffer (void) const noexcept; //uint32_t GetIndexInBuffer (void) const noexcept;
float GetStrength (void) const noexcept; float GetStrength (void) const noexcept;
RTTR_ENABLE() RTTR_ENABLE()
}; };

View File

@ -16,6 +16,12 @@ namespace SHADE
// Diffuse color set to 1 // Diffuse color set to 1
color = SHVec4::One; color = SHVec4::One;
// light will default not cast shadows
castShadows = false;
// shadow map index is invalid.
shadowMapIndex = INVALID_SHADOW_MAP_INDEX;
} }
} }

View File

@ -26,6 +26,8 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
struct SHLightData struct SHLightData
{ {
static constexpr uint32_t INVALID_SHADOW_MAP_INDEX = std::numeric_limits<uint32_t>::max();
//! position of the light //! position of the light
SHVec3 position; SHVec3 position;
@ -46,6 +48,13 @@ namespace SHADE
//! Strength of the light //! Strength of the light
float strength; float strength;
//! Whether or not the light will cast a shadow. More technically, whether or
//! not the light will result in the addition of a depth map into the render graph
//! to be used for shadow mapping calculations.
bool castShadows;
//! Index of the shadow map when it gets placed in the descriptor array of textures (that are all shadow maps).
uint32_t shadowMapIndex;
void Reset (void) noexcept; void Reset (void) noexcept;
//! TODO: //! TODO:

View File

@ -68,6 +68,56 @@ namespace SHADE
renderGraphStorage->graphResources->try_emplace(resourceName, resource); renderGraphStorage->graphResources->try_emplace(resourceName, resource);
} }
void SHRenderGraph::RemoveResource(std::string resourceName) noexcept
{
// 1. Check if nodes are using said attachment and remove if they are
// - Check subpasses while at it and remove as well if used as attachment
// 2. Regenerate graph
// - Delete all vulkan objects first as well and clear the necessary containers
if (!renderGraphStorage->graphResources->contains(resourceName))
return;
renderGraphStorage->logicalDevice->WaitIdle();
uint64_t handleID = renderGraphStorage->graphResources->at (resourceName).GetId().Raw;
// Record nodes that will be affected
std::vector<uint32_t> affectedNodes{};
// Detach resource from all nodes if applicable
for (uint32_t i = 0; i < nodes.size(); ++i)
{
if (nodes[i]->DetachResource(resourceName, handleID))
affectedNodes.emplace_back(i);
}
// Up to this point the nodes and subpasses should have no trace of the deleted resource. Attachment
// descriptions and subpass indices should also have been reconfigured at this point. However, this
// means that the subpass descriptions and subpass dependencies need to be reconfigured.
// configure subpass dependencies and descriptions.
for (auto& affectedNode : affectedNodes)
nodes[affectedNode]->ConfigureSubpasses();
for (auto& affectedNode : affectedNodes)
nodes[affectedNode]->CreateRenderpass();
for (auto& affectedNode : affectedNodes)
nodes[affectedNode]->CreateFramebuffer();
/*
* IMPORTANT NOTES
*
* This remove resource function would be more complete if it accounted for renderpass compatibility by
* recreating the graphics pipelines stored in render graph nodes. However due to time constraints, this is left out. As such,
* pipelines that are recreated with a certain renderpass and subpass will assumed to be compatible when used in different subpasses.
*
* This function also recreates renderpasses and framebuffers so it does not account for removing of resources that are used in nodes whose
* renderpasses and framebuffers are used externally in systems like Editor with ImGui.
*/
}
void SHRenderGraph::LinkNonOwningResource(Handle<SHRenderGraph> resourceOrigin, std::string resourceName) noexcept void SHRenderGraph::LinkNonOwningResource(Handle<SHRenderGraph> resourceOrigin, std::string resourceName) noexcept
{ {
// resource to link // resource to link
@ -236,140 +286,12 @@ namespace SHADE
*/ */
/***************************************************************************/ /***************************************************************************/
void SHRenderGraph::ConfigureSubpasses(void) noexcept void SHRenderGraph::ConfigureAllSubpasses(void) noexcept
{ {
// For all nodes // For all nodes
for (auto& node : nodes) for (auto& node : nodes)
{ {
// Create subpass description and dependencies based on number of subpasses node->ConfigureSubpasses();
node->spDescs.resize(node->subpasses.size());
node->spDeps.resize(node->subpasses.size());
// Now we want to loop through all attachments in all subpasses in the node and query
// the resources being used. For each resource we want to query the type and record it
// in bit fields (1 bit for each subpass).
uint32_t colorRead = 0, colorWrite = 0, depthRead = 0, depthWrite = 0, inputDependencies = 0;
uint32_t i = 0;
// For all subpasses (see above description about bit field for this).
for (auto& subpass : node->subpasses)
{
// Configure subpass description
auto& desc = node->spDescs[i];
desc.pColorAttachments = subpass->colorReferences.data();
desc.colorAttachmentCount = static_cast<uint32_t>(subpass->colorReferences.size());
desc.pInputAttachments = subpass->inputReferences.data();
desc.inputAttachmentCount = static_cast<uint32_t>(subpass->inputReferences.size());
desc.pDepthStencilAttachment = subpass->depthReferences.data();
desc.pipelineBindPoint = vk::PipelineBindPoint::eGraphics; // TODO: Just graphics for now. See if its possible to allow user defined params.
// Get reference to subpass description
auto& dep = node->spDeps[i];
// Configure subpass index for dependencies
dep.srcSubpass = (i == 0) ? VK_SUBPASS_EXTERNAL : i - 1;
dep.dstSubpass = i;
// First we want to see if the subpass has color, depth or input attachments and set bit field accordingly
if (subpass->colorReferences.size())
{
colorRead |= (1 << i);
colorWrite |= (1 << i);
}
// Same thing for depth
if (subpass->depthReferences.size())
{
depthRead |= (1 << i);
depthWrite |= (1 << i);
}
if (subpass->inputReferences.size())
inputDependencies |= (1 << i);
// Input attachments can be any type, so we need to check what type it is
for (auto& inputAtt : subpass->inputReferences)
{
auto resource = node->attResources[inputAtt.attachment];
if (resource->resourceTypeFlags & static_cast<uint32_t>(SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT))
{
if (resource->resourceTypeFlags & static_cast<uint32_t>(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR) ||
resource->resourceTypeFlags & static_cast<uint32_t>(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT))
colorRead |= (1 << i);
else if (resource->resourceTypeFlags & static_cast<uint32_t>(SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL))
depthRead |= (1 << i);
}
else
{
SHLOG_ERROR("While configuring subpass, an input reference was detected but the resource to be used is not marked as SH_ATT_DESC_TYPE_FLAGS::INPUT. ");
}
}
++i;
}
// Loop through all subpasses again but this time we use the bit field to initialize
// the dependencies.
for (i = 0; i < node->subpasses.size(); ++i)
{
vk::PipelineStageFlags srcStage;
vk::PipelineStageFlags dstStage;
vk::AccessFlags srcAccess;
vk::AccessFlags dstAccess;
auto& dep = node->spDeps[i];
if (colorRead & (1 << i))
{
srcStage |= vk::PipelineStageFlagBits::eColorAttachmentOutput;
dstStage |= vk::PipelineStageFlagBits::eColorAttachmentOutput;
srcAccess |= vk::AccessFlagBits::eColorAttachmentWrite;
dstAccess |= vk::AccessFlagBits::eColorAttachmentRead;
}
if (colorWrite & (1 << i))
{
srcStage |= vk::PipelineStageFlagBits::eColorAttachmentOutput;
dstStage |= vk::PipelineStageFlagBits::eColorAttachmentOutput;
srcAccess |= vk::AccessFlagBits::eColorAttachmentWrite;
dstAccess |= vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eColorAttachmentRead;
}
if (depthRead & (1 << i))
{
srcStage |= vk::PipelineStageFlagBits::eEarlyFragmentTests;
dstStage |= vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests;
srcAccess |= vk::AccessFlagBits::eDepthStencilAttachmentWrite;
dstAccess |= vk::AccessFlagBits::eDepthStencilAttachmentRead;
}
if (depthWrite & (1 << i))
{
srcStage |= vk::PipelineStageFlagBits::eEarlyFragmentTests;
dstStage |= vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests;
srcAccess |= vk::AccessFlagBits::eDepthStencilAttachmentWrite;
dstAccess |= vk::AccessFlagBits::eDepthStencilAttachmentRead | vk::AccessFlagBits::eDepthStencilAttachmentWrite;
}
if (inputDependencies & (1 << i))
{
dstStage |= vk::PipelineStageFlagBits::eFragmentShader;
dstAccess |= vk::AccessFlagBits::eInputAttachmentRead;
}
//// If subpass of first renderpass, stage flag should be bottom of pipe
//if (&node == &nodes.front() && i == 0)
// srcStage = vk::PipelineStageFlagBits::eBottomOfPipe;
//// If subpass of last renderpass, stage flag should be bottom of pipe
//if (&node == &nodes.back() && i == node->subpasses.size() - 1)
// dstStage = vk::PipelineStageFlagBits::eTopOfPipe;
dep.srcStageMask = srcStage;
dep.dstStageMask = dstStage;
dep.srcAccessMask = srcAccess;
dep.dstAccessMask = dstAccess;
dep.srcStageMask = srcStage;
// initialize input descriptors
node->subpasses[i]->CreateInputDescriptors();
}
} }
} }
@ -604,12 +526,17 @@ namespace SHADE
{ {
CheckForNodeComputes(); CheckForNodeComputes();
ConfigureAttachmentDescriptions(); ConfigureAttachmentDescriptions();
ConfigureSubpasses(); ConfigureAllSubpasses();
ConfigureRenderpasses(); ConfigureRenderpasses();
ConfigureFramebuffers(); ConfigureFramebuffers();
ConfigureSubSystems(); ConfigureSubSystems();
} }
void SHRenderGraph::Regenerate(void) noexcept
{
}
/***************************************************************************/ /***************************************************************************/
/*! /*!

View File

@ -51,7 +51,7 @@ namespace SHADE
/* PRIVATE MEMBER FUNCTIONS */ /* PRIVATE MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
void ConfigureAttachmentDescriptions (void) noexcept; void ConfigureAttachmentDescriptions (void) noexcept;
void ConfigureSubpasses (void) noexcept; void ConfigureAllSubpasses (void) noexcept;
void ConfigureRenderpasses (void) noexcept; void ConfigureRenderpasses (void) noexcept;
void ConfigureSubSystems (void) noexcept; void ConfigureSubSystems (void) noexcept;
void ConfigureFramebuffers (void) noexcept; void ConfigureFramebuffers (void) noexcept;
@ -89,13 +89,52 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* PUBLIC MEMBER FUNCTIONS */ /* PUBLIC MEMBER FUNCTIONS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
void Init (std::string graphName, Handle<SHVkLogicalDevice> logicalDevice, Handle<SHVkSwapchain> swapchain, SHResourceHub* resourceHub, std::vector<Handle<SHVkCommandPool>>& cmdPools) noexcept; void Init
void AddResource(std::string resourceName, std::initializer_list<SH_RENDER_GRAPH_RESOURCE_FLAGS> typeFlags, uint32_t w = static_cast<uint32_t>(-1), uint32_t h = static_cast<uint32_t>(-1), vk::Format format = vk::Format::eB8G8R8A8Unorm, uint8_t levels = 1, vk::ImageUsageFlagBits usageFlags = {}, vk::ImageCreateFlagBits createFlags = {}); (
void LinkNonOwningResource (Handle<SHRenderGraph> resourceOrigin, std::string resourceName) noexcept; std::string graphName,
Handle<SHRenderGraphNode> AddNode (std::string nodeName, std::initializer_list<ResourceInstruction> resourceInstruction, std::initializer_list<std::string> predecessorNodes) noexcept; Handle<SHVkLogicalDevice> logicalDevice,
void AddRenderToSwapchainNode (std::string toSwapchainResource, std::string swapchainResource, std::initializer_list<std::string> predecessorNodes, std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> shaderModules) noexcept; Handle<SHVkSwapchain> swapchain, SHResourceHub* resourceHub,
std::vector<Handle<SHVkCommandPool>>& cmdPools
) noexcept;
void AddResource
(
std::string resourceName,
std::initializer_list<SH_RENDER_GRAPH_RESOURCE_FLAGS> typeFlags,
uint32_t w = static_cast<uint32_t>(-1),
uint32_t h = static_cast<uint32_t>(-1),
vk::Format format = vk::Format::eB8G8R8A8Unorm,
uint8_t levels = 1,
vk::ImageUsageFlagBits usageFlags = {},
vk::ImageCreateFlagBits createFlags = {}
);
void RemoveResource (std::string resourceName) noexcept;
void LinkNonOwningResource
(
Handle<SHRenderGraph> resourceOrigin,
std::string resourceName
) noexcept;
Handle<SHRenderGraphNode> AddNode
(
std::string nodeName,
std::initializer_list<ResourceInstruction> resourceInstruction,
std::initializer_list<std::string> predecessorNodes
) noexcept;
void AddRenderToSwapchainNode
(
std::string toSwapchainResource,
std::string swapchainResource,
std::initializer_list<std::string> predecessorNodes,
std::pair<Handle<SHVkShaderModule>,
Handle<SHVkShaderModule>> shaderModules
) noexcept;
void Generate (void) noexcept; void Generate (void) noexcept;
void Regenerate (void) noexcept;
void CheckForNodeComputes (void) noexcept; void CheckForNodeComputes (void) noexcept;
void Execute (uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) noexcept; void Execute (uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool) noexcept;
void Begin (uint32_t frameIndex) noexcept; void Begin (uint32_t frameIndex) noexcept;

View File

@ -26,6 +26,12 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
void SHRenderGraphNode::CreateRenderpass(void) noexcept void SHRenderGraphNode::CreateRenderpass(void) noexcept
{ {
if (renderpass)
{
if (renderpass)
renderpass.Free();
}
renderpass = graphStorage->logicalDevice->CreateRenderpass(attachmentDescriptions, spDescs, spDeps); renderpass = graphStorage->logicalDevice->CreateRenderpass(attachmentDescriptions, spDescs, spDeps);
SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eRenderPass, renderpass->GetVkRenderpass(), "[RenderPass] " + name); SET_VK_OBJ_NAME(graphStorage->logicalDevice, vk::ObjectType::eRenderPass, renderpass->GetVkRenderpass(), "[RenderPass] " + name);
} }
@ -40,6 +46,15 @@ namespace SHADE
/***************************************************************************/ /***************************************************************************/
void SHRenderGraphNode::CreateFramebuffer(void) noexcept void SHRenderGraphNode::CreateFramebuffer(void) noexcept
{ {
if (!framebuffers.empty())
{
for (auto fbo : framebuffers)
{
if (fbo)
fbo.Free();
}
}
for (uint32_t i = 0; i < framebuffers.size(); ++i) for (uint32_t i = 0; i < framebuffers.size(); ++i)
{ {
std::vector<Handle<SHVkImageView>> imageViews(attResources.size()); std::vector<Handle<SHVkImageView>> imageViews(attResources.size());
@ -100,6 +115,139 @@ namespace SHADE
} }
} }
void SHRenderGraphNode::ConfigureSubpasses(void) noexcept
{
// Create subpass description and dependencies based on number of subpasses
spDescs.resize(subpasses.size());
spDeps.resize(subpasses.size());
// Now we want to loop through all attachments in all subpasses in the node and query
// the resources being used. For each resource we want to query the type and record it
// in bit fields (1 bit for each subpass).
uint32_t colorRead = 0, colorWrite = 0, depthRead = 0, depthWrite = 0, inputDependencies = 0;
uint32_t i = 0;
// For all subpasses (see above description about bit field for this).
for (auto& subpass : subpasses)
{
// Configure subpass description
auto& desc = spDescs[i];
desc.pColorAttachments = subpass->colorReferences.data();
desc.colorAttachmentCount = static_cast<uint32_t>(subpass->colorReferences.size());
desc.pInputAttachments = subpass->inputReferences.data();
desc.inputAttachmentCount = static_cast<uint32_t>(subpass->inputReferences.size());
desc.pDepthStencilAttachment = subpass->depthReferences.data();
desc.pipelineBindPoint = vk::PipelineBindPoint::eGraphics; // TODO: Just graphics for now. See if its possible to allow user defined params.
// Get reference to subpass description
auto& dep = spDeps[i];
// Configure subpass index for dependencies
dep.srcSubpass = (i == 0) ? VK_SUBPASS_EXTERNAL : i - 1;
dep.dstSubpass = i;
// First we want to see if the subpass has color, depth or input attachments and set bit field accordingly
if (subpass->colorReferences.size())
{
colorRead |= (1 << i);
colorWrite |= (1 << i);
}
// Same thing for depth
if (subpass->depthReferences.size())
{
depthRead |= (1 << i);
depthWrite |= (1 << i);
}
if (subpass->inputReferences.size())
inputDependencies |= (1 << i);
// Input attachments can be any type, so we need to check what type it is
for (auto& inputAtt : subpass->inputReferences)
{
auto resource = attResources[inputAtt.attachment];
if (resource->resourceTypeFlags & static_cast<uint32_t>(SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT))
{
if (resource->resourceTypeFlags & static_cast<uint32_t>(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR) ||
resource->resourceTypeFlags & static_cast<uint32_t>(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT))
colorRead |= (1 << i);
else if (resource->resourceTypeFlags & static_cast<uint32_t>(SH_RENDER_GRAPH_RESOURCE_FLAGS::DEPTH_STENCIL))
depthRead |= (1 << i);
}
else
{
SHLOG_ERROR("While configuring subpass, an input reference was detected but the resource to be used is not marked as SH_ATT_DESC_TYPE_FLAGS::INPUT. ");
}
}
++i;
}
// Loop through all subpasses again but this time we use the bit field to initialize
// the dependencies.
for (i = 0; i < subpasses.size(); ++i)
{
vk::PipelineStageFlags srcStage;
vk::PipelineStageFlags dstStage;
vk::AccessFlags srcAccess;
vk::AccessFlags dstAccess;
auto& dep = spDeps[i];
if (colorRead & (1 << i))
{
srcStage |= vk::PipelineStageFlagBits::eColorAttachmentOutput;
dstStage |= vk::PipelineStageFlagBits::eColorAttachmentOutput;
srcAccess |= vk::AccessFlagBits::eColorAttachmentWrite;
dstAccess |= vk::AccessFlagBits::eColorAttachmentRead;
}
if (colorWrite & (1 << i))
{
srcStage |= vk::PipelineStageFlagBits::eColorAttachmentOutput;
dstStage |= vk::PipelineStageFlagBits::eColorAttachmentOutput;
srcAccess |= vk::AccessFlagBits::eColorAttachmentWrite;
dstAccess |= vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eColorAttachmentRead;
}
if (depthRead & (1 << i))
{
srcStage |= vk::PipelineStageFlagBits::eEarlyFragmentTests;
dstStage |= vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests;
srcAccess |= vk::AccessFlagBits::eDepthStencilAttachmentWrite;
dstAccess |= vk::AccessFlagBits::eDepthStencilAttachmentRead;
}
if (depthWrite & (1 << i))
{
srcStage |= vk::PipelineStageFlagBits::eEarlyFragmentTests;
dstStage |= vk::PipelineStageFlagBits::eEarlyFragmentTests | vk::PipelineStageFlagBits::eLateFragmentTests;
srcAccess |= vk::AccessFlagBits::eDepthStencilAttachmentWrite;
dstAccess |= vk::AccessFlagBits::eDepthStencilAttachmentRead | vk::AccessFlagBits::eDepthStencilAttachmentWrite;
}
if (inputDependencies & (1 << i))
{
dstStage |= vk::PipelineStageFlagBits::eFragmentShader;
dstAccess |= vk::AccessFlagBits::eInputAttachmentRead;
}
//// If subpass of first renderpass, stage flag should be bottom of pipe
//if (&node == &nodes.front() && i == 0)
// srcStage = vk::PipelineStageFlagBits::eBottomOfPipe;
//// If subpass of last renderpass, stage flag should be bottom of pipe
//if (&node == &nodes.back() && i == subpasses.size() - 1)
// dstStage = vk::PipelineStageFlagBits::eTopOfPipe;
dep.srcStageMask = srcStage;
dep.dstStageMask = dstStage;
dep.srcAccessMask = srcAccess;
dep.dstAccessMask = dstAccess;
dep.srcStageMask = srcStage;
// initialize input descriptors
subpasses[i]->CreateInputDescriptors();
}
}
/***************************************************************************/ /***************************************************************************/
/*! /*!
@ -335,6 +483,58 @@ namespace SHADE
} }
} }
/***************************************************************************/
/*!
\brief
For detaching attachments from the node. The node would need to be
rebuilt but it won't be done in this function. This function just removes
any footprint of the resource in the class.
\param resourceHandleID
The handle ID of the resource.
*/
/***************************************************************************/
bool SHRenderGraphNode::DetachResource(std::string const& resourceName, uint64_t resourceHandleID) noexcept
{
if (resourceAttachmentMapping->contains(resourceHandleID))
{
// Get attachment index in the node's attachment container
auto index = resourceAttachmentMapping->at(resourceHandleID);
// remove attachment from the list of attachments
attResources.erase (attResources.begin() + index);
// remove attachment reference
attachmentDescriptions.erase (attachmentDescriptions.begin() + index);
// Remove footprint of attachment from all subpasses as well
for (auto it = subpasses.begin(); it != subpasses.end(); ++it)
{
// attempt to detach resource from subpass
(*it)->DetachResource(resourceName, index);
// If the subpass ends up having no attachments after, erase it from the node
if ((*it)->HasNoAttachments())
{
// erase from indexing
subpassIndexing.erase((*it)->GetName());
// erase from container of subpasses.
it = subpasses.erase(it);
}
}
// give existing subpasses new indices
for (uint32_t i = 0; i < subpasses.size(); ++i)
subpasses[i]->SetIndex(i);
return true;
}
return false;
}
void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept void SHRenderGraphNode::Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept
{ {
uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0; uint32_t framebufferIndex = (framebuffers.size() > 1) ? frameIndex : 0;

View File

@ -55,7 +55,7 @@ namespace SHADE
//! Vector of subpasses //! Vector of subpasses
std::vector<Handle<SHSubpass>> subpasses; std::vector<Handle<SHSubpass>> subpasses;
//! Descriptions to pass to renderpass for renderpass creation. We want to keep this here because //! Descriptions to pass to renderpass for renderpass creation.
std::vector<vk::SubpassDescription> spDescs; std::vector<vk::SubpassDescription> spDescs;
//! Subpass dependencies for renderpass creation //! Subpass dependencies for renderpass creation
@ -92,6 +92,7 @@ namespace SHADE
void CreateRenderpass(void) noexcept; void CreateRenderpass(void) noexcept;
void CreateFramebuffer(void) noexcept; void CreateFramebuffer(void) noexcept;
void HandleResize (void) noexcept; void HandleResize (void) noexcept;
void ConfigureSubpasses (void) noexcept;
public: public:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@ -107,6 +108,7 @@ namespace SHADE
Handle<SHSubpass> AddSubpass(std::string subpassName, Handle<SHViewport> viewport, Handle<SHRenderer> renderer) noexcept; Handle<SHSubpass> AddSubpass(std::string subpassName, Handle<SHViewport> viewport, Handle<SHRenderer> renderer) noexcept;
Handle<SHRenderGraphNodeCompute> AddNodeCompute(std::string nodeName, Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings = {}, float numWorkGroupScale = 1.0f) noexcept; Handle<SHRenderGraphNodeCompute> AddNodeCompute(std::string nodeName, Handle<SHVkShaderModule> computeShaderModule, std::initializer_list<std::string> resources, std::unordered_set<BindingAndSetHash>&& dynamicBufferBindings = {}, float numWorkGroupScale = 1.0f) noexcept;
void AddDummySubpassIfNeeded (void) noexcept; void AddDummySubpassIfNeeded (void) noexcept;
bool DetachResource (std::string const& resourceName, uint64_t resourceHandleID) noexcept;
// TODO: RemoveSubpass() // TODO: RemoveSubpass()
void Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept; void Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;

View File

@ -68,7 +68,6 @@ namespace SHADE
, depthReferences{ std::move(rhs.depthReferences) } , depthReferences{ std::move(rhs.depthReferences) }
, inputReferences{ std::move(rhs.inputReferences) } , inputReferences{ std::move(rhs.inputReferences) }
, resourceAttachmentMapping{ rhs.resourceAttachmentMapping } , resourceAttachmentMapping{ rhs.resourceAttachmentMapping }
, descriptorSetLayout{ rhs.descriptorSetLayout }
, exteriorDrawCalls{ std::move(rhs.exteriorDrawCalls) } , exteriorDrawCalls{ std::move(rhs.exteriorDrawCalls) }
, graphStorage{ rhs.graphStorage } , graphStorage{ rhs.graphStorage }
, inputNames{ std::move(rhs.inputNames) } , inputNames{ std::move(rhs.inputNames) }
@ -105,7 +104,6 @@ namespace SHADE
depthReferences = std::move(rhs.depthReferences); depthReferences = std::move(rhs.depthReferences);
inputReferences = std::move(rhs.inputReferences); inputReferences = std::move(rhs.inputReferences);
resourceAttachmentMapping = std::move(rhs.resourceAttachmentMapping); resourceAttachmentMapping = std::move(rhs.resourceAttachmentMapping);
descriptorSetLayout = rhs.descriptorSetLayout;
exteriorDrawCalls = std::move(rhs.exteriorDrawCalls); exteriorDrawCalls = std::move(rhs.exteriorDrawCalls);
graphStorage = rhs.graphStorage; graphStorage = rhs.graphStorage;
inputNames = std::move(rhs.inputNames); inputNames = std::move(rhs.inputNames);
@ -253,6 +251,64 @@ namespace SHADE
} }
} }
/***************************************************************************/
/*!
\brief
Removes all footprints of a resource in the subpass.
\param resourceName
Name of resource.
\param attachmentIndex
index of attachment.
*/
/***************************************************************************/
void SHSubpass::DetachResource(std::string const& resourceName, uint32_t attachmentIndex) noexcept
{
for (uint32_t i = 0; i < colorReferences.size(); ++i)
{
if (colorReferences[i].attachment == attachmentIndex)
{
colorReferences.erase (colorReferences.begin() + i);
break;
}
}
for (uint32_t i = 0; i < depthReferences.size(); ++i)
{
if (depthReferences[i].attachment == attachmentIndex)
{
depthReferences.erase(depthReferences.begin() + i);
break;
}
}
for (uint32_t i = 0; i < inputReferences.size(); ++i)
{
if (inputReferences[i].attachment == attachmentIndex)
{
inputReferences.erase(inputReferences.begin() + i);
break;
}
}
for (uint32_t i = 0; i < inputNames.size(); ++i)
{
if (inputNames[i] == resourceName)
{
inputNames.erase(inputNames.begin() + i);
break;
}
}
}
bool SHSubpass::HasNoAttachments(void) const noexcept
{
return colorReferences.empty() && depthReferences.empty() && inputReferences.empty();
}
void SHSubpass::AddExteriorDrawCalls(ExteriorDrawCallFunction const& newDrawCall) noexcept void SHSubpass::AddExteriorDrawCalls(ExteriorDrawCallFunction const& newDrawCall) noexcept
{ {
exteriorDrawCalls.push_back(newDrawCall); exteriorDrawCalls.push_back(newDrawCall);
@ -269,6 +325,21 @@ namespace SHADE
if (inputNames.empty()) if (inputNames.empty())
return; return;
for (auto& set : inputImageDescriptorSets)
{
if (set)
set.Free();
}
if (inputDescriptorLayout)
inputDescriptorLayout.Free();
for (auto& sampler : inputSamplers)
{
if (sampler)
sampler.Free();
}
inputImageDescriptorSets.resize(SHGraphicsConstants::NUM_FRAME_BUFFERS); inputImageDescriptorSets.resize(SHGraphicsConstants::NUM_FRAME_BUFFERS);
std::vector<SHVkDescriptorSetLayout::Binding> bindings{}; std::vector<SHVkDescriptorSetLayout::Binding> bindings{};
@ -369,58 +440,23 @@ namespace SHADE
} }
} }
//void SHSubpass::InitComputeBarriers(void) noexcept /***************************************************************************/
//{ /*!
// std::unordered_set <uint64_t> handleBarriers{};
// // we will have swapchainNumImages vectors of vector of barriers \brief
// subpassComputeBarriers.resize(graphStorage->swapchain->GetNumImages()); This function is mainly used for the purposes of giving a subpass a new
index in the case another subpass in the node gets deleted, and subpasses
need to be re-indexed.
// for (auto sbCompute : subpassComputes) \param index
// { New index of the subpass.
// // for every resource the subpass compute is using
// for (auto resource : sbCompute->resources)
// {
// // Get the resource handle
// uint64_t resourceRaw = resource.GetId().Raw;
// // if the barrier is not registered */
// if (!handleBarriers.contains(resourceRaw)) /***************************************************************************/
// { void SHSubpass::SetIndex(uint32_t index) noexcept
// // If the resource is a swapchain image {
// bool isSwapchainImage = (resource->resourceTypeFlags & static_cast<uint32_t>(SH_ATT_DESC_TYPE_FLAGS::COLOR_PRESENT)); subpassIndex = index;
// for (uint32_t i = 0; i < graphStorage->swapchain->GetNumImages(); ++i) }
// {
// // if swapchain image, we want the index of the swapchain image, if not take base image
// uint32_t imageIndex = isSwapchainImage ? i : 0;
// // Prepare image barrier
// vk::ImageMemoryBarrier imageBarrier
// {
// .oldLayout = colorReferences[resourceAttachmentMapping->at(resource.GetId().Raw)].layout,
// .newLayout = vk::ImageLayout::eGeneral,
// .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
// .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
// .image = resource->GetImage(imageIndex)->GetVkImage(),
// .subresourceRange =
// {
// .aspectMask = resource->imageAspectFlags,
// .levelCount = resource->GetMipLevels(),
// .baseArrayLayer = 0,
// .layerCount = 1
// }
// };
// // push the barrier
// subpassComputeBarriers[i].push_back(imageBarrier);
// }
// // Image transition registered
// handleBarriers.emplace(resourceRaw);
// }
// }
// }
//}
/***************************************************************************/ /***************************************************************************/
/*! /*!

View File

@ -50,9 +50,6 @@ namespace SHADE
//! //!
Handle<SHSuperBatch> superBatch; Handle<SHSuperBatch> superBatch;
//! Descriptor set layout to hold attachments
Handle<SHVkDescriptorSetLayout> descriptorSetLayout;
//! Color attachments //! Color attachments
std::vector<vk::AttachmentReference> colorReferences; std::vector<vk::AttachmentReference> colorReferences;
@ -122,6 +119,8 @@ namespace SHADE
void Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept; void Execute(Handle<SHVkCommandBuffer> commandBuffer, Handle<SHVkDescriptorPool> descPool, uint32_t frameIndex) noexcept;
void HandleResize (void) noexcept; void HandleResize (void) noexcept;
void BindInputDescriptorSets (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t setIndex, uint32_t frameIndex) const noexcept; void BindInputDescriptorSets (Handle<SHVkCommandBuffer> cmdBuffer, uint32_t setIndex, uint32_t frameIndex) const noexcept;
void DetachResource (std::string const& resourceName, uint32_t attachmentIndex) noexcept;
bool HasNoAttachments (void) const noexcept;
void Init(SHResourceHub& resourceManager) noexcept; void Init(SHResourceHub& resourceManager) noexcept;
@ -132,6 +131,10 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* GETTERS AND SETTERS */ /* GETTERS AND SETTERS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
private:
void SetIndex (uint32_t index) noexcept;
public:
Handle<SHRenderGraphNode> const& GetParentNode(void) const noexcept; Handle<SHRenderGraphNode> const& GetParentNode(void) const noexcept;
SHSubPassIndex GetIndex() const noexcept; SHSubPassIndex GetIndex() const noexcept;
Handle<SHSuperBatch> GetSuperBatch(void) const noexcept; Handle<SHSuperBatch> GetSuperBatch(void) const noexcept;