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

@ -15,11 +15,6 @@
namespace AZ
{
namespace RPI
{
class PassHierarchyFilter;
}
namespace Render
{
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.
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.
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.
virtual bool PopActiveContext() = 0;
//! 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;
//! 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 option Only valid for an InputOutput attachment. Use PassAttachmentReadbackOption::Input to capture the input state
//! and use PassAttachmentReadbackOption::Output to capture the output state

@ -647,54 +647,46 @@ namespace AZ
UpdateViewsOfCascadeSegments();
}
void DirectionalLightFeatureProcessor::CacheCascadedShadowmapsPass() {
const AZStd::vector<RPI::Pass*>& passes = RPI::PassSystemInterface::Get()->GetPassesForTemplateName(Name("CascadedShadowmapsTemplate"));
void DirectionalLightFeatureProcessor::CacheCascadedShadowmapsPass()
{
m_cascadedShadowmapsPasses.clear();
for (RPI::Pass* pass : passes)
{
if (RPI::RenderPipeline* pipeline = pass->GetRenderPipeline())
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();
// 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);
AZ_Assert(shadowPass, "It is not a CascadedShadowmapPass.");
if (pipeline->GetDefaultView())
{
CascadedShadowmapsPass* shadowPass = azrtti_cast<CascadedShadowmapsPass*>(pass);
AZ_Assert(shadowPass, "It is not a CascadedShadowmapPass.");
if (pipeline->GetDefaultView())
{
m_cascadedShadowmapsPasses[pipelineId].push_back(shadowPass);
}
m_cascadedShadowmapsPasses[pipelineId].push_back(shadowPass);
}
}
}
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
});
}
void DirectionalLightFeatureProcessor::CacheEsmShadowmapsPass()
{
const AZStd::vector<RPI::Pass*>& passes = RPI::PassSystemInterface::Get()->GetPassesForTemplateName(Name("EsmShadowmapsTemplate"));
m_esmShadowmapsPasses.clear();
for (RPI::Pass* pass : passes)
{
if (RPI::RenderPipeline* pipeline = pass->GetRenderPipeline())
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(Name("EsmShadowmapsTemplate"), GetParentScene());
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);
AZ_Assert(esmPass, "It is not an EsmShadowmapPass.");
if (esmPass->GetLightTypeName() == m_lightTypeName)
{
EsmShadowmapsPass* esmPass = azrtti_cast<EsmShadowmapsPass*>(pass);
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);
}
m_esmShadowmapsPasses[pipelineId].push_back(esmPass);
}
}
}
}
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
});
}
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,
// to filter out shadows from objects that are excluded from the cubemap
RPI::PassClassFilter<RPI::EnvironmentCubeMapPass> passFilter;
AZStd::vector<AZ::RPI::Pass*> cubeMapPasses = AZ::RPI::PassSystemInterface::Get()->FindPasses(passFilter);
if (!cubeMapPasses.empty())
{
usageFlags |= RPI::View::UsageReflectiveCubeMap;
}
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass<RPI::EnvironmentCubeMapPass>();
passFilter.SetOwenrScene(GetParentScene()); // only handles passes for this scene
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [&usageFlags]([[maybe_unused]] RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
{
usageFlags |= RPI::View::UsageReflectiveCubeMap;
return RPI::PassFilterExecutionFlow::StopVisitingPasses;
});
segment.m_view = RPI::View::CreateView(viewName, usageFlags);
}

@ -80,35 +80,48 @@ namespace AZ
}
// update the size multiplier on the DiffuseProbeGridDownsamplePass output
AZStd::vector<Name> downsamplePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseProbeGridDownsamplePass") };
RPI::PassHierarchyFilter downsamplePassFilter(downsamplePassHierarchy);
const AZStd::vector<RPI::Pass*>& downsamplePasses = RPI::PassSystemInterface::Get()->FindPasses(downsamplePassFilter);
for (RPI::Pass* pass : downsamplePasses)
// 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.
{
for (uint32_t outputIndex = 0; outputIndex < pass->GetOutputCount(); ++outputIndex)
{
RPI::Ptr<RPI::PassAttachment> outputAttachment = pass->GetOutputBinding(outputIndex).m_attachment;
RPI::PassAttachmentSizeMultipliers& sizeMultipliers = outputAttachment->m_sizeMultipliers;
sizeMultipliers.m_widthMultiplier = sizeMultiplier;
sizeMultipliers.m_heightMultiplier = sizeMultiplier;
}
// set the output scale on the PassSrg
RPI::FullscreenTrianglePass* downsamplePass = static_cast<RPI::FullscreenTrianglePass*>(pass);
auto constantIndex = downsamplePass->GetShaderResourceGroup()->FindShaderInputConstantIndex(Name("m_outputImageScale"));
downsamplePass->GetShaderResourceGroup()->SetConstant(constantIndex, aznumeric_cast<uint32_t>(1.0f / sizeMultiplier));
AZStd::vector<Name> downsamplePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseProbeGridDownsamplePass") };
RPI::PassFilter downsamplePassFilter = RPI::PassFilter::CreateWithPassHierarchy(downsamplePassHierarchy);
RPI::PassSystemInterface::Get()->ForEachPass(
downsamplePassFilter,
[sizeMultiplier](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
{
for (uint32_t outputIndex = 0; outputIndex < pass->GetOutputCount(); ++outputIndex)
{
RPI::Ptr<RPI::PassAttachment> outputAttachment = pass->GetOutputBinding(outputIndex).m_attachment;
RPI::PassAttachmentSizeMultipliers& sizeMultipliers = outputAttachment->m_sizeMultipliers;
sizeMultipliers.m_widthMultiplier = 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
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);
auto constantIndex = compositePass->GetShaderResourceGroup()->FindShaderInputConstantIndex(Name("m_imageScale"));
compositePass->GetShaderResourceGroup()->SetConstant(constantIndex, aznumeric_cast<uint32_t>(1.0f / sizeMultiplier));
AZStd::vector<Name> compositePassHierarchy = { Name("DiffuseGlobalIlluminationPass"), Name("DiffuseCompositePass") };
RPI::PassFilter compositePassFilter = RPI::PassFilter::CreateWithPassHierarchy(compositePassHierarchy);
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

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

@ -10,9 +10,10 @@
#include <ACES/Aces.h>
#include <Atom/Feature/ACES/AcesDisplayMapperFeatureProcessor.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/PassSystemInterface.h>
#include <Atom/RPI.Public/Pass/PassUtils.h>
#include <Atom/RPI.Public/Pass/Specific/SwapChainPass.h>
#include <Atom/RPI.Public/RenderPipeline.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
// the swapchain format changed (for example, moving from LDR to HDR display)
auto* passSystem = RPI::PassSystemInterface::Get();
const Name fullscreenCopyTemplateName("FullscreenCopyTemplate");
if (passSystem->HasPassesForTemplateName(fullscreenCopyTemplateName))
{
const AZStd::vector<RPI::Pass*>& passes = passSystem->GetPassesForTemplateName(fullscreenCopyTemplateName);
for (RPI::Pass* pass : passes)
const Name copyToSwapChainPassName("CopyToSwapChain");
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(copyToSwapChainPassName, GetRenderPipeline());
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
{
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();
}

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

@ -109,15 +109,15 @@ namespace AZ
void ImGuiSystemComponent::ForAllImGuiPasses(PassFunction func)
{
ImGuiContext* contextToRestore = ImGui::GetCurrentContext();
RPI::PassClassFilter<ImGuiPass> filter;
auto imguiPasses = RPI::PassSystemInterface::Get()->FindPasses(filter);
for (RPI::Pass* pass : imguiPasses)
{
ImGuiPass* imguiPass = azrtti_cast<ImGuiPass*>(pass);
ImGui::SetCurrentContext(imguiPass->GetContext());
func(imguiPass);
}
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass<ImGuiPass>();
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [func](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
{
ImGuiPass* imguiPass = azrtti_cast<ImGuiPass*>(pass);
ImGui::SetCurrentContext(imguiPass->GetContext());
func(imguiPass);
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
});
ImGui::SetCurrentContext(contextToRestore);
}
@ -169,29 +169,37 @@ namespace AZ
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;
for (RPI::Pass* pass : foundPasses)
{
ImGuiPass* imGuiPass = azrtti_cast<ImGuiPass*>(pass);
if (imGuiPass)
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassHierarchy(passHierarchyFilter);
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [&foundImGuiPasses](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
{
foundImGuiPasses.push_back(imGuiPass);
}
}
ImGuiPass* imGuiPass = azrtti_cast<ImGuiPass*>(pass);
if (imGuiPass)
{
foundImGuiPasses.push_back(imGuiPass);
}
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
});
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;
}
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();

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

@ -15,6 +15,7 @@
#include <AzFramework/Asset/AssetSystemBus.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/RenderPipeline.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
void DepthOfFieldSettings::UpdateAutoFocusDepth(bool enabled)
{
auto* passSystem = AZ::RPI::PassSystemInterface::Get();
{
const Name TemplateNameReadBackFocusDepth = Name("DepthOfFieldReadBackFocusDepthTemplate");
if (passSystem->HasPassesForTemplateName(TemplateNameReadBackFocusDepth))
{
const AZStd::vector<RPI::Pass*>& dofPasses = passSystem->GetPassesForTemplateName(TemplateNameReadBackFocusDepth);
for (RPI::Pass* pass : dofPasses)
// [GFX TODO][ATOM-4908] multiple camera should be distingushed.
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithTemplateName(TemplateNameReadBackFocusDepth, GetParentScene());
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this, enabled](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
{
auto* dofPass = azrtti_cast<AZ::Render::DepthOfFieldReadBackFocusDepthPass*>(pass);
// Check this pass belongs to a render pipeline of the scene.
// [GFX TODO][ATOM-4908] multiple camera should be distingushed.
const RPI::RenderPipelineId pipelineId = dofPass->GetRenderPipeline()->GetId();
if (enabled && GetParentScene()->GetRenderPipeline(pipelineId))
if (enabled)
{
m_normalizedFocusDistanceForAutoFocus = dofPass->GetNormalizedFocusDistanceForAutoFocus();
}
}
}
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
});
}
void DepthOfFieldSettings::SetCameraEntityId(EntityId cameraEntityId)

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

@ -31,12 +31,14 @@ namespace AZ
0,
[](const uint8_t& value)
{
auto passes = RPI::PassSystem::Get()->FindPasses(RPI::PassClassFilter<LookModificationCompositePass>());
for (auto* pass : passes)
{
LookModificationCompositePass* lookModPass = azrtti_cast<LookModificationCompositePass*>(pass);
lookModPass->SetSampleQuality(LookModificationCompositePass::SampleQuality(value));
}
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassClass<LookModificationCompositePass>();
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [value](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
{
LookModificationCompositePass* lookModPass = azrtti_cast<LookModificationCompositePass*>(pass);
lookModPass->SetSampleQuality(LookModificationCompositePass::SampleQuality(value));
return RPI::PassFilterExecutionFlow::ContinueVisitingPasses;
});
},
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."

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

@ -377,14 +377,7 @@ namespace AZ
bool ProfilingCaptureSystemComponent::CapturePassTimestamp(const AZStd::string& outputFilePath)
{
// Find the root pass.
AZStd::vector<RPI::Pass*> passes = FindPasses({ "Root" });
if (passes.empty())
{
return false;
}
RPI::Pass* root = passes[0];
RPI::Pass* root = AZ::RPI::PassSystemInterface::Get()->GetRootPass().get();
// Enable all the Timestamp queries in passes.
root->SetTimestampQueryEnabled(true);
@ -465,14 +458,7 @@ namespace AZ
bool ProfilingCaptureSystemComponent::CapturePassPipelineStatistics(const AZStd::string& outputFilePath)
{
// Find the root pass.
AZStd::vector<RPI::Pass*> passes = FindPasses({ "Root" });
if (passes.empty())
{
return false;
}
RPI::Pass* root = passes[0];
RPI::Pass* root = AZ::RPI::PassSystemInterface::Get()->GetRootPass().get();
// Enable all the PipelineStatistics queries in passes.
root->SetPipelineStatisticsQueryEnabled(true);
@ -572,19 +558,6 @@ namespace AZ
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)
{
// Update the delayed captures

@ -78,8 +78,6 @@ namespace AZ
// Recursively collect all the passes from the root pass.
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_cpuFrameTimeStatisticsCapture;
DelayedQueryCaptureHelper m_pipelineStatisticsCapture;

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

@ -150,7 +150,7 @@ namespace AZ
auto transientImageDesc = RHI::ImageDescriptor::Create2D(imageBindFlags, mipSize.m_width, mipSize.m_height, RHI::Format::R16G16B16A16_FLOAT);
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_path = transientAttachmentName;
transientPassAttachment->m_lifetime = RHI::AttachmentLifetimeType::Transient;

@ -33,20 +33,22 @@ namespace AZ
return;
}
RPI::PassHierarchyFilter passFilter(AZ::Name("ReflectionScreenSpaceBlurPass"));
const AZStd::vector<RPI::Pass*>& passes = RPI::PassSystemInterface::Get()->FindPasses(passFilter);
if (!passes.empty())
{
Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast<ReflectionScreenSpaceBlurPass*>(passes.front());
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(AZ::Name("ReflectionScreenSpaceBlurPass"), GetRenderPipeline());
// 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
const uint32_t MaxNumRoughnessMips = 8;
uint32_t maxMipLevel = AZStd::min(MaxNumRoughnessMips, blurPass->GetNumBlurMips()) - 1;
RPI::PassSystemInterface::Get()->ForEachPass(passFilter, [this](RPI::Pass* pass) -> RPI::PassFilterExecutionFlow
{
Render::ReflectionScreenSpaceBlurPass* blurPass = azrtti_cast<ReflectionScreenSpaceBlurPass*>(pass);
auto constantIndex = m_shaderResourceGroup->FindShaderInputConstantIndex(Name("m_maxMipLevel"));
m_shaderResourceGroup->SetConstant(constantIndex, maxMipLevel);
}
// 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
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);
}

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

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

@ -17,6 +17,7 @@
#include <MorphTargets/MorphTargetDispatchItem.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/RPIUtils.h>
#include <Atom/RPI.Public/Shader/Shader.h>
@ -241,12 +242,12 @@ namespace AZ
void SkinnedMeshFeatureProcessor::OnRenderPipelineAdded(RPI::RenderPipelinePtr pipeline)
{
InitSkinningAndMorphPass(pipeline->GetRootPass());
InitSkinningAndMorphPass(pipeline.get());
}
void SkinnedMeshFeatureProcessor::OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline)
{
InitSkinningAndMorphPass(renderPipeline->GetRootPass());
InitSkinningAndMorphPass(renderPipeline);
}
void SkinnedMeshFeatureProcessor::OnBeginPrepareRender()
@ -289,9 +290,10 @@ namespace AZ
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)
{
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)
{
MorphTargetComputePass* morphTargetComputePass = azdynamic_cast<MorphTargetComputePass*>(morphTargetPass.get());

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

@ -68,9 +68,6 @@ namespace AZ
template<typename PassType>
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
AZStd::array_view<Ptr<Pass>> GetChildren() const;

@ -139,6 +139,10 @@ namespace AZ
//! Returns the number of output attachment bindings
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
//! If the pass is disabled, it (and any children if it's a ParentPass) won't be rendered.
void SetEnabled(bool enabled);

@ -16,95 +16,85 @@ namespace AZ
{
namespace RPI
{
// A base class for a filter which can be used to filter passes
class PassFilter
{
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;
class Scene;
class RenderPipeline;
//! Return this filter's info as a string
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
class PassFilter
{
public:
AZ_RTTI(PassHierarchyFilter, "{478F169F-BA97-4321-AC34-EDE823997159}", PassFilter);
AZ_CLASS_ALLOCATOR(PassHierarchyFilter, SystemAllocator, 0);
//! Construct filter with only pass name.
PassHierarchyFilter(const Name& passName);
virtual ~PassHierarchyFilter() = default;
//! Construct filter with pass name and its parents' names in the order of the hierarchy
//! This means k-th element is always an ancestor of the (k-1)-th element.
//! And the last element is the pass name.
PassHierarchyFilter(const AZStd::vector<Name>& passHierarchy);
PassHierarchyFilter(const AZStd::vector<AZStd::string>& passHierarchy);
// PassFilter overrides...
bool Matches(const Pass* pass) const override;
const Name* GetPassName() const override;
AZStd::string ToString() const override;
static PassFilter CreateWithPassName(Name passName, const Scene* scene);
static PassFilter CreateWithPassName(Name passName, const RenderPipeline* renderPipeline);
//! Create a PassFilter with pass hierarchy information
//! 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"
static PassFilter CreateWithPassHierarchy(const AZStd::vector<Name>& passHierarchy);
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:
PassHierarchyFilter() = delete;
void UpdateFilterOptions();
AZStd::vector<Name> m_parentNames;
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>
AZStd::string PassClassFilter<PassClass>::ToString() const
{
return AZStd::string::format("PassClassFilter<%s>", PassClass::RTTI_TypeName());
template <typename PassClass>
PassFilter PassFilter::CreateWithPassClass()
{
PassFilter filter;
filter.m_passClassTypeId = PassClass::RTTI_Type();
filter.UpdateFilterOptions();
return filter;
}
} // namespace RPI
} // namespace AZ

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

@ -92,13 +92,13 @@ namespace AZ
// PassSystemInterface library related functions...
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;
const AZStd::shared_ptr<PassTemplate> GetPassTemplate(const Name& name) const override;
void RemovePassFromLibrary(Pass* pass) override;
void RegisterPass(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:
// Returns the root of the pass tree hierarchy

@ -75,6 +75,13 @@ namespace AZ
u32 m_maxDrawItemsRenderedInAPass = 0;
};
enum PassFilterExecutionFlow : uint8_t
{
StopVisitingPasses,
ContinueVisitingPasses,
};
class PassSystemInterface
{
friend class Pass;
@ -186,9 +193,6 @@ namespace AZ
//! Returns true if the pass factory contains passes created with the given template name
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
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
virtual void RemovePassFromLibrary(Pass* pass) = 0;
//! Find matching passes from registered passes with specified filter
virtual AZStd::vector<Pass*> FindPasses(const PassFilter& passFilter) const = 0;
//! Visit the matching passes from registered passes with specified filter
//! 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:
// 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);
}
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
{
if (HasDrawListTag() && GetDrawListTag() == drawListTag)

@ -238,6 +238,11 @@ namespace AZ
return m_attachmentBindings[bindingIndex];
}
const PassTemplate* Pass::GetPassTemplate() const
{
return m_template.get();
}
void Pass::AddAttachmentBinding(PassAttachmentBinding attachmentBinding)
{
// 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/ParentPass.h>
#include <Atom/RPI.Public/RenderPipeline.h>
namespace AZ
{
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)
{
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);
for (uint32_t index = 0; index < m_parentNames.size(); index++)
filter.m_parentNames.resize(passHierarchy.size() - 1);
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)
{
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);
for (uint32_t index = 0; index < m_parentNames.size(); index++)
filter.m_parentNames.resize(passHierarchy.size() - 1);
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;
}
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
for (int32_t index = static_cast<int32_t>(m_parentNames.size() - 1); index >= 0; index--)
if ((options & FilterOptions::PassClass) && pass->RTTI_GetType() != m_passClassTypeId)
{
const Name& parentName = m_parentNames[index];
while (parent)
return false;
}
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();
}
// if parent is nullptr the it didn't find a parent has matching current parentName
if (!parent)
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"
// move to next parent
parent = parent->GetParent();
ParentPass* parent = pass->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;
}
const Name* PassHierarchyFilter::GetPassName() const
void PassFilter::UpdateFilterOptions()
{
return &m_passName;
}
AZStd::string PassHierarchyFilter::ToString() const
{
AZStd::string result = "PassHierarchyFilter";
for (uint32_t index = 0; index < m_parentNames.size(); index++)
m_filterOptions = FilterOptions::Empty;
if (!m_passName.IsEmpty())
{
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 AZ

@ -85,47 +85,80 @@ namespace AZ
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;
if (passName)
// 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 the pass' name is known, find passes with matching names first
const auto constItr = m_passNameMapping.find(*passName);
if (constItr == m_passNameMapping.end())
if (passList.size() == 0)
{
return result;
return PassFilterExecutionFlow::ContinueVisitingPasses;
}
const AZStd::vector<Pass*>& passes = constItr->second;
for (Pass* pass : passes)
// if there is not other filter options enabled, skip the filter and call pass functions directly
if (options == PassFilter::FilterOptions::Empty)
{
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
{
// If the filter doesn't know matching pass' name, need to go through all registered passes
for (auto& namePasses : m_passNameMapping)
// Check with the pass filter and call pass functions
for (Pass* pass : passList)
{
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...
@ -419,3 +452,4 @@ namespace AZ
} // namespace RPI
} // namespace AZ

@ -456,11 +456,6 @@ namespace AZ
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)
{
return m_passLibrary.AddPassTemplate(name, passTemplate);
@ -487,10 +482,21 @@ namespace AZ
RemovePassFromLibrary(pass);
--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

@ -19,6 +19,8 @@
#include <Atom/RPI.Public/Pass/PassSystem.h>
#include <Atom/RPI.Public/Pass/RasterPass.h>
#include <Atom/RPI.Public/RenderPipeline.h>
#include <AzCore/UnitTest/TestTypes.h>
#include <Common/RPITestFixture.h>
@ -573,7 +575,7 @@ namespace UnitTest
EXPECT_TRUE(pass != nullptr);
}
TEST_F(PassTests, PassHierarchyFilter)
TEST_F(PassTests, PassFilter_PassHierarchy)
{
m_data->AddPassTemplatesToLibrary();
@ -587,62 +589,55 @@ namespace UnitTest
parent2->AsParent()->AddChild(parent1);
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
PassHierarchyFilter filter({ Name("pass1") });
PassFilter filter = PassFilter::CreateWithPassHierarchy({Name("pass1")});
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;
PassHierarchyFilter filter(AZStd::vector<Name>{});
PassFilter filter = PassFilter::CreateWithPassHierarchy(AZStd::vector<Name>{});
AZ_TEST_STOP_TRACE_SUPPRESSION(1);
EXPECT_FALSE(filter.Matches(pass.get()));
}
{
// Filters with partial hierarchy by using string vector
AZStd::vector<AZStd::string> passHierarchy1 = { "parent1", "pass1" };
PassHierarchyFilter filter1(passHierarchy1);
PassFilter filter1 = PassFilter::CreateWithPassHierarchy(passHierarchy1);
EXPECT_TRUE(filter1.Matches(pass.get()));
AZStd::vector<AZStd::string> passHierarchy2 = { "parent2", "pass1" };
PassHierarchyFilter filter2(passHierarchy2);
PassFilter filter2 = PassFilter::CreateWithPassHierarchy(passHierarchy2);
EXPECT_TRUE(filter2.Matches(pass.get()));
AZStd::vector<AZStd::string> passHierarchy3 = { "parent3", "parent2", "pass1" };
PassHierarchyFilter filter3(passHierarchy3);
PassFilter filter3 = PassFilter::CreateWithPassHierarchy(passHierarchy3);
EXPECT_TRUE(filter3.Matches(pass.get()));
}
{
// Filters with partial hierarchy by using Name vector
AZStd::vector<Name> passHierarchy1 = { Name("parent1"), Name("pass1") };
PassHierarchyFilter filter1(passHierarchy1);
PassFilter filter1 = PassFilter::CreateWithPassHierarchy(passHierarchy1);
EXPECT_TRUE(filter1.Matches(pass.get()));
AZStd::vector<Name> passHierarchy2 = { Name("parent2"), Name("pass1")};
PassHierarchyFilter filter2(passHierarchy2);
PassFilter filter2 = PassFilter::CreateWithPassHierarchy(passHierarchy2);
EXPECT_TRUE(filter2.Matches(pass.get()));
AZStd::vector<Name> passHierarchy3 = { Name("parent3"), Name("parent2"), Name("pass1") };
PassHierarchyFilter filter3(passHierarchy3);
PassFilter filter3 = PassFilter::CreateWithPassHierarchy(passHierarchy3);
EXPECT_TRUE(filter3.Matches(pass.get()));
}
{
// 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()));
PassHierarchyFilter filter2(Name("parent1"));
PassFilter filter2 = PassFilter::CreateWithPassHierarchy({ Name("parent1") });
EXPECT_TRUE(filter2.Matches(parent1.get()));
EXPECT_FALSE(filter2.Matches(pass.get()));
}
@ -650,11 +645,131 @@ namespace UnitTest
{
// Failed to find pass
// 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()));
// 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()));
}
}
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/Scene.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/RPIUtils.h>
#include <Atom/RPI.Public/Shader/Shader.h>
@ -142,12 +143,13 @@ namespace AZ
EnablePasses(true);
}
void HairFeatureProcessor::EnablePasses([[maybe_unused]] bool enable)
void HairFeatureProcessor::EnablePasses(bool enable)
{
RPI::Ptr<RPI::Pass> desiredPass = m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairParentPassName);
if (desiredPass)
RPI::PassFilter passFilter = RPI::PassFilter::CreateWithPassName(HairParentPassName, GetParentScene());
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;
}
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)
{
// Proceed only if this is the main pipeline that contains the parent pass
if (!renderPipeline.get()->GetRootPass()->FindPassByNameRecursive(HairParentPassName))
if (!HasHairParentPass())
{
return;
}
@ -323,10 +332,10 @@ namespace AZ
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
if (!renderPipeline->GetRootPass()->FindPassByNameRecursive(HairParentPassName))
if (!HasHairParentPass())
{
return;
}
@ -338,7 +347,7 @@ namespace AZ
void HairFeatureProcessor::OnRenderPipelinePassesChanged(RPI::RenderPipeline* renderPipeline)
{
// Proceed only if this is the main pipeline that contains the parent pass
if (!renderPipeline->GetRootPass()->FindPassByNameRecursive(HairParentPassName))
if (!HasHairParentPass())
{
return;
}
@ -457,7 +466,8 @@ namespace AZ
{
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)
{
m_computePasses[passName] = static_cast<HairSkinningComputePass*>(desiredPass.get());
@ -478,8 +488,9 @@ namespace AZ
bool HairFeatureProcessor::InitPPLLFillPass()
{
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)
{
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
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)
{
m_hairPPLLResolvePass = static_cast<HairPPLLResolvePass*>(desiredPass.get());
@ -518,8 +530,8 @@ namespace AZ
m_hairShortCutGeometryDepthAlphaPass = nullptr;
m_hairShortCutGeometryShadingPass = nullptr;
m_hairShortCutGeometryDepthAlphaPass = static_cast<HairShortCutGeometryDepthAlphaPass*>(
m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairShortCutGeometryDepthAlphaPassName).get());
RPI::PassFilter depthAlphaPassFilter = RPI::PassFilter::CreateWithPassName(HairShortCutGeometryDepthAlphaPassName, m_renderPipeline);
m_hairShortCutGeometryDepthAlphaPass = static_cast<HairShortCutGeometryDepthAlphaPass*>(RPI::PassSystemInterface::Get()->FindFirstPass(depthAlphaPassFilter));
if (m_hairShortCutGeometryDepthAlphaPass)
{
m_hairShortCutGeometryDepthAlphaPass->SetFeatureProcessor(this);
@ -530,8 +542,8 @@ namespace AZ
return false;
}
m_hairShortCutGeometryShadingPass = static_cast<HairShortCutGeometryShadingPass*>(
m_renderPipeline->GetRootPass()->FindPassByNameRecursive(HairShortCutGeometryShadingPassName).get());
RPI::PassFilter shaderingPassFilter = RPI::PassFilter::CreateWithPassName(HairShortCutGeometryShadingPassName, m_renderPipeline);
m_hairShortCutGeometryShadingPass = static_cast<HairShortCutGeometryShadingPass*>(RPI::PassSystemInterface::Get()->FindFirstPass(shaderingPassFilter));
if (m_hairShortCutGeometryShadingPass)
{
m_hairShortCutGeometryShadingPass->SetFeatureProcessor(this);

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

Loading…
Cancel
Save