From 7f8dc2b6478296a7cf71053de1916acac9a4ffb8 Mon Sep 17 00:00:00 2001 From: Brandon Mak Date: Mon, 2 Jan 2023 18:24:29 +0800 Subject: [PATCH] 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 --- SHADE_Engine/src/Editor/SHEditor.cpp | 4 +- .../MiddleEnd/Interface/SHDebugDrawSystem.cpp | 4 +- .../MiddleEnd/Interface/SHGraphicsConstants.h | 133 +++++++++-------- .../MiddleEnd/Interface/SHGraphicsSystem.cpp | 48 ++++--- .../MiddleEnd/Interface/SHGraphicsSystem.h | 6 +- .../Graphics/RenderGraph/SHRenderGraph.cpp | 60 +------- .../src/Graphics/RenderGraph/SHRenderGraph.h | 9 +- .../RenderGraph/SHRenderGraphNode.cpp | 136 ++++++++++++++++++ .../Graphics/RenderGraph/SHRenderGraphNode.h | 19 ++- 9 files changed, 266 insertions(+), 153 deletions(-) diff --git a/SHADE_Engine/src/Editor/SHEditor.cpp b/SHADE_Engine/src/Editor/SHEditor.cpp index 93b42418..f3fe6b72 100644 --- a/SHADE_Engine/src/Editor/SHEditor.cpp +++ b/SHADE_Engine/src/Editor/SHEditor.cpp @@ -502,7 +502,7 @@ namespace SHADE //auto const& renderers = gfxSystem->GetDefaultViewport()->GetRenderers(); 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) { @@ -521,7 +521,7 @@ namespace SHADE ImGui_ImplVulkan_DestroyFontUploadObjects(); - renderGraph->GetNode("ImGui Node")->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle cmd, Handle renderer, uint32_t frameIndex) + renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::IMGUI_PASS.data())->GetSubpass("ImGui Draw")->AddExteriorDrawCalls([](Handle cmd, Handle renderer, uint32_t frameIndex) { cmd->BeginLabeledSegment("ImGui Draw"); ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), cmd->GetVkCommandBuffer()); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp index b57249de..fc701da3 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHDebugDrawSystem.cpp @@ -101,7 +101,7 @@ namespace SHADE // Register function for subpass //auto const& RENDERERS = gfxSystem->GetDefaultViewport()->GetRenderers(); 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 cmdBuffer, Handle renderer, uint32_t frameIndex) { const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex(); @@ -125,7 +125,7 @@ namespace SHADE } 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 cmdBuffer, Handle renderer, uint32_t frameIndex) { const uint32_t FRAME_IDX = gfxSystem->GetCurrentFrameIndex(); diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h index c889a321..f331ce02 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsConstants.h @@ -31,68 +31,79 @@ namespace SHADE static constexpr uint32_t EDITOR = 0; }; - //struct DescriptorSetIndex - //{ - // /***************************************************************************/ - // /*! - // \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; + struct RenderGraphNodeNames + { + /***************************************************************************/ + /*! + + \brief + Name of G-Buffer render graph node. + + */ + /***************************************************************************/ + static constexpr std::string_view GBUFFER_PASS = "G-Buffer"; - // /***************************************************************************/ - // /*! - // \brief - // To store font data. - // - // */ - // /***************************************************************************/ - // 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 { diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp index 18d79579..2ad41151 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.cpp @@ -44,6 +44,8 @@ of DigiPen Institute of Technology is prohibited. #include "Graphics/MiddleEnd/TextRendering/SHFreetypeInstance.h" #include "Graphics/MiddleEnd/TextRendering/SHTextRenderingSubSystem.h" #include "Graphics/MiddleEnd/GlobalData/SHGlobalDescriptorSets.h" +#include "Events/SHEvent.h" +#include "Graphics/MiddleEnd/Lights/SHLightComponent.h" namespace SHADE { @@ -198,7 +200,8 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* 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", "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. // 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 */ /*-----------------------------------------------------------------------*/ // 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", "Light Layer Indices", @@ -274,7 +277,7 @@ namespace SHADE "Scene", "SSAO Blur" }, - {"G-Buffer"}); + { SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS .data()}); /*-----------------------------------------------------------------------*/ /* DEFERRED COMPOSITE SUBPASS INIT */ @@ -286,19 +289,19 @@ namespace SHADE /*-----------------------------------------------------------------------*/ // Set up Debug Draw Passes // - 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); debugDrawDepthSubpass->AddColorOutput("Scene"); debugDrawDepthSubpass->AddDepthOutput("Depth Buffer"); // - 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); debugDrawSubpass->AddColorOutput("Scene"); /*-----------------------------------------------------------------------*/ /* 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); uiSubpass->AddColorOutput("Scene"); uiSubpass->AddColorOutput("Entity ID"); @@ -313,16 +316,16 @@ namespace SHADE #ifdef SHEDITOR { // 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", {}, {}); 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", {}, {}); imGuiSubpass->AddColorOutput("Present"); } #else - renderGraph->AddRenderToSwapchainNode("Scene", "Present", { "Screen Space Pass" }, { renderToSwapchainVS, renderToSwapchainFS }); + renderGraph->AddRenderToSwapchainNode("Scene", "Present", { SHGraphicsConstants::RenderGraphNodeNames::SCREEN_SPACE_PASS .data()}, {renderToSwapchainVS, renderToSwapchainFS}); #endif @@ -396,7 +399,7 @@ namespace SHADE textRenderingSubSystem = resourceManager.Create(); // 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); SHGlobalDescriptorSets::SetLightingSubSystem(lightingSubSystem); @@ -423,7 +426,7 @@ namespace SHADE defaultMaterial = AddMaterial ( 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); } @@ -724,16 +727,29 @@ namespace SHADE 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*>(eventPtr.get())->data; + auto* lightComp = SHComponentManager::GetComponent(EVENT_DATA->lightEntity); + std::string resourceName = "ShadowMap " + std::to_string(EVENT_DATA->lightEntity); + // 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. + auto shadowMapNode = renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::SHADOW_MAP_PASS.data()); + shadowMapNode->RuntimeLinkResource(resourceName); // Add a subpass to render to that shadow map + shadowMapNode->RuntimeAddSubpass(resourceName + " Subpass", worldViewport, worldRenderer); + + // regenerate the node + //shadowMapNode->RuntimeStandaloneRegenerate(); - //renderGraph->GetNode (); - return event->handle; + return eventPtr->handle; } Handle SHGraphicsSystem::AddMaterial(Handle vertShader, Handle fragShader, Handle subpass) @@ -1076,7 +1092,7 @@ namespace SHADE Handle SHGraphicsSystem::GetPrimaryRenderpass() const noexcept { - return renderGraph->GetNode(G_BUFFER_RENDER_GRAPH_NODE_NAME.data()); + return renderGraph->GetNode(SHGraphicsConstants::RenderGraphNodeNames::GBUFFER_PASS.data()); } Handle SHGraphicsSystem::GetDebugDrawPipeline(DebugDrawPipelineType type) const noexcept diff --git a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h index 40148e05..88d66ded 100644 --- a/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h +++ b/SHADE_Engine/src/Graphics/MiddleEnd/Interface/SHGraphicsSystem.h @@ -177,7 +177,7 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* Light functions */ /*-----------------------------------------------------------------------*/ - SHEventHandle ReceiveLightEnableShadowEvent (SHEventPtr event) noexcept; + SHEventHandle ReceiveLightEnableShadowEvent (SHEventPtr eventPtr) noexcept; /*-----------------------------------------------------------------------------*/ /* Material Functions */ @@ -405,10 +405,6 @@ namespace SHADE SHWindow* GetWindow() noexcept { return window; } private: - /*-----------------------------------------------------------------------------*/ - /* Constants */ - /*-----------------------------------------------------------------------------*/ - static constexpr std::string_view G_BUFFER_RENDER_GRAPH_NODE_NAME = "G-Buffer"; /*-----------------------------------------------------------------------------*/ /* Data Members */ diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp index e9a0e0bd..e6b9ae33 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.cpp @@ -169,65 +169,7 @@ namespace SHADE for (uint32_t i = 0; auto& node : nodes) { - // key is handle ID, value is final layout. - std::unordered_map 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(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); - } - } + node->StandaloneConfigureAttDesc(i == nodes.size() - 1); ++i; } diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h index 7dc19a80..6dbc4308 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraph.h @@ -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, * 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. - * - + * - 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. * */ diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp index 56d8734a..cc9d61a9 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.cpp @@ -495,6 +495,68 @@ namespace SHADE } } + void SHRenderGraphNode::StandaloneConfigureAttDesc(bool isLastNode) noexcept + { + // key is handle ID, value is final layout. + std::unordered_map 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(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 attachmentDescriptions.erase (attachmentDescriptions.begin() + index); + // erase from mapping as well + resourceAttachmentMapping->erase(resourceHandleID); + // Remove footprint of attachment from all subpasses as well for (auto it = subpasses.begin(); it != subpasses.end(); ++it) { @@ -629,6 +694,77 @@ namespace SHADE 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 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 viewport, Handle 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(); + } + /***************************************************************************/ /*! diff --git a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h index a581d21c..d8e4caa4 100644 --- a/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h +++ b/SHADE_Engine/src/Graphics/RenderGraph/SHRenderGraphNode.h @@ -93,6 +93,9 @@ namespace SHADE void CreateFramebuffer(void) noexcept; void HandleResize (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: /*-----------------------------------------------------------------------*/ @@ -105,15 +108,17 @@ namespace SHADE /*-----------------------------------------------------------------------*/ /* PUBLIC MEMBER FUNCTIONS */ /*-----------------------------------------------------------------------*/ - Handle AddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept; + Handle AddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept; Handle AddNodeCompute(std::string nodeName, Handle computeShaderModule, std::initializer_list resources, std::unordered_set&& dynamicBufferBindings = {}, float numWorkGroupScale = 1.0f) noexcept; - void AddDummySubpassIfNeeded (void) noexcept; - bool DetachResource (std::string const& resourceName, uint64_t resourceHandleID) noexcept; + + void Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; + Handle GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept; + void FinaliseBatch(uint32_t frameIndex, Handle descPool); - // TODO: RemoveSubpass() - void Execute(Handle commandBuffer, Handle descPool, uint32_t frameIndex) noexcept; - Handle GetOrCreatePipeline(std::pair, Handle> const& vsFsPair, Handle subpass) noexcept; - void FinaliseBatch(uint32_t frameIndex, Handle descPool); + // Runtime functions that don't affect the renderpass + void RuntimeLinkResource(std::string resourceName) noexcept; + void RuntimeAddSubpass(std::string subpassName, Handle viewport, Handle renderer) noexcept; + void RuntimeStandaloneRegenerate (void) noexcept; /*-----------------------------------------------------------------------*/ /* SETTERS AND GETTERS */