ATOM-16489 Add find passes functions for Scene or RenderPipeline in PassSystemInterface (#4739) (#4963)

* ATOM-16489 Add find passes functions for Scene or RenderPipeline in PassSystemInterface
Introduced new PassSystemInterface::ForEachPass() funtion to replace PassSystemInterface::FindPasses(), PassSystemInterface::GetPassesByTemplateName and ParentPass::FindPassByNameRecursive() functions.
Update all the places which were using those three functions.
The new pass finding filter support any combination of pass name, pass template name, pass class type, pass hirechary, owner scene, owner render pipeline.
Update unit tests.

Signed-off-by: Qing Tao <qingtao@amazon.com>
(cherry picked from commit fe8dac7989)
monroegm-disable-blank-issue-2
Qing Tao 4 years ago committed by GitHub
parent 91ca986e2a
commit a5694a5ac6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -50,12 +50,12 @@ namespace AZ
return scope; return scope;
} }
//! Sets the active context based on the provided PassHierarchyFilter. If the filter doesn't match exactly one pass, then do nothing. //! Sets the active context based on the provided pass hierarchy filter. If the filter doesn't match exactly one pass, then do nothing.
static ImGuiActiveContextScope FromPass(const RPI::PassHierarchyFilter& passHierarchyFilter) static ImGuiActiveContextScope FromPass(const AZStd::vector<AZStd::string>& passHierarchy)
{ {
ImGuiActiveContextScope scope; ImGuiActiveContextScope scope;
scope.ConnectToImguiNotificationBus(); scope.ConnectToImguiNotificationBus();
ImGuiSystemRequestBus::BroadcastResult(scope.m_isEnabled, &ImGuiSystemRequests::PushActiveContextFromPass, passHierarchyFilter); ImGuiSystemRequestBus::BroadcastResult(scope.m_isEnabled, &ImGuiSystemRequests::PushActiveContextFromPass, passHierarchy);
return scope; return scope;
} }

@ -15,11 +15,6 @@
namespace AZ namespace AZ
{ {
namespace RPI
{
class PassHierarchyFilter;
}
namespace Render namespace Render
{ {
class ImGuiPass; class ImGuiPass;
@ -51,7 +46,7 @@ namespace AZ
//! Pushes whichever ImGui pass is default on the top of the active context stack. Returns true/false for success/fail. //! Pushes whichever ImGui pass is default on the top of the active context stack. Returns true/false for success/fail.
virtual bool PushActiveContextFromDefaultPass() = 0; virtual bool PushActiveContextFromDefaultPass() = 0;
//! Pushes whichever ImGui pass is provided in passHierarchy on the top of the active context stack. Returns true/false for success/fail. //! Pushes whichever ImGui pass is provided in passHierarchy on the top of the active context stack. Returns true/false for success/fail.
virtual bool PushActiveContextFromPass(const RPI::PassHierarchyFilter& passHierarchy) = 0; virtual bool PushActiveContextFromPass(const AZStd::vector<AZStd::string>& passHierarchy) = 0;
//! Pops the active context off the top of the active context stack. Returns true if there's a context to pop. //! Pops the active context off the top of the active context stack. Returns true if there's a context to pop.
virtual bool PopActiveContext() = 0; virtual bool PopActiveContext() = 0;
//! Gets the context at the top of the active context stack. Returns nullptr if the stack is emtpy. //! Gets the context at the top of the active context stack. Returns nullptr if the stack is emtpy.

@ -50,7 +50,7 @@ namespace AZ
virtual bool CaptureScreenshotWithPreview(const AZStd::string& outputFilePath) = 0; virtual bool CaptureScreenshotWithPreview(const AZStd::string& outputFilePath) = 0;
//! Save a buffer attachment or a image attachment binded to a pass's slot to a data file. //! Save a buffer attachment or a image attachment binded to a pass's slot to a data file.
//! @param passHierarchy For finding the pass by using PassHierarchyFilter //! @param passHierarchy For finding the pass by using a pass hierarchy filter. Check PassFilter::CreateWithPassHierarchy() function for detail
//! @param slotName Name of the pass's slot. The attachment bound to this slot will be captured. //! @param slotName Name of the pass's slot. The attachment bound to this slot will be captured.
//! @param option Only valid for an InputOutput attachment. Use PassAttachmentReadbackOption::Input to capture the input state //! @param option Only valid for an InputOutput attachment. Use PassAttachmentReadbackOption::Input to capture the input state
//! and use PassAttachmentReadbackOption::Output to capture the output state //! and use PassAttachmentReadbackOption::Output to capture the output state

@ -647,54 +647,46 @@ namespace AZ
UpdateViewsOfCascadeSegments(); UpdateViewsOfCascadeSegments();
} }
void DirectionalLightFeatureProcessor::CacheCascadedShadowmapsPass() { void DirectionalLightFeatureProcessor::CacheCascadedShadowmapsPass()
const AZStd::vector<RPI::Pass*>& passes = RPI::PassSystemInterface::Get()->GetPassesForTemplateName(Name("CascadedShadowmapsTemplate")); {
m_cascadedShadowmapsPasses.clear(); m_cascadedShadowmapsPasses.clear();
for (RPI::Pass* pass : passes)
{ RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(Name("CascadedShadowmapsTemplate"), GetParentScene());
if (RPI::RenderPipeline* pipeline = pass->GetRenderPipeline()) RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
{ {
RPI::RenderPipeline* pipeline = pass->GetRenderPipeline();
const RPI::RenderPipelineId pipelineId = pipeline->GetId(); const RPI::RenderPipelineId pipelineId = pipeline->GetId();
// This function can be called when the pipeline is not attached to the scene.
// So we check it is attached to the scene. CascadedShadowmapsPass* shadowPass = azrtti_cast<CascadedShadowmapsPass*>(pass);
if (GetParentScene()->GetRenderPipeline(pipelineId).get() == pipeline) AZ_Assert(shadowPass, "It is not a CascadedShadowmapPass.");
if (pipeline->GetDefaultView())
{ {
CascadedShadowmapsPass* shadowPass = azrtti_cast<CascadedShadowmapsPass*>(pass); m_cascadedShadowmapsPasses[pipelineId].push_back(shadowPass);
AZ_Assert(shadowPass, "It is not a CascadedShadowmapPass.");
if (pipeline->GetDefaultView())
{
m_cascadedShadowmapsPasses[pipelineId].push_back(shadowPass);
}
} }
} return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
} });
} }
void DirectionalLightFeatureProcessor::CacheEsmShadowmapsPass() void DirectionalLightFeatureProcessor::CacheEsmShadowmapsPass()
{ {
const AZStd::vector<RPI::Pass*>& passes = RPI::PassSystemInterface::Get()->GetPassesForTemplateName(Name("EsmShadowmapsTemplate"));
m_esmShadowmapsPasses.clear(); m_esmShadowmapsPasses.clear();
for (RPI::Pass* pass : passes)
{ RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(Name("EsmShadowmapsTemplate"), GetParentScene());
if (RPI::RenderPipeline* pipeline = pass->GetRenderPipeline()) RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
{ {
const RPI::RenderPipelineId pipelineId = pipeline->GetId(); const RPI::RenderPipelineId pipelineId = pass->GetRenderPipeline()->GetId();
// checking the render pipeline is just removed from the scene.
if (GetParentScene()->GetRenderPipeline(pipelineId).get() == pipeline) if (m_cascadedShadowmapsPasses.find(pipelineId) != m_cascadedShadowmapsPasses.end())
{ {
if (m_cascadedShadowmapsPasses.find(pipelineId) != m_cascadedShadowmapsPasses.end()) EsmShadowmapsPass* esmPass = azrtti_cast<EsmShadowmapsPass*>(pass);
AZ_Assert(esmPass, "It is not an EsmShadowmapPass.");
if (esmPass->GetLightTypeName() == m_lightTypeName)
{ {
EsmShadowmapsPass* esmPass = azrtti_cast<EsmShadowmapsPass*>(pass); m_esmShadowmapsPasses[pipelineId].push_back(esmPass);
AZ_Assert(esmPass, "It is not an EsmShadowmapPass.");
if (m_cascadedShadowmapsPasses.find(esmPass->GetRenderPipeline()->GetId()) != m_cascadedShadowmapsPasses.end() &&
esmPass->GetLightTypeName() == m_lightTypeName)
{
m_esmShadowmapsPasses[pipelineId].push_back(esmPass);
}
} }
} }
} return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
} });
} }
void DirectionalLightFeatureProcessor::PrepareCameraViews() void DirectionalLightFeatureProcessor::PrepareCameraViews()
@ -1063,12 +1055,13 @@ namespace AZ
// if the shadow is rendering in an EnvironmentCubeMapPass it also needs to be a ReflectiveCubeMap view, // if the shadow is rendering in an EnvironmentCubeMapPass it also needs to be a ReflectiveCubeMap view,
// to filter out shadows from objects that are excluded from the cubemap // to filter out shadows from objects that are excluded from the cubemap
RPI::PassClassFilter<RPI::EnvironmentCubeMapPass> passFilter; RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass<RPI::EnvironmentCubeMapPass>();
AZStd::vector<AZ::RPI::Pass*> cubeMapPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter); passFilter.SetOwenrScene(GetParentScene()); // only handles passes for this scene
if (!cubeMapPasses.empty()) RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [&usageFlags]([[maybe_unused]] RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
{ {
usageFlags |= RPI::View::UsageReflectiveCubeMap; usageFlags |= RPI::View::UsageReflectiveCubeMap;
} return RPI::PassFilterExecutionFlow::StopVisitingPasses;
});
segment.m_view = RPI::View::CreateView(viewName, usageFlags); segment.m_view = RPI::View::CreateView(viewName, usageFlags);
} }

@ -80,35 +80,48 @@ namespace AZ
} }
// update the size multiplier on the DiffuseProbeGridDownsamplePass output // update the size multiplier on the DiffuseProbeGridDownsamplePass output
AZStd::vector<Name> downsamplePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseProbeGridDownsamplePass") }; // NOTE: The ownerScene wasn't added to both filters. This is because the passes from the non-owner scene may have invalid SRG values which could lead to
RPI::PassHierarchyFilter downsamplePassFilter(downsamplePassHierarchy); // GPU error if the scene doesn't have this feature processor enabled.
const AZStd::vector<RPI::Pass*>& downsamplePasses = RPI::PassSystemInterface::Get()->FindPasses(downsamplePassFilter); // For example, the ASV MultiScene sample may have TDR.
for (RPI::Pass* pass : downsamplePasses)
{ {
for (uint32_t outputIndex = 0; outputIndex < pass->GetOutputCount(); ++outputIndex) AZStd::vector<Name> downsamplePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseProbeGridDownsamplePass") };
{ RPI::PassFilter downsamplePassFilter = RPI::PassFilter::CreateWithPassHierarchy(downsamplePassHierarchy);
RPI::Ptr<RPI::PassAttachment> outputAttachment = pass->GetOutputBinding(outputIndex).m_attachment; RPI::PassSystemInterface::Get()->ForEachPass(
RPI::PassAttachmentSizeMultipliers& sizeMultipliers = outputAttachment->m_sizeMultipliers; downsamplePassFilter,
[sizeMultiplier](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
sizeMultipliers.m_widthMultiplier = sizeMultiplier; {
sizeMultipliers.m_heightMultiplier = sizeMultiplier; for (uint32_t outputIndex = 0; outputIndex < pass->GetOutputCount(); ++outputIndex)
} {
RPI::Ptr<RPI::PassAttachment> outputAttachment = pass->GetOutputBinding(outputIndex).m_attachment;
// set the output scale on the PassSrg RPI::PassAttachmentSizeMultipliers& sizeMultipliers = outputAttachment->m_sizeMultipliers;
RPI::FullscreenTrianglePass* downsamplePass = static_cast<RPI::FullscreenTrianglePass*>(pass);
auto constantIndex = downsamplePass->GetShaderResourceGroup()->FindShaderInputConstantIndex(Name("m_outputImageScale")); sizeMultipliers.m_widthMultiplier = sizeMultiplier;
downsamplePass->GetShaderResourceGroup()->SetConstant(constantIndex, aznumeric_cast<uint32_t>(1.0f / sizeMultiplier)); sizeMultipliers.m_heightMultiplier = sizeMultiplier;
}
// set the output scale on the PassSrg
RPI::FullscreenTrianglePass* downsamplePass = static_cast<RPI::FullscreenTrianglePass*>(pass);
RHI::ShaderInputNameIndex outputImageScaleShaderInput = "m_outputImageScale";
downsamplePass->GetShaderResourceGroup()->SetConstant(
outputImageScaleShaderInput, aznumeric_cast<uint32_t>(1.0f / sizeMultiplier));
// handle all downsample passes
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
});
} }
// update the image scale on the DiffuseComposite pass // update the image scale on the DiffuseComposite pass
AZStd::vector<Name> compositePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseCompositePass") };
RPI::PassHierarchyFilter compositePassFilter(compositePassHierarchy);
const AZStd::vector<RPI::Pass*>& compositePasses = RPI::PassSystemInterface::Get()->FindPasses(compositePassFilter);
for (RPI::Pass* pass : compositePasses)
{ {
RPI::FullscreenTrianglePass* compositePass = static_cast<RPI::FullscreenTrianglePass*>(pass); AZStd::vector<Name> compositePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseCompositePass") };
auto constantIndex = compositePass->GetShaderResourceGroup()->FindShaderInputConstantIndex(Name("m_imageScale")); RPI::PassFilter compositePassFilter = RPI::PassFilter::CreateWithPassHierarchy(compositePassHierarchy);
compositePass->GetShaderResourceGroup()->SetConstant(constantIndex, aznumeric_cast<uint32_t>(1.0f / sizeMultiplier)); RPI::PassSystemInterface::Get()->ForEachPass(compositePassFilter, [sizeMultiplier](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
{
RPI::FullscreenTrianglePass* compositePass = static_cast<RPI::FullscreenTrianglePass*>(pass);
RHI::ShaderInputNameIndex imageScaleShaderInput = "m_imageScale";
compositePass->GetShaderResourceGroup()->SetConstant(imageScaleShaderInput, aznumeric_cast<uint32_t>(1.0f / sizeMultiplier));
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
});
} }
} }
} // namespace Render } // namespace Render

@ -603,12 +603,12 @@ namespace AZ
RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice(); RHI::Ptr<RHI::Device> device = RHI::RHISystemInterface::Get()->GetDevice();
if (device->GetFeatures().m_rayTracing == false) if (device->GetFeatures().m_rayTracing == false)
{ {
RPI::PassHierarchyFilter updatePassFilter(AZ::Name("DiffuseProbeGridUpdatePass")); RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("DiffuseProbeGridUpdatePass"), GetParentScene());
const AZStd::vector<RPI::Pass*>& updatePasses = RPI::PassSystemInterface::Get()->FindPasses(updatePassFilter); RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
for (RPI::Pass* pass : updatePasses) {
{ pass->SetEnabled(false);
pass->SetEnabled(false); return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
} });
} }
} }

@ -10,9 +10,10 @@
#include <ACES/Aces.h> #include <ACES/Aces.h>
#include <Atom/Feature/ACES/AcesDisplayMapperFeatureProcessor.h> #include <Atom/Feature/ACES/AcesDisplayMapperFeatureProcessor.h>
#include <Atom/RPI.Public/Pass/FullscreenTrianglePass.h> #include <Atom/RPI.Public/Pass/FullscreenTrianglePass.h>
#include <Atom/RPI.Public/Pass/PassUtils.h> #include <Atom/RPI.Public/Pass/PassFilter.h>
#include <Atom/RPI.Public/Pass/PassFactory.h> #include <Atom/RPI.Public/Pass/PassFactory.h>
#include <Atom/RPI.Public/Pass/PassSystemInterface.h> #include <Atom/RPI.Public/Pass/PassSystemInterface.h>
#include <Atom/RPI.Public/Pass/PassUtils.h>
#include <Atom/RPI.Public/Pass/Specific/SwapChainPass.h> #include <Atom/RPI.Public/Pass/Specific/SwapChainPass.h>
#include <Atom/RPI.Public/RenderPipeline.h> #include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Public/RPIUtils.h> #include <Atom/RPI.Public/RPIUtils.h>
@ -66,22 +67,14 @@ namespace AZ
{ {
// Need to invalidate the CopyToSwapChain pass so that it updates the pipeline state in the event that // Need to invalidate the CopyToSwapChain pass so that it updates the pipeline state in the event that
// the swapchain format changed (for example, moving from LDR to HDR display) // the swapchain format changed (for example, moving from LDR to HDR display)
auto* passSystem = RPI::PassSystemInterface::Get(); const Name copyToSwapChainPassName("CopyToSwapChain");
const Name fullscreenCopyTemplateName("FullscreenCopyTemplate"); RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(copyToSwapChainPassName, GetRenderPipeline());
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
if (passSystem->HasPassesForTemplateName(fullscreenCopyTemplateName))
{
const AZStd::vector<RPI::Pass*>& passes = passSystem->GetPassesForTemplateName(fullscreenCopyTemplateName);
for (RPI::Pass* pass : passes)
{ {
RPI::FullscreenTrianglePass* fullscreenTrianglePass = azrtti_cast<RPI::FullscreenTrianglePass*>(pass); pass->QueueForInitialization();
const Name& passName = fullscreenTrianglePass->GetName(); return RPI::PassFilterExecutionFlow::StopVisitingPasses;
if (passName.GetStringView() == "CopyToSwapChain") });
{
fullscreenTrianglePass->QueueForInitialization();
}
}
}
ConfigureDisplayParameters(); ConfigureDisplayParameters();
} }

@ -372,29 +372,25 @@ namespace AZ
} }
m_latestCaptureInfo.clear(); m_latestCaptureInfo.clear();
// Find the pass first RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass<RPI::ImageAttachmentPreviewPass>();
RPI::PassClassFilter<RPI::ImageAttachmentPreviewPass> passFilter; AZ::RPI::ImageAttachmentPreviewPass* previewPass = azrtti_cast<AZ::RPI::ImageAttachmentPreviewPass*>(RPI::PassSystemInterface::Get()->FindFirstPass(passFilter));
AZStd::vector<AZ::RPI::Pass*> foundPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter); if (!previewPass)
if (foundPasses.size() == 0)
{ {
AZ_Warning("FrameCaptureSystemComponent", false, "Failed to find an ImageAttachmentPreviewPass pass "); AZ_Warning("FrameCaptureSystemComponent", false, "Failed to find an ImageAttachmentPreviewPass");
return false; return false;
} }
AZ::RPI::ImageAttachmentPreviewPass* previewPass = azrtti_cast<AZ::RPI::ImageAttachmentPreviewPass*>(foundPasses[0]);
bool result = previewPass->ReadbackOutput(m_readback); bool result = previewPass->ReadbackOutput(m_readback);
if (result) if (result)
{ {
m_state = State::Pending; m_state = State::Pending;
m_result = FrameCaptureResult::None; m_result = FrameCaptureResult::None;
SystemTickBus::Handler::BusConnect(); SystemTickBus::Handler::BusConnect();
return true;
} }
else
{ AZ_Warning("FrameCaptureSystemComponent", false, "CaptureScreenshotWithPreview. Failed to readback output from the ImageAttachmentPreviewPass");
AZ_Warning("FrameCaptureSystemComponent", false, "CaptureScreenshotWithPreview. Failed to readback output from the ImageAttachmentPreviewPass");; return false;
}
return result;
} }
bool FrameCaptureSystemComponent::CapturePassAttachment(const AZStd::vector<AZStd::string>& passHierarchy, const AZStd::string& slot, bool FrameCaptureSystemComponent::CapturePassAttachment(const AZStd::vector<AZStd::string>& passHierarchy, const AZStd::string& slot,
@ -405,6 +401,12 @@ namespace AZ
return false; return false;
} }
if (passHierarchy.size() == 0)
{
AZ_Warning("FrameCaptureSystemComponent", false, "Empty data in passHierarchy");
return false;
}
InitReadback(); InitReadback();
if (m_state != State::Idle) if (m_state != State::Idle)
@ -426,17 +428,15 @@ namespace AZ
} }
m_latestCaptureInfo.clear(); m_latestCaptureInfo.clear();
// Find the pass first RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassHierarchy(passHierarchy);
AZ::RPI::PassHierarchyFilter passFilter(passHierarchy); RPI::Pass* pass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter);
AZStd::vector<AZ::RPI::Pass*> foundPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter);
if (foundPasses.size() == 0) if (!pass)
{ {
AZ_Warning("FrameCaptureSystemComponent", false, "Failed to find pass from %s", passFilter.ToString().c_str()); AZ_Warning("FrameCaptureSystemComponent", false, "Failed to find pass from %s", passHierarchy[0].c_str());
return false; return false;
} }
AZ::RPI::Pass* pass = foundPasses[0];
if (pass->ReadbackAttachment(m_readback, Name(slot), option)) if (pass->ReadbackAttachment(m_readback, Name(slot), option))
{ {
m_state = State::Pending; m_state = State::Pending;
@ -444,6 +444,7 @@ namespace AZ
SystemTickBus::Handler::BusConnect(); SystemTickBus::Handler::BusConnect();
return true; return true;
} }
AZ_Warning("FrameCaptureSystemComponent", false, "Failed to readback the attachment bound to pass [%s] slot [%s]", pass->GetName().GetCStr(), slot.c_str()); AZ_Warning("FrameCaptureSystemComponent", false, "Failed to readback the attachment bound to pass [%s] slot [%s]", pass->GetName().GetCStr(), slot.c_str());
return false; return false;
} }

@ -109,15 +109,15 @@ namespace AZ
void ImGuiSystemComponent::ForAllImGuiPasses(PassFunction func) void ImGuiSystemComponent::ForAllImGuiPasses(PassFunction func)
{ {
ImGuiContext* contextToRestore = ImGui::GetCurrentContext(); ImGuiContext* contextToRestore = ImGui::GetCurrentContext();
RPI::PassClassFilter<ImGuiPass> filter;
auto imguiPasses = RPI::PassSystemInterface::Get()->FindPasses(filter); RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass<ImGuiPass>();
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [func](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
for (RPI::Pass* pass : imguiPasses) {
{ ImGuiPass* imguiPass = azrtti_cast<ImGuiPass*>(pass);
ImGuiPass* imguiPass = azrtti_cast<ImGuiPass*>(pass); ImGui::SetCurrentContext(imguiPass->GetContext());
ImGui::SetCurrentContext(imguiPass->GetContext()); func(imguiPass);
func(imguiPass); return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
} });
ImGui::SetCurrentContext(contextToRestore); ImGui::SetCurrentContext(contextToRestore);
} }
@ -169,29 +169,37 @@ namespace AZ
return false; return false;
} }
bool ImGuiSystemComponent::PushActiveContextFromPass(const RPI::PassHierarchyFilter& passHierarchyFilter) bool ImGuiSystemComponent::PushActiveContextFromPass(const AZStd::vector<AZStd::string>& passHierarchyFilter)
{ {
AZStd::vector<AZ::RPI::Pass*> foundPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passHierarchyFilter); if (passHierarchyFilter.size() == 0)
{
AZ_Warning("ImGuiSystemComponent", false, "passHierarchyFilter is empty");
return false;
}
AZStd::vector<ImGuiPass*> foundImGuiPasses; AZStd::vector<ImGuiPass*> foundImGuiPasses;
for (RPI::Pass* pass : foundPasses) RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassHierarchy(passHierarchyFilter);
{ RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [&foundImGuiPasses](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
ImGuiPass* imGuiPass = azrtti_cast<ImGuiPass*>(pass);
if (imGuiPass)
{ {
foundImGuiPasses.push_back(imGuiPass); ImGuiPass* imGuiPass = azrtti_cast<ImGuiPass*>(pass);
} if (imGuiPass)
} {
foundImGuiPasses.push_back(imGuiPass);
}
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
});
if (foundImGuiPasses.size() == 0) if (foundImGuiPasses.size() == 0)
{ {
AZ_Warning("ImGuiSystemComponent", false, "Failed to find ImGui pass to activate from %s", passHierarchyFilter.ToString().c_str()); AZ_Warning("ImGuiSystemComponent", false, "Failed to find ImGui pass to activate from %s", passHierarchyFilter[0].c_str());
return false; return false;
} }
if (foundImGuiPasses.size() > 1) if (foundImGuiPasses.size() > 1)
{ {
AZ_Warning("ImGuiSystemComponent", false, "Found more than one ImGui pass to activate from %s, only activating first one.", passHierarchyFilter.ToString().c_str()); AZ_Warning("ImGuiSystemComponent", false, "Found more than one ImGui pass to activate from %s, only activating first one.", passHierarchyFilter[0].c_str());
} }
ImGuiContext* context = foundImGuiPasses.at(0)->GetContext(); ImGuiContext* context = foundImGuiPasses.at(0)->GetContext();

@ -56,7 +56,7 @@ namespace AZ
ImGuiPass* GetDefaultImGuiPass() override; ImGuiPass* GetDefaultImGuiPass() override;
bool PushActiveContextFromDefaultPass() override; bool PushActiveContextFromDefaultPass() override;
bool PushActiveContextFromPass(const RPI::PassHierarchyFilter& passHierarchy) override; bool PushActiveContextFromPass(const AZStd::vector<AZStd::string>& passHierarchy) override;
bool PopActiveContext() override; bool PopActiveContext() override;
ImGuiContext* GetActiveContext() override; ImGuiContext* GetActiveContext() override;

@ -15,6 +15,7 @@
#include <AzFramework/Asset/AssetSystemBus.h> #include <AzFramework/Asset/AssetSystemBus.h>
#include <Atom/RPI.Public/Image/ImageSystemInterface.h> #include <Atom/RPI.Public/Image/ImageSystemInterface.h>
#include <Atom/RPI.Public/Pass/PassFilter.h>
#include <Atom/RPI.Public/Pass/PassSystemInterface.h> #include <Atom/RPI.Public/Pass/PassSystemInterface.h>
#include <Atom/RPI.Public/RenderPipeline.h> #include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Public/RPIUtils.h> #include <Atom/RPI.Public/RPIUtils.h>
@ -259,24 +260,19 @@ namespace AZ
// [GFX TODO][ATOM-3035]This function is temporary and will change with improvement to the draw list tag system // [GFX TODO][ATOM-3035]This function is temporary and will change with improvement to the draw list tag system
void DepthOfFieldSettings::UpdateAutoFocusDepth(bool enabled) void DepthOfFieldSettings::UpdateAutoFocusDepth(bool enabled)
{ {
auto* passSystem = AZ::RPI::PassSystemInterface::Get();
const Name TemplateNameReadBackFocusDepth = Name("DepthOfFieldReadBackFocusDepthTemplate"); const Name TemplateNameReadBackFocusDepth = Name("DepthOfFieldReadBackFocusDepthTemplate");
if (passSystem->HasPassesForTemplateName(TemplateNameReadBackFocusDepth)) // [GFX TODO][ATOM-4908] multiple camera should be distingushed.
{ RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(TemplateNameReadBackFocusDepth, GetParentScene());
const AZStd::vector<RPI::Pass*>& dofPasses = passSystem->GetPassesForTemplateName(TemplateNameReadBackFocusDepth); RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this, enabled](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
for (RPI::Pass* pass : dofPasses)
{ {
auto* dofPass = azrtti_cast<AZ::Render::DepthOfFieldReadBackFocusDepthPass*>(pass); auto* dofPass = azrtti_cast<AZ::Render::DepthOfFieldReadBackFocusDepthPass*>(pass);
// Check this pass belongs to a render pipeline of the scene. if (enabled)
// [GFX TODO][ATOM-4908] multiple camera should be distingushed.
const RPI::RenderPipelineId pipelineId = dofPass->GetRenderPipeline()->GetId();
if (enabled && GetParentScene()->GetRenderPipeline(pipelineId))
{ {
m_normalizedFocusDistanceForAutoFocus = dofPass->GetNormalizedFocusDistanceForAutoFocus(); m_normalizedFocusDistanceForAutoFocus = dofPass->GetNormalizedFocusDistanceForAutoFocus();
} }
} return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
} });
} }
void DepthOfFieldSettings::SetCameraEntityId(EntityId cameraEntityId) void DepthOfFieldSettings::SetCameraEntityId(EntityId cameraEntityId)

@ -10,6 +10,7 @@
#include <AzCore/Math/MathUtils.h> #include <AzCore/Math/MathUtils.h>
#include <AzCore/Serialization/SerializeContext.h> #include <AzCore/Serialization/SerializeContext.h>
#include <Atom/RPI.Public/Pass/PassFilter.h>
#include <Atom/RPI.Public/Pass/PassSystemInterface.h> #include <Atom/RPI.Public/Pass/PassSystemInterface.h>
#include <Atom/RPI.Public/RenderPipeline.h> #include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Public/Shader/ShaderResourceGroup.h> #include <Atom/RPI.Public/Shader/ShaderResourceGroup.h>
@ -188,21 +189,21 @@ namespace AZ
void ExposureControlSettings::UpdateLuminanceHeatmap() void ExposureControlSettings::UpdateLuminanceHeatmap()
{ {
auto* passSystem = AZ::RPI::PassSystemInterface::Get();
// [GFX-TODO][ATOM-13194] Support multiple views for the luminance heatmap // [GFX-TODO][ATOM-13194] Support multiple views for the luminance heatmap
// [GFX-TODO][ATOM-13224] Remove UpdateLuminanceHeatmap and UpdateEyeAdaptationPass // [GFX-TODO][ATOM-13224] Remove UpdateLuminanceHeatmap and UpdateEyeAdaptationPass
const RPI::Ptr<RPI::Pass> luminanceHeatmap = passSystem->GetRootPass()->FindPassByNameRecursive(m_luminanceHeatmapNameId); RPI::PassFilter heatmapPassFilter = RPI::PassFilter::CreateWithPassName(m_luminanceHeatmapNameId, GetParentScene());
if (luminanceHeatmap) RPI::PassSystemInterface::Get()->ForEachPass(heatmapPassFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
{ {
luminanceHeatmap->SetEnabled(m_heatmapEnabled); pass->SetEnabled(m_heatmapEnabled);
} return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
});
const RPI::Ptr<RPI::Pass> histogramGenerator = passSystem->GetRootPass()->FindPassByNameRecursive(m_luminanceHistogramGeneratorNameId);
if (histogramGenerator) RPI::PassFilter histogramPassFilter = RPI::PassFilter::CreateWithPassName(m_luminanceHistogramGeneratorNameId, GetParentScene());
{ RPI::PassSystemInterface::Get()->ForEachPass(histogramPassFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
histogramGenerator->SetEnabled(m_heatmapEnabled); {
} pass->SetEnabled(m_heatmapEnabled);
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
});
} }
void ExposureControlSettings::UpdateBuffer() void ExposureControlSettings::UpdateBuffer()

@ -31,12 +31,14 @@ namespace AZ
0, 0,
[](const uint8_t& value) [](const uint8_t& value)
{ {
auto passes = RPI::PassSystem::Get()->FindPasses(RPI::PassClassFilter<LookModificationCompositePass>()); RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass<LookModificationCompositePass>();
for (auto* pass : passes) RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [value](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
{ {
LookModificationCompositePass* lookModPass = azrtti_cast<LookModificationCompositePass*>(pass); LookModificationCompositePass* lookModPass = azrtti_cast<LookModificationCompositePass*>(pass);
lookModPass->SetSampleQuality(LookModificationCompositePass::SampleQuality(value)); lookModPass->SetSampleQuality(LookModificationCompositePass::SampleQuality(value));
}
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
});
}, },
ConsoleFunctorFlags::Null, ConsoleFunctorFlags::Null,
"This can be increased to deal with particularly tricky luts. Range (0-2). 0 (default) - Standard linear sampling. 1 - 7 tap b-spline sampling. 2 - 19 tap b-spline sampling." "This can be increased to deal with particularly tricky luts. Range (0-2). 0 (default) - Standard linear sampling. 1 - 7 tap b-spline sampling. 2 - 19 tap b-spline sampling."

@ -16,6 +16,7 @@
#include <Atom/RHI/Factory.h> #include <Atom/RHI/Factory.h>
#include <Atom/RPI.Public/Pass/PassFilter.h>
#include <Atom/RPI.Public/Pass/PassSystemInterface.h> #include <Atom/RPI.Public/Pass/PassSystemInterface.h>
#include <Atom/RPI.Public/RPISystemInterface.h> #include <Atom/RPI.Public/RPISystemInterface.h>
#include <Atom/RPI.Public/Scene.h> #include <Atom/RPI.Public/Scene.h>
@ -71,26 +72,18 @@ namespace AZ
void SMAAFeatureProcessor::UpdateConvertToPerceptualPass() void SMAAFeatureProcessor::UpdateConvertToPerceptualPass()
{ {
auto* passSystem = AZ::RPI::PassSystemInterface::Get(); RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(m_convertToPerceptualColorPassTemplateNameId, GetParentScene());
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
if (passSystem->HasPassesForTemplateName(m_convertToPerceptualColorPassTemplateNameId))
{
const AZStd::vector<RPI::Pass*>& convertToPerceptualColorPasses = passSystem->GetPassesForTemplateName(m_convertToPerceptualColorPassTemplateNameId);
for (RPI::Pass* pass : convertToPerceptualColorPasses)
{ {
pass->SetEnabled(m_data.m_enable); pass->SetEnabled(m_data.m_enable);
} return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
} });
} }
void SMAAFeatureProcessor::UpdateEdgeDetectionPass() void SMAAFeatureProcessor::UpdateEdgeDetectionPass()
{ {
auto* passSystem = AZ::RPI::PassSystemInterface::Get(); RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(m_edgeDetectioPassTemplateNameId, GetParentScene());
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
if (passSystem->HasPassesForTemplateName(m_edgeDetectioPassTemplateNameId))
{
const AZStd::vector<RPI::Pass*>& edgeDetectionPasses = passSystem->GetPassesForTemplateName(m_edgeDetectioPassTemplateNameId);
for (RPI::Pass* pass : edgeDetectionPasses)
{ {
auto* edgeDetectionPass = azrtti_cast<AZ::Render::SMAAEdgeDetectionPass*>(pass); auto* edgeDetectionPass = azrtti_cast<AZ::Render::SMAAEdgeDetectionPass*>(pass);
@ -106,18 +99,14 @@ namespace AZ
edgeDetectionPass->SetPredicationScale(m_data.m_predicationScale); edgeDetectionPass->SetPredicationScale(m_data.m_predicationScale);
edgeDetectionPass->SetPredicationStrength(m_data.m_predicationStrength); edgeDetectionPass->SetPredicationStrength(m_data.m_predicationStrength);
} }
} return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
} });
} }
void SMAAFeatureProcessor::UpdateBlendingWeightCalculationPass() void SMAAFeatureProcessor::UpdateBlendingWeightCalculationPass()
{ {
auto* passSystem = AZ::RPI::PassSystemInterface::Get(); RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(m_blendingWeightCalculationPassTemplateNameId, GetParentScene());
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
if (passSystem->HasPassesForTemplateName(m_blendingWeightCalculationPassTemplateNameId))
{
const AZStd::vector<RPI::Pass*>& blendingWeightCalculationPasses = passSystem->GetPassesForTemplateName(m_blendingWeightCalculationPassTemplateNameId);
for (RPI::Pass* pass : blendingWeightCalculationPasses)
{ {
auto* blendingWeightCalculationPass = azrtti_cast<AZ::Render::SMAABlendingWeightCalculationPass*>(pass); auto* blendingWeightCalculationPass = azrtti_cast<AZ::Render::SMAABlendingWeightCalculationPass*>(pass);
@ -130,18 +119,14 @@ namespace AZ
blendingWeightCalculationPass->SetDiagonalDetectionEnable(m_data.m_enableDiagonalDetection); blendingWeightCalculationPass->SetDiagonalDetectionEnable(m_data.m_enableDiagonalDetection);
blendingWeightCalculationPass->SetCornerDetectionEnable(m_data.m_enableCornerDetection); blendingWeightCalculationPass->SetCornerDetectionEnable(m_data.m_enableCornerDetection);
} }
} return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
} });
} }
void SMAAFeatureProcessor::UpdateNeighborhoodBlendingPass() void SMAAFeatureProcessor::UpdateNeighborhoodBlendingPass()
{ {
auto* passSystem = AZ::RPI::PassSystemInterface::Get(); RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(m_neighborhoodBlendingPassTemplateNameId, GetParentScene());
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
if (passSystem->HasPassesForTemplateName(m_neighborhoodBlendingPassTemplateNameId))
{
const AZStd::vector<RPI::Pass*>& neighborhoodBlendingPasses = passSystem->GetPassesForTemplateName(m_neighborhoodBlendingPassTemplateNameId);
for (RPI::Pass* pass : neighborhoodBlendingPasses)
{ {
auto* neighborhoodBlendingPass = azrtti_cast<AZ::Render::SMAANeighborhoodBlendingPass*>(pass); auto* neighborhoodBlendingPass = azrtti_cast<AZ::Render::SMAANeighborhoodBlendingPass*>(pass);
@ -153,8 +138,8 @@ namespace AZ
{ {
neighborhoodBlendingPass->SetOutputMode(SMAAOutputMode::PassThrough); neighborhoodBlendingPass->SetOutputMode(SMAAOutputMode::PassThrough);
} }
} return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
} });
} }
void SMAAFeatureProcessor::Render([[maybe_unused]] const SMAAFeatureProcessor::RenderPacket& packet) void SMAAFeatureProcessor::Render([[maybe_unused]] const SMAAFeatureProcessor::RenderPacket& packet)

@ -377,14 +377,7 @@ namespace AZ
bool ProfilingCaptureSystemComponent::CapturePassTimestamp(const AZStd::string& outputFilePath) bool ProfilingCaptureSystemComponent::CapturePassTimestamp(const AZStd::string& outputFilePath)
{ {
// Find the root pass. RPI::Pass* root = AZ::RPI::PassSystemInterface::Get()->GetRootPass().get();
AZStd::vector<RPI::Pass*> passes = FindPasses({ "Root" });
if (passes.empty())
{
return false;
}
RPI::Pass* root = passes[0];
// Enable all the Timestamp queries in passes. // Enable all the Timestamp queries in passes.
root->SetTimestampQueryEnabled(true); root->SetTimestampQueryEnabled(true);
@ -465,14 +458,7 @@ namespace AZ
bool ProfilingCaptureSystemComponent::CapturePassPipelineStatistics(const AZStd::string& outputFilePath) bool ProfilingCaptureSystemComponent::CapturePassPipelineStatistics(const AZStd::string& outputFilePath)
{ {
// Find the root pass. RPI::Pass* root = AZ::RPI::PassSystemInterface::Get()->GetRootPass().get();
AZStd::vector<RPI::Pass*> passes = FindPasses({ "Root" });
if (passes.empty())
{
return false;
}
RPI::Pass* root = passes[0];
// Enable all the PipelineStatistics queries in passes. // Enable all the PipelineStatistics queries in passes.
root->SetPipelineStatisticsQueryEnabled(true); root->SetPipelineStatisticsQueryEnabled(true);
@ -572,19 +558,6 @@ namespace AZ
return passes; return passes;
} }
AZStd::vector<RPI::Pass*> ProfilingCaptureSystemComponent::FindPasses(AZStd::vector<AZStd::string>&& passHierarchy) const
{
// Find the pass first.
RPI::PassHierarchyFilter passFilter(passHierarchy);
AZStd::vector<AZ::RPI::Pass*> foundPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter);
if (foundPasses.size() == 0)
{
AZ_Warning("ProfilingCaptureSystemComponent", false, "Failed to find pass from %s", passFilter.ToString().c_str());
}
return foundPasses;
}
void ProfilingCaptureSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time) void ProfilingCaptureSystemComponent::OnTick([[maybe_unused]] float deltaTime, [[maybe_unused]] ScriptTimePoint time)
{ {
// Update the delayed captures // Update the delayed captures

@ -78,8 +78,6 @@ namespace AZ
// Recursively collect all the passes from the root pass. // Recursively collect all the passes from the root pass.
AZStd::vector<const RPI::Pass*> CollectPassesRecursively(const RPI::Pass* root) const; AZStd::vector<const RPI::Pass*> CollectPassesRecursively(const RPI::Pass* root) const;
AZStd::vector<AZ::RPI::Pass*> FindPasses(AZStd::vector<AZStd::string>&& passHierarchy) const;
DelayedQueryCaptureHelper m_timestampCapture; DelayedQueryCaptureHelper m_timestampCapture;
DelayedQueryCaptureHelper m_cpuFrameTimeStatisticsCapture; DelayedQueryCaptureHelper m_cpuFrameTimeStatisticsCapture;
DelayedQueryCaptureHelper m_pipelineStatisticsCapture; DelayedQueryCaptureHelper m_pipelineStatisticsCapture;

@ -28,16 +28,17 @@ namespace AZ
void ReflectionCopyFrameBufferPass::BuildInternal() void ReflectionCopyFrameBufferPass::BuildInternal()
{ {
RPI::PassHierarchyFilter passFilter(AZ::Name("ReflectionScreenSpaceBlurPass")); RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("ReflectionScreenSpaceBlurPass"), GetRenderPipeline());
const AZStd::vector<RPI::Pass*>& passes = RPI::PassSystemInterface::Get()->FindPasses(passFilter); RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
if (!passes.empty()) {
{ Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast<ReflectionScreenSpaceBlurPass*>(pass);
Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast<ReflectionScreenSpaceBlurPass*>(passes.front()); Data::Instance<RPI::AttachmentImage>& frameBufferAttachment = blurPass->GetFrameBufferImageAttachment();
Data::Instance<RPI::AttachmentImage>& frameBufferAttachment = blurPass->GetFrameBufferImageAttachment();
RPI::PassAttachmentBinding& outputBinding = GetOutputBinding(0); RPI::PassAttachmentBinding& outputBinding = GetOutputBinding(0);
AttachImageToSlot(outputBinding.m_name, frameBufferAttachment); AttachImageToSlot(outputBinding.m_name, frameBufferAttachment);
}
return RPI::PassFilterExecutionFlow::StopVisitingPasses;
});
FullscreenTrianglePass::BuildInternal(); FullscreenTrianglePass::BuildInternal();
} }

@ -150,7 +150,7 @@ namespace AZ
auto transientImageDesc = RHI::ImageDescriptor::Create2D(imageBindFlags, mipSize.m_width, mipSize.m_height, RHI::Format::R16G16B16A16_FLOAT); auto transientImageDesc = RHI::ImageDescriptor::Create2D(imageBindFlags, mipSize.m_width, mipSize.m_height, RHI::Format::R16G16B16A16_FLOAT);
RPI::PassAttachment* transientPassAttachment = aznew RPI::PassAttachment(); RPI::PassAttachment* transientPassAttachment = aznew RPI::PassAttachment();
AZStd::string transientAttachmentName = AZStd::string::format("ReflectionScreenSpace_BlurImage%d", mip); AZStd::string transientAttachmentName = AZStd::string::format("%s.ReflectionScreenSpace_BlurImage%d", GetPathName().GetCStr(), mip);
transientPassAttachment->m_name = transientAttachmentName; transientPassAttachment->m_name = transientAttachmentName;
transientPassAttachment->m_path = transientAttachmentName; transientPassAttachment->m_path = transientAttachmentName;
transientPassAttachment->m_lifetime = RHI::AttachmentLifetimeType::Transient; transientPassAttachment->m_lifetime = RHI::AttachmentLifetimeType::Transient;

@ -33,20 +33,22 @@ namespace AZ
return; return;
} }
RPI::PassHierarchyFilter passFilter(AZ::Name("ReflectionScreenSpaceBlurPass")); RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("ReflectionScreenSpaceBlurPass"), GetRenderPipeline());
const AZStd::vector<RPI::Pass*>& passes = RPI::PassSystemInterface::Get()->FindPasses(passFilter);
if (!passes.empty())
{
Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast<ReflectionScreenSpaceBlurPass*>(passes.front());
// compute the max mip level based on the available mips in the previous frame image, and capping it RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
// to stay within a range that has reasonable data {
const uint32_t MaxNumRoughnessMips = 8; Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast<ReflectionScreenSpaceBlurPass*>(pass);
uint32_t maxMipLevel = AZStd::min(MaxNumRoughnessMips, blurPass->GetNumBlurMips()) - 1;
auto constantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_maxMipLevel")); // compute the max mip level based on the available mips in the previous frame image, and capping it
m_shaderResourceGroup->SetConstant(constantIndex, maxMipLevel); // to stay within a range that has reasonable data
} const uint32_t MaxNumRoughnessMips = 8;
uint32_t maxMipLevel = AZStd::min(MaxNumRoughnessMips, blurPass->GetNumBlurMips()) - 1;
auto constantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_maxMipLevel"));
m_shaderResourceGroup->SetConstant(constantIndex, maxMipLevel);
return RPI::PassFilterExecutionFlow::StopVisitingPasses;
});
FullscreenTrianglePass::CompileResources(context); FullscreenTrianglePass::CompileResources(context);
} }

@ -313,52 +313,38 @@ namespace AZ::Render
void ProjectedShadowFeatureProcessor::CachePasses() void ProjectedShadowFeatureProcessor::CachePasses()
{ {
const AZStd::vector<RPI::RenderPipelineId> validPipelineIds = CacheProjectedShadowmapsPass(); CacheProjectedShadowmapsPass();
CacheEsmShadowmapsPass(validPipelineIds); CacheEsmShadowmapsPass();
m_shadowmapPassNeedsUpdate = true; m_shadowmapPassNeedsUpdate = true;
} }
AZStd::vector<RPI::RenderPipelineId> ProjectedShadowFeatureProcessor::CacheProjectedShadowmapsPass() void ProjectedShadowFeatureProcessor::CacheProjectedShadowmapsPass()
{ {
const AZStd::vector<RPI::RenderPipelinePtr>& renderPipelines = GetParentScene()->GetRenderPipelines();
const auto* passSystem = RPI::PassSystemInterface::Get();;
const AZStd::vector<RPI::Pass*>& passes = passSystem->GetPassesForTemplateName(Name("ProjectedShadowmapsTemplate"));
AZStd::vector<RPI::RenderPipelineId> validPipelineIds;
m_projectedShadowmapsPasses.clear(); m_projectedShadowmapsPasses.clear();
for (RPI::Pass* pass : passes) RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(Name("ProjectedShadowmapsTemplate"), GetParentScene());
{ RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
ProjectedShadowmapsPass* shadowPass = static_cast<ProjectedShadowmapsPass*>(pass);
for (const RPI::RenderPipelinePtr& pipeline : renderPipelines)
{ {
if (pipeline.get() == shadowPass->GetRenderPipeline()) ProjectedShadowmapsPass* shadowPass = static_cast<ProjectedShadowmapsPass*>(pass);
{ m_projectedShadowmapsPasses.emplace_back(shadowPass);
m_projectedShadowmapsPasses.emplace_back(shadowPass); return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
validPipelineIds.push_back(shadowPass->GetRenderPipeline()->GetId()); });
}
}
}
return validPipelineIds;
} }
void ProjectedShadowFeatureProcessor::CacheEsmShadowmapsPass(const AZStd::vector<RPI::RenderPipelineId>& validPipelineIds) void ProjectedShadowFeatureProcessor::CacheEsmShadowmapsPass()
{ {
const Name LightTypeName = Name("projected"); const Name LightTypeName = Name("projected");
const auto* passSystem = RPI::PassSystemInterface::Get();
const AZStd::vector<RPI::Pass*> passes = passSystem->GetPassesForTemplateName(Name("EsmShadowmapsTemplate"));
m_esmShadowmapsPasses.clear(); m_esmShadowmapsPasses.clear();
for (RPI::Pass* pass : passes) RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(Name("EsmShadowmapsTemplate"), GetParentScene());
{ RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this, LightTypeName](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
EsmShadowmapsPass* esmPass = static_cast<EsmShadowmapsPass*>(pass);
if (esmPass->GetRenderPipeline() &&
AZStd::find(validPipelineIds.begin(), validPipelineIds.end(), esmPass->GetRenderPipeline()->GetId()) != validPipelineIds.end() &&
esmPass->GetLightTypeName() == LightTypeName)
{ {
m_esmShadowmapsPasses.emplace_back(esmPass); EsmShadowmapsPass* esmPass = static_cast<EsmShadowmapsPass*>(pass);
} if (esmPass->GetLightTypeName() == LightTypeName)
} {
m_esmShadowmapsPasses.emplace_back(esmPass);
}
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
});
} }
void ProjectedShadowFeatureProcessor::UpdateFilterParameters() void ProjectedShadowFeatureProcessor::UpdateFilterParameters()

@ -97,8 +97,8 @@ namespace AZ::Render
// Functions for caching the ProjectedShadowmapsPass and EsmShadowmapsPass. // Functions for caching the ProjectedShadowmapsPass and EsmShadowmapsPass.
void CachePasses(); void CachePasses();
AZStd::vector<RPI::RenderPipelineId> CacheProjectedShadowmapsPass(); void CacheProjectedShadowmapsPass();
void CacheEsmShadowmapsPass(const AZStd::vector<RPI::RenderPipelineId>& validPipelineIds); void CacheEsmShadowmapsPass();
//! Functions to update the parameter of Gaussian filter used in ESM. //! Functions to update the parameter of Gaussian filter used in ESM.
void UpdateFilterParameters(); void UpdateFilterParameters();

@ -17,6 +17,7 @@
#include <MorphTargets/MorphTargetDispatchItem.h> #include <MorphTargets/MorphTargetDispatchItem.h>
#include <Atom/RPI.Public/Model/ModelLodUtils.h> #include <Atom/RPI.Public/Model/ModelLodUtils.h>
#include <Atom/RPI.Public/Pass/PassFilter.h>
#include <Atom/RPI.Public/Pass/PassSystemInterface.h> #include <Atom/RPI.Public/Pass/PassSystemInterface.h>
#include <Atom/RPI.Public/RPIUtils.h> #include <Atom/RPI.Public/RPIUtils.h>
#include <Atom/RPI.Public/Shader/Shader.h> #include <Atom/RPI.Public/Shader/Shader.h>
@ -241,12 +242,12 @@ namespace AZ
void SkinnedMeshFeatureProcessor::OnRenderPipelineAdded(RPI::RenderPipelinePtr pipeline) void SkinnedMeshFeatureProcessor::OnRenderPipelineAdded(RPI::RenderPipelinePtr pipeline)
{ {
InitSkinningAndMorphPass(pipeline->GetRootPass()); InitSkinningAndMorphPass(pipeline.get());
} }
void SkinnedMeshFeatureProcessor::OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline) void SkinnedMeshFeatureProcessor::OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline)
{ {
InitSkinningAndMorphPass(renderPipeline->GetRootPass()); InitSkinningAndMorphPass(renderPipeline);
} }
void SkinnedMeshFeatureProcessor::OnBeginPrepareRender() void SkinnedMeshFeatureProcessor::OnBeginPrepareRender()
@ -289,9 +290,10 @@ namespace AZ
return false; return false;
} }
void SkinnedMeshFeatureProcessor::InitSkinningAndMorphPass(const RPI::Ptr<RPI::ParentPass> pipelineRootPass) void SkinnedMeshFeatureProcessor::InitSkinningAndMorphPass(RPI::RenderPipeline* renderPipeline)
{ {
RPI::Ptr<RPI::Pass> skinningPass = pipelineRootPass->FindPassByNameRecursive(AZ::Name{ "SkinningPass" }); RPI::PassFilter skinPassFilter = RPI::PassFilter::CreateWithPassName(AZ::Name{ "SkinningPass" }, renderPipeline);
RPI::Ptr<RPI::Pass> skinningPass = RPI::PassSystemInterface::Get()->FindFirstPass(skinPassFilter);
if (skinningPass) if (skinningPass)
{ {
SkinnedMeshComputePass* skinnedMeshComputePass = azdynamic_cast<SkinnedMeshComputePass*>(skinningPass.get()); SkinnedMeshComputePass* skinnedMeshComputePass = azdynamic_cast<SkinnedMeshComputePass*>(skinningPass.get());
@ -310,7 +312,8 @@ namespace AZ
} }
} }
RPI::Ptr<RPI::Pass> morphTargetPass = pipelineRootPass->FindPassByNameRecursive(AZ::Name{ "MorphTargetPass" }); RPI::PassFilter morphPassFilter = RPI::PassFilter::CreateWithPassName(AZ::Name{ "MorphTargetPass" }, renderPipeline);
RPI::Ptr<RPI::Pass> morphTargetPass = RPI::PassSystemInterface::Get()->FindFirstPass(morphPassFilter);
if (morphTargetPass) if (morphTargetPass)
{ {
MorphTargetComputePass* morphTargetComputePass = azdynamic_cast<MorphTargetComputePass*>(morphTargetPass.get()); MorphTargetComputePass* morphTargetComputePass = azdynamic_cast<MorphTargetComputePass*>(morphTargetPass.get());

@ -66,7 +66,7 @@ namespace AZ
private: private:
AZ_DISABLE_COPY_MOVE(SkinnedMeshFeatureProcessor); AZ_DISABLE_COPY_MOVE(SkinnedMeshFeatureProcessor);
void InitSkinningAndMorphPass(const RPI::Ptr<RPI::ParentPass> pipelineRootPass); void InitSkinningAndMorphPass(RPI::RenderPipeline* renderPipeline);
SkinnedMeshRenderProxyInterfaceHandle AcquireRenderProxyInterface(const SkinnedMeshRenderProxyDesc& desc) override; SkinnedMeshRenderProxyInterfaceHandle AcquireRenderProxyInterface(const SkinnedMeshRenderProxyDesc& desc) override;
bool ReleaseRenderProxyInterface(SkinnedMeshRenderProxyInterfaceHandle& handle) override; bool ReleaseRenderProxyInterface(SkinnedMeshRenderProxyInterfaceHandle& handle) override;

@ -68,9 +68,6 @@ namespace AZ
template<typename PassType> template<typename PassType>
Ptr<PassType> FindChildPass() const; Ptr<PassType> FindChildPass() const;
//! Searches the tree for the first pass that has same pass name (Depth-first search). Return nullptr if none found.
Ptr<Pass> FindPassByNameRecursive(const Name& passName) const;
//! Gets the list of children. Useful for validating hierarchies //! Gets the list of children. Useful for validating hierarchies
AZStd::array_view<Ptr<Pass>> GetChildren() const; AZStd::array_view<Ptr<Pass>> GetChildren() const;

@ -139,6 +139,10 @@ namespace AZ
//! Returns the number of output attachment bindings //! Returns the number of output attachment bindings
uint32_t GetOutputCount() const; uint32_t GetOutputCount() const;
//! Returns the pass template which was used for create this pass.
//! It may return nullptr if the pass wasn't create from a template
const PassTemplate* GetPassTemplate() const;
//! Enable/disable this pass //! Enable/disable this pass
//! If the pass is disabled, it (and any children if it's a ParentPass) won't be rendered. //! If the pass is disabled, it (and any children if it's a ParentPass) won't be rendered.
void SetEnabled(bool enabled); void SetEnabled(bool enabled);

@ -16,95 +16,85 @@ namespace AZ
{ {
namespace RPI namespace RPI
{ {
// A base class for a filter which can be used to filter passes class Scene;
class PassFilter class RenderPipeline;
{
public:
//! Whether the input pass matches with the filter
virtual bool Matches(const Pass* pass) const = 0;
//! Return the pass' name if a pass name is used for the filter.
//! Return nullptr if the filter doesn't have pass name used for matching
virtual const Name* GetPassName() const = 0;
//! Return this filter's info as a string class PassFilter
virtual AZStd::string ToString() const = 0;
};
//! Filter for passes which have a matching name and also with ordered parents.
//! For example, if the filter is initialized with
//! pass name: "ShadowPass1"
//! pass parents names: "MainPipeline", "Shadow"
//! Passes with these names match the filter:
//! "Root.MainPipeline.SwapChainPass.Shadow.ShadowPass1"
//! or "Root.MainPipeline.Shadow.ShadowPass1"
//! or "MainPipeline.Shadow.Group1.ShadowPass1"
//!
//! Passes with these names wont match:
//! "MainPipeline.ShadowPass1"
//! or "Shadow.MainPipeline.ShadowPass1"
class PassHierarchyFilter
: public PassFilter
{ {
public: public:
AZ_RTTI(PassHierarchyFilter, "{478F169F-BA97-4321-AC34-EDE823997159}", PassFilter); static PassFilter CreateWithPassName(Name passName, const Scene* scene);
AZ_CLASS_ALLOCATOR(PassHierarchyFilter, SystemAllocator, 0); static PassFilter CreateWithPassName(Name passName, const RenderPipeline* renderPipeline);
//! Construct filter with only pass name. //! Create a PassFilter with pass hierarchy information
PassHierarchyFilter(const Name& passName); //! Filter for passes which have a matching name and also with ordered parents.
//! For example, if the filter is initialized with
virtual ~PassHierarchyFilter() = default; //! pass name: "ShadowPass1"
//! pass parents names: "MainPipeline", "Shadow"
//! Construct filter with pass name and its parents' names in the order of the hierarchy //! Passes with these names match the filter:
//! This means k-th element is always an ancestor of the (k-1)-th element. //! "Root.MainPipeline.SwapChainPass.Shadow.ShadowPass1"
//! And the last element is the pass name. //! or "Root.MainPipeline.Shadow.ShadowPass1"
PassHierarchyFilter(const AZStd::vector<Name>& passHierarchy); //! or "MainPipeline.Shadow.Group1.ShadowPass1"
PassHierarchyFilter(const AZStd::vector<AZStd::string>& passHierarchy); //!
//! Passes with these names wont match:
// PassFilter overrides... //! "MainPipeline.ShadowPass1"
bool Matches(const Pass* pass) const override; //! or "Shadow.MainPipeline.ShadowPass1"
const Name* GetPassName() const override; static PassFilter CreateWithPassHierarchy(const AZStd::vector<Name>& passHierarchy);
AZStd::string ToString() const override; static PassFilter CreateWithPassHierarchy(const AZStd::vector<AZStd::string>& passHierarchy);
static PassFilter CreateWithTemplateName(Name templateName, const Scene* scene);
static PassFilter CreateWithTemplateName(Name templateName, const RenderPipeline* renderPipeline);
template <typename PassClass>
static PassFilter CreateWithPassClass();
enum FilterOptions : uint32_t
{
Empty = 0,
PassName = AZ_BIT(0),
PassTemplateName = AZ_BIT(1),
PassClass = AZ_BIT(2),
PassHierarchy = AZ_BIT(3),
OwnerScene = AZ_BIT(4),
OwnerRenderPipeline = AZ_BIT(5)
};
void SetOwenrScene(const Scene* scene);
void SetOwenrRenderPipeline(const RenderPipeline* renderPipeline);
void SetPassName(Name passName);
void SetTemplateName(Name passTemplateName);
void SetPassClass(TypeId passClassTypeId);
const Name& GetPassName() const;
const Name& GetPassTemplateName() const;
uint32_t GetEnabledFilterOptions() const;
//! Return true if the input pass matches the filter
bool Matches(const Pass* pass) const;
//! Return true if the input pass matches the filter with selected filter options
//! The input filter options should be a subset of options returned by GetEnabledFilterOptions()
//! This function is used to avoid extra checks for passes which was already filtered.
//! Check PassLibrary::ForEachPass() function's implementation for more details
bool Matches(const Pass* pass, uint32_t options) const;
private: private:
PassHierarchyFilter() = delete; void UpdateFilterOptions();
AZStd::vector<Name> m_parentNames;
Name m_passName; Name m_passName;
Name m_templateName;
TypeId m_passClassTypeId = TypeId::CreateNull();
AZStd::vector<Name> m_parentNames;
const RenderPipeline* m_ownerRenderPipeline = nullptr;
const Scene* m_ownerScene = nullptr;
uint32_t m_filterOptions = 0;
}; };
//! Filter for passes based on their class. template <typename PassClass>
template<typename PassClass> PassFilter PassFilter::CreateWithPassClass()
class PassClassFilter {
: public PassFilter PassFilter filter;
{ filter.m_passClassTypeId = PassClass::RTTI_Type();
public: filter.UpdateFilterOptions();
AZ_RTTI(PassClassFilter, "{AF6E3AD5-433A-462A-997A-F36D8A551D02}", PassFilter); return filter;
AZ_CLASS_ALLOCATOR(PassHierarchyFilter, SystemAllocator, 0);
PassClassFilter() = default;
// PassFilter overrides...
bool Matches(const Pass* pass) const override;
const Name* GetPassName() const override;
AZStd::string ToString() const override;
};
template<typename PassClass>
bool PassClassFilter<PassClass>::Matches(const Pass* pass) const
{
return pass->RTTI_IsTypeOf(PassClass::RTTI_Type());
}
template<typename PassClass>
const Name* PassClassFilter<PassClass>::GetPassName() const
{
return nullptr;
}
template<typename PassClass>
AZStd::string PassClassFilter<PassClass>::ToString() const
{
return AZStd::string::format("PassClassFilter<%s>", PassClass::RTTI_TypeName());
} }
} // namespace RPI } // namespace RPI
} // namespace AZ } // namespace AZ

@ -84,8 +84,8 @@ namespace AZ
bool LoadPassTemplateMappings(const AZStd::string& templateMappingPath); bool LoadPassTemplateMappings(const AZStd::string& templateMappingPath);
bool LoadPassTemplateMappings(Data::Asset<AnyAsset> mappingAsset); bool LoadPassTemplateMappings(Data::Asset<AnyAsset> mappingAsset);
//! Returns a list of passes found in the pass name mapping using the provided pass filter //! Visit each pass which matches the filter
AZStd::vector<Pass*> FindPasses(const PassFilter& passFilter) const; void ForEachPass(const PassFilter& passFilter, AZStd::function<PassFilterExecutionFlow(Pass*)> passFunction);
private: private:

@ -92,13 +92,13 @@ namespace AZ
// PassSystemInterface library related functions... // PassSystemInterface library related functions...
bool HasPassesForTemplateName(const Name& templateName) const override; bool HasPassesForTemplateName(const Name& templateName) const override;
const AZStd::vector<Pass*>& GetPassesForTemplateName(const Name& templateName) const override;
bool AddPassTemplate(const Name& name, const AZStd::shared_ptr<PassTemplate>& passTemplate) override; bool AddPassTemplate(const Name& name, const AZStd::shared_ptr<PassTemplate>& passTemplate) override;
const AZStd::shared_ptr<PassTemplate> GetPassTemplate(const Name& name) const override; const AZStd::shared_ptr<PassTemplate> GetPassTemplate(const Name& name) const override;
void RemovePassFromLibrary(Pass* pass) override; void RemovePassFromLibrary(Pass* pass) override;
void RegisterPass(Pass* pass) override; void RegisterPass(Pass* pass) override;
void UnregisterPass(Pass* pass) override; void UnregisterPass(Pass* pass) override;
AZStd::vector<Pass*> FindPasses(const PassFilter& passFilter) const override; void ForEachPass(const PassFilter& filter, AZStd::function<PassFilterExecutionFlow(Pass*)> passFunction) override;
Pass* FindFirstPass(const PassFilter& filter) override;
private: private:
// Returns the root of the pass tree hierarchy // Returns the root of the pass tree hierarchy

@ -75,6 +75,13 @@ namespace AZ
u32 m_maxDrawItemsRenderedInAPass = 0; u32 m_maxDrawItemsRenderedInAPass = 0;
}; };
enum PassFilterExecutionFlow : uint8_t
{
StopVisitingPasses,
ContinueVisitingPasses,
};
class PassSystemInterface class PassSystemInterface
{ {
friend class Pass; friend class Pass;
@ -186,9 +193,6 @@ namespace AZ
//! Returns true if the pass factory contains passes created with the given template name //! Returns true if the pass factory contains passes created with the given template name
virtual bool HasPassesForTemplateName(const Name& templateName) const = 0; virtual bool HasPassesForTemplateName(const Name& templateName) const = 0;
//! Get the passes created with the given template name.
virtual const AZStd::vector<Pass*>& GetPassesForTemplateName(const Name& templateName) const = 0;
//! Adds a PassTemplate to the library //! Adds a PassTemplate to the library
virtual bool AddPassTemplate(const Name& name, const AZStd::shared_ptr<PassTemplate>& passTemplate) = 0; virtual bool AddPassTemplate(const Name& name, const AZStd::shared_ptr<PassTemplate>& passTemplate) = 0;
@ -197,9 +201,16 @@ namespace AZ
//! Removes all references to the given pass from the pass library //! Removes all references to the given pass from the pass library
virtual void RemovePassFromLibrary(Pass* pass) = 0; virtual void RemovePassFromLibrary(Pass* pass) = 0;
//! Find matching passes from registered passes with specified filter //! Visit the matching passes from registered passes with specified filter
virtual AZStd::vector<Pass*> FindPasses(const PassFilter& passFilter) const = 0; //! The return value of the passFunction decides if the search continues or not
//! Note: this function will find all the passes which match the pass filter even they are for render pipelines which are not added to a scene
//! This function is fast if a pass name or a pass template name is specified.
virtual void ForEachPass(const PassFilter& filter, AZStd::function<PassFilterExecutionFlow(Pass*)> passFunction) = 0;
//! Find the first matching pass from registered passes with specified filter
//! Note: this function SHOULD ONLY be used when you are certain you only need to handle the first pass found
virtual Pass* FindFirstPass(const PassFilter& filter) = 0;
private: private:
// These functions are only meant to be used by the Pass class // These functions are only meant to be used by the Pass class

@ -149,29 +149,6 @@ namespace AZ
return index.IsValid() ? m_children[index.GetIndex()] : Ptr<Pass>(nullptr); return index.IsValid() ? m_children[index.GetIndex()] : Ptr<Pass>(nullptr);
} }
Ptr<Pass> ParentPass::FindPassByNameRecursive(const Name& passName) const
{
for (const Ptr<Pass>& child : m_children)
{
if (child->GetName() == passName)
{
return child.get();
}
ParentPass* asParent = child->AsParent();
if (asParent)
{
auto pass = asParent->FindPassByNameRecursive(passName);
if (pass)
{
return pass;
}
}
}
return nullptr;
}
const Pass* ParentPass::FindPass(RHI::DrawListTag drawListTag) const const Pass* ParentPass::FindPass(RHI::DrawListTag drawListTag) const
{ {
if (HasDrawListTag() && GetDrawListTag() == drawListTag) if (HasDrawListTag() && GetDrawListTag() == drawListTag)

@ -238,6 +238,11 @@ namespace AZ
return m_attachmentBindings[bindingIndex]; return m_attachmentBindings[bindingIndex];
} }
const PassTemplate* Pass::GetPassTemplate() const
{
return m_template.get();
}
void Pass::AddAttachmentBinding(PassAttachmentBinding attachmentBinding) void Pass::AddAttachmentBinding(PassAttachmentBinding attachmentBinding)
{ {
// Add the index of the binding to the input, output or input/output list based on the slot type // Add the index of the binding to the input, output or input/output list based on the slot type

@ -8,101 +8,264 @@
#include <Atom/RPI.Public/Pass/PassFilter.h> #include <Atom/RPI.Public/Pass/PassFilter.h>
#include <Atom/RPI.Public/Pass/ParentPass.h> #include <Atom/RPI.Public/Pass/ParentPass.h>
#include <Atom/RPI.Public/RenderPipeline.h>
namespace AZ namespace AZ
{ {
namespace RPI namespace RPI
{ {
PassHierarchyFilter::PassHierarchyFilter(const Name& passName) PassFilter PassFilter::CreateWithPassName(Name passName, const Scene* scene)
{ {
m_passName = passName; PassFilter filter;
filter.m_passName = passName;
filter.m_ownerScene = scene;
filter.UpdateFilterOptions();
return filter;
}
PassFilter PassFilter::CreateWithPassName(Name passName, const RenderPipeline* renderPipeline)
{
PassFilter filter;
filter.m_passName = passName;
filter.m_ownerRenderPipeline = renderPipeline;
filter.UpdateFilterOptions();
return filter;
} }
PassHierarchyFilter::PassHierarchyFilter(const AZStd::vector<AZStd::string>& passHierarchy) PassFilter PassFilter::CreateWithTemplateName(Name templateName, const Scene* scene)
{ {
PassFilter filter;
filter.m_templateName = templateName;
filter.m_ownerScene = scene;
filter.UpdateFilterOptions();
return filter;
}
PassFilter PassFilter::CreateWithTemplateName(Name templateName, const RenderPipeline* renderPipeline)
{
PassFilter filter;
filter.m_templateName = templateName;
filter.m_ownerRenderPipeline = renderPipeline;
filter.UpdateFilterOptions();
return filter;
}
PassFilter PassFilter::CreateWithPassHierarchy(const AZStd::vector<Name>& passHierarchy)
{
PassFilter filter;
if (passHierarchy.size() == 0) if (passHierarchy.size() == 0)
{ {
AZ_Assert(false, "passHierarchy should have at least one element"); AZ_Assert(false, "passHierarchy should have at least one element");
return; return filter;
} }
m_passName = Name(passHierarchy.back()); filter.m_passName = passHierarchy.back();
m_parentNames.resize(passHierarchy.size() - 1); filter.m_parentNames.resize(passHierarchy.size() - 1);
for (uint32_t index = 0; index < m_parentNames.size(); index++) for (uint32_t index = 0; index < filter.m_parentNames.size(); index++)
{ {
m_parentNames[index] = Name(passHierarchy[index]); filter.m_parentNames[index] = passHierarchy[index];
} }
filter.UpdateFilterOptions();
return filter;
} }
PassHierarchyFilter::PassHierarchyFilter(const AZStd::vector<Name>& passHierarchy) PassFilter PassFilter::CreateWithPassHierarchy(const AZStd::vector<AZStd::string>& passHierarchy)
{ {
PassFilter filter;
if (passHierarchy.size() == 0) if (passHierarchy.size() == 0)
{ {
AZ_Assert(false, "passHierarchy should have at least one element"); AZ_Assert(false, "passHierarchy should have at least one element");
return; return filter;
} }
m_passName = passHierarchy.back(); filter.m_passName = Name(passHierarchy.back());
m_parentNames.resize(passHierarchy.size() - 1); filter.m_parentNames.resize(passHierarchy.size() - 1);
for (uint32_t index = 0; index < m_parentNames.size(); index++) for (uint32_t index = 0; index < filter.m_parentNames.size(); index++)
{ {
m_parentNames[index] = passHierarchy[index]; filter.m_parentNames[index] = Name(passHierarchy[index]);
} }
filter.UpdateFilterOptions();
return filter;
}
void PassFilter::SetOwenrScene(const Scene* scene)
{
m_ownerScene = scene;
UpdateFilterOptions();
}
void PassFilter::SetOwenrRenderPipeline(const RenderPipeline* renderPipeline)
{
m_ownerRenderPipeline = renderPipeline;
UpdateFilterOptions();
} }
bool PassHierarchyFilter::Matches(const Pass* pass) const void PassFilter::SetPassName(Name passName)
{ {
if (pass->GetName() != m_passName) m_passName = passName;
UpdateFilterOptions();
}
void PassFilter::SetTemplateName(Name passTemplateName)
{
m_templateName = passTemplateName;
UpdateFilterOptions();
}
void PassFilter::SetPassClass(TypeId passClassTypeId)
{
m_passClassTypeId = passClassTypeId;
UpdateFilterOptions();
}
const Name& PassFilter::GetPassName() const
{
return m_passName;
}
const Name& PassFilter::GetPassTemplateName() const
{
return m_templateName;
}
uint32_t PassFilter::GetEnabledFilterOptions() const
{
return m_filterOptions;
}
bool PassFilter::Matches(const Pass* pass) const
{
return Matches(pass, m_filterOptions);
}
bool PassFilter::Matches(const Pass* pass, uint32_t options) const
{
AZ_Assert( (options&m_filterOptions) == options, "options should be a subset of m_filterOptions");
// return false if the pass doesn't have a pass template or the template's name is not matching
if (options & FilterOptions::PassTemplateName && (!pass->GetPassTemplate() || pass->GetPassTemplate()->m_name != m_templateName))
{ {
return false; return false;
} }
ParentPass* parent = pass->GetParent(); if ((options & FilterOptions::PassName) && pass->GetName() != m_passName)
{
return false;
}
// search from the back of the array with the most close parent if ((options & FilterOptions::PassClass) && pass->RTTI_GetType() != m_passClassTypeId)
for (int32_t index = static_cast<int32_t>(m_parentNames.size() - 1); index >= 0; index--)
{ {
const Name& parentName = m_parentNames[index]; return false;
while (parent) }
if ((options & FilterOptions::OwnerRenderPipeline) && m_ownerRenderPipeline != pass->GetRenderPipeline())
{
return false;
}
// If the owner render pipeline was checked, the owner scene check can be skipped
if (options & FilterOptions::OwnerScene)
{
if (pass->GetRenderPipeline())
{ {
if (parent->GetName() == parentName) // return false if the owner scene doesn't match
if (m_ownerScene != pass->GetRenderPipeline()->GetScene())
{ {
break; return false;
} }
parent = parent->GetParent();
} }
else
// if parent is nullptr the it didn't find a parent has matching current parentName
if (!parent)
{ {
// return false if the pass doesn't have an owner scene
return false; return false;
} }
}
if ((options & FilterOptions::PassHierarchy))
{
// Filter for passes which have a matching name and also with ordered parents.
// For example, if the filter is initialized with
// pass name: "ShadowPass1"
// pass parents names: "MainPipeline", "Shadow"
// Passes with these names match the filter:
// "Root.MainPipeline.SwapChainPass.Shadow.ShadowPass1"
// or "Root.MainPipeline.Shadow.ShadowPass1"
// or "MainPipeline.Shadow.Group1.ShadowPass1"
//
// Passes with these names wont match:
// "MainPipeline.ShadowPass1"
// or "Shadow.MainPipeline.ShadowPass1"
// move to next parent ParentPass* parent = pass->GetParent();
parent = parent->GetParent();
// search from the back of the array with the most close parent
for (int32_t index = static_cast<int32_t>(m_parentNames.size() - 1); index >= 0; index--)
{
const Name& parentName = m_parentNames[index];
while (parent)
{
if (parent->GetName() == parentName)
{
break;
}
parent = parent->GetParent();
}
// if parent is nullptr the it didn't find a parent has matching current parentName
if (!parent)
{
return false;
}
// move to next parent
parent = parent->GetParent();
}
} }
return true; return true;
} }
const Name* PassHierarchyFilter::GetPassName() const void PassFilter::UpdateFilterOptions()
{ {
return &m_passName; m_filterOptions = FilterOptions::Empty;
} if (!m_passName.IsEmpty())
AZStd::string PassHierarchyFilter::ToString() const
{
AZStd::string result = "PassHierarchyFilter";
for (uint32_t index = 0; index < m_parentNames.size(); index++)
{ {
result += AZStd::string::format(" [%s]", m_parentNames[index].GetCStr()); m_filterOptions |= FilterOptions::PassName;
}
if (!m_templateName.IsEmpty())
{
m_filterOptions |= FilterOptions::PassTemplateName;
}
if (m_parentNames.size() > 0)
{
m_filterOptions |= FilterOptions::PassHierarchy;
}
if (m_ownerRenderPipeline)
{
m_filterOptions |= FilterOptions::OwnerRenderPipeline;
}
if (m_ownerScene)
{
// If the OwnerRenderPipeline exists, we shouldn't need to filter owner scene
// Validate the owner render pipeline belongs to the owner scene
if (m_filterOptions & FilterOptions::OwnerRenderPipeline)
{
if (m_ownerRenderPipeline->GetScene() != m_ownerScene)
{
AZ_Warning("RPI", false, "The owner scene filter doesn't match owner render pipeline. It will be skipped.");
}
}
else
{
m_filterOptions |= FilterOptions::OwnerScene;
}
}
if (!m_passClassTypeId.IsNull())
{
m_filterOptions |= FilterOptions::PassClass;
} }
result += AZStd::string::format(" [%s]", m_passName.GetCStr());
return result;
} }
} // namespace RPI } // namespace RPI
} // namespace AZ } // namespace AZ

@ -85,47 +85,80 @@ namespace AZ
return (GetPassesForTemplate(templateName).size() > 0); return (GetPassesForTemplate(templateName).size() > 0);
} }
AZStd::vector<Pass*> PassLibrary::FindPasses(const PassFilter& passFilter) const void PassLibrary::ForEachPass(const PassFilter& passFilter, AZStd::function<PassFilterExecutionFlow(Pass*)> passFunction)
{ {
const Name* passName = passFilter.GetPassName(); uint32_t filterOptions = passFilter.GetEnabledFilterOptions();
AZStd::vector<Pass*> result; // A lambda function which visits each pass in a pass list, if the pass matches the pass filter, then call the pass function
auto visitList = [passFilter, passFunction](const AZStd::vector<Pass*>& passList, uint32_t options) -> PassFilterExecutionFlow
if (passName)
{ {
// If the pass' name is known, find passes with matching names first if (passList.size() == 0)
const auto constItr = m_passNameMapping.find(*passName);
if (constItr == m_passNameMapping.end())
{ {
return result; return PassFilterExecutionFlow::ContinueVisitingPasses;
} }
// if there is not other filter options enabled, skip the filter and call pass functions directly
const AZStd::vector<Pass*>& passes = constItr->second; if (options == PassFilter::FilterOptions::Empty)
for (Pass* pass : passes)
{ {
if (passFilter.Matches(pass)) for (Pass* pass : passList)
{ {
result.push_back(pass); // If user want to skip processing, return directly.
if (passFunction(pass) == PassFilterExecutionFlow::StopVisitingPasses)
{
return PassFilterExecutionFlow::StopVisitingPasses;
}
} }
return PassFilterExecutionFlow::ContinueVisitingPasses;
} }
}
else // Check with the pass filter and call pass functions
{ for (Pass* pass : passList)
// If the filter doesn't know matching pass' name, need to go through all registered passes
for (auto& namePasses : m_passNameMapping)
{ {
for (Pass* pass : namePasses.second) if (passFilter.Matches(pass, options))
{ {
if (passFilter.Matches(pass)) if (passFunction(pass) == PassFilterExecutionFlow::StopVisitingPasses)
{ {
result.push_back(pass); return PassFilterExecutionFlow::StopVisitingPasses;
} }
} }
} }
return PassFilterExecutionFlow::ContinueVisitingPasses;
};
// Check pass template name first
if (filterOptions & PassFilter::FilterOptions::PassTemplateName)
{
auto entry = GetEntry(passFilter.GetPassTemplateName());
if (!entry)
{
return;
}
filterOptions &= ~(PassFilter::FilterOptions::PassTemplateName);
visitList(entry->m_passes, filterOptions);
return;
}
else if (filterOptions & PassFilter::FilterOptions::PassName)
{
const auto constItr = m_passNameMapping.find(passFilter.GetPassName());
if (constItr == m_passNameMapping.end())
{
return;
}
filterOptions &= ~(PassFilter::FilterOptions::PassName);
visitList(constItr->second, filterOptions);
return;
} }
return result; // check againest every passes. This might be slow
AZ_PROFILE_SCOPE(RPI, "PassLibrary::ForEachPass");
for (auto& namePasses : m_passNameMapping)
{
if (visitList(namePasses.second, filterOptions) == PassFilterExecutionFlow::StopVisitingPasses)
{
return;
}
}
} }
// Add Functions... // Add Functions...
@ -419,3 +452,4 @@ namespace AZ
} // namespace RPI } // namespace RPI
} // namespace AZ } // namespace AZ

@ -456,11 +456,6 @@ namespace AZ
return m_passLibrary.HasPassesForTemplate(templateName); return m_passLibrary.HasPassesForTemplate(templateName);
} }
const AZStd::vector<Pass*>& PassSystem::GetPassesForTemplateName(const Name& templateName) const
{
return m_passLibrary.GetPassesForTemplate(templateName);
}
bool PassSystem::AddPassTemplate(const Name& name, const AZStd::shared_ptr<PassTemplate>& passTemplate) bool PassSystem::AddPassTemplate(const Name& name, const AZStd::shared_ptr<PassTemplate>& passTemplate)
{ {
return m_passLibrary.AddPassTemplate(name, passTemplate); return m_passLibrary.AddPassTemplate(name, passTemplate);
@ -487,10 +482,21 @@ namespace AZ
RemovePassFromLibrary(pass); RemovePassFromLibrary(pass);
--m_passCounter; --m_passCounter;
} }
void PassSystem::ForEachPass(const PassFilter& filter, AZStd::function<PassFilterExecutionFlow(Pass*)> passFunction)
{
return m_passLibrary.ForEachPass(filter, passFunction);
}
AZStd::vector<Pass*> PassSystem::FindPasses(const PassFilter& passFilter) const Pass* PassSystem::FindFirstPass(const PassFilter& filter)
{ {
return m_passLibrary.FindPasses(passFilter); Pass* foundPass = nullptr;
m_passLibrary.ForEachPass(filter, [&foundPass](RPI::Pass* pass) ->PassFilterExecutionFlow
{
foundPass = pass;
return PassFilterExecutionFlow::StopVisitingPasses;
});
return foundPass;
} }
SwapChainPass* PassSystem::FindSwapChainPass(AzFramework::NativeWindowHandle windowHandle) const SwapChainPass* PassSystem::FindSwapChainPass(AzFramework::NativeWindowHandle windowHandle) const

@ -19,6 +19,8 @@
#include <Atom/RPI.Public/Pass/PassSystem.h> #include <Atom/RPI.Public/Pass/PassSystem.h>
#include <Atom/RPI.Public/Pass/RasterPass.h> #include <Atom/RPI.Public/Pass/RasterPass.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <AzCore/UnitTest/TestTypes.h> #include <AzCore/UnitTest/TestTypes.h>
#include <Common/RPITestFixture.h> #include <Common/RPITestFixture.h>
@ -573,7 +575,7 @@ namespace UnitTest
EXPECT_TRUE(pass != nullptr); EXPECT_TRUE(pass != nullptr);
} }
TEST_F(PassTests, PassHierarchyFilter) TEST_F(PassTests, PassFilter_PassHierarchy)
{ {
m_data->AddPassTemplatesToLibrary(); m_data->AddPassTemplatesToLibrary();
@ -587,62 +589,55 @@ namespace UnitTest
parent2->AsParent()->AddChild(parent1); parent2->AsParent()->AddChild(parent1);
parent1->AsParent()->AddChild(pass); parent1->AsParent()->AddChild(pass);
{
// Filter with only pass name
PassHierarchyFilter filter(Name("pass1"));
EXPECT_TRUE(filter.Matches(pass.get()));
}
{ {
// Filter with pass hierarchy which has only one element // Filter with pass hierarchy which has only one element
PassHierarchyFilter filter({ Name("pass1") }); PassFilter filter = PassFilter::CreateWithPassHierarchy({Name("pass1")});
EXPECT_TRUE(filter.Matches(pass.get())); EXPECT_TRUE(filter.Matches(pass.get()));
} }
{ {
// Filter with empty pass hierarchy. Result one assert // Filter with empty pass hierarchy, triggers one assert
AZ_TEST_START_TRACE_SUPPRESSION; AZ_TEST_START_TRACE_SUPPRESSION;
PassHierarchyFilter filter(AZStd::vector<Name>{}); PassFilter filter = PassFilter::CreateWithPassHierarchy(AZStd::vector<Name>{});
AZ_TEST_STOP_TRACE_SUPPRESSION(1); AZ_TEST_STOP_TRACE_SUPPRESSION(1);
EXPECT_FALSE(filter.Matches(pass.get()));
} }
{ {
// Filters with partial hierarchy by using string vector // Filters with partial hierarchy by using string vector
AZStd::vector<AZStd::string> passHierarchy1 = { "parent1", "pass1" }; AZStd::vector<AZStd::string> passHierarchy1 = { "parent1", "pass1" };
PassHierarchyFilter filter1(passHierarchy1); PassFilter filter1 = PassFilter::CreateWithPassHierarchy(passHierarchy1);
EXPECT_TRUE(filter1.Matches(pass.get())); EXPECT_TRUE(filter1.Matches(pass.get()));
AZStd::vector<AZStd::string> passHierarchy2 = { "parent2", "pass1" }; AZStd::vector<AZStd::string> passHierarchy2 = { "parent2", "pass1" };
PassHierarchyFilter filter2(passHierarchy2); PassFilter filter2 = PassFilter::CreateWithPassHierarchy(passHierarchy2);
EXPECT_TRUE(filter2.Matches(pass.get())); EXPECT_TRUE(filter2.Matches(pass.get()));
AZStd::vector<AZStd::string> passHierarchy3 = { "parent3", "parent2", "pass1" }; AZStd::vector<AZStd::string> passHierarchy3 = { "parent3", "parent2", "pass1" };
PassHierarchyFilter filter3(passHierarchy3); PassFilter filter3 = PassFilter::CreateWithPassHierarchy(passHierarchy3);
EXPECT_TRUE(filter3.Matches(pass.get())); EXPECT_TRUE(filter3.Matches(pass.get()));
} }
{ {
// Filters with partial hierarchy by using Name vector // Filters with partial hierarchy by using Name vector
AZStd::vector<Name> passHierarchy1 = { Name("parent1"), Name("pass1") }; AZStd::vector<Name> passHierarchy1 = { Name("parent1"), Name("pass1") };
PassHierarchyFilter filter1(passHierarchy1); PassFilter filter1 = PassFilter::CreateWithPassHierarchy(passHierarchy1);
EXPECT_TRUE(filter1.Matches(pass.get())); EXPECT_TRUE(filter1.Matches(pass.get()));
AZStd::vector<Name> passHierarchy2 = { Name("parent2"), Name("pass1")}; AZStd::vector<Name> passHierarchy2 = { Name("parent2"), Name("pass1")};
PassHierarchyFilter filter2(passHierarchy2); PassFilter filter2 = PassFilter::CreateWithPassHierarchy(passHierarchy2);
EXPECT_TRUE(filter2.Matches(pass.get())); EXPECT_TRUE(filter2.Matches(pass.get()));
AZStd::vector<Name> passHierarchy3 = { Name("parent3"), Name("parent2"), Name("pass1") }; AZStd::vector<Name> passHierarchy3 = { Name("parent3"), Name("parent2"), Name("pass1") };
PassHierarchyFilter filter3(passHierarchy3); PassFilter filter3 = PassFilter::CreateWithPassHierarchy(passHierarchy3);
EXPECT_TRUE(filter3.Matches(pass.get())); EXPECT_TRUE(filter3.Matches(pass.get()));
} }
{ {
// Find non-leaf pass // Find non-leaf pass
PassHierarchyFilter filter1(AZStd::vector<AZStd::string>{"parent3", "parent1"}); PassFilter filter1 = PassFilter::CreateWithPassHierarchy(AZStd::vector<AZStd::string>{"parent3", "parent1"});
EXPECT_TRUE(filter1.Matches(parent1.get())); EXPECT_TRUE(filter1.Matches(parent1.get()));
PassHierarchyFilter filter2(Name("parent1")); PassFilter filter2 = PassFilter::CreateWithPassHierarchy({ Name("parent1") });
EXPECT_TRUE(filter2.Matches(parent1.get())); EXPECT_TRUE(filter2.Matches(parent1.get()));
EXPECT_FALSE(filter2.Matches(pass.get())); EXPECT_FALSE(filter2.Matches(pass.get()));
} }
@ -650,11 +645,131 @@ namespace UnitTest
{ {
// Failed to find pass // Failed to find pass
// Mis-matching hierarchy // Mis-matching hierarchy
PassHierarchyFilter filter1(AZStd::vector<AZStd::string>{"Parent1", "Parent3", "pass1"}); PassFilter filter1 = PassFilter::CreateWithPassHierarchy(AZStd::vector<AZStd::string>{"Parent1", "Parent3", "pass1"});
EXPECT_FALSE(filter1.Matches(pass.get())); EXPECT_FALSE(filter1.Matches(pass.get()));
// Mis-matching name // Mis-matching name
PassHierarchyFilter filter2(AZStd::vector<AZStd::string>{"Parent1", "pass1"}); PassFilter filter2 = PassFilter::CreateWithPassHierarchy(AZStd::vector<AZStd::string>{"Parent1", "pass1"});
EXPECT_FALSE(filter2.Matches(parent1.get())); EXPECT_FALSE(filter2.Matches(parent1.get()));
} }
} }
TEST_F(PassTests, PassFilter_Empty_Success)
{
m_data->AddPassTemplatesToLibrary();
// create a pass tree
Ptr<Pass> pass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1"));
Ptr<Pass> parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1"));
Ptr<Pass> parent2 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent2"));
Ptr<Pass> parent3 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent3"));
parent3->AsParent()->AddChild(parent2);
parent2->AsParent()->AddChild(parent1);
parent1->AsParent()->AddChild(pass);
PassFilter filter;
// Any pass can match an empty filter
EXPECT_TRUE(filter.Matches(pass.get()));
EXPECT_TRUE(filter.Matches(parent1.get()));
EXPECT_TRUE(filter.Matches(parent2.get()));
EXPECT_TRUE(filter.Matches(parent3.get()));
}
TEST_F(PassTests, PassFilter_PassClass_Success)
{
m_data->AddPassTemplatesToLibrary();
// create a pass tree
Ptr<Pass> pass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1"));
Ptr<Pass> depthPass = m_passSystem->CreatePassFromTemplate(Name("DepthPrePass"), Name("depthPass"));
Ptr<Pass> parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1"));
parent1->AsParent()->AddChild(pass);
parent1->AsParent()->AddChild(depthPass);
PassFilter filter1 = PassFilter::CreateWithPassClass<Pass>();
EXPECT_TRUE(filter1.Matches(pass.get()));
EXPECT_FALSE(filter1.Matches(parent1.get()));
PassFilter filter2 = PassFilter::CreateWithPassClass<ParentPass>();
EXPECT_FALSE(filter2.Matches(pass.get()));
EXPECT_TRUE(filter2.Matches(parent1.get()));
}
TEST_F(PassTests, PassFilter_PassTemplate_Success)
{
m_data->AddPassTemplatesToLibrary();
// create a pass tree
Ptr<Pass> childPass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1"));
Ptr<Pass> parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1"));
PassFilter filter1 = PassFilter::CreateWithTemplateName(Name("Pass"), (Scene*) nullptr);
// childPass doesn't have a template
EXPECT_FALSE(filter1.Matches(childPass.get()));
PassFilter filter2 = PassFilter::CreateWithTemplateName(Name("ParentPass"), (Scene*) nullptr);
EXPECT_TRUE(filter2.Matches(parent1.get()));
}
TEST_F(PassTests, ForEachPass_PassTemplateFilter_Success)
{
m_data->AddPassTemplatesToLibrary();
// create a pass tree
Ptr<Pass> pass = m_passSystem->CreatePassFromClass(Name("Pass"), Name("pass1"));
Ptr<Pass> parent1 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent1"));
Ptr<Pass> parent2 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent2"));
Ptr<Pass> parent3 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent3"));
parent3->AsParent()->AddChild(parent2);
parent2->AsParent()->AddChild(parent1);
parent1->AsParent()->AddChild(pass);
// Create render pipeline
const RPI::PipelineViewTag viewTag{ "viewTag1" };
RPI::RenderPipelineDescriptor desc;
desc.m_mainViewTagName = viewTag.GetStringView();
desc.m_name = "TestPipeline";
RPI::RenderPipelinePtr pipeline = RPI::RenderPipeline::CreateRenderPipeline(desc);
Ptr<Pass> parent4 = m_passSystem->CreatePassFromTemplate(Name("ParentPass"), Name("parent4"));
pipeline->GetRootPass()->AddChild(parent4);
Name templateName = Name("ParentPass");
PassFilter filter1 = PassFilter::CreateWithTemplateName(templateName, (RenderPipeline*)nullptr);
int count = 0;
m_passSystem->ForEachPass(filter1, [&count, templateName](RPI::Pass* pass) -> PassFilterExecutionFlow
{
EXPECT_TRUE(pass->GetPassTemplate()->m_name == templateName);
count++;
return PassFilterExecutionFlow::ContinueVisitingPasses;
});
// three from CreatePassFromTemplate() calls and one from Render Pipeline.
EXPECT_TRUE(count == 4);
count = 0;
m_passSystem->ForEachPass(filter1, [&count, templateName](RPI::Pass* pass) -> PassFilterExecutionFlow
{
EXPECT_TRUE(pass->GetPassTemplate()->m_name == templateName);
count++;
return PassFilterExecutionFlow::StopVisitingPasses;
});
EXPECT_TRUE(count == 1);
PassFilter filter2 = PassFilter::CreateWithTemplateName(templateName, pipeline.get());
count = 0;
m_passSystem->ForEachPass(filter2, [&count]([[maybe_unused]] RPI::Pass* pass) -> PassFilterExecutionFlow
{
count++;
return PassFilterExecutionFlow::ContinueVisitingPasses;
});
// only the ParentPass in the render pipeline was found
EXPECT_TRUE(count == 1);
}
} }

@ -19,6 +19,7 @@
#include <Atom/RPI.Public/View.h> #include <Atom/RPI.Public/View.h>
#include <Atom/RPI.Public/Scene.h> #include <Atom/RPI.Public/Scene.h>
#include <Atom/RPI.Public/RenderPipeline.h> #include <Atom/RPI.Public/RenderPipeline.h>
#include <Atom/RPI.Public/Pass/PassFilter.h>
#include <Atom/RPI.Public/Pass/PassSystemInterface.h> #include <Atom/RPI.Public/Pass/PassSystemInterface.h>
#include <Atom/RPI.Public/RPIUtils.h> #include <Atom/RPI.Public/RPIUtils.h>
#include <Atom/RPI.Public/Shader/Shader.h> #include <Atom/RPI.Public/Shader/Shader.h>
@ -142,12 +143,13 @@ namespace AZ
EnablePasses(true); EnablePasses(true);
} }
void HairFeatureProcessor::EnablePasses([[maybe_unused]] bool enable) void HairFeatureProcessor::EnablePasses(bool enable)
{ {
RPI::Ptr<RPI::Pass> desiredPass = m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairParentPassName); RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairParentPassName, GetParentScene());
if (desiredPass) RPI::Pass* pass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter);
if (pass)
{ {
desiredPass->SetEnabled(enable); pass->SetEnabled(enable);
} }
} }
@ -309,10 +311,17 @@ namespace AZ
m_forceClearRenderData = true; m_forceClearRenderData = true;
} }
bool HairFeatureProcessor::HasHairParentPass()
{
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairParentPassName, GetParentScene());
RPI::Pass* pass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter);
return pass;
}
void HairFeatureProcessor::OnRenderPipelineAdded(RPI::RenderPipelinePtr renderPipeline) void HairFeatureProcessor::OnRenderPipelineAdded(RPI::RenderPipelinePtr renderPipeline)
{ {
// Proceed only if this is the main pipeline that contains the parent pass // Proceed only if this is the main pipeline that contains the parent pass
if (!renderPipeline.get()->GetRootPass()->FindPassByNameRecursive(HairParentPassName)) if (!HasHairParentPass())
{ {
return; return;
} }
@ -323,10 +332,10 @@ namespace AZ
m_forceRebuildRenderData = true; m_forceRebuildRenderData = true;
} }
void HairFeatureProcessor::OnRenderPipelineRemoved(RPI::RenderPipeline* renderPipeline) void HairFeatureProcessor::OnRenderPipelineRemoved([[maybe_unused]] RPI::RenderPipeline* renderPipeline)
{ {
// Proceed only if this is the main pipeline that contains the parent pass // Proceed only if this is the main pipeline that contains the parent pass
if (!renderPipeline->GetRootPass()->FindPassByNameRecursive(HairParentPassName)) if (!HasHairParentPass())
{ {
return; return;
} }
@ -338,7 +347,7 @@ namespace AZ
void HairFeatureProcessor::OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline) void HairFeatureProcessor::OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline)
{ {
// Proceed only if this is the main pipeline that contains the parent pass // Proceed only if this is the main pipeline that contains the parent pass
if (!renderPipeline->GetRootPass()->FindPassByNameRecursive(HairParentPassName)) if (!HasHairParentPass())
{ {
return; return;
} }
@ -457,7 +466,8 @@ namespace AZ
{ {
m_computePasses[passName] = nullptr; m_computePasses[passName] = nullptr;
RPI::Ptr<RPI::Pass> desiredPass = m_renderPipeline->GetRootPass()->FindPassByNameRecursive(passName); RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(passName, m_renderPipeline);
RPI::Ptr<RPI::Pass> desiredPass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter);
if (desiredPass) if (desiredPass)
{ {
m_computePasses[passName] = static_cast<HairSkinningComputePass*>(desiredPass.get()); m_computePasses[passName] = static_cast<HairSkinningComputePass*>(desiredPass.get());
@ -478,8 +488,9 @@ namespace AZ
bool HairFeatureProcessor::InitPPLLFillPass() bool HairFeatureProcessor::InitPPLLFillPass()
{ {
m_hairPPLLRasterPass = nullptr; // reset it to null, just in case it fails to load the assets properly m_hairPPLLRasterPass = nullptr; // reset it to null, just in case it fails to load the assets properly
RPI::Ptr<RPI::Pass> desiredPass = m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairPPLLRasterPassName); RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairPPLLRasterPassName, m_renderPipeline);
RPI::Ptr<RPI::Pass> desiredPass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter);
if (desiredPass) if (desiredPass)
{ {
m_hairPPLLRasterPass = static_cast<HairPPLLRasterPass*>(desiredPass.get()); m_hairPPLLRasterPass = static_cast<HairPPLLRasterPass*>(desiredPass.get());
@ -497,7 +508,8 @@ namespace AZ
{ {
m_hairPPLLResolvePass = nullptr; // reset it to null, just in case it fails to load the assets properly m_hairPPLLResolvePass = nullptr; // reset it to null, just in case it fails to load the assets properly
RPI::Ptr<RPI::Pass> desiredPass = m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairPPLLResolvePassName); RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairPPLLResolvePassName, m_renderPipeline);
RPI::Ptr<RPI::Pass> desiredPass = RPI::PassSystemInterface::Get()->FindFirstPass(passFilter);
if (desiredPass) if (desiredPass)
{ {
m_hairPPLLResolvePass = static_cast<HairPPLLResolvePass*>(desiredPass.get()); m_hairPPLLResolvePass = static_cast<HairPPLLResolvePass*>(desiredPass.get());
@ -518,8 +530,8 @@ namespace AZ
m_hairShortCutGeometryDepthAlphaPass = nullptr; m_hairShortCutGeometryDepthAlphaPass = nullptr;
m_hairShortCutGeometryShadingPass = nullptr; m_hairShortCutGeometryShadingPass = nullptr;
m_hairShortCutGeometryDepthAlphaPass = static_cast<HairShortCutGeometryDepthAlphaPass*>( RPI::PassFilter depthAlphaPassFilter = RPI::PassFilter::CreateWithPassName(HairShortCutGeometryDepthAlphaPassName, m_renderPipeline);
m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairShortCutGeometryDepthAlphaPassName).get()); m_hairShortCutGeometryDepthAlphaPass = static_cast<HairShortCutGeometryDepthAlphaPass*>(RPI::PassSystemInterface::Get()->FindFirstPass(depthAlphaPassFilter));
if (m_hairShortCutGeometryDepthAlphaPass) if (m_hairShortCutGeometryDepthAlphaPass)
{ {
m_hairShortCutGeometryDepthAlphaPass->SetFeatureProcessor(this); m_hairShortCutGeometryDepthAlphaPass->SetFeatureProcessor(this);
@ -530,8 +542,8 @@ namespace AZ
return false; return false;
} }
m_hairShortCutGeometryShadingPass = static_cast<HairShortCutGeometryShadingPass*>( RPI::PassFilter shaderingPassFilter = RPI::PassFilter::CreateWithPassName(HairShortCutGeometryShadingPassName, m_renderPipeline);
m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairShortCutGeometryShadingPassName).get()); m_hairShortCutGeometryShadingPass = static_cast<HairShortCutGeometryShadingPass*>(RPI::PassSystemInterface::Get()->FindFirstPass(shaderingPassFilter));
if (m_hairShortCutGeometryShadingPass) if (m_hairShortCutGeometryShadingPass)
{ {
m_hairShortCutGeometryShadingPass->SetFeatureProcessor(this); m_hairShortCutGeometryShadingPass->SetFeatureProcessor(this);

@ -165,6 +165,8 @@ namespace AZ
void EnablePasses(bool enable); void EnablePasses(bool enable);
bool HasHairParentPass();
//! The following will serve to register the FP in the Thumbnail system //! The following will serve to register the FP in the Thumbnail system
AZStd::vector<AZStd::string> m_hairFeatureProcessorRegistryName; AZStd::vector<AZStd::string> m_hairFeatureProcessorRegistryName;

Loading…
Cancel
Save