Added constants for render graph node names

- Fleshed out event function to add resource and subpass to shadow map render graph node when shadow is turned on
- Added support for linking resources and subpasses to render graph at runtime
This commit is contained in:
Brandon Mak 2023-01-02 18:24:29 +08:00
parent 03becd8e47
commit 7f8dc2b647
9 changed files with 266 additions and 153 deletions

View File

@ -502,7 +502,7 @@ namespace SHADE
//auto const& renderers = gfxSystem->GetDefaultViewport()->GetRenderers(); //auto const& renderers = gfxSystem->GetDefaultViewport()->GetRenderers();
auto renderGraph = gfxSystem->GetRenderGraph(); auto renderGraph = gfxSystem->GetRenderGraph();
auto renderPass = renderGraph->GetNode("ImGui Node")->GetRenderpass(); auto renderPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::IMGUI_PASS.data())->GetRenderpass();
if(ImGui_ImplVulkan_Init(&initInfo, renderPass->GetVkRenderpass()) == false) if(ImGui_ImplVulkan_Init(&initInfo, renderPass->GetVkRenderpass()) == false)
{ {
@ -521,7 +521,7 @@ namespace SHADE
ImGui_ImplVulkan_DestroyFontUploadObjects(); ImGui_ImplVulkan_DestroyFontUploadObjects();
renderGraph->GetNode("ImGui Node")->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle<SHVkCommandBuffer> cmd, Handle<SHRenderer> renderer, uint32_t frameIndex) renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::IMGUI_PASS.data())->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle<SHVkCommandBuffer> cmd, Handle<SHRenderer> renderer, uint32_t frameIndex)
{ {
cmd->BeginLabeledSegment("ImGui Draw"); cmd->BeginLabeledSegment("ImGui Draw");
ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd->GetVkCommandBuffer()); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd->GetVkCommandBuffer());

View File

@ -101,7 +101,7 @@ namespace SHADE
// Register function for subpass // Register function for subpass
//auto const& RENDERERS = gfxSystem->GetDefaultViewport()->GetRenderers(); //auto const& RENDERERS = gfxSystem->GetDefaultViewport()->GetRenderers();
auto renderGraph = gfxSystem->GetRenderGraph(); auto renderGraph = gfxSystem->GetRenderGraph();
auto subPass = renderGraph->GetNode("Debug Draw")->GetSubpass("Debug Draw"); auto subPass = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW.data())->GetSubpass("Debug Draw");
subPass->AddExteriorDrawCalls([this](Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex) subPass->AddExteriorDrawCalls([this](Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex)
{ {
const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex(); const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex();
@ -125,7 +125,7 @@ namespace SHADE
} }
cmdBuffer->EndLabeledSegment(); cmdBuffer->EndLabeledSegment();
}); });
auto subPassWithDepth = renderGraph->GetNode("Debug Draw with Depth")->GetSubpass("Debug Draw with Depth"); auto subPassWithDepth = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW_DEPTH_PASS.data())->GetSubpass("Debug Draw with Depth");
subPassWithDepth->AddExteriorDrawCalls([this](Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex) subPassWithDepth->AddExteriorDrawCalls([this](Handle<SHVkCommandBuffer> cmdBuffer, Handle<SHRenderer> renderer, uint32_t frameIndex)
{ {
const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex(); const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex();

View File

@ -31,68 +31,79 @@ namespace SHADE
static constexpr uint32_t EDITOR = 0; static constexpr uint32_t EDITOR = 0;
}; };
//struct DescriptorSetIndex struct RenderGraphNodeNames
//{ {
// /***************************************************************************/ /***************************************************************************/
// /*! /*!
// \brief
// DescriptorSet Index for static global values like generic data, and
// texture samplers
// */
// /***************************************************************************/
// static constexpr uint32_t STATIC_GLOBALS = 0;
// /***************************************************************************/
// /*!
// \brief
// DescriptorSet Index for dynamic global values like lights.
// */
// /***************************************************************************/
// static constexpr uint32_t DYNAMIC_GLOBALS = 1;
// /***************************************************************************/
// /*!
// \brief
// DescriptorSet Index for high frequency changing global values like
// camera matrices.
// */
// /***************************************************************************/
// static constexpr uint32_t HIGH_FREQUENCY_GLOBALS = 2;
// /***************************************************************************/
// /*!
// \brief
// DescriptorSet Index for per-instance/material changing values.
// */
// /***************************************************************************/
// static constexpr uint32_t PER_INSTANCE = 3;
// /***************************************************************************/
// /*!
// \brief
// DescriptorSet Index for render graph resources. Unlike the sets from
// 1 to 3 and 6, this set index does not have hard coded bindings and is
// NOT part of the layouts included in the global data.
// */
// /***************************************************************************/
// static constexpr uint32_t RENDERGRAPH_RESOURCE = 4;
// /***************************************************************************/
// /*!
// \brief
// DescriptorSet Index for render graph node compute resources. For data
// that we wish to pass to compute shaders in the render graph, this is
// the set to use. Unlike the sets from 1 to 3 and 6, this set index does not have
// hard coded bindings and is NOT part of the layouts included in the global
// data.
// */
// /***************************************************************************/
// static constexpr uint32_t RENDERGRAPH_NODE_COMPUTE_RESOURCE = 5;
// /***************************************************************************/ \brief
// /*! Name of G-Buffer render graph node.
// \brief
// To store font data. */
// /***************************************************************************/
// */ static constexpr std::string_view GBUFFER_PASS = "G-Buffer";
// /***************************************************************************/
// static constexpr uint32_t FONT_DATA = 4; /***************************************************************************/
//}; /*!
\brief
Name of shadow map render graph node.
*/
/***************************************************************************/
static constexpr std::string_view SHADOW_MAP_PASS = "Shadow Map Pass";
/***************************************************************************/
/*!
\brief
Name of deferred composite render graph node.
*/
/***************************************************************************/
static constexpr std::string_view DEFERRED_COMPOSITE_PASS = "Deferred Comp Pass";
/***************************************************************************/
/*!
\brief
Name of Debug Draw with Depth render graph node.
*/
/***************************************************************************/
static constexpr std::string_view DEBUG_DRAW_DEPTH_PASS = "Debug Draw with Depth Pass";
/***************************************************************************/
/*!
\brief
Name of Debug Draw render graph node.
*/
/***************************************************************************/
static constexpr std::string_view DEBUG_DRAW = "Debug Draw Pass";
/***************************************************************************/
/*!
\brief
Name of screen space pass render graph node.
*/
/***************************************************************************/
static constexpr std::string_view SCREEN_SPACE_PASS = "Screen Space Pass";
/***************************************************************************/
/*!
\brief
Name of ImGui pass render graph node.
*/
/***************************************************************************/
static constexpr std::string_view IMGUI_PASS = "ImGui Pass";
};
struct DescriptorSetBindings struct DescriptorSetBindings
{ {

View File

@ -44,6 +44,8 @@ of DigiPen Institute of Technology is prohibited.
#include "Graphics/MiddleEnd/TextRendering/SHFreetypeInstance.h" #include "Graphics/MiddleEnd/TextRendering/SHFreetypeInstance.h"
#include "Graphics/MiddleEnd/TextRendering/SHTextRenderingSubSystem.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderingSubSystem.h"
#include "Graphics/MiddleEnd/GlobalData/SHGlobalDescriptorSets.h" #include "Graphics/MiddleEnd/GlobalData/SHGlobalDescriptorSets.h"
#include "Events/SHEvent.h"
#include "Graphics/MiddleEnd/Lights/SHLightComponent.h"
namespace SHADE namespace SHADE
{ {
@ -198,7 +200,8 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* MAIN NODE */ /* MAIN NODE */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
auto gBufferNode = renderGraph->AddNode("G-Buffer", auto gBufferNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data(),
//auto gBufferNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data()
{ {
"Position", "Position",
"Entity ID", "Entity ID",
@ -259,13 +262,13 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
// Shadow map pass will have no resources bound at first. Lighting system will add resources to the node. // 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. // 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", {}, {}); auto shadowMapPass = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data(), {}, {});
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* DEFERRED COMPOSITE NODE */ /* DEFERRED COMPOSITE NODE */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
// This pass will facilitate both lighting and shadows in 1 single pass. // This pass will facilitate both lighting and shadows in 1 single pass.
auto deferredCompositeNode = renderGraph->AddNode("Deferred Comp Pass", auto deferredCompositeNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::DEFERRED_COMPOSITE_PASS.data(),
{ {
"Position", "Position",
"Light Layer Indices", "Light Layer Indices",
@ -274,7 +277,7 @@ namespace SHADE
"Scene", "Scene",
"SSAO Blur" "SSAO Blur"
}, },
{"G-Buffer"}); { SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS .data()});
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* DEFERRED COMPOSITE SUBPASS INIT */ /* DEFERRED COMPOSITE SUBPASS INIT */
@ -286,19 +289,19 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
// 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", "Deferred Comp Pass"}); auto debugDrawNodeDepth = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW_DEPTH_PASS.data(), {"Scene", "Depth Buffer"}, {SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphNodeNames::DEFERRED_COMPOSITE_PASS.data()});
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");
// - No Depth Test // - No Depth Test
auto debugDrawNode = renderGraph->AddNode("Debug Draw", { "Scene" }, { "Debug Draw with Depth" }); auto debugDrawNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW.data(), {"Scene"}, {SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW_DEPTH_PASS.data()});
auto debugDrawSubpass = debugDrawNode->AddSubpass("Debug Draw", worldViewport, worldRenderer); auto debugDrawSubpass = debugDrawNode->AddSubpass("Debug Draw", worldViewport, worldRenderer);
debugDrawSubpass->AddColorOutput("Scene"); debugDrawSubpass->AddColorOutput("Scene");
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* SCREEN SPACE PASS */ /* SCREEN SPACE PASS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
auto screenSpaceNode = renderGraph->AddNode("Screen Space Pass", { "Scene", "Entity ID" }, {"Deferred Comp Pass", "G-Buffer", "Debug Draw" }); auto screenSpaceNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::SCREEN_SPACE_PASS.data(), {"Scene", "Entity ID"}, {SHGraphicsConstants::RenderGraphNodeNames::DEFERRED_COMPOSITE_PASS.data(), SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data(), SHGraphicsConstants::RenderGraphNodeNames::DEBUG_DRAW.data()});
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");
@ -313,16 +316,16 @@ namespace SHADE
#ifdef SHEDITOR #ifdef SHEDITOR
{ {
// Dummy Node to transition scene render graph resource // Dummy Node to transition scene render graph resource
auto dummyNode = renderGraph->AddNode("Dummy Pass", { "Scene" }, { "Screen Space Pass" }); auto dummyNode = renderGraph->AddNode("Dummy Pass", { "Scene" }, { SHGraphicsConstants::RenderGraphNodeNames::SCREEN_SPACE_PASS .data()});
auto dummySubpass = dummyNode->AddSubpass("Dummy Subpass", {}, {}); auto dummySubpass = dummyNode->AddSubpass("Dummy Subpass", {}, {});
dummySubpass->AddInput("Scene"); dummySubpass->AddInput("Scene");
auto imGuiNode = renderGraph->AddNode("ImGui Node", { "Present" }, {}); auto imGuiNode = renderGraph->AddNode(SHGraphicsConstants::RenderGraphNodeNames::IMGUI_PASS.data(), {"Present"}, {});
auto imGuiSubpass = imGuiNode->AddSubpass("ImGui Draw", {}, {}); auto imGuiSubpass = imGuiNode->AddSubpass("ImGui Draw", {}, {});
imGuiSubpass->AddColorOutput("Present"); imGuiSubpass->AddColorOutput("Present");
} }
#else #else
renderGraph->AddRenderToSwapchainNode("Scene", "Present", { "Screen Space Pass" }, { renderToSwapchainVS, renderToSwapchainFS }); renderGraph->AddRenderToSwapchainNode("Scene", "Present", { SHGraphicsConstants::RenderGraphNodeNames::SCREEN_SPACE_PASS .data()}, {renderToSwapchainVS, renderToSwapchainFS});
#endif #endif
@ -396,7 +399,7 @@ namespace SHADE
textRenderingSubSystem = resourceManager.Create<SHTextRenderingSubSystem>(); textRenderingSubSystem = resourceManager.Create<SHTextRenderingSubSystem>();
// initialize the text renderer // initialize the text renderer
auto uiNode = renderGraph->GetNode("Screen Space Pass"); auto uiNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::SCREEN_SPACE_PASS.data());
textRenderingSubSystem->Init(device, uiNode->GetRenderpass(), uiNode->GetSubpass("UI"), descPool, textVS, textFS); textRenderingSubSystem->Init(device, uiNode->GetRenderpass(), uiNode->GetSubpass("UI"), descPool, textVS, textFS);
SHGlobalDescriptorSets::SetLightingSubSystem(lightingSubSystem); SHGlobalDescriptorSets::SetLightingSubSystem(lightingSubSystem);
@ -423,7 +426,7 @@ namespace SHADE
defaultMaterial = AddMaterial defaultMaterial = AddMaterial
( (
defaultVertShader, defaultFragShader, defaultVertShader, defaultFragShader,
renderGraph->GetNode("G-Buffer")->GetSubpass("G-Buffer Write") renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data())->GetSubpass("G-Buffer Write")
); );
defaultMaterial->SetProperty("data.textureIndex", defaultTexture->TextureArrayIndex); defaultMaterial->SetProperty("data.textureIndex", defaultTexture->TextureArrayIndex);
} }
@ -724,16 +727,29 @@ namespace SHADE
renderers.erase(iter); renderers.erase(iter);
} }
SHEventHandle SHGraphicsSystem::ReceiveLightEnableShadowEvent(SHEventPtr event) noexcept SHEventHandle SHGraphicsSystem::ReceiveLightEnableShadowEvent(SHEventPtr eventPtr) noexcept
{ {
// we need to wait for the device to finish using the graph first
device->WaitIdle();
auto const& EVENT_DATA = reinterpret_cast<const SHEventSpec<SHLightEnableShadowEvent>*>(eventPtr.get())->data;
auto* lightComp = SHComponentManager::GetComponent<SHLightComponent>(EVENT_DATA->lightEntity);
std::string resourceName = "ShadowMap " + std::to_string(EVENT_DATA->lightEntity);
// Add the shadow map resource to the graph // Add the shadow map resource to the graph
renderGraph->AddResource(resourceName, {SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR, SH_RENDER_GRAPH_RESOURCE_FLAGS::INPUT, SH_RENDER_GRAPH_RESOURCE_FLAGS::STORAGE}, resizeWidth, resizeHeight, vk::Format::eD24UnormS8Uint);
// link resource to node. This means linking the resource and regenerating the node's renderpass and framebuffer. // link resource to node. This means linking the resource and regenerating the node's renderpass and framebuffer.
auto shadowMapNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data());
shadowMapNode->RuntimeLinkResource(resourceName);
// Add a subpass to render to that shadow map // Add a subpass to render to that shadow map
shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", worldViewport, worldRenderer);
//renderGraph->GetNode (); // regenerate the node
return event->handle; //shadowMapNode->RuntimeStandaloneRegenerate();
return eventPtr->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)
@ -1076,7 +1092,7 @@ namespace SHADE
Handle<SHRenderGraphNode> SHGraphicsSystem::GetPrimaryRenderpass() const noexcept Handle<SHRenderGraphNode> SHGraphicsSystem::GetPrimaryRenderpass() const noexcept
{ {
return renderGraph->GetNode(G_BUFFER_RENDER_GRAPH_NODE_NAME.data()); return renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data());
} }
Handle<SHVkPipeline> SHGraphicsSystem::GetDebugDrawPipeline(DebugDrawPipelineType type) const noexcept Handle<SHVkPipeline> SHGraphicsSystem::GetDebugDrawPipeline(DebugDrawPipelineType type) const noexcept

View File

@ -177,7 +177,7 @@ namespace SHADE
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Light functions */ /* Light functions */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
SHEventHandle ReceiveLightEnableShadowEvent (SHEventPtr event) noexcept; SHEventHandle ReceiveLightEnableShadowEvent (SHEventPtr eventPtr) noexcept;
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Material Functions */ /* Material Functions */
@ -405,10 +405,6 @@ namespace SHADE
SHWindow* GetWindow() noexcept { return window; } SHWindow* GetWindow() noexcept { return window; }
private: private:
/*-----------------------------------------------------------------------------*/
/* Constants */
/*-----------------------------------------------------------------------------*/
static constexpr std::string_view G_BUFFER_RENDER_GRAPH_NODE_NAME = "G-Buffer";
/*-----------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------*/
/* Data Members */ /* Data Members */

View File

@ -169,65 +169,7 @@ namespace SHADE
for (uint32_t i = 0; auto& node : nodes) for (uint32_t i = 0; auto& node : nodes)
{ {
// key is handle ID, value is final layout. node->StandaloneConfigureAttDesc(i == nodes.size() - 1);
std::unordered_map<uint32_t, vk::ImageLayout> resourceAttFinalLayouts;
if (!node->subpasses.empty())
{
// We first want to take all resources track their layout as undefined at the start of the node/renderpass
auto const resources = node->GetResources();
for (auto& resource : resources)
{
resource->GetInfoTracker()->TrackLayout(node, {}, vk::ImageLayout::eUndefined);
}
// attempt to get all final layouts for all resources
for (auto& subpass : node->subpasses)
{
for (auto& color : subpass->colorReferences)
{
// If final renderpass and attachment is a COLOR_PRESENT resource, make resource transition to present after last subpass
if (i == nodes.size() - 1 && (node->attResources[color.attachment]->resourceTypeFlags & static_cast<uint32_t>(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)))
resourceAttFinalLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR;
else
resourceAttFinalLayouts[color.attachment] = color.layout;
node->attResources[color.attachment]->infoTracker->TrackLayout(node, subpass, color.layout);
}
for (auto& depth : subpass->depthReferences)
{
resourceAttFinalLayouts[depth.attachment] = depth.layout;
node->attResources[depth.attachment]->infoTracker->TrackLayout(node, subpass, depth.layout);
}
for (auto& input : subpass->inputReferences)
{
resourceAttFinalLayouts[input.attachment] = input.layout;
node->attResources[input.attachment]->infoTracker->TrackLayout(node, subpass, input.layout);
}
}
for (uint32_t j = 0; j < node->attachmentDescriptions.size(); ++j)
{
auto& att = node->attachmentDescriptions[j];
auto& resource = node->attResources[j];
// If resource is from another render graph, use the final layout it had when it was last used in that graph. This is initialized in LinkNonOwningResource.
// We also want to load the attachment, not "don't care".
if (resource->resourceTypeFlags & SHUtilities::ConvertEnum(SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED) &&
renderGraphStorage->nonOwningResourceInitialLayouts.contains(resource.GetId().Raw))
{
att.initialLayout = renderGraphStorage->nonOwningResourceInitialLayouts.at(resource.GetId().Raw);
att.loadOp = vk::AttachmentLoadOp::eLoad;
att.stencilLoadOp = vk::AttachmentLoadOp::eLoad;
}
else
att.initialLayout = vk::ImageLayout::eUndefined;
att.finalLayout = resourceAttFinalLayouts[j];
resource->GetInfoTracker()->TrackLayout(node, {}, att.finalLayout);
}
}
++i; ++i;
} }

View File

@ -164,7 +164,14 @@ namespace SHADE
* that manage the resources instead and can facilitate such linking of resources. Either that, or we allow only 1 render graph, * that manage the resources instead and can facilitate such linking of resources. Either that, or we allow only 1 render graph,
* but different matrices (SHRenderer) can be used in different nodes. * but different matrices (SHRenderer) can be used in different nodes.
* - There are also way too many hash maps created for ease of access. This definitely can be cut down. * - There are also way too many hash maps created for ease of access. This definitely can be cut down.
* - * - In hindsight there should have been a distinction between static and dynamic nodes. Static nodes are the ones that are accounted
* for in the generation of the render graph. Dynamic nodes begin with nothing at first, but allows for linking of resources and subpasses
* while the render graph is executing. The resources here should also be dynamic, which means it should never be used in anywhere else other
* than in the node that is using it. This would mean its initial layouts are always specified as undefined and final layouts specified as
* whatever the last subpass that is using that resource specifies in the node. Dynamic nodes are meant to render to resources that would later
* be used externally, as descriptors for example (the descriptors can be used in a render graph node compute for example). Dynamic nodes run as
* if they are the only nodes in the graph, because their resources are not used in other nodes and are thus not predecessors or successors of any
* other node.
* *
*/ */

View File

@ -495,6 +495,68 @@ namespace SHADE
} }
} }
void SHRenderGraphNode::StandaloneConfigureAttDesc(bool isLastNode) noexcept
{
// key is handle ID, value is final layout.
std::unordered_map<uint32_t, vk::ImageLayout> resourceAttFinalLayouts;
if (!subpasses.empty())
{
// We first want to take all resources track their layout as undefined at the start of the node/renderpass
for (auto& resource : attResources)
{
resource->GetInfoTracker()->TrackLayout(GetHandle(), {}, vk::ImageLayout::eUndefined);
}
// attempt to get all final layouts for all resources
for (auto& subpass : subpasses)
{
for (auto& color : subpass->colorReferences)
{
// If final renderpass and attachment is a COLOR_PRESENT resource, make resource transition to present after last subpass
if (isLastNode && (attResources[color.attachment]->resourceTypeFlags & static_cast<uint32_t>(SH_RENDER_GRAPH_RESOURCE_FLAGS::COLOR_PRESENT)))
resourceAttFinalLayouts[color.attachment] = vk::ImageLayout::ePresentSrcKHR;
else
resourceAttFinalLayouts[color.attachment] = color.layout;
attResources[color.attachment]->infoTracker->TrackLayout(GetHandle(), subpass, color.layout);
}
for (auto& depth : subpass->depthReferences)
{
resourceAttFinalLayouts[depth.attachment] = depth.layout;
attResources[depth.attachment]->infoTracker->TrackLayout(GetHandle(), subpass, depth.layout);
}
for (auto& input : subpass->inputReferences)
{
resourceAttFinalLayouts[input.attachment] = input.layout;
attResources[input.attachment]->infoTracker->TrackLayout(GetHandle(), subpass, input.layout);
}
}
for (uint32_t j = 0; j < attachmentDescriptions.size(); ++j)
{
auto& att = attachmentDescriptions[j];
auto& resource = attResources[j];
// If resource is from another render graph, use the final layout it had when it was last used in that graph. This is initialized in LinkNonOwningResource.
// We also want to load the attachment, not "don't care".
if (resource->resourceTypeFlags & SHUtilities::ConvertEnum(SH_RENDER_GRAPH_RESOURCE_FLAGS::SHARED) &&
graphStorage->nonOwningResourceInitialLayouts.contains(resource.GetId().Raw))
{
att.initialLayout = graphStorage->nonOwningResourceInitialLayouts.at(resource.GetId().Raw);
att.loadOp = vk::AttachmentLoadOp::eLoad;
att.stencilLoadOp = vk::AttachmentLoadOp::eLoad;
}
else
att.initialLayout = vk::ImageLayout::eUndefined;
att.finalLayout = resourceAttFinalLayouts[j];
resource->GetInfoTracker()->TrackLayout(GetHandle(), {}, att.finalLayout);
}
}
}
/***************************************************************************/ /***************************************************************************/
/*! /*!
@ -521,6 +583,9 @@ namespace SHADE
// remove attachment reference // remove attachment reference
attachmentDescriptions.erase (attachmentDescriptions.begin() + index); attachmentDescriptions.erase (attachmentDescriptions.begin() + index);
// erase from mapping as well
resourceAttachmentMapping->erase(resourceHandleID);
// Remove footprint of attachment from all subpasses as well // Remove footprint of attachment from all subpasses as well
for (auto it = subpasses.begin(); it != subpasses.end(); ++it) for (auto it = subpasses.begin(); it != subpasses.end(); ++it)
{ {
@ -629,6 +694,77 @@ namespace SHADE
batcher.FinaliseBatches(graphStorage->logicalDevice, descPool, frameIndex); batcher.FinaliseBatches(graphStorage->logicalDevice, descPool, frameIndex);
} }
/***************************************************************************/
/*!
\brief
This function simply appends to the container of VkAttachmentDescription
and attResources. It will assume the resource is used standalone in the
node and will not account for its usage in other nodes. As such its
initialLayout will always be UNDEFINED and its finalLayout will be
whatever is calculated if the node is regenerated using
StandaloneRegnerate. This function also does not affect the render graph
while its running since the 2 containers above have already been copied
to the GPU.
\param resourceName
The name of the resource for getting the resource.
*/
/***************************************************************************/
void SHRenderGraphNode::RuntimeLinkResource(std::string resourceName) noexcept
{
// Get new resource
Handle<SHRenderGraphResource> newResource = graphStorage->graphResources->at(resourceName);
// append new resource to container
attResources.push_back(newResource);
attachmentDescriptions.push_back(vk::AttachmentDescription
{
.format = newResource->GetResourceFormat(),
.samples = vk::SampleCountFlagBits::e1,
.loadOp = vk::AttachmentLoadOp::eClear,
.storeOp = vk::AttachmentStoreOp::eStore,
.stencilLoadOp = vk::AttachmentLoadOp::eClear,
.stencilStoreOp = vk::AttachmentStoreOp::eStore,
});
resourceAttachmentMapping->try_emplace(newResource.GetId().Raw, attachmentDescriptions.size() - 1);
}
void SHRenderGraphNode::RuntimeAddSubpass(std::string subpassName, Handle<SHViewport> viewport, Handle<SHRenderer> renderer) noexcept
{
AddSubpass(std::move (subpassName), viewport, renderer);
}
/***************************************************************************/
/*!
\brief
USE WITH CAUTION because the function does not reevaluate resource
layouts in attachment descriptions. All resources here will start at
UNDEFINED and end at whatever the last subpass using the attachment
specifies. It will also not support render graph node computes given its
complexity if it has to be accounted for.
IN SHORT, IT GENERATES A RENDERPASS AS IF ITS THE ONLY NODE
IN THE RENDER GRAPH. SEE NOTES IN SHRenderGraph.h
This function is mainly meant for nodes that are dynamic (in hindsight,
there really should have been a distinction between static and dynamic
nodes).
*/
/***************************************************************************/
void SHRenderGraphNode::RuntimeStandaloneRegenerate(void) noexcept
{
StandaloneConfigureAttDesc(false);
ConfigureSubpasses();
CreateRenderpass();
CreateFramebuffer();
}
/***************************************************************************/ /***************************************************************************/
/*! /*!

View File

@ -93,6 +93,9 @@ namespace SHADE
void CreateFramebuffer(void) noexcept; void CreateFramebuffer(void) noexcept;
void HandleResize (void) noexcept; void HandleResize (void) noexcept;
void ConfigureSubpasses (void) noexcept; void ConfigureSubpasses (void) noexcept;
bool DetachResource(std::string const& resourceName, uint64_t resourceHandleID) noexcept;
void AddDummySubpassIfNeeded(void) noexcept;
void StandaloneConfigureAttDesc (bool isLastNode) noexcept;
public: public:
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@ -107,14 +110,16 @@ 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;
bool DetachResource (std::string const& resourceName, uint64_t resourceHandleID) noexcept;
// 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;
Handle<SHVkPipeline> GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept; Handle<SHVkPipeline> GetOrCreatePipeline(std::pair<Handle<SHVkShaderModule>, Handle<SHVkShaderModule>> const& vsFsPair, Handle<SHSubpass> subpass) noexcept;
void FinaliseBatch(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool); void FinaliseBatch(uint32_t frameIndex, Handle<SHVkDescriptorPool> descPool);
// Runtime functions that don't affect the renderpass
void RuntimeLinkResource(std::string resourceName) noexcept;
void RuntimeAddSubpass(std::string subpassName, Handle<SHViewport> viewport, Handle<SHRenderer> renderer) noexcept;
void RuntimeStandaloneRegenerate (void) noexcept;
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* SETTERS AND GETTERS */ /* SETTERS AND GETTERS */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/