Open 3D Engine Atom Gem API Reference 23.10.0
O3DE is an open-source, fully-featured, high-fidelity, modular 3D engine for building games and simulations, available to every industry.
AZ::RHI::FrameGraphCompiler Class Reference

#include <FrameGraphCompiler.h>

Inherits AZ::RHI::DeviceObject.

Inherited by AZ::DX12::FrameGraphCompiler, AZ::Metal::FrameGraphCompiler, AZ::Null::FrameGraphCompiler, and AZ::Vulkan::FrameGraphCompiler.

Public Member Functions

 AZ_RTTI (FrameGraphCompiler, "{A126F362-C163-432E-94DE-61AA4DFDF102}", Object)
 
ResultCode Init (Device &device)
 
void Shutdown () override final
 Clears the current bound device to null.
 
MessageOutcome Compile (const FrameGraphCompileRequest &request)
 
- Public Member Functions inherited from AZ::RHI::DeviceObject
 AZ_RTTI (DeviceObject, "{17D34F71-944C-4AF5-9823-627474C4C0A6}", Object)
 
bool IsInitialized () const
 Returns whether the device object is initialized.
 
DeviceGetDevice () const
 
- Public Member Functions inherited from AZ::RHI::Object
 AZ_RTTI (Object, "{E43378F1-2331-4173-94B8-990ED20E6003}")
 
void SetName (const Name &name)
 Sets the name of the object.
 
const Name & GetName () const
 Returns the name set on the object by SetName.
 
uint32_t use_count ()
 Returns the current use count of the object.
 

Additional Inherited Members

- Protected Member Functions inherited from AZ::RHI::DeviceObject
void Init (Device &device)
 The derived class should call this method to assign the device.
 
void Shutdown () override
 Clears the current bound device to null.
 
- Protected Member Functions inherited from AZ::RHI::Object
void add_ref () const
 
void release () const
 
- Protected Attributes inherited from AZ::RHI::Object
AZStd::atomic_int m_useCount = 0
 

Detailed Description

FrameGraphCompiler controls compilation of FrameGraph each frame. FrameScheduler owns and drives an instance of this class, so end-users should never need to interact with it directly. Platform implementations, on the other hand, are required to override this class in order to perform platform-specific scope construction.

The compiler is designed to be invoked every frame; the graph is simply rebuilt each time. The compile operation is also done on a single thread; so overhead should be kept to a minimum.

The RHI base class performs platform-independent compilation before passing control down to the derived platform implementation. The provided FrameGraph instance is compiled in-place according to the following phases:

 == Cross-Queue Graph Edges == 

FrameGraph contains a graph of Scope instances. Scopes are topologically sorted prior to compilation as part of the graph construction process. Scopes associate directly to a "Hardware Queue Class": Graphics, Compute, or Copy. These three queue classes must be synchronized between each other. To make this easier on platforms, the base compiler takes the topologically flattened graph and collates it into three independent sorted lists–one for each queue class. Then, a queue-centric producer-consumer graph is constructed across the scopes. Specifically:

class Scope { Scope* m_producersByQueue[HardwareQueueClassCount]; Scope* m_consumersByQueue[HardwareQueueClassCount]; };

This graph makes it possible to walk along a queue or across queue boundaries at dependency points. Each platform can then trivially crawl this graph to derive signal / wait fence values, if applicable.

 == Transient Attachments ==

Transient attachments are intra-frame and do not persist after the frame ends and can take the form of buffers or images. These attachments are owned by a TransientAttachmentPool; every frame, the pool is reset. Since attachments are always declared for usage on scopes, its full usage chain–and thus its lifetime across the frame–is immediately available.

The phase first constructs the scope lifetime for each attachment. Then, memory for each attachment is allocated from the transient attachment pool, one scope at a time. This allows the pool to record begin and end usages for each attachment per scope. Internally, the platform implementation can use this information to place aliased resources onto one or more heaps of memory.

One important consideration is dealing with aliasing across queue boundaries. Since queues must be synchronized between each other, attempting to alias memory across two queues at the same time will produce a race condition. To solve this, when faced with a queue overlap, the compiler extends the lifetime of the attachment until a join operation occurs. However, the compiler picks a single queue which is allowed to alias during that region by inspecting which one will see the biggest potential gain. This way, some aliasing is still allowed when async compute / copy is in use.

Finally, because the resources themselves are effectively re-created each frame, a cache of views is kept inside the compiler. The cache is big enough to avoid having to re-create views every frame, but bounded in order to release entries old views.

 == Platform-Specific Compilation ==

Finally, the compiler calls into the platform-specific compile method, which hands control over to the derived class. The platform implementation is expected to further process the frame graph and scope data down to platform-specific actions. For example:

1) Derive transition barriers by walking the scope attachment chain on each frame attachment. 2) Derive queue fence values by walking the queue-centric scope graph.

Member Function Documentation

◆ Compile()

MessageOutcome AZ::RHI::FrameGraphCompiler::Compile ( const FrameGraphCompileRequest request)

Compiles the frame graph. Platform-independent compilation is done first according to the provided flags. At the end, the platform-dependent compilation method is invoked.

◆ Shutdown()

void AZ::RHI::FrameGraphCompiler::Shutdown ( )
finaloverridevirtual

Clears the current bound device to null.

Reimplemented from AZ::RHI::DeviceObject.


The documentation for this class was generated from the following file: