Merge branch 'stabilization/2110' into Atom/santorac/MoveDoubleSided

monroegm-disable-blank-issue-2
santorac 4 years ago
commit eb542bfe69

@ -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();
for (RPI::Pass* pass : passes)
{ {
if (RPI::RenderPipeline* pipeline = pass->GetRenderPipeline()) m_cascadedShadowmapsPasses.clear();
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(Name("CascadedShadowmapsTemplate"), GetParentScene());
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.
if (GetParentScene()->GetRenderPipeline(pipelineId).get() == pipeline)
{
CascadedShadowmapsPass* shadowPass = azrtti_cast<CascadedShadowmapsPass*>(pass); CascadedShadowmapsPass* shadowPass = azrtti_cast<CascadedShadowmapsPass*>(pass);
AZ_Assert(shadowPass, "It is not a CascadedShadowmapPass."); AZ_Assert(shadowPass, "It is not a CascadedShadowmapPass.");
if (pipeline->GetDefaultView()) if (pipeline->GetDefaultView())
{ {
m_cascadedShadowmapsPasses[pipelineId].push_back(shadowPass); 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();
// checking the render pipeline is just removed from the scene.
if (GetParentScene()->GetRenderPipeline(pipelineId).get() == pipeline)
{ {
const RPI::RenderPipelineId pipelineId = pass->GetRenderPipeline()->GetId();
if (m_cascadedShadowmapsPasses.find(pipelineId) != m_cascadedShadowmapsPasses.end()) if (m_cascadedShadowmapsPasses.find(pipelineId) != m_cascadedShadowmapsPasses.end())
{ {
EsmShadowmapsPass* esmPass = azrtti_cast<EsmShadowmapsPass*>(pass); EsmShadowmapsPass* esmPass = azrtti_cast<EsmShadowmapsPass*>(pass);
AZ_Assert(esmPass, "It is not an EsmShadowmapPass."); AZ_Assert(esmPass, "It is not an EsmShadowmapPass.");
if (m_cascadedShadowmapsPasses.find(esmPass->GetRenderPipeline()->GetId()) != m_cascadedShadowmapsPasses.end() && if (esmPass->GetLightTypeName() == m_lightTypeName)
esmPass->GetLightTypeName() == m_lightTypeName)
{ {
m_esmShadowmapsPasses[pipelineId].push_back(esmPass); 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,10 +80,15 @@ namespace AZ
} }
// update the size multiplier on the DiffuseProbeGridDownsamplePass output // update the size multiplier on the DiffuseProbeGridDownsamplePass output
// 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
// GPU error if the scene doesn't have this feature processor enabled.
// For example, the ASV MultiScene sample may have TDR.
{
AZStd::vector<Name> downsamplePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseProbeGridDownsamplePass") }; AZStd::vector<Name> downsamplePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseProbeGridDownsamplePass") };
RPI::PassHierarchyFilter downsamplePassFilter(downsamplePassHierarchy); RPI::PassFilter downsamplePassFilter = RPI::PassFilter::CreateWithPassHierarchy(downsamplePassHierarchy);
const AZStd::vector<RPI::Pass*>& downsamplePasses = RPI::PassSystemInterface::Get()->FindPasses(downsamplePassFilter); RPI::PassSystemInterface::Get()->ForEachPass(
for (RPI::Pass* pass : downsamplePasses) downsamplePassFilter,
[sizeMultiplier](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
{ {
for (uint32_t outputIndex = 0; outputIndex < pass->GetOutputCount(); ++outputIndex) for (uint32_t outputIndex = 0; outputIndex < pass->GetOutputCount(); ++outputIndex)
{ {
@ -96,19 +101,27 @@ namespace AZ
// set the output scale on the PassSrg // set the output scale on the PassSrg
RPI::FullscreenTrianglePass* downsamplePass = static_cast<RPI::FullscreenTrianglePass*>(pass); RPI::FullscreenTrianglePass* downsamplePass = static_cast<RPI::FullscreenTrianglePass*>(pass);
auto constantIndex = downsamplePass->GetShaderResourceGroup()->FindShaderInputConstantIndex(Name("m_outputImageScale")); RHI::ShaderInputNameIndex outputImageScaleShaderInput = "m_outputImageScale";
downsamplePass->GetShaderResourceGroup()->SetConstant(constantIndex, aznumeric_cast<uint32_t>(1.0f / sizeMultiplier)); 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") }; AZStd::vector<Name> compositePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseCompositePass") };
RPI::PassHierarchyFilter compositePassFilter(compositePassHierarchy); RPI::PassFilter compositePassFilter = RPI::PassFilter::CreateWithPassHierarchy(compositePassHierarchy);
const AZStd::vector<RPI::Pass*>& compositePasses = RPI::PassSystemInterface::Get()->FindPasses(compositePassFilter); RPI::PassSystemInterface::Get()->ForEachPass(compositePassFilter, [sizeMultiplier](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
for (RPI::Pass* pass : compositePasses)
{ {
RPI::FullscreenTrianglePass* compositePass = static_cast<RPI::FullscreenTrianglePass*>(pass); RPI::FullscreenTrianglePass* compositePass = static_cast<RPI::FullscreenTrianglePass*>(pass);
auto constantIndex = compositePass->GetShaderResourceGroup()->FindShaderInputConstantIndex(Name("m_imageScale")); RHI::ShaderInputNameIndex imageScaleShaderInput = "m_imageScale";
compositePass->GetShaderResourceGroup()->SetConstant(constantIndex, aznumeric_cast<uint32_t>(1.0f / sizeMultiplier)); 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);
const Name& passName = fullscreenTrianglePass->GetName();
if (passName.GetStringView() == "CopyToSwapChain")
{ {
fullscreenTrianglePass->QueueForInitialization(); pass->QueueForInitialization();
} return RPI::PassFilterExecutionFlow::StopVisitingPasses;
} });
}
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);
for (RPI::Pass* pass : imguiPasses) RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass<ImGuiPass>();
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [func](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
{ {
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)
{
if (passHierarchyFilter.size() == 0)
{ {
AZStd::vector<AZ::RPI::Pass*> foundPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passHierarchyFilter); 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); ImGuiPass* imGuiPass = azrtti_cast<ImGuiPass*>(pass);
if (imGuiPass) if (imGuiPass)
{ {
foundImGuiPasses.push_back(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>
@ -260,23 +261,18 @@ 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); RPI::PassFilter histogramPassFilter = RPI::PassFilter::CreateWithPassName(m_luminanceHistogramGeneratorNameId, GetParentScene());
if (histogramGenerator) 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*>(passes.front()); Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast<ReflectionScreenSpaceBlurPass*>(pass);
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,11 +33,11 @@ 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()) RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
{ {
Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast<ReflectionScreenSpaceBlurPass*>(passes.front()); Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast<ReflectionScreenSpaceBlurPass*>(pass);
// compute the max mip level based on the available mips in the previous frame image, and capping it // compute the max mip level based on the available mips in the previous frame image, and capping it
// to stay within a range that has reasonable data // to stay within a range that has reasonable data
@ -46,7 +46,9 @@ namespace AZ
auto constantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_maxMipLevel")); auto constantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_maxMipLevel"));
m_shaderResourceGroup->SetConstant(constantIndex, 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); ProjectedShadowmapsPass* shadowPass = static_cast<ProjectedShadowmapsPass*>(pass);
for (const RPI::RenderPipelinePtr& pipeline : renderPipelines)
{
if (pipeline.get() == shadowPass->GetRenderPipeline())
{
m_projectedShadowmapsPasses.emplace_back(shadowPass); m_projectedShadowmapsPasses.emplace_back(shadowPass);
validPipelineIds.push_back(shadowPass->GetRenderPipeline()->GetId()); return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
} });
}
}
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); EsmShadowmapsPass* esmPass = static_cast<EsmShadowmapsPass*>(pass);
if (esmPass->GetRenderPipeline() && if (esmPass->GetLightTypeName() == LightTypeName)
AZStd::find(validPipelineIds.begin(), validPipelineIds.end(), esmPass->GetRenderPipeline()->GetId()) != validPipelineIds.end() &&
esmPass->GetLightTypeName() == LightTypeName)
{ {
m_esmShadowmapsPasses.emplace_back(esmPass); 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,21 +16,16 @@ namespace AZ
{ {
namespace RPI namespace RPI
{ {
// A base class for a filter which can be used to filter passes class Scene;
class RenderPipeline;
class PassFilter class PassFilter
{ {
public: public:
//! Whether the input pass matches with the filter static PassFilter CreateWithPassName(Name passName, const Scene* scene);
virtual bool Matches(const Pass* pass) const = 0; static PassFilter CreateWithPassName(Name passName, const RenderPipeline* renderPipeline);
//! 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
virtual AZStd::string ToString() const = 0;
};
//! Create a PassFilter with pass hierarchy information
//! Filter for passes which have a matching name and also with ordered parents. //! Filter for passes which have a matching name and also with ordered parents.
//! For example, if the filter is initialized with //! For example, if the filter is initialized with
//! pass name: "ShadowPass1" //! pass name: "ShadowPass1"
@ -43,68 +38,63 @@ namespace AZ
//! Passes with these names wont match: //! Passes with these names wont match:
//! "MainPipeline.ShadowPass1" //! "MainPipeline.ShadowPass1"
//! or "Shadow.MainPipeline.ShadowPass1" //! or "Shadow.MainPipeline.ShadowPass1"
class PassHierarchyFilter static PassFilter CreateWithPassHierarchy(const AZStd::vector<Name>& passHierarchy);
: public PassFilter 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
{ {
public: Empty = 0,
AZ_RTTI(PassHierarchyFilter, "{478F169F-BA97-4321-AC34-EDE823997159}", PassFilter); PassName = AZ_BIT(0),
AZ_CLASS_ALLOCATOR(PassHierarchyFilter, SystemAllocator, 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);
//! Construct filter with only pass name. const Name& GetPassName() const;
PassHierarchyFilter(const Name& passName); const Name& GetPassTemplateName() const;
virtual ~PassHierarchyFilter() = default; uint32_t GetEnabledFilterOptions() const;
//! Construct filter with pass name and its parents' names in the order of the hierarchy //! Return true if the input pass matches the filter
//! This means k-th element is always an ancestor of the (k-1)-th element. bool Matches(const Pass* pass) const;
//! And the last element is the pass name.
PassHierarchyFilter(const AZStd::vector<Name>& passHierarchy);
PassHierarchyFilter(const AZStd::vector<AZStd::string>& passHierarchy);
// PassFilter overrides... //! Return true if the input pass matches the filter with selected filter options
bool Matches(const Pass* pass) const override; //! The input filter options should be a subset of options returned by GetEnabledFilterOptions()
const Name* GetPassName() const override; //! This function is used to avoid extra checks for passes which was already filtered.
AZStd::string ToString() const override; //! 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>
class PassClassFilter
: public PassFilter
{
public:
AZ_RTTI(PassClassFilter, "{AF6E3AD5-433A-462A-997A-F36D8A551D02}", PassFilter);
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> template <typename PassClass>
AZStd::string PassClassFilter<PassClass>::ToString() const PassFilter PassFilter::CreateWithPassClass()
{ {
return AZStd::string::format("PassClassFilter<%s>", PassClass::RTTI_TypeName()); PassFilter filter;
filter.m_passClassTypeId = PassClass::RTTI_Type();
filter.UpdateFilterOptions();
return filter;
} }
} // 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;
@ -198,8 +202,15 @@ 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,57 +8,196 @@
#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;
}
filter.m_passName = Name(passHierarchy.back());
filter.m_parentNames.resize(passHierarchy.size() - 1);
for (uint32_t index = 0; index < filter.m_parentNames.size(); 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();
}
void PassFilter::SetPassName(Name 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);
} }
m_passName = passHierarchy.back(); bool PassFilter::Matches(const Pass* pass, uint32_t options) const
{
AZ_Assert( (options&m_filterOptions) == options, "options should be a subset of m_filterOptions");
m_parentNames.resize(passHierarchy.size() - 1); // return false if the pass doesn't have a pass template or the template's name is not matching
for (uint32_t index = 0; index < m_parentNames.size(); index++) if (options & FilterOptions::PassTemplateName && (!pass->GetPassTemplate() || pass->GetPassTemplate()->m_name != m_templateName))
{ {
m_parentNames[index] = passHierarchy[index]; return false;
} }
if ((options & FilterOptions::PassName) && pass->GetName() != m_passName)
{
return false;
} }
bool PassHierarchyFilter::Matches(const Pass* pass) const if ((options & FilterOptions::PassClass) && pass->RTTI_GetType() != m_passClassTypeId)
{ {
if (pass->GetName() != m_passName) return false;
}
if ((options & FilterOptions::OwnerRenderPipeline) && m_ownerRenderPipeline != pass->GetRenderPipeline())
{ {
return false; return false;
} }
// If the owner render pipeline was checked, the owner scene check can be skipped
if (options & FilterOptions::OwnerScene)
{
if (pass->GetRenderPipeline())
{
// return false if the owner scene doesn't match
if (m_ownerScene != pass->GetRenderPipeline()->GetScene())
{
return false;
}
}
else
{
// return false if the pass doesn't have an owner scene
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"
ParentPass* parent = pass->GetParent(); ParentPass* parent = pass->GetParent();
// search from the back of the array with the most close parent // search from the back of the array with the most close parent
@ -83,26 +222,50 @@ namespace AZ
// move to next parent // move to next parent
parent = parent->GetParent(); 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())
{
m_filterOptions |= FilterOptions::PassName;
} }
if (!m_templateName.IsEmpty())
AZStd::string PassHierarchyFilter::ToString() const
{ {
AZStd::string result = "PassHierarchyFilter"; m_filterOptions |= FilterOptions::PassTemplateName;
for (uint32_t index = 0; index < m_parentNames.size(); index++) }
if (m_parentNames.size() > 0)
{ {
result += AZStd::string::format(" [%s]", m_parentNames[index].GetCStr()); 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 if (passFilter.Matches(pass, options))
for (auto& namePasses : m_passNameMapping)
{ {
for (Pass* pass : namePasses.second) if (passFunction(pass) == PassFilterExecutionFlow::StopVisitingPasses)
{ {
if (passFilter.Matches(pass)) return PassFilterExecutionFlow::StopVisitingPasses;
}
}
}
return PassFilterExecutionFlow::ContinueVisitingPasses;
};
// Check pass template name first
if (filterOptions & PassFilter::FilterOptions::PassTemplateName)
{ {
result.push_back(pass); 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);
@ -488,9 +483,20 @@ namespace AZ
--m_passCounter; --m_passCounter;
} }
AZStd::vector<Pass*> PassSystem::FindPasses(const PassFilter& passFilter) const void PassSystem::ForEachPass(const PassFilter& filter, AZStd::function<PassFilterExecutionFlow(Pass*)> passFunction)
{
return m_passLibrary.ForEachPass(filter, passFunction);
}
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());
@ -479,7 +489,8 @@ namespace AZ
{ {
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