[new] ATOM-17253 Using AtomTressFX gem as an example to inject hair passes to main pipeline at run-time (#7661)
* Change AtomTressFX passes to write to exsiting DepthLinear buffer instead of creating a new one as output. Signed-off-by: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> * Added new api in RPI to apply render pipeline changes from FP Signed-off-by: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> * Update AtomTressFX gem to create hair parent pass at runtime Signed-off-by: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com> * Change Scene::ApplyRenderPipelineChange() to TryApplyRenderPIpelineChanges(). Have TryApplyRenderPIpelineChanges() called automatically when a render pipeline is added to a Scene. Re-apply the render pipeline change when RenderPipeline got recreated (Pass hot-reloading support) Add AddPassBefore() and AddPassAfter() function to RenderPIpeline class. Signed-off-by: Qing Tao <55564570+VickyAtAZ@users.noreply.github.com>
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
"Name": "MainPipeline",
|
||||
"MainViewTag": "MainCamera",
|
||||
"RootPassTemplate": "MainPipeline",
|
||||
"AllowModification": true,
|
||||
"RenderSettings": {
|
||||
"MultisampleState": {
|
||||
"samples": 4
|
||||
|
||||
@@ -30,6 +30,8 @@ namespace AZ
|
||||
|
||||
namespace RPI
|
||||
{
|
||||
class RenderPipeline;
|
||||
|
||||
//! @class FeatureProcessor
|
||||
//! @brief Interface that FeatureProcessors should derive from
|
||||
//! @detail FeatureProcceors will record simulation state from the simulation job graph into a buffer that is isolated from the asynchronous rendering graph.
|
||||
@@ -87,6 +89,9 @@ namespace AZ
|
||||
//! Perform any necessary deactivation.
|
||||
virtual void Deactivate() {}
|
||||
|
||||
//! Apply changes and add additional render passes to the render pipeline from the feature processors
|
||||
virtual void ApplyRenderPipelineChange(RenderPipeline* ) {}
|
||||
|
||||
//! Allows the feature processor to expose supporting views based on
|
||||
//! the main views passed in. Main views (persistent views) are views that must be
|
||||
//! rendered and impacts the presentation of the application. Support
|
||||
|
||||
@@ -66,6 +66,7 @@ namespace AZ
|
||||
//! Inserts a pass at specified position
|
||||
//! If the position is invalid, the child pass won't be added, and the function returns false
|
||||
bool InsertChild(const Ptr<Pass>& child, ChildPassIndex position);
|
||||
bool InsertChild(const Ptr<Pass>& child, uint32_t index);
|
||||
|
||||
//! Searches for a child pass with the given name. Returns the child's index if found, null index otherwise
|
||||
ChildPassIndex FindChildPassIndex(const Name& passName) const;
|
||||
|
||||
@@ -184,6 +184,23 @@ namespace AZ
|
||||
//! Get draw filter mask
|
||||
RHI::DrawFilterMask GetDrawFilterMask() const;
|
||||
|
||||
//! Get the RenderPipelineDescriptor which was used to create this RenderPipeline
|
||||
const RenderPipelineDescriptor& GetDescriptor() const;
|
||||
|
||||
// Helper functions to modify the passes of this render pipeline
|
||||
//! Find a reference pass's location and add the new pass before the reference pass
|
||||
//! After the new pass was inserted, the new pass and the reference pass are siblings
|
||||
bool AddPassBefore(Ptr<Pass> newPass, const AZ::Name& referencePassName);
|
||||
|
||||
//! Find a reference pass's location and add the new pass after the reference pass
|
||||
//! After the new pass was inserted, the new pass and the reference pass are siblings
|
||||
bool AddPassAfter(Ptr<Pass> newPass, const AZ::Name& referencePassName);
|
||||
|
||||
//! Find the first pass with matching name in the render pipeline
|
||||
//! Note: to find all the passes with matching name in this render pipeline,
|
||||
//! use RPI::PassSystemInterface::Get()->ForEachPass() function instead.
|
||||
Ptr<Pass> FindFirstPass(const AZ::Name& passName);
|
||||
|
||||
private:
|
||||
RenderPipeline() = default;
|
||||
|
||||
@@ -238,8 +255,8 @@ namespace AZ
|
||||
|
||||
PipelineViewTag m_mainViewTag;
|
||||
|
||||
// Whether the pipeline should be removed after one execution
|
||||
bool m_executeOnce = false;
|
||||
// Was the pipeline modified by Scene's feature processor
|
||||
bool m_wasModifiedByScene = false;
|
||||
|
||||
// The window handle associated with this render pipeline if it's created for a window
|
||||
AzFramework::NativeWindowHandle m_windowHandle = nullptr;
|
||||
@@ -247,15 +264,15 @@ namespace AZ
|
||||
// Render settings that can be queried by passes to setup things like render target resolution
|
||||
PipelineRenderSettings m_activeRenderSettings;
|
||||
|
||||
// Original settings from RenderPipelineDescriptor, used to revert active render settings to original settings from RenderPipelineDescriptor
|
||||
PipelineRenderSettings m_originalRenderSettings;
|
||||
|
||||
// A tag to filter draw items submitted by passes of this render pipeline.
|
||||
// This tag is allocated when it's added to a scene. It's set to invalid when it's removed to the scene.
|
||||
RHI::DrawFilterTag m_drawFilterTag;
|
||||
// A mask to filter draw items submitted by passes of this render pipeline.
|
||||
// This mask is created from the value of m_drawFilterTag.
|
||||
RHI::DrawFilterMask m_drawFilterMask = 0;
|
||||
RHI::DrawFilterMask m_drawFilterMask = 0;
|
||||
|
||||
// The descriptor used to created this render pipeline
|
||||
RenderPipelineDescriptor m_descriptor;
|
||||
};
|
||||
|
||||
} // namespace RPI
|
||||
|
||||
@@ -169,6 +169,9 @@ namespace AZ
|
||||
//! This function is called every time scene's render pipelines change.
|
||||
//! User may call this function explicitly if render pipelines were changed
|
||||
void RebuildPipelineStatesLookup();
|
||||
|
||||
//! Try apply render pipeline changes from each feature processors if the pipeline allows modification and wasn't modified.
|
||||
void TryApplyRenderPipelineChanges(RenderPipeline* pipeline);
|
||||
|
||||
protected:
|
||||
// SceneFinder overrides...
|
||||
@@ -192,6 +195,7 @@ namespace AZ
|
||||
// This is called after PassSystem's FramePrepare so passes can still modify view srgs in its FramePrepareIntenal function before they are submitted to command list
|
||||
void UpdateSrgs();
|
||||
|
||||
|
||||
private:
|
||||
Scene();
|
||||
|
||||
|
||||
@@ -41,6 +41,9 @@ namespace AZ
|
||||
|
||||
//! Flag indicating if this pipeline should execute one time and then be removed.
|
||||
bool m_executeOnce = false;
|
||||
|
||||
//! Flag indicating if this pipeline can accept modifications from scene's feature processors
|
||||
bool m_allowModification = false;
|
||||
};
|
||||
|
||||
} // namespace RPI
|
||||
|
||||
@@ -76,6 +76,16 @@ namespace AZ
|
||||
}
|
||||
|
||||
bool ParentPass::InsertChild(const Ptr<Pass>& child, ChildPassIndex position)
|
||||
{
|
||||
if (!position.IsValid())
|
||||
{
|
||||
AZ_Assert(false, "Can't insert a child pass with invalid position");
|
||||
return false;
|
||||
}
|
||||
return InsertChild(child, position.GetIndex());
|
||||
}
|
||||
|
||||
bool ParentPass::InsertChild(const Ptr<Pass>& child, uint32_t index)
|
||||
{
|
||||
if (child->m_parent != nullptr)
|
||||
{
|
||||
@@ -83,13 +93,13 @@ namespace AZ
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!position.IsValid() || position.GetIndex() > m_children.size())
|
||||
if (index > m_children.size())
|
||||
{
|
||||
AZ_Assert(false, "Can't insert a child pass with invalid position");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto insertPos = m_children.cbegin() + position.GetIndex();
|
||||
auto insertPos = m_children.cbegin() + index;
|
||||
m_children.insert(insertPos, child);
|
||||
|
||||
child->m_parent = this;
|
||||
|
||||
@@ -294,7 +294,7 @@ namespace AZ
|
||||
void PassLibrary::OnAssetReloaded(Data::Asset<Data::AssetData> asset)
|
||||
{
|
||||
// Handle pass asset reload
|
||||
Data::Asset<PassAsset> passAsset = Data::static_pointer_cast<PassAsset>(asset);
|
||||
Data::Asset<PassAsset> passAsset = { asset.GetAs<PassAsset>() , AZ::Data::AssetLoadBehavior::PreLoad};
|
||||
if (passAsset && passAsset->GetPassTemplate())
|
||||
{
|
||||
LoadPassAsset(passAsset->GetPassTemplate()->m_name, passAsset, true);
|
||||
|
||||
@@ -370,6 +370,7 @@ namespace AZ
|
||||
m_commonShaderAssetForSrgs = AssetUtils::LoadCriticalAsset<ShaderAsset>( m_descriptor.m_commonSrgsShaderAssetPath.c_str());
|
||||
if (!m_commonShaderAssetForSrgs.IsReady())
|
||||
{
|
||||
AZ_Error("RPI system", false, "Failed to load RPI system asset %s", m_descriptor.m_commonSrgsShaderAssetPath.c_str());
|
||||
return;
|
||||
}
|
||||
m_sceneSrgLayout = m_commonShaderAssetForSrgs->FindShaderResourceGroupLayout(SrgBindingSlot::Scene);
|
||||
@@ -395,6 +396,7 @@ namespace AZ
|
||||
m_passSystem.InitPassTemplates();
|
||||
|
||||
m_systemAssetsInitialized = true;
|
||||
AZ_TracePrintf("RPI system", "System assets initialized\n");
|
||||
}
|
||||
|
||||
bool RPISystem::IsInitialized() const
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <Atom/RHI/DrawListTagRegistry.h>
|
||||
|
||||
#include <Atom/RPI.Public/Pass/PassFilter.h>
|
||||
#include <Atom/RPI.Public/Pass/PassSystem.h>
|
||||
#include <Atom/RPI.Public/Pass/Specific/SwapChainPass.h>
|
||||
#include <Atom/RPI.Public/RenderPipeline.h>
|
||||
@@ -97,10 +98,9 @@ namespace AZ
|
||||
|
||||
void RenderPipeline::InitializeRenderPipeline(RenderPipeline* pipeline, const RenderPipelineDescriptor& desc)
|
||||
{
|
||||
pipeline->m_descriptor = desc;
|
||||
pipeline->m_mainViewTag = Name(desc.m_mainViewTagName);
|
||||
pipeline->m_nameId = desc.m_name.data();
|
||||
pipeline->m_executeOnce = desc.m_executeOnce;
|
||||
pipeline->m_originalRenderSettings = desc.m_renderSettings;
|
||||
pipeline->m_activeRenderSettings = desc.m_renderSettings;
|
||||
pipeline->m_rootPass->SetRenderPipeline(pipeline);
|
||||
pipeline->m_rootPass->m_flags.m_isPipelineRoot = true;
|
||||
@@ -337,6 +337,10 @@ namespace AZ
|
||||
m_rootPass = newRoot;
|
||||
passSystem->GetRootPass()->AddChild(m_rootPass);
|
||||
|
||||
// Re-Apply render pipeline change
|
||||
m_wasModifiedByScene = false;
|
||||
m_scene->TryApplyRenderPipelineChanges(this);
|
||||
|
||||
m_wasPassModified = true;
|
||||
}
|
||||
else
|
||||
@@ -366,7 +370,7 @@ namespace AZ
|
||||
|
||||
bool RenderPipeline::IsExecuteOnce()
|
||||
{
|
||||
return m_executeOnce;
|
||||
return m_descriptor.m_executeOnce;
|
||||
}
|
||||
|
||||
void RenderPipeline::RemoveFromScene()
|
||||
@@ -477,7 +481,7 @@ namespace AZ
|
||||
|
||||
void RenderPipeline::RevertRenderSettings()
|
||||
{
|
||||
m_activeRenderSettings = m_originalRenderSettings;
|
||||
m_activeRenderSettings = m_descriptor.m_renderSettings;
|
||||
}
|
||||
|
||||
void RenderPipeline::AddToRenderTickOnce()
|
||||
@@ -527,5 +531,60 @@ namespace AZ
|
||||
m_drawFilterMask = 0;
|
||||
}
|
||||
}
|
||||
|
||||
const RenderPipelineDescriptor& RenderPipeline::GetDescriptor() const
|
||||
{
|
||||
return m_descriptor;
|
||||
}
|
||||
|
||||
bool RenderPipeline::AddPassBefore(Ptr<Pass> newPass, const AZ::Name& referencePassName)
|
||||
{
|
||||
auto foundPass = FindFirstPass(referencePassName);
|
||||
|
||||
if (!foundPass)
|
||||
{
|
||||
AZ_Warning("RenderPipeline", false, "Add pass to render pipeline failed: can't find reference pass [%s] in render pipeline [%s]",
|
||||
referencePassName.GetCStr(), GetId().GetCStr());
|
||||
return false;
|
||||
}
|
||||
|
||||
// insert the pass
|
||||
auto parentPass = foundPass->GetParent();
|
||||
auto passIndex = parentPass->FindChildPassIndex(referencePassName);
|
||||
// Note: no need to check if passIndex is valid since the pass was already found
|
||||
return parentPass->InsertChild(newPass, passIndex.GetIndex());
|
||||
}
|
||||
|
||||
bool RenderPipeline::AddPassAfter(Ptr<Pass> newPass, const AZ::Name& referencePassName)
|
||||
{
|
||||
auto foundPass = FindFirstPass(referencePassName);
|
||||
|
||||
if (!foundPass)
|
||||
{
|
||||
AZ_Warning("RenderPipeline", false, "Add pass to render pipeline failed: can't find reference pass [%s] in render pipeline [%s]",
|
||||
referencePassName.GetCStr(), GetId().GetCStr());
|
||||
return false;
|
||||
}
|
||||
|
||||
// insert the pass
|
||||
auto parentPass = foundPass->GetParent();
|
||||
auto passIndex = parentPass->FindChildPassIndex(referencePassName);
|
||||
// Note: no need to check if passIndex is valid since the pass was already found
|
||||
return parentPass->InsertChild(newPass, passIndex.GetIndex()+1);
|
||||
}
|
||||
|
||||
Ptr<Pass> RenderPipeline::FindFirstPass(const AZ::Name& passName)
|
||||
{
|
||||
auto passFilter = RPI::PassFilter::CreateWithPassHierarchy({passName});
|
||||
passFilter.SetOwnerRenderPipeline(this);
|
||||
RPI::Ptr<RPI::Pass> foundPass = nullptr;
|
||||
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [&foundPass](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
|
||||
{
|
||||
foundPass = pass;
|
||||
return RPI::PassFilterExecutionFlow::StopVisitingPasses;
|
||||
});
|
||||
|
||||
return foundPass;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,6 +285,22 @@ namespace AZ
|
||||
return foundFP == AZStd::end(m_featureProcessors) ? nullptr : (*foundFP).get();
|
||||
}
|
||||
|
||||
void Scene::TryApplyRenderPipelineChanges(RenderPipeline* pipeline)
|
||||
{
|
||||
// return directly if the pipeline doesn't allow modification or it was already modifed by scene
|
||||
if (!pipeline->m_descriptor.m_allowModification || pipeline->m_wasModifiedByScene)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pipeline->m_wasModifiedByScene = true;
|
||||
for (auto& fp : m_featureProcessors)
|
||||
{
|
||||
fp->ApplyRenderPipelineChange(pipeline);
|
||||
}
|
||||
AZ::RPI::PassSystemInterface::Get()->ProcessQueuedChanges();
|
||||
}
|
||||
|
||||
void Scene::AddRenderPipeline(RenderPipelinePtr pipeline)
|
||||
{
|
||||
if (pipeline->m_scene != nullptr)
|
||||
@@ -311,6 +327,9 @@ namespace AZ
|
||||
}
|
||||
|
||||
pipeline->OnAddedToScene(this);
|
||||
|
||||
TryApplyRenderPipelineChanges(pipeline.get());
|
||||
|
||||
PassSystemInterface::Get()->ProcessQueuedChanges();
|
||||
pipeline->BuildPipelineViews();
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ namespace AZ
|
||||
->Field("RootPassTemplate", &RenderPipelineDescriptor::m_rootPassTemplate)
|
||||
->Field("ExecuteOnce", &RenderPipelineDescriptor::m_executeOnce)
|
||||
->Field("RenderSettings", &RenderPipelineDescriptor::m_renderSettings)
|
||||
->Field("AllowModification", &RenderPipelineDescriptor::m_allowModification)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user