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

659 lines
31 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#include <Atom/RPI.Public/Base.h>
#include <Atom/RPI.Public/Buffer/Buffer.h>
#include <Atom/RPI.Public/GpuQuery/GpuQuerySystemInterface.h>
#include <Atom/RPI.Reflect/Image/Image.h>
#include <Atom/RPI.Public/Image/AttachmentImage.h>
#include <Atom/RPI.Public/Image/AttachmentImage.h>
#include <Atom/RPI.Public/Pass/PassAttachment.h>
#include <Atom/RPI.Public/Pass/PassDefines.h>
#include <Atom/RPI.Public/Pass/PassSystemInterface.h>
#include <Atom/RPI.Reflect/Pass/PassAsset.h>
#include <Atom/RPI.Reflect/Pass/PassDescriptor.h>
#include <Atom/RHI/DrawList.h>
#include <Atom/RHI.Reflect/Limits.h>
#include <Atom/RHI.Reflect/Scissor.h>
#include <Atom/RHI.Reflect/Viewport.h>
#include <AzCore/std/containers/span.h>
#include <AzCore/Memory/SystemAllocator.h>
#include <AzCore/std/containers/map.h>
#include <AzCore/std/smart_ptr/unique_ptr.h>
#define AZ_RPI_PASS(PASS_NAME) \
friend class PassFactory; \
friend class PassLibrary; \
friend class PassSystem; \
friend class PassFactory; \
friend class ParentPass; \
friend class RenderPipeline; \
friend class UnitTest::PassTests; \
namespace UnitTest
{
class PassTests;
}
namespace AZ
{
namespace RHI
{
class FrameGraphBuilder;
class FrameGraphAttachmentInterface;
}
namespace RPI
{
class Pass;
class PassTemplate;
struct PassRequest;
struct PassValidationResults;
class AttachmentReadback;
class ImageAttachmentCopy;
using SortedPipelineViewTags = AZStd::set<PipelineViewTag, AZNameSortAscending>;
using PassesByDrawList = AZStd::map<RHI::DrawListTag, const Pass*>;
const uint32_t PassAttachmentBindingCountMax = 32;
const uint32_t PassInputBindingCountMax = 16;
const uint32_t PassInputOutputBindingCountMax = PassInputBindingCountMax;
const uint32_t PassOutputBindingCountMax = PassInputBindingCountMax;
enum class PassAttachmentReadbackOption : uint8_t
{
Input = 0,
Output
};
//! Atom's base pass class (every pass class in Atom must derive from this class).
//!
//! Passes are organized into a tree hierarchy with the derived ParentPass class.
//! The root of the entire hierarchy is owned by the PassSystem.
//!
//! When authoring a new pass class, inherit from Pass and override any of the virtual functions
//! ending with 'Internal' to define the behavior of your passes. These virtual are recursively
//! called in preorder traversal throughout the pass tree. Only FrameBegin and FrameEnd are
//! guaranteed to be called per frame. The other override-able functions are called as needed
//! when scheduled with the PassSystem. See QueueForBuildAndInitialization, QueueForRemoval and QueueForInitialization.
//!
//! Passes are created by the PassFactory. They can be created using either Pass Name,
//! a PassTemplate, or a PassRequest. To register your pass class with the PassFactory,
//! you'll need to write a static create method (see ParentPass and RenderPass for examples)
//! and register this create method with the PassFactory.
class Pass
: public AZStd::intrusive_base
{
AZ_RPI_PASS(Pass);
friend class ImageAttachmentPreviewPass;
public:
using ChildPassIndex = RHI::Handle<uint32_t, class ChildPass>;
// Input parameters for Prepare
struct FramePrepareParams
{
FramePrepareParams(RHI::FrameGraphBuilder* frameGraphBuilder = nullptr)
: m_frameGraphBuilder(frameGraphBuilder)
{}
RHI::FrameGraphBuilder* m_frameGraphBuilder = nullptr;
// This should include SRGs that are higher level than
// the Pass, like per-frame and per-scene SRGs.
const ShaderResourceGroupList* m_shaderResourceGroupsToBind = nullptr;
RHI::Scissor m_scissorState;
RHI::Viewport m_viewportState;
};
AZ_RTTI(Pass, "{EA34FF66-631D-433B-B449-71F5647E7BB5}", AZStd::intrusive_base);
AZ_CLASS_ALLOCATOR(Pass, SystemAllocator, 0);
virtual ~Pass();
// --- Simple getters/setters ---
//! Returns the name of the pass (example: Bloom)
const Name& GetName() const;
//! Return the path name of the pass (example: Root.SwapChain.Bloom)
const Name& GetPathName() const;
//! Returns the depth of this pass in the tree hierarchy (Root depth is 0)
uint32_t GetTreeDepth() const;
//! Returns the number of input attachment bindings
uint32_t GetInputCount() const;
//! Returns the number of input/output attachment bindings
uint32_t GetInputOutputCount() const;
//! 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);
virtual bool IsEnabled() const;
bool HasDrawListTag() const;
bool HasPipelineViewTag() const;
//! Return the set of attachment bindings
PassAttachmentBindingListView GetAttachmentBindings() const;
//! Casts the pass to a parent pass if valid, else returns nullptr
ParentPass* AsParent();
const ParentPass* AsParent() const;
// --- Utility functions ---
//! Queues the pass to have Build() and Initialize() called by the PassSystem on frame update
void QueueForBuildAndInitialization();
//! Queues the pass to have RemoveFromParent() called by the PassSystem on frame update
void QueueForRemoval();
//! Queues the pass to have Initialize() called by the PassSystem on frame update
void QueueForInitialization();
//! Adds an attachment binding to the list of this Pass' attachment bindings
void AddAttachmentBinding(PassAttachmentBinding attachmentBinding);
// Returns a reference to the N-th input binding, where N is the index passed to the function
PassAttachmentBinding& GetInputBinding(uint32_t index);
// Returns a reference to the N-th input/output binding, where N is the index passed to the function
PassAttachmentBinding& GetInputOutputBinding(uint32_t index);
// Returns a reference to the N-th output binding, where N is the index passed to the function
PassAttachmentBinding& GetOutputBinding(uint32_t index);
//! Attach an external buffer resource as attachment to specified slot
//! The buffer will be added as a pass attachment then attach to the pass slot
//! Note: the pass attachment and binding will be removed after the general Build call.
//! you can add this call in pass' BuildInternal so it will be added whenever attachments get rebuilt
void AttachBufferToSlot(AZStd::string_view slot, Data::Instance<Buffer> buffer);
void AttachBufferToSlot(const Name& slot, Data::Instance<Buffer> buffer);
void AttachImageToSlot(const Name& slot, Data::Instance<AttachmentImage> image);
// --- Virtual functions which may need to be override by derived classes ---
//! Collect all different view tags from this pass
virtual void GetPipelineViewTags(SortedPipelineViewTags& outTags) const;
//! Adds this pass' DrawListTags to the outDrawListMask.
virtual void GetViewDrawListInfo(RHI::DrawListMask& outDrawListMask, PassesByDrawList& outPassesByDrawList, const PipelineViewTag& viewTag) const;
//! Check if the pass has a DrawListTag. Pass' DrawListTag can be used to filter draw items.
virtual RHI::DrawListTag GetDrawListTag() const;
//! Function used by views to sort draw lists. Can be overridden so passes can provide custom sort functionality.
virtual void SortDrawList(RHI::DrawList& drawList) const;
//! Check if the pass is associated to a view. If pass has a pipeline view tag, the rpi view assigned to this view tag will have pass's draw list tag.
virtual const PipelineViewTag& GetPipelineViewTag() const;
//! Set render pipeline this pass belongs to
virtual void SetRenderPipeline(RenderPipeline* pipeline);
RenderPipeline* GetRenderPipeline() const;
Scene* GetScene() const;
//! Validates entire tree hierarchy (ensures passes have valid state and attachments).
//! Functionality compiled out if AZ_RPI_ENABLE_PASS_VALIDATION is not defined.
virtual void Validate(PassValidationResults& validationResults);
// --- Debug and validation print functions ---
//! Prints the pass
virtual void DebugPrint() const;
//! Return the latest Timestamp result of this pass
TimestampResult GetLatestTimestampResult() const;
//! Return the latest PipelineStatistic result of this pass
PipelineStatisticsResult GetLatestPipelineStatisticsResult() const;
//! Enables/Disables Timestamp queries for this pass
virtual void SetTimestampQueryEnabled(bool enable);
//! Enables/Disables PipelineStatistics queries for this pass
virtual void SetPipelineStatisticsQueryEnabled(bool enable);
//! Readback an attachment attached to the specified slot name
//! @param readback The AttachmentReadback object which is used for readback. Its callback function will be called when readback is finished.
//! @param slotName The attachment bind to the slot with this slotName is to be readback
//! @param option The option is used for choosing input or output state when readback an InputOutput attachment.
//! It's ignored if the attachment isn't an InputOutput attachment.
//! Return true if the readback request was successful. User may expect the AttachmentReadback's callback function would be called.
bool ReadbackAttachment(AZStd::shared_ptr<AttachmentReadback> readback, const Name& slotName, PassAttachmentReadbackOption option = PassAttachmentReadbackOption::Output);
//! Returns whether the Timestamp queries is enabled/disabled for this pass
bool IsTimestampQueryEnabled() const;
//! Returns whether the PipelineStatistics queries is enabled/disabled for this pass
bool IsPipelineStatisticsQueryEnabled() const;
//! Helper function to print spaces to indent the pass
void PrintIndent(AZStd::string& stringOutput, uint32_t indent) const;
//! Prints the name of the pass
void PrintPassName(AZStd::string& stringOutput, uint32_t indent = 0) const;
//! Prints the attachment binding at the given index
void DebugPrintBinding(AZStd::string& stringOutput, const PassAttachmentBinding& binding) const;
//! Prints the attachment binding at the given index and its connection
void DebugPrintBindingAndConnection(AZStd::string& stringOutput, uint8_t bindingIndex) const;
//! Prints the pass name and all the errors accumulated during build and setup
void PrintErrors() const;
//! Prints the pass name and all the warnings accumulated during build and setup
void PrintWarnings() const;
//! Helper function to print an array of messages (like errors or warnings) for a pass
void PrintMessages(const AZStd::vector<AZStd::string>& messages) const;
//! Prints the pass and all the list of inputs and input/outputs that are missing an attachment
void PrintBindingsWithoutAttachments(uint32_t slotTypeMask) const;
//! Returns pointer to the parent pass
ParentPass* GetParent() const;
PassState GetPassState() const;
// Update all bindings on this pass that are connected to bindings on other passes
void UpdateConnectedBindings();
// Update input and input/output bindings on this pass that are connected to bindings on other passes
void UpdateConnectedInputBindings();
// Update output bindings on this pass that are connected to bindings on other passes
void UpdateConnectedOutputBindings();
protected:
explicit Pass(const PassDescriptor& descriptor);
// Creates a pass descriptor for creating a duplicate pass. Used for hot reloading.
PassDescriptor GetPassDescriptor() const;
// Imports owned imported attachments into the FrameGraph
// Called in pass's frame prepare function
void ImportAttachments(RHI::FrameGraphAttachmentInterface attachmentDatabase);
// --- Find functions ---
// Searches for an adjacent pass with the given Name. An adjacent pass is either:
// a parent pass, a child pass, a sibling pass or the pass itself (this).
// Special names: "This" will return this, and "Parent" will return the parent pass.
// Search order: 1.This -> 2.Parent -> 3.Siblings -> 4.Children
Ptr<Pass> FindAdjacentPass(const Name& passName);
// Searches this pass's attachment bindings for one with the provided Name (nullptr if none found)
PassAttachmentBinding* FindAttachmentBinding(const Name& slotName);
// Searches this pass's attachment bindings for one with the provided Name (nullptr if none found)
const PassAttachmentBinding* FindAttachmentBinding(const Name& slotName) const;
// Searches the attachments owned by this pass using the provided Name (nullptr if none found)
Ptr<PassAttachment> FindOwnedAttachment(const Name& attachmentName) const;
// Find an attachment with a matching name from either inputs, outputs or inputOutputs and returns it.
// Returns nullptr if no attachment found.
Ptr<PassAttachment> FindAttachment(const Name& slotName) const;
// Searches adjacent passes for an attachment binding matching the PassAttachmentRef. An adjacent pass is either:
// a parent pass, a child pass, a sibling pass or the pass itself (this).
const PassAttachmentBinding* FindAdjacentBinding(const PassAttachmentRef& attachmentRef);
// --- Template related setup ---
// Process a PassConnection to connect two PassAttachmentBindings
void ProcessConnection(const PassConnection& connection, uint32_t slotTypeMask = 0xFFFFFFFF);
// --- Validation and Error Functions ---
void LogError(AZStd::string&& message);
void LogWarning(AZStd::string&& message);
// --- Pass Behavior Functions ---
// These functions come in pairs, one virtual function (name ending in -Internal) and one
// non-virtual. Each non-virtual function will call it's virtual counterpart. Classes
// inheriting from Pass can override any or all of the virtual -Internal functions to
// customize it's behavior, hence why these functions are called the pass behavior functions.
// Resets everything in the pass (like Attachments).
// Called from PassSystem when pass is QueueForBuildAndInitialization.
void Reset();
virtual void ResetInternal() { }
// Builds and sets up any attachments and input/output connections the pass needs.
// Called from PassSystem when pass is QueueForBuildAndInitialization.
void Build(bool calledFromPassSystem = false);
virtual void BuildInternal() { }
// Allows for additional pass initialization between building and rendering
// Can be queued independently of Build so as to only invoke Initialize() without Build()
void Initialize();
virtual void InitializeInternal() { };
// Called after the pass initialization phase has finished. Allows passes to reset various states and flags.
void OnInitializationFinished();
virtual void OnInitializationFinishedInternal() { };
// The Pass's 'Render' function. Called every frame, here the pass sets up it's rendering logic with
// the FrameGraphBuilder. This is where your derived pass needs to call ImportScopeProducer on
// the FrameGraphBuilder if it's a ScopeProducer (see ForwardPass::FrameBeginInternal for example).
void FrameBegin(FramePrepareParams params);
virtual void FrameBeginInternal([[maybe_unused]] FramePrepareParams params) { }
// Called every frame after the frame has been rendered. Allows the pass
// to perform any post-frame cleanup, such as resetting per-frame state.
void FrameEnd();
virtual void FrameEndInternal() { }
void UpdateReadbackAttachment(FramePrepareParams params, bool beforeAddScopes);
// Setup ImageAttachmentCopy
void UpdateAttachmentCopy(FramePrepareParams params);
// --- Protected Members ---
const Name PassNameThis{"This"};
const Name PassNameParent{"Parent"};
const Name PipelineKeyword{"Pipeline"};
// List of input, output and input/output attachment bindings
// Fixed size for performance and so we can hold pointers to the bindings for connections
AZStd::fixed_vector<PassAttachmentBinding, PassAttachmentBindingCountMax> m_attachmentBindings;
// List of attachments owned by this pass.
// It includes both transient attachments and imported attachments
AZStd::vector<Ptr<PassAttachment>> m_ownedAttachments;
// List of passes before which this pass needs to execute (specified by the PassRequest)
// Note most pass ordering is determined by attachments. This is only to be used for
// dependencies between passes that don't have any attachments/connections in common.
AZStd::vector<Pass*> m_executeBeforePasses;
// List of passes that this pass needs to execute after (specified by the PassRequest)
// Note most pass ordering is determined by attachments. This is only to be used for
// dependencies between passes that don't have any attachments/connections in common.
AZStd::vector<Pass*> m_executeAfterPasses;
// The render pipeline this pass belongs to.
RenderPipeline* m_pipeline = nullptr;
// The PassTemplate used to create this pass
// Null if this pass was not created by a PassTemplate
AZStd::shared_ptr<PassTemplate> m_template = nullptr;
// The PassRequest used to create this pass
// Only valid if m_createdByPassRequest flag is set
PassRequest m_request;
// Pointer to the parent pass if this pass is a child pass
ParentPass* m_parent = nullptr;
struct
{
union
{
struct
{
// Whether this pass was created with a PassRequest (in which case m_request holds valid data)
uint64_t m_createdByPassRequest : 1;
// Whether the pass is enabled (behavior can be customized by overriding IsEnabled() )
uint64_t m_enabled : 1;
// False if parent or one of it's ancestors is disabled
uint64_t m_parentEnabled : 1;
// If this is a parent pass, indicates if the pass has already created children this frame
// Prevents ParentPass::CreateChildPasses from executing multiple times in the same pass
uint64_t m_alreadyCreatedChildren : 1;
// If this is a parent pass, indicates whether the pass needs to create child passes
uint64_t m_createChildren : 1;
// Whether this pass belongs to the pass hierarchy, i.e. if you can trace it's parents up to the Root pass
uint64_t m_partOfHierarchy : 1;
// Whether this pass has a DrawListTag
uint64_t m_hasDrawListTag : 1;
// Whether this pass has a PipelineViewTag
uint64_t m_hasPipelineViewTag : 1;
// Whether the pass should gather timestamp query metrics
uint64_t m_timestampQueryEnabled : 1;
// Whether the pass should gather pipeline statics
uint64_t m_pipelineStatisticsQueryEnabled : 1;
// Whether the pass is the root pass for a pipeline. Used to control pipeline render tick rate
uint64_t m_isPipelineRoot : 1;
};
uint64_t m_allFlags = 0;
};
} m_flags;
// Arbitrary message log limit so we don't get an
// ever increasing array when an error starts spamming
static const size_t MessageLogLimit = 256;
AZStd::vector<AZStd::string> m_errorMessages;
AZStd::vector<AZStd::string> m_warningMessages;
uint32_t m_errors = 0;
uint32_t m_warnings = 0;
// Sort type to be used by the default sort implementation. Passes can also provide
// fully custom sort implementations by overriding the SortDrawList() function.
RHI::DrawListSortType m_drawListSortType = RHI::DrawListSortType::KeyThenDepth;
// For read back attachment
AZStd::shared_ptr<AttachmentReadback> m_attachmentReadback;
PassAttachmentReadbackOption m_readbackOption;
// For image attachment preview
AZStd::weak_ptr<ImageAttachmentCopy> m_attachmentCopy;
private:
// Return the Timestamp result of this pass
virtual TimestampResult GetTimestampResultInternal() const;
// Return the PipelineStatistics result of this pass
virtual PipelineStatisticsResult GetPipelineStatisticsResultInternal() const;
// Used to maintain references to imported attachments so they're underlying
// buffers and images don't get deleted during attachment build phase
void StoreImportedAttachmentReferences();
// Used by the RenderPipeline to create it's passes immediately instead of waiting on
// the next Pass System update. The function internally build and initializes the pass.
void ManualPipelineBuildAndInitialize();
// --- Hierarchy related functions ---
// Called when the pass gets a new spot in the pass hierarchy
virtual void OnHierarchyChange();
// Called when the pass is removed from it's parent list of children
virtual void OnOrphan();
// The pass removes itself from its parent.
void RemoveFromParent();
// --- Template related setup ---
// Generates bindings from source PassTemplate
void CreateBindingsFromTemplate();
// Generates attachments from source PassTemplate
void CreateAttachmentsFromTemplate();
// Generates attachments from source PassRequest
void CreateAttachmentsFromRequest();
// Uses FrameGraphAttachmentInterface to create transient attachments for the pass
void CreateTransientAttachments(RHI::FrameGraphAttachmentInterface attachmentDatabase);
// Creates an attachment from a given description and returns a pointer to it
template<typename AttachmentDescType>
Ptr<PassAttachment> CreateAttachmentFromDesc(const AttachmentDescType& desc);
// Overrides an existing attachment if matching name is found, otherwise creates and adds new attachment
template<typename AttachmentDescType>
void OverrideOrAddAttachment(const AttachmentDescType& desc);
// Updates a binding on this pass using the binding it is connected to.
// This sets the binding's attachment pointer to the connected binding's attachment
void UpdateConnectedBinding(PassAttachmentBinding& binding);
// Process a PassFallbackConnection to connect an output to an input to act as a short-circuit for when Pass is disabled
void ProcessFallbackConnection(const PassFallbackConnection& connection);
// Sets up inputs from the list of PassConnections in PassRequest
void SetupInputsFromRequest();
// Sets up outputs from the list of PassConnections in PassRequest
void SetupOutputsFromRequest();
// Sets up explicitly declared dependencies on other passes declared in the PassRequest
void SetupPassDependencies();
// Sets up inputs from the list of PassConnections in PassTemplate
void SetupInputsFromTemplate();
// Sets up outputs from the list of PassConnections in PassTemplate
void SetupOutputsFromTemplate();
// Updates attachment sizes and formats from their specified source attachments
void UpdateOwnedAttachments();
// Updates m_attachmentUsageIndex on the bindings to handle multiple bindings using the same attachment
void UpdateAttachmentUsageIndices();
// --- Private Members ---
// List of attachment binding indices for all the input bindings
AZStd::fixed_vector<uint8_t, PassInputBindingCountMax> m_inputBindingIndices;
// List of attachment binding indices for all the input/output bindings
AZStd::fixed_vector<uint8_t, PassInputOutputBindingCountMax> m_inputOutputBindingIndices;
// List of attachment binding indices for all the output bindings
AZStd::fixed_vector<uint8_t, PassOutputBindingCountMax> m_outputBindingIndices;
// Used to maintain references to imported attachments so they're underlying
// buffers and images don't get deleted during attachment build phase
AZStd::vector<Ptr<PassAttachment>> m_importedAttachmentStore;
// Name of the pass. Will be concatenated with parent names to form a unique path
Name m_name;
// Path of the pass in the hierarchy. Example: Root.Ssao.Downsample
Name m_path;
// Depth of the tree hierarchy this pass is at.
// Example: Root would be depth 0, Root.Ssao.Downsample depth 2
uint32_t m_treeDepth = 0;
// Used to track what phase of build/execution the pass is in
PassState m_state = PassState::Uninitialized;
// Used to track what phases of build/initialization the pass is queued for
PassQueueState m_queueState = PassQueueState::NoQueue;
};
//! Struct used to return results from Pass hierarchy validation
struct PassValidationResults
{
bool IsValid();
void PrintValidationIfError();
AZStd::vector<Pass*> m_passesWithErrors;
AZStd::vector<Pass*> m_passesWithWarnings;
AZStd::vector<Pass*> m_passesWithMissingInputs;
AZStd::vector<Pass*> m_passesWithMissingOutputs;
AZStd::vector<Pass*> m_passesWithMissingInputOutputs;
};
} // namespace RPI
} // namespace AZ
#ifdef AZ_ENABLE_TRACING
#define AZ_RPI_PASS_ASSERT(expression, ...) \
if (!(expression)) \
{ \
AZ_Assert(false, __VA_ARGS__); \
AZStd::string message = AZStd::string::format(__VA_ARGS__); \
LogError( AZStd::string::format(__VA_ARGS__) ); \
} \
#define AZ_RPI_PASS_ERROR(expression, ...) \
if (!(expression)) \
{ \
AZ_Error("Pass System", false, __VA_ARGS__); \
AZStd::string message = AZStd::string::format(__VA_ARGS__); \
LogError( AZStd::string::format(__VA_ARGS__) ); \
} \
#define AZ_RPI_PASS_WARNING(expression, ...) \
if (!(expression)) \
{ \
AZ_Warning("Pass System", false, __VA_ARGS__); \
AZStd::string message = AZStd::string::format(__VA_ARGS__); \
LogWarning( AZStd::string::format(__VA_ARGS__) ); \
} \
#else
#define AZ_RPI_PASS_ASSERT(expression, ...) AZ_Assert(false, __VA_ARGS__);
#define AZ_RPI_PASS_ERROR(expression, ...) AZ_Error("Pass System", false, __VA_ARGS__);
#define AZ_RPI_PASS_WARNING(expression, ...) AZ_Warning("Pass System", false, __VA_ARGS__);
#endif
#if AZ_RPI_ENABLE_PASS_DEBUGGING
// This macro will break in pass code (functions that belong to Pass or it's child classes)
// if the name of the pass being executed is the same as the one specified for targeted debugging
// in the pass system (see functions with "TargetedPassDebugging" above)
#define AZ_RPI_BREAK_ON_TARGET_PASS \
if(!GetName().IsEmpty() && \
GetName() == AZ::RPI::PassSystemInterface::Get()->GetTargetedPassDebuggingName()) \
{ \
AZ::Debug::Trace::Break(); \
}
#else
#define AZ_RPI_BREAK_ON_TARGET_PASS
#endif