You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/Atom/RPI/Code/Source/RPI.Public/Pass/ParentPass.cpp

482 lines
15 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include <AtomCore/Instance/InstanceDatabase.h>
#include <AtomCore/std/containers/vector_set.h>
#include <Atom/RPI.Public/Pass/SlowClearPass.h>
#include <Atom/RPI.Public/Pass/ParentPass.h>
#include <Atom/RPI.Public/Pass/PassAttachment.h>
#include <Atom/RPI.Public/Pass/PassDefines.h>
#include <Atom/RPI.Public/Pass/PassSystemInterface.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Reflect/Pass/SlowClearPassData.h>
#include <Atom/RPI.Reflect/Pass/PassName.h>
#include <Atom/RPI.Reflect/Pass/PassRequest.h>
namespace AZ
{
namespace RPI
{
Ptr<ParentPass> ParentPass::Create(const PassDescriptor& descriptor)
{
Ptr<ParentPass> pass = aznew ParentPass(descriptor);
return pass;
}
Ptr<ParentPass> ParentPass::Recreate() const
{
PassDescriptor desc = GetPassDescriptor();
Ptr<ParentPass> pass = aznew ParentPass(desc);
return pass;
}
ParentPass::ParentPass(const PassDescriptor& descriptor)
: Pass(descriptor)
{
m_flags.m_createChildren = true;
}
ParentPass::~ParentPass()
{
// Explicitly remove children so we call their OnOrphan function
RemoveChildren();
}
// --- Child Pass Addition ---
void ParentPass::AddChild(const Ptr<Pass>& child)
{
if (child->m_parent != nullptr)
{
AZ_Assert(false, "Can't add Pass that already has a parent. Remove the Pass from it's parent before adding it to another Pass.");
return;
}
m_children.push_back(child);
child->m_parent = this;
child->OnHierarchyChange();
QueueForBuildAndInitialization();
// Notify pipeline
if (m_pipeline)
{
m_pipeline->SetPassModified();
// Set child's pipeline if the parent has a owning pipeline
child->SetRenderPipeline(m_pipeline);
}
}
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)
{
AZ_Assert(false, "Can't add Pass that already has a parent. Remove the Pass from it's parent before adding it to another Pass.");
return false;
}
if (index > m_children.size())
{
AZ_Assert(false, "Can't insert a child pass with invalid position");
return false;
}
auto insertPos = m_children.cbegin() + index;
m_children.insert(insertPos, child);
child->m_parent = this;
child->OnHierarchyChange();
QueueForBuildAndInitialization();
// Notify pipeline
if (m_pipeline)
{
m_pipeline->SetPassModified();
// Set child's pipeline if the parent has a owning pipeline
child->SetRenderPipeline(m_pipeline);
}
return true;
}
void ParentPass::OnHierarchyChange()
{
Pass::OnHierarchyChange();
// Notify children about hierarchy change
for (const Ptr<Pass>& child : m_children)
{
child->OnHierarchyChange();
}
}
// --- Child Pass Removal ---
// The parameter type cannot be a reference as "const Ptr<Pass>&".
// Otherwise, the content of "pass" will be overwritten by AZStd::remove()
// when "pass" is a reference of a member of m_children.
void ParentPass::RemoveChild(Ptr<Pass> pass)
{
AZ_Assert(pass->m_parent == this, "Trying to remove a pass of which we are not the parent.");
// Find child and move it to the end of the list
[[maybe_unused]] auto it = AZStd::remove(m_children.begin(), m_children.end(), pass);
AZ_Assert((it + 1) == m_children.end(), "Pass::RemoveChild found more than one Ptr<Pass> in m_children, which is not allowed.");
// Delete the child that is now at the end of the list
m_children.pop_back();
// Signal child that it was orphaned
pass->OnOrphan();
// Notify pipeline
if (m_pipeline)
{
m_pipeline->SetPassModified();
}
}
void ParentPass::RemoveChildren()
{
for (auto child : m_children)
{
child->OnOrphan();
}
m_children.clear();
// Notify pipeline
if (m_pipeline)
{
m_pipeline->SetPassModified();
}
}
void ParentPass::OnOrphan()
{
Pass::OnOrphan();
for (const Ptr<Pass>& child : m_children)
{
child->OnHierarchyChange();
}
}
// --- Finders ---
Pass::ChildPassIndex ParentPass::FindChildPassIndex(const Name& passName) const
{
for (uint32_t index = 0; index < m_children.size(); ++index)
{
if (passName == m_children[index]->GetName())
{
return ChildPassIndex(index);
}
}
return ChildPassIndex::Null;
}
Ptr<Pass> ParentPass::FindChildPass(const Name& passName) const
{
ChildPassIndex index = FindChildPassIndex(passName);
return index.IsValid() ? m_children[index.GetIndex()] : Ptr<Pass>(nullptr);
}
const Pass* ParentPass::FindPass(RHI::DrawListTag drawListTag) const
{
if (HasDrawListTag() && GetDrawListTag() == drawListTag)
{
return this;
}
for (const Ptr<Pass>& child : m_children)
{
ParentPass* asParent = child->AsParent();
if (asParent)
{
const Pass* pass = asParent->FindPass(drawListTag);
if (pass)
{
return pass;
}
}
else if (child->HasDrawListTag() && child->GetDrawListTag() == drawListTag)
{
return child.get();
}
}
return nullptr;
}
// --- Timestamp functions ---
void ParentPass::SetTimestampQueryEnabled(bool enable)
{
Pass::SetTimestampQueryEnabled(enable);
for (auto& child : m_children)
{
child->SetTimestampQueryEnabled(enable);
}
}
void ParentPass::SetPipelineStatisticsQueryEnabled(bool enable)
{
Pass::SetPipelineStatisticsQueryEnabled(enable);
for (auto& child : m_children)
{
child->SetPipelineStatisticsQueryEnabled(enable);
}
}
// --- Child creation ---
void ParentPass::CreatePassesFromTemplate()
{
PassSystemInterface* passSystem = PassSystemInterface::Get();
if (m_template == nullptr)
{
return;
}
for (const PassRequest& request : m_template->m_passRequests)
{
Ptr<Pass> pass = passSystem->CreatePassFromRequest(&request);
if (pass)
{
AddChild(pass);
}
}
}
void ParentPass::CreateClearPassFromBinding(PassAttachmentBinding& binding, PassRequest& clearRequest)
{
if (binding.m_unifiedScopeDesc.m_loadStoreAction.m_loadAction == RHI::AttachmentLoadAction::Clear ||
binding.m_unifiedScopeDesc.m_loadStoreAction.m_loadActionStencil == RHI::AttachmentLoadAction::Clear)
{
// Set the name of the child clear pass as well as the binding it's connected to
clearRequest.m_passName = ConcatPassName(Name("Clear"), binding.m_name);
clearRequest.m_connections[0].m_attachmentRef.m_attachment = binding.m_name;
// Set the pass clear value to the clear value of the attachment binding
SlowClearPassData* clearData = static_cast<SlowClearPassData*>(clearRequest.m_passData.get());
clearData->m_clearValue = binding.m_unifiedScopeDesc.m_loadStoreAction.m_clearValue;
// Create and add the pass
Ptr<Pass> clearPass = PassSystemInterface::Get()->CreatePassFromRequest(&clearRequest);
if (clearPass)
{
AddChild(clearPass);
}
}
}
void ParentPass::CreateClearPassesFromBindings()
{
PassRequest clearRequest;
clearRequest.m_templateName = Name("SlowClearPassTemplate");
clearRequest.m_passData = AZStd::make_shared<SlowClearPassData>();
clearRequest.m_connections.push_back();
clearRequest.m_connections[0].m_localSlot = Name("ClearInputOutput");
clearRequest.m_connections[0].m_attachmentRef.m_pass = Name("Parent");
for (uint32_t idx = 0; idx < GetInputCount(); ++idx)
{
CreateClearPassFromBinding(GetInputBinding(idx), clearRequest);
}
for (uint32_t idx = 0; idx < GetInputOutputCount(); ++idx)
{
CreateClearPassFromBinding(GetInputOutputBinding(idx), clearRequest);
}
}
// --- Pass behavior functions ---
void ParentPass::CreateChildPasses()
{
// The already created flag prevents this function from executing multiple times a frame
if (!m_flags.m_createChildren || m_flags.m_alreadyCreatedChildren)
{
return;
}
m_flags.m_alreadyCreatedChildren = true;
RemoveChildren();
CreateClearPassesFromBindings();
CreatePassesFromTemplate();
CreateChildPassesInternal();
m_flags.m_createChildren = false;
}
void ParentPass::ResetInternal()
{
for (const Ptr<Pass>& child : m_children)
{
child->Reset();
}
}
void ParentPass::BuildInternal()
{
CreateChildPasses();
for (const Ptr<Pass>& child : m_children)
{
child->Build();
}
}
void ParentPass::OnInitializationFinishedInternal()
{
for (const Ptr<Pass>& child : m_children)
{
child->OnInitializationFinished();
}
}
void ParentPass::InitializeInternal()
{
for (const Ptr<Pass>& child : m_children)
{
child->Initialize();
}
}
void ParentPass::Validate(PassValidationResults& validationResults)
{
if (PassValidation::IsEnabled())
{
Pass::Validate(validationResults);
for (const Ptr<Pass>& child : m_children)
{
child->Validate(validationResults);
}
}
}
void ParentPass::FrameBeginInternal(FramePrepareParams params)
{
for (const Ptr<Pass>& child : m_children)
{
child->FrameBegin(params);
}
}
void ParentPass::FrameEndInternal()
{
for (const Ptr<Pass>& child : m_children)
{
child->FrameEnd();
}
}
// --- Misc ---
void ParentPass::SetRenderPipeline(RenderPipeline* pipeline)
{
// Call base implementation
Pass::SetRenderPipeline(pipeline);
// Set render pipeline on children
for (const auto& child : m_children)
{
child->SetRenderPipeline(pipeline);
}
}
void ParentPass::GetViewDrawListInfo(RHI::DrawListMask& outDrawListMask, PassesByDrawList& outPassesByDrawList, const PipelineViewTag& viewTag) const
{
// Call base implementation
Pass::GetViewDrawListInfo(outDrawListMask, outPassesByDrawList, viewTag);
// Get mask from children
for (const auto& child : m_children)
{
child->GetViewDrawListInfo(outDrawListMask, outPassesByDrawList, viewTag);
}
}
void ParentPass::GetPipelineViewTags(SortedPipelineViewTags& outTags) const
{
// Call base implementation
Pass::GetPipelineViewTags(outTags);
// Get pipeline view tags from children
for (const auto& child : m_children)
{
child->GetPipelineViewTags(outTags);
}
}
Ptr<PassAttachment> ParentPass::GetOwnedAttachment(const Name& attachmentName) const
{
for (Ptr<PassAttachment> attachment : m_ownedAttachments)
{
if (attachment->m_name == attachmentName)
{
return attachment;
}
}
return nullptr;
}
// --- Debug functions ---
AZStd::span<const Ptr<Pass>> ParentPass::GetChildren() const
{
return m_children;
}
void ParentPass::DebugPrint() const
{
if (PassValidation::IsEnabled())
{
Pass::DebugPrint();
// Print children
for (const Ptr<Pass>& child : m_children)
{
child->DebugPrint();
}
}
}
PipelineStatisticsResult ParentPass::GetPipelineStatisticsResultInternal() const
{
AZStd::vector<PipelineStatisticsResult> pipelineStatisticsResultArray;
pipelineStatisticsResultArray.reserve(m_children.size());
// Calculate the PipelineStatistics result by summing all of its child's PipelineStatistics
for (const Ptr<Pass>& childPass : m_children)
{
pipelineStatisticsResultArray.emplace_back(childPass->GetLatestPipelineStatisticsResult());
}
return PipelineStatisticsResult(pipelineStatisticsResultArray);
}
} // namespace RPI
} // namespace AZ