Merge branch 'stabilization/2110' into Atom/santorac/MoveDoubleSided
This commit is contained in:
@@ -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
|
||||
|
||||
+32
-39
@@ -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);
|
||||
}
|
||||
|
||||
+35
-22
@@ -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;
|
||||
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;
|
||||
}
|
||||
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));
|
||||
// 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
|
||||
|
||||
+6
-6
@@ -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;
|
||||
|
||||
|
||||
+8
-12
@@ -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)
|
||||
|
||||
+14
-13
@@ -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);
|
||||
}
|
||||
// [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;
|
||||
});
|
||||
|
||||
const RPI::Ptr<RPI::Pass> histogramGenerator = passSystem->GetRootPass()->FindPassByNameRecursive(m_luminanceHistogramGeneratorNameId);
|
||||
if (histogramGenerator)
|
||||
{
|
||||
histogramGenerator->SetEnabled(m_heatmapEnabled);
|
||||
}
|
||||
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()
|
||||
|
||||
+8
-6
@@ -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;
|
||||
|
||||
+10
-9
@@ -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();
|
||||
}
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+14
-12
@@ -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 Scene;
|
||||
class RenderPipeline;
|
||||
|
||||
class PassFilter
|
||||
{
|
||||
public:
|
||||
//! Whether the input pass matches with the filter
|
||||
virtual bool Matches(const Pass* pass) const = 0;
|
||||
static PassFilter CreateWithPassName(Name passName, const Scene* scene);
|
||||
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;
|
||||
//! 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();
|
||||
|
||||
//! Return this filter's info as a string
|
||||
virtual AZStd::string ToString() const = 0;
|
||||
};
|
||||
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)
|
||||
};
|
||||
|
||||
//! Filter for passes which have a matching name and also with ordered parents.
|
||||
//! For example, if the filter is initialized with
|
||||
//! pass name: "ShadowPass1"
|
||||
//! pass parents names: "MainPipeline", "Shadow"
|
||||
//! Passes with these names match the filter:
|
||||
//! "Root.MainPipeline.SwapChainPass.Shadow.ShadowPass1"
|
||||
//! or "Root.MainPipeline.Shadow.ShadowPass1"
|
||||
//! or "MainPipeline.Shadow.Group1.ShadowPass1"
|
||||
//!
|
||||
//! Passes with these names wont match:
|
||||
//! "MainPipeline.ShadowPass1"
|
||||
//! or "Shadow.MainPipeline.ShadowPass1"
|
||||
class PassHierarchyFilter
|
||||
: public PassFilter
|
||||
{
|
||||
public:
|
||||
AZ_RTTI(PassHierarchyFilter, "{478F169F-BA97-4321-AC34-EDE823997159}", PassFilter);
|
||||
AZ_CLASS_ALLOCATOR(PassHierarchyFilter, SystemAllocator, 0);
|
||||
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.
|
||||
PassHierarchyFilter(const Name& passName);
|
||||
const Name& GetPassName() const;
|
||||
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
|
||||
//! 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);
|
||||
//! Return true if the input pass matches the filter
|
||||
bool Matches(const Pass* pass) const;
|
||||
|
||||
// PassFilter overrides...
|
||||
bool Matches(const Pass* pass) const override;
|
||||
const Name* GetPassName() const override;
|
||||
AZStd::string ToString() const override;
|
||||
//! 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;
|
||||
|
||||
//! 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 matching passes from registered passes with specified filter
|
||||
virtual AZStd::vector<Pass*> FindPasses(const PassFilter& passFilter) const = 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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 filter;
|
||||
}
|
||||
|
||||
filter.m_passName = passHierarchy.back();
|
||||
|
||||
filter.m_parentNames.resize(passHierarchy.size() - 1);
|
||||
for (uint32_t index = 0; index < filter.m_parentNames.size(); index++)
|
||||
{
|
||||
filter.m_parentNames[index] = passHierarchy[index];
|
||||
}
|
||||
filter.UpdateFilterOptions();
|
||||
return filter;
|
||||
}
|
||||
|
||||
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 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();
|
||||
}
|
||||
|
||||
PassHierarchyFilter::PassHierarchyFilter(const AZStd::vector<AZStd::string>& passHierarchy)
|
||||
void PassFilter::SetTemplateName(Name passTemplateName)
|
||||
{
|
||||
if (passHierarchy.size() == 0)
|
||||
{
|
||||
AZ_Assert(false, "passHierarchy should have at least one element");
|
||||
return;
|
||||
}
|
||||
|
||||
m_passName = Name(passHierarchy.back());
|
||||
|
||||
m_parentNames.resize(passHierarchy.size() - 1);
|
||||
for (uint32_t index = 0; index < m_parentNames.size(); index++)
|
||||
{
|
||||
m_parentNames[index] = Name(passHierarchy[index]);
|
||||
}
|
||||
m_templateName = passTemplateName;
|
||||
UpdateFilterOptions();
|
||||
}
|
||||
|
||||
PassHierarchyFilter::PassHierarchyFilter(const AZStd::vector<Name>& passHierarchy)
|
||||
void PassFilter::SetPassClass(TypeId passClassTypeId)
|
||||
{
|
||||
if (passHierarchy.size() == 0)
|
||||
{
|
||||
AZ_Assert(false, "passHierarchy should have at least one element");
|
||||
return;
|
||||
}
|
||||
|
||||
m_passName = passHierarchy.back();
|
||||
|
||||
m_parentNames.resize(passHierarchy.size() - 1);
|
||||
for (uint32_t index = 0; index < m_parentNames.size(); index++)
|
||||
{
|
||||
m_parentNames[index] = passHierarchy[index];
|
||||
}
|
||||
m_passClassTypeId = passClassTypeId;
|
||||
UpdateFilterOptions();
|
||||
}
|
||||
|
||||
bool PassHierarchyFilter::Matches(const Pass* pass) const
|
||||
const Name& PassFilter::GetPassName() const
|
||||
{
|
||||
if (pass->GetName() != m_passName)
|
||||
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();
|
||||
|
||||
// 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::PassName) && pass->GetName() != m_passName)
|
||||
{
|
||||
const Name& parentName = m_parentNames[index];
|
||||
while (parent)
|
||||
{
|
||||
if (parent->GetName() == parentName)
|
||||
{
|
||||
break;
|
||||
}
|
||||
parent = parent->GetParent();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// if parent is nullptr the it didn't find a parent has matching current parentName
|
||||
if (!parent)
|
||||
if ((options & FilterOptions::PassClass) && pass->RTTI_GetType() != m_passClassTypeId)
|
||||
{
|
||||
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())
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
// move to next parent
|
||||
parent = parent->GetParent();
|
||||
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();
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the filter doesn't know matching pass' name, need to go through all registered passes
|
||||
for (auto& namePasses : m_passNameMapping)
|
||||
{
|
||||
for (Pass* pass : namePasses.second)
|
||||
{
|
||||
if (passFilter.Matches(pass))
|
||||
// If user want to skip processing, return directly.
|
||||
if (passFunction(pass) == PassFilterExecutionFlow::StopVisitingPasses)
|
||||
{
|
||||
result.push_back(pass);
|
||||
return PassFilterExecutionFlow::StopVisitingPasses;
|
||||
}
|
||||
}
|
||||
return PassFilterExecutionFlow::ContinueVisitingPasses;
|
||||
}
|
||||
|
||||
// Check with the pass filter and call pass functions
|
||||
for (Pass* pass : passList)
|
||||
{
|
||||
if (passFilter.Matches(pass, options))
|
||||
{
|
||||
if (passFunction(pass) == PassFilterExecutionFlow::StopVisitingPasses)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
AZStd::vector<Pass*> PassSystem::FindPasses(const PassFilter& passFilter) const
|
||||
|
||||
void PassSystem::ForEachPass(const PassFilter& filter, AZStd::function<PassFilterExecutionFlow(Pass*)> passFunction)
|
||||
{
|
||||
return m_passLibrary.FindPasses(passFilter);
|
||||
return m_passLibrary.ForEachPass(filter, passFunction);
|
||||
}
|
||||
|
||||
Pass* PassSystem::FindFirstPass(const PassFilter& filter)
|
||||
{
|
||||
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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user